| /** |
| * 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()...) |
| }) |
| } |