blob: bf7d6ddf08638a90e2a15fd5e8562f71e913bd11 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 cli
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/spf13/cobra"
"mynewt.apache.org/newt/newt/builder"
"mynewt.apache.org/newt/newt/newtutil"
"mynewt.apache.org/newt/newt/pkg"
"mynewt.apache.org/newt/newt/resolve"
"mynewt.apache.org/newt/newt/syscfg"
"mynewt.apache.org/newt/newt/target"
"mynewt.apache.org/newt/newt/ycfg"
"mynewt.apache.org/newt/util"
)
var amendDelete bool = false
// target variables that can have values amended with the amend command.
var amendVars = []string{"aflags", "cflags", "cxxflags", "lflags", "syscfg"}
var setVars = []string{"aflags", "app", "build_profile", "bsp", "cflags",
"cxxflags", "lflags", "loader", "syscfg"}
func resolveExistingTargetArg(arg string) (*target.Target, error) {
t := ResolveTarget(arg)
if t == nil {
return nil, util.NewNewtError("Unknown target: " + arg)
}
return t, nil
}
// Tells you if a target's directory contains extra user files (i.e., files
// other than pkg.yml).
func targetContainsUserFiles(t *target.Target) (bool, error) {
contents, err := ioutil.ReadDir(t.Package().BasePath())
if err != nil {
return false, err
}
userFiles := false
for _, node := range contents {
name := node.Name()
if name != "." && name != ".." &&
name != pkg.PACKAGE_FILE_NAME && name != target.TARGET_FILENAME {
userFiles = true
break
}
}
return userFiles, nil
}
func pkgVarSliceString(pack *pkg.LocalPackage, key string) string {
vals := pack.PkgY.GetValStringSlice(key, nil)
sort.Strings(vals)
var buffer bytes.Buffer
for _, v := range vals {
buffer.WriteString(v)
buffer.WriteString(" ")
}
return buffer.String()
}
//Process amend command for syscfg target variable
func amendSysCfg(value string, t *target.Target) error {
// Get the current syscfg.vals name-value pairs
sysVals := t.Package().SyscfgY.GetValStringMapString("syscfg.vals", nil)
// Convert the input syscfg into name-value pairs
amendSysVals, err := syscfg.KeyValueFromStr(value)
if err != nil {
return err
}
// Have current syscfg.vals in syscfg.yml file
if sysVals != nil {
// Either delete syscfg variable or replace with new value
for k, v := range amendSysVals {
if amendDelete {
delete(sysVals, k)
} else {
sysVals[k] = v
}
}
} else {
// No syscfg.vals in syscfg.yml file. Use all the new
// syscfg name-value pairs if not deleting
if !amendDelete {
sysVals = amendSysVals
}
}
itfMap := util.StringMapStringToItfMapItf(sysVals)
t.Package().SyscfgY.Replace("syscfg.vals", itfMap)
return nil
}
//Process amend command for aflags, cflags, cxxflags, and lflags target variables.
func amendBuildFlags(kv []string, t *target.Target) error {
pkgVar := "pkg." + kv[0]
curFlags := t.Package().PkgY.GetValStringSlice(pkgVar, nil)
amendFlags := strings.Fields(kv[1])
newFlags := []string{}
exist := false
// add flags
if !amendDelete {
newFlags = curFlags
for _, amendVal := range amendFlags {
exist = false
for _, curVal := range curFlags {
if amendVal == curVal {
exist = true
}
}
// Add flag if flag is not already set
if !exist {
newFlags = append(newFlags, amendVal)
}
}
} else {
// Delete Flag if it exist.
for _, curVal := range curFlags {
exist = false
for _, deleteVal := range amendFlags {
if deleteVal == curVal {
exist = true
break
}
}
// Not deleting this flag, add it to the set of new
// flags to save
if !exist {
newFlags = append(newFlags, curVal)
}
}
}
t.Package().PkgY.Replace(pkgVar, newFlags)
return nil
}
func targetShowCmd(cmd *cobra.Command, args []string) {
TryGetProject()
targetNames := []string{}
if len(args) == 0 {
for name, _ := range target.GetTargets() {
// Don't display the special unittest target; this is used
// internally by newt, so the user doesn't need to know about it.
// XXX: This is a hack; come up with a better solution for unit
// testing.
if !strings.HasSuffix(name, "/unittest") {
targetNames = append(targetNames, name)
}
}
} else {
targetSlice, err := ResolveTargets(args...)
if err != nil {
NewtUsage(cmd, err)
}
for _, t := range targetSlice {
targetNames = append(targetNames, t.FullName())
}
}
sort.Strings(targetNames)
for _, name := range targetNames {
kvPairs := map[string]string{}
util.StatusMessage(util.VERBOSITY_DEFAULT, name+"\n")
target := target.GetTargets()[name]
settings := target.TargetY.AllSettingsAsStrings()
for k, v := range settings {
kvPairs[strings.TrimPrefix(k, "target.")] = v
}
// A few variables come from the base package rather than the target.
kvPairs["syscfg"] = syscfg.KeyValueToStr(
target.Package().SyscfgY.GetValStringMapString("syscfg.vals", nil))
kvPairs["cflags"] = pkgVarSliceString(target.Package(), "pkg.cflags")
kvPairs["cxxflags"] = pkgVarSliceString(target.Package(), "pkg.cxxflags")
kvPairs["lflags"] = pkgVarSliceString(target.Package(), "pkg.lflags")
kvPairs["aflags"] = pkgVarSliceString(target.Package(), "pkg.aflags")
keys := []string{}
for k, _ := range kvPairs {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
val := kvPairs[k]
if len(val) > 0 {
util.StatusMessage(util.VERBOSITY_DEFAULT, " %s=%s\n",
k, kvPairs[k])
}
}
}
}
func targetCmakeCmd(cmd *cobra.Command, args []string) {
TryGetProject()
// Verify and resolve each specified package.
targets, err := ResolveTargets(args...)
if err != nil {
NewtUsage(cmd, err)
return
}
if len(targets) != 1 {
NewtUsage(cmd, err)
return
}
err = builder.CMakeTargetGenerate(targets[0])
if err != nil {
NewtUsage(nil, err)
}
}
func targetSetCmd(cmd *cobra.Command, args []string) {
if len(args) < 2 {
NewtUsage(cmd,
util.NewNewtError("Must specify at least two arguments "+
"(target-name & k=v) to set"))
}
TryGetProject()
// Parse target name.
t, err := resolveExistingTargetArg(args[0])
if err != nil {
NewtUsage(cmd, err)
}
// Parse series of k=v pairs. If an argument doesn't contain a '='
// character, display the valid values for the variable and quit.
vars := [][]string{}
for i := 1; i < len(args); i++ {
kv := strings.SplitN(args[i], "=", 2)
key := strings.TrimPrefix(kv[0], "target.")
supported := false
for _, v := range setVars {
if key == v {
supported = true
break
}
}
if !supported {
NewtUsage(cmd,
util.NewNewtError("Not a valid variable: "+key))
}
if !strings.HasPrefix(kv[0], "target.") {
kv[0] = "target." + kv[0]
}
// Make sure it is a valid variable.
if len(kv) == 1 {
// User entered a variable name without a value.
NewtUsage(cmd, nil)
}
// Trim trailing slash from value. This is necessary when tab
// completion is used to fill in the value.
kv[1] = strings.TrimSuffix(kv[1], "/")
vars = append(vars, kv)
}
// Set each specified variable in the target.
for _, kv := range vars {
// A few variables are special cases; they get set in the base package
// instead of the target.
if kv[0] == "target.syscfg" {
t.Package().SyscfgY = ycfg.YCfg{}
kv, err := syscfg.KeyValueFromStr(kv[1])
if err != nil {
NewtUsage(cmd, err)
}
itfMap := util.StringMapStringToItfMapItf(kv)
t.Package().SyscfgY.Replace("syscfg.vals", itfMap)
} else if kv[0] == "target.cflags" ||
kv[0] == "target.cxxflags" ||
kv[0] == "target.lflags" ||
kv[0] == "target.aflags" {
kv[0] = "pkg." + strings.TrimPrefix(kv[0], "target.")
if kv[1] == "" {
// User specified empty value; delete variable.
t.Package().PkgY.Replace(kv[0], nil)
} else {
t.Package().PkgY.Replace(kv[0], strings.Fields(kv[1]))
}
} else {
if kv[1] == "" {
// User specified empty value; delete variable.
t.TargetY.Delete(kv[0])
} else {
// Assign value to specified variable.
t.TargetY.Replace(kv[0], kv[1])
}
}
}
if err := t.Save(); err != nil {
NewtUsage(cmd, err)
}
for _, kv := range vars {
if kv[1] == "" {
util.StatusMessage(util.VERBOSITY_DEFAULT,
"Target %s successfully unset %s\n", t.FullName(), kv[0])
} else {
util.StatusMessage(util.VERBOSITY_DEFAULT,
"Target %s successfully set %s to %s\n", t.FullName(), kv[0],
kv[1])
}
}
}
func targetAmendCmd(cmd *cobra.Command, args []string) {
if len(args) < 2 {
NewtUsage(cmd,
util.NewNewtError("Must specify at least two arguments "+
"(target-name & variable=value) to append"))
}
TryGetProject()
// Parse target name.
t, err := resolveExistingTargetArg(args[0])
if err != nil {
NewtUsage(cmd, err)
}
// Parse series of k=v pairs. If an argument doesn't contain a '='
// character, display the valid values for the variable and quit.
vars := [][]string{}
for i := 1; i < len(args); i++ {
kv := strings.SplitN(args[i], "=", 2)
// Check that the variable can have values appended.
valid := false
for _, v := range amendVars {
if kv[0] == v {
valid = true
break
}
}
if !valid {
NewtUsage(cmd,
util.NewNewtError("Cannot amend values for "+kv[0]))
}
if len(kv) == 1 {
// User entered a variable name without a '='
NewtUsage(cmd, nil)
}
kv[1] = strings.TrimSpace(kv[1])
if kv[1] == "" {
NewtUsage(cmd,
util.NewNewtError("Must provide a value to"+
" append for variable "+kv[0]))
}
// Trim trailing slash from value. This is necessary when tab
// completion is used to fill in the value.
kv[1] = strings.TrimSuffix(kv[1], "/")
vars = append(vars, kv)
}
for _, kv := range vars {
if kv[0] == "syscfg" {
err = amendSysCfg(kv[1], t)
if err != nil {
NewtUsage(cmd, err)
}
} else if kv[0] == "cflags" ||
kv[0] == "cxxflags" ||
kv[0] == "lflags" ||
kv[0] == "aflags" {
err = amendBuildFlags(kv, t)
if err != nil {
NewtUsage(cmd, err)
}
}
}
if err := t.Save(); err != nil {
NewtUsage(cmd, err)
}
for _, kv := range vars {
util.StatusMessage(util.VERBOSITY_DEFAULT,
"Amended %s for Target %s successfully\n",
kv[0], t.FullName())
}
}
func targetCreateCmd(cmd *cobra.Command, args []string) {
if len(args) != 1 {
NewtUsage(cmd, util.NewNewtError("Missing target name"))
}
proj := TryGetProject()
pkgName, err := ResolveNewTargetName(args[0])
if err != nil {
NewtUsage(cmd, err)
}
repo := proj.LocalRepo()
pack := pkg.NewLocalPackage(repo, repo.Path()+"/"+pkgName)
pack.SetName(pkgName)
pack.SetType(pkg.PACKAGE_TYPE_TARGET)
t := target.NewTarget(pack)
err = t.Save()
if err != nil {
NewtUsage(nil, err)
} else {
util.StatusMessage(util.VERBOSITY_DEFAULT,
"Target %s successfully created\n", pkgName)
}
}
func targetDelOne(t *target.Target) error {
if !newtutil.NewtForce {
// Determine if the target directory contains extra user files. If it
// does, a prompt (or force) is required to delete it.
userFiles, err := targetContainsUserFiles(t)
if err != nil {
return err
}
if userFiles {
fmt.Printf("Target directory %s contains some extra content; "+
"delete anyway? (y/N): ", t.Package().BasePath())
rsp := PromptYesNo(false)
if !rsp {
return nil
}
}
}
if err := os.RemoveAll(t.Package().BasePath()); err != nil {
return util.NewNewtError(err.Error())
}
util.StatusMessage(util.VERBOSITY_DEFAULT,
"Target %s successfully deleted.\n", t.FullName())
return nil
}
func targetDelCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd, util.NewNewtError("Must specify at least one "+
"target to delete"))
}
TryGetProject()
targets, err := ResolveTargets(args...)
if err != nil {
NewtUsage(cmd, err)
}
for _, t := range targets {
if err := targetDelOne(t); err != nil {
NewtUsage(cmd, err)
}
}
}
func targetCopyCmd(cmd *cobra.Command, args []string) {
if len(args) != 2 {
NewtUsage(cmd, util.NewNewtError("Must specify exactly one "+
"source target and one destination target"))
}
proj := TryGetProject()
srcTarget, err := resolveExistingTargetArg(args[0])
if err != nil {
NewtUsage(cmd, err)
}
dstName, err := ResolveNewTargetName(args[1])
if err != nil {
NewtUsage(cmd, err)
}
// Copy the source target's base package and adjust the fields which need
// to change.
dstTarget := srcTarget.Clone(proj.LocalRepo(), dstName)
// Save the new target.
err = dstTarget.Save()
if err != nil {
NewtUsage(nil, err)
}
// Copy syscfg.yml file.
srcSyscfgPath := fmt.Sprintf("%s/%s",
srcTarget.Package().BasePath(),
pkg.SYSCFG_YAML_FILENAME)
dstSyscfgPath := fmt.Sprintf("%s/%s",
dstTarget.Package().BasePath(),
pkg.SYSCFG_YAML_FILENAME)
if err := util.CopyFile(srcSyscfgPath, dstSyscfgPath); err != nil {
// If there is just no source syscfg.yml file, that is not an error.
if !util.IsNotExist(err) {
NewtUsage(nil, err)
}
}
util.StatusMessage(util.VERBOSITY_DEFAULT,
"Target successfully copied; %s --> %s\n",
srcTarget.FullName(), dstTarget.FullName())
}
func printSetting(entry syscfg.CfgEntry) {
util.StatusMessage(util.VERBOSITY_DEFAULT,
" * Setting: %s\n", entry.Name)
util.StatusMessage(util.VERBOSITY_DEFAULT,
" * Description: %s\n", entry.Description)
util.StatusMessage(util.VERBOSITY_DEFAULT,
" * Value: %s", entry.Value)
util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
if len(entry.History) > 1 {
util.StatusMessage(util.VERBOSITY_DEFAULT,
" * Overridden: ")
for i := 1; i < len(entry.History); i++ {
util.StatusMessage(util.VERBOSITY_DEFAULT, "%s, ",
entry.History[i].Source.FullName())
}
util.StatusMessage(util.VERBOSITY_DEFAULT,
"default=%s\n", entry.History[0].Value)
}
if len(entry.ValueRefName) > 0 {
util.StatusMessage(util.VERBOSITY_DEFAULT,
" * Copied from: %s\n",
entry.ValueRefName)
}
}
func printBriefSetting(entry syscfg.CfgEntry) {
util.StatusMessage(util.VERBOSITY_DEFAULT, " %s: %s",
entry.Name, entry.Value)
var extras []string
if len(entry.History) > 1 {
s := fmt.Sprintf("overridden by %s",
entry.History[len(entry.History)-1].Source.FullName())
extras = append(extras, s)
}
if len(entry.ValueRefName) > 0 {
s := fmt.Sprintf("copied from %s", entry.ValueRefName)
extras = append(extras, s)
}
if len(extras) > 0 {
util.StatusMessage(util.VERBOSITY_DEFAULT, " (%s)",
strings.Join(extras, ", "))
}
util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
}
func printPkgCfg(pkgName string, cfg syscfg.Cfg, entries []syscfg.CfgEntry) {
util.StatusMessage(util.VERBOSITY_DEFAULT, "* PACKAGE: %s\n", pkgName)
settingNames := make([]string, len(entries))
for i, entry := range entries {
settingNames[i] = entry.Name
}
sort.Strings(settingNames)
for _, name := range settingNames {
printSetting(cfg.Settings[name])
}
}
func printCfg(targetName string, cfg syscfg.Cfg) {
if errText := cfg.ErrorText(); errText != "" {
util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
}
util.StatusMessage(util.VERBOSITY_DEFAULT, "Syscfg for %s:\n", targetName)
pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
pkgNames := make([]string, 0, len(pkgNameEntryMap))
for pkgName, _ := range pkgNameEntryMap {
pkgNames = append(pkgNames, pkgName)
}
sort.Strings(pkgNames)
for i, pkgName := range pkgNames {
if i > 0 {
util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
}
printPkgCfg(pkgName, cfg, pkgNameEntryMap[pkgName])
}
}
func printPkgBriefCfg(pkgName string, cfg syscfg.Cfg, entries []syscfg.CfgEntry) {
util.StatusMessage(util.VERBOSITY_DEFAULT, "[%s]\n", pkgName)
settingNames := make([]string, len(entries))
for i, entry := range entries {
settingNames[i] = entry.Name
}
sort.Strings(settingNames)
for _, name := range settingNames {
printBriefSetting(cfg.Settings[name])
}
}
func printBriefCfg(targetName string, cfg syscfg.Cfg) {
if errText := cfg.ErrorText(); errText != "" {
util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
}
util.StatusMessage(util.VERBOSITY_DEFAULT, "Brief syscfg for %s:\n", targetName)
pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
pkgNames := make([]string, 0, len(pkgNameEntryMap))
for pkgName, _ := range pkgNameEntryMap {
pkgNames = append(pkgNames, pkgName)
}
sort.Strings(pkgNames)
for i, pkgName := range pkgNames {
if i > 0 {
util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
}
printPkgBriefCfg(pkgName, cfg, pkgNameEntryMap[pkgName])
}
}
func yamlPkgCfg(w io.Writer, pkgName string, cfg syscfg.Cfg,
entries []syscfg.CfgEntry) {
settingNames := make([]string, len(entries))
for i, entry := range entries {
settingNames[i] = entry.Name
}
sort.Strings(settingNames)
fmt.Fprintf(w, " ### %s\n", pkgName)
for _, name := range settingNames {
fmt.Fprintf(w, " %s: '%s'\n", name, cfg.Settings[name].Value)
}
}
func yamlCfg(cfg syscfg.Cfg) string {
if errText := cfg.ErrorText(); errText != "" {
util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
}
pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
pkgNames := make([]string, 0, len(pkgNameEntryMap))
for pkgName, _ := range pkgNameEntryMap {
pkgNames = append(pkgNames, pkgName)
}
sort.Strings(pkgNames)
buf := bytes.Buffer{}
fmt.Fprintf(&buf, "syscfg.vals:\n")
for i, pkgName := range pkgNames {
if i > 0 {
fmt.Fprintf(&buf, "\n")
}
yamlPkgCfg(&buf, pkgName, cfg, pkgNameEntryMap[pkgName])
}
return string(buf.Bytes())
}
func targetBuilderConfigResolve(b *builder.TargetBuilder) *resolve.Resolution {
res, err := b.Resolve()
if err != nil {
NewtUsage(nil, err)
}
warningText := strings.TrimSpace(res.WarningText())
if warningText != "" {
log.Warn(warningText + "\n")
}
return res
}
func targetConfigShowCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd,
util.NewNewtError("Must specify target or unittest name"))
}
TryGetProject()
for i, arg := range args {
b, err := TargetBuilderForTargetOrUnittest(arg)
if err != nil {
NewtUsage(cmd, err)
}
res := targetBuilderConfigResolve(b)
printCfg(b.GetTarget().Name(), res.Cfg)
if i < len(args)-1 {
util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
}
}
}
func targetConfigBriefCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd,
util.NewNewtError("Must specify target or unittest name"))
}
TryGetProject()
for i, arg := range args {
b, err := TargetBuilderForTargetOrUnittest(arg)
if err != nil {
NewtUsage(cmd, err)
}
res := targetBuilderConfigResolve(b)
printBriefCfg(b.GetTarget().Name(), res.Cfg)
if i < len(args)-1 {
util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
}
}
}
func targetConfigInitCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd,
util.NewNewtError("Must specify target or unittest name"))
}
type entry struct {
lpkg *pkg.LocalPackage
path string
b *builder.TargetBuilder
exists bool
}
TryGetProject()
anyExist := false
entries := make([]entry, len(args))
for i, pkgName := range args {
e := &entries[i]
b, err := TargetBuilderForTargetOrUnittest(pkgName)
if err != nil {
NewtUsage(cmd, err)
}
e.b = b
e.lpkg = b.GetTestPkg()
if e.lpkg == nil {
e.lpkg = b.GetTarget().Package()
}
e.path = builder.PkgSyscfgPath(e.lpkg.BasePath())
if util.NodeExist(e.path) {
e.exists = true
anyExist = true
}
}
if anyExist && !newtutil.NewtForce {
util.StatusMessage(util.VERBOSITY_DEFAULT,
"Configuration files already exist:\n")
for _, e := range entries {
if e.exists {
util.StatusMessage(util.VERBOSITY_DEFAULT, " * %s\n",
e.path)
}
}
util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
fmt.Printf("Overwrite them? (y/N): ")
rsp := PromptYesNo(false)
if !rsp {
return
}
}
for _, e := range entries {
res := targetBuilderConfigResolve(e.b)
yaml := yamlCfg(res.Cfg)
if err := ioutil.WriteFile(e.path, []byte(yaml), 0644); err != nil {
NewtUsage(nil, util.FmtNewtError("Error writing file \"%s\"; %s",
e.path, err.Error()))
}
}
}
func targetDepCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd,
util.NewNewtError("Must specify target or unittest name"))
}
TryGetProject()
b, err := TargetBuilderForTargetOrUnittest(args[0])
if err != nil {
NewtUsage(cmd, err)
}
res, err := b.Resolve()
if err != nil {
NewtUsage(nil, err)
}
dg, err := b.CreateDepGraph()
if err != nil {
NewtUsage(nil, err)
}
// If user specified any package names, only include specified packages.
if len(args) > 1 {
rpkgs, err := ResolveRpkgs(res, args[1:])
if err != nil {
NewtUsage(cmd, err)
}
var missingRpkgs []*resolve.ResolvePackage
dg, missingRpkgs = builder.FilterDepGraph(dg, rpkgs)
for _, rpkg := range missingRpkgs {
util.StatusMessage(util.VERBOSITY_QUIET,
"Warning: Package \"%s\" not included in target \"%s\"\n",
rpkg.Lpkg.FullName(), b.GetTarget().FullName())
}
}
if len(dg) > 0 {
util.StatusMessage(util.VERBOSITY_DEFAULT,
builder.DepGraphText(dg)+"\n")
}
}
func targetRevdepCmd(cmd *cobra.Command, args []string) {
if len(args) < 1 {
NewtUsage(cmd, util.NewNewtError("Must specify target name"))
}
TryGetProject()
b, err := TargetBuilderForTargetOrUnittest(args[0])
if err != nil {
NewtUsage(cmd, err)
}
res, err := b.Resolve()
if err != nil {
NewtUsage(nil, err)
}
dg, err := b.CreateRevdepGraph()
if err != nil {
NewtUsage(nil, err)
}
// If user specified any package names, only include specified packages.
if len(args) > 1 {
rpkgs, err := ResolveRpkgs(res, args[1:])
if err != nil {
NewtUsage(cmd, err)
}
var missingRpkgs []*resolve.ResolvePackage
dg, missingRpkgs = builder.FilterDepGraph(dg, rpkgs)
for _, rpkg := range missingRpkgs {
util.StatusMessage(util.VERBOSITY_QUIET,
"Warning: Package \"%s\" not included in target \"%s\"\n",
rpkg.Lpkg.FullName(), b.GetTarget().FullName())
}
}
if len(dg) > 0 {
util.StatusMessage(util.VERBOSITY_DEFAULT,
builder.RevdepGraphText(dg)+"\n")
}
}
func AddTargetCommands(cmd *cobra.Command) {
targetHelpText := ""
targetHelpEx := ""
targetCmd := &cobra.Command{
Use: "target",
Short: "Commands to create, delete, configure, and query targets",
Long: targetHelpText,
Example: targetHelpEx,
Run: func(cmd *cobra.Command, args []string) {
cmd.Usage()
},
}
cmd.AddCommand(targetCmd)
showHelpText := "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)
AddTabCompleteFn(showCmd, targetList)
cmakeHelpText := "Generate CMakeLists.txt for target specified " +
"by <target-name>."
cmakeHelpEx := " newt target cmake <target-name>\n"
cmakeHelpEx += " newt target cmake my_target1"
cmakeCmd := &cobra.Command{
Use: "cmake",
Short: "",
Long: cmakeHelpText,
Example: cmakeHelpEx,
Run: targetCmakeCmd,
}
targetCmd.AddCommand(cmakeCmd)
AddTabCompleteFn(cmakeCmd, targetList)
setHelpText := "Set a target variable (<var-name>) on target "
setHelpText += "<target-name> to value <value>.\n"
setHelpText += "Variables that can be set are:\n"
setHelpText += strings.Join(setVars, "\n") + "\n\n"
setHelpText += "Warning: When setting the syscfg variable, a new syscfg.yml file\n"
setHelpText += "is created and the current settings are deleted. Only the settings\n"
setHelpText += "specified in the command are saved in the syscfg.yml file."
setHelpText += "\nIf you want to change or add a new syscfg value and keep the other\n"
setHelpText += "syscfg values, use the newt target amend command.\n"
setHelpEx := " newt target set my_target1 build_profile=optimized "
setHelpEx += "cflags=\"-DNDEBUG\"\n"
setHelpEx += " newt target set my_target1 "
setHelpEx += "syscfg=LOG_NEWTMGR=1:CONFIG_NEWTMGR=0\n"
setCmd := &cobra.Command{
Use: "set <target-name> <var-name>=<value> " +
"[<var-name>=<value>...]",
Short: "Set target configuration variable",
Long: setHelpText,
Example: setHelpEx,
Run: targetSetCmd,
}
targetCmd.AddCommand(setCmd)
AddTabCompleteFn(setCmd, targetList)
amendHelpText := "Add, change, or delete values for multi-value target variables\n\n"
amendHelpText += "Variables that can have values amended are:\n"
amendHelpText += strings.Join(amendVars, "\n") + "\n\n"
amendHelpText += "To change the value for a single value variable, such as bsp, use the\nnewt target set command.\n"
amendHelpEx := " newt target amend my_target cflags=\"-DNDEBUG -DTEST\"\n"
amendHelpEx += " Adds -DDEBUG and -DTEST to cflags\n\n"
amendHelpEx += " newt target amend my_target lflags=\"-Lmylib\" "
amendHelpEx += "syscfg=LOG_LEVEL:CONFIG_NEWTMGR=0\n"
amendHelpEx += " Adds -Lmylib to lflags and syscfg variables LOG_LEVEL=1 and CONFIG_NEWTMGR=0\n\n"
amendHelpEx += " newt target amend my_target -d syscfg=CONFIG_NEWTMGR "
amendHelpEx += "cflags=\"-DNDEBUG\"\n"
amendHelpEx += " Deletes syscfg variable CONFIG_NEWTMGR and -DNDEBUG from cflags\n"
amendCmd := &cobra.Command{
Use: "amend <target-name> <var-name>=<value>" +
"[<var-name>=<value>...]\n",
Short: "Add, change, or delete values for multi-value target variables",
Long: amendHelpText,
Example: amendHelpEx,
Run: targetAmendCmd,
}
amendCmd.Flags().BoolVarP(&amendDelete, "delete", "d", false,
"Delete Variable values")
targetCmd.AddCommand(amendCmd)
AddTabCompleteFn(amendCmd, targetList)
createHelpText := "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)
delHelpText := "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,
}
delCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
"force", "f", false,
"Force delete of targets with user files without prompt")
targetCmd.AddCommand(delCmd)
copyHelpText := "Create a new target <dst-target> by cloning <src-target>"
copyHelpEx := " newt target copy blinky_sim my_target"
copyCmd := &cobra.Command{
Use: "copy <src-target> <dst-target>",
Short: "Copy target",
Long: copyHelpText,
Example: copyHelpEx,
Run: targetCopyCmd,
}
targetCmd.AddCommand(copyCmd)
AddTabCompleteFn(copyCmd, targetList)
configHelpText := "View or populate a target's system configuration"
configCmd := &cobra.Command{
Use: "config",
Short: configHelpText,
Long: configHelpText,
Run: func(cmd *cobra.Command, args []string) {
cmd.Usage()
},
}
targetCmd.AddCommand(configCmd)
configShowCmd := &cobra.Command{
Use: "show <target> [target...]",
Short: "View a target's system configuration",
Long: "View a target's system configuration",
Run: targetConfigShowCmd,
}
configCmd.AddCommand(configShowCmd)
AddTabCompleteFn(configShowCmd, func() []string {
return append(targetList(), unittestList()...)
})
configBriefCmd := &cobra.Command{
Use: "brief <target> [target...]",
Short: "View a summary of target's system configuration",
Long: "View a summary of target's system configuration",
Run: targetConfigBriefCmd,
}
configCmd.AddCommand(configBriefCmd)
AddTabCompleteFn(configBriefCmd, func() []string {
return append(targetList(), unittestList()...)
})
configInitCmd := &cobra.Command{
Use: "init",
Short: "Populate a target's system configuration file",
Long: "Populate a target's system configuration file (syscfg). " +
"Unspecified settings are given default values.",
Run: targetConfigInitCmd,
}
configInitCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
"force", "f", false,
"Force overwrite of target configuration")
configCmd.AddCommand(configInitCmd)
AddTabCompleteFn(configInitCmd, func() []string {
return append(targetList(), unittestList()...)
})
depHelpText := "View a target's dependency graph."
depCmd := &cobra.Command{
Use: "dep <target> [pkg-1] [pkg-2] [...]",
Short: "View target's dependency graph",
Long: depHelpText,
Run: targetDepCmd,
}
targetCmd.AddCommand(depCmd)
AddTabCompleteFn(depCmd, func() []string {
return append(targetList(), unittestList()...)
})
revdepHelpText := "View a target's reverse-dependency graph."
revdepCmd := &cobra.Command{
Use: "revdep <target> [pkg-1] [pkg-2] [...]",
Short: "View target's reverse-dependency graph",
Long: revdepHelpText,
Run: targetRevdepCmd,
}
targetCmd.AddCommand(revdepCmd)
AddTabCompleteFn(revdepCmd, func() []string {
return append(targetList(), unittestList()...)
})
}