github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/cmd/noms/noms_root.go (about) 1 // Copyright 2016 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 "os" 10 11 "strings" 12 13 "github.com/attic-labs/kingpin" 14 "github.com/attic-labs/noms/cmd/util" 15 "github.com/attic-labs/noms/go/config" 16 "github.com/attic-labs/noms/go/d" 17 "github.com/attic-labs/noms/go/datas" 18 "github.com/attic-labs/noms/go/hash" 19 "github.com/attic-labs/noms/go/types" 20 ) 21 22 func nomsRoot(noms *kingpin.Application) (*kingpin.CmdClause, util.KingpinHandler) { 23 cmd := noms.Command("root", "Manage the root hash of the entire database.") 24 db := cmd.Arg("db", "database to work with - see Spelling Databases at https://github.com/attic-labs/noms/blob/master/doc/spelling.md").Required().String() 25 var updateRoot string 26 cmd.Flag("update", "replaces the database root hash").StringVar(&updateRoot) 27 28 return cmd, func(_ string) int { 29 cfg := config.NewResolver() 30 cs, err := cfg.GetChunkStore(*db) 31 d.CheckErrorNoUsage(err) 32 33 currRoot := cs.Root() 34 35 if updateRoot == "" { 36 fmt.Println(currRoot) 37 return 0 38 } 39 40 if updateRoot[0] == '#' { 41 updateRoot = updateRoot[1:] 42 } 43 h, ok := hash.MaybeParse(updateRoot) 44 if !ok { 45 fmt.Fprintf(os.Stderr, "Invalid hash: %s\n", h.String()) 46 return 1 47 } 48 49 // If BUG 3407 is correct, we might be able to just take cs and make a Database directly from that. 50 db, err := cfg.GetDatabase(*db) 51 d.CheckErrorNoUsage(err) 52 defer db.Close() 53 if !validate(db.ReadValue(h), db) { 54 return 1 55 } 56 57 fmt.Println(`💀⚠️😱 WARNING 😱⚠️💀 58 59 This operation replaces the entire database with the value of the given 60 hash. The old database becomes eligible for GC. 61 62 ANYTHING NOT SAVED WILL BE LOST 63 64 Continue?`) 65 var input string 66 n, err := fmt.Scanln(&input) 67 d.CheckErrorNoUsage(err) 68 if n != 1 || strings.ToLower(input) != "y" { 69 return 0 70 } 71 72 ok = cs.Commit(h, currRoot) 73 if !ok { 74 fmt.Fprintln(os.Stderr, "Optimistic concurrency failure") 75 return 1 76 } 77 78 fmt.Printf("Success. Previous root was: %s\n", currRoot) 79 return 0 80 } 81 } 82 83 func validate(r types.Value, vr types.ValueReader) bool { 84 rootType := types.MakeMapType(types.StringType, types.MakeRefType(types.ValueType)) 85 if !types.IsValueSubtypeOf(r, rootType) { 86 fmt.Fprintf(os.Stderr, "Root of database must be %s, but you specified: %s\n", rootType.Describe(), types.TypeOf(r).Describe()) 87 return false 88 } 89 90 return r.(types.Map).Any(func(k, v types.Value) bool { 91 if !datas.IsCommit(v.(types.Ref).TargetValue(vr)) { 92 fmt.Fprintf(os.Stderr, "Invalid root map. Value for key '%s' is not a ref of commit.\n", string(k.(types.String))) 93 return false 94 } 95 return true 96 }) 97 }