Commit 42c82d33 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent e2627fd4
...@@ -21,101 +21,9 @@ ...@@ -21,101 +21,9 @@
package main package main
import ( import (
"flag"
"fmt"
"os"
"lab.nexedi.com/kirr/neo/go/neo/neotools" "lab.nexedi.com/kirr/neo/go/neo/neotools"
) )
func usage() {
w := os.Stderr
fmt.Fprintf(w,
`Neo is a tool for running NEO services and commands.
Usage:
neo command [arguments]
The commands are:
`)
for _, cmd := range neotools.Commands {
fmt.Fprintf(w, "\t%-11s %s\n", cmd.Name, cmd.Summary)
}
fmt.Fprintf(w,
`
Use "neo help [command]" for more information about a command.
Additional help topics:
`)
for _, topic := range neotools.HelpTopics {
fmt.Fprintf(w, "\t%-11s %s\n", topic.Name, topic.Summary)
}
fmt.Fprintf(w,
`
Use "neo help [topic]" for more information about that topic.
`)
}
// help shows general help or help for a command/topic
func help(argv []string) {
if len(argv) < 2 { // help topic ...
usage()
os.Exit(2)
}
topic := argv[1]
// topic can either be a command name or a help topic
command := neotools.Commands.Lookup(topic)
if command != nil {
command.Usage(os.Stdout)
os.Exit(0)
}
helpTopic := neotools.HelpTopics.Lookup(topic)
if helpTopic != nil {
fmt.Println(helpTopic.Text)
os.Exit(0)
}
fmt.Fprintf(os.Stderr, "Unknown help topic `%s`. Run 'neo help'.\n", topic)
os.Exit(2)
}
func main() { func main() {
flag.Usage = usage neotools.Prog.Main()
flag.Parse()
argv := flag.Args()
if len(argv) == 0 {
usage()
os.Exit(2)
}
command := argv[0]
// help on a topic
if command == "help" {
help(argv)
return
}
// run subcommand
cmd := neotools.Commands.Lookup(command)
if cmd == nil {
fmt.Fprintf(os.Stderr, "neo: unknown subcommand \"%s\"\n", command)
fmt.Fprintf(os.Stderr, "Run 'neo help' for usage.\n")
os.Exit(2)
}
cmd.Main(argv)
} }
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
// Package neotools provides tools for running and managing NEO databases.
package neotools package neotools
// registry of all commands & help topics
import "lab.nexedi.com/kirr/neo/go/zodb/zodbtools" import "lab.nexedi.com/kirr/neo/go/zodb/zodbtools"
...@@ -30,3 +30,11 @@ var Commands = zodbtools.CommandRegistry{ ...@@ -30,3 +30,11 @@ var Commands = zodbtools.CommandRegistry{
var HelpTopics = zodbtools.HelpRegistry{ var HelpTopics = zodbtools.HelpRegistry{
// XXX for now empty // XXX for now empty
} }
// main neo driver
var Prog = zodbtools.MainProg{
Name: "neo",
Summary: "Neo is a tool for running NEO services and commands",
Commands: Commands,
HelpTopics: HelpTopics,
}
...@@ -17,107 +17,16 @@ ...@@ -17,107 +17,16 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
// Zodb is a driver program for invoking zodbtools subcommands // Zodb is a driver program for invoking zodbtools subcommands.
package main package main
import ( import (
"flag"
"fmt"
"os"
"lab.nexedi.com/kirr/neo/go/zodb/zodbtools" "lab.nexedi.com/kirr/neo/go/zodb/zodbtools"
// so that support for well-known ZODB storages is linked-in and available
_ "lab.nexedi.com/kirr/neo/go/zodb/wks" _ "lab.nexedi.com/kirr/neo/go/zodb/wks"
) )
func usage() {
w := os.Stderr
fmt.Fprintf(w,
`Zodb is a tool for managing ZODB databases.
Usage:
zodb command [arguments]
The commands are:
`)
for _, cmd := range zodbtools.Commands {
fmt.Fprintf(w, "\t%-11s %s\n", cmd.Name, cmd.Summary)
}
fmt.Fprintf(w,
`
Use "zodb help [command]" for more information about a command.
Additional help topics:
`)
for _, topic := range zodbtools.HelpTopics {
fmt.Fprintf(w, "\t%-11s %s\n", topic.Name, topic.Summary)
}
fmt.Fprintf(w,
`
Use "zodb help [topic]" for more information about that topic.
`)
}
// help shows general help or help for a command/topic
func help(argv []string) {
if len(argv) < 2 { // help topic ...
usage()
os.Exit(2)
}
topic := argv[1]
// topic can either be a command name or a help topic
command := zodbtools.Commands.Lookup(topic)
if command != nil {
command.Usage(os.Stdout)
os.Exit(0)
}
helpTopic := zodbtools.HelpTopics.Lookup(topic)
if helpTopic != nil {
fmt.Println(helpTopic.Text)
os.Exit(0)
}
fmt.Fprintf(os.Stderr, "Unknown help topic `%s`. Run 'zodb help'.\n", topic)
os.Exit(2)
}
func main() { func main() {
flag.Usage = usage zodbtools.Prog.Main()
flag.Parse()
argv := flag.Args()
if len(argv) == 0 {
usage()
os.Exit(2)
}
command := argv[0]
// help on a topic
if command == "help" {
help(argv)
return
}
// run subcommand
cmd := zodbtools.Commands.Lookup(command)
if cmd == nil {
fmt.Fprintf(os.Stderr, "zodb: unknown subcommand \"%s\"\n", command)
fmt.Fprintf(os.Stderr, "Run 'zodb help' for usage.\n")
os.Exit(2)
}
cmd.Main(argv)
} }
...@@ -17,5 +17,13 @@ ...@@ -17,5 +17,13 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
// Package neotools provides tools for running and managing NEO databases. // fs1 is a driver program for running & invoking fs1 subcommands.
package neotools package main
import (
"lab.nexedi.com/kirr/neo/go/zodb/storage/fs1/fs1tools"
)
func main() {
fs1tools.Prog.Main()
}
...@@ -17,5 +17,24 @@ ...@@ -17,5 +17,24 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
// Package zodbtools provides tools for managing ZODB databases // Package fs1tools provides tools for managing and maintaining ZODB FileStorage v1 databases.
package zodbtools package fs1tools
import "lab.nexedi.com/kirr/neo/go/zodb/zodbtools"
var Commands = zodbtools.CommandRegistry{
{"tail", tailSummary, tailUsage, tailMain},
// {"reindex", reindexSummary, reindexUsage, reindexMain},
}
var HelpTopics = zodbtools.HelpRegistry{
// XXX for now empty
}
// main fs1 driver
var Prog = zodbtools.MainProg{
Name: "fs1",
Summary: "Fs1 is a tool to manage and maintain ZODB FileStorage v1 databases",
Commands: Commands,
HelpTopics: HelpTopics,
}
...@@ -17,15 +17,7 @@ ...@@ -17,15 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
/* package fs1tools
fstail - Tool to dump the last few transactions from a FileStorage.
Format is the same as in fstail/py originally written by Jeremy Hylton:
https://github.com/zopefoundation/ZODB/blob/master/src/ZODB/scripts/fstail.py
https://github.com/zopefoundation/ZODB/commit/551122cc
*/
package main
import ( import (
"crypto/sha1" "crypto/sha1"
...@@ -43,8 +35,15 @@ import ( ...@@ -43,8 +35,15 @@ import (
"lab.nexedi.com/kirr/go123/xfmt" "lab.nexedi.com/kirr/go123/xfmt"
) )
/*
Tail dumps the last few transactions from a FileStorage.
Format is the same as in fstail/py originally written by Jeremy Hylton:
func fsTail(w io.Writer, path string, ntxn int) (err error) { https://github.com/zopefoundation/ZODB/blob/master/src/ZODB/scripts/fstail.py
https://github.com/zopefoundation/ZODB/commit/551122cc
*/
func Tail(w io.Writer, path string, ntxn int) (err error) {
// path & fstail on error context // path & fstail on error context
defer func() { defer func() {
if err != nil { if err != nil {
...@@ -144,13 +143,14 @@ func fsTail(w io.Writer, path string, ntxn int) (err error) { ...@@ -144,13 +143,14 @@ func fsTail(w io.Writer, path string, ntxn int) (err error) {
return err return err
} }
// ----------------------------------------
func main() { const tailSummary = "dump last few transactions of a database"
ntxn := 10 const ntxnDefault = 10
flag.Usage = func() { func tailUsage(w io.Writer) {
fmt.Fprintf(os.Stderr, fmt.Fprintf(w,
`fstail [options] <storage> `Usage: fs1 tail [options] <storage>
Dump transactions from a FileStorage in reverse order Dump transactions from a FileStorage in reverse order
<storage> is a path to FileStorage <storage> is a path to FileStorage
...@@ -159,20 +159,25 @@ Dump transactions from a FileStorage in reverse order ...@@ -159,20 +159,25 @@ Dump transactions from a FileStorage in reverse order
-h --help this help text. -h --help this help text.
-n <N> output the last <N> transactions (default %d). -n <N> output the last <N> transactions (default %d).
`, ntxn) `, ntxnDefault)
} }
func tailMain(argv []string) {
ntxn := ntxnDefault
flag.IntVar(&ntxn, "n", ntxn, "output the last <N> transactions") flags := flag.FlagSet{Usage: func() { tailUsage(os.Stderr) }}
flag.Parse() flags.Init("", flag.ExitOnError)
flags.IntVar(&ntxn, "n", ntxn, "output the last <N> transactions")
flags.Parse(argv[1:])
argv := flag.Args() argv = flags.Args()
if len(argv) < 1 { if len(argv) < 1 {
flag.Usage() flags.Usage()
os.Exit(2) os.Exit(2)
} }
storPath := argv[0] storPath := argv[0]
err := fsTail(os.Stdout, storPath, ntxn) err := Tail(os.Stdout, storPath, ntxn)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package main package fs1tools
//go:generate sh -c "python2 -m ZODB.scripts.fstail -n 1000000 ../../testdata/1.fs >testdata/1.fsdump.ok" //go:generate sh -c "python2 -m ZODB.scripts.fstail -n 1000000 ../../testdata/1.fs >testdata/1.fsdump.ok"
...@@ -46,10 +46,10 @@ func diff(a, b string) string { ...@@ -46,10 +46,10 @@ func diff(a, b string) string {
return dmp.DiffPrettyText(diffv) return dmp.DiffPrettyText(diffv)
} }
func TestFsTail(t *testing.T) { func TestTail(t *testing.T) {
buf := bytes.Buffer{} buf := bytes.Buffer{}
err := fsTail(&buf, "../../testdata/1.fs", 1000000) err := Tail(&buf, "../testdata/1.fs", 1000000)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -61,10 +61,10 @@ func TestFsTail(t *testing.T) { ...@@ -61,10 +61,10 @@ func TestFsTail(t *testing.T) {
} }
} }
func BenchmarkFsTail(b *testing.B) { func BenchmarkTail(b *testing.B) {
// FIXME small testdata/1.fs is not representative for benchmarking // FIXME small testdata/1.fs is not representative for benchmarking
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
err := fsTail(ioutil.Discard, "../../testdata/1.fs", 1000000) err := Tail(ioutil.Discard, "../testdata/1.fs", 1000000)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package fs1 package fs1
// open URL support // open by URL support
import ( import (
"context" "context"
......
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package zodbtools
// infrastructure to organize main tools driver
import (
"flag"
"fmt"
"io"
"os"
)
// Command describes one zodb subcommand
type Command struct {
Name string
Summary string
Usage func (w io.Writer)
Main func (argv []string)
}
// CommandRegistry is ordered collection of Commands
type CommandRegistry []Command
// Lookup returns Command with corresponding name or nil
func (cmdv CommandRegistry) Lookup(command string) *Command {
for i := range cmdv {
if cmdv[i].Name == command {
return &cmdv[i]
}
}
return nil
}
// HelpTopic describes one help topic
type HelpTopic struct {
Name string
Summary string
Text string
}
// HelpRegistry is ordered collection of HelpTopics
type HelpRegistry []HelpTopic
// Lookup returns HelpTopic with corresponding name or nil
func (helpv HelpRegistry) Lookup(topic string) *HelpTopic {
for i := range helpv {
if helpv[i].Name == topic {
return &helpv[i]
}
}
return nil
}
// ----------------------------------------
// MainProg defines a program to run with subcommands and help topics.
type MainProg struct {
Name string // name of the program, e.g. "zodb"
Summary string // 1-line summary of what program does
Commands CommandRegistry // provided subcommands
HelpTopics HelpRegistry // provided help topics
}
// Main is the main entry point for the program. Call it from main.
func (prog *MainProg) Main() {
flag.Usage = prog.usage
flag.Parse()
argv := flag.Args()
if len(argv) == 0 {
prog.usage()
os.Exit(2)
}
command := argv[0]
// help on a topic
if command == "help" {
prog.help(argv)
return
}
// run subcommand
cmd := prog.Commands.Lookup(command)
if cmd == nil {
fmt.Fprintf(os.Stderr, "%s: unknown subcommand \"%s\"\n", prog.Name, command)
fmt.Fprintf(os.Stderr, "Run '%s help' for usage.\n", prog.Name)
os.Exit(2)
}
cmd.Main(argv)
}
// usage shows usage text for whole program
func (prog *MainProg) usage() {
w := os.Stderr
fmt.Fprintf(w,
`%s.
Usage:
%s command [arguments]
The commands are:
`, prog.Summary, prog.Name)
for _, cmd := range prog.Commands {
fmt.Fprintf(w, "\t%-11s %s\n", cmd.Name, cmd.Summary)
}
fmt.Fprintf(w,
`
Use "%s help [command]" for more information about a command.
`, prog.Name)
if len(prog.HelpTopics) > 0 {
fmt.Fprintf(w,
`
Additional help topics:
`)
for _, topic := range prog.HelpTopics {
fmt.Fprintf(w, "\t%-11s %s\n", topic.Name, topic.Summary)
}
fmt.Fprintf(w,
`
Use "%s help [topic]" for more information about that topic.
`, prog.Name)
}
}
// help shows general help or help for a command/topic
func (prog *MainProg) help(argv []string) {
if len(argv) < 2 { // help topic ...
prog.usage()
os.Exit(2)
}
topic := argv[1]
// topic can either be a command name or a help topic
command := prog.Commands.Lookup(topic)
if command != nil {
command.Usage(os.Stdout)
os.Exit(0)
}
helpTopic := prog.HelpTopics.Lookup(topic)
if helpTopic != nil {
fmt.Println(helpTopic.Text)
os.Exit(0)
}
fmt.Fprintf(os.Stderr, "Unknown help topic `%s`. Run '%s help'.\n", topic, prog.Name)
os.Exit(2)
}
...@@ -20,26 +20,6 @@ ...@@ -20,26 +20,6 @@
package zodbtools package zodbtools
// registry for all help topics // registry for all help topics
// HelpTopic describes one help topic
type HelpTopic struct {
Name string
Summary string
Text string
}
// HelpRegistry is ordered collection of HelpTopics
type HelpRegistry []HelpTopic
// Lookup returns HelpTopic with corresponding name or nil
func (helpv HelpRegistry) Lookup(topic string) *HelpTopic {
for i := range helpv {
if helpv[i].Name == topic {
return &helpv[i]
}
}
return nil
}
const helpZURL = const helpZURL =
`Almost every zodb command works with a database. `Almost every zodb command works with a database.
A database can be specified by way of providing URL for its storage. A database can be specified by way of providing URL for its storage.
......
...@@ -17,38 +17,23 @@ ...@@ -17,38 +17,23 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
// Package zodbtools provides tools for managing ZODB databases
package zodbtools package zodbtools
// registry for all commands
import "io"
// Command describes one zodb subcommand
type Command struct {
Name string
Summary string
Usage func (w io.Writer)
Main func (argv []string)
}
// CommandRegistry is ordered collection of Commands
type CommandRegistry []Command
// Lookup returns Command with corresponding name or nil
func (cmdv CommandRegistry) Lookup(command string) *Command {
for i := range cmdv {
if cmdv[i].Name == command {
return &cmdv[i]
}
}
return nil
}
// registry of all zodbtools commands // registry of all zodbtools commands
var Commands = CommandRegistry{ var Commands = CommandRegistry{
// NOTE the order commands are listed here is the order how they will appear in help // NOTE the order commands are listed here is the order how they will appear in help
// TODO analyze ? // TODO analyze ?
// TODO cmp // TODO cmp
{"info", infoSummary, infoUsage, infoMain}, {"info", infoSummary, infoUsage, infoMain},
{"dump", dumpSummary, dumpUsage, dumpMain}, {"dump", dumpSummary, dumpUsage, dumpMain},
{"catobj", catobjSummary, catobjUsage, catobjMain}, {"catobj", catobjSummary, catobjUsage, catobjMain},
} }
// main zodbtools driver
var Prog = MainProg{
Name: "zodb",
Summary: "Zodb is a tool for managing ZODB databases",
Commands: Commands,
HelpTopics: HelpTopics,
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment