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