2017-07-27 02:30:48 +02:00
|
|
|
// Package snapcraft implements the Pipe interface providing Snapcraft bindings.
|
2021-11-23 15:18:09 +02:00
|
|
|
//
|
|
|
|
// nolint:tagliatelle
|
2017-07-27 02:30:48 +02:00
|
|
|
package snapcraft
|
|
|
|
|
|
|
|
import (
|
2020-09-21 19:47:51 +02:00
|
|
|
"errors"
|
2017-08-02 14:06:28 +02:00
|
|
|
"fmt"
|
2017-07-28 03:05:43 +02:00
|
|
|
"os"
|
2017-07-27 02:30:48 +02:00
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2018-06-25 02:12:53 +02:00
|
|
|
"strings"
|
2017-12-17 21:25:04 +02:00
|
|
|
|
2022-06-22 02:11:15 +02:00
|
|
|
"github.com/caarlos0/log"
|
2017-12-18 13:00:19 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/artifact"
|
2021-07-25 00:59:43 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/gio"
|
2019-05-29 14:13:52 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/ids"
|
2018-09-12 19:18:01 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/pipe"
|
2018-07-10 07:08:22 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/semerrgroup"
|
2018-07-09 05:47:30 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/tmpl"
|
2022-04-12 03:43:22 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/yaml"
|
2019-05-27 17:47:05 +02:00
|
|
|
"github.com/goreleaser/goreleaser/pkg/config"
|
2018-08-15 04:50:20 +02:00
|
|
|
"github.com/goreleaser/goreleaser/pkg/context"
|
2017-07-27 02:30:48 +02:00
|
|
|
)
|
|
|
|
|
2021-07-24 05:23:59 +02:00
|
|
|
const releasesExtra = "releases"
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// ErrNoSnapcraft is shown when snapcraft cannot be found in $PATH.
|
2017-07-27 02:30:48 +02:00
|
|
|
var ErrNoSnapcraft = errors.New("snapcraft not present in $PATH")
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// ErrNoDescription is shown when no description provided.
|
2017-08-17 23:41:08 +02:00
|
|
|
var ErrNoDescription = errors.New("no description provided for snapcraft")
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// ErrNoSummary is shown when no summary provided.
|
2017-08-17 23:41:08 +02:00
|
|
|
var ErrNoSummary = errors.New("no summary provided for snapcraft")
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Metadata to generate the snap package.
|
2017-09-15 02:19:56 +02:00
|
|
|
type Metadata struct {
|
2017-07-27 02:30:48 +02:00
|
|
|
Name string
|
2023-06-25 04:38:24 +02:00
|
|
|
Title string `yaml:",omitempty"`
|
2017-07-27 02:30:48 +02:00
|
|
|
Version string
|
|
|
|
Summary string
|
|
|
|
Description string
|
2023-06-25 04:38:24 +02:00
|
|
|
Icon string `yaml:",omitempty"`
|
2019-04-18 22:21:40 +02:00
|
|
|
Base string `yaml:",omitempty"`
|
2019-04-17 22:26:30 +02:00
|
|
|
License string `yaml:",omitempty"`
|
2017-07-27 02:30:48 +02:00
|
|
|
Grade string `yaml:",omitempty"`
|
|
|
|
Confinement string `yaml:",omitempty"`
|
|
|
|
Architectures []string
|
2023-06-12 14:03:24 +02:00
|
|
|
Assumes []string `yaml:",omitempty"`
|
2021-03-17 15:18:56 +02:00
|
|
|
Layout map[string]LayoutMetadata `yaml:",omitempty"`
|
2017-08-04 07:42:55 +02:00
|
|
|
Apps map[string]AppMetadata
|
2023-06-12 14:03:24 +02:00
|
|
|
Hooks map[string]interface{} `yaml:",omitempty"`
|
2019-03-14 14:56:11 +02:00
|
|
|
Plugs map[string]interface{} `yaml:",omitempty"`
|
2017-07-27 02:30:48 +02:00
|
|
|
}
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// AppMetadata for the binaries that will be in the snap package.
|
2022-03-06 04:16:43 +02:00
|
|
|
// See: https://snapcraft.io/docs/snapcraft-app-and-service-metadata
|
2017-08-04 07:42:55 +02:00
|
|
|
type AppMetadata struct {
|
2022-03-06 04:16:43 +02:00
|
|
|
Command string
|
|
|
|
|
|
|
|
Adapter string `yaml:",omitempty"`
|
|
|
|
After []string `yaml:",omitempty"`
|
|
|
|
Aliases []string `yaml:",omitempty"`
|
|
|
|
Autostart string `yaml:",omitempty"`
|
|
|
|
Before []string `yaml:",omitempty"`
|
|
|
|
BusName string `yaml:"bus-name,omitempty"`
|
|
|
|
CommandChain []string `yaml:"command-chain,omitempty"`
|
|
|
|
CommonID string `yaml:"common-id,omitempty"`
|
|
|
|
Completer string `yaml:",omitempty"`
|
|
|
|
Daemon string `yaml:",omitempty"`
|
|
|
|
Desktop string `yaml:",omitempty"`
|
|
|
|
Environment map[string]interface{} `yaml:",omitempty"`
|
|
|
|
Extensions []string `yaml:",omitempty"`
|
|
|
|
InstallMode string `yaml:"install-mode,omitempty"`
|
|
|
|
Passthrough map[string]interface{} `yaml:",omitempty"`
|
|
|
|
Plugs []string `yaml:",omitempty"`
|
|
|
|
PostStopCommand string `yaml:"post-stop-command,omitempty"`
|
|
|
|
RefreshMode string `yaml:"refresh-mode,omitempty"`
|
|
|
|
ReloadCommand string `yaml:"reload-command,omitempty"`
|
|
|
|
RestartCondition string `yaml:"restart-condition,omitempty"`
|
|
|
|
RestartDelay string `yaml:"restart-delay,omitempty"`
|
|
|
|
Slots []string `yaml:",omitempty"`
|
|
|
|
Sockets map[string]interface{} `yaml:",omitempty"`
|
|
|
|
StartTimeout string `yaml:"start-timeout,omitempty"`
|
|
|
|
StopCommand string `yaml:"stop-command,omitempty"`
|
|
|
|
StopMode string `yaml:"stop-mode,omitempty"`
|
|
|
|
StopTimeout string `yaml:"stop-timeout,omitempty"`
|
|
|
|
Timer string `yaml:",omitempty"`
|
|
|
|
WatchdogTimeout string `yaml:"watchdog-timeout,omitempty"`
|
2017-07-27 02:30:48 +02:00
|
|
|
}
|
|
|
|
|
2021-03-17 15:18:56 +02:00
|
|
|
type LayoutMetadata struct {
|
|
|
|
Symlink string `yaml:",omitempty"`
|
|
|
|
Bind string `yaml:",omitempty"`
|
|
|
|
BindFile string `yaml:"bind-file,omitempty"`
|
|
|
|
Type string `yaml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
2022-04-14 02:29:39 +02:00
|
|
|
const defaultNameTemplate = `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}`
|
2017-12-27 01:44:11 +02:00
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Pipe for snapcraft packaging.
|
2017-07-27 02:30:48 +02:00
|
|
|
type Pipe struct{}
|
|
|
|
|
2023-03-20 03:17:18 +02:00
|
|
|
func (Pipe) String() string { return "snapcraft packages" }
|
2023-06-20 14:33:59 +02:00
|
|
|
func (Pipe) ContinueOnError() bool { return true }
|
2023-03-20 03:17:18 +02:00
|
|
|
func (Pipe) Skip(ctx *context.Context) bool { return len(ctx.Config.Snapcrafts) == 0 }
|
|
|
|
func (Pipe) Dependencies(_ *context.Context) []string { return []string{"snapcraft"} }
|
2017-07-27 02:30:48 +02:00
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Default sets the pipe defaults.
|
2017-12-27 01:44:11 +02:00
|
|
|
func (Pipe) Default(ctx *context.Context) error {
|
2021-04-25 19:20:49 +02:00
|
|
|
ids := ids.New("snapcrafts")
|
2019-05-27 17:47:05 +02:00
|
|
|
for i := range ctx.Config.Snapcrafts {
|
2021-04-25 19:20:49 +02:00
|
|
|
snap := &ctx.Config.Snapcrafts[i]
|
2019-05-27 17:47:05 +02:00
|
|
|
if snap.NameTemplate == "" {
|
|
|
|
snap.NameTemplate = defaultNameTemplate
|
|
|
|
}
|
2023-01-24 03:05:24 +02:00
|
|
|
grade, err := tmpl.New(ctx).Apply(snap.Grade)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
snap.Grade = grade
|
|
|
|
if snap.Grade == "" {
|
|
|
|
snap.Grade = "stable"
|
|
|
|
}
|
2021-07-24 05:23:59 +02:00
|
|
|
if len(snap.ChannelTemplates) == 0 {
|
|
|
|
switch snap.Grade {
|
|
|
|
case "devel":
|
|
|
|
snap.ChannelTemplates = []string{"edge", "beta"}
|
|
|
|
default:
|
|
|
|
snap.ChannelTemplates = []string{"edge", "beta", "candidate", "stable"}
|
|
|
|
}
|
|
|
|
}
|
2019-05-27 17:47:05 +02:00
|
|
|
if len(snap.Builds) == 0 {
|
|
|
|
for _, b := range ctx.Config.Builds {
|
|
|
|
snap.Builds = append(snap.Builds, b.ID)
|
|
|
|
}
|
|
|
|
}
|
2019-05-29 14:13:52 +02:00
|
|
|
ids.Inc(snap.ID)
|
2017-12-27 01:44:11 +02:00
|
|
|
}
|
2019-05-29 14:13:52 +02:00
|
|
|
return ids.Validate()
|
2017-12-27 01:44:11 +02:00
|
|
|
}
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Run the pipe.
|
2017-07-27 02:30:48 +02:00
|
|
|
func (Pipe) Run(ctx *context.Context) error {
|
2019-05-27 17:47:05 +02:00
|
|
|
for _, snap := range ctx.Config.Snapcrafts {
|
|
|
|
// TODO: deal with pipe.skip?
|
|
|
|
if err := doRun(ctx, snap); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func doRun(ctx *context.Context, snap config.Snapcraft) error {
|
2022-04-03 03:58:33 +02:00
|
|
|
tpl := tmpl.New(ctx)
|
2023-06-30 19:46:53 +02:00
|
|
|
if err := tpl.ApplyAll(
|
|
|
|
&snap.Summary,
|
|
|
|
&snap.Description,
|
2023-08-03 14:17:26 +02:00
|
|
|
&snap.Disable,
|
2023-06-30 19:46:53 +02:00
|
|
|
); err != nil {
|
2022-04-03 03:58:33 +02:00
|
|
|
return err
|
|
|
|
}
|
2023-08-03 14:17:26 +02:00
|
|
|
if snap.Disable == "true" {
|
|
|
|
return pipe.Skip("configuration is disabled")
|
|
|
|
}
|
2019-05-27 17:47:05 +02:00
|
|
|
if snap.Summary == "" && snap.Description == "" {
|
2018-09-12 19:18:01 +02:00
|
|
|
return pipe.Skip("no summary nor description were provided")
|
2017-07-27 02:30:48 +02:00
|
|
|
}
|
2019-05-27 17:47:05 +02:00
|
|
|
if snap.Summary == "" {
|
2017-08-17 23:41:08 +02:00
|
|
|
return ErrNoSummary
|
|
|
|
}
|
2019-05-27 17:47:05 +02:00
|
|
|
if snap.Description == "" {
|
2017-08-17 23:41:08 +02:00
|
|
|
return ErrNoDescription
|
2017-07-27 02:30:48 +02:00
|
|
|
}
|
2023-06-30 19:46:53 +02:00
|
|
|
if _, err := exec.LookPath("snapcraft"); err != nil {
|
2017-07-27 02:30:48 +02:00
|
|
|
return ErrNoSnapcraft
|
|
|
|
}
|
|
|
|
|
2021-04-25 19:20:49 +02:00
|
|
|
g := semerrgroup.New(ctx.Parallelism)
|
2017-12-17 21:25:04 +02:00
|
|
|
for platform, binaries := range ctx.Artifacts.Filter(
|
|
|
|
artifact.And(
|
|
|
|
artifact.ByGoos("linux"),
|
|
|
|
artifact.ByType(artifact.Binary),
|
2019-05-27 17:47:05 +02:00
|
|
|
artifact.ByIDs(snap.Builds...),
|
2017-12-17 21:25:04 +02:00
|
|
|
),
|
|
|
|
).GroupByPlatform() {
|
2021-11-14 03:23:11 +02:00
|
|
|
arch := linuxArch(platform)
|
2020-02-06 03:08:18 +02:00
|
|
|
if !isValidArch(arch) {
|
2018-06-20 14:39:10 +02:00
|
|
|
log.WithField("arch", arch).Warn("ignored unsupported arch")
|
|
|
|
continue
|
|
|
|
}
|
2017-12-17 21:25:04 +02:00
|
|
|
binaries := binaries
|
|
|
|
g.Go(func() error {
|
2019-05-27 17:47:05 +02:00
|
|
|
return create(ctx, snap, arch, binaries)
|
2017-12-17 21:25:04 +02:00
|
|
|
})
|
2017-07-27 02:30:48 +02:00
|
|
|
}
|
|
|
|
return g.Wait()
|
|
|
|
}
|
|
|
|
|
2020-02-06 03:08:18 +02:00
|
|
|
func isValidArch(arch string) bool {
|
|
|
|
// https://snapcraft.io/docs/architectures
|
2022-04-16 04:25:32 +02:00
|
|
|
for _, a := range []string{"s390x", "ppc64el", "arm64", "armhf", "i386", "amd64"} {
|
2020-02-06 03:08:18 +02:00
|
|
|
if arch == a {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Publish packages.
|
2018-10-20 19:25:46 +02:00
|
|
|
func (Pipe) Publish(ctx *context.Context) error {
|
|
|
|
snaps := ctx.Artifacts.Filter(artifact.ByType(artifact.PublishableSnapcraft)).List()
|
|
|
|
for _, snap := range snaps {
|
2022-08-07 17:32:15 +02:00
|
|
|
if err := push(ctx, snap); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-10-20 19:25:46 +02:00
|
|
|
}
|
2022-08-07 17:32:15 +02:00
|
|
|
return nil
|
2018-10-20 19:25:46 +02:00
|
|
|
}
|
|
|
|
|
2019-08-12 22:44:48 +02:00
|
|
|
func create(ctx *context.Context, snap config.Snapcraft, arch string, binaries []*artifact.Artifact) error {
|
2021-04-25 19:20:49 +02:00
|
|
|
log := log.WithField("arch", arch)
|
2023-06-06 16:46:02 +02:00
|
|
|
folder, err := tmpl.New(ctx).WithArtifact(binaries[0]).Apply(snap.NameTemplate)
|
2017-12-17 21:25:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-01-26 17:23:08 +02:00
|
|
|
|
2021-07-24 05:23:59 +02:00
|
|
|
channels, err := processChannelsTemplates(ctx, snap)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-07-28 03:05:43 +02:00
|
|
|
// prime is the directory that then will be compressed to make the .snap package.
|
2021-04-25 19:20:49 +02:00
|
|
|
folderDir := filepath.Join(ctx.Config.Dist, folder)
|
|
|
|
primeDir := filepath.Join(folderDir, "prime")
|
|
|
|
metaDir := filepath.Join(primeDir, "meta")
|
2017-11-26 16:09:12 +02:00
|
|
|
// #nosec
|
2021-04-25 19:20:49 +02:00
|
|
|
if err = os.MkdirAll(metaDir, 0o755); err != nil {
|
2017-07-28 03:05:43 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-06-06 20:07:18 +02:00
|
|
|
for _, file := range snap.Files {
|
|
|
|
if file.Destination == "" {
|
|
|
|
file.Destination = file.Source
|
|
|
|
}
|
|
|
|
if file.Mode == 0 {
|
2021-04-25 19:20:49 +02:00
|
|
|
file.Mode = 0o644
|
2020-06-06 20:07:18 +02:00
|
|
|
}
|
2021-07-24 05:23:59 +02:00
|
|
|
destinationDir := filepath.Join(primeDir, filepath.Dir(file.Destination))
|
|
|
|
if err := os.MkdirAll(destinationDir, 0o755); err != nil {
|
|
|
|
return fmt.Errorf("failed to create directory '%s': %w", destinationDir, err)
|
2020-06-06 20:07:18 +02:00
|
|
|
}
|
2021-07-25 00:59:43 +02:00
|
|
|
if err := gio.CopyWithMode(file.Source, filepath.Join(primeDir, file.Destination), os.FileMode(file.Mode)); err != nil {
|
2020-09-21 19:47:51 +02:00
|
|
|
return fmt.Errorf("failed to link extra file '%s': %w", file.Source, err)
|
2020-06-06 20:07:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-25 19:20:49 +02:00
|
|
|
file := filepath.Join(primeDir, "meta", "snap.yaml")
|
2018-10-27 00:31:06 +02:00
|
|
|
log.WithField("file", file).Debug("creating snap metadata")
|
2017-07-27 02:30:48 +02:00
|
|
|
|
2021-04-25 19:20:49 +02:00
|
|
|
metadata := &Metadata{
|
2017-07-27 02:30:48 +02:00
|
|
|
Version: ctx.Version,
|
2019-05-27 17:47:05 +02:00
|
|
|
Summary: snap.Summary,
|
|
|
|
Description: snap.Description,
|
|
|
|
Grade: snap.Grade,
|
|
|
|
Confinement: snap.Confinement,
|
2017-07-27 02:30:48 +02:00
|
|
|
Architectures: []string{arch},
|
2021-03-17 15:18:56 +02:00
|
|
|
Layout: map[string]LayoutMetadata{},
|
2018-12-12 22:24:22 +02:00
|
|
|
Apps: map[string]AppMetadata{},
|
2017-07-27 02:30:48 +02:00
|
|
|
}
|
2018-02-16 14:35:44 +02:00
|
|
|
|
2023-06-12 14:03:24 +02:00
|
|
|
if snap.Title != "" {
|
|
|
|
metadata.Title = snap.Title
|
|
|
|
}
|
|
|
|
|
|
|
|
if snap.Icon != "" {
|
|
|
|
metadata.Icon = snap.Icon
|
|
|
|
}
|
|
|
|
|
2019-05-27 17:47:05 +02:00
|
|
|
if snap.Base != "" {
|
|
|
|
metadata.Base = snap.Base
|
2019-04-18 22:21:40 +02:00
|
|
|
}
|
|
|
|
|
2019-05-27 17:47:05 +02:00
|
|
|
if snap.License != "" {
|
|
|
|
metadata.License = snap.License
|
2019-04-17 22:26:30 +02:00
|
|
|
}
|
|
|
|
|
2018-02-16 14:35:44 +02:00
|
|
|
metadata.Name = ctx.Config.ProjectName
|
2019-05-27 17:47:05 +02:00
|
|
|
if snap.Name != "" {
|
|
|
|
metadata.Name = snap.Name
|
2017-08-07 18:28:04 +02:00
|
|
|
}
|
2017-07-27 02:30:48 +02:00
|
|
|
|
2021-03-17 15:18:56 +02:00
|
|
|
for targetPath, layout := range snap.Layout {
|
|
|
|
metadata.Layout[targetPath] = LayoutMetadata{
|
|
|
|
Symlink: layout.Symlink,
|
|
|
|
Bind: layout.Bind,
|
|
|
|
BindFile: layout.BindFile,
|
|
|
|
Type: layout.Type,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-26 17:23:08 +02:00
|
|
|
// if the user didn't specify any apps then
|
|
|
|
// default to the main binary being the command:
|
|
|
|
if len(snap.Apps) == 0 {
|
2021-04-25 19:20:49 +02:00
|
|
|
name := snap.Name
|
2020-01-30 15:57:07 +02:00
|
|
|
if name == "" {
|
2021-06-26 18:57:10 +02:00
|
|
|
name = filepath.Base(binaries[0].Name)
|
2017-08-20 21:35:46 +02:00
|
|
|
}
|
2020-01-30 15:57:07 +02:00
|
|
|
metadata.Apps[name] = AppMetadata{
|
2021-06-26 18:57:10 +02:00
|
|
|
Command: filepath.Base(filepath.Base(binaries[0].Name)),
|
2017-08-04 07:42:55 +02:00
|
|
|
}
|
2020-01-26 17:23:08 +02:00
|
|
|
}
|
2017-07-28 03:05:43 +02:00
|
|
|
|
2020-01-26 17:23:08 +02:00
|
|
|
for _, binary := range binaries {
|
|
|
|
// build the binaries and link resources
|
2017-07-28 03:05:43 +02:00
|
|
|
destBinaryPath := filepath.Join(primeDir, filepath.Base(binary.Path))
|
2018-12-13 14:09:36 +02:00
|
|
|
log.WithField("src", binary.Path).
|
|
|
|
WithField("dst", destBinaryPath).
|
2021-07-25 00:59:43 +02:00
|
|
|
Debug("copying")
|
2020-01-26 17:23:08 +02:00
|
|
|
|
2021-07-25 00:59:43 +02:00
|
|
|
if err = gio.CopyWithMode(binary.Path, destBinaryPath, 0o555); err != nil {
|
|
|
|
return fmt.Errorf("failed to copy binary: %w", err)
|
2018-12-12 22:32:22 +02:00
|
|
|
}
|
2020-07-20 15:36:09 +02:00
|
|
|
}
|
2019-06-23 03:37:55 +02:00
|
|
|
|
2020-07-20 15:36:09 +02:00
|
|
|
// setup the apps: directive for each binary
|
|
|
|
for name, config := range snap.Apps {
|
|
|
|
command := name
|
|
|
|
if config.Command != "" {
|
|
|
|
command = config.Command
|
|
|
|
}
|
2020-01-26 17:23:08 +02:00
|
|
|
|
2020-07-20 15:36:09 +02:00
|
|
|
// TODO: test that the correct binary is used in Command
|
|
|
|
// See https://github.com/goreleaser/goreleaser/pull/1449
|
|
|
|
appMetadata := AppMetadata{
|
|
|
|
Command: strings.TrimSpace(strings.Join([]string{
|
|
|
|
command,
|
|
|
|
config.Args,
|
|
|
|
}, " ")),
|
2022-03-06 04:16:43 +02:00
|
|
|
Adapter: config.Adapter,
|
|
|
|
After: config.After,
|
|
|
|
Aliases: config.Aliases,
|
|
|
|
Autostart: config.Autostart,
|
|
|
|
Before: config.Before,
|
|
|
|
BusName: config.BusName,
|
|
|
|
CommandChain: config.CommandChain,
|
|
|
|
CommonID: config.CommonID,
|
|
|
|
Completer: config.Completer,
|
2020-10-06 15:59:53 +02:00
|
|
|
Daemon: config.Daemon,
|
2022-03-06 04:16:43 +02:00
|
|
|
Desktop: config.Desktop,
|
|
|
|
Environment: config.Environment,
|
|
|
|
Extensions: config.Extensions,
|
|
|
|
InstallMode: config.InstallMode,
|
|
|
|
Passthrough: config.Passthrough,
|
|
|
|
Plugs: config.Plugs,
|
|
|
|
PostStopCommand: config.PostStopCommand,
|
|
|
|
RefreshMode: config.RefreshMode,
|
|
|
|
ReloadCommand: config.ReloadCommand,
|
2020-10-06 15:59:53 +02:00
|
|
|
RestartCondition: config.RestartCondition,
|
2022-03-06 04:16:43 +02:00
|
|
|
RestartDelay: config.RestartDelay,
|
|
|
|
Slots: config.Slots,
|
|
|
|
Sockets: config.Sockets,
|
|
|
|
StartTimeout: config.StartTimeout,
|
|
|
|
StopCommand: config.StopCommand,
|
|
|
|
StopMode: config.StopMode,
|
|
|
|
StopTimeout: config.StopTimeout,
|
|
|
|
Timer: config.Timer,
|
|
|
|
WatchdogTimeout: config.WatchdogTimeout,
|
2020-07-20 15:36:09 +02:00
|
|
|
}
|
2020-06-06 20:07:18 +02:00
|
|
|
|
2020-07-20 15:36:09 +02:00
|
|
|
if config.Completer != "" {
|
|
|
|
destCompleterPath := filepath.Join(primeDir, config.Completer)
|
2021-04-25 19:20:49 +02:00
|
|
|
if err := os.MkdirAll(filepath.Dir(destCompleterPath), 0o755); err != nil {
|
2020-09-21 19:47:51 +02:00
|
|
|
return fmt.Errorf("failed to create folder: %w", err)
|
2020-01-30 15:57:07 +02:00
|
|
|
}
|
2020-07-20 15:36:09 +02:00
|
|
|
log.WithField("src", config.Completer).
|
|
|
|
WithField("dst", destCompleterPath).
|
2021-07-24 05:23:59 +02:00
|
|
|
Debug("copy")
|
|
|
|
|
2021-07-25 00:59:43 +02:00
|
|
|
if err := gio.CopyWithMode(config.Completer, destCompleterPath, 0o644); err != nil {
|
2021-07-24 05:23:59 +02:00
|
|
|
return fmt.Errorf("failed to copy completer: %w", err)
|
2020-07-20 15:36:09 +02:00
|
|
|
}
|
2021-07-24 05:23:59 +02:00
|
|
|
|
2020-07-20 15:36:09 +02:00
|
|
|
appMetadata.Completer = config.Completer
|
2020-01-26 17:23:08 +02:00
|
|
|
}
|
2020-07-20 15:36:09 +02:00
|
|
|
|
|
|
|
metadata.Apps[name] = appMetadata
|
2023-06-12 14:03:24 +02:00
|
|
|
metadata.Assumes = snap.Assumes
|
|
|
|
metadata.Hooks = snap.Hooks
|
2020-07-20 15:36:09 +02:00
|
|
|
metadata.Plugs = snap.Plugs
|
2018-08-15 14:38:42 +02:00
|
|
|
}
|
|
|
|
|
2017-07-27 02:30:48 +02:00
|
|
|
out, err := yaml.Marshal(metadata)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-03-20 02:45:08 +02:00
|
|
|
log.WithField("file", file).Debugf("writing metadata file")
|
2021-04-25 19:20:49 +02:00
|
|
|
if err = os.WriteFile(file, out, 0o644); err != nil { //nolint: gosec
|
2017-07-27 02:30:48 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-04-25 19:20:49 +02:00
|
|
|
snapFile := filepath.Join(ctx.Config.Dist, folder+".snap")
|
2019-05-27 17:47:05 +02:00
|
|
|
log.WithField("snap", snapFile).Info("creating")
|
2017-11-26 16:09:12 +02:00
|
|
|
/* #nosec */
|
2021-04-25 19:20:49 +02:00
|
|
|
cmd := exec.CommandContext(ctx, "snapcraft", "pack", primeDir, "--output", snapFile)
|
2017-07-27 05:43:53 +02:00
|
|
|
if out, err = cmd.CombinedOutput(); err != nil {
|
2021-07-25 02:32:04 +02:00
|
|
|
return fmt.Errorf("failed to generate snap package: %w: %s", err, string(out))
|
2017-07-27 05:43:53 +02:00
|
|
|
}
|
2019-05-27 17:47:05 +02:00
|
|
|
if !snap.Publish {
|
2018-10-20 20:13:31 +02:00
|
|
|
return nil
|
|
|
|
}
|
2019-08-12 22:44:48 +02:00
|
|
|
ctx.Artifacts.Add(&artifact.Artifact{
|
2022-04-14 02:29:39 +02:00
|
|
|
Type: artifact.PublishableSnapcraft,
|
|
|
|
Name: folder + ".snap",
|
|
|
|
Path: snapFile,
|
|
|
|
Goos: binaries[0].Goos,
|
|
|
|
Goarch: binaries[0].Goarch,
|
|
|
|
Goarm: binaries[0].Goarm,
|
|
|
|
Goamd64: binaries[0].Goamd64,
|
2021-07-24 05:23:59 +02:00
|
|
|
Extra: map[string]interface{}{
|
|
|
|
releasesExtra: channels,
|
|
|
|
},
|
2017-12-17 21:25:04 +02:00
|
|
|
})
|
2017-07-27 02:30:48 +02:00
|
|
|
return nil
|
|
|
|
}
|
2018-10-20 19:26:49 +02:00
|
|
|
|
2021-05-21 04:53:22 +02:00
|
|
|
const (
|
|
|
|
reviewWaitMsg = `Waiting for previous upload(s) to complete their review process.`
|
|
|
|
humanReviewMsg = `A human will soon review your snap`
|
2021-05-26 16:39:11 +02:00
|
|
|
needsReviewMsg = `(NEEDS REVIEW)`
|
2021-05-21 04:53:22 +02:00
|
|
|
)
|
2019-07-20 23:31:04 +02:00
|
|
|
|
2019-08-12 22:44:48 +02:00
|
|
|
func push(ctx *context.Context, snap *artifact.Artifact) error {
|
2021-04-25 19:20:49 +02:00
|
|
|
log := log.WithField("snap", snap.Name)
|
2022-06-24 04:36:19 +02:00
|
|
|
releases := artifact.ExtraOr(*snap, releasesExtra, []string{})
|
2018-10-20 20:16:14 +02:00
|
|
|
/* #nosec */
|
2021-07-24 05:23:59 +02:00
|
|
|
cmd := exec.CommandContext(ctx, "snapcraft", "upload", "--release="+strings.Join(releases, ","), snap.Path)
|
|
|
|
log.WithField("args", cmd.Args).Info("pushing snap")
|
2018-10-20 19:26:49 +02:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2021-05-26 16:39:11 +02:00
|
|
|
if strings.Contains(string(out), reviewWaitMsg) || strings.Contains(string(out), humanReviewMsg) || strings.Contains(string(out), needsReviewMsg) {
|
2019-07-20 23:31:04 +02:00
|
|
|
log.Warn(reviewWaitMsg)
|
|
|
|
} else {
|
2021-07-25 02:32:04 +02:00
|
|
|
return fmt.Errorf("failed to push %s package: %w: %s", snap.Path, err, string(out))
|
2019-07-20 23:31:04 +02:00
|
|
|
}
|
2018-10-20 19:26:49 +02:00
|
|
|
}
|
|
|
|
snap.Type = artifact.Snapcraft
|
|
|
|
ctx.Artifacts.Add(snap)
|
|
|
|
return nil
|
|
|
|
}
|
2020-06-06 20:07:18 +02:00
|
|
|
|
2021-07-24 05:23:59 +02:00
|
|
|
func processChannelsTemplates(ctx *context.Context, snap config.Snapcraft) ([]string, error) {
|
|
|
|
// nolint:prealloc
|
|
|
|
var channels []string
|
|
|
|
for _, channeltemplate := range snap.ChannelTemplates {
|
|
|
|
channel, err := tmpl.New(ctx).Apply(channeltemplate)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to execute channel template '%s': %w", err, err)
|
|
|
|
}
|
|
|
|
if channel == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
channels = append(channels, channel)
|
|
|
|
}
|
|
|
|
|
|
|
|
return channels, nil
|
|
|
|
}
|
2021-11-14 03:23:11 +02:00
|
|
|
|
|
|
|
var archToSnap = map[string]string{
|
|
|
|
"386": "i386",
|
|
|
|
"arm": "armhf",
|
|
|
|
"arm6": "armhf",
|
|
|
|
"arm7": "armhf",
|
|
|
|
"ppc64le": "ppc64el",
|
|
|
|
}
|
|
|
|
|
2022-04-16 04:25:32 +02:00
|
|
|
// TODO: write tests for this
|
2021-11-14 03:23:11 +02:00
|
|
|
func linuxArch(key string) string {
|
|
|
|
// XXX: list of all linux arches: `go tool dist list | grep linux`
|
|
|
|
arch := strings.TrimPrefix(key, "linux")
|
2022-04-16 04:25:32 +02:00
|
|
|
for _, suffix := range []string{
|
|
|
|
"hardfloat",
|
|
|
|
"softfloat",
|
|
|
|
"v1",
|
|
|
|
"v2",
|
|
|
|
"v3",
|
|
|
|
"v4",
|
|
|
|
} {
|
2021-11-14 03:23:11 +02:00
|
|
|
arch = strings.TrimSuffix(arch, suffix)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got, ok := archToSnap[arch]; ok {
|
|
|
|
return got
|
|
|
|
}
|
|
|
|
|
|
|
|
return arch
|
|
|
|
}
|