github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/cmd/noms/noms_list.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 "fmt" 9 10 "github.com/attic-labs/kingpin" 11 12 "github.com/attic-labs/noms/cmd/util" 13 "github.com/attic-labs/noms/go/d" 14 "github.com/attic-labs/noms/go/diff" 15 "github.com/attic-labs/noms/go/spec" 16 "github.com/attic-labs/noms/go/types" 17 ) 18 19 func nomsList(noms *kingpin.Application) (*kingpin.CmdClause, util.KingpinHandler) { 20 list := noms.Command("list", "Interact with lists.") 21 22 listNew := list.Command("new", "creates a new list") 23 newDb := listNew.Arg("database", "spec to db to create list within").Required().String() 24 newEntries := listNew.Arg("items", "items to insert").Strings() 25 26 listAppend := list.Command("append", "appends one or more items to a list") 27 appendSpec := listAppend.Arg("spec", "value spec for the list to edit").Required().String() 28 appendEntries := listAppend.Arg("items", "items to insert").Strings() 29 30 listInsert := list.Command("insert", "inserts one or more items into a list") 31 insertAt := listInsert.Arg("pos", "position to insert new items at").Required().Uint64() 32 insertSpec := listInsert.Arg("spec", "value spec for the list to edit").Required().String() 33 insertEntries := listInsert.Arg("items", "items to insert").Strings() 34 35 listDel := list.Command("del", "removes one or more items from the list") 36 delSpec := listDel.Arg("spec", "value spec for the list to edit").Required().String() 37 delPos := listDel.Arg("pos", "index to remove items at").Required().Uint64() 38 delLen := listDel.Arg("len", "number of items to remove").Required().Uint64() 39 40 return list, func(input string) int { 41 switch input { 42 case listNew.FullCommand(): 43 return nomsListNew(*newDb, *newEntries) 44 case listAppend.FullCommand(): 45 return nomsListAppend(*appendSpec, *appendEntries) 46 case listInsert.FullCommand(): 47 return nomsListInsert(*insertSpec, *insertAt, *insertEntries) 48 case listDel.FullCommand(): 49 return nomsListDel(*delSpec, *delPos, *delLen) 50 } 51 d.Panic("notreached") 52 return 1 53 } 54 } 55 56 func nomsListNew(dbStr string, args []string) int { 57 sp, err := spec.ForDatabase(dbStr) 58 d.PanicIfError(err) 59 applyListInserts(sp, types.NewList(sp.GetDatabase()), nil, 0, args) 60 return 0 61 } 62 63 func nomsListAppend(specStr string, args []string) int { 64 sp, err := spec.ForPath(specStr) 65 d.PanicIfError(err) 66 rootVal, basePath := splitPath(sp) 67 listVal := basePath.Resolve(rootVal, sp.GetDatabase()) 68 if listVal == nil { 69 d.CheckErrorNoUsage(fmt.Errorf("no value at path: %s", specStr)) 70 } 71 if list, ok := listVal.(types.List); ok { 72 applyListInserts(sp, rootVal, basePath, list.Len(), args) 73 } else { 74 d.CheckErrorNoUsage(fmt.Errorf("value at %s is not list", specStr)) 75 } 76 return 0 77 } 78 79 func nomsListInsert(specStr string, pos uint64, args []string) int { 80 sp, err := spec.ForPath(specStr) 81 d.PanicIfError(err) 82 rootVal, basePath := splitPath(sp) 83 applyListInserts(sp, rootVal, basePath, pos, args) 84 return 0 85 } 86 87 func nomsListDel(specStr string, pos uint64, len uint64) int { 88 sp, err := spec.ForPath(specStr) 89 d.PanicIfError(err) 90 91 rootVal, basePath := splitPath(sp) 92 patch := diff.Patch{} 93 // TODO: if len-pos is large this will start to become problematic 94 for i := pos; i < pos+len; i++ { 95 patch = append(patch, diff.Difference{ 96 Path: append(basePath, types.NewIndexPath(types.Number(i))), 97 ChangeType: types.DiffChangeRemoved, 98 }) 99 } 100 101 appplyPatch(sp, rootVal, basePath, patch) 102 return 0 103 } 104 105 func applyListInserts(sp spec.Spec, rootVal types.Value, basePath types.Path, pos uint64, args []string) { 106 if rootVal == nil { 107 d.CheckErrorNoUsage(fmt.Errorf("No value at: %s", sp.String())) 108 return 109 } 110 db := sp.GetDatabase() 111 patch := diff.Patch{} 112 for i := 0; i < len(args); i++ { 113 vv, err := argumentToValue(args[i], db) 114 if err != nil { 115 d.CheckError(fmt.Errorf("Invalid value: %s at position %d: %s", args[i], i, err)) 116 } 117 patch = append(patch, diff.Difference{ 118 Path: append(basePath, types.NewIndexPath(types.Number(pos+uint64(i)))), 119 ChangeType: types.DiffChangeAdded, 120 NewValue: vv, 121 }) 122 } 123 appplyPatch(sp, rootVal, basePath, patch) 124 }