github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/cmd/noms/noms_set.go (about) 1 // Copyright 2018 Attic Labs, Inc. All rights reserved. 2 // Licensed under the Apache License, version 2.0: 3 // http://www.apache.org/licenses/LICENSE-2.0 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "strconv" 11 12 "github.com/attic-labs/kingpin" 13 14 "github.com/attic-labs/noms/cmd/util" 15 "github.com/attic-labs/noms/go/d" 16 "github.com/attic-labs/noms/go/datas" 17 "github.com/attic-labs/noms/go/diff" 18 "github.com/attic-labs/noms/go/spec" 19 "github.com/attic-labs/noms/go/types" 20 ) 21 22 func nomsSet(noms *kingpin.Application) (*kingpin.CmdClause, util.KingpinHandler) { 23 set := noms.Command("set", "Interact with sets.") 24 25 setNew := set.Command("new", "creates a new set") 26 newDb := setNew.Arg("database", "spec to db to create set within").Required().String() 27 newEntries := setNew.Arg("items", "items to insert").Strings() 28 29 setInsert := set.Command("insert", "inserts one or more items into a set") 30 insertSpec := setInsert.Arg("spec", "value spec for the set to edit").Required().String() 31 insertEntries := setInsert.Arg("items", "items to insert").Strings() 32 33 setDel := set.Command("del", "removes one or more items from a set") 34 delSpec := setDel.Arg("spec", "value spec for the set to edit").Required().String() 35 delEntries := setDel.Arg("items", "items to delete").Strings() 36 37 return set, func(input string) int { 38 switch input { 39 case setNew.FullCommand(): 40 return nomsSetNew(*newDb, *newEntries) 41 case setInsert.FullCommand(): 42 return nomsSetInsert(*insertSpec, *insertEntries) 43 case setDel.FullCommand(): 44 return nomsSetDel(*delSpec, *delEntries) 45 } 46 d.Panic("notreached") 47 return 1 48 } 49 } 50 51 func nomsSetNew(dbStr string, args []string) int { 52 sp, err := spec.ForDatabase(dbStr) 53 d.PanicIfError(err) 54 applySetEdits(sp, types.NewSet(sp.GetDatabase()), nil, types.DiffChangeAdded, args) 55 return 0 56 } 57 58 func nomsSetInsert(specStr string, args []string) int { 59 sp, err := spec.ForPath(specStr) 60 d.PanicIfError(err) 61 rootVal, basePath := splitPath(sp) 62 applySetEdits(sp, rootVal, basePath, types.DiffChangeAdded, args) 63 return 0 64 } 65 66 func nomsSetDel(specStr string, args []string) int { 67 sp, err := spec.ForPath(specStr) 68 d.PanicIfError(err) 69 rootVal, basePath := splitPath(sp) 70 applySetEdits(sp, rootVal, basePath, types.DiffChangeRemoved, args) 71 return 0 72 } 73 74 func applySetEdits(sp spec.Spec, rootVal types.Value, basePath types.Path, ct types.DiffChangeType, args []string) { 75 if rootVal == nil { 76 d.CheckErrorNoUsage(fmt.Errorf("No value at: %s", sp.String())) 77 return 78 } 79 db := sp.GetDatabase() 80 patch := diff.Patch{} 81 for i := 0; i < len(args); i++ { 82 vv, err := argumentToValue(args[i], db) 83 if err != nil { 84 d.CheckErrorNoUsage(err) 85 } 86 var pp types.PathPart 87 if types.ValueCanBePathIndex(vv) { 88 pp = types.NewIndexPath(vv) 89 } else { 90 pp = types.NewHashIndexPath(vv.Hash()) 91 } 92 d := diff.Difference{ 93 Path: append(basePath, pp), 94 } 95 if ct == types.DiffChangeAdded { 96 d.NewValue = vv 97 } else { 98 d.OldValue = vv 99 } 100 patch = append(patch, d) 101 } 102 appplyPatch(sp, rootVal, basePath, patch) 103 } 104 105 func argumentToValue(arg string, db datas.Database) (types.Value, error) { 106 if arg == "" { 107 return types.String(""), nil 108 } 109 if arg == "true" { 110 return types.Bool(true), nil 111 } 112 if arg == "false" { 113 return types.Bool(false), nil 114 } 115 if arg[0] == '"' { 116 buf := bytes.Buffer{} 117 for i := 1; i < len(arg); i++ { 118 c := arg[i] 119 if c == '"' { 120 if i != len(arg)-1 { 121 break 122 } 123 return types.String(buf.String()), nil 124 } 125 if c == '\\' { 126 i++ 127 c = arg[i] 128 if c != '\\' && c != '"' { 129 return nil, fmt.Errorf("Invalid string argument: %s: Only '\\' and '\"' can be escaped", arg) 130 } 131 } 132 buf.WriteByte(c) 133 } 134 return nil, fmt.Errorf("Invalid string argument: %s", arg) 135 } 136 if arg[0] == '@' { 137 p, err := spec.NewAbsolutePath(arg[1:]) 138 d.PanicIfError(err) 139 return p.Resolve(db), nil 140 } 141 if n, err := strconv.ParseFloat(arg, 64); err == nil { 142 return types.Number(n), nil 143 } 144 145 return types.String(arg), nil 146 }