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 }