diff --git a/README.md b/README.md index 9e41d83..c6bb932 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ CachyOS 7.2.7-1 patch. Refresh it explicitly when updating the snapshot. | [dev](packages/dev.list) | Languages and development tools | | [gaming](packages/gaming.list) | Steam, Proton, Prism, MangoHud and r2modman; Sober is in flatpaks/gaming.list | | [system](packages/system.list) | System utilities; the selected kernels are added by the installer | -| [fiw-tools](packages/fiw-tools.list) | OpenDeck and Music Presence; FiwNode and Apdatifier packaging is pending | +| [fiw-tools](packages/fiw-tools.list) | FiwNode binary release, Apdatifier Gentoo, OpenDeck and Music Presence | | [tidewm](packages/tidewm.list) | Optional compositor and supporting utilities | Filelight, NVIDIA drivers and Btrfs tools are separate extras. Ext4 does not @@ -91,7 +91,8 @@ the default. Kernel choice is independent of bootloader choice. ## Configs -Every config is independently selectable. KDE appearance covers colours, +Every config is independently selectable, even when its package section is +unchecked—for example, to configure apps already installed. KDE appearance covers colours, fonts, cursor, window decorations and Dolphin styling. Panels, widgets and wallpapers are excluded. All portable current shortcut assignments, including disabled defaults, are captured with their launchers and helpers; diff --git a/cmd/dots/main.go b/cmd/dots/main.go index 3ae913b..a8dd413 100644 --- a/cmd/dots/main.go +++ b/cmd/dots/main.go @@ -88,9 +88,6 @@ func (m *model) prepare() { sort.Strings(ids) for _, id := range ids { c := m.catalog.Configs[id] - if c.Group != "" && !contains(m.selection.Groups, c.Group) { - continue - } m.rows = append(m.rows, row{id, c.Label, contains(m.selection.Configs, id)}) } case 3: diff --git a/cmd/dots/main_test.go b/cmd/dots/main_test.go index 31ba992..9f7752c 100644 --- a/cmd/dots/main_test.go +++ b/cmd/dots/main_test.go @@ -39,3 +39,14 @@ func TestBootloaderChoicesAreExclusive(t *testing.T) { t.Fatal("multiple bootloaders selected") } } + +func TestConfigsSelectableWithoutPackageGroups(t *testing.T) { + m := model{stage: 2, catalog: catalog{Configs: map[string]config{ + "fish": {Label: "Fish", Group: "cli"}, + "kitty": {Label: "Kitty", Group: "fiw-apps"}, + }}, selection: selection{Configs: []string{"fish"}}} + m.prepare() + if len(m.rows) != 2 || !m.rows[0].checked { + t.Fatal("configs were hidden or deselected by package choices") + } +} diff --git a/docs/setup.md b/docs/setup.md index 0166e51..8a8c7dc 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -52,12 +52,26 @@ personal font collection is not included. Neovim uses its built-in theme as a fallback when Catppuccin is not installed. Vesktop's selected Midnight theme CSS is captured with a fixed upstream snapshot and its MIT licence. +## Fiw tools + +The `fiw-tools` section includes FiwNode's x86-64 binary release and the +released Apdatifier Gentoo widget, alongside OpenDeck and Music Presence. +Apdatifier installs QML/scripts without compilation; any dependencies needing +source builds still go through the normal compile/skip prompt. + +FiwNode uses its default configuration. The installer does not copy sound +libraries, microphone/output selections or personal app state. Older copies +in `~/.local/bin` can shadow the Portage-installed binaries in `/usr/bin`; +remove those manually when ready to switch. The daemon starts on demand. + +Apdatifier is available through Plasma's **Add Widgets** menu. Installing it +does not alter panels. An existing user-installed widget can override the +system copy; use `kpackagetool6` to manage it. Its preferences remain local. + ## Remaining work before declaring a fresh install verified - Run both presets on a fresh Gentoo test installation. Root package execution has not been exercised on the working desktop. -- Package FiwNode and Apdatifier Gentoo. Their existing installs are preserved; - the preview reports their packaging as pending. - Implement target-specific Limine/GRUB deployment after reviewing the target ESP and boot layout. Current variants select packages and provide setup notes. - Refresh the optional TideWM live ebuild branch/dependency recipe against the diff --git a/lib/rice.py b/lib/rice.py index fc7869f..d278adf 100644 --- a/lib/rice.py +++ b/lib/rice.py @@ -117,9 +117,6 @@ def merge_json(old, patch): def config_entries(selection): for name in selection['configs']: - group = CATALOG[name].get('group') - if group and group not in selection['groups']: - continue for kind in ('files', 'kconfig', 'json'): root = REPO / 'configs' / name / kind if not root.is_dir(): @@ -283,15 +280,11 @@ def preview(selection): 'Kernel: ' + selection['kernel'] + (' + binary fallback' if selection['kernel'] == 'custom' else ''), 'Bootloader: ' + selection['bootloader'], '', 'Selected configs:'] for name in selection['configs']: - if CATALOG[name].get('group') and CATALOG[name]['group'] not in selection['groups']: - lines.append(' ' + name + ' (inactive: owning package group is not selected)') - else: - lines.append(' ' + name + ': ' + CATALOG[name]['label']) + lines.append(' ' + name + ': ' + CATALOG[name]['label']) lines += ['', 'Config files: ' + str(len(list(config_entries(selection)))), 'Root configuration files: ' + str(len(root_files(selection))), 'Existing config conflicts: ask; updates preserve edits as .new.'] - if 'fiw-tools' in selection['groups']: - lines += ['', 'Pending packaging: FiwNode and Apdatifier Gentoo. Existing installations are preserved.'] + if selection['bootloader'] != 'keep': lines.append('Bootloader package selected; ESP/firmware deployment is a separate explicit setup step (docs/boot.md).') if selection.get('firefox_privacy'): @@ -325,7 +318,10 @@ def source_builds(output): values = set(re.findall(r'^\[ebuild[^\]]*\]\s+(?:\([^)]*\)\s+)?([^\s:]+)', output, re.M)) # Dedicated -bin ebuilds install upstream binaries; these do not require # compiling the application just because Portage labels them "ebuild". - return {value for value in values if not cp_from_cpv(value).endswith('-bin')} + # This released Plasma widget installs QML/scripts without a compile phase. + no_compile = {'kde-misc/apdatifier-gentoo'} + return {value for value in values if not cp_from_cpv(value).endswith('-bin') + and cp_from_cpv(value) not in no_compile} def resolve(stage, selection, packages, execute=False): @@ -450,7 +446,7 @@ def install_packages(selection): stderr=subprocess.DEVNULL).returncode != 0] report = {'requested': requested, 'skipped': skipped, 'emerge_exit_code': result.returncode, 'missing': missing, - 'pending': ['FiwNode and Apdatifier packaging'] if 'fiw-tools' in selection['groups'] else []} + 'pending': []} state = Path('/var/lib/Fiw-Gentoo-Dots') state.mkdir(parents=True, exist_ok=True) (state / ('packages-' + stamp + '.json')).write_text(json.dumps(report, indent=2) + '\n') diff --git a/overlay/kde-misc/apdatifier-gentoo/Manifest b/overlay/kde-misc/apdatifier-gentoo/Manifest new file mode 100644 index 0000000..3d60d30 --- /dev/null +++ b/overlay/kde-misc/apdatifier-gentoo/Manifest @@ -0,0 +1 @@ +DIST apdatifier-gentoo_v1.0.0.plasmoid 504155 BLAKE2B 96fc227e9704621e64ffb68709d5cd0d5f92fd5fc2e1b29c3625a251c43a8c47b95aaa3cfadf090516898558f0a0206607324b9070cc282abe89fb309779d276 SHA512 d6900ecaf0fc5d5322c7d734c0f90723efeee091c975e66ee9d3e066f4b2073829ec49da37ec122a4b9f9f3f89cb5c7d49a4b419d7bbe278db01ed3730f47511 diff --git a/overlay/kde-misc/apdatifier-gentoo/apdatifier-gentoo-1.0.0.ebuild b/overlay/kde-misc/apdatifier-gentoo/apdatifier-gentoo-1.0.0.ebuild new file mode 100644 index 0000000..dcbc852 --- /dev/null +++ b/overlay/kde-misc/apdatifier-gentoo/apdatifier-gentoo-1.0.0.ebuild @@ -0,0 +1,54 @@ +# Copyright 2026 Fiw +# Distributed under the terms of the MIT License + +EAPI=8 + +DESCRIPTION="Gentoo/Portage update notifier for KDE Plasma 6" +HOMEPAGE="https://github.com/Fi3w0/apdatifier-gentoo" +SRC_URI="https://github.com/Fi3w0/apdatifier-gentoo/releases/download/v${PV}/apdatifier-gentoo_v${PV}.plasmoid" +S="${WORKDIR}/${P}" + +LICENSE="MIT" +SLOT="0" +KEYWORDS="amd64" +RESTRICT="mirror" +BDEPEND="app-arch/unzip" +RDEPEND=" + app-admin/sudo + app-misc/jq + app-portage/portage-utils + dev-libs/libxml2 + dev-qt/qt5compat:6[qml] + dev-qt/qtbase:6[network] + dev-vcs/git + kde-frameworks/kiconthemes:6 + kde-frameworks/kirigami:6 + kde-frameworks/kitemmodels:6 + kde-frameworks/kcmutils:6 + kde-frameworks/knotifications:6 + kde-frameworks/kdeclarative:6 + kde-frameworks/ksvg:6 + kde-plasma/libplasma:6 + kde-plasma/plasma5support:6 + kde-plasma/plasma-workspace:6 + net-misc/curl +" + +src_unpack() { + mkdir -p "${S}" || die + unzip -q "${DISTDIR}/${A}" -d "${S}" || die +} + +src_install() { + insinto /usr/share/plasma/plasmoids/com.github.fiw.apdatifier-gentoo + doins metadata.json + doins -r contents + fperms +x /usr/share/plasma/plasmoids/com.github.fiw.apdatifier-gentoo/contents/tools/sh/{init,management,terminal,upgrade,utils,widgets} + dodoc "${FILESDIR}/LICENSE.MIT" +} + +pkg_postinst() { + elog "Add Apdatifier Gentoo through Plasma's Add Widgets menu." + elog "This package does not change panels or enable scheduled checks." + elog "A per-user copy can override this system package; manage it with kpackagetool6." +} diff --git a/overlay/kde-misc/apdatifier-gentoo/files/LICENSE.MIT b/overlay/kde-misc/apdatifier-gentoo/files/LICENSE.MIT new file mode 100644 index 0000000..83c3470 --- /dev/null +++ b/overlay/kde-misc/apdatifier-gentoo/files/LICENSE.MIT @@ -0,0 +1,23 @@ +## [MIT License](https://opensource.org/license/mit/) + +**Copyright (c) 2023 exequtic** + +**Copyright (c) 2026 Fi3w0 (Gentoo fork modifications)** + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.** diff --git a/overlay/media-sound/fiwnode-bin/Manifest b/overlay/media-sound/fiwnode-bin/Manifest new file mode 100644 index 0000000..db6a7ab --- /dev/null +++ b/overlay/media-sound/fiwnode-bin/Manifest @@ -0,0 +1 @@ +DIST FiwNode-v0.1.0-linux-x86_64.tar.gz 5824766 BLAKE2B 89cd87e52adf95824d91bdd3f121259bccadb22d437ba098612f8c55f9077d76a36e010e187419a8c8e0b771311853a5fbd23eece9060e27ba12b68b3d8387a2 SHA512 e5790a8bf7b29082a823d3afa5661f195f4cc25fd0a36abe49f1d4f09899c1f91b40bff6421eb055a4e867dcc7b9adab6a028d22c083187a0c1a8a818aa01262 diff --git a/overlay/media-sound/fiwnode-bin/fiwnode-bin-0.1.0.ebuild b/overlay/media-sound/fiwnode-bin/fiwnode-bin-0.1.0.ebuild new file mode 100644 index 0000000..85a2bd4 --- /dev/null +++ b/overlay/media-sound/fiwnode-bin/fiwnode-bin-0.1.0.ebuild @@ -0,0 +1,45 @@ +# Copyright 2026 Fiw +# Distributed under the terms of the MIT License + +EAPI=8 + +inherit desktop xdg + +DESCRIPTION="FiwNode soundboard and virtual microphone for PipeWire" +HOMEPAGE="https://github.com/Fi3w0/FiwNode" +SRC_URI="https://github.com/Fi3w0/FiwNode/releases/download/v${PV}/FiwNode-v${PV}-linux-x86_64.tar.gz" +S="${WORKDIR}/FiwNode-v${PV}-linux-x86_64" + +LICENSE="MIT" +SLOT="0" +KEYWORDS="amd64" +RESTRICT="mirror strip" +QA_PREBUILT="usr/bin/*" + +RDEPEND=" + >=sys-libs/glibc-2.39 + dev-db/sqlite:3 + dev-qt/qtbase:6[dbus,gui,widgets] + dev-qt/qtdeclarative:6 + dev-qt/qtsvg:6 + media-video/ffmpeg + media-video/pipewire + media-video/wireplumber +" + +src_install() { + dobin bin/fiwnode bin/fiwnode-daemon bin/fiwnode-gui + domenu assets/dev.fiw.fiwnode.desktop + doicon -s scalable assets/icons/fiwnode.svg + doicon -s scalable assets/icons/fiwnode-tray-symbolic.svg + insinto /usr/share/icons/hicolor/symbolic/apps + doins assets/icons/fiwnode-tray-symbolic.svg + dodoc README.md CHANGELOG.md LICENSE +} + +pkg_postinst() { + xdg_pkg_postinst + elog "FiwNode starts its daemon on demand; no system service is enabled." + elog "Existing per-user installs in ~/.local/bin can shadow /usr/bin." + elog "Remove those old binaries manually when you are ready to use this package." +} diff --git a/packages/fiw-tools.list b/packages/fiw-tools.list index d98a368..5e2c3bd 100644 --- a/packages/fiw-tools.list +++ b/packages/fiw-tools.list @@ -1,3 +1,5 @@ # fiw-tools — explicit selections; Portage resolves dependencies. app-misc/opendeck-bin::fiw-dots media-sound/music-presence-bin::fiw-dots +media-sound/fiwnode-bin::fiw-dots +kde-misc/apdatifier-gentoo::fiw-dots diff --git a/tests/test_configs.py b/tests/test_configs.py index ae125df..08027cb 100644 --- a/tests/test_configs.py +++ b/tests/test_configs.py @@ -72,10 +72,25 @@ class ConfigTests(unittest.TestCase): self.assertEqual(list(home.iterdir()), []) def test_source_plan_distinguishes_binary_payloads_and_dependencies(self): - output = '[binary N ] app-misc/jq-1.8.2::gentoo\n[ebuild N ] dev-libs/foo-2.0::gentoo\n[ebuild N ] games-util/ge-proton-bin-11.7::fiw-dots\n' + output = '[binary N ] app-misc/jq-1.8.2::gentoo\n[ebuild N ] dev-libs/foo-2.0::gentoo\n[ebuild N ] games-util/ge-proton-bin-11.7::fiw-dots\n[ebuild N ] kde-misc/apdatifier-gentoo-1.0.0::fiw-dots\n' self.assertEqual(rice.source_builds(output), {'dev-libs/foo-2.0'}) self.assertEqual(rice.cp_from_cpv('dev-libs/foo-2.0'), 'dev-libs/foo') + def test_configs_restore_without_installing_package_sections(self): + selection = rice.load_selection() + selection['groups'] = [] + selection['configs'] = ['fish', 'kitty', 'neovim', 'fastfetch'] + selection['extras'] = [] + self.assertEqual(rice.package_map(selection), {}) + with tempfile.TemporaryDirectory() as temp: + home = Path(temp) + report = rice.apply_configs(selection, home, conflict='apply') + self.assertTrue(report['applied']) + for relative in ['.config/fish/conf.d/fiw.fish', '.config/kitty/kitty.conf', + '.config/nvim/init.lua', '.config/fastfetch/config.jsonc']: + self.assertTrue((home / relative).is_file(), relative) + self.assertNotIn('inactive', rice.preview(selection)) + def test_category_separation_and_stock_kernel(self): selection = rice.load_selection() packages = rice.package_map(selection)