mirror of
https://github.com/safing/portbase
synced 2025-09-01 18:19:57 +00:00
159 lines
4.1 KiB
Go
159 lines
4.1 KiB
Go
package updater
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/safing/portbase/log"
|
|
"github.com/safing/portbase/utils"
|
|
)
|
|
|
|
// ScanStorage scans root within the storage dir and adds found resources to the registry. If an error occurred, it is logged and the last error is returned. Everything that was found despite errors is added to the registry anyway. Leave root empty to scan the full storage dir.
|
|
func (reg *ResourceRegistry) ScanStorage(root string) error {
|
|
var lastError error
|
|
|
|
// prep root
|
|
if root == "" {
|
|
root = reg.storageDir.Path
|
|
} else {
|
|
var err error
|
|
root, err = filepath.Abs(root)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !strings.HasPrefix(root, reg.storageDir.Path) {
|
|
return errors.New("supplied scan root path not within storage")
|
|
}
|
|
}
|
|
|
|
// walk fs
|
|
_ = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
lastError = fmt.Errorf("%s: could not read %s: %s", reg.Name, path, err)
|
|
log.Warning(lastError.Error())
|
|
return nil
|
|
}
|
|
|
|
// get relative path to storage
|
|
relativePath, err := filepath.Rel(reg.storageDir.Path, path)
|
|
if err != nil {
|
|
lastError = fmt.Errorf("%s: could not get relative path of %s: %s", reg.Name, path, err)
|
|
log.Warning(lastError.Error())
|
|
return nil
|
|
}
|
|
// ignore files in tmp dir
|
|
if strings.HasPrefix(relativePath, reg.tmpDir.Path) {
|
|
return nil
|
|
}
|
|
|
|
// convert to identifier and version
|
|
relativePath = filepath.ToSlash(relativePath)
|
|
identifier, version, ok := GetIdentifierAndVersion(relativePath)
|
|
if !ok {
|
|
// file does not conform to format
|
|
return nil
|
|
}
|
|
|
|
// save
|
|
err = reg.AddResource(identifier, version, true, false, false)
|
|
if err != nil {
|
|
lastError = fmt.Errorf("%s: could not get add resource %s v%s: %s", reg.Name, identifier, version, err)
|
|
log.Warning(lastError.Error())
|
|
}
|
|
return nil
|
|
})
|
|
|
|
return lastError
|
|
}
|
|
|
|
// LoadIndexes loads the current release indexes from disk and will fetch a new version if not available and online.
|
|
func (reg *ResourceRegistry) LoadIndexes() error {
|
|
err := reg.loadIndexFile("stable.json", true, false)
|
|
if err != nil {
|
|
err = reg.downloadIndex("stable.json", true, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = reg.loadIndexFile("beta.json", false, true)
|
|
if err != nil {
|
|
err = reg.downloadIndex("beta.json", false, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (reg *ResourceRegistry) loadIndexFile(name string, stableRelease, betaRelease bool) error {
|
|
data, err := ioutil.ReadFile(filepath.Join(reg.storageDir.Path, name))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
releases := make(map[string]string)
|
|
err = json.Unmarshal(data, &releases)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(releases) == 0 {
|
|
return fmt.Errorf("%s is empty", name)
|
|
}
|
|
|
|
err = reg.AddResources(releases, false, stableRelease, betaRelease)
|
|
if err != nil {
|
|
log.Warningf("%s: failed to add resource: %s", reg.Name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CreateSymlinks creates a directory structure with unversions symlinks to the given updates list.
|
|
func (reg *ResourceRegistry) CreateSymlinks(symlinkRoot *utils.DirStructure) error {
|
|
err := os.RemoveAll(symlinkRoot.Path)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to wipe symlink root: %s", err)
|
|
}
|
|
|
|
err = symlinkRoot.Ensure()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create symlink root: %s", err)
|
|
}
|
|
|
|
reg.RLock()
|
|
defer reg.RUnlock()
|
|
|
|
for _, res := range reg.resources {
|
|
if res.SelectedVersion == nil {
|
|
return fmt.Errorf("no selected version available for %s", res.Identifier)
|
|
}
|
|
|
|
targetPath := res.SelectedVersion.storagePath()
|
|
linkPath := filepath.Join(symlinkRoot.Path, filepath.FromSlash(res.Identifier))
|
|
linkPathDir := filepath.Dir(linkPath)
|
|
|
|
err = symlinkRoot.EnsureAbsPath(linkPathDir)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create dir for link: %s", err)
|
|
}
|
|
|
|
relativeTargetPath, err := filepath.Rel(linkPathDir, targetPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get relative target path: %s", err)
|
|
}
|
|
|
|
err = os.Symlink(relativeTargetPath, linkPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to link %s: %s", res.Identifier, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|