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"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/apex/log"
|
|
|
|
"github.com/goreleaser/goreleaser/context"
|
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
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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-07-27 02:30:48 +02:00
|
|
|
// SnapcraftMetadata to generate the snap package
|
|
|
|
type SnapcraftMetadata struct {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// Pipe for snapcraft packaging
|
|
|
|
type Pipe struct{}
|
|
|
|
|
|
|
|
// Description of the pipe
|
|
|
|
func (Pipe) Description() string {
|
|
|
|
return "Creating Linux packages with snapcraft"
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
for platform, groups := range ctx.Binaries {
|
|
|
|
if !strings.Contains(platform, "linux") {
|
|
|
|
log.WithField("platform", platform).Debug("skipped non-linux builds for snapcraft")
|
|
|
|
continue
|
|
|
|
}
|
2017-08-27 18:18:23 +02:00
|
|
|
arch := linux.Arch(platform)
|
2017-07-27 02:30:48 +02:00
|
|
|
for folder, binaries := range groups {
|
|
|
|
g.Go(func() error {
|
|
|
|
return create(ctx, folder, arch, binaries)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return g.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
func create(ctx *context.Context, folder, arch string, binaries []context.Binary) error {
|
2017-08-20 21:35:46 +02:00
|
|
|
var log = log.WithField("arch", arch)
|
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")
|
2017-07-28 03:05:43 +02:00
|
|
|
if err := os.MkdirAll(metaDir, 0755); err != nil {
|
|
|
|
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
|
|
|
|
|
|
|
var metadata = &SnapcraftMetadata{
|
|
|
|
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
|
|
|
}
|
2017-08-07 18:28:04 +02:00
|
|
|
if ctx.Config.Snapcraft.Name != "" {
|
|
|
|
metadata.Name = ctx.Config.Snapcraft.Name
|
|
|
|
} else {
|
|
|
|
metadata.Name = ctx.Config.ProjectName
|
|
|
|
}
|
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-08-02 14:06:28 +02:00
|
|
|
if err := os.Link(binary.Path, destBinaryPath); err != nil {
|
|
|
|
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")
|
|
|
|
var cmd = exec.Command("snapcraft", "snap", 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-08-04 02:42:11 +02:00
|
|
|
ctx.AddArtifact(snap)
|
2017-07-27 02:30:48 +02:00
|
|
|
return nil
|
|
|
|
}
|