update-userdata-devtool #58
| @ -77,10 +77,10 @@ func main() { | |||||||
| 	pfp := path.Join(scriptDir, "pp.csv") | 	pfp := path.Join(scriptDir, "pp.csv") | ||||||
| 
 | 
 | ||||||
| 	cfg := engine.Config{ | 	cfg := engine.Config{ | ||||||
| 		Root:          "root", | 		Root:              "root", | ||||||
| 		OutputSize:    uint32(size), | 		OutputSize:        uint32(size), | ||||||
| 		FlagCount:     uint32(128), | 		FlagCount:         uint32(128), | ||||||
| 		MenuSeparator: menuSeparator, | 		MenuSeparator:     menuSeparator, | ||||||
| 		ResetOnEmptyInput: true, | 		ResetOnEmptyInput: true, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -92,10 +92,10 @@ func main() { | |||||||
| 	pfp := path.Join(scriptDir, "pp.csv") | 	pfp := path.Join(scriptDir, "pp.csv") | ||||||
| 
 | 
 | ||||||
| 	cfg := engine.Config{ | 	cfg := engine.Config{ | ||||||
| 		Root:          "root", | 		Root:              "root", | ||||||
| 		OutputSize:    uint32(size), | 		OutputSize:        uint32(size), | ||||||
| 		FlagCount:     uint32(128), | 		FlagCount:         uint32(128), | ||||||
| 		MenuSeparator: menuSeparator, | 		MenuSeparator:     menuSeparator, | ||||||
| 		ResetOnEmptyInput: true, | 		ResetOnEmptyInput: true, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -78,10 +78,10 @@ func main() { | |||||||
| 	pfp := path.Join(scriptDir, "pp.csv") | 	pfp := path.Join(scriptDir, "pp.csv") | ||||||
| 
 | 
 | ||||||
| 	cfg := engine.Config{ | 	cfg := engine.Config{ | ||||||
| 		Root:          "root", | 		Root:              "root", | ||||||
| 		OutputSize:    uint32(size), | 		OutputSize:        uint32(size), | ||||||
| 		FlagCount:     uint32(128), | 		FlagCount:         uint32(128), | ||||||
| 		MenuSeparator: menuSeparator, | 		MenuSeparator:     menuSeparator, | ||||||
| 		ResetOnEmptyInput: true, | 		ResetOnEmptyInput: true, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ func main() { | |||||||
| 	var stateDebug bool | 	var stateDebug bool | ||||||
| 	var host string | 	var host string | ||||||
| 	var port uint | 	var port uint | ||||||
| 	 | 
 | ||||||
| 	flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") | 	flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") | ||||||
| 	flag.StringVar(&override.ResourceConn, "resource", "?", "resource connection string") | 	flag.StringVar(&override.ResourceConn, "resource", "?", "resource connection string") | ||||||
| 	flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string") | 	flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string") | ||||||
| @ -81,9 +81,9 @@ func main() { | |||||||
| 	pfp := path.Join(scriptDir, "pp.csv") | 	pfp := path.Join(scriptDir, "pp.csv") | ||||||
| 
 | 
 | ||||||
| 	cfg := engine.Config{ | 	cfg := engine.Config{ | ||||||
| 		Root:       "root", | 		Root:              "root", | ||||||
| 		OutputSize: uint32(size), | 		OutputSize:        uint32(size), | ||||||
| 		FlagCount:  uint32(128), | 		FlagCount:         uint32(128), | ||||||
| 		ResetOnEmptyInput: true, | 		ResetOnEmptyInput: true, | ||||||
| 	} | 	} | ||||||
| 	if stateDebug { | 	if stateDebug { | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ const ( | |||||||
| 	defaultSSHHost  string = "127.0.0.1" | 	defaultSSHHost  string = "127.0.0.1" | ||||||
| 	defaultSSHPort  uint   = 7122 | 	defaultSSHPort  uint   = 7122 | ||||||
| 	defaultHTTPHost string = "127.0.0.1" | 	defaultHTTPHost string = "127.0.0.1" | ||||||
| 	defaultHTTPPort uint     = 7123 | 	defaultHTTPPort uint   = 7123 | ||||||
| 	defaultDomain          = "sarafu.local" | 	defaultDomain          = "sarafu.local" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -52,7 +52,6 @@ func SearchDomains() []string { | |||||||
| 	return ParsedDomains | 	return ParsedDomains | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| func Language() string { | func Language() string { | ||||||
| 	return viseconfig.DefaultLanguage | 	return viseconfig.DefaultLanguage | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"path" | 	"path" | ||||||
| 
 | 
 | ||||||
|  | 	"git.defalsify.org/vise.git/engine" | ||||||
| 	"git.defalsify.org/vise.git/logging" | 	"git.defalsify.org/vise.git/logging" | ||||||
| 
 | 
 | ||||||
| 	"git.grassecon.net/grassrootseconomics/sarafu-vise/config" | 	"git.grassecon.net/grassrootseconomics/sarafu-vise/config" | ||||||
| @ -16,8 +17,9 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
| 	logg      = logging.NewVanilla().WithContextKey("SessionId") | 	logg          = logging.NewVanilla().WithContextKey("SessionId") | ||||||
| 	scriptDir = path.Join("services", "registration") | 	scriptDir     = path.Join("services", "registration") | ||||||
|  | 	menuSeparator = ": " | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| @ -25,6 +27,8 @@ func main() { | |||||||
| 
 | 
 | ||||||
| 	override := config.NewOverride() | 	override := config.NewOverride() | ||||||
| 	var sessionId string | 	var sessionId string | ||||||
|  | 	var size uint | ||||||
|  | 	var engineDebug bool | ||||||
| 
 | 
 | ||||||
| 	flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") | 	flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") | ||||||
| 	flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") | 	flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") | ||||||
| @ -32,6 +36,8 @@ func main() { | |||||||
| 
 | 
 | ||||||
| 	flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string") | 	flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string") | ||||||
| 	flag.StringVar(&override.StateConn, "state", "?", "state store connection string") | 	flag.StringVar(&override.StateConn, "state", "?", "state store connection string") | ||||||
|  | 	flag.BoolVar(&engineDebug, "d", false, "use engine debug output") | ||||||
|  | 	flag.UintVar(&size, "s", 160, "max size of output") | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
| 
 | 
 | ||||||
| 	config.Apply(override) | 	config.Apply(override) | ||||||
| @ -50,13 +56,23 @@ func main() { | |||||||
| 		os.Exit(1) | 		os.Exit(1) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	cfg := engine.Config{ | ||||||
|  | 		Root:              "root", | ||||||
|  | 		SessionId:         sessionId, | ||||||
|  | 		OutputSize:        uint32(size), | ||||||
|  | 		FlagCount:         uint32(128), | ||||||
|  | 		MenuSeparator:     menuSeparator, | ||||||
|  | 		EngineDebug:       engineDebug, | ||||||
|  | 		ResetOnEmptyInput: true, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	x := cmd.NewCmd(sessionId, flagParser) | 	x := cmd.NewCmd(sessionId, flagParser) | ||||||
|  | 	x = x.WithEngine(cfg) | ||||||
| 	err = x.Parse(flag.Args()) | 	err = x.Parse(flag.Args()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		fmt.Fprintf(os.Stderr, "cmd parse fail: %v\n", err) | 		fmt.Fprintf(os.Stderr, "cmd parse fail: %v\n", err) | ||||||
| 		os.Exit(1) | 		os.Exit(1) | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	logg.Infof("start command", "conn", conns, "subcmd", x) | 	logg.Infof("start command", "conn", conns, "subcmd", x) | ||||||
| 
 | 
 | ||||||
| 	menuStorageService := storage.NewMenuStorageService(conns) | 	menuStorageService := storage.NewMenuStorageService(conns) | ||||||
| @ -70,5 +86,4 @@ func main() { | |||||||
| 		fmt.Fprintf(os.Stderr, "cmd exec error: %v\n", err) | 		fmt.Fprintf(os.Stderr, "cmd exec error: %v\n", err) | ||||||
| 		os.Exit(1) | 		os.Exit(1) | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ func formatItem(k []byte, v []byte, sessionId string) (string, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
| 	s := fmt.Sprintf("%v\t%v\n", o.Label, string(v)) | 	s := fmt.Sprintf("%v\n\t%v\n", o.Label, string(v)) | ||||||
| 
 | 
 | ||||||
| 	return s, nil | 	return s, nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,23 +3,45 @@ package cmd | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"regexp" | ||||||
|  | 	"strings" | ||||||
| 
 | 
 | ||||||
|  | 	"git.defalsify.org/vise.git/db" | ||||||
|  | 	"git.defalsify.org/vise.git/engine" | ||||||
| 	"git.defalsify.org/vise.git/logging" | 	"git.defalsify.org/vise.git/logging" | ||||||
|  | 	"git.defalsify.org/vise.git/persist" | ||||||
|  | 	"git.defalsify.org/vise.git/resource" | ||||||
|  | 	"git.defalsify.org/vise.git/state" | ||||||
| 	"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application" | 	"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application" | ||||||
| 	"git.grassecon.net/grassrootseconomics/visedriver/storage" | 	"git.grassecon.net/grassrootseconomics/visedriver/storage" | ||||||
|  | 
 | ||||||
|  | 	storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | var argc map[string]int = map[string]int{ | ||||||
|  | 	"reset":     0, | ||||||
|  | 	"admin":     1, | ||||||
|  | 	"clone":     1, | ||||||
|  | 	"overwrite": 2, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| var ( | var ( | ||||||
| 	logg = logging.NewVanilla().WithDomain("cmd").WithContextKey("SessionId") | 	logg             = logging.NewVanilla().WithDomain("cmd").WithContextKey("SessionId") | ||||||
|  | 	cloneTargetRegex = `^\+000` | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Cmd struct { | type Cmd struct { | ||||||
| 	sessionId  string | 	sessionId    string | ||||||
| 	conn       storage.ConnData | 	conn         storage.ConnData | ||||||
| 	flagParser *application.FlagManager | 	flagParser   *application.FlagManager | ||||||
| 	cmd        int | 	cmd          int | ||||||
| 	enable     bool | 	enable       bool | ||||||
| 	exec       func(ctx context.Context, ss storage.StorageService) error | 	param        string | ||||||
|  | 	exec         func(ctx context.Context, ss storage.StorageService) error | ||||||
|  | 	engineConfig *engine.Config | ||||||
|  | 	st           *state.State | ||||||
|  | 	key          string | ||||||
|  | 	value        string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewCmd(sessionId string, flagParser *application.FlagManager) *Cmd { | func NewCmd(sessionId string, flagParser *application.FlagManager) *Cmd { | ||||||
| @ -29,10 +51,115 @@ func NewCmd(sessionId string, flagParser *application.FlagManager) *Cmd { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (c *Cmd) WithEngine(engineConfig engine.Config) *Cmd { | ||||||
|  | 	c.engineConfig = &engineConfig | ||||||
|  | 	return c | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (c *Cmd) Exec(ctx context.Context, ss storage.StorageService) error { | func (c *Cmd) Exec(ctx context.Context, ss storage.StorageService) error { | ||||||
| 	return c.exec(ctx, ss) | 	return c.exec(ctx, ss) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (c *Cmd) engine(ctx context.Context, rs resource.Resource, pe *persist.Persister) (engine.Engine, error) { | ||||||
|  | 	if c.engineConfig == nil { | ||||||
|  | 		return nil, fmt.Errorf("engine config missing") | ||||||
|  | 	} | ||||||
|  | 	en := engine.NewEngine(*c.engineConfig, rs) | ||||||
|  | 
 | ||||||
|  | 	st := pe.GetState() | ||||||
|  | 	if st == nil { | ||||||
|  | 		return nil, fmt.Errorf("persister state fail") | ||||||
|  | 	} | ||||||
|  | 	en = en.WithState(st) | ||||||
|  | 	st.UseDebug() | ||||||
|  | 	ca := pe.GetMemory() | ||||||
|  | 	if ca == nil { | ||||||
|  | 		return nil, fmt.Errorf("persister cache fail") | ||||||
|  | 	} | ||||||
|  | 	en = en.WithMemory(ca) | ||||||
|  | 	logg.DebugCtxf(ctx, "state loaded", "state", st) | ||||||
|  | 	return en, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *Cmd) execClone(ctx context.Context, ss storage.StorageService) error { | ||||||
|  | 	re := regexp.MustCompile(cloneTargetRegex) | ||||||
|  | 	if !re.MatchString(c.param) { | ||||||
|  | 		return fmt.Errorf("Clone sessionId must match target: %s", c.param) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pe, err := ss.GetPersister(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("get persister error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	err = pe.Load(c.engineConfig.SessionId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("persister load error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/// TODO consider DRY with devtools/store/dump
 | ||||||
|  | 	store, err := ss.GetUserdataDb(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("store retrieve error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	store.SetSession(c.engineConfig.SessionId) | ||||||
|  | 	store.SetPrefix(db.DATATYPE_USERDATA) | ||||||
|  | 	dmp, err := store.Dump(ctx, []byte("")) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("store dump fail: %v\n", err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for true { | ||||||
|  | 		store.SetSession(c.engineConfig.SessionId) | ||||||
|  | 		k, v := dmp.Next(ctx) | ||||||
|  | 		if k == nil { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		store.SetSession(c.param) | ||||||
|  | 		err = store.Put(ctx, k, v) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("user data store clone failed on key: %x", k) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return pe.Save(c.param) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *Cmd) execReset(ctx context.Context, ss storage.StorageService) error { | ||||||
|  | 	pe, err := ss.GetPersister(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("get persister error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	rs, err := ss.GetResource(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("get resource error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	dbResource, ok := rs.(*resource.DbResource) | ||||||
|  | 	if !ok { | ||||||
|  | 		return fmt.Errorf("get dbresource error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	err = pe.Load(c.engineConfig.SessionId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("persister load error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	en, err := c.engine(ctx, dbResource, pe) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	_, err = en.(*engine.DefaultEngine).Reset(ctx, false) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	st := pe.GetState() | ||||||
|  | 	logg.DebugCtxf(ctx, "state after reset", "state", st) | ||||||
|  | 
 | ||||||
|  | 	err = pe.Save(c.engineConfig.SessionId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (c *Cmd) execAdmin(ctx context.Context, ss storage.StorageService) error { | func (c *Cmd) execAdmin(ctx context.Context, ss storage.StorageService) error { | ||||||
| 	pe, err := ss.GetPersister(ctx) | 	pe, err := ss.GetPersister(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -63,6 +190,51 @@ func (c *Cmd) execAdmin(ctx context.Context, ss storage.StorageService) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (c *Cmd) execOverwrite(ctx context.Context, ss storage.StorageService) error { | ||||||
|  | 	store, err := ss.GetUserdataDb(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("failed to get userdata store: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Map of symbolic keys to their DataTyp constants
 | ||||||
|  | 	symbolicKeys := map[string]storedb.DataTyp{ | ||||||
|  | 		"first_name":  storedb.DATA_FIRST_NAME, | ||||||
|  | 		"family_name": storedb.DATA_FAMILY_NAME, | ||||||
|  | 		"yob":         storedb.DATA_YOB, | ||||||
|  | 		"location":    storedb.DATA_LOCATION, | ||||||
|  | 		"gender":      storedb.DATA_GENDER, | ||||||
|  | 		"offerings":   storedb.DATA_OFFERINGS, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Lookup symbolic key
 | ||||||
|  | 	dtype, ok := symbolicKeys[strings.ToLower(c.key)] | ||||||
|  | 	if !ok { | ||||||
|  | 		return fmt.Errorf("unknown key '%s'. Available keys: %v", c.key, keysOf(symbolicKeys)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	k := storedb.ToBytes(dtype) | ||||||
|  | 
 | ||||||
|  | 	store.SetPrefix(db.DATATYPE_USERDATA) | ||||||
|  | 	store.SetSession(c.sessionId) | ||||||
|  | 
 | ||||||
|  | 	err = store.Put(ctx, k, []byte(c.value)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("failed to overwrite entry for key %s: %v", c.key, err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	logg.InfoCtxf(ctx, "overwrote data", "sessionId", c.sessionId, "key", c.key, "value", c.value) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // keysOf returns a list of keys from the symbolic map for error messages
 | ||||||
|  | func keysOf(m map[string]storedb.DataTyp) []string { | ||||||
|  | 	keys := make([]string, 0, len(m)) | ||||||
|  | 	for k := range m { | ||||||
|  | 		keys = append(keys, k) | ||||||
|  | 	} | ||||||
|  | 	return keys | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (c *Cmd) parseCmdAdmin(cmd string, param string, more []string) (bool, error) { | func (c *Cmd) parseCmdAdmin(cmd string, param string, more []string) (bool, error) { | ||||||
| 	if cmd == "admin" { | 	if cmd == "admin" { | ||||||
| 		if param == "1" { | 		if param == "1" { | ||||||
| @ -76,13 +248,56 @@ func (c *Cmd) parseCmdAdmin(cmd string, param string, more []string) (bool, erro | |||||||
| 	return false, nil | 	return false, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (c *Cmd) parseCmdReset(cmd string, param string, more []string) (bool, error) { | ||||||
|  | 	if cmd == "reset" { | ||||||
|  | 		c.enable = false | ||||||
|  | 		c.exec = c.execReset | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  | 	return false, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *Cmd) parseCmdClone(cmd string, param string, more []string) (bool, error) { | ||||||
|  | 	if cmd == "clone" { | ||||||
|  | 		c.enable = false | ||||||
|  | 		c.param = param | ||||||
|  | 		c.exec = c.execClone | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  | 	return false, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *Cmd) parseCmdOverwrite(cmd string, param string, more []string) (bool, error) { | ||||||
|  | 	if cmd == "overwrite" { | ||||||
|  | 		if len(more) < 1 { | ||||||
|  | 			return false, fmt.Errorf("overwrite requires key and value") | ||||||
|  | 		} | ||||||
|  | 		c.key = param | ||||||
|  | 		c.value = more[0] | ||||||
|  | 		c.exec = c.execOverwrite | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  | 	return false, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (c *Cmd) Parse(args []string) error { | func (c *Cmd) Parse(args []string) error { | ||||||
| 	if len(args) < 2 { | 	var param string | ||||||
|  | 	if len(args) < 1 { | ||||||
| 		return fmt.Errorf("Wrong number of arguments: %v", args) | 		return fmt.Errorf("Wrong number of arguments: %v", args) | ||||||
| 	} | 	} | ||||||
| 	cmd := args[0] | 	cmd := args[0] | ||||||
| 	param := args[1] | 
 | ||||||
| 	args = args[2:] | 	n, ok := argc[cmd] | ||||||
|  | 	if !ok { | ||||||
|  | 		return fmt.Errorf("invalid command: %v", cmd) | ||||||
|  | 	} | ||||||
|  | 	if n > 0 { | ||||||
|  | 		if len(args) < n+1 { | ||||||
|  | 			return fmt.Errorf("Wrong number of arguments, need: %d", n) | ||||||
|  | 		} | ||||||
|  | 		param = args[1] | ||||||
|  | 		args = args[2:] | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	r, err := c.parseCmdAdmin(cmd, param, args) | 	r, err := c.parseCmdAdmin(cmd, param, args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -92,5 +307,29 @@ func (c *Cmd) Parse(args []string) error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	r, err = c.parseCmdReset(cmd, param, args) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if r { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	r, err = c.parseCmdClone(cmd, param, args) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if r { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	r, err = c.parseCmdOverwrite(cmd, param, args) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if r { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return fmt.Errorf("unknown subcommand: %s", cmd) | 	return fmt.Errorf("unknown subcommand: %s", cmd) | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,9 +10,9 @@ import ( | |||||||
| func TestInsertOrShift(t *testing.T) { | func TestInsertOrShift(t *testing.T) { | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| 		name     string | 		name     string | ||||||
| 		profile Profile | 		profile  Profile | ||||||
| 		index   int | 		index    int | ||||||
| 		value   string | 		value    string | ||||||
| 		expected []string | 		expected []string | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
|  | |||||||
| @ -181,8 +181,8 @@ func (s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) { | |||||||
| 	accountService := services.New(ctx, menuStorageService) | 	accountService := services.New(ctx, menuStorageService) | ||||||
| 	_, err = lhs.GetHandler(accountService) | 	_, err = lhs.GetHandler(accountService) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 	       fmt.Fprintf(os.Stderr, "get accounts service handler: %v\n", err) | 		fmt.Fprintf(os.Stderr, "get accounts service handler: %v\n", err) | ||||||
| 	       os.Exit(1) | 		os.Exit(1) | ||||||
| 	} | 	} | ||||||
| 	en := lhs.GetEngine(lhs.Cfg, rs, pe) | 	en := lhs.GetEngine(lhs.Cfg, rs, pe) | ||||||
| 	closer := func() { | 	closer := func() { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user