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  }