blob: b9053c615e3bfbcde2904417d4c7104022a114ff [file] [log] [blame]
/*
Copyright 2015 Runtime Inc.
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 (
"fmt"
"github.com/mynewt/newt/cli"
"github.com/spf13/cobra"
"log"
"os"
"path/filepath"
"regexp"
"strings"
)
var ExitOnFailure bool = false
var ExportAll bool = false
var ImportAll bool = false
var NewtVersion string = "0.1"
var NewtLogLevel string = ""
var NewtNest *cli.Nest
var newtSilent bool
var newtQuiet bool
var newtVerbose bool
var NewtBranchClutch string
var NewtBranchEgg string
func NewtUsage(cmd *cobra.Command, err error) {
if err != nil {
sErr := err.(*cli.NewtError)
log.Printf("[DEBUG] %s", sErr.StackTrace)
fmt.Fprintf(os.Stderr, "Error: %s\n", sErr.Text)
}
if cmd != nil {
cmd.Help()
}
os.Exit(1)
}
// Display help text with a max line width of 79 characters
func formatHelp(text string) string {
// first compress all new lines and extra spaces
words := regexp.MustCompile("\\s+").Split(text, -1)
linelen := 0
fmtText := ""
for _, word := range words {
word = strings.Trim(word, "\n ") + " "
tmplen := linelen + len(word)
if tmplen >= 80 {
fmtText += "\n"
linelen = 0
}
fmtText += word
linelen += len(word)
}
return fmtText
}
// Extracts "<key>=<value>" strings from the supplied slice and inserts them
// into the specified target's variable map.
func extractTargetVars(args []string, t *cli.Target) error {
for i := 0; i < len(args); i++ {
pair := strings.SplitN(args[i], "=", 2)
if len(pair) != 2 {
return cli.NewNewtError("invalid argument: " + args[i])
}
t.Vars[pair[0]] = pair[1]
}
return nil
}
func targetSetCmd(cmd *cobra.Command, args []string) {
if len(args) != 2 {
NewtUsage(cmd,
cli.NewNewtError("Must specify two arguments (sect & k=v) to set"))
}
t, err := cli.LoadTarget(NewtNest, args[0])
if err != nil {
NewtUsage(cmd, err)
}
ar := strings.Split(args[1], "=")
t.Vars[ar[0]] = ar[1]
if err := t.Save(); err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Target %s successfully set %s to %s\n", args[0], ar[0], ar[1])
}
func targetUnsetCmd(cmd *cobra.Command, args []string) {
if len(args) != 2 {
NewtUsage(cmd,
cli.NewNewtError("Must specify two arguments (sect & k) to unset"))
}
t, err := cli.LoadTarget(NewtNest, args[0])
if err != nil {
NewtUsage(cmd, err)
}
if err := t.DeleteVar(args[1]); err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Target %s successfully unset %s\n", args[0], args[1])
}
func targetShowCmd(cmd *cobra.Command, args []string) {
dispSect := ""
if len(args) == 1 {
dispSect = args[0]
}
targets, err := cli.GetTargets(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
for _, target := range targets {
if dispSect == "" || dispSect == target.Vars["name"] {
cli.StatusMessage(cli.VERBOSITY_QUIET, target.Vars["name"]+"\n")
vars := target.GetVars()
for k, v := range vars {
cli.StatusMessage(cli.VERBOSITY_QUIET, " %s: %s\n", k, v)
}
}
}
}
func targetCreateCmd(cmd *cobra.Command, args []string) {
if len(args) != 1 {
NewtUsage(cmd, cli.NewNewtError("Wrong number of args to create cmd."))
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Creating target "+args[0]+"\n")
if cli.TargetExists(NewtNest, args[0]) {
NewtUsage(cmd, cli.NewNewtError(
"Target already exists, cannot create target with same name."))
}
target := &cli.Target{
Nest: NewtNest,
Vars: map[string]string{},
}
target.Vars["name"] = args[0]
err := target.Save()
if err != nil {
NewtUsage(nil, err)
} else {
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Target %s successfully created!\n", args[0])
}
}
func targetBuildCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd, cli.NewNewtError("Must specify target to build"))
}
t, err := cli.LoadTarget(NewtNest, args[0])
if err != nil {
NewtUsage(nil, err)
}
if len(args) > 1 && args[1] == "clean" {
if len(args) > 2 && args[2] == "all" {
err = t.BuildClean(true)
} else {
err = t.BuildClean(false)
}
if err != nil {
NewtUsage(nil, err)
}
} else {
// Parse any remaining key-value pairs and insert them into the target.
err = extractTargetVars(args[1:], t)
if err != nil {
NewtUsage(nil, err)
}
err = t.Build()
if err != nil {
NewtUsage(nil, err)
}
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Successfully run!\n")
}
func targetDelCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd, cli.NewNewtError("Must specify target to delete"))
}
t, err := cli.LoadTarget(NewtNest, args[0])
if err != nil {
NewtUsage(cmd, err)
}
if err := t.Remove(); err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Target %s successfully removed\n", args[0])
}
func targetTestCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd, cli.NewNewtError("Must specify target to build"))
}
t, err := cli.LoadTarget(NewtNest, args[0])
if err != nil {
NewtUsage(nil, err)
}
if len(args) > 1 && args[1] == "clean" {
if len(args) > 2 && args[2] == "all" {
err = t.Test("testclean", true)
} else {
err = t.Test("testclean", false)
}
if err != nil {
NewtUsage(nil, err)
}
} else {
// Parse any remaining key-value pairs and insert them into the target.
err = extractTargetVars(args[1:], t)
if err != nil {
NewtUsage(cmd, err)
}
err = t.Test("test", ExitOnFailure)
if err != nil {
NewtUsage(nil, err)
}
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Successfully run!\n")
}
func targetExportCmd(cmd *cobra.Command, args []string) {
var targetName string
if ExportAll {
targetName = ""
} else {
if len(args) < 1 {
NewtUsage(cmd, cli.NewNewtError("Must either specify -a flag or name of "+
"target to export"))
}
targetName = args[0]
}
err := cli.ExportTargets(NewtNest, targetName, ExportAll, os.Stdout)
if err != nil {
NewtUsage(cmd, err)
}
}
func targetImportCmd(cmd *cobra.Command, args []string) {
var targetName string
if ImportAll {
targetName = ""
} else {
if len(args) < 1 {
NewtUsage(cmd, cli.NewNewtError("Must either specify -a flag or name of "+
"target to import"))
}
targetName = args[0]
}
err := cli.ImportTargets(NewtNest, targetName, ImportAll, os.Stdin)
if err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Target(s) successfully imported!\n")
}
func targetAddCmds(base *cobra.Command) {
targetHelpText := formatHelp(`Targets tell the newt tool how to build the source
code within a given nest.`)
targetHelpEx := " newt target create <target-name>\n"
targetHelpEx += " newt target set <target-name> <var-name>=<value>\n"
targetHelpEx += " newt target unset <target-name> <var-name>\n"
targetHelpEx += " newt target show <target-name>\n"
targetHelpEx += " newt target delete <target-name>\n"
targetHelpEx += " newt target build <target-name> [clean[, all]]\n"
targetHelpEx += " newt target test <target-name> [clean[, all]]\n"
targetHelpEx += " newt target export [-a -export-all] [<target-name>]\n"
targetHelpEx += " newt target import [-a -import-all] [<target-name>]"
targetCmd := &cobra.Command{
Use: "target",
Short: "Set and view target information",
Long: targetHelpText,
Example: targetHelpEx,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cli.Init(NewtLogLevel, newtSilent, newtQuiet, newtVerbose)
var err error
NewtNest, err = cli.NewNest()
if err != nil {
NewtUsage(nil, err)
}
},
Run: func(cmd *cobra.Command, args []string) {
cmd.Usage()
},
}
setHelpText := formatHelp(`Set a target variable (<var-name>) on target
<target-name> to value <value>.`)
setHelpEx := " newt target set <target-name> <var-name>=<value>\n"
setHelpEx += " newt target set my_target1 var_name=value\n"
setHelpEx += " newt target set my_target1 arch=cortex_m4"
setCmd := &cobra.Command{
Use: "set",
Short: "Set target configuration variable",
Long: setHelpText,
Example: setHelpEx,
Run: targetSetCmd,
}
targetCmd.AddCommand(setCmd)
unsetHelpText := formatHelp(`Unset a target variable (<var-name>) on target
<target-name>.`)
unsetHelpEx := " newt target unset <target-name> <var-name>\n"
unsetHelpEx += " newt target unset my_target1 var_name"
unsetCmd := &cobra.Command{
Use: "unset",
Short: "Unset target configuration variable",
Long: unsetHelpText,
Example: unsetHelpEx,
Run: targetUnsetCmd,
}
targetCmd.AddCommand(unsetCmd)
delHelpText := formatHelp(`Delete the target specified by <target-name>.`)
delHelpEx := " newt target delete <target-name>\n"
delHelpEx += " newt target delete my_target1"
delCmd := &cobra.Command{
Use: "delete",
Short: "Delete target",
Long: delHelpText,
Example: delHelpEx,
Run: targetDelCmd,
}
targetCmd.AddCommand(delCmd)
createHelpText := formatHelp(`Create a target specified by <target-name>.`)
createHelpEx := " newt target create <target-name>\n"
createHelpEx += " newt target create my_target1"
createCmd := &cobra.Command{
Use: "create",
Short: "Create a target",
Long: createHelpText,
Example: createHelpEx,
Run: targetCreateCmd,
}
targetCmd.AddCommand(createCmd)
showHelpText := formatHelp(`Show all the variables for the target specified
by <target-name>.`)
showHelpEx := " newt target show <target-name>\n"
showHelpEx += " newt target show my_target1"
showCmd := &cobra.Command{
Use: "show",
Short: "View target configuration variables",
Long: showHelpText,
Example: showHelpEx,
Run: targetShowCmd,
}
targetCmd.AddCommand(showCmd)
buildHelpText := formatHelp(`Build the target specified by <target-name>.
If clean is specified, then all the binaries and object files for this
target will be removed. If the all option is specified, all binaries
and object files for all targets will be removed.`)
buildHelpEx := " newt target build <target-name> [clean[, all]]\n"
buildHelpEx += " newt target build my_target1\n"
buildHelpEx += " newt target build my_target1 clean\n"
buildHelpEx += " newt target build my_target1 clean all\n"
buildCmd := &cobra.Command{
Use: "build",
Short: "Build target",
Long: buildHelpText,
Example: buildHelpEx,
Run: targetBuildCmd,
}
targetCmd.AddCommand(buildCmd)
testHelpText := formatHelp(`Test the target specified by <target-name>. If
clean is specified, then all the test binaries and object files for this
target will be removed. If the all option is specified, all test
binaries and object files for all targets will be removed.`)
testHelpEx := " newt target test <target-name> [clean, [all]]\n"
testHelpEx += " newt target test mytarget1\n"
testHelpEx += " newt target test mytarget1 clean\n"
testHelpEx += " newt target test mytarget1 clean all"
testCmd := &cobra.Command{
Use: "test",
Short: "Test target",
Long: testHelpText,
Example: testHelpEx,
Run: targetTestCmd,
}
targetCmd.AddCommand(testCmd)
exportHelpText := formatHelp(`Export build targets from the current nest, and
print them to standard output. If the -a (or -export-all) option is
specified, then all targets will be exported. Otherwise, <target-name>
must be specified, and only that target will be exported.`)
exportHelpEx := " newt target export [-a -export-all] [<target-name>]\n"
exportHelpEx += " newt target export -a > my_exports.txt\n"
exportHelpEx += " newt target export my_target > my_target_export.txt"
exportCmd := &cobra.Command{
Use: "export",
Short: "Export target",
Long: exportHelpText,
Example: exportHelpEx,
Run: targetExportCmd,
}
exportCmd.PersistentFlags().BoolVarP(&ExportAll, "export-all", "a", false,
"If present, export all targets")
targetCmd.AddCommand(exportCmd)
importHelpText := formatHelp(`Import build targets from standard input. If
the -a (or -import-all) option is specified, then all targets will be
imported. Otherwise, a <target-name> must be specified, and only that
target will be imported.`)
importHelpEx := " newt target import [-a -import-all] [<target-name>]\n"
importHelpEx += " newt target import -a < exported_targets.txt\n"
importHelpEx += " newt target import ex_tgt_1 < exported_targets.txt"
importCmd := &cobra.Command{
Use: "import",
Short: "Import target",
Long: importHelpText,
Example: importHelpEx,
Run: targetImportCmd,
}
importCmd.PersistentFlags().BoolVarP(&ImportAll, "import-all", "a", false,
"If present, import all targets")
targetCmd.AddCommand(importCmd)
base.AddCommand(targetCmd)
}
func dispEgg(egg *cli.Egg) error {
cli.StatusMessage(cli.VERBOSITY_QUIET, "Egg %s, version %s\n",
egg.FullName, egg.Version)
cli.StatusMessage(cli.VERBOSITY_QUIET, " path: %s\n",
filepath.Clean(egg.BasePath))
if egg.Capabilities != nil {
cli.StatusMessage(cli.VERBOSITY_QUIET, " capabilities: ")
caps, err := egg.GetCapabilities()
if err != nil {
return err
}
for _, capability := range caps {
cli.StatusMessage(cli.VERBOSITY_QUIET, "%s ", capability)
}
cli.StatusMessage(cli.VERBOSITY_QUIET, "\n")
}
if len(egg.Deps) > 0 {
cli.StatusMessage(cli.VERBOSITY_QUIET, " deps: ")
for _, dep := range egg.Deps {
if dep == nil {
continue
}
cli.StatusMessage(cli.VERBOSITY_QUIET, "%s ", dep)
}
cli.StatusMessage(cli.VERBOSITY_QUIET, "\n")
}
if egg.LinkerScript != "" {
cli.StatusMessage(cli.VERBOSITY_QUIET, " linkerscript: %s\n",
egg.LinkerScript)
}
return nil
}
func dispEggShell(eggShell *cli.EggShell) error {
cli.StatusMessage(cli.VERBOSITY_QUIET, "Egg %s from clutch %s, version %s\n",
eggShell.FullName, eggShell.Clutch.Name, eggShell.Version)
if eggShell.Caps != nil {
cli.StatusMessage(cli.VERBOSITY_QUIET, " capabilities: ")
caps, err := eggShell.GetCapabilities()
if err != nil {
return err
}
for _, capability := range caps {
cli.StatusMessage(cli.VERBOSITY_QUIET, "%s ", capability)
}
cli.StatusMessage(cli.VERBOSITY_QUIET, "\n")
}
if len(eggShell.Deps) > 0 {
cli.StatusMessage(cli.VERBOSITY_QUIET, " deps: ")
for _, dep := range eggShell.Deps {
if dep == nil {
continue
}
cli.StatusMessage(cli.VERBOSITY_QUIET, "%s ", dep)
}
cli.StatusMessage(cli.VERBOSITY_QUIET, "\n")
}
return nil
}
func eggListCmd(cmd *cobra.Command, args []string) {
eggMgr, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := eggMgr.LoadConfigs(nil, false); err != nil {
NewtUsage(cmd, err)
}
for _, egg := range eggMgr.Eggs {
if err := dispEgg(egg); err != nil {
NewtUsage(cmd, err)
}
}
}
func eggCheckDepsCmd(cmd *cobra.Command, args []string) {
eggMgr, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := eggMgr.LoadConfigs(nil, false); err != nil {
NewtUsage(cmd, err)
}
if err := eggMgr.CheckDeps(); err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Dependencies successfully resolved!\n")
}
func eggHuntCmd(cmd *cobra.Command, args []string) {
var err error
if len(args) != 1 {
NewtUsage(cmd,
cli.NewNewtError("Must specify string to hunt for"))
}
/*
* First check local.
*/
eggMgr, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := eggMgr.LoadConfigs(nil, false); err != nil {
NewtUsage(cmd, err)
}
found := false
for _, egg := range eggMgr.Eggs {
contains := strings.Contains(egg.FullName, args[0])
if contains == true {
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Installed egg %s@%s\n",
egg.FullName, egg.Version)
found = true
}
}
/*
* Then check remote clutches.
*/
clutches, err := NewtNest.GetClutches()
if err != nil {
NewtUsage(cmd, err)
}
for _, clutch := range clutches {
for _, eggShell := range clutch.EggShells {
contains := strings.Contains(eggShell.FullName, args[0])
if contains == true {
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Clutch %s has egg %s@%s\n",
clutch.Name, eggShell.FullName,
eggShell.Version)
found = true
}
}
}
if found == false {
cli.StatusMessage(cli.VERBOSITY_QUIET, "No egg found!\n")
}
}
func eggShowCmd(cmd *cobra.Command, args []string) {
var eggName string
var clutchName string = ""
if len(args) < 1 || len(args) > 2 {
NewtUsage(cmd,
cli.NewNewtError("Must specify full name of the egg"))
}
if len(args) == 1 {
eggName = args[0]
} else {
clutchName = args[0]
eggName = args[1]
}
eggMgr, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := eggMgr.LoadConfigs(nil, false); err != nil {
NewtUsage(cmd, err)
}
egg, err := eggMgr.ResolveEggName(eggName)
if err == nil {
egg.LoadConfig(nil, false)
dispEgg(egg)
}
clutches, err := NewtNest.GetClutches()
if err != nil {
NewtUsage(cmd, err)
}
for _, clutch := range clutches {
if clutchName == "" || clutch.Name == clutchName {
eggShell, err := clutch.ResolveEggShellName(eggName)
if err == nil {
dispEggShell(eggShell)
}
}
}
}
func eggShellInstall(eggShell *cli.EggShell) error {
eggMgr, err := cli.NewClutch(NewtNest)
if err != nil {
return err
}
if err := eggMgr.LoadConfigs(nil, false); err != nil {
return err
}
_, err = eggMgr.ResolveEggName(eggShell.FullName)
if err == nil {
return cli.NewNewtError(fmt.Sprintf("Egg %s already installed!",
eggShell.FullName))
}
err = eggShell.Install(eggMgr, NewtBranchEgg)
if err != nil {
return err
}
return nil
}
func eggInstallCmd(cmd *cobra.Command, args []string) {
var eggName string
var clutchName string = ""
var clutch *cli.Clutch
var eggShell *cli.EggShell
if len(args) < 1 || len(args) > 2 {
NewtUsage(cmd,
cli.NewNewtError("Must specify full name of the egg"))
}
if len(args) == 1 {
eggName = args[0]
} else {
clutchName = args[0]
eggName = args[1]
}
/*
* Find the eggShell to install.
*/
clutches, err := NewtNest.GetClutches()
if err != nil {
NewtUsage(cmd, err)
}
if clutchName != "" {
clutch = clutches[clutchName]
}
if clutch != nil {
eggShell, err := clutch.ResolveEggShellName(eggName)
if err != nil {
NewtUsage(cmd, err)
}
err = eggShellInstall(eggShell)
if err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Installation was a success!\n")
return
}
eggShell = nil
for _, tmpClutch := range clutches {
if clutchName == "" || tmpClutch.Name == clutchName {
tmpEggShell, err := tmpClutch.ResolveEggShellName(eggName)
if err != nil && eggShell != nil {
NewtUsage(cmd,
cli.NewNewtError(fmt.Sprintf("Ambiguous source "+
"egg %s in clutches %s and %s",
eggName, clutch.Name, tmpClutch.Name)))
} else {
eggShell = tmpEggShell
clutch = tmpClutch
}
}
}
if eggShell == nil {
NewtUsage(cmd,
cli.NewNewtError(fmt.Sprintf("Can't find egg with name %s",
eggName)))
}
err = eggShellInstall(eggShell)
if err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Installation was a success!\n")
}
func eggRemoveCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 || len(args) > 2 {
NewtUsage(cmd,
cli.NewNewtError("Must specify full name of the egg"))
}
eggName := args[0]
eggMgr, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := eggMgr.LoadConfigs(nil, false); err != nil {
NewtUsage(cmd, err)
}
egg, err := eggMgr.ResolveEggName(eggName)
if err != nil {
NewtUsage(cmd,
cli.NewNewtError(fmt.Sprintf("Egg %s has not been installed",
eggName)))
}
err = egg.Remove()
if err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Removed successfully!\n")
}
func eggAddCmds(baseCmd *cobra.Command) {
eggHelpText := formatHelp(`Commands to search, display and install eggs
in the current nest. Eggs are newt's version of packages, and are
the fundamental building blocks of nests.`)
eggHelpEx := " newt egg list\n"
eggHelpEx += " newt egg checkdeps\n"
eggHelpEx += " newt egg hunt <egg-name>\n"
eggHelpEx += " newt egg show [<clutch-name> ] <egg-name>\n"
eggHelpEx += " newt egg install [<clutch-name> ] <egg-name>\n"
eggHelpEx += " newt egg remove [<clutch-name> ] <egg-name>"
eggCmd := &cobra.Command{
Use: "egg",
Short: "Commands to list and inspect eggs on a nest",
Long: eggHelpText,
Example: eggHelpEx,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cli.Init(NewtLogLevel, newtSilent, newtQuiet, newtVerbose)
var err error
NewtNest, err = cli.NewNest()
if err != nil {
NewtUsage(nil, err)
}
},
Run: func(cmd *cobra.Command, args []string) {
NewtUsage(cmd, nil)
},
}
listHelpText := formatHelp(`List all of the eggs in the current nest.`)
listHelpEx := " newt egg list"
listCmd := &cobra.Command{
Use: "list",
Short: "List eggs in the current nest",
Long: listHelpText,
Example: listHelpEx,
Run: eggListCmd,
}
eggCmd.AddCommand(listCmd)
checkDepsHelpText := formatHelp(`Resolve all dependencies in the local
nest. This command goes through all eggs currently installed, checks
their dependencies, and prints any unresolved dependencies between
eggs.`)
checkDepsHelpEx := " newt egg checkdeps"
checkDepsCmd := &cobra.Command{
Use: "checkdeps",
Short: "Check egg dependencies",
Long: checkDepsHelpText,
Example: checkDepsHelpEx,
Run: eggCheckDepsCmd,
}
eggCmd.AddCommand(checkDepsCmd)
huntHelpText := formatHelp(`Hunt for an egg, specified by <egg-name>.
The local nest, along with all remote nests (clutches) are
searched. All matched eggs are shown.`)
huntHelpEx := " newt egg hunt <egg-name>"
huntCmd := &cobra.Command{
Use: "hunt",
Short: "Search for egg from clutches",
Long: huntHelpText,
Example: huntHelpEx,
Run: eggHuntCmd,
}
eggCmd.AddCommand(huntCmd)
showHelpText := formatHelp(`Show the contents of the egg, specified by
<egg-name>. <egg-name> is resolved using all the clutches installed
in the current nest or, if <clutch-name> is specified, only
<clutch-name> will be searched.`)
showHelpEx := " newt egg show [<clutch-name> ] <egg-name>"
showCmd := &cobra.Command{
Use: "show",
Short: "Show the contents of an egg.",
Long: showHelpText,
Example: showHelpEx,
Run: eggShowCmd,
}
eggCmd.AddCommand(showCmd)
installHelpText := formatHelp(`Install the egg specified by <egg-name> to
the local nest. <egg-name> is searched for throughout the clutches in
the local nest. If <clutch-name> is specified, then only <clutch-name>
is searched for <egg-name>.`)
installHelpEx := " newt egg install [<clutch-name> ] <egg-name>"
installCmd := &cobra.Command{
Use: "install",
Short: "Install an egg",
Long: installHelpText,
Example: installHelpEx,
Run: eggInstallCmd,
}
installCmd.Flags().StringVarP(&NewtBranchEgg, "branch", "b", "",
"Branch (or tag) of the clutch to install from.")
eggCmd.AddCommand(installCmd)
removeHelpText := formatHelp(`Remove the egg, specified by <egg-name> from
the local nest. If present the egg is taking only from the clutch
specified by <clutch-name>.`)
removeHelpEx := " newt egg remove [<clutch-name> ] <egg-name>"
removeCmd := &cobra.Command{
Use: "remove",
Short: "Remove an egg",
Long: removeHelpText,
Example: removeHelpEx,
Run: eggRemoveCmd,
}
eggCmd.AddCommand(removeCmd)
baseCmd.AddCommand(eggCmd)
}
func nestGenerateClutchCmd(cmd *cobra.Command, args []string) {
if len(args) != 2 {
NewtUsage(cmd,
cli.NewNewtError("Must specify name and URL to lay clutch file"))
}
clutchName := args[0]
clutchUrl := args[1]
clutch, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
clutch.Name = clutchName
clutch.RemoteUrl = clutchUrl
local, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := clutch.LoadFromClutch(local); err != nil {
NewtUsage(cmd, err)
}
clutchStr, err := clutch.Serialize()
if err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT, "%s", clutchStr)
}
func nestAddClutchCmd(cmd *cobra.Command, args []string) {
if len(args) != 2 {
NewtUsage(cmd,
cli.NewNewtError("Must specify both name and URL to "+
"larva install command"))
}
name := args[0]
url := args[1]
clutch, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := clutch.Install(name, url, NewtBranchClutch); err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Clutch "+name+" successfully installed to Nest.\n")
}
func nestListClutchesCmd(cmd *cobra.Command, args []string) {
clutches, err := NewtNest.GetClutches()
if err != nil {
NewtUsage(cmd, err)
}
for name, clutch := range clutches {
cli.StatusMessage(cli.VERBOSITY_QUIET,
"Remote clutch %s (eggshells: %d)\n", name, len(clutch.EggShells))
}
}
func nestCreateCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd,
cli.NewNewtError("Must specify a nest name to create"))
}
wd, err := os.Getwd()
if err != nil {
NewtUsage(cmd, cli.NewNewtError(err.Error()))
}
nestDir := wd + "/" + args[0]
if len(args) > 1 {
nestDir = args[1]
}
tadpoleUrl := ""
if len(args) > 2 {
tadpoleUrl = args[2]
}
if err := cli.CreateNest(args[0], nestDir, tadpoleUrl); err != nil {
NewtUsage(cmd, err)
}
cli.StatusMessage(cli.VERBOSITY_DEFAULT,
"Nest %s successfully created in %s\n", args[0], nestDir)
}
func nestShowClutchCmd(cmd *cobra.Command, args []string) {
if len(args) != 1 {
NewtUsage(cmd,
cli.NewNewtError("Must specify a clutch name to show-clutch command"))
}
clutch, err := cli.NewClutch(NewtNest)
if err != nil {
NewtUsage(cmd, err)
}
if err := clutch.Load(args[0]); err != nil {
NewtUsage(cmd, err)
}
// Clutch loaded, now print out clutch information
cli.StatusMessage(cli.VERBOSITY_QUIET, "Clutch Name: %s\n", clutch.Name)
cli.StatusMessage(cli.VERBOSITY_QUIET, "Clutch URL: %s\n",
clutch.RemoteUrl)
i := 0
for _, eggShell := range clutch.EggShells {
i++
cli.StatusMessage(cli.VERBOSITY_QUIET, " %s@%s", eggShell.FullName,
eggShell.Version)
if i%4 == 0 {
cli.StatusMessage(cli.VERBOSITY_QUIET, "\n")
}
}
if i%4 != 0 {
cli.StatusMessage(cli.VERBOSITY_QUIET, "\n")
}
}
func nestAddCmds(baseCmd *cobra.Command) {
var nestCmd *cobra.Command
var createCmd *cobra.Command
nestHelpText := formatHelp(`The nest commands help manage the local nest.
A nest represents the workspace for one or more projects, each project being a
collection of eggs (packages.) In addition to containing eggs, a local nest contains the
target (build) definitions, and a list of clutches (snapshots of remote nests
which contain eggs that can be installed into the current nest.)`)
nestHelpEx := " newt nest create <nest-name> [, <nest-skele-url>]\n"
nestHelpEx += " newt nest list-clutches\n"
nestHelpEx += " newt nest show-clutch <clutch-name>\n"
nestHelpEx += " newt nest add-clutch <clutch-name> <clutch-url>\n"
nestHelpEx += " newt nest generate-clutch <clutch-name> <clutch-url>"
nestCmd = &cobra.Command{
Use: "nest",
Short: "Commands to manage nests & clutches (remote egg repositories)",
Long: nestHelpText,
Example: nestHelpEx,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cli.Init(NewtLogLevel, newtSilent, newtQuiet, newtVerbose)
var err error
if cmd != nestCmd && cmd != createCmd {
NewtNest, err = cli.NewNest()
if err != nil {
NewtUsage(cmd, err)
}
}
},
Run: func(cmd *cobra.Command, args []string) {
NewtUsage(cmd, nil)
},
}
createHelpText := formatHelp(`Create a new nest, specified by <nest-name>.
If the optional <nest-url> parameter is specified, then download the
skeleton of the nest file from that URL, instead of using the default.`)
createHelpEx := " newt nest create <nest-name> [, <nest-url>]\n"
createHelpEx += " newt nest create mynest"
createCmd = &cobra.Command{
Use: "create",
Short: "Create a new nest",
Long: createHelpText,
Example: createHelpEx,
Run: nestCreateCmd,
}
nestCmd.AddCommand(createCmd)
generateHelpText := formatHelp(`Generate a clutch file from a snapshot
of the eggs in the current directory. generate-clutch takes two
arguments, the name of the current nest and the URL at which
the nest is located.`)
generateHelpEx := " newt nest generate-clutch <name> <url>\n"
generateHelpEx += " newt nest generate-clutch larva " +
"https://www.github.com/mynewt/larva"
generateCmd := &cobra.Command{
Use: "generate-clutch",
Short: "Generate a clutch file from the eggs in the current directory",
Long: generateHelpText,
Example: generateHelpEx,
Run: nestGenerateClutchCmd,
}
nestCmd.AddCommand(generateCmd)
addClutchHelpText := formatHelp(`Add a remote clutch to the current nest.
When search for eggs to install, the clutch specified by clutch-name
and clutch-url will be searched for eggs that match the search. This
includes both direct searches with newt egg hunt, as well as resolving
dependencies in egg.yml files.`)
addClutchHelpEx := " newt nest add-clutch <clutch-name> <clutch-url>\n"
addClutchHelpEx += " newt nest add-clutch larva " +
"https://www.github.com/mynewt/larva"
addClutchCmd := &cobra.Command{
Use: "add-clutch",
Short: "Add a remote clutch, and put it in the current nest",
Long: addClutchHelpText,
Example: addClutchHelpEx,
Run: nestAddClutchCmd,
}
addClutchCmd.Flags().StringVarP(&NewtBranchClutch, "branch", "b", "master",
"Branch (or tag) of the clutch to install from.")
nestCmd.AddCommand(addClutchCmd)
listClutchesHelpText := formatHelp(`List the clutches installed in the current
nest. A clutch represents a collection of eggs in a nest. List clutches
includes the current nest, along with any remote clutches that have been
added using the add-clutch command.`)
listClutchesHelpEx := " newt nest list-clutches"
listClutchesCmd := &cobra.Command{
Use: "list-clutches",
Short: "List the clutches installed in the current nest",
Long: listClutchesHelpText,
Example: listClutchesHelpEx,
Run: nestListClutchesCmd,
}
nestCmd.AddCommand(listClutchesCmd)
showClutchHelpText := formatHelp(`Show information about a clutch, given by the
<clutch-name> parameter. Displays the clutch name, URL and packages
associated with a given clutch.`)
showClutchHelpEx := " newt nest show-clutch <clutch-name>\n"
showClutchHelpEx += " newt nest show-clutch larva"
showClutchCmd := &cobra.Command{
Use: "show-clutch",
Short: "Show an individual clutch in the current nest",
Long: showClutchHelpText,
Example: showClutchHelpEx,
Run: nestShowClutchCmd,
}
nestCmd.AddCommand(showClutchCmd)
baseCmd.AddCommand(nestCmd)
}
func parseCmds() *cobra.Command {
newtHelpText := formatHelp(`Newt allows you to create your own embedded
project based on the Mynewt operating system. Newt provides both
build and package management in a single tool, which allows you to
compose an embedded workspace, and set of projects, and then build
the necessary artifacts from those projects. For more information
on the Mynewt operating system, please visit
https://www.github.com/mynewt/documentation.`)
newtHelpText += "\n\n" + formatHelp(`Please use the newt help command,
and specify the name of the command you want help for, for help on
how to use a specific command`)
newtHelpEx := " newt\n"
newtHelpEx += " newt help [<command-name>]\n"
newtHelpEx += " For help on <command-name>. If not specified, " +
"print this message."
newtCmd := &cobra.Command{
Use: "newt",
Short: "Newt is a tool to help you compose and build your own OS",
Long: newtHelpText,
Example: newtHelpEx,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
newtCmd.PersistentFlags().BoolVarP(&newtVerbose, "verbose", "v", false,
"Enable verbose output when executing commands.")
newtCmd.PersistentFlags().BoolVarP(&newtQuiet, "quiet", "q", false,
"Be quiet; only display error output.")
newtCmd.PersistentFlags().BoolVarP(&newtSilent, "silent", "s", false,
"Be silent; don't output anything.")
newtCmd.PersistentFlags().StringVarP(&NewtLogLevel, "loglevel", "l",
"WARN", "Log level, defaults to WARN.")
versHelpText := formatHelp(`Display the Newt version number.`)
versHelpEx := " newt version"
versCmd := &cobra.Command{
Use: "version",
Short: "Display the Newt version number.",
Long: versHelpText,
Example: versHelpEx,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Newt version: %s\n", NewtVersion)
},
}
newtCmd.AddCommand(versCmd)
targetAddCmds(newtCmd)
eggAddCmds(newtCmd)
nestAddCmds(newtCmd)
return newtCmd
}
func main() {
cmd := parseCmds()
cmd.Execute()
}