Skip to content
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

NAME := volt
SRC := $(shell find . -type d -name 'vendor' -prune -o -type f -name '*.go' -print)
VERSION := $(shell sed -n -E 's/var voltVersion = "([^"]+)"/\1/p' subcmd/version.go)
VERSION := $(shell sed -n -E 's/var VoltVersion = "([^"]+)"/\1/p' usecase/version.go)
RELEASE_LDFLAGS := -s -w -extldflags '-static'
RELEASE_OS := linux windows darwin
RELEASE_ARCH := amd64 386
Expand Down
20 changes: 20 additions & 0 deletions _docs/layer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

## Layered architecture

The volt commands like `volt get` which may modify lock.json, config.toml,
filesystem, are executed in several steps:

1. (UI layer): Passes subcommand arguments, lock.json & config.toml structure to Gateway layer
2. (Gateway layer): Invokes usecase(s). This layer cannot touch filesystem, do network requests, because it makes unit testing difficult
3. (Usecase layer): Modify files, do network requests, and other business logic

Below is the dependency graph:

```
UI --> Gateway --> Usecase
```

* UI only depends Gateway
* Gateway doesn't know UI
* Gateway only depends Usecase
* Usecase doesn't know Gateway
10 changes: 5 additions & 5 deletions subcmd/build.go → gateway/build.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package subcmd
package gateway

import (
"flag"
"fmt"
"os"

"github.com/vim-volt/volt/gateway/builder"
"github.com/vim-volt/volt/logger"
"github.com/vim-volt/volt/subcmd/builder"
"github.com/vim-volt/volt/transaction"
)

Expand Down Expand Up @@ -53,10 +53,10 @@ Description
return fs
}

func (cmd *buildCmd) Run(args []string) *Error {
func (cmd *buildCmd) Run(cmdctx *CmdContext) *Error {
// Parse args
fs := cmd.FlagSet()
fs.Parse(args)
fs.Parse(cmdctx.Args)
if cmd.helped {
return nil
}
Expand All @@ -69,7 +69,7 @@ func (cmd *buildCmd) Run(args []string) *Error {
}
defer transaction.Remove()

err = builder.Build(cmd.full)
err = builder.Build(cmd.full, cmdctx.Config, cmdctx.LockJSON)
if err != nil {
logger.Error()
return &Error{Code: 12, Msg: "Failed to build: " + err.Error()}
Expand Down
4 changes: 2 additions & 2 deletions subcmd/build_test.go → gateway/build_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package subcmd
package gateway

import (
"bytes"
Expand All @@ -13,10 +13,10 @@ import (
"github.com/haya14busa/go-vimlparser"
"github.com/vim-volt/volt/config"
"github.com/vim-volt/volt/fileutil"
"github.com/vim-volt/volt/gateway/builder"
"github.com/vim-volt/volt/internal/testutil"
"github.com/vim-volt/volt/lockjson"
"github.com/vim-volt/volt/pathutil"
"github.com/vim-volt/volt/subcmd/builder"
)

// Checks:
Expand Down
2 changes: 1 addition & 1 deletion subcmd/builder/base.go → gateway/builder/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (

"github.com/hashicorp/go-multierror"
"github.com/vim-volt/volt/fileutil"
"github.com/vim-volt/volt/gateway/buildinfo"
"github.com/vim-volt/volt/lockjson"
"github.com/vim-volt/volt/logger"
"github.com/vim-volt/volt/pathutil"
"github.com/vim-volt/volt/subcmd/buildinfo"
)

// BaseBuilder is a base struct which all builders must implement
Expand Down
18 changes: 7 additions & 11 deletions subcmd/builder/builder.go → gateway/builder/builder.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
package builder

import (
"github.com/pkg/errors"
"os"

"github.com/pkg/errors"

"github.com/vim-volt/volt/config"
"github.com/vim-volt/volt/gateway/buildinfo"
"github.com/vim-volt/volt/lockjson"
"github.com/vim-volt/volt/logger"
"github.com/vim-volt/volt/pathutil"
"github.com/vim-volt/volt/subcmd/buildinfo"
)

// Builder creates/updates ~/.vim/pack/volt directory
type Builder interface {
Build(buildInfo *buildinfo.BuildInfo, buildReposMap map[pathutil.ReposPath]*buildinfo.Repos) error
Build(buildInfo *buildinfo.BuildInfo, buildReposMap map[pathutil.ReposPath]*buildinfo.Repos, lockJSON *lockjson.LockJSON) error
}

const currentBuildInfoVersion = 2

// Build creates/updates ~/.vim/pack/volt directory
func Build(full bool) error {
// Read config.toml
cfg, err := config.Read()
if err != nil {
return errors.Wrap(err, "could not read config.toml")
}

func Build(full bool, cfg *config.Config, lockJSON *lockjson.LockJSON) error {
// Get builder
blder, err := getBuilder(cfg.Build.Strategy)
if err != nil {
Expand Down Expand Up @@ -75,7 +71,7 @@ func Build(full bool) error {
}
}

return blder.Build(buildInfo, buildReposMap)
return blder.Build(buildInfo, buildReposMap, lockJSON)
}

func getBuilder(strategy string) (Builder, error) {
Expand Down
10 changes: 2 additions & 8 deletions subcmd/builder/copy.go → gateway/builder/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (

"github.com/hashicorp/go-multierror"
"github.com/vim-volt/volt/fileutil"
"github.com/vim-volt/volt/gateway/buildinfo"
"github.com/vim-volt/volt/gitutil"
"github.com/vim-volt/volt/lockjson"
"github.com/vim-volt/volt/logger"
"github.com/vim-volt/volt/pathutil"
"github.com/vim-volt/volt/plugconf"
"github.com/vim-volt/volt/subcmd/buildinfo"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/object"
Expand All @@ -25,19 +25,13 @@ type copyBuilder struct {
BaseBuilder
}

func (builder *copyBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap map[pathutil.ReposPath]*buildinfo.Repos) error {
func (builder *copyBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap map[pathutil.ReposPath]*buildinfo.Repos, lockJSON *lockjson.LockJSON) error {
// Exit if vim executable was not found in PATH
vimExePath, err := pathutil.VimExecutable()
if err != nil {
return err
}

// Read lock.json
lockJSON, err := lockjson.Read()
if err != nil {
return errors.New("could not read lock.json: " + err.Error())
}

// Get current profile's repos list
reposList, err := lockJSON.GetCurrentReposList()
if err != nil {
Expand Down
8 changes: 2 additions & 6 deletions subcmd/builder/symlink.go → gateway/builder/symlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,26 @@ import (

"gopkg.in/src-d/go-git.v4"

"github.com/vim-volt/volt/gateway/buildinfo"
"github.com/vim-volt/volt/gitutil"
"github.com/vim-volt/volt/lockjson"
"github.com/vim-volt/volt/logger"
"github.com/vim-volt/volt/pathutil"
"github.com/vim-volt/volt/plugconf"
"github.com/vim-volt/volt/subcmd/buildinfo"
)

type symlinkBuilder struct {
BaseBuilder
}

// TODO: rollback when return err (!= nil)
func (builder *symlinkBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap map[pathutil.ReposPath]*buildinfo.Repos) error {
func (builder *symlinkBuilder) Build(buildInfo *buildinfo.BuildInfo, buildReposMap map[pathutil.ReposPath]*buildinfo.Repos, lockJSON *lockjson.LockJSON) error {
// Exit if vim executable was not found in PATH
if _, err := pathutil.VimExecutable(); err != nil {
return err
}

// Get current profile's repos list
lockJSON, err := lockjson.Read()
if err != nil {
return errors.Wrap(err, "could not read lock.json")
}
reposList, err := lockJSON.GetCurrentReposList()
if err != nil {
return err
Expand Down
File renamed without changes.
42 changes: 42 additions & 0 deletions gateway/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package gateway

import (
"flag"

"github.com/vim-volt/volt/config"
"github.com/vim-volt/volt/lockjson"
)

var cmdMap = make(map[string]Cmd)

// LookUpCmd looks up subcommand by name.
func LookUpCmd(cmd string) Cmd {
return cmdMap[cmd]
}

// Cmd represents volt's subcommand interface.
// All subcommands must implement this.
type Cmd interface {
ProhibitRootExecution(args []string) bool
Run(cmdctx *CmdContext) *Error
FlagSet() *flag.FlagSet
}

// CmdContext is a data transfer object between Subcmd and Gateway layer.
type CmdContext struct {
Cmd string
Args []string
LockJSON *lockjson.LockJSON
Config *config.Config
}

// Error is a command error.
// It also has a exit code.
type Error struct {
Code int
Msg string
}

func (e *Error) Error() string {
return e.Msg
}
28 changes: 8 additions & 20 deletions subcmd/get.go → gateway/get.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package subcmd
package gateway

import (
"flag"
Expand All @@ -17,12 +17,12 @@ import (

"github.com/vim-volt/volt/config"
"github.com/vim-volt/volt/fileutil"
"github.com/vim-volt/volt/gateway/builder"
"github.com/vim-volt/volt/gitutil"
"github.com/vim-volt/volt/lockjson"
"github.com/vim-volt/volt/logger"
"github.com/vim-volt/volt/pathutil"
"github.com/vim-volt/volt/plugconf"
"github.com/vim-volt/volt/subcmd/builder"
"github.com/vim-volt/volt/transaction"

multierror "github.com/hashicorp/go-multierror"
Expand Down Expand Up @@ -116,31 +116,25 @@ Options`)
return fs
}

func (cmd *getCmd) Run(args []string) *Error {
func (cmd *getCmd) Run(cmdctx *CmdContext) *Error {
// Parse args
args, err := cmd.parseArgs(args)
args, err := cmd.parseArgs(cmdctx.Args)
if err == ErrShowedHelp {
return nil
}
if err != nil {
return &Error{Code: 10, Msg: "Failed to parse args: " + err.Error()}
}

// Read lock.json
lockJSON, err := lockjson.Read()
if err != nil {
return &Error{Code: 11, Msg: "Could not read lock.json: " + err.Error()}
}

reposPathList, err := cmd.getReposPathList(args, lockJSON)
reposPathList, err := cmd.getReposPathList(args, cmdctx.LockJSON)
if err != nil {
return &Error{Code: 12, Msg: "Could not get repos list: " + err.Error()}
}
if len(reposPathList) == 0 {
return &Error{Code: 13, Msg: "No repositories are specified"}
}

err = cmd.doGet(reposPathList, lockJSON)
err = cmd.doGet(reposPathList, cmdctx.Config, cmdctx.LockJSON)
if err != nil {
return &Error{Code: 20, Msg: err.Error()}
}
Expand Down Expand Up @@ -187,7 +181,7 @@ func (cmd *getCmd) getReposPathList(args []string, lockJSON *lockjson.LockJSON)
return reposPathList, nil
}

func (cmd *getCmd) doGet(reposPathList []pathutil.ReposPath, lockJSON *lockjson.LockJSON) error {
func (cmd *getCmd) doGet(reposPathList []pathutil.ReposPath, cfg *config.Config, lockJSON *lockjson.LockJSON) error {
// Find matching profile
profile, err := lockJSON.Profiles.FindByName(lockJSON.CurrentProfileName)
if err != nil {
Expand All @@ -203,12 +197,6 @@ func (cmd *getCmd) doGet(reposPathList []pathutil.ReposPath, lockJSON *lockjson.
}
defer transaction.Remove()

// Read config.toml
cfg, err := config.Read()
if err != nil {
return errors.Wrap(err, "could not read config.toml")
}

done := make(chan getParallelResult, len(reposPathList))
getCount := 0
// Invoke installing / upgrading tasks
Expand Down Expand Up @@ -255,7 +243,7 @@ func (cmd *getCmd) doGet(reposPathList []pathutil.ReposPath, lockJSON *lockjson.
}

// Build ~/.vim/pack/volt dir
err = builder.Build(false)
err = builder.Build(false, cfg, lockJSON)
if err != nil {
return errors.Wrap(err, "could not build "+pathutil.VimVoltDir())
}
Expand Down
2 changes: 1 addition & 1 deletion subcmd/get_test.go → gateway/get_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package subcmd
package gateway

import (
"bytes"
Expand Down
9 changes: 5 additions & 4 deletions subcmd/help.go → gateway/help.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package subcmd
package gateway

import (
"flag"
Expand Down Expand Up @@ -99,7 +99,8 @@ Command
return fs
}

func (cmd *helpCmd) Run(args []string) *Error {
func (cmd *helpCmd) Run(cmdctx *CmdContext) *Error {
args := cmdctx.Args
if len(args) == 0 {
cmd.FlagSet().Usage()
return nil
Expand All @@ -112,7 +113,7 @@ func (cmd *helpCmd) Run(args []string) *Error {
if !exists {
return &Error{Code: 1, Msg: fmt.Sprintf("Unknown command '%s'", args[0])}
}
args = append([]string{"-help"}, args[1:]...)
fs.Run(args)
cmdctx.Args = append([]string{"-help"}, args[1:]...)
fs.Run(cmdctx)
return nil
}
2 changes: 1 addition & 1 deletion subcmd/help_test.go → gateway/help_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package subcmd
package gateway

import (
"strings"
Expand Down
Loading