156 lines
4.5 KiB
Go
156 lines
4.5 KiB
Go
|
// Copyright (C) 2024 Jared Allard
|
||
|
//
|
||
|
// This program is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU Affero General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// This program is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU Affero General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU Affero General Public License
|
||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
|
||
|
package packages
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
|
||
|
"github.com/jaredallard/overlay/.tools/internal/steps"
|
||
|
"gopkg.in/yaml.v3"
|
||
|
)
|
||
|
|
||
|
// Resolver is the resolver to use to determine if an update is available.
|
||
|
type Resolver string
|
||
|
|
||
|
// Contains the supported resolvers.
|
||
|
const (
|
||
|
// GitResolver is the git resolver.
|
||
|
GitResolver Resolver = "git"
|
||
|
|
||
|
// APTResolver is a version resolver powered by an APT repository.
|
||
|
APTResolver Resolver = "apt"
|
||
|
)
|
||
|
|
||
|
// List contains all of the packages that should be updated.
|
||
|
type List map[string]Package
|
||
|
|
||
|
// Package is an package that should be updated by the updater.
|
||
|
type Package struct {
|
||
|
// Name of the ebuild. This is only set when loaded from the config.
|
||
|
// It is a readonly field.
|
||
|
Name string `yaml:"name,omitempty"`
|
||
|
|
||
|
// Resolver to use to determine if an update is available.
|
||
|
// Currently only "git" is supported.
|
||
|
Resolver Resolver `yaml:"resolver"`
|
||
|
|
||
|
// GitOptions is the options for the git resolver.
|
||
|
GitOptions GitOptions `yaml:"options"`
|
||
|
|
||
|
// APTOptions is the options for the APT resolver.
|
||
|
APTOptions APTOptions `yaml:"options"`
|
||
|
|
||
|
// Steps are the steps to use to update the ebuild, if not set it
|
||
|
// defaults to a copy the existing ebuild and regenerate the manifest.
|
||
|
Steps steps.Steps `yaml:"steps"`
|
||
|
}
|
||
|
|
||
|
// LoadPackages returns a map of packages from the provided path.
|
||
|
func LoadPackages(path string) (List, error) {
|
||
|
f, err := os.Open(path)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("failed to open ebuilds file: %w", err)
|
||
|
}
|
||
|
defer f.Close()
|
||
|
|
||
|
pkgs := make(List)
|
||
|
if err := yaml.NewDecoder(f).Decode(&pkgs); err != nil {
|
||
|
return nil, fmt.Errorf("failed to decode ebuilds: %w", err)
|
||
|
}
|
||
|
|
||
|
return pkgs, nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalYAML unmarshals the ebuild configuration from YAML while
|
||
|
// converting options into the appropriate type for the provided
|
||
|
// resolver.
|
||
|
func (p *Package) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||
|
var raw struct {
|
||
|
Resolver Resolver `yaml:"resolver"`
|
||
|
Options yaml.Node `yaml:"options"`
|
||
|
Steps steps.Steps
|
||
|
}
|
||
|
|
||
|
if err := unmarshal(&raw); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
p.Resolver = raw.Resolver
|
||
|
p.Steps = raw.Steps
|
||
|
|
||
|
switch p.Resolver {
|
||
|
case GitResolver:
|
||
|
if err := raw.Options.Decode(&p.GitOptions); err != nil {
|
||
|
return fmt.Errorf("failed to decode git options: %w", err)
|
||
|
}
|
||
|
case APTResolver:
|
||
|
if err := raw.Options.Decode(&p.APTOptions); err != nil {
|
||
|
return fmt.Errorf("failed to decode APT options: %w", err)
|
||
|
}
|
||
|
default:
|
||
|
return fmt.Errorf("unsupported resolver: %s", p.Resolver)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// UnmarshalYAML unmarshals the ebuilds from YAML while carrying the
|
||
|
// name from the key into the ebuild name.
|
||
|
func (l List) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||
|
pkgs := make(map[string]Package)
|
||
|
if err := unmarshal(&pkgs); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
for name, ebuild := range pkgs {
|
||
|
ebuild.Name = name
|
||
|
l[name] = ebuild
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// GitOptions is the options for the git resolver.
|
||
|
type GitOptions struct {
|
||
|
// URL is the URL to the git repository. Must be a valid option to
|
||
|
// 'git clone'.
|
||
|
URL string `yaml:"url"`
|
||
|
|
||
|
// Tags denote if tags should be used as the version source.
|
||
|
Tags bool `yaml:"tags"`
|
||
|
|
||
|
// ConsiderPreReleases denotes if pre-releases should be considered,
|
||
|
// when a tag is used and the version is able to be parsed as a
|
||
|
// semver. Defaults to false.
|
||
|
ConsiderPreReleases bool `yaml:"consider_pre_releases"`
|
||
|
}
|
||
|
|
||
|
// APTOptions contains the options for the APT resolver.
|
||
|
type APTOptions struct {
|
||
|
// Repository is the URL of the APT repository. Should match the
|
||
|
// following format:
|
||
|
// deb http://archive.ubuntu.com/ubuntu/ focal main
|
||
|
Repository string `yaml:"repository"`
|
||
|
|
||
|
// Package is the name of the package to watch versions for.
|
||
|
Package string `yaml:"package"`
|
||
|
|
||
|
// StripRelease is a boolean that denotes if extra release information
|
||
|
// (in the context of a semver) should be stripped. Defaults to true.
|
||
|
StripRelease *bool `yaml:"strip_release"`
|
||
|
}
|