154 lines
5.0 KiB
Go
154 lines
5.0 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package preferences
|
|
|
|
/*
|
|
#include <stdlib.h>
|
|
#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
|
|
}
|