Various cleanup bits, always use the version from lsb_release instead of hardcoding
This commit is contained in:
parent
4d6176bc13
commit
fa0302e5aa
@ -1,12 +1,17 @@
|
|||||||
cmake_minimum_required(VERSION 3.5.0)
|
cmake_minimum_required(VERSION 3.5.0)
|
||||||
project(snapd-installation-monitor)
|
project(snapd-installation-monitor)
|
||||||
|
|
||||||
|
# Enable CMake features
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
|
# Find required Qt6 components
|
||||||
find_package(Qt6 COMPONENTS Widgets DBus REQUIRED)
|
find_package(Qt6 COMPONENTS Widgets DBus REQUIRED)
|
||||||
|
|
||||||
|
# Set C++ standard
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Add the main application executable
|
||||||
add_executable(snapd-installation-monitor main.cpp)
|
add_executable(snapd-installation-monitor main.cpp)
|
||||||
target_link_libraries(snapd-installation-monitor Qt6::Widgets Qt6::DBus)
|
target_link_libraries(snapd-installation-monitor Qt6::Widgets Qt6::DBus)
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// cleanUpFiles removes partial, old, and orphaned snap and assertion files from the download and assertions directories.
|
// cleanUpFiles removes partial, old, and orphaned snap and assertion files from the download and assertions directories.
|
||||||
func cleanUpFiles(snapsDir, assertionsDir, seedYaml string) {
|
func cleanUpFiles(snapsDir string, assertionsDir string) {
|
||||||
verboseLog("Starting cleanup process...")
|
verboseLog("Starting cleanup process...")
|
||||||
|
|
||||||
// Load the seed.yaml data
|
// Load the seed.yaml data
|
||||||
seedData := loadSeedData(seedYaml)
|
seedData := loadSeedData()
|
||||||
|
|
||||||
// Create a map of valid snap and assertion files based on seed.yaml
|
// Create a map of valid snap and assertion files based on seed.yaml
|
||||||
validSnaps := make(map[string]bool)
|
validSnaps := make(map[string]bool)
|
||||||
|
@ -12,15 +12,6 @@ import (
|
|||||||
"github.com/snapcore/snapd/store"
|
"github.com/snapcore/snapd/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Seed structure for seed.yaml
|
|
||||||
type seed struct {
|
|
||||||
Snaps []struct {
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
Channel string `yaml:"channel"`
|
|
||||||
File string `yaml:"file"`
|
|
||||||
} `yaml:"snaps"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
storeClient *store.Store
|
storeClient *store.Store
|
||||||
@ -30,6 +21,7 @@ var (
|
|||||||
processedSnaps = make(map[string]bool)
|
processedSnaps = make(map[string]bool)
|
||||||
snapSizeMap = make(map[string]float64)
|
snapSizeMap = make(map[string]float64)
|
||||||
totalSnapSize float64
|
totalSnapSize float64
|
||||||
|
seedYaml string
|
||||||
)
|
)
|
||||||
|
|
||||||
type SnapInfo struct {
|
type SnapInfo struct {
|
||||||
@ -61,14 +53,14 @@ func main() {
|
|||||||
// Define directories based on the seed directory
|
// Define directories based on the seed directory
|
||||||
snapsDir := filepath.Join(seedDirectory, "snaps")
|
snapsDir := filepath.Join(seedDirectory, "snaps")
|
||||||
assertionsDir := filepath.Join(seedDirectory, "assertions")
|
assertionsDir := filepath.Join(seedDirectory, "assertions")
|
||||||
seedYaml := filepath.Join(seedDirectory, "seed.yaml")
|
seedYaml = filepath.Join(seedDirectory, "seed.yaml")
|
||||||
|
|
||||||
// Setup directories and seed.yaml
|
// Setup directories and seed.yaml
|
||||||
initializeDirectories(snapsDir, assertionsDir)
|
initializeDirectories(snapsDir, assertionsDir)
|
||||||
initializeSeedYaml(seedYaml)
|
initializeSeedYaml()
|
||||||
|
|
||||||
// Load existing snaps from seed.yaml
|
// Load existing snaps from seed.yaml
|
||||||
existingSnapsInYaml := loadExistingSnaps(seedYaml)
|
existingSnapsInYaml := loadExistingSnaps()
|
||||||
|
|
||||||
// Populate currentSnaps based on existing snaps
|
// Populate currentSnaps based on existing snaps
|
||||||
for snapName := range existingSnapsInYaml {
|
for snapName := range existingSnapsInYaml {
|
||||||
@ -133,7 +125,7 @@ func main() {
|
|||||||
cleanUpCurrentSnaps(assertionsDir, snapsDir)
|
cleanUpCurrentSnaps(assertionsDir, snapsDir)
|
||||||
|
|
||||||
// Update seed.yaml with the current required snaps
|
// Update seed.yaml with the current required snaps
|
||||||
if err := updateSeedYaml(snapsDir, seedYaml, currentSnaps); err != nil {
|
if err := updateSeedYaml(snapsDir, currentSnaps); err != nil {
|
||||||
log.Fatalf("Failed to update seed.yaml: %v", err)
|
log.Fatalf("Failed to update seed.yaml: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +135,7 @@ func main() {
|
|||||||
if err := validateSeed(seedYaml); err != nil {
|
if err := validateSeed(seedYaml); err != nil {
|
||||||
log.Fatalf("Seed validation failed: %v", err)
|
log.Fatalf("Seed validation failed: %v", err)
|
||||||
}
|
}
|
||||||
cleanUpFiles(snapsDir, assertionsDir, seedYaml)
|
cleanUpFiles(snapsDir, assertionsDir)
|
||||||
|
|
||||||
// Mark "Finalizing" as complete
|
// Mark "Finalizing" as complete
|
||||||
if progressTracker != nil {
|
if progressTracker != nil {
|
||||||
@ -155,11 +147,21 @@ func main() {
|
|||||||
func collectSnapsToProcess(snapsDir, assertionsDir string) ([]SnapDetails, error) {
|
func collectSnapsToProcess(snapsDir, assertionsDir string) ([]SnapDetails, error) {
|
||||||
var snapsToProcess []SnapDetails
|
var snapsToProcess []SnapDetails
|
||||||
|
|
||||||
|
versionID, err := getVersionID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultChannel := "latest/stable/ubuntu-" + versionID
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
fallbackChannel := "latest/stable"
|
fallbackChannel := "latest/stable"
|
||||||
for snapEntry := range requiredSnaps {
|
for snapEntry := range requiredSnaps {
|
||||||
// Extract channel if specified, default to "stable"
|
// Extract channel if specified, default to "stable"
|
||||||
parts := strings.SplitN(snapEntry, "=", 2)
|
parts := strings.SplitN(snapEntry, "=", 2)
|
||||||
channel := "latest/stable/ubuntu-25.04"
|
channel := defaultChannel
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
channel = parts[1]
|
channel = parts[1]
|
||||||
}
|
}
|
||||||
@ -173,9 +175,10 @@ func collectSnapsToProcess(snapsDir, assertionsDir string) ([]SnapDetails, error
|
|||||||
|
|
||||||
// Append only those snaps that need updates
|
// Append only those snaps that need updates
|
||||||
for _, snapDetails := range snapList {
|
for _, snapDetails := range snapList {
|
||||||
verboseLog("Processing snap: %s with result: %v", snapDetails.InstanceName, snapDetails.Result)
|
verboseLog("Processing snap: %s", snapDetails.InstanceName)
|
||||||
if len(snapDetails.Result.Deltas) > 0 {
|
if len(snapDetails.Result.Deltas) > 0 {
|
||||||
for _, delta := range snapDetails.Result.Deltas {
|
for _, delta := range snapDetails.Result.Deltas {
|
||||||
|
verboseLog("Delta found for %s from %d to %d", snapDetails.InstanceName, delta.FromRevision, delta.ToRevision)
|
||||||
snapSize := float64(delta.Size)
|
snapSize := float64(delta.Size)
|
||||||
snapSizeMap[snapDetails.Result.Info.SuggestedName] = snapSize
|
snapSizeMap[snapDetails.Result.Info.SuggestedName] = snapSize
|
||||||
totalSnapSize += snapSize
|
totalSnapSize += snapSize
|
||||||
|
@ -32,6 +32,7 @@ func collectSnapDependencies(snapName, channel, fallbackChannel, snapsDir, asser
|
|||||||
|
|
||||||
var result *store.SnapActionResult
|
var result *store.SnapActionResult
|
||||||
var err error
|
var err error
|
||||||
|
workingChannel := ""
|
||||||
|
|
||||||
// Fetch or refresh snap information
|
// Fetch or refresh snap information
|
||||||
if oldSnap == nil || oldSnap.SnapID == "" || oldSnap.Revision.N == 0 {
|
if oldSnap == nil || oldSnap.SnapID == "" || oldSnap.Revision.N == 0 {
|
||||||
@ -41,18 +42,25 @@ func collectSnapDependencies(snapName, channel, fallbackChannel, snapsDir, asser
|
|||||||
result, err = fetchOrRefreshSnapInfo(snapName, nil, fallbackChannel)
|
result, err = fetchOrRefreshSnapInfo(snapName, nil, fallbackChannel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
workingChannel = fallbackChannel
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
workingChannel = channel
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
verboseLog("Old snap info: %s %d", oldSnap.SnapID, oldSnap.Revision.N)
|
||||||
result, err = fetchOrRefreshSnapInfo(snapName, oldSnap, channel)
|
result, err = fetchOrRefreshSnapInfo(snapName, oldSnap, channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "snap has no updates available") {
|
if strings.Contains(err.Error(), "snap has no updates available") {
|
||||||
result, err = fetchOrRefreshSnapInfo(snapName, nil, channel)
|
result, err = fetchOrRefreshSnapInfo(snapName, nil, channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
workingChannel = channel
|
||||||
}
|
}
|
||||||
} else if strings.Contains(err.Error(), "no snap revision available as specified") {
|
} else if strings.Contains(err.Error(), "no snap revision available as specified") {
|
||||||
result, err = fetchOrRefreshSnapInfo(snapName, oldSnap, fallbackChannel)
|
result, err = fetchOrRefreshSnapInfo(snapName, oldSnap, fallbackChannel)
|
||||||
@ -61,14 +69,20 @@ func collectSnapDependencies(snapName, channel, fallbackChannel, snapsDir, asser
|
|||||||
result, err = fetchOrRefreshSnapInfo(snapName, nil, fallbackChannel)
|
result, err = fetchOrRefreshSnapInfo(snapName, nil, fallbackChannel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
workingChannel = fallbackChannel
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
workingChannel = fallbackChannel
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
workingChannel = channel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,9 +92,10 @@ func collectSnapDependencies(snapName, channel, fallbackChannel, snapsDir, asser
|
|||||||
|
|
||||||
info := result.Info
|
info := result.Info
|
||||||
newSnap := &store.CurrentSnap{
|
newSnap := &store.CurrentSnap{
|
||||||
InstanceName: snapName,
|
InstanceName: snapName,
|
||||||
SnapID: info.SnapID,
|
SnapID: info.SnapID,
|
||||||
Revision: snap.Revision{N: info.Revision.N},
|
Revision: snap.Revision{N: info.Revision.N},
|
||||||
|
TrackingChannel: workingChannel,
|
||||||
}
|
}
|
||||||
snapInCurrentSnaps, oldRevision := isSnapInCurrentSnaps(snapName)
|
snapInCurrentSnaps, oldRevision := isSnapInCurrentSnaps(snapName)
|
||||||
if snapInCurrentSnaps {
|
if snapInCurrentSnaps {
|
||||||
@ -176,7 +191,7 @@ func fetchOrRefreshSnapInfo(snapName string, currentSnap *store.CurrentSnap, cha
|
|||||||
results, _, err := storeClient.SnapAction(ctx, includeSnap, actions, nil, nil, nil)
|
results, _, err := storeClient.SnapAction(ctx, includeSnap, actions, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
verboseLog("SnapAction error for %s: %v", snapName, err)
|
verboseLog("SnapAction error for %s: %v", snapName, err)
|
||||||
if strings.Contains(err.Error(), "snap has no updates available") && currentSnap != nil {
|
if (strings.Contains(err.Error(), "snap has no updates available") || strings.Contains(err.Error(), "no snap revision available as specified")) && currentSnap != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("snap action failed for %s: %w", snapName, err)
|
return nil, fmt.Errorf("snap action failed for %s: %w", snapName, err)
|
||||||
@ -232,6 +247,12 @@ func findPreviousSnap(downloadDir, assertionsDir, snapName string) (string, *sto
|
|||||||
assertFilePath := filepath.Join(assertionsDir, strings.Replace(file.Name(), ".snap", ".assert", 1))
|
assertFilePath := filepath.Join(assertionsDir, strings.Replace(file.Name(), ".snap", ".assert", 1))
|
||||||
currentSnap = parseSnapInfo(assertFilePath, snapName)
|
currentSnap = parseSnapInfo(assertFilePath, snapName)
|
||||||
currentSnap.Revision.N = revision
|
currentSnap.Revision.N = revision
|
||||||
|
trackingChannel, err := getChannelName(snapName)
|
||||||
|
if err != nil {
|
||||||
|
verboseLog("Failed to get existing channel name for %s", snapName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
currentSnap.TrackingChannel = "latest/" + trackingChannel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,42 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"github.com/snapcore/snapd/store"
|
"github.com/snapcore/snapd/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type seed struct {
|
||||||
|
Snaps []struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Channel string `yaml:"channel"`
|
||||||
|
File string `yaml:"file"`
|
||||||
|
} `yaml:"snaps"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// getChannelName returns the channel name for a specific snap name
|
||||||
|
func getChannelName(snapName string) (string, error) {
|
||||||
|
file, err := ioutil.ReadFile(seedYaml)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to read seed.yaml: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var seedData seed
|
||||||
|
if err := yaml.Unmarshal(file, &seedData); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to parse seed.yaml: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, snap := range seedData.Snaps {
|
||||||
|
if snap.Name == snapName {
|
||||||
|
return snap.Channel, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("snap %s not found in seed.yaml", snapName)
|
||||||
|
}
|
||||||
|
|
||||||
// initializeSeedYaml ensures that seed.yaml exists; if not, creates it.
|
// initializeSeedYaml ensures that seed.yaml exists; if not, creates it.
|
||||||
func initializeSeedYaml(seedYaml string) {
|
func initializeSeedYaml() {
|
||||||
if _, err := os.Stat(seedYaml); os.IsNotExist(err) {
|
if _, err := os.Stat(seedYaml); os.IsNotExist(err) {
|
||||||
file, err := os.Create(seedYaml)
|
file, err := os.Create(seedYaml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -23,7 +52,7 @@ func initializeSeedYaml(seedYaml string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loadSeedData loads seed data from seed.yaml
|
// loadSeedData loads seed data from seed.yaml
|
||||||
func loadSeedData(seedYaml string) seed {
|
func loadSeedData() seed {
|
||||||
file, err := ioutil.ReadFile(seedYaml)
|
file, err := ioutil.ReadFile(seedYaml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to read seed.yaml: %v", err)
|
log.Fatalf("Failed to read seed.yaml: %v", err)
|
||||||
@ -38,7 +67,7 @@ func loadSeedData(seedYaml string) seed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loadExistingSnaps loads snaps from seed.yaml into a map
|
// loadExistingSnaps loads snaps from seed.yaml into a map
|
||||||
func loadExistingSnaps(seedYaml string) map[string]bool {
|
func loadExistingSnaps() map[string]bool {
|
||||||
file, err := ioutil.ReadFile(seedYaml)
|
file, err := ioutil.ReadFile(seedYaml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to read seed.yaml: %v", err)
|
log.Fatalf("Failed to read seed.yaml: %v", err)
|
||||||
@ -58,7 +87,7 @@ func loadExistingSnaps(seedYaml string) map[string]bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateSeedYaml updates the seed.yaml file with the current required snaps
|
// updateSeedYaml updates the seed.yaml file with the current required snaps
|
||||||
func updateSeedYaml(snapsDir, seedYaml string, currentSnaps []*store.CurrentSnap) error {
|
func updateSeedYaml(snapsDir string, currentSnaps []*store.CurrentSnap) error {
|
||||||
// Log the snaps to be written
|
// Log the snaps to be written
|
||||||
verboseLog("CurrentSnaps to be written to seed.yaml:")
|
verboseLog("CurrentSnaps to be written to seed.yaml:")
|
||||||
for _, snapInfo := range currentSnaps {
|
for _, snapInfo := range currentSnaps {
|
||||||
@ -92,7 +121,7 @@ func updateSeedYaml(snapsDir, seedYaml string, currentSnaps []*store.CurrentSnap
|
|||||||
File string `yaml:"file"`
|
File string `yaml:"file"`
|
||||||
}{
|
}{
|
||||||
Name: snapInfo.InstanceName,
|
Name: snapInfo.InstanceName,
|
||||||
Channel: "stable", // Assuming 'stable' channel; modify as needed
|
Channel: strings.Replace(snapInfo.TrackingChannel, "latest/", "", -1),
|
||||||
File: snapFileName,
|
File: snapFileName,
|
||||||
}
|
}
|
||||||
seedData.Snaps = append(seedData.Snaps, snapData)
|
seedData.Snaps = append(seedData.Snaps, snapData)
|
||||||
|
@ -148,3 +148,28 @@ func verifySnapIntegrity(filePath, expectedChecksum string) bool {
|
|||||||
}
|
}
|
||||||
return checksumMatches
|
return checksumMatches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the raw VERSION_ID from /etc/os-release to use for branch detection
|
||||||
|
func getVersionID() (string, error) {
|
||||||
|
file, err := os.Open("/etc/os-release")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to open /etc/os-release: %w", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.HasPrefix(line, "VERSION_ID=") {
|
||||||
|
// Remove the prefix and any surrounding quotes
|
||||||
|
versionID := strings.Trim(strings.SplitN(line, "=", 2)[1], `"`)
|
||||||
|
return versionID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return "", fmt.Errorf("error reading /etc/os-release: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("VERSION_ID not found in /etc/os-release")
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user