github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/cmd/noms/noms.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2016 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  package main
    23  
    24  import (
    25  	"context"
    26  	"fmt"
    27  	"log"
    28  	"math/rand"
    29  	"os"
    30  	"strings"
    31  	"time"
    32  
    33  	"github.com/attic-labs/kingpin"
    34  	flag "github.com/juju/gnuflag"
    35  
    36  	"github.com/dolthub/dolt/go/store/cmd/noms/util"
    37  	"github.com/dolthub/dolt/go/store/util/exit"
    38  	"github.com/dolthub/dolt/go/store/util/profile"
    39  	"github.com/dolthub/dolt/go/store/util/verbose"
    40  )
    41  
    42  var commands = []*util.Command{
    43  	nomsCommit,
    44  	nomsConfig,
    45  	nomsDiff,
    46  	nomsDs,
    47  	nomsLog,
    48  	nomsMerge,
    49  	nomsRoot,
    50  	nomsShow,
    51  	nomsSync,
    52  	nomsVersion,
    53  	nomsManifest,
    54  	nomsCat,
    55  }
    56  
    57  var kingpinCommands = []util.KingpinCommand{
    58  	nomsBlob,
    59  	nomsList,
    60  	nomsMap,
    61  	nomsSet,
    62  	nomsStats,
    63  	nomsStruct,
    64  }
    65  
    66  var actions = []string{
    67  	"interacting with",
    68  	"poking at",
    69  	"goofing with",
    70  	"dancing with",
    71  	"playing with",
    72  	"contemplation of",
    73  	"showing off",
    74  	"jiggerypokery of",
    75  	"singing to",
    76  	"nomming on",
    77  	"fighting with",
    78  }
    79  
    80  func usageString() string {
    81  	i := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(len(actions))
    82  	return fmt.Sprintf(`Noms is a tool for %s Noms data.`, actions[i])
    83  }
    84  
    85  func main() {
    86  	// allow short (-h) help
    87  	kingpin.EnableFileExpansion = false
    88  	kingpin.CommandLine.HelpFlag.Short('h')
    89  	noms := kingpin.New("noms", usageString())
    90  
    91  	// global flags
    92  	cpuProfileVal := noms.Flag("cpuprofile", "write cpu profile to file").String()
    93  	memProfileVal := noms.Flag("memprofile", "write memory profile to file").String()
    94  	blockProfileVal := noms.Flag("blockprofile", "write block profile to file").String()
    95  	verboseVal := noms.Flag("verbose", "show more").Short('v').Bool()
    96  
    97  	// set up docs for non-kingpin commands
    98  	addNomsDocs(noms)
    99  
   100  	handlers := map[string]util.KingpinHandler{}
   101  
   102  	// install kingpin handlers
   103  	for _, cmdFunction := range kingpinCommands {
   104  		command, handler := cmdFunction(context.Background(), noms)
   105  		handlers[command.FullCommand()] = handler
   106  	}
   107  
   108  	input := kingpin.MustParse(noms.Parse(os.Args[1:]))
   109  
   110  	// apply global flags
   111  	profile.ApplyProfileFlags(cpuProfileVal, memProfileVal, blockProfileVal)
   112  	verbose.SetVerbose(*verboseVal)
   113  
   114  	if handler := handlers[strings.Split(input, " ")[0]]; handler != nil {
   115  		handler(input)
   116  	}
   117  
   118  	// fall back to previous (non-kingpin) noms commands
   119  
   120  	flag.Parse(false)
   121  
   122  	args := flag.Args()
   123  
   124  	// Don't prefix log messages with timestamp when running interactively
   125  	log.SetFlags(0)
   126  
   127  	for _, cmd := range commands {
   128  		if cmd.Name() == args[0] {
   129  			flags := cmd.Flags()
   130  			flags.Usage = cmd.Usage
   131  
   132  			flags.Parse(true, args[1:])
   133  			args = flags.Args()
   134  			if cmd.Nargs != 0 && len(args) < cmd.Nargs {
   135  				cmd.Usage()
   136  			}
   137  			exitCode := cmd.Run(context.Background(), args)
   138  			if exitCode != 0 {
   139  				exit.Exit(exitCode)
   140  			}
   141  			return
   142  		}
   143  	}
   144  }
   145  
   146  // addDatabaseArg adds a "database" arg to the passed command
   147  func addDatabaseArg(cmd *kingpin.CmdClause) (arg *string) {
   148  	return cmd.Arg("database", "a noms database path").Required().String() // TODO: custom parser for noms db URL?
   149  }
   150  
   151  // addNomsDocs - adds documentation (docs only, not commands) for existing (pre-kingpin) commands.
   152  func addNomsDocs(noms *kingpin.Application) {
   153  	// commmit
   154  	commit := noms.Command("commit", `Commits a specified value as head of the dataset
   155  If absolute-path is not provided, then it is read from stdin. See Spelling Objects at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the dataset and absolute-path arguments.
   156  `)
   157  	commit.Flag("allow-dupe", "creates a new commit, even if it would be identical (modulo metadata and parents) to the existing HEAD.").Default("0").Int()
   158  	commit.Flag("date", "alias for -meta 'date=<date>'. '<date>' must be iso8601-formatted. If '<date>' is empty, it defaults to the current date.").String()
   159  	commit.Flag("message", "alias for -meta 'message=<message>'").String()
   160  	commit.Flag("meta", "'<key>=<value>' - creates a metadata field called 'key' set to 'value'. Value should be human-readable encoded.").String()
   161  	commit.Flag("meta-p", "'<key>=<path>' - creates a metadata field called 'key' set to the value at <path>").String()
   162  	commit.Arg("absolute-path", "the path to read data from").String()
   163  	// TODO: this should be required, but kingpin does not allow required args after non-required ones. Perhaps a custom type would fix that?
   164  	commit.Arg("database", "a noms database path").String()
   165  
   166  	// config
   167  	noms.Command("config", "Prints the active configuration if a .nomsconfig file is present")
   168  
   169  	// diff
   170  	diff := noms.Command("diff", `Shows the difference between two objects
   171  See Spelling Objects at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the object arguments.
   172  `)
   173  	diff.Flag("stat", "Writes a summary of the changes instead").Short('s').Bool()
   174  	diff.Arg("object1", "").Required().String()
   175  	diff.Arg("object2", "").Required().String()
   176  
   177  	// ds
   178  	ds := noms.Command("ds", `Noms dataset management
   179  See Spelling Objects at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the database argument.
   180  `)
   181  	ds.Flag("delete", "dataset to delete").Short('d').String()
   182  	ds.Arg("database", "a noms database path").String()
   183  
   184  	// log
   185  	log := noms.Command("log", `Displays the history of a path
   186  See Spelling Values at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the <path-spec> parameter.
   187  `)
   188  	log.Flag("color", "value of 1 forces color on, 0 forces color off").Default("-1").Int()
   189  	log.Flag("max-lines", "max number of lines to show per commit (-1 for all lines)").Default("9").Int()
   190  	log.Flag("max-commits", "max number of commits to display (0 for all commits)").Short('n').Default("0").Int()
   191  	log.Flag("oneline", "show a summary of each commit on a single line").Bool()
   192  	log.Flag("graph", "show ascii-based commit hierarchy on left side of output").Bool()
   193  	log.Flag("show-value", "show commit value rather than diff information").Bool()
   194  	log.Flag("tz", "display formatted date comments in specified timezone, must be: local or utc").Enum("local", "utc")
   195  	log.Arg("path-spec", "").Required().String()
   196  
   197  	// merge
   198  	merge := noms.Command("merge", `Merges and commits the head values of two named datasets
   199  See Spelling Objects at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the database argument.
   200  You must provide a working database and the names of two Datasets you want to merge. The values at the heads of these Datasets will be merged, put into a new Commit object, and set as the Head of the third provided Dataset name.
   201  `)
   202  	merge.Flag("policy", "conflict resolution policy for merging. Defaults to 'n', which means no resolution strategy will be applied. Supported values are 'l' (left), 'r' (right) and 'p' (prompt). 'prompt' will bring up a simple command-line prompt allowing you to resolve conflicts by choosing between 'l' or 'r' on a case-by-case basis.").Default("n").Enum("n", "r", "l", "p")
   203  	addDatabaseArg(merge)
   204  	merge.Arg("left-dataset-name", "a dataset").Required().String()
   205  	merge.Arg("right-dataset-name", "a dataset").Required().String()
   206  	merge.Arg("output-dataset-name", "a dataset").Required().String()
   207  
   208  	// root
   209  	root := noms.Command("root", `Get or set the current root hash of the entire database
   210  See Spelling Objects at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the database argument.
   211  `)
   212  	root.Flag("update", "Replaces the entire database with the one with the given hash").String()
   213  	addDatabaseArg(root)
   214  
   215  	// show
   216  	show := noms.Command("show", `Shows a serialization of a Noms object
   217  See Spelling Objects at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the object argument.
   218  `)
   219  	show.Flag("raw", "If true, dumps the raw binary version of the data").Bool()
   220  	show.Flag("stats", "If true, reports statistics related to the value").Bool()
   221  	show.Flag("tz", "display formatted date comments in specified timezone, must be: local or utc").Enum("local", "utc")
   222  	show.Arg("object", "a noms object").Required().String()
   223  
   224  	// sync
   225  	sync := noms.Command("sync", `Moves datasets between or within databases
   226  See Spelling Objects at https://github.com/attic-labs/noms/blob/master/doc/spelling.md for details on the object and dataset arguments.
   227  `)
   228  	sync.Flag("parallelism", "").Short('p').Default("512").Int()
   229  	sync.Arg("source-object", "a noms source object").Required().String()
   230  	sync.Arg("dest-dataset", "a noms dataset").Required().String()
   231  
   232  	// version
   233  	noms.Command("version", "Print the noms version")
   234  
   235  	//manifest
   236  	manifest := noms.Command("manifest", `Prints a database's manifest in a more readable format`)
   237  	addDatabaseArg(manifest)
   238  
   239  	//cat
   240  	cat := noms.Command("cat", `Prints the contents of an nbs file`)
   241  	cat.Arg("nbs-file", "nbs file").Required().String()
   242  	cat.Flag("raw", "If true, includes the raw binary version of each chunk in the nbs file").Bool()
   243  	cat.Flag("decompressed", "If true, includes the decompressed binary version of each chunk in the nbs file").Bool()
   244  	cat.Flag("no-show", "If true, skips printing of the value").Bool()
   245  	cat.Flag("hashes-only", "If true, only prints the b32 hashes").Bool()
   246  }