接着我们分析下命令行工具,这里除了导入导出工具还有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,
})