github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/cmd/noms/noms_struct.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 nomsStruct(noms *kingpin.Application) (*kingpin.CmdClause, util.KingpinHandler) { 20 strukt := noms.Command("struct", "Interact with structs.") 21 22 struktNew := strukt.Command("new", "creates a new struct") 23 newDb := struktNew.Arg("database", "spec to db to create struct within").Required().String() 24 newName := struktNew.Flag("name", "name for new struct").String() 25 newFields := struktNew.Arg("fields", "key/value pairs for field names and values").Strings() 26 27 struktSet := strukt.Command("set", "sets one or more fields of a struct") 28 setSpec := struktSet.Arg("spec", "value spec for the struct to edit").Required().String() 29 setFields := struktSet.Arg("fields", "key/value pairs for field names and values").Strings() 30 31 struktDel := strukt.Command("del", "removes one or more fields from a struct") 32 delSpec := struktDel.Arg("spec", "value spec for the struct to edit").Required().String() 33 delFields := struktDel.Arg("fields", "fields to be removed").Strings() 34 35 return strukt, func(input string) int { 36 switch input { 37 case struktNew.FullCommand(): 38 return nomsStructNew(*newDb, *newName, *newFields) 39 case struktSet.FullCommand(): 40 return nomsStructSet(*setSpec, *setFields) 41 case struktDel.FullCommand(): 42 return nomsStructDel(*delSpec, *delFields) 43 } 44 d.Panic("notreached") 45 return 1 46 } 47 } 48 49 func nomsStructNew(dbStr string, name string, args []string) int { 50 sp, err := spec.ForDatabase(dbStr) 51 d.PanicIfError(err) 52 applyStructEdits(sp, types.NewStruct(name, nil), nil, args) 53 return 0 54 } 55 56 func nomsStructSet(specStr string, args []string) int { 57 sp, err := spec.ForPath(specStr) 58 d.PanicIfError(err) 59 60 rootVal, basePath := splitPath(sp) 61 applyStructEdits(sp, rootVal, basePath, args) 62 return 0 63 } 64 65 func nomsStructDel(specStr string, args []string) int { 66 sp, err := spec.ForPath(specStr) 67 d.PanicIfError(err) 68 69 rootVal, basePath := splitPath(sp) 70 patch := diff.Patch{} 71 for i := 0; i < len(args); i++ { 72 if !types.IsValidStructFieldName(args[i]) { 73 d.CheckError(fmt.Errorf("Invalid field name: %s at position: %d", args[i], i)) 74 } 75 patch = append(patch, diff.Difference{ 76 Path: append(basePath, types.FieldPath{Name: args[i]}), 77 ChangeType: types.DiffChangeRemoved, 78 }) 79 } 80 81 appplyPatch(sp, rootVal, basePath, patch) 82 return 0 83 } 84 85 func splitPath(sp spec.Spec) (rootVal types.Value, basePath types.Path) { 86 db := sp.GetDatabase() 87 rootPath := sp.Path 88 rootPath.Path = types.Path{} 89 rootVal = rootPath.Resolve(db) 90 if rootVal == nil { 91 d.CheckError(fmt.Errorf("Invalid path: %s", sp.String())) 92 return 93 } 94 basePath = sp.Path.Path 95 return 96 } 97 98 func applyStructEdits(sp spec.Spec, rootVal types.Value, basePath types.Path, args []string) { 99 if len(args)%2 != 0 { 100 d.CheckError(fmt.Errorf("Must be an even number of key/value pairs")) 101 } 102 if rootVal == nil { 103 d.CheckErrorNoUsage(fmt.Errorf("No value at: %s", sp.String())) 104 return 105 } 106 db := sp.GetDatabase() 107 patch := diff.Patch{} 108 for i := 0; i < len(args); i += 2 { 109 if !types.IsValidStructFieldName(args[i]) { 110 d.CheckError(fmt.Errorf("Invalid field name: %s at position: %d", args[i], i)) 111 } 112 nv, err := argumentToValue(args[i+1], db) 113 if err != nil { 114 d.CheckError(fmt.Errorf("Invalid field value: %s at position %d: %s", args[i+1], i+1, err)) 115 } 116 patch = append(patch, diff.Difference{ 117 Path: append(basePath, types.FieldPath{Name: args[i]}), 118 ChangeType: types.DiffChangeModified, 119 NewValue: nv, 120 }) 121 } 122 appplyPatch(sp, rootVal, basePath, patch) 123 } 124 125 func appplyPatch(sp spec.Spec, rootVal types.Value, basePath types.Path, patch diff.Patch) { 126 db := sp.GetDatabase() 127 baseVal := basePath.Resolve(rootVal, db) 128 if baseVal == nil { 129 d.CheckErrorNoUsage(fmt.Errorf("No value at: %s", sp.String())) 130 } 131 132 newRootVal := diff.Apply(rootVal, patch) 133 d.Chk.NotNil(newRootVal) 134 r := db.WriteValue(newRootVal) 135 db.Flush() 136 newAbsPath := spec.AbsolutePath{ 137 Hash: r.TargetHash(), 138 Path: basePath, 139 } 140 fmt.Println(newAbsPath.String()) 141 }