1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-10 03:47:03 +02:00
goreleaser/pipeline/snapcraft/snapcraft.go

189 lines
5.1 KiB
Go
Raw Normal View History

2017-07-27 02:30:48 +02:00
// Package snapcraft implements the Pipe interface providing Snapcraft bindings.
package snapcraft
import (
"errors"
2017-08-02 14:06:28 +02:00
"fmt"
2017-07-27 02:30:48 +02:00
"io/ioutil"
2017-07-28 03:05:43 +02:00
"os"
2017-07-27 02:30:48 +02:00
"os/exec"
"path/filepath"
2017-12-17 21:25:04 +02:00
2017-07-27 02:30:48 +02:00
"github.com/apex/log"
2017-12-18 13:00:19 +02:00
"golang.org/x/sync/errgroup"
yaml "gopkg.in/yaml.v2"
2017-07-27 02:30:48 +02:00
"github.com/goreleaser/goreleaser/context"
2017-12-18 13:00:19 +02:00
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/filenametemplate"
2017-08-27 18:18:23 +02:00
"github.com/goreleaser/goreleaser/internal/linux"
2017-08-20 21:35:46 +02:00
"github.com/goreleaser/goreleaser/pipeline"
2017-07-27 02:30:48 +02:00
)
// ErrNoSnapcraft is shown when snapcraft cannot be found in $PATH
var ErrNoSnapcraft = errors.New("snapcraft not present in $PATH")
2017-08-17 23:41:08 +02:00
// ErrNoDescription is shown when no description provided
var ErrNoDescription = errors.New("no description provided for snapcraft")
// ErrNoSummary is shown when no summary provided
var ErrNoSummary = errors.New("no summary provided for snapcraft")
2017-09-15 02:19:56 +02:00
// Metadata to generate the snap package
type Metadata struct {
2017-07-27 02:30:48 +02:00
Name string
Version string
Summary string
Description string
Grade string `yaml:",omitempty"`
Confinement string `yaml:",omitempty"`
Architectures []string
2017-08-04 07:42:55 +02:00
Apps map[string]AppMetadata
2017-07-27 02:30:48 +02:00
}
2017-08-04 07:42:55 +02:00
// AppMetadata for the binaries that will be in the snap package
type AppMetadata struct {
2017-07-27 02:30:48 +02:00
Command string
2017-08-04 07:42:55 +02:00
Plugs []string `yaml:",omitempty"`
Daemon string `yaml:",omitempty"`
2017-07-27 02:30:48 +02:00
}
const defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
2017-07-27 02:30:48 +02:00
// Pipe for snapcraft packaging
type Pipe struct{}
func (Pipe) String() string {
return "creating Linux packages with snapcraft"
2017-07-27 02:30:48 +02:00
}
// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
var snap = &ctx.Config.Snapcraft
if snap.NameTemplate == "" {
snap.NameTemplate = defaultNameTemplate
}
return nil
}
2017-07-27 02:30:48 +02:00
// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
2017-08-17 23:41:08 +02:00
if ctx.Config.Snapcraft.Summary == "" && ctx.Config.Snapcraft.Description == "" {
2017-08-20 21:35:46 +02:00
return pipeline.Skip("no summary nor description were provided")
2017-07-27 02:30:48 +02:00
}
2017-08-17 23:41:08 +02:00
if ctx.Config.Snapcraft.Summary == "" {
return ErrNoSummary
}
2017-08-04 03:29:02 +02:00
if ctx.Config.Snapcraft.Description == "" {
2017-08-17 23:41:08 +02:00
return ErrNoDescription
2017-07-27 02:30:48 +02:00
}
_, err := exec.LookPath("snapcraft")
if err != nil {
return ErrNoSnapcraft
}
var g errgroup.Group
2018-05-28 01:10:06 +02:00
sem := make(chan bool, 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),
),
).GroupByPlatform() {
2018-05-28 01:10:06 +02:00
sem <- true
arch := linux.Arch(platform)
if arch == "armel" {
log.WithField("arch", arch).Warn("ignored unsupported arch")
continue
}
2017-12-17 21:25:04 +02:00
binaries := binaries
g.Go(func() error {
2018-05-28 01:10:06 +02:00
go func() {
<-sem
}()
2017-12-17 21:25:04 +02:00
return create(ctx, arch, binaries)
})
2017-07-27 02:30:48 +02:00
}
return g.Wait()
}
2017-12-17 21:25:04 +02:00
func create(ctx *context.Context, arch string, binaries []artifact.Artifact) error {
2017-08-20 21:35:46 +02:00
var log = log.WithField("arch", arch)
folder, err := filenametemplate.Apply(
ctx.Config.Snapcraft.NameTemplate,
filenametemplate.NewFields(ctx, ctx.Config.Snapcraft.Replacements, binaries...),
)
2017-12-17 21:25:04 +02:00
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.
2017-08-27 18:47:41 +02:00
var folderDir = filepath.Join(ctx.Config.Dist, folder)
var primeDir = filepath.Join(folderDir, "prime")
var metaDir = filepath.Join(primeDir, "meta")
// #nosec
2017-12-18 02:31:27 +02:00
if err = os.MkdirAll(metaDir, 0755); err != nil {
2017-07-28 03:05:43 +02:00
return err
}
var file = filepath.Join(primeDir, "meta", "snap.yaml")
2017-08-20 21:35:46 +02:00
log.WithField("file", file).Debug("creating snap metadata")
2017-07-27 02:30:48 +02:00
2017-09-15 02:19:56 +02:00
var metadata = &Metadata{
2017-07-27 02:30:48 +02:00
Version: ctx.Version,
Summary: ctx.Config.Snapcraft.Summary,
Description: ctx.Config.Snapcraft.Description,
Grade: ctx.Config.Snapcraft.Grade,
Confinement: ctx.Config.Snapcraft.Confinement,
Architectures: []string{arch},
2017-08-04 07:42:55 +02:00
Apps: make(map[string]AppMetadata),
2017-07-27 02:30:48 +02:00
}
metadata.Name = ctx.Config.ProjectName
2017-08-07 18:28:04 +02:00
if ctx.Config.Snapcraft.Name != "" {
metadata.Name = ctx.Config.Snapcraft.Name
}
2017-07-27 02:30:48 +02:00
for _, binary := range binaries {
log.WithField("path", binary.Path).
WithField("name", binary.Name).
2017-08-20 21:35:46 +02:00
Debug("passed binary to snapcraft")
appMetadata := AppMetadata{
Command: binary.Name,
}
2017-08-04 07:42:55 +02:00
if configAppMetadata, ok := ctx.Config.Snapcraft.Apps[binary.Name]; ok {
appMetadata.Plugs = configAppMetadata.Plugs
appMetadata.Daemon = configAppMetadata.Daemon
}
metadata.Apps[binary.Name] = appMetadata
2017-07-28 03:05:43 +02:00
destBinaryPath := filepath.Join(primeDir, filepath.Base(binary.Path))
2017-12-18 02:31:27 +02:00
if err = os.Link(binary.Path, destBinaryPath); err != nil {
2017-08-02 14:06:28 +02:00
return err
}
2017-07-27 02:30:48 +02:00
}
out, err := yaml.Marshal(metadata)
if err != nil {
return err
}
if err = ioutil.WriteFile(file, out, 0644); err != nil {
return err
}
2017-08-27 18:47:41 +02:00
var snap = filepath.Join(ctx.Config.Dist, folder+".snap")
/* #nosec */
2018-02-04 20:11:19 +02:00
var cmd = exec.CommandContext(ctx, "snapcraft", "pack", primeDir, "--output", snap)
2017-07-27 05:43:53 +02:00
if out, err = cmd.CombinedOutput(); err != nil {
2017-08-02 14:06:28 +02:00
return fmt.Errorf("failed to generate snap package: %s", string(out))
2017-07-27 05:43:53 +02:00
}
2017-12-17 21:25:04 +02:00
ctx.Artifacts.Add(artifact.Artifact{
Type: artifact.LinuxPackage,
Name: folder + ".snap",
Path: snap,
Goos: binaries[0].Goos,
Goarch: binaries[0].Goarch,
Goarm: binaries[0].Goarm,
})
2017-07-27 02:30:48 +02:00
return nil
}