Package Fiw tools and make app configs independent of package groups

This commit is contained in:
fi3w0 2026-10-03 05:00:47 +02:00
parent 98c16f952f
commit e67a8bce93
12 changed files with 179 additions and 19 deletions

View file

@ -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 | | [dev](packages/dev.list) | Languages and development tools |
| [gaming](packages/gaming.list) | Steam, Proton, Prism, MangoHud and r2modman; Sober is in flatpaks/gaming.list | | [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 | | [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 | | [tidewm](packages/tidewm.list) | Optional compositor and supporting utilities |
Filelight, NVIDIA drivers and Btrfs tools are separate extras. Ext4 does not 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 ## 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 fonts, cursor, window decorations and Dolphin styling. Panels, widgets and
wallpapers are excluded. All portable current shortcut assignments, wallpapers are excluded. All portable current shortcut assignments,
including disabled defaults, are captured with their launchers and helpers; including disabled defaults, are captured with their launchers and helpers;

View file

@ -88,9 +88,6 @@ func (m *model) prepare() {
sort.Strings(ids) sort.Strings(ids)
for _, id := range ids { for _, id := range ids {
c := m.catalog.Configs[id] 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)}) m.rows = append(m.rows, row{id, c.Label, contains(m.selection.Configs, id)})
} }
case 3: case 3:

View file

@ -39,3 +39,14 @@ func TestBootloaderChoicesAreExclusive(t *testing.T) {
t.Fatal("multiple bootloaders selected") 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")
}
}

View file

@ -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 a fallback when Catppuccin is not installed. Vesktop's selected Midnight
theme CSS is captured with a fixed upstream snapshot and its MIT licence. 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 ## Remaining work before declaring a fresh install verified
- Run both presets on a fresh Gentoo test installation. Root package execution - Run both presets on a fresh Gentoo test installation. Root package execution
has not been exercised on the working desktop. 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 - Implement target-specific Limine/GRUB deployment after reviewing the target
ESP and boot layout. Current variants select packages and provide setup notes. ESP and boot layout. Current variants select packages and provide setup notes.
- Refresh the optional TideWM live ebuild branch/dependency recipe against the - Refresh the optional TideWM live ebuild branch/dependency recipe against the

View file

@ -117,9 +117,6 @@ def merge_json(old, patch):
def config_entries(selection): def config_entries(selection):
for name in selection['configs']: 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'): for kind in ('files', 'kconfig', 'json'):
root = REPO / 'configs' / name / kind root = REPO / 'configs' / name / kind
if not root.is_dir(): if not root.is_dir():
@ -283,15 +280,11 @@ def preview(selection):
'Kernel: ' + selection['kernel'] + (' + binary fallback' if selection['kernel'] == 'custom' else ''), 'Kernel: ' + selection['kernel'] + (' + binary fallback' if selection['kernel'] == 'custom' else ''),
'Bootloader: ' + selection['bootloader'], '', 'Selected configs:'] 'Bootloader: ' + selection['bootloader'], '', 'Selected configs:']
for name in selection['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)))), lines += ['', 'Config files: ' + str(len(list(config_entries(selection)))),
'Root configuration files: ' + str(len(root_files(selection))), 'Root configuration files: ' + str(len(root_files(selection))),
'Existing config conflicts: ask; updates preserve edits as .new.'] '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': if selection['bootloader'] != 'keep':
lines.append('Bootloader package selected; ESP/firmware deployment is a separate explicit setup step (docs/boot.md).') lines.append('Bootloader package selected; ESP/firmware deployment is a separate explicit setup step (docs/boot.md).')
if selection.get('firefox_privacy'): 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)) values = set(re.findall(r'^\[ebuild[^\]]*\]\s+(?:\([^)]*\)\s+)?([^\s:]+)', output, re.M))
# Dedicated -bin ebuilds install upstream binaries; these do not require # Dedicated -bin ebuilds install upstream binaries; these do not require
# compiling the application just because Portage labels them "ebuild". # 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): def resolve(stage, selection, packages, execute=False):
@ -450,7 +446,7 @@ def install_packages(selection):
stderr=subprocess.DEVNULL).returncode != 0] stderr=subprocess.DEVNULL).returncode != 0]
report = {'requested': requested, 'skipped': skipped, 'emerge_exit_code': result.returncode, report = {'requested': requested, 'skipped': skipped, 'emerge_exit_code': result.returncode,
'missing': missing, 'missing': missing,
'pending': ['FiwNode and Apdatifier packaging'] if 'fiw-tools' in selection['groups'] else []} 'pending': []}
state = Path('/var/lib/Fiw-Gentoo-Dots') state = Path('/var/lib/Fiw-Gentoo-Dots')
state.mkdir(parents=True, exist_ok=True) state.mkdir(parents=True, exist_ok=True)
(state / ('packages-' + stamp + '.json')).write_text(json.dumps(report, indent=2) + '\n') (state / ('packages-' + stamp + '.json')).write_text(json.dumps(report, indent=2) + '\n')

View file

@ -0,0 +1 @@
DIST apdatifier-gentoo_v1.0.0.plasmoid 504155 BLAKE2B 96fc227e9704621e64ffb68709d5cd0d5f92fd5fc2e1b29c3625a251c43a8c47b95aaa3cfadf090516898558f0a0206607324b9070cc282abe89fb309779d276 SHA512 d6900ecaf0fc5d5322c7d734c0f90723efeee091c975e66ee9d3e066f4b2073829ec49da37ec122a4b9f9f3f89cb5c7d49a4b419d7bbe278db01ed3730f47511

View file

@ -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."
}

View file

@ -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.**

View file

@ -0,0 +1 @@
DIST FiwNode-v0.1.0-linux-x86_64.tar.gz 5824766 BLAKE2B 89cd87e52adf95824d91bdd3f121259bccadb22d437ba098612f8c55f9077d76a36e010e187419a8c8e0b771311853a5fbd23eece9060e27ba12b68b3d8387a2 SHA512 e5790a8bf7b29082a823d3afa5661f195f4cc25fd0a36abe49f1d4f09899c1f91b40bff6421eb055a4e867dcc7b9adab6a028d22c083187a0c1a8a818aa01262

View file

@ -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."
}

View file

@ -1,3 +1,5 @@
# fiw-tools — explicit selections; Portage resolves dependencies. # fiw-tools — explicit selections; Portage resolves dependencies.
app-misc/opendeck-bin::fiw-dots app-misc/opendeck-bin::fiw-dots
media-sound/music-presence-bin::fiw-dots media-sound/music-presence-bin::fiw-dots
media-sound/fiwnode-bin::fiw-dots
kde-misc/apdatifier-gentoo::fiw-dots

View file

@ -72,10 +72,25 @@ class ConfigTests(unittest.TestCase):
self.assertEqual(list(home.iterdir()), []) self.assertEqual(list(home.iterdir()), [])
def test_source_plan_distinguishes_binary_payloads_and_dependencies(self): 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.source_builds(output), {'dev-libs/foo-2.0'})
self.assertEqual(rice.cp_from_cpv('dev-libs/foo-2.0'), 'dev-libs/foo') 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): def test_category_separation_and_stock_kernel(self):
selection = rice.load_selection() selection = rice.load_selection()
packages = rice.package_map(selection) packages = rice.package_map(selection)