1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2016-2023 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package main
import (
"errors"
"fmt"
"path/filepath"
"github.com/jessevdk/go-flags"
"golang.org/x/xerrors"
"github.com/snapcore/snapd/i18n"
// for SanitizePlugsSlots
"github.com/snapcore/snapd/interfaces/builtin"
"github.com/snapcore/snapd/snap"
"github.com/snapcore/snapd/snap/pack"
)
type packCmd struct {
CheckSkeleton bool `long:"check-skeleton"`
Filename string `long:"filename"`
Compression string `long:"compression"`
Positional struct {
SnapDir string `positional-arg-name:"<snap-dir>"`
TargetDir string `positional-arg-name:"<target-dir>"`
} `positional-args:"yes"`
}
var shortPackHelp = i18n.G("Pack the given directory as a snap")
var longPackHelp = i18n.G(`
The pack command packs the given snap-dir as a snap and writes the result to
target-dir. If target-dir is omitted, the result is written to current
directory. If both source-dir and target-dir are omitted, the pack command packs
the current directory.
The default file name for a snap can be derived entirely from its snap.yaml, but
in some situations it's simpler for a script to feed the filename in. In those
cases, --filename can be given to override the default. If this filename is
not absolute it will be taken as relative to target-dir.
When used with --check-skeleton, pack only checks whether snap-dir contains
valid snap metadata and raises an error otherwise. Application commands listed
in snap metadata file, but appearing with incorrect permission bits result in an
error. Commands that are missing from snap-dir are listed in diagnostic
messages.`,
)
func init() {
cmd := addCommand("pack",
shortPackHelp,
longPackHelp,
func() flags.Commander {
return &packCmd{}
}, map[string]string{
// TRANSLATORS: This should not start with a lowercase letter.
"check-skeleton": i18n.G("Validate snap-dir metadata only"),
// TRANSLATORS: This should not start with a lowercase letter.
"filename": i18n.G("Output to this filename"),
// TRANSLATORS: This should not start with a lowercase letter.
"compression": i18n.G("Compression to use (e.g. xz or lzo)"),
}, nil)
cmd.extra = func(cmd *flags.Command) {
// TRANSLATORS: this describes the default filename for a snap, e.g. core_16-2.35.2_amd64.snap
cmd.FindOptionByLongName("filename").DefaultMask = i18n.G("<name>_<version>_<architecture>.snap")
}
}
func (x *packCmd) Execute([]string) error {
// plug/slot sanitization is disabled (no-op) by default at the package level for "snap" command,
// for "snap pack" however we want real validation.
snap.SanitizePlugsSlots = builtin.SanitizePlugsSlots
if x.Positional.TargetDir != "" && x.Filename != "" && filepath.IsAbs(x.Filename) {
return errors.New(i18n.G("you can't specify an absolute filename while also specifying target dir."))
}
if x.Positional.SnapDir == "" {
x.Positional.SnapDir = "."
}
if x.Positional.TargetDir == "" {
x.Positional.TargetDir = "."
}
if x.CheckSkeleton {
err := pack.CheckSkeleton(Stderr, x.Positional.SnapDir)
if errors.Is(err, snap.ErrMissingPaths) {
return nil
}
return err
}
snapPath, err := pack.Pack(x.Positional.SnapDir, &pack.Options{
TargetDir: x.Positional.TargetDir,
SnapName: x.Filename,
Compression: x.Compression,
})
if err != nil {
// TRANSLATORS: the %q is the snap-dir (the first positional
// argument to the command); the %v is an error
return xerrors.Errorf(i18n.G("cannot pack %q: %w"), x.Positional.SnapDir, err)
}
// TRANSLATORS: %s is the path to the built snap file
fmt.Fprintf(Stdout, i18n.G("built: %s\n"), snapPath)
return nil
}
|