接着我们分析下命令行工具,这里除了导入导出工具还有gizmo语法支持、graphql支持等相关命令行工具。
gogen.go里定义了如何生成Gizmo的文档。
//go:generate go run ./cmd/docgen/docgen.go -i ./docs/GizmoAPI.md.in -o ./docs/GizmoAPI.md
imports.go前面我们已经介绍过了
tools.go定义了打包工具,主要用于静态资源的打包
import _ "github.com/gobuffalo/packr/v2/packr2"
cmd/docgen/docgen.go,根据命令行参数生成最终的文档:
packageName = flag.String("pck", "github.com/cayleygraph/cayley/query/gizmo", "")out = flag.String("o", "-", "output file")in = flag.String("i", "", "input file")func main() {path := filepath.Join(os.Getenv("GOPATH"), "src", *packageName)fset := token.NewFileSet()pkgs, err := parser.ParseDir(fset, path, nil, parser.ParseComments)p := pkgs[filepath.Base(*packageName)]dp := doc.New(p, *packageName, doc.AllDecls)var w io.Writer = os.Stdoutif fname := *out; fname != "" && fname != "-" {f, err := os.Create(fname)var r io.Reader = strings.NewReader(placeholder)if fname := *in; fname != "" {f, err := os.Open(fname)sc := bufio.NewScanner(r)for sc.Scan() {line := bytes.TrimSpace(sc.Bytes())if bytes.Equal(line, []byte(placeholder)) {writeDocs(w, dp)} else {w.Write(line)
func writeDocs(w io.Writer, dp *doc.Package) {
func Signature(m *doc.Func) string {
func isJsArgs(f *ast.FieldList) bool {
func funcDocs(s string) string {
cmd/cayley/cayley.go里面定义了一组命令,使用了cobra工具来生成命令:
var (rootCmd = &cobra.Command{Use: "cayley",func init() {rootCmd.AddCommand(versionCmd,command.NewInitDatabaseCmd(),command.NewLoadDatabaseCmd(),command.NewDumpDatabaseCmd(),command.NewUpgradeCmd(),command.NewReplCmd(),command.NewQueryCmd(),command.NewHttpCmd(),command.NewConvertCmd(),command.NewDedupCommand(),)
func main() {if err := rootCmd.Execute(); err != nil {
cmd/cayley/command里面是各个详细命令的定义,比如进行数据转换convert.go
func newLazyReader(open func() (quad.ReadCloser, error)) quad.ReadCloser {return &lazyReader{open: open}
type lazyReader struct {rc quad.ReadCloseropen func() (quad.ReadCloser, error)}
func (r *lazyReader) ReadQuad() (quad.Quad, error) {rc, err := r.open()return r.rc.ReadQuad()
type multiReader struct {rc []quad.ReadCloseri int}
func (r *multiReader) ReadQuad() (quad.Quad, error) {for {if r.i >= len(r.rc) {rc := r.rc[r.i]q, err := rc.ReadQuad()
func NewConvertCmd() *cobra.Command {cmd := &cobra.Command{Use: "convert",for _, path := range files {path := pathmulti.rc = append(multi.rc, newLazyReader(func() (quad.ReadCloser, error) {if dump == "-" {clog.Infof("reading %q", path)} else {fmt.Printf("reading %q\n", path)}return internal.QuadReaderFor(path, loadf)}))}
database.go定义了指定数据库需要的各种参数,命令行参数和yaml配置文件都可以用来启动服务,也定义了加载数据库和dump数据库相关的命令。
const (KeyBackend = "store.backend"KeyAddress = "store.address"KeyPath = "store.path"KeyReadOnly = "store.read_only"KeyOptions = "store.options"KeyLoadBatch = "load.batch"
func registerLoadFlags(cmd *cobra.Command) {
func registerDumpFlags(cmd *cobra.Command) {
func NewInitDatabaseCmd() *cobra.Command {cmd := &cobra.Command{Use: "init",if graph.IsRegistered(name) && !graph.IsPersistent(name) {return ErrNotPersistent}// TODO: maybe check read-only flag in config before that?if err := initDatabase(); err != nil {
func NewLoadDatabaseCmd() *cobra.Command {cmd := &cobra.Command{Use: "load",if err = initDatabase(); err != nil {return err}}h, err := openDatabase()
func NewDumpDatabaseCmd() *cobra.Command {cmd := &cobra.Command{Use: "dump",
func NewUpgradeCmd() *cobra.Command {cmd := &cobra.Command{Use: "upgrade",
func printBackendInfo() {
func initDatabase() error {return graph.InitQuadStore(name, path, graph.Options(opts))
func openDatabase() (*graph.Handle, error) {qw, err := graph.NewQuadWriter("single", qs, opts)
func openForQueries(cmd *cobra.Command) (*graph.Handle, error) {
同样支持profile
type profileData struct {cpuProfile *os.FilememPath string}
func mustSetupProfile(cmd *cobra.Command) profileData {func mustFinishProfile(p profileData) {
dedup.go
func iriFlag(s string, err error) (quad.IRI, error) {return quad.IRI(s), nil
func NewDedupCommand() *cobra.Command {cmd := &cobra.Command{Use: "dedup",
func valueLess(a, b graph.Ref) bool {
type sortVals []graph.Reftype sortProp []property
func hashProperties(h hash.Hash, m map[interface{}]property) string {
type property struct {Pred graph.RefValues []graph.Ref}
func dedupProperties(ctx context.Context, h *graph.Handle, pred, typ quad.IRI) error {
func dedupValueTx(ctx context.Context, h *graph.Handle, tx *graph.Transaction, a, b graph.Ref) error {
dump.go 数据的dump
func writerQuadsTo(path string, typ string, qr quad.Reader) error {f, err = os.Create(path)
func dumpDatabase(h *graph.Handle, path string, typ string) error {qr := graph.NewQuadStoreReader(h.QuadStore)defer qr.Close()return writerQuadsTo(path, typ, qr)
http.go启动http服务,我们就可以操作页面访问cayley
func NewHttpCmd() *cobra.Command {cmd := &cobra.Command{Use: "http",h, err := openForQueries(cmd)if err != nil {return err}defer h.Close()err = chttp.SetupRoutes(h, &chttp.Config{Timeout: viper.GetDuration(keyQueryTimeout),ReadOnly: viper.GetBool(KeyReadOnly),})return http.ListenAndServe(host, nil)
repl.go提供了命令解释器,可以交互式解析命令
func getContext() (context.Context, func()) {
func registerQueryFlags(cmd *cobra.Command) {langs := query.Languages()
func NewReplCmd() *cobra.Command {cmd := &cobra.Command{Use: "repl",
func NewQueryCmd() *cobra.Command {cmd := &cobra.Command{Use: "query",h, err := openForQueries(cmd)if err != nil {return err}defer h.Close()ctx, cancel := getContext()defer cancel()timeout := viper.GetDuration("timeout")if timeout > 0 {ctx, cancel = context.WithTimeout(ctx, timeout)defer cancel()}lang, _ := cmd.Flags().GetString("lang")limit, err := cmd.Flags().GetInt("limit")if err != nil {return err}enc := json.NewEncoder(os.Stdout)it, err := query.Execute(ctx, h, lang, querystr, query.Options{Collation: query.JSON,Limit: limit,})


文章转载自golang算法架构leetcode技术php,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




