github.com/dctrud/umoci@v0.4.3-0.20191016193643-05a1d37de015/cmd/umoci/main.go (about) 1 /* 2 * umoci: Umoci Modifies Open Containers' Images 3 * Copyright (C) 2016, 2017, 2018 SUSE LLC. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package main 19 20 import ( 21 "fmt" 22 "os" 23 24 "github.com/apex/log" 25 logcli "github.com/apex/log/handlers/cli" 26 "github.com/pkg/errors" 27 "github.com/urfave/cli" 28 ) 29 30 // version is version ID for the source, read from VERSION in the source and 31 // populated on build by make. 32 var version = "" 33 34 // gitCommit is the commit hash that the binary was built from and will be 35 // populated on build by make. 36 var gitCommit = "" 37 38 const ( 39 usage = `umoci modifies Open Container images` 40 41 // Categories used to automatically monkey-patch flags to commands. 42 categoryLayout = "layout" 43 categoryImage = "image" 44 ) 45 46 func main() { 47 app := cli.NewApp() 48 app.Name = "umoci" 49 app.Usage = usage 50 app.Authors = []cli.Author{ 51 { 52 Name: "Aleksa Sarai", 53 Email: "asarai@suse.com", 54 }, 55 } 56 57 // Fill the version. 58 v := "unknown" 59 if version != "" { 60 v = version 61 } 62 if gitCommit != "" { 63 v = fmt.Sprintf("%s~git%s", v, gitCommit) 64 } 65 app.Version = v 66 67 app.Flags = []cli.Flag{ 68 cli.BoolFlag{ 69 Name: "verbose", 70 Usage: "alias for --log=info", 71 }, 72 cli.StringFlag{ 73 Name: "log", 74 Usage: "set the log level (debug, info, [warn], error, fatal)", 75 Value: "warn", 76 }, 77 } 78 79 app.Before = func(ctx *cli.Context) error { 80 log.SetHandler(logcli.New(os.Stderr)) 81 82 if ctx.GlobalBool("verbose") { 83 if ctx.GlobalIsSet("log") { 84 return errors.New("--log=* and --verbose are mutually exclusive") 85 } 86 ctx.GlobalSet("log", "info") 87 } 88 89 level, err := log.ParseLevel(ctx.GlobalString("log")) 90 if err != nil { 91 return errors.Wrap(err, "parsing log level") 92 } 93 log.SetLevel(level) 94 return nil 95 } 96 97 app.Commands = []cli.Command{ 98 configCommand, 99 unpackCommand, 100 repackCommand, 101 gcCommand, 102 initCommand, 103 newCommand, 104 tagAddCommand, 105 tagRemoveCommand, 106 tagListCommand, 107 statCommand, 108 rawSubcommand, 109 insertCommand, 110 } 111 112 app.Metadata = map[string]interface{}{} 113 114 // In order to make the uxXyz wrappers not too cumbersome we automatically 115 // add them to images with categories set to categoryImage or 116 // categoryLayout. Monkey patching was never this neat. 117 for _, cmd := range flattenCommands(app.Commands) { 118 switch cmd.Category { 119 case categoryImage: 120 oldBefore := cmd.Before 121 cmd.Before = func(ctx *cli.Context) error { 122 if _, ok := ctx.App.Metadata["--image-path"]; !ok { 123 return errors.Errorf("missing mandatory argument: --image") 124 } 125 if _, ok := ctx.App.Metadata["--image-tag"]; !ok { 126 return errors.Errorf("missing mandatory argument: --image") 127 } 128 if oldBefore != nil { 129 return oldBefore(ctx) 130 } 131 return nil 132 } 133 *cmd = uxImage(*cmd) 134 case categoryLayout: 135 oldBefore := cmd.Before 136 cmd.Before = func(ctx *cli.Context) error { 137 if _, ok := ctx.App.Metadata["--image-path"]; !ok { 138 return errors.Errorf("missing mandatory argument: --layout") 139 } 140 if oldBefore != nil { 141 return oldBefore(ctx) 142 } 143 return nil 144 } 145 *cmd = uxLayout(*cmd) 146 } 147 } 148 149 // Actually run umoci. 150 if err := app.Run(os.Args); err != nil { 151 // If an error is a permission based error, give a hint to the user 152 // that --rootless might help. We probably should only be doing this if 153 // we're an unprivileged user. 154 if os.IsPermission(errors.Cause(err)) { 155 log.Info("umoci encountered a permission error: maybe --rootless will help?") 156 } 157 log.Fatalf("%v", err) 158 log.Debugf("%+v", err) 159 } 160 }