From da03c913ee4e54516e12dcdcc876c782f096018b Mon Sep 17 00:00:00 2001 From: Tudor Marcu Date: Tue, 19 Dec 2017 16:22:29 -0800 Subject: [PATCH] Mixer: Update CLI to use cobra package The cobra package is very mature for writing CLIs, and makes the code much easier to maintain and add new commands to. This feature ports the current implementation over to using cobra, maintaining the same calling convention for the commands. However, it would be trivial and perhaps better to update the form from: mixer build-chroots --flags to mixer build chroots --flags with chroots being a subcommand of build, as the code is currently structured in cmd. Signed-off-by: Tudor Marcu --- builder/builder.go | 46 +++++--- helpers/helpers.go | 16 ++- mixer/cmd/build.go | 169 +++++++++++++++++++++++++++ mixer/cmd/bundles.go | 81 +++++++++++++ mixer/cmd/root.go | 97 +++++++++++++++ mixer/cmd/rpms.go | 51 ++++++++ mixer/main.go | 273 +++---------------------------------------- 7 files changed, 460 insertions(+), 273 deletions(-) create mode 100644 mixer/cmd/build.go create mode 100644 mixer/cmd/bundles.go create mode 100644 mixer/cmd/root.go create mode 100644 mixer/cmd/rpms.go diff --git a/builder/builder.go b/builder/builder.go index 8760be0..7b57fd1 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -1,3 +1,17 @@ +// Copyright © 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package builder import ( @@ -210,6 +224,10 @@ func (b *Builder) UpdateRepo(ver string, allbundles bool) { // FIXME: Maybe use Go's tar or compress packages to do this _, err = exec.Command("tar", "-xzf", repo, "-C", "clr-bundles/").Output() + if err != nil { + helpers.PrintError(err) + os.Exit(1) + } bundles := b.Bundledir if _, err := os.Stat(bundles); os.IsNotExist(err) { clrbundles := "clr-bundles/clr-bundles-" + ver + "/bundles/" @@ -266,7 +284,7 @@ func (b *Builder) AddBundles(bundles []string, force bool, allbundles bool, git // Check if mix bundles dir exists if _, err := os.Stat(bundledir); os.IsNotExist(err) { - helpers.PrintError(errors.New("Mix bundles directory does not exist. Run mixer init-mix.")) + helpers.PrintError(errors.New("Mix bundles directory does not exist. Run mixer init-mix")) os.Exit(1) } @@ -380,7 +398,7 @@ func (b *Builder) InitMix(clearver string, mixver string, all bool, upstreamurl return nil } -// UpdatMixVer automatically bumps the mixversion file +10 to prepare for the next build +// UpdateMixVer automatically bumps the mixversion file +10 to prepare for the next build // without requiring user intervention. This makes the flow slightly more automatable. func (b *Builder) UpdateMixVer() { mixver, _ := strconv.Atoi(b.Mixver) @@ -506,16 +524,16 @@ func (b *Builder) setVersion(publish bool) { if b.Upstreamurl != "" { fmt.Println("Saving the upstream version URL " + b.Upstreamurl) - upstream_url := b.Statedir + "/www/" + b.Mixver + "/upstream_url" - err = ioutil.WriteFile(upstream_url, []byte(b.Upstreamurl), 0644) + upstreamurl := b.Statedir + "/www/" + b.Mixver + "/upstreamurl" + err = ioutil.WriteFile(upstreamurl, []byte(b.Upstreamurl), 0644) if err != nil { helpers.PrintError(err) os.Exit(1) } } fmt.Println("Saving the upstream version " + b.Clearver) - upstream_ver := b.Statedir + "/www/" + b.Mixver + "/upstream_ver" - err = ioutil.WriteFile(upstream_ver, []byte(b.Clearver), 0644) + upstreamver := b.Statedir + "/www/" + b.Mixver + "/upstreamver" + err = ioutil.WriteFile(upstreamver, []byte(b.Clearver), 0644) if err != nil { helpers.PrintError(err) os.Exit(1) @@ -591,6 +609,10 @@ func (b *Builder) BuildUpdate(prefixflag string, minvflag int, formatflag string // Step 4: hardlink relevant dirs _, err = exec.Command("hardlink", "-f", b.Statedir+"/image/"+b.Mixver+"/").Output() + if err != nil { + helpers.PrintError(err) + os.Exit(1) + } // Step 5: update the latest version b.setVersion(publishflag) @@ -600,7 +622,7 @@ func (b *Builder) BuildUpdate(prefixflag string, minvflag int, formatflag string // BuildImage will now proceed to build the full image with the previously // validated configuration. -func (b *Builder) BuildImage(format string, template string) { +func (b *Builder) BuildImage(format string, template string) error { // If the user did not pass in a format, default to builder.conf if format == "" { format = b.Format @@ -615,9 +637,7 @@ func (b *Builder) BuildImage(format string, template string) { wd, _ := os.Getwd() tempStage, err := ioutil.TempDir(wd, "ister-swupd-client-") if err != nil { - // TODO: This should return a proper error and the caller deals with printing. - helpers.PrintError(err) - return + return err } defer os.RemoveAll(tempStage) @@ -626,11 +646,7 @@ func (b *Builder) BuildImage(format string, template string) { imagecmd.Stdout = os.Stdout imagecmd.Stderr = os.Stderr - err = imagecmd.Run() - if err != nil { - helpers.PrintError(err) - fmt.Println("Failed to create image, check /var/log/ister") - } + return imagecmd.Run() } // AddRPMList copies rpms into the repodir and calls createrepo_c on it to diff --git a/helpers/helpers.go b/helpers/helpers.go index e0184ef..706bb44 100644 --- a/helpers/helpers.go +++ b/helpers/helpers.go @@ -1,3 +1,17 @@ +// Copyright © 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package helpers import ( @@ -233,5 +247,5 @@ func CheckRPM(rpm string) error { if strings.Contains(string(output), "RPM v") { return nil } - return fmt.Errorf("ERROR: %s is not valid!", rpm) + return fmt.Errorf("ERROR: %s is not valid", rpm) } diff --git a/mixer/cmd/build.go b/mixer/cmd/build.go new file mode 100644 index 0000000..5d6c131 --- /dev/null +++ b/mixer/cmd/build.go @@ -0,0 +1,169 @@ +// Copyright © 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/clearlinux/mixer-tools/builder" + "github.com/clearlinux/mixer-tools/helpers" + "github.com/pkg/errors" + + "github.com/spf13/cobra" +) + +type buildCmdFlags struct { + format string + increment bool + minVersion int + noSigning bool + prefix string + noPublish bool + keepChroot bool + template string +} + +var buildFlags buildCmdFlags + +// buildCmd represents the base build command when called without any subcommands +var buildCmd = &cobra.Command{ + Use: "build", + Short: "Build various pieces of OS content", +} + +func buildChroots(builder *builder.Builder, signflag bool) error { + // Create the signing and validation key/cert + if _, err := os.Stat(builder.Cert); os.IsNotExist(err) { + fmt.Println("Generating certificate for signature validation...") + privkey, err := helpers.CreateKeyPair() + if err != nil { + return errors.Wrap(err, "Error generating OpenSSL keypair") + } + template := helpers.CreateCertTemplate() + + err = builder.BuildChroots(template, privkey, signflag) + if err != nil { + return errors.Wrap(err, "Error building chroots") + } + } else { + err := builder.BuildChroots(nil, nil, true) + if err != nil { + return errors.Wrap(err, "Error building chroots") + } + } + return nil +} + +var buildChrootsCmd = &cobra.Command{ + Use: "chroots", + Short: "Build the chroots for your mix", + Long: `Build the chroots for your mix`, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.NewFromConfig(config) + return buildChroots(b, buildFlags.noSigning) + }, +} + +var buildUpdateCmd = &cobra.Command{ + Use: "update", + Short: "Build the update content for your mix", + Long: `Build the update content for your mix`, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.NewFromConfig(config) + err := b.BuildUpdate(buildFlags.prefix, buildFlags.minVersion, buildFlags.format, buildFlags.noSigning, !buildFlags.noPublish, buildFlags.keepChroot) + if err != nil { + return errors.Wrap(err, "Error building update") + } + + if buildFlags.increment { + b.UpdateMixVer() + } + return nil + }, +} + +var buildAllCmd = &cobra.Command{ + Use: "all", + Short: "Build all content for mix with default options", + Long: `Build all content for mix with default options`, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.NewFromConfig(config) + rpms, err := ioutil.ReadDir(b.Rpmdir) + if err == nil { + b.AddRPMList(rpms) + } + err = buildChroots(b, buildFlags.noSigning) + if err != nil { + return errors.Wrap(err, "Error building chroots") + } + err = b.BuildUpdate(buildFlags.prefix, buildFlags.minVersion, buildFlags.format, buildFlags.noSigning, !buildFlags.noPublish, buildFlags.keepChroot) + if err != nil { + return errors.Wrap(err, "Error building update") + } + + b.UpdateMixVer() + return nil + }, +} + +var buildImageCmd = &cobra.Command{ + Use: "image", + Short: "Build an image from the mix content", + Long: `Build an image from the mix content`, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.NewFromConfig(config) + err := b.BuildImage(buildFlags.format, buildFlags.template) + if err != nil { + return errors.Wrap(err, "Error building image") + } + return nil + }, +} + +func setUpdateFlags(cmd *cobra.Command) { + cmd.Flags().StringVar(&buildFlags.format, "format", "", "Supply format to use") + cmd.Flags().BoolVar(&buildFlags.increment, "increment", false, "Automatically increment the mixversion post build") + cmd.Flags().IntVar(&buildFlags.minVersion, "minversion", 0, "Supply minversion to build update with") + cmd.Flags().BoolVar(&buildFlags.noSigning, "no-signing", false, "Do not generate a certificate and do not sign the Manifest.MoM") + cmd.Flags().StringVar(&buildFlags.prefix, "prefix", "", "Supply prefix for where the swupd binaries live") + cmd.Flags().BoolVar(&buildFlags.noPublish, "no-publish", false, "Do not update the latest version after update") + cmd.Flags().BoolVar(&buildFlags.keepChroot, "keep-chroots", false, "Keep individual chroots created and not just consolidated 'full'") +} + +var buildCmds = []*cobra.Command{ + buildChrootsCmd, + buildUpdateCmd, + buildAllCmd, + buildImageCmd, +} + +func init() { + for _, cmd := range buildCmds { + buildCmd.AddCommand(cmd) + cmd.Flags().StringVarP(&config, "config", "c", "", "Builder config to use") + } + + RootCmd.AddCommand(buildCmd) + + buildChrootsCmd.Flags().BoolVar(&buildFlags.noSigning, "no-signing", false, "Do not generate a certificate to sign the Manifest.MoM") + + buildImageCmd.Flags().StringVar(&buildFlags.format, "format", "", "Supply the format used for the Mix") + buildImageCmd.Flags().StringVar(&buildFlags.template, "template", "", "Path to template file to use") + + setUpdateFlags(buildUpdateCmd) + setUpdateFlags(buildAllCmd) +} diff --git a/mixer/cmd/bundles.go b/mixer/cmd/bundles.go new file mode 100644 index 0000000..7754568 --- /dev/null +++ b/mixer/cmd/bundles.go @@ -0,0 +1,81 @@ +// Copyright © 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + "strings" + + "github.com/clearlinux/mixer-tools/builder" + + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +type bundleCmdFlags struct { + all bool + force bool + git bool +} + +var bundleFlags bundleCmdFlags + +var addBundlesCmd = &cobra.Command{ + Use: "add-bundles [bundle list]", + Short: "Add clr-bundles to your mix", + Long: `Add clr-bundles to your mix`, + RunE: func(cmd *cobra.Command, args []string) error { + if bundleFlags.all == false { + if len(args) <= 0 { + return errors.New("add-bundles requires at least 1 argument if --all is not passed") + } + } + bundles := strings.Split(args[0], ",") + b := builder.NewFromConfig(config) + // TODO change this to return (int, error) + numadded := b.AddBundles(bundles, bundleFlags.force, bundleFlags.all, bundleFlags.git) + fmt.Println(numadded, " bundles were added") + return nil + }, +} + +var getBundlesCmd = &cobra.Command{ + Use: "get-bundles", + Short: "Get the clr-bundles from upstream", + Long: `Get the clr-bundles from upstream`, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.NewFromConfig(config) + fmt.Println("Getting clr-bundles for version " + b.Clearver) + // TODO change this to return an error + b.UpdateRepo(b.Clearver, false) + return nil + }, +} + +var bundlesCmds = []*cobra.Command{ + addBundlesCmd, + getBundlesCmd, +} + +func init() { + for _, cmd := range bundlesCmds { + RootCmd.AddCommand(cmd) + cmd.Flags().StringVarP(&config, "config", "c", "", "Builder config to use") + } + + addBundlesCmd.Flags().BoolVar(&bundleFlags.force, "force", false, "Override bundles that already exist") + addBundlesCmd.Flags().BoolVar(&bundleFlags.all, "all", false, "Add all bundles from CLR; takes precedence over -bundles") + addBundlesCmd.Flags().BoolVar(&bundleFlags.git, "git", false, "Automatically apply new git commit") +} diff --git a/mixer/cmd/root.go b/mixer/cmd/root.go new file mode 100644 index 0000000..44de572 --- /dev/null +++ b/mixer/cmd/root.go @@ -0,0 +1,97 @@ +// Copyright © 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + "os" + "os/exec" + "strconv" + + "github.com/clearlinux/mixer-tools/builder" + + "github.com/spf13/cobra" +) + +var config string + +// RootCmd represents the base command when called without any subcommands +var RootCmd = &cobra.Command{ + Use: "mixer", + Long: `Mixer is a tool used to compose OS update content and images.`, +} + +type initCmdFlags struct { + all bool + clearver int + mixver int + upstreamurl string +} + +var initFlags initCmdFlags + +var initCmd = &cobra.Command{ + Use: "init-mix", + Short: "Initialize the mixer and workspace", + Long: `Initialize the mixer and workspace`, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.New() + b.LoadBuilderConf(config) + b.ReadBuilderConf() + return b.InitMix(strconv.Itoa(initFlags.clearver), strconv.Itoa(initFlags.mixver), initFlags.all, initFlags.upstreamurl) + }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + if err := RootCmd.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "Mixer Error: %s\n", err) + os.Exit(1) + } +} + +func checkDeps() error { + deps := []string{ + "createrepo_c", + "git", + "hardlink", + "m4", + "openssl", + "parallel", + "rpm", + "yum", + } + for _, dep := range deps { + if _, err := exec.LookPath(dep); err != nil { + return fmt.Errorf("failed to find program %q: %v", dep, err) + } + } + return nil +} + +func init() { + if err := checkDeps(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + } + + RootCmd.AddCommand(initCmd) + + initCmd.Flags().BoolVar(&initFlags.all, "all", false, "Create a mix with all Clear bundles included") + initCmd.Flags().IntVar(&initFlags.clearver, "clearver", 1, "Supply the Clear version to compose the mix from") + initCmd.Flags().IntVar(&initFlags.mixver, "mixver", 0, "Supply the Mix version to build") + initCmd.Flags().StringVar(&config, "config", "", "Supply a specific builder.conf to use for mixing") + initCmd.Flags().StringVar(&initFlags.upstreamurl, "upstreamurl", "https://download.clearlinux.org", "Supply an upstream URL to use for mixing") +} diff --git a/mixer/cmd/rpms.go b/mixer/cmd/rpms.go new file mode 100644 index 0000000..f55f9a3 --- /dev/null +++ b/mixer/cmd/rpms.go @@ -0,0 +1,51 @@ +// Copyright © 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "io/ioutil" + + "github.com/clearlinux/mixer-tools/builder" + + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var addRPMCmd = &cobra.Command{ + Use: "add-rpms", + Short: "Add rpms to local yum repository", + Long: `Add rpms to local yum repository`, + RunE: func(cmd *cobra.Command, args []string) error { + b := builder.NewFromConfig(config) + rpms, err := ioutil.ReadDir(b.Rpmdir) + if err != nil { + return errors.Wrapf(err, "Error cannot read %s\n", b.Rpmdir) + } + // TODO return error to check from AddRPMList + b.AddRPMList(rpms) + return nil + }, +} + +var rpmCmds = []*cobra.Command{ + addRPMCmd, +} + +func init() { + for _, cmd := range rpmCmds { + RootCmd.AddCommand(cmd) + cmd.Flags().StringVarP(&config, "config", "c", "", "Builder config to use") + } +} diff --git a/mixer/main.go b/mixer/main.go index 02649dd..220db6f 100644 --- a/mixer/main.go +++ b/mixer/main.go @@ -1,272 +1,31 @@ +// Copyright © 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package main import ( - "flag" "fmt" - "io/ioutil" "os" - "os/exec" - "strconv" - "strings" - "github.com/clearlinux/mixer-tools/builder" - "github.com/clearlinux/mixer-tools/helpers" + "github.com/clearlinux/mixer-tools/mixer/cmd" ) const Version = "3.2.1" -type Command struct { - Name string - Description string - Run func(args []string) -} - -var commands []*Command - -func init() { - commands = []*Command{ - {"build-all", "Build all content for mix with default options", cmdBuildAll}, - {"build-chroots", "Build chroots for the mix", cmdBuildChroots}, - {"build-update", "Build all update content for the mix", cmdBuildUpdate}, - {"build-image", "Build an image from the mix content", cmdBuildImage}, - {"add-rpms", "Add rpms to local yum repository", cmdAddRPMs}, - {"get-bundles", "Get the clr-bundles from upstream", cmdGetBundles}, - {"add-bundles", "Add clr-bundles to your mix", cmdAddBundles}, - {"init-mix", "Initialize the mixer and workspace", cmdInitMix}, - {"help", "Show help options", cmdHelp}, - } -} - -func PrintMainHelp() { - fmt.Printf("usage: mixer [args]\n") - for _, cmd := range commands { - fmt.Printf("\t%-20s\t%s\n", cmd.Name, cmd.Description) - } -} - -func CheckDeps() error { - deps := []string{ - "createrepo_c", - "git", - "hardlink", - "m4", - "openssl", - "parallel", - "rpm", - "yum", - } - for _, dep := range deps { - if _, err := exec.LookPath(dep); err != nil { - return fmt.Errorf("failed to find program %q: %v\n", dep, err) - } - } - return nil -} - func main() { fmt.Printf("Mixer %s\n", Version) os.Setenv("LD_PRELOAD", "/usr/lib64/nosync/nosync.so") - if len(os.Args) == 1 { - PrintMainHelp() - return - } - - var cmd *Command - name := os.Args[1] - if name == "-h" { - name = "help" - } - if name != "version" && name != "help" { - err := CheckDeps() - if err != nil { - fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) - os.Exit(1) - } - } - - for _, c := range commands { - if c.Name == name { - cmd = c - } - } - - if cmd == nil { - fmt.Printf("%q is not a valid command.\n", name) - os.Exit(-1) - } - - args := os.Args[2:] - cmd.Run(args) -} - -type UpdateVars struct { - Format string - Increment bool - MinVersion int - NoSigning bool - Prefix string - NoPublish bool - KeepChroot bool -} - -func setupUpdateFlags(v *UpdateVars, fs *flag.FlagSet) { - fs.StringVar(&v.Format, "format", "", "Supply format to use") - fs.BoolVar(&v.Increment, "increment", false, "Automatically increment the mixversion post build") - fs.IntVar(&v.MinVersion, "minversion", 0, "Supply minversion to build update with") - fs.BoolVar(&v.NoSigning, "no-signing", false, "Do not generate a certificate and do not sign the Manifest.MoM") - fs.StringVar(&v.Prefix, "prefix", "", "Supply prefix for where the swupd binaries live") - fs.BoolVar(&v.NoPublish, "no-publish", false, "Do not update the latest version after update") - fs.BoolVar(&v.KeepChroot, "keep-chroots", false, "Keep individual chroots created and not just consolidated 'full'") -} - -func cmdBuildAll(args []string) { - fs := flag.NewFlagSet("build-all", flag.ExitOnError) - config := fs.String("config", "", "Supply a specific builder.conf to use for mixing") - - v := &UpdateVars{} - setupUpdateFlags(v, fs) - - fs.Parse(args) - - b := builder.NewFromConfig(*config) - rpms, err := ioutil.ReadDir(b.Rpmdir) - if err == nil { - b.AddRPMList(rpms) - } - BuildChroots(b, v.NoSigning) - err = b.BuildUpdate(v.Prefix, v.MinVersion, v.Format, v.NoSigning, !v.NoPublish, v.KeepChroot) - if err != nil { - os.Exit(-1) - } - - b.UpdateMixVer() -} - -func cmdBuildChroots(args []string) { - fs := flag.NewFlagSet("build-chroots", flag.ExitOnError) - config := fs.String("config", "", "Supply a specific builder.conf to use for mixing") - noSigning := fs.Bool("no-signing", false, "Do not generate a certificate to sign the Manifest.MoM") - - fs.Parse(args) - - b := builder.NewFromConfig(*config) - BuildChroots(b, *noSigning) -} - -func cmdBuildUpdate(args []string) { - fs := flag.NewFlagSet("build-update", flag.ExitOnError) - config := fs.String("config", "", "Supply a specific builder.conf to use for mixing") - - v := &UpdateVars{} - setupUpdateFlags(v, fs) - - fs.Parse(args) - - b := builder.NewFromConfig(*config) - err := b.BuildUpdate(v.Prefix, v.MinVersion, v.Format, v.NoSigning, !v.NoPublish, v.KeepChroot) - if err != nil { - os.Exit(-1) - } - - if v.Increment { - b.UpdateMixVer() - } -} - -func cmdBuildImage(args []string) { - imagecmd := flag.NewFlagSet("build-image", flag.ExitOnError) - imageformat := imagecmd.String("format", "", "Supply the format used for the Mix") - conf := imagecmd.String("config", "", "Supply a specific builder.conf to use for mixing") - imagetemplate := imagecmd.String("template", "", "Path to tempalte file to use") - - imagecmd.Parse(args) - - b := builder.NewFromConfig(*conf) - b.BuildImage(*imageformat, *imagetemplate) -} - -func cmdAddRPMs(args []string) { - flags := flag.NewFlagSet("add-rpms", flag.ExitOnError) - conf := flags.String("config", "", "Supply a specific builder.conf to use for mixing") - flags.Parse(args) - - b := builder.NewFromConfig(*conf) - rpms, err := ioutil.ReadDir(b.Rpmdir) - if err != nil { - fmt.Printf("ERROR: cannot read %s\n", b.Rpmdir) - } - b.AddRPMList(rpms) -} - -func cmdGetBundles(args []string) { - bundlescmd := flag.NewFlagSet("get-bundles", flag.ExitOnError) - bundleconf := bundlescmd.String("config", "", "Supply a specific builder.conf to use for mixing") - bundlescmd.Parse(args) - b := builder.NewFromConfig(*bundleconf) - fmt.Println("Getting clr-bundles for version " + b.Clearver) - b.UpdateRepo(b.Clearver, false) -} - -func cmdAddBundles(args []string) { - flags := flag.NewFlagSet("add-bundles", flag.ExitOnError) - bundlesarg := flags.String("bundles", "", "Comma-separated list of bundles to add") - force := flags.Bool("force", false, "Override bundles that already exist") - all := flags.Bool("all", false, "Add all bundles from CLR; takes precedence over -bundles") - git := flags.Bool("git", false, "Automatically apply new git commit") - conf := flags.String("config", "", "Supply a specific builder.conf to use for mixing") - flags.Parse(args) - - var bundles []string - if !*all { - if len(*bundlesarg) == 0 { - flags.Usage() - os.Exit(1) - } else { - bundles = strings.Split(*bundlesarg, ",") - } - } - - b := builder.NewFromConfig(*conf) - b.AddBundles(bundles, *force, *all, *git) -} - -func cmdInitMix(args []string) { - initcmd := flag.NewFlagSet("init-mix", flag.ExitOnError) - allflag := initcmd.Bool("all", false, "Create a mix with all Clear bundles included") - clearflag := initcmd.Int("clearver", 1, "Supply the Clear version to compose the mix from") - mixflag := initcmd.Int("mixver", 0, "Supply the Mix version to build") - initconf := initcmd.String("config", "", "Supply a specific builder.conf to use for mixing") - upstreamurl := initcmd.String("upstreamurl", "https://download.clearlinux.org", "Supply an upstream URL to use for mixing") - initcmd.Parse(args) - b := builder.New() - b.LoadBuilderConf(*initconf) - b.ReadBuilderConf() - b.InitMix(strconv.Itoa(*clearflag), strconv.Itoa(*mixflag), *allflag, *upstreamurl) -} - -func cmdHelp(args []string) { - PrintMainHelp() -} - -func BuildChroots(builder *builder.Builder, signflag bool) { - // Create the signing and validation key/cert - if _, err := os.Stat(builder.Cert); os.IsNotExist(err) { - fmt.Println("Generating certificate for signature validation...") - privkey, err := helpers.CreateKeyPair() - if err != nil { - os.Exit(1) - } - template := helpers.CreateCertTemplate() - - err = builder.BuildChroots(template, privkey, signflag) - if err != nil { - os.Exit(-1) - } - } else { - err := builder.BuildChroots(nil, nil, true) - if err != nil { - os.Exit(-1) - } - } + cmd.Execute() }