// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package preferences /* #include #include "native.h" */ import "C" import ( "errors" "unsafe" "git.stormux.org/storm/cthulhu/internal/tentacle" ) func (page *tentaclePage) action(action int) (*tentacle.ManagementRequest, error) { if action == C.PREFS_TENTACLE_SELECT { if selected := page.selected(); selected != nil { page.selectedKey = selected.key } page.controls() return nil, nil } if action == C.PREFS_TENTACLE_REPOSITORY_SELECT { page.render() return nil, nil } if action == C.PREFS_TENTACLE_REFRESH { return &tentacle.ManagementRequest{Action: "list"}, nil } if page.snapshot == nil || page.snapshot.Suppressed || page.snapshot.Message != "" { message := "Tentacle management is unavailable for this run." if page.snapshot != nil && page.snapshot.Message != "" { message = page.snapshot.Message } return nil, errors.New(message) } if action == C.PREFS_TENTACLE_REPOSITORY_ADD { id := C.CString("tentacleRepositoryURL") origin, err := tentacle.RepositoryURL(C.GoString(C.prefs_entry_get(id))) C.free(unsafe.Pointer(id)) if err != nil { return nil, err } return &tentacle.ManagementRequest{Action: "repository-add", URL: origin}, nil } if action == C.PREFS_TENTACLE_REPOSITORY_REMOVE || action == C.PREFS_TENTACLE_REPOSITORY_REFRESH { origin := page.origin() if origin == "" { return nil, errors.New("Select a repository tab first.") } operation := "repository-remove" if action == C.PREFS_TENTACLE_REPOSITORY_REFRESH { operation = "repository-refresh" } return &tentacle.ManagementRequest{Action: operation, URL: origin}, nil } selected := page.selected() if selected == nil { return nil, errors.New("Select a tentacle first.") } page.selectedKey = selected.key if action == C.PREFS_TENTACLE_UPDATE { return page.updatePackage(selected) } if !selected.installed { return page.installPackage(selected, action) } operation := "" switch action { case C.PREFS_TENTACLE_TOGGLE: operation = "enable" if selected.status.Entry.Enabled { operation = "disable" } case C.PREFS_TENTACLE_RETRY: operation = "retry" case C.PREFS_TENTACLE_REMOVE: operation = "remove" case C.PREFS_TENTACLE_SETTINGS: operation = "settings" default: return nil, errors.New("Unknown tentacle action.") } return &tentacle.ManagementRequest{Action: operation, ID: selected.status.Entry.ID}, nil } func (page *tentaclePage) updatePackage(selected *tentacleRow) (*tentacle.ManagementRequest, error) { if !selected.installed { return nil, errors.New("Install this tentacle first.") } entry := selected.status.Entry for _, update := range page.snapshot.Updates { if update.ID != entry.ID { continue } manifest := findTentacleManifest(page.snapshot, update.RepositoryURL, update.RepositoryID, update.LocalID) if manifest == nil { return nil, errors.New("Updated package manifest is unavailable; refresh the repository before upgrading.") } message := tentacleUpdateConfirmation(entry, update, *manifest) if !confirmTentaclePackage(message, "Update") { return nil, nil } return &tentacle.ManagementRequest{Action: "upgrade", ID: update.LocalID, URL: update.RepositoryURL}, nil } return nil, errors.New("No newer version is available for the selected tentacle. Refresh its repository to check again.") } func (page *tentaclePage) installPackage(selected *tentacleRow, action int) (*tentacle.ManagementRequest, error) { if action != C.PREFS_TENTACLE_TOGGLE && action != C.PREFS_TENTACLE_INSTALL { return nil, errors.New("Install this tentacle first.") } entry := selected.status.Entry manifest := findTentacleManifest(page.snapshot, entry.Repository, entry.RepositoryID, entry.LocalID) if manifest == nil || len(manifest.Releases) == 0 { return nil, errors.New("No package has been published for this tentacle. Refresh the repository after a release is published.") } operation, label := "install", "Install" if action == C.PREFS_TENTACLE_TOGGLE { operation, label = "install-enable", "Install and enable" } message := tentacleInstallConfirmation(entry, *manifest, label) if !confirmTentaclePackage(message, label) { return nil, nil } return &tentacle.ManagementRequest{Action: operation, ID: entry.LocalID, URL: entry.Repository}, nil } func confirmTentaclePackage(message, label string) bool { text, button := C.CString(message), C.CString(label) defer C.free(unsafe.Pointer(text)) defer C.free(unsafe.Pointer(button)) return C.prefs_tentacle_confirm(text, button) != 0 } // Snapshot repositories have unique identities and local package IDs. func findTentacleManifest(snapshot *tentacle.Snapshot, origin, repositoryID, localID string) *tentacle.Manifest { for _, repository := range snapshot.Repositories { if repository.URL != origin || repository.ID != repositoryID { continue } for index := range repository.Tentacles { if repository.Tentacles[index].ID == localID { return &repository.Tentacles[index] } } } return nil }