github.com/cayleygraph/cayley@v0.7.7/cmd/cayley/cayley.go (about) 1 // Copyright 2016 The Cayley Authors. All rights reserved. 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 // +build !appengine 16 17 package main 18 19 import ( 20 "flag" 21 "fmt" 22 "net/http" 23 _ "net/http/pprof" 24 "os" 25 "path/filepath" 26 "strings" 27 28 "github.com/cayleygraph/cayley/cmd/cayley/command" 29 "github.com/prometheus/client_golang/prometheus/promhttp" 30 "github.com/spf13/cobra" 31 "github.com/spf13/viper" 32 33 "github.com/cayleygraph/cayley/clog" 34 _ "github.com/cayleygraph/cayley/clog/glog" 35 "github.com/cayleygraph/cayley/graph" 36 "github.com/cayleygraph/cayley/version" 37 "github.com/cayleygraph/quad" 38 39 // Load supported backends 40 _ "github.com/cayleygraph/cayley/graph/all" 41 42 // Load all supported quad formats. 43 _ "github.com/cayleygraph/quad/dot" 44 _ "github.com/cayleygraph/quad/gml" 45 _ "github.com/cayleygraph/quad/graphml" 46 _ "github.com/cayleygraph/quad/json" 47 _ "github.com/cayleygraph/quad/jsonld" 48 _ "github.com/cayleygraph/quad/nquads" 49 _ "github.com/cayleygraph/quad/pquads" 50 51 // Load writer registry 52 _ "github.com/cayleygraph/cayley/writer" 53 54 // Load supported query languages 55 _ "github.com/cayleygraph/cayley/query/gizmo" 56 _ "github.com/cayleygraph/cayley/query/graphql" 57 _ "github.com/cayleygraph/cayley/query/mql" 58 _ "github.com/cayleygraph/cayley/query/sexp" 59 ) 60 61 var ( 62 rootCmd = &cobra.Command{ 63 Use: "cayley", 64 Short: "Cayley is a graph store and graph query layer.", 65 PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 66 clog.Infof("Cayley version: %s (%s)", version.Version, version.GitHash) 67 if conf, _ := cmd.Flags().GetString("config"); conf != "" { 68 viper.SetConfigFile(conf) 69 } 70 err := viper.ReadInConfig() 71 if _, ok := err.(viper.ConfigFileNotFoundError); !ok && err != nil { 72 return err 73 } 74 if conf := viper.ConfigFileUsed(); conf != "" { 75 wd, _ := os.Getwd() 76 if rel, _ := filepath.Rel(wd, conf); rel != "" && strings.Count(rel, "..") < 3 { 77 conf = rel 78 } 79 clog.Infof("using config file: %s", conf) 80 } 81 // force viper to load flags to variables 82 graph.IgnoreDuplicates = viper.GetBool("load.ignore_duplicates") 83 graph.IgnoreMissing = viper.GetBool("load.ignore_missing") 84 quad.DefaultBatch = viper.GetInt("load.batch") 85 if host, _ := cmd.Flags().GetString("pprof"); host != "" { 86 go func() { 87 if err := http.ListenAndServe(host, nil); err != nil { 88 clog.Errorf("failed to run pprof handler: %v", err) 89 } 90 }() 91 } 92 if host, _ := cmd.Flags().GetString("metrics"); host != "" { 93 go func() { 94 if err := http.ListenAndServe(host, promhttp.Handler()); err != nil { 95 clog.Errorf("failed to run metrics handler: %v", err) 96 } 97 }() 98 } 99 return nil 100 }, 101 } 102 versionCmd = &cobra.Command{ 103 Use: "version", 104 Short: "Prints the version of Cayley.", 105 // do not execute any persistent actions 106 PersistentPreRun: func(cmd *cobra.Command, args []string) {}, 107 Run: func(cmd *cobra.Command, args []string) { 108 fmt.Println("Cayley version:", version.Version) 109 fmt.Println("Git commit hash:", version.GitHash) 110 if version.BuildDate != "" { 111 fmt.Println("Build date:", version.BuildDate) 112 } 113 }, 114 } 115 ) 116 117 type pFlag struct { 118 flag.Value 119 } 120 121 func (pFlag) Type() string { return "string" } 122 123 func init() { 124 // set config names and paths 125 viper.SetConfigName("cayley") 126 viper.SetEnvPrefix("cayley") 127 viper.AddConfigPath(".") 128 viper.AddConfigPath("$HOME/.cayley/") 129 viper.AddConfigPath("/etc/") 130 if conf := os.Getenv("CAYLEY_CFG"); conf != "" { 131 viper.SetConfigFile(conf) 132 } 133 134 rootCmd.AddCommand( 135 versionCmd, 136 command.NewInitDatabaseCmd(), 137 command.NewLoadDatabaseCmd(), 138 command.NewDumpDatabaseCmd(), 139 command.NewUpgradeCmd(), 140 command.NewReplCmd(), 141 command.NewQueryCmd(), 142 command.NewHttpCmd(), 143 command.NewConvertCmd(), 144 command.NewDedupCommand(), 145 ) 146 rootCmd.PersistentFlags().StringP("config", "c", "", "path to an explicit configuration file") 147 148 qnames := graph.QuadStores() 149 rootCmd.PersistentFlags().StringP("db", "d", "memstore", "database backend to use: "+strings.Join(qnames, ", ")) 150 rootCmd.PersistentFlags().StringP("dbpath", "a", "", "path or address string for database") 151 rootCmd.PersistentFlags().Bool("read_only", false, "open database in read-only mode") 152 153 rootCmd.PersistentFlags().Bool("dup", true, "don't stop loading on duplicated on add") 154 rootCmd.PersistentFlags().Bool("missing", false, "don't stop loading on missing key on delete") 155 rootCmd.PersistentFlags().Int("batch", quad.DefaultBatch, "size of quads batch to load at once") 156 157 rootCmd.PersistentFlags().String("memprofile", "", "path to output memory profile") 158 rootCmd.PersistentFlags().String("cpuprofile", "", "path to output cpu profile") 159 160 rootCmd.PersistentFlags().String("pprof", "", "host to serve pprof on (disabled by default)") 161 rootCmd.PersistentFlags().String("metrics", "", "host to serve metrics on (disabled by default)") 162 163 // bind flags to config variables 164 viper.BindPFlag(command.KeyBackend, rootCmd.PersistentFlags().Lookup("db")) 165 viper.BindPFlag(command.KeyAddress, rootCmd.PersistentFlags().Lookup("dbpath")) 166 viper.BindPFlag(command.KeyReadOnly, rootCmd.PersistentFlags().Lookup("read_only")) 167 viper.BindPFlag("load.ignore_duplicates", rootCmd.PersistentFlags().Lookup("dup")) 168 viper.BindPFlag("load.ignore_missing", rootCmd.PersistentFlags().Lookup("missing")) 169 viper.BindPFlag(command.KeyLoadBatch, rootCmd.PersistentFlags().Lookup("batch")) 170 171 // make both store.path and store.address work 172 viper.RegisterAlias(command.KeyPath, command.KeyAddress) 173 // aliases for legacy config files 174 viper.RegisterAlias("database", command.KeyBackend) 175 viper.RegisterAlias("db_path", command.KeyAddress) 176 viper.RegisterAlias("read_only", command.KeyReadOnly) 177 viper.RegisterAlias("db_options", command.KeyOptions) 178 179 { // re-register standard Go flags to cobra 180 rf := rootCmd.PersistentFlags() 181 flag.CommandLine.VisitAll(func(f *flag.Flag) { 182 switch f.Name { 183 case "v": // glog.v 184 rf.VarP(pFlag{f.Value}, "verbose", "v", f.Usage) 185 case "vmodule": // glog.vmodule 186 rf.Var(pFlag{f.Value}, "vmodule", f.Usage) 187 case "log_backtrace_at": // glog.log_backtrace_at 188 rf.Var(pFlag{f.Value}, "backtrace", f.Usage) 189 case "stderrthreshold": // glog.stderrthreshold 190 rf.VarP(pFlag{f.Value}, "log", "l", f.Usage) 191 case "alsologtostderr": // glog.alsologtostderr 192 rf.Var(pFlag{f.Value}, f.Name, f.Usage) 193 case "logtostderr": // glog.logtostderr 194 f.Value.Set("true") 195 rf.Var(pFlag{f.Value}, f.Name, f.Usage) 196 case "log_dir": // glog.log_dir 197 rf.Var(pFlag{f.Value}, "logs", f.Usage) 198 } 199 }) 200 // make sure flags parsed flag is set - parse empty args 201 flag.CommandLine = flag.NewFlagSet("", flag.ContinueOnError) 202 flag.CommandLine.Parse([]string{""}) 203 } 204 } 205 206 func main() { 207 if err := rootCmd.Execute(); err != nil { 208 clog.Errorf("%v", err) 209 os.Exit(1) 210 } 211 }