这是indexloc提供的服务,不要输入任何密码
Skip to content

Proposal for incremental path refactor #995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions cli/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type Config struct {
// package.json at the root of the repo
RootPackageJSON *fs.PackageJSON
// Current Working Directory
Cwd string
Cwd fs.AbsolutePath
}

// IsLoggedIn returns true if we have a token and either a team id or team slug
Expand Down Expand Up @@ -99,8 +99,8 @@ func ParseAndValidate(args []string, ui cli.Ui, turboVersion string) (c *Config,
return nil, err
}
// Precedence is flags > env > config > default
packageJSONPath := filepath.Join(cwd, "package.json")
rootPackageJSON, err := fs.ReadPackageJSON(packageJSONPath)
packageJSONPath := cwd.Join("package.json")
rootPackageJSON, err := fs.ReadPackageJSON(packageJSONPath.ToStringDuringMigration())
if err != nil {
return nil, fmt.Errorf("package.json: %w", err)
}
Expand Down Expand Up @@ -214,14 +214,14 @@ func ParseAndValidate(args []string, ui cli.Ui, turboVersion string) (c *Config,
return c, nil
}

func ReadTurboConfig(rootPath string, rootPackageJSON *fs.PackageJSON) (*fs.TurboConfigJSON, error) {
func ReadTurboConfig(rootPath fs.AbsolutePath, rootPackageJSON *fs.PackageJSON) (*fs.TurboConfigJSON, error) {
// If turbo.json exists, we use that
// If pkg.Turbo exists, we warn about running the migration
// Use pkg.Turbo if turbo.json doesn't exist
// If neither exists, it's a fatal error
turboJSONPath := filepath.Join(rootPath, "turbo.json")
turboJSONPath := rootPath.Join("turbo.json")

if !fs.FileExists(turboJSONPath) {
if !turboJSONPath.FileExists() {
if rootPackageJSON.LegacyTurboConfig == nil {
// TODO: suggestion on how to create one
return nil, fmt.Errorf("Could not find turbo.json. Follow directions at https://turborepo.org/docs/getting-started to create one")
Expand All @@ -244,17 +244,23 @@ func ReadTurboConfig(rootPath string, rootPackageJSON *fs.PackageJSON) (*fs.Turb

// Selects the current working directory from OS
// and overrides with the `--cwd=` input argument
func selectCwd(inputArgs []string) (string, error) {
cwd, err := os.Getwd()
func selectCwd(inputArgs []string) (fs.AbsolutePath, error) {
cwd, err := fs.GetCwd()
if err != nil {
return "", fmt.Errorf("invalid working directory: %w", err)
return "", err
}
for _, arg := range inputArgs {
if arg == "--" {
break
} else if strings.HasPrefix(arg, "--cwd=") {
if len(arg[len("--cwd="):]) > 0 {
cwd = arg[len("--cwd="):]
cwdArgRaw := arg[len("--cwd="):]
cwdArg, err := fs.CheckedToAbsolutePath(cwdArgRaw)
if err != nil {
// the argument is a relative path. Join it with our actual cwd
return cwd.Join(cwdArgRaw), nil
}
return cwdArg, nil
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions cli/internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ package config

import (
"fmt"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/vercel/turborepo/cli/internal/fs"
)

func TestSelectCwd(t *testing.T) {
defaultCwd, err := os.Getwd()
defaultCwd, err := fs.GetCwd()
if err != nil {
t.Errorf("failed to get cwd: %v", err)
}

cases := []struct {
Name string
InputArgs []string
Expected string
Expected fs.AbsolutePath
}{
{
Name: "default",
Expand All @@ -27,12 +27,12 @@ func TestSelectCwd(t *testing.T) {
{
Name: "choose command-line flag cwd",
InputArgs: []string{"foo", "--cwd=zop"},
Expected: "zop",
Expected: defaultCwd.Join("zop"),
},
{
Name: "ignore other flags not cwd",
InputArgs: []string{"foo", "--ignore-this-1", "--cwd=zop", "--ignore-this=2"},
Expected: "zop",
Expected: defaultCwd.Join("zop"),
},
{
Name: "ignore args after pass through",
Expand Down
5 changes: 2 additions & 3 deletions cli/internal/fs/package_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package fs
import (
"encoding/json"
"io/ioutil"
"os"
"strings"
"sync"

Expand All @@ -24,8 +23,8 @@ type TurboConfigJSON struct {
RemoteCacheOptions RemoteCacheOptions `json:"remoteCache,omitempty"`
}

func ReadTurboConfigJSON(path string) (*TurboConfigJSON, error) {
file, err := os.Open(path)
func ReadTurboConfigJSON(path AbsolutePath) (*TurboConfigJSON, error) {
file, err := path.Open()
if err != nil {
return nil, err
}
Expand Down
7 changes: 5 additions & 2 deletions cli/internal/fs/package_json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package fs

import (
"os"
"path/filepath"
"strings"
"testing"

Expand All @@ -14,7 +13,11 @@ func Test_ParseTurboConfigJson(t *testing.T) {
if err != nil {
t.Errorf("failed to get cwd: %v", err)
}
turboJSONPath := filepath.Join(defaultCwd, "testdata", "turbo.json")
cwd, err := CheckedToAbsolutePath(defaultCwd)
if err != nil {
t.Fatalf("cwd is not an absolute directory %v: %v", defaultCwd, err)
}
turboJSONPath := cwd.Join("testdata", "turbo.json")
turboConfig, err := ReadTurboConfigJSON(turboJSONPath)
if err != nil {
t.Fatalf("invalid parse: %#v", err)
Expand Down
64 changes: 64 additions & 0 deletions cli/internal/fs/path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package fs

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
)

// AbsolutePath represents a platform-dependent absolute path on the filesystem,
// and is used to enfore correct path manipulation
type AbsolutePath string

func CheckedToAbsolutePath(s string) (AbsolutePath, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call this SafeAbsolutePath?

if filepath.IsAbs(s) {
return AbsolutePath(s), nil
}
return "", fmt.Errorf("%v is not an absolute path", s)
}

func UnsafeToAbsolutePath(s string) AbsolutePath {
return AbsolutePath(s)
}

func GetCwd() (AbsolutePath, error) {
cwdRaw, err := os.Getwd()
if err != nil {
return "", fmt.Errorf("invalid working directory: %w", err)
}
cwd, err := CheckedToAbsolutePath(cwdRaw)
if err != nil {
return "", fmt.Errorf("cwd is not an absolute path %v: %v", cwdRaw, err)
}
return cwd, nil
}

func (ap AbsolutePath) ToStringDuringMigration() string {
return ap.asString()
}

func (ap AbsolutePath) Join(args ...string) AbsolutePath {
return AbsolutePath(filepath.Join(ap.asString(), filepath.Join(args...)))
}
func (ap AbsolutePath) asString() string {
return string(ap)
}
func (ap AbsolutePath) Dir() AbsolutePath {
return AbsolutePath(filepath.Dir(ap.asString()))
}
func (ap AbsolutePath) MkdirAll() error {
return os.MkdirAll(ap.asString(), DirPermissions)
}
func (ap AbsolutePath) Remove() error {
return os.Remove(ap.asString())
}
func (ap AbsolutePath) Open() (*os.File, error) {
return os.Open(ap.asString())
}
func (ap AbsolutePath) ReadFile() ([]byte, error) {
return ioutil.ReadFile(ap.asString())
}
func (ap AbsolutePath) FileExists() bool {
return FileExists(ap.asString())
}
4 changes: 2 additions & 2 deletions cli/internal/prune/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ type PruneOptions struct {
docker bool
}

func parsePruneArgs(args []string, cwd string) (*PruneOptions, error) {
var options = &PruneOptions{cwd: cwd}
func parsePruneArgs(args []string, cwd fs.AbsolutePath) (*PruneOptions, error) {
var options = &PruneOptions{cwd: cwd.ToStringDuringMigration()}

if len(args) == 0 {
return nil, errors.Errorf("At least one target must be specified.")
Expand Down
4 changes: 2 additions & 2 deletions cli/internal/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,14 +445,14 @@ func getDefaultRunOptions() *RunOptions {
}
}

func parseRunArgs(args []string, cwd string, output cli.Ui) (*RunOptions, error) {
func parseRunArgs(args []string, cwd fs.AbsolutePath, output cli.Ui) (*RunOptions, error) {
var runOptions = getDefaultRunOptions()

if len(args) == 0 {
return nil, errors.Errorf("At least one task must be specified.")
}

runOptions.cwd = cwd
runOptions.cwd = cwd.ToStringDuringMigration()
unresolvedCacheFolder := filepath.FromSlash("./node_modules/.cache/turbo")

if os.Getenv("TURBO_FORCE") == "true" {
Expand Down
32 changes: 16 additions & 16 deletions cli/internal/run/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import (
)

func TestParseConfig(t *testing.T) {
defaultCwd, err := os.Getwd()
defaultCwd, err := fs.GetCwd()
if err != nil {
t.Errorf("failed to get cwd: %v", err)
}
defaultCacheFolder := filepath.Join(defaultCwd, filepath.FromSlash("node_modules/.cache/turbo"))
defaultCacheFolder := defaultCwd.Join(filepath.FromSlash("node_modules/.cache/turbo"))
cases := []struct {
Name string
Args []string
Expand All @@ -39,8 +39,8 @@ func TestParseConfig(t *testing.T) {
cache: true,
forceExecution: false,
profile: "",
cwd: defaultCwd,
cacheFolder: defaultCacheFolder,
cwd: defaultCwd.ToStringDuringMigration(),
cacheFolder: defaultCacheFolder.ToStringDuringMigration(),
cacheHitLogsMode: FullLogs,
cacheMissLogsMode: FullLogs,
},
Expand All @@ -59,8 +59,8 @@ func TestParseConfig(t *testing.T) {
forceExecution: false,
profile: "",
scope: []string{"foo", "blah"},
cwd: defaultCwd,
cacheFolder: defaultCacheFolder,
cwd: defaultCwd.ToStringDuringMigration(),
cacheFolder: defaultCacheFolder.ToStringDuringMigration(),
cacheHitLogsMode: FullLogs,
cacheMissLogsMode: FullLogs,
},
Expand All @@ -78,8 +78,8 @@ func TestParseConfig(t *testing.T) {
cache: true,
forceExecution: false,
profile: "",
cwd: defaultCwd,
cacheFolder: defaultCacheFolder,
cwd: defaultCwd.ToStringDuringMigration(),
cacheFolder: defaultCacheFolder.ToStringDuringMigration(),
cacheHitLogsMode: FullLogs,
cacheMissLogsMode: FullLogs,
},
Expand All @@ -97,8 +97,8 @@ func TestParseConfig(t *testing.T) {
cache: true,
forceExecution: false,
profile: "",
cwd: defaultCwd,
cacheFolder: defaultCacheFolder,
cwd: defaultCwd.ToStringDuringMigration(),
cacheFolder: defaultCacheFolder.ToStringDuringMigration(),
cacheHitLogsMode: FullLogs,
cacheMissLogsMode: FullLogs,
},
Expand All @@ -116,8 +116,8 @@ func TestParseConfig(t *testing.T) {
cache: true,
forceExecution: false,
profile: "",
cwd: defaultCwd,
cacheFolder: defaultCacheFolder,
cwd: defaultCwd.ToStringDuringMigration(),
cacheFolder: defaultCacheFolder.ToStringDuringMigration(),
passThroughArgs: []string{"--boop", "zoop"},
cacheHitLogsMode: FullLogs,
cacheMissLogsMode: FullLogs,
Expand All @@ -136,8 +136,8 @@ func TestParseConfig(t *testing.T) {
cache: true,
forceExecution: false,
profile: "",
cwd: defaultCwd,
cacheFolder: defaultCacheFolder,
cwd: defaultCwd.ToStringDuringMigration(),
cacheFolder: defaultCacheFolder.ToStringDuringMigration(),
passThroughArgs: []string{},
cacheHitLogsMode: FullLogs,
cacheMissLogsMode: FullLogs,
Expand All @@ -153,8 +153,8 @@ func TestParseConfig(t *testing.T) {
bail: true,
concurrency: 10,
cache: true,
cwd: defaultCwd,
cacheFolder: defaultCacheFolder,
cwd: defaultCwd.ToStringDuringMigration(),
cacheFolder: defaultCacheFolder.ToStringDuringMigration(),
cacheHitLogsMode: FullLogs,
cacheMissLogsMode: FullLogs,
},
Expand Down