golang源码分析:cayley(8)

2023-08-09 15:11:31 浏览数 (1)

接着我们分析下命令行工具,这里除了导入导出工具还有gizmo语法支持、graphql支持等相关命令行工具。

gogen.go里定义了如何生成Gizmo的文档。

代码语言:javascript复制
//go:generate go run ./cmd/docgen/docgen.go -i ./docs/GizmoAPI.md.in -o ./docs/GizmoAPI.md

imports.go前面我们已经介绍过了

tools.go定义了打包工具,主要用于静态资源的打包

代码语言:javascript复制
import _ "github.com/gobuffalo/packr/v2/packr2"

cmd/docgen/docgen.go,根据命令行参数生成最终的文档:

代码语言:javascript复制
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.Stdout
  if 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)
代码语言:javascript复制
func writeDocs(w io.Writer, dp *doc.Package) {
代码语言:javascript复制
func Signature(m *doc.Func) string {
代码语言:javascript复制
func isJsArgs(f *ast.FieldList) bool {
代码语言:javascript复制
func funcDocs(s string) string {

cmd/cayley/cayley.go里面定义了一组命令,使用了cobra工具来生成命令:

代码语言:javascript复制
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(),
  )
代码语言:javascript复制
func main() {
  if err := rootCmd.Execute(); err != nil {

cmd/cayley/command里面是各个详细命令的定义,比如进行数据转换convert.go

代码语言:javascript复制
  func newLazyReader(open func() (quad.ReadCloser, error)) quad.ReadCloser {
  return &lazyReader{open: open}
代码语言:javascript复制
type lazyReader struct {
  rc   quad.ReadCloser
  open func() (quad.ReadCloser, error)
}
代码语言:javascript复制
func (r *lazyReader) ReadQuad() (quad.Quad, error) {
        rc, err := r.open()
        return r.rc.ReadQuad()
代码语言:javascript复制
type multiReader struct {
  rc []quad.ReadCloser
  i  int
}
代码语言:javascript复制
func (r *multiReader) ReadQuad() (quad.Quad, error) {
  for {
    if r.i >= len(r.rc) {
            rc := r.rc[r.i]
    q, err := rc.ReadQuad()
代码语言:javascript复制
func NewConvertCmd() *cobra.Command {
  cmd := &cobra.Command{
    Use:     "convert",
        for _, path := range files {
        path := path
        multi.rc = append(multi.rc, newLazyReader(func() (quad.ReadCloser, error) {
          if dump == "-" {
            clog.Infof("reading %q", path)
          } else {
            fmt.Printf("reading %qn", path)
          }
          return internal.QuadReaderFor(path, loadf)
        }))
      }

database.go定义了指定数据库需要的各种参数,命令行参数和yaml配置文件都可以用来启动服务,也定义了加载数据库和dump数据库相关的命令。

代码语言:javascript复制
const (
  KeyBackend  = "store.backend"
  KeyAddress  = "store.address"
  KeyPath     = "store.path"
  KeyReadOnly = "store.read_only"
  KeyOptions  = "store.options"


  KeyLoadBatch = "load.batch"
代码语言:javascript复制
func registerLoadFlags(cmd *cobra.Command) {
代码语言:javascript复制
func registerDumpFlags(cmd *cobra.Command) {
代码语言:javascript复制
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 {
代码语言:javascript复制
func NewLoadDatabaseCmd() *cobra.Command {
  cmd := &cobra.Command{
    Use:   "load",
                if err = initDatabase(); err != nil {
          return err
        }
      }
      h, err := openDatabase()
代码语言:javascript复制
func NewDumpDatabaseCmd() *cobra.Command {
  cmd := &cobra.Command{
    Use:   "dump",
代码语言:javascript复制
func NewUpgradeCmd() *cobra.Command {
  cmd := &cobra.Command{
    Use:   "upgrade",
代码语言:javascript复制
func printBackendInfo() {
代码语言:javascript复制
func initDatabase() error {
        return graph.InitQuadStore(name, path, graph.Options(opts))
代码语言:javascript复制
func openDatabase() (*graph.Handle, error) {
        qw, err := graph.NewQuadWriter("single", qs, opts)
代码语言:javascript复制
func openForQueries(cmd *cobra.Command) (*graph.Handle, error) {

同样支持profile

代码语言:javascript复制
type profileData struct {
  cpuProfile *os.File
  memPath    string
}
代码语言:javascript复制
func mustSetupProfile(cmd *cobra.Command) profileData {
func mustFinishProfile(p profileData) {

dedup.go

代码语言:javascript复制
func iriFlag(s string, err error) (quad.IRI, error) {
        return quad.IRI(s), nil
代码语言:javascript复制
func NewDedupCommand() *cobra.Command {
  cmd := &cobra.Command{
    Use:   "dedup",
代码语言:javascript复制
func valueLess(a, b graph.Ref) bool {
代码语言:javascript复制
type sortVals []graph.Ref
type sortProp []property
代码语言:javascript复制
func hashProperties(h hash.Hash, m map[interface{}]property) string {
代码语言:javascript复制
type property struct {
  Pred   graph.Ref
  Values []graph.Ref
}
代码语言:javascript复制
func dedupProperties(ctx context.Context, h *graph.Handle, pred, typ quad.IRI) error {
代码语言:javascript复制
func dedupValueTx(ctx context.Context, h *graph.Handle, tx *graph.Transaction, a, b graph.Ref) error {

dump.go 数据的dump

代码语言:javascript复制
func writerQuadsTo(path string, typ string, qr quad.Reader) error {
        f, err = os.Create(path)
代码语言:javascript复制
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

代码语言:javascript复制
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提供了命令解释器,可以交互式解析命令

代码语言:javascript复制
func getContext() (context.Context, func()) {
代码语言:javascript复制
func registerQueryFlags(cmd *cobra.Command) {
  langs := query.Languages()
代码语言:javascript复制
func NewReplCmd() *cobra.Command {
  cmd := &cobra.Command{
    Use:   "repl",
代码语言:javascript复制
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,
      })

0 人点赞