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