You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/03/02 05:27:04 UTC
[3/3] incubator-mynewt-newt git commit: (MYNEWT-141) Replace SQLite
targets with yml files.
(MYNEWT-141) Replace SQLite targets with yml files.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/1d8f746f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/1d8f746f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/1d8f746f
Branch: refs/heads/develop
Commit: 1d8f746f58fd81a5d975a6ce7319dd45cc2ba848
Parents: 9305e8e
Author: Christopher Collins <cc...@gmail.com>
Authored: Mon Feb 29 18:24:09 2016 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Tue Mar 1 20:21:04 2016 -0800
----------------------------------------------------------------------
newt/cli/legacy.go | 109 ++++++++++++++++++++++++
newt/cli/repo.go | 219 ++++++++++--------------------------------------
newt/cli/target.go | 180 ++++++++++++++++++++++-----------------
newt/newt.go | 57 ++++++++-----
4 files changed, 291 insertions(+), 274 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/1d8f746f/newt/cli/legacy.go
----------------------------------------------------------------------
diff --git a/newt/cli/legacy.go b/newt/cli/legacy.go
new file mode 100644
index 0000000..bdb7303
--- /dev/null
+++ b/newt/cli/legacy.go
@@ -0,0 +1,109 @@
+/**
+ * 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 (
+ "database/sql"
+ _ "github.com/mattn/go-sqlite3"
+ "log"
+ "os"
+ "strings"
+)
+
+// Migrates target definitions from the legacy sqlite database to
+// "targets/<target-name>/pkg.yml". If a target is already in the new format,
+// it is not modified. On success, the legacy database is renamed to prevent
+// subsequent migrations. The database file is renamed as follows:
+// .app/app.db --> .app/legacy-app.db
+//
+// @return true if any targets were migrated.
+func LegacyMigrateTargets(repo *Repo) bool {
+ const TARGET_SECT_PREFIX = "_target_"
+
+ dbName := repo.StorePath + "/app.db"
+ db, err := sql.Open("sqlite3", dbName)
+ if err != nil {
+ return false
+ }
+
+ // Populate repo configuration
+ log.Printf("[DEBUG] Reading legacy repo configuration from %s", dbName)
+ rows, err := db.Query("SELECT cfg_name,key,value FROM newt_cfg")
+ if err != nil {
+ return false
+ }
+ defer rows.Close()
+
+ // Copy all target settings from the database into the contents map.
+ contents := map[string]map[string]string{}
+ for rows.Next() {
+ var cfgName sql.NullString
+ var cfgKey sql.NullString
+ var cfgVal sql.NullString
+
+ err := rows.Scan(&cfgName, &cfgKey, &cfgVal)
+ if err != nil {
+ return false
+ }
+
+ if strings.HasPrefix(cfgName.String, TARGET_SECT_PREFIX) {
+ mapping, ok := contents[cfgName.String]
+ if !ok {
+ mapping = make(map[string]string)
+ contents[cfgName.String] = mapping
+ }
+
+ mapping[cfgKey.String] = cfgVal.String
+ }
+ }
+
+ // Iterate through the contents map, populating the target store with each
+ // target that doesn't already exist.
+ anyMigrated := false
+ for prefixedName, mapping := range contents {
+ name := prefixedName[len(TARGET_SECT_PREFIX):len(prefixedName)]
+
+ if !TargetExists(repo, name) {
+ target := NewTarget(repo, name)
+ for k, v := range mapping {
+ log.Printf("[DEBUG] Migrating legacy target %s, key=%s val=%s",
+ name, k, v)
+ target.Vars[k] = v
+ }
+
+ err := target.Save()
+ if err != nil {
+ return anyMigrated
+ }
+
+ anyMigrated = true
+ }
+ }
+
+ newName := repo.StorePath + "/legacy-app.db"
+ log.Printf("[DEBUG] Renaming legacy database: %s --> %s", dbName, newName)
+ err = os.Rename(dbName, newName)
+ if err != nil {
+ StatusMessage(VERBOSITY_QUIET, "Warning: Failed to rename legacy "+
+ "database (%s --> %s); %s\n", dbName, newName, err.Error())
+ }
+
+ return anyMigrated
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/1d8f746f/newt/cli/repo.go
----------------------------------------------------------------------
diff --git a/newt/cli/repo.go b/newt/cli/repo.go
index a5066b4..fb286bd 100644
--- a/newt/cli/repo.go
+++ b/newt/cli/repo.go
@@ -20,15 +20,12 @@
package cli
import (
- "database/sql"
"fmt"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
-
- _ "github.com/mattn/go-sqlite3"
)
type Repo struct {
@@ -52,11 +49,8 @@ type Repo struct {
AddlPackagePaths []string
- // Configuration
- Config map[string]map[string]string
-
- // The database handle for the repo configuration database
- db *sql.DB
+ // Targets
+ Targets map[string]map[string]string
}
// Create a new Repo object and initialize it
@@ -165,190 +159,69 @@ func (repo *Repo) getRepoFile() (string, error) {
return rFile, err
}
-// Create the contents of the configuration database
-func (repo *Repo) createDb(db *sql.DB) error {
- query := `
- CREATE TABLE IF NOT EXISTS newt_cfg (
- cfg_name VARCHAR(255) NOT NULL,
- key VARCHAR(255) NOT NULL,
- value TEXT
- )
- `
- _, err := db.Exec(query)
- if err != nil {
- return NewNewtError(err.Error())
- } else {
- return nil
- }
+func (repo *Repo) TargetDir(targetName string) string {
+ return repo.BasePath + "/targets/" + targetName
}
-// Initialize the configuration database specified by dbName. If the database
-// doesn't exist, create it.
-func (repo *Repo) initDb(dbName string) error {
- db, err := sql.Open("sqlite3", dbName)
+// Loads a single target definition residing in the specified directory. The
+// path must contain a pkg.yml file at the top level to be a valid target
+// definion.
+func (repo *Repo) loadTarget(path string) error {
+ v, err := ReadConfig(path, "pkg")
if err != nil {
return err
}
- repo.db = db
-
- err = repo.createDb(db)
- if err != nil {
- return err
- }
-
- // Populate repo configuration
- log.Printf("[DEBUG] Populating Repo configuration from %s", dbName)
-
- rows, err := db.Query("SELECT * FROM newt_cfg")
- if err != nil {
- return NewNewtError(err.Error())
- }
- defer rows.Close()
-
- for rows.Next() {
- var cfgName sql.NullString
- var cfgKey sql.NullString
- var cfgVal sql.NullString
- err := rows.Scan(&cfgName, &cfgKey, &cfgVal)
- if err != nil {
- return NewNewtError(err.Error())
- }
-
- log.Printf("[DEBUG] Setting sect %s, key %s to val %s", cfgName.String,
- cfgKey.String, cfgVal.String)
-
- _, ok := repo.Config[cfgName.String]
- if !ok {
- repo.Config[cfgName.String] = make(map[string]string)
- }
-
- repo.Config[cfgName.String][cfgKey.String] = cfgVal.String
- }
-
- return nil
-}
-
-// Get a configuration variable in section sect, with key
-// error is populated if variable doesn't exist
-func (repo *Repo) GetConfig(sect string, key string) (string, error) {
- sectMap, ok := repo.Config[sect]
+ targetName := filepath.Base(path)
+ targetMap, ok := repo.Targets[targetName]
if !ok {
- return "", NewNewtError("No configuration section exists")
+ targetMap = make(map[string]string)
+ repo.Targets[targetName] = targetMap
}
-
- val, ok := sectMap[key]
- if !ok {
- return "", NewNewtError("No configuration variable exists")
+ settings := v.AllSettings()
+ for k, v := range settings {
+ targetMap[k] = v.(string)
}
- return val, nil
-}
-
-func (repo *Repo) GetConfigSect(sect string) (map[string]string, error) {
- sm, ok := repo.Config[sect]
- if !ok {
- return nil, NewNewtError("No configuration section exists")
- }
-
- return sm, nil
+ return nil
}
-// Delete a configuration variable in section sect with key and val
-// Returns an error if configuration variable cannot be deleted
-// (most likely due to database error or key not existing)
-func (repo *Repo) DelConfig(sect string, key string) error {
- db := repo.db
-
- log.Printf("[DEBUG] Deleting sect %s, key %s", sect, key)
-
- tx, err := db.Begin()
- if err != nil {
+// Loads all target definitions rooted at the specified path. Targets have the
+// following file structure:
+// <path>/<target-name>/pkg.yml
+func (repo *Repo) loadPath(path string) error {
+ targetDirList, err := ioutil.ReadDir(path)
+ if err != nil && !os.IsNotExist(err) {
return NewNewtError(err.Error())
}
- stmt, err := tx.Prepare("DELETE FROM newt_cfg WHERE cfg_name=? AND key=?")
- if err != nil {
- return err
- }
- defer stmt.Close()
-
- res, err := stmt.Exec(sect, key)
- if err != nil {
- return err
- }
+ for _, node := range targetDirList {
+ name := node.Name()
+ if node.IsDir() &&
+ !filepath.HasPrefix(name, ".") &&
+ !filepath.HasPrefix(name, "..") {
- tx.Commit()
+ fullPath := path + name + "/"
- if affected, err := res.RowsAffected(); affected > 0 && err == nil {
- log.Printf("[DEBUG] sect %s, key %s successfully deleted from database",
- sect, key)
- } else {
- log.Printf("[DEBUG] sect %s, key %s not found, considering \"delete\" successful",
- sect, key)
+ err = repo.loadTarget(fullPath)
+ if err != nil {
+ return err
+ }
+ }
}
return nil
}
-// Set a configuration variable in section sect with key, and val
-// Returns an error if configuration variable cannot be set
-// (most likely not able to set it in database.)
-func (repo *Repo) SetConfig(sect string, key string, val string) error {
- _, ok := repo.Config[sect]
+// Retrieves the key-value variable map for the target with the specified name.
+// error is populated if variable doesn't exist
+func (repo *Repo) GetTargetVars(name string) (map[string]string, error) {
+ targetVars, ok := repo.Targets[name]
if !ok {
- repo.Config[sect] = make(map[string]string)
- }
- repo.Config[sect][key] = val
-
- // Store config
- log.Printf("[DEBUG] Storing value %s into key %s for section %s",
- val, sect, key)
- db := repo.db
-
- tx, err := db.Begin()
- if err != nil {
- return NewNewtError(err.Error())
- }
-
- stmt, err := tx.Prepare(
- "UPDATE newt_cfg SET value=? WHERE cfg_name=? AND key=?")
- if err != nil {
- return NewNewtError(err.Error())
+ return nil, NewNewtError(fmt.Sprintf("Target not found: %s", name))
}
- defer stmt.Close()
- res, err := stmt.Exec(val, sect, key)
- if err != nil {
- return NewNewtError(err.Error())
- }
-
- // Value already existed, and we updated it. Mission accomplished!
- // Exit
- if affected, err := res.RowsAffected(); affected > 0 && err == nil {
- tx.Commit()
- log.Printf("[DEBUG] Key %s, sect %s successfully updated to %s", key, sect, val)
- return nil
- }
-
- // Otherwise, insert a new row
- stmt1, err := tx.Prepare("INSERT INTO newt_cfg VALUES (?, ?, ?)")
- if err != nil {
- return NewNewtError(err.Error())
- }
- defer stmt1.Close()
-
- _, err = stmt1.Exec(sect, key, val)
- if err != nil {
- return NewNewtError(err.Error())
- }
-
- tx.Commit()
-
- log.Printf("[DEBUG] Key %s, sect %s successfully create, value set to %s",
- key, sect, val)
-
- return nil
+ return targetVars, nil
}
func (repo *Repo) PkgPaths() []string {
@@ -460,7 +333,7 @@ func (repo *Repo) Init() error {
return err
}
- log.Printf("[DEBUG] Configuration loaded! Initializing .app database")
+ log.Printf("[DEBUG] Configuration loaded")
// Create Repo store directory
repo.StorePath = repo.BasePath + "/.app/"
@@ -470,16 +343,12 @@ func (repo *Repo) Init() error {
}
}
- // Create Repo configuration database
- repo.Config = make(map[string]map[string]string)
-
- dbName := repo.StorePath + "/app.db"
- if err := repo.initDb(dbName); err != nil {
+ // Load target YAML files.
+ repo.Targets = make(map[string]map[string]string)
+ if err := repo.loadPath(repo.BasePath + "/targets/"); err != nil {
return err
}
- log.Printf("[DEBUG] Database initialized.")
-
// Load PkgLists for the current Repo
repo.PkgListPath = repo.StorePath + "/pkg-lists/"
if NodeNotExist(repo.PkgListPath) {
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/1d8f746f/newt/cli/target.go
----------------------------------------------------------------------
diff --git a/newt/cli/target.go b/newt/cli/target.go
index 8b026a3..5b4ee3c 100644
--- a/newt/cli/target.go
+++ b/newt/cli/target.go
@@ -22,6 +22,7 @@ package cli
import (
"bufio"
"fmt"
+ "io/ioutil"
"log"
"os"
"path/filepath"
@@ -30,8 +31,6 @@ import (
"strings"
)
-const TARGET_SECT_PREFIX = "_target_"
-
type Target struct {
Vars map[string]string
@@ -55,40 +54,44 @@ type Target struct {
Repo *Repo
}
+func NewTarget(repo *Repo, name string) *Target {
+ target := Target{
+ Repo: repo,
+ Name: name,
+ Vars: map[string]string{
+ "name": name,
+ "vers": "0.0.1",
+ "arch": "sim",
+ "compiler_def": "default",
+ },
+ }
+
+ return &target
+}
+
// Check if the target specified by name exists for the Repo specified by
// r
func TargetExists(repo *Repo, name string) bool {
- _, err := repo.GetConfig(TARGET_SECT_PREFIX+name, "name")
- if err == nil {
- return true
- } else {
- return false
- }
+ _, err := repo.GetTargetVars(name)
+ return err == nil
}
func parseTargetStringSlice(str string) ([]string, error) {
- slice := strings.Split(str, " ")
+ var slice []string
+ if str != "" {
+ slice = strings.Split(str, " ")
+ }
return slice, nil
}
-func (t *Target) SetDefaults() error {
+// Migrates some special key-value pairs from the target's Vars map to named
+// struct fields. This function should be called any time a target is
+// modified.
+func (t *Target) populateFields() error {
var err error
- t.Name = t.Vars["name"]
-
- // Must have an architecture set, default to sim.
- if t.Vars["arch"] == "" {
- t.Vars["arch"] = "sim"
- t.Arch = "sim"
- } else {
- t.Arch = t.Vars["arch"]
- }
-
+ t.Arch = t.Vars["arch"]
t.Cdef = t.Vars["compiler_def"]
- if t.Cdef == "" {
- t.Cdef = "default"
- }
-
t.Bsp = t.Vars["bsp"]
t.Cflags = t.Vars["cflags"]
t.Lflags = t.Vars["lflags"]
@@ -99,7 +102,8 @@ func (t *Target) SetDefaults() error {
}
t.Identities = map[string]string{}
for _, ident := range identities {
- StatusMessage(VERBOSITY_VERBOSE, " set default ident %s\n", ident)
+ StatusMessage(VERBOSITY_VERBOSE, "Setting identity; target=%s "+
+ "identity=%s\n", t.Name, ident)
t.Identities[ident] = t.Name
}
t.Capabilities, err = parseTargetStringSlice(t.Vars["capabilities"])
@@ -115,6 +119,11 @@ func (t *Target) SetDefaults() error {
return nil
}
+func (t *Target) SetVar(key string, value string) error {
+ t.Vars[key] = value
+ return t.populateFields()
+}
+
func (t *Target) HasIdentity(identity string) bool {
for cur, _ := range t.Identities {
if cur == identity {
@@ -127,19 +136,21 @@ func (t *Target) HasIdentity(identity string) bool {
// Load the target specified by name for the repository specified by r
func LoadTarget(repo *Repo, name string) (*Target, error) {
- t := &Target{
- Repo: repo,
- }
+ t := NewTarget(repo, name)
var err error
-
- t.Vars, err = repo.GetConfigSect(TARGET_SECT_PREFIX + name)
+ vars, err := repo.GetTargetVars(name)
if err != nil {
return nil, err
}
- // Cannot have both a project and package set
- err = t.SetDefaults()
+ for k, v := range vars {
+ log.Printf("[DEBUG] Setting target %s, key=%s val=%s", name, k, v)
+ t.Vars[strings.TrimPrefix(k, "pkg.")] = v
+ }
+
+ // Copy special key-value pairs into their corresponding target fields.
+ err = t.populateFields()
if err != nil {
return nil, err
}
@@ -147,8 +158,9 @@ func LoadTarget(repo *Repo, name string) (*Target, error) {
return t, nil
}
-// Export a target, or all targets. If exportAll is true, then all targets are exported, if false,
-// then only the target represented by targetName is exported
+// Export a target, or all targets. If exportAll is true, then all targets are
+// exported, if false, then only the target represented by targetName is
+// exported.
func ExportTargets(repo *Repo, name string, exportAll bool, fp *os.File) error {
targets, err := GetTargets(repo)
if err != nil {
@@ -200,7 +212,8 @@ func ImportTargets(repo *Repo, name string, importAll bool, fp *os.File) error {
currentTarget = nil
}
- // look either for an end of target definitions, or a new target definition
+ // look either for an end of target definitions, or a new target
+ // definition
if line == "@endtargets" {
break
} else {
@@ -209,17 +222,7 @@ func ImportTargets(repo *Repo, name string, importAll bool, fp *os.File) error {
if importAll || elements[1] == name {
// create a current target
- currentTarget = &Target{
- Repo: repo,
- }
-
- var err error
- currentTarget.Vars = map[string]string{}
- if err != nil {
- return err
- }
-
- currentTarget.Vars["name"] = elements[1]
+ currentTarget = NewTarget(repo, elements[1])
}
}
} else {
@@ -236,10 +239,6 @@ func ImportTargets(repo *Repo, name string, importAll bool, fp *os.File) error {
}
for _, target := range targets {
- if err := target.SetDefaults(); err != nil {
- return err
- }
-
if err := target.Save(); err != nil {
return err
}
@@ -251,15 +250,13 @@ func ImportTargets(repo *Repo, name string, importAll bool, fp *os.File) error {
// Get a list of targets for the repository specified by r
func GetTargets(repo *Repo) ([]*Target, error) {
targets := []*Target{}
- for sect, _ := range repo.Config {
- if strings.HasPrefix(sect, TARGET_SECT_PREFIX) {
- target, err := LoadTarget(repo, sect[len(TARGET_SECT_PREFIX):len(sect)])
- if err != nil {
- return nil, err
- }
-
- targets = append(targets, target)
+ for targetName, _ := range repo.Targets {
+ target, err := LoadTarget(repo, targetName)
+ if err != nil {
+ return nil, err
}
+
+ targets = append(targets, target)
}
return targets, nil
}
@@ -357,11 +354,14 @@ func (t *Target) Test(cmd string, flag bool) error {
return nil
}
-func (t *Target) DeleteVar(name string) error {
- targetCfgSect := TARGET_SECT_PREFIX + t.Vars["name"]
+func (t *Target) DeleteVar(varName string) error {
+ _, exists := t.Vars[varName]
- if err := t.Repo.DelConfig(targetCfgSect, name); err != nil {
- return err
+ if exists {
+ delete(t.Vars, varName)
+ if err := t.Save(); err != nil {
+ return err
+ }
}
return nil
@@ -369,36 +369,58 @@ func (t *Target) DeleteVar(name string) error {
// Save the target's configuration elements
func (t *Target) Save() error {
- repo := t.Repo
+ dirpath := t.Repo.TargetDir(t.Name)
+ if err := os.MkdirAll(dirpath, 0755); err != nil {
+ return NewNewtError(err.Error())
+ }
- if _, ok := t.Vars["name"]; !ok {
- return NewNewtError("Cannot save a target without a name")
+ filepath := dirpath + "/pkg.yml"
+ file, err := os.Create(filepath)
+ if err != nil {
+ return NewNewtError(err.Error())
}
+ defer file.Close()
- targetCfg := TARGET_SECT_PREFIX + t.Vars["name"]
+ file.WriteString("### Target: " + t.Name + "\n\n")
- for k, v := range t.Vars {
- if err := repo.SetConfig(targetCfg, k, v); err != nil {
- return err
- }
+ keys := []string{}
+ for k, _ := range t.Vars {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+
+ for _, k := range keys {
+ file.WriteString("pkg." + k + ": " + t.Vars[k] + "\n")
}
return nil
}
-func (t *Target) Remove() error {
- repo := t.Repo
+// Tells you if the target's directory contains extra user files (i.e., files
+// other than pkg.yml).
+func (t *Target) ContainsUserFiles() (bool, error) {
+ path := t.Repo.TargetDir(t.Name)
+ contents, err := ioutil.ReadDir(path)
+ if err != nil {
+ return false, err
+ }
- if _, ok := t.Vars["name"]; !ok {
- return NewNewtError("Cannot remove a target without a name")
+ userFiles := false
+ for _, node := range contents {
+ name := node.Name()
+ if name != "." && name != ".." && name != "yml" {
+ userFiles = true
+ break
+ }
}
- cfgSect := TARGET_SECT_PREFIX + t.Vars["name"]
+ return userFiles, nil
+}
- for k, _ := range t.Vars {
- if err := repo.DelConfig(cfgSect, k); err != nil {
- return err
- }
+func (t *Target) Remove() error {
+ path := t.Repo.TargetDir(t.Name)
+ if err := os.RemoveAll(path); err != nil {
+ return NewNewtError(err.Error())
}
return nil
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/1d8f746f/newt/newt.go
----------------------------------------------------------------------
diff --git a/newt/newt.go b/newt/newt.go
index ace82a4..d64b9ee 100644
--- a/newt/newt.go
+++ b/newt/newt.go
@@ -20,6 +20,7 @@
package main
import (
+ "bufio"
"fmt"
"log"
"os"
@@ -41,6 +42,7 @@ var NewtRepo *cli.Repo
var newtSilent bool
var newtQuiet bool
var newtVerbose bool
+var newtForce bool
var AutoTargets string = "autotargets"
var NewtBranchPkgList string
var NewtBranchPkg string
@@ -132,7 +134,7 @@ func targetSetCmd(cmd *cobra.Command, args []string) {
return
} else {
// Assign value to specified variable.
- t.Vars[ar[0]] = ar[1]
+ t.SetVar(ar[0], ar[1])
}
if err := t.Save(); err != nil {
@@ -167,12 +169,12 @@ type ByName []*cli.Target
func (a ByName) Len() int { return len(a) }
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a ByName) Less(i, j int) bool { return a[i].Vars["name"] < a[j].Vars["name"] }
+func (a ByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
func targetShowCmd(cmd *cobra.Command, args []string) {
- dispSect := ""
+ dispTarget := ""
if len(args) == 1 {
- dispSect = args[0]
+ dispTarget = args[0]
}
targets, err := cli.GetTargets(NewtRepo)
@@ -183,8 +185,8 @@ func targetShowCmd(cmd *cobra.Command, args []string) {
sort.Sort(ByName(targets))
for _, target := range targets {
- if dispSect == "" || dispSect == target.Vars["name"] {
- cli.StatusMessage(cli.VERBOSITY_QUIET, target.Vars["name"]+"\n")
+ if dispTarget == "" || dispTarget == target.Name {
+ cli.StatusMessage(cli.VERBOSITY_QUIET, target.Name+"\n")
vars := target.GetVars()
var keys []string
@@ -212,11 +214,7 @@ func targetCreateCmd(cmd *cobra.Command, args []string) {
"Target already exists, cannot create target with same name."))
}
- target := &cli.Target{
- Repo: NewtRepo,
- Vars: map[string]string{},
- }
- target.Vars["name"] = args[0]
+ target := cli.NewTarget(NewtRepo, args[0])
err := target.Save()
if err != nil {
@@ -272,6 +270,25 @@ func targetDelCmd(cmd *cobra.Command, args []string) {
NewtUsage(cmd, err)
}
+ if !newtForce {
+ // Determine if the target directory contains extra user files. If it
+ // does, a prompt (or force) is required to delete it.
+ userFiles, err := t.ContainsUserFiles()
+ if err != nil {
+ NewtUsage(cmd, err)
+ }
+
+ if userFiles {
+ scanner := bufio.NewScanner(os.Stdin)
+ fmt.Printf("Target directory %s contains some extra content; "+
+ "delete anyway? (y/N): ", t.Name)
+ rc := scanner.Scan()
+ if !rc || strings.ToLower(scanner.Text()) != "y" {
+ return
+ }
+ }
+ }
+
// Clean target prior to deletion; ignore errors during clean.
t.BuildClean(false)
@@ -460,19 +477,17 @@ func targetAddCmds(base *cobra.Command) {
NewtUsage(nil, err)
}
- file, err := os.Open(NewtRepo.BasePath + "/" + AutoTargets)
- if err == nil {
- err = cli.ImportTargets(NewtRepo, "", true, file)
+ // Try to migrate targets from legacy sqlite database. If any
+ // targets are migrated, recreate the repo from the updated targets
+ // directory.
+ if cli.LegacyMigrateTargets(NewtRepo) {
+ NewtRepo, err = cli.NewRepo()
if err != nil {
- log.Printf("[DEBUG] failed to import automatic "+
- "targets %s", err.Error())
+ NewtUsage(nil, err)
}
- file.Close()
- } else {
- log.Printf("[DEBUG] failed to import automatic "+
- "targets %s", err.Error())
}
},
+
Run: func(cmd *cobra.Command, args []string) {
cmd.Usage()
},
@@ -1455,6 +1470,8 @@ func parseCmds() *cobra.Command {
"Be silent; don't output anything.")
newtCmd.PersistentFlags().StringVarP(&NewtLogLevel, "loglevel", "l",
"WARN", "Log level, defaults to WARN.")
+ newtCmd.PersistentFlags().BoolVarP(&newtForce, "force", "f", false,
+ "Perform operations without prompting for confirmation.")
versHelpText := formatHelp(`Display the Newt version number.`)
versHelpEx := " newt version"