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 <tudor.marcu@intel.com>
This commit is contained in:
Tudor Marcu
2018-01-02 09:43:30 -08:00
committed by tmarcu
parent 71807efa21
commit da03c913ee
7 changed files with 460 additions and 273 deletions
+31 -15
View File
@@ -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
+15 -1
View File
@@ -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)
}
+169
View File
@@ -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)
}
+81
View File
@@ -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")
}
+97
View File
@@ -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")
}
+51
View File
@@ -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")
}
}
+16 -257
View File
@@ -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 <command> [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()
}