golang 源碼分析:cayley-8-
接着我們分析下命令行工具,這裏除了導入導出工具還有 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.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)
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.ReadCloser
open func() (quad.ReadCloser, error)
}
func (r *lazyReader) ReadQuad() (quad.Quad, error) {
rc, err := r.open()
return r.rc.ReadQuad()
type multiReader struct {
rc []quad.ReadCloser
i 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 := path
multi.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
dedup.go
type sortVals []graph.Ref
type sortProp []property
func hashProperties(h hash.Hash, m map[interface{}]property) string {
type property struct {
Pred graph.Ref
Values []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,
})
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/yoFbZ-K7bI99MeCeJop6xQ