Skip to content

Commit a83a374

Browse files
committed
refactor: don't read lock.json,config.toml in subcmd package
See _docs/json-dsl.md for layered architecture: 1. (Gateway layer): pass subcommand arguments, lock.json & config.toml structure to Subcmd layer 2. (Subcmd layer): Create an AST according to given information * This layer cannot touch filesystem, because it makes unit testing difficult
1 parent a5ad062 commit a83a374

22 files changed

+230
-237
lines changed

subcmd/cmd.go renamed to gateway/gateway.go

Lines changed: 36 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,84 @@
1-
package subcmd
1+
package gateway
22

33
import (
44
"errors"
5-
"flag"
65
"os"
76
"os/user"
87
"runtime"
98

109
"github.com/vim-volt/volt/config"
10+
"github.com/vim-volt/volt/lockjson"
1111
"github.com/vim-volt/volt/logger"
12+
"github.com/vim-volt/volt/subcmd"
1213
)
1314

14-
var cmdMap = make(map[string]Cmd)
15-
16-
// Cmd represents volt's subcommand interface.
17-
// All subcommands must implement this.
18-
type Cmd interface {
19-
ProhibitRootExecution(args []string) bool
20-
Run(args []string) *Error
21-
FlagSet() *flag.FlagSet
22-
}
23-
2415
// RunnerFunc invokes c with args.
2516
// On unit testing, a mock function was given.
26-
type RunnerFunc func(c Cmd, args []string) *Error
27-
28-
// Error is a command error.
29-
// It also has a exit code.
30-
type Error struct {
31-
Code int
32-
Msg string
33-
}
34-
35-
func (e *Error) Error() string {
36-
return e.Msg
37-
}
17+
type RunnerFunc func(c subcmd.Cmd, runctx *subcmd.RunContext) *subcmd.Error
3818

3919
// DefaultRunner simply runs command with args
40-
func DefaultRunner(c Cmd, args []string) *Error {
41-
return c.Run(args)
20+
func DefaultRunner(c subcmd.Cmd, runctx *subcmd.RunContext) *subcmd.Error {
21+
return c.Run(runctx)
4222
}
4323

4424
// Run is invoked by main(), each argument means 'volt {subcmd} {args}'.
45-
func Run(args []string, cont RunnerFunc) *Error {
25+
func Run(args []string, cont RunnerFunc) *subcmd.Error {
4626
if os.Getenv("VOLT_DEBUG") != "" {
4727
logger.SetLevel(logger.DebugLevel)
4828
}
4929

5030
if len(args) <= 1 {
5131
args = append(args, "help")
5232
}
53-
subCmd := args[1]
33+
cmdname := args[1]
5434
args = args[2:]
5535

36+
// Read config.toml
37+
cfg, err := config.Read()
38+
if err != nil {
39+
err = errors.New("could not read config.toml: " + err.Error())
40+
return &subcmd.Error{Code: 2, Msg: err.Error()}
41+
}
42+
5643
// Expand subcommand alias
57-
subCmd, args, err := expandAlias(subCmd, args)
44+
cmdname, args, err = expandAlias(cmdname, args, cfg)
5845
if err != nil {
59-
return &Error{Code: 1, Msg: err.Error()}
46+
return &subcmd.Error{Code: 1, Msg: err.Error()}
6047
}
6148

62-
c, exists := cmdMap[subCmd]
49+
c, exists := subcmd.LookupSubcmd(cmdname)
6350
if !exists {
64-
return &Error{Code: 3, Msg: "Unknown command '" + subCmd + "'"}
51+
return &subcmd.Error{Code: 3, Msg: "Unknown command '" + cmdname + "'"}
6552
}
6653

6754
// Disallow executing the commands which may modify files in root priviledge
6855
if c.ProhibitRootExecution(args) {
6956
err := detectPriviledgedUser()
7057
if err != nil {
71-
return &Error{Code: 4, Msg: err.Error()}
58+
return &subcmd.Error{Code: 4, Msg: err.Error()}
7259
}
7360
}
7461

75-
return cont(c, args)
76-
}
77-
78-
func expandAlias(subCmd string, args []string) (string, []string, error) {
79-
cfg, err := config.Read()
62+
// Read lock.json
63+
lockJSON, err := lockjson.Read()
8064
if err != nil {
81-
return "", nil, errors.New("could not read config.toml: " + err.Error())
65+
err = errors.New("failed to read lock.json: " + err.Error())
66+
return &subcmd.Error{Code: 5, Msg: err.Error()}
8267
}
83-
if newArgs, exists := cfg.Alias[subCmd]; exists && len(newArgs) > 0 {
84-
subCmd = newArgs[0]
68+
69+
return cont(c, &subcmd.RunContext{
70+
Args: args,
71+
LockJSON: lockJSON,
72+
Config: cfg,
73+
})
74+
}
75+
76+
func expandAlias(cmdname string, args []string, cfg *config.Config) (string, []string, error) {
77+
if newArgs, exists := cfg.Alias[cmdname]; exists && len(newArgs) > 0 {
78+
cmdname = newArgs[0]
8579
args = append(newArgs[1:], args...)
8680
}
87-
return subCmd, args, nil
81+
return cmdname, args, nil
8882
}
8983

9084
// On Windows, this function always returns nil.

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ package main
55
import (
66
"os"
77

8+
"github.com/vim-volt/volt/gateway"
89
"github.com/vim-volt/volt/logger"
9-
"github.com/vim-volt/volt/subcmd"
1010
)
1111

1212
func main() {
13-
err := subcmd.Run(os.Args, subcmd.DefaultRunner)
13+
err := gateway.Run(os.Args, gateway.DefaultRunner)
1414
if err != nil {
1515
logger.Error(err.Msg)
1616
os.Exit(err.Code)

migration/lockjson.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package migration
33
import (
44
"errors"
55

6+
"github.com/vim-volt/volt/config"
67
"github.com/vim-volt/volt/lockjson"
78
"github.com/vim-volt/volt/transaction"
89
)
@@ -31,15 +32,9 @@ Description
3132
To suppress this, running this command simply reads and writes migrated structure to lock.json.`
3233
}
3334

34-
func (*lockjsonMigrater) Migrate() error {
35-
// Read lock.json
36-
lockJSON, err := lockjson.ReadNoMigrationMsg()
37-
if err != nil {
38-
return errors.New("could not read lock.json: " + err.Error())
39-
}
40-
35+
func (*lockjsonMigrater) Migrate(lockJSON *lockjson.LockJSON, cfg *config.Config) error {
4136
// Begin transaction
42-
err = transaction.Create()
37+
err := transaction.Create()
4338
if err != nil {
4439
return err
4540
}

migration/migrater.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ package migration
33
import (
44
"errors"
55
"sort"
6+
7+
"github.com/vim-volt/volt/config"
8+
"github.com/vim-volt/volt/lockjson"
69
)
710

811
// Migrater migrates many kinds of data.
912
type Migrater interface {
10-
Migrate() error
13+
Migrate(*lockjson.LockJSON, *config.Config) error
1114
Name() string
1215
Description(brief bool) string
1316
}

migration/plugconf-config-func.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"path/filepath"
88
"strings"
99

10+
"github.com/vim-volt/volt/config"
1011
"github.com/vim-volt/volt/lockjson"
1112
"github.com/vim-volt/volt/logger"
1213
"github.com/vim-volt/volt/pathutil"
@@ -39,13 +40,7 @@ Description
3940
All plugconf files are replaced with new contents.`
4041
}
4142

42-
func (*plugconfConfigMigrater) Migrate() error {
43-
// Read lock.json
44-
lockJSON, err := lockjson.ReadNoMigrationMsg()
45-
if err != nil {
46-
return errors.New("could not read lock.json: " + err.Error())
47-
}
48-
43+
func (*plugconfConfigMigrater) Migrate(lockJSON *lockjson.LockJSON, cfg *config.Config) error {
4944
results, parseErr := plugconf.ParseMultiPlugconf(lockJSON.Repos)
5045
if parseErr.HasErrs() {
5146
logger.Error("Please fix the following errors before migration:")
@@ -82,21 +77,21 @@ func (*plugconfConfigMigrater) Migrate() error {
8277
// After checking errors, write the content to files
8378
for _, info := range infoList {
8479
os.MkdirAll(filepath.Dir(info.path), 0755)
85-
err = ioutil.WriteFile(info.path, info.content, 0644)
80+
err := ioutil.WriteFile(info.path, info.content, 0644)
8681
if err != nil {
8782
return err
8883
}
8984
}
9085

9186
// Begin transaction
92-
err = transaction.Create()
87+
err := transaction.Create()
9388
if err != nil {
9489
return err
9590
}
9691
defer transaction.Remove()
9792

9893
// Build ~/.vim/pack/volt dir
99-
err = builder.Build(false)
94+
err = builder.Build(false, lockJSON, cfg)
10095
if err != nil {
10196
return errors.New("could not build " + pathutil.VimVoltDir() + ": " + err.Error())
10297
}

subcmd/build.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ Description
5353
return fs
5454
}
5555

56-
func (cmd *buildCmd) Run(args []string) *Error {
56+
func (cmd *buildCmd) Run(runctx *RunContext) *Error {
5757
// Parse args
5858
fs := cmd.FlagSet()
59-
fs.Parse(args)
59+
fs.Parse(runctx.Args)
6060
if cmd.helped {
6161
return nil
6262
}
@@ -69,7 +69,7 @@ func (cmd *buildCmd) Run(args []string) *Error {
6969
}
7070
defer transaction.Remove()
7171

72-
err = builder.Build(cmd.full)
72+
err = builder.Build(cmd.full, runctx.LockJSON, runctx.Config)
7373
if err != nil {
7474
logger.Error()
7575
return &Error{Code: 12, Msg: "Failed to build: " + err.Error()}

subcmd/builder/base.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import (
1818
)
1919

2020
// BaseBuilder is a base struct which all builders must implement
21-
type BaseBuilder struct{}
21+
type BaseBuilder struct {
22+
lockJSON *lockjson.LockJSON
23+
}
2224

2325
func (builder *BaseBuilder) installVimrcAndGvimrc(profileName, vimrcPath, gvimrcPath string) error {
2426
// Save old vimrc file as {vimrc}.bak

subcmd/builder/builder.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/vim-volt/volt/buildinfo"
88
"github.com/vim-volt/volt/config"
9+
"github.com/vim-volt/volt/lockjson"
910
"github.com/vim-volt/volt/logger"
1011
"github.com/vim-volt/volt/pathutil"
1112
)
@@ -18,15 +19,9 @@ type Builder interface {
1819
const currentBuildInfoVersion = 2
1920

2021
// Build creates/updates ~/.vim/pack/volt directory
21-
func Build(full bool) error {
22-
// Read config.toml
23-
cfg, err := config.Read()
24-
if err != nil {
25-
return errors.New("could not read config.toml: " + err.Error())
26-
}
27-
22+
func Build(full bool, lockJSON *lockjson.LockJSON, cfg *config.Config) error {
2823
// Get builder
29-
blder, err := getBuilder(cfg.Build.Strategy)
24+
blder, err := getBuilder(cfg.Build.Strategy, lockJSON)
3025
if err != nil {
3126
return err
3227
}
@@ -78,12 +73,13 @@ func Build(full bool) error {
7873
return blder.Build(buildInfo, buildReposMap)
7974
}
8075

81-
func getBuilder(strategy string) (Builder, error) {
76+
func getBuilder(strategy string, lockJSON *lockjson.LockJSON) (Builder, error) {
77+
base := &BaseBuilder{lockJSON: lockJSON}
8278
switch strategy {
8379
case config.SymlinkBuilder:
84-
return &symlinkBuilder{}, nil
80+
return &symlinkBuilder{base}, nil
8581
case config.CopyBuilder:
86-
return &copyBuilder{}, nil
82+
return &copyBuilder{base}, nil
8783
default:
8884
return nil, errors.New("unknown builder type: " + strategy)
8985
}

subcmd/builder/copy.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
)
2323

2424
type copyBuilder struct {
25-
BaseBuilder
25+
*BaseBuilder
2626
}
2727

2828
func (builder *copyBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap map[pathutil.ReposPath]*buildinfo.Repos) error {
@@ -32,14 +32,8 @@ func (builder *copyBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap
3232
return err
3333
}
3434

35-
// Read lock.json
36-
lockJSON, err := lockjson.Read()
37-
if err != nil {
38-
return errors.New("could not read lock.json: " + err.Error())
39-
}
40-
4135
// Get current profile's repos list
42-
reposList, err := lockJSON.GetCurrentReposList()
36+
reposList, err := builder.lockJSON.GetCurrentReposList()
4337
if err != nil {
4438
return err
4539
}
@@ -50,7 +44,7 @@ func (builder *copyBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap
5044
vimrcPath := filepath.Join(vimDir, pathutil.Vimrc)
5145
gvimrcPath := filepath.Join(vimDir, pathutil.Gvimrc)
5246
err = builder.installVimrcAndGvimrc(
53-
lockJSON.CurrentProfileName, vimrcPath, gvimrcPath,
47+
builder.lockJSON.CurrentProfileName, vimrcPath, gvimrcPath,
5448
)
5549
if err != nil {
5650
return err
@@ -98,7 +92,7 @@ func (builder *copyBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap
9892
}
9993

10094
// Write bundled plugconf file
101-
rcDir := pathutil.RCDir(lockJSON.CurrentProfileName)
95+
rcDir := pathutil.RCDir(builder.lockJSON.CurrentProfileName)
10296
vimrc := ""
10397
if path := filepath.Join(rcDir, pathutil.ProfileVimrc); pathutil.Exists(path) {
10498
vimrc = path

subcmd/builder/symlink.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
)
2121

2222
type symlinkBuilder struct {
23-
BaseBuilder
23+
*BaseBuilder
2424
}
2525

2626
// TODO: rollback when return err (!= nil)
@@ -31,11 +31,7 @@ func (builder *symlinkBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposM
3131
}
3232

3333
// Get current profile's repos list
34-
lockJSON, err := lockjson.Read()
35-
if err != nil {
36-
return errors.New("could not read lock.json: " + err.Error())
37-
}
38-
reposList, err := lockJSON.GetCurrentReposList()
34+
reposList, err := builder.lockJSON.GetCurrentReposList()
3935
if err != nil {
4036
return err
4137
}
@@ -46,7 +42,7 @@ func (builder *symlinkBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposM
4642
vimrcPath := filepath.Join(vimDir, pathutil.Vimrc)
4743
gvimrcPath := filepath.Join(vimDir, pathutil.Gvimrc)
4844
err = builder.installVimrcAndGvimrc(
49-
lockJSON.CurrentProfileName, vimrcPath, gvimrcPath,
45+
builder.lockJSON.CurrentProfileName, vimrcPath, gvimrcPath,
5046
)
5147
if err != nil {
5248
return err
@@ -86,7 +82,7 @@ func (builder *symlinkBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposM
8682
}
8783

8884
// Write bundled plugconf file
89-
rcDir := pathutil.RCDir(lockJSON.CurrentProfileName)
85+
rcDir := pathutil.RCDir(builder.lockJSON.CurrentProfileName)
9086
vimrc := ""
9187
if path := filepath.Join(rcDir, pathutil.ProfileVimrc); pathutil.Exists(path) {
9288
vimrc = path

0 commit comments

Comments
 (0)