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

Add back support for file:... dependencies #854

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 5 commits into from
Mar 9, 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
22 changes: 18 additions & 4 deletions cli/internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,28 @@ func isProtocolExternal(protocol string) bool {
return protocol != "" && protocol != "npm"
}

func isWorkspaceReference(packageVersion string, dependencyVersion string) bool {
func isWorkspaceReference(packageVersion string, dependencyVersion string, cwd string, rootpath string) bool {
protocol, dependencyVersion := parseDependencyProtocol(dependencyVersion)

if protocol == "workspace" {
// TODO: Since support at the moment is non-existent for workspaces that contain multiple
// versions of the same package name, just assume its a match and don't check the range
// for an exact match.
return true
} else if protocol == "file" {
abs, err := filepath.Abs(filepath.Join(cwd, dependencyVersion))
if err != nil {
// Default to internal if we have the package but somehow cannot get the path
// TODO(gsoltis): log this?
return true
}
isWithinRepo, err := fs.DirContainsPath(rootpath, filepath.FromSlash(abs))
if err != nil {
// Default to internal if we have the package but somehow cannot get the path
// TODO(gsoltis): log this?
return true
}
return isWithinRepo
} else if isProtocolExternal(protocol) {
// Other protocols are assumed to be external references ("github:", "link:", "file:" etc)
return false
Expand Down Expand Up @@ -203,7 +217,7 @@ func WithGraph(rootpath string, config *config.Config) Option {
for _, pkg := range c.PackageInfos {
pkg := pkg
populateGraphWaitGroup.Go(func() error {
return c.populateTopologicGraphForPackageJson(pkg)
return c.populateTopologicGraphForPackageJson(pkg, rootpath)
})
packageDepsHashGroup.Go(func() error {
return c.loadPackageDepsHash(pkg)
Expand Down Expand Up @@ -305,7 +319,7 @@ func (c *Context) resolveWorkspaceRootDeps(rootPackageJSON *fs.PackageJSON) erro
return nil
}

func (c *Context) populateTopologicGraphForPackageJson(pkg *fs.PackageJSON) error {
func (c *Context) populateTopologicGraphForPackageJson(pkg *fs.PackageJSON, rootpath string) error {
c.mutex.Lock()
defer c.mutex.Unlock()
depMap := make(map[string]string)
Expand All @@ -328,7 +342,7 @@ func (c *Context) populateTopologicGraphForPackageJson(pkg *fs.PackageJSON) erro

// split out internal vs. external deps
for depName, depVersion := range depMap {
if item, ok := c.PackageInfos[depName]; ok && isWorkspaceReference(item.Version, depVersion) {
if item, ok := c.PackageInfos[depName]; ok && isWorkspaceReference(item.Version, depVersion, pkg.Dir, rootpath) {
internalDepsSet.Add(depName)
c.TopologicalGraph.Connect(dag.BasicEdge(pkg.Name, depName))
} else {
Expand Down
25 changes: 23 additions & 2 deletions cli/internal/context/context_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package context

import (
"path/filepath"
"reflect"
"testing"
)
Expand All @@ -26,6 +27,14 @@ func Test_getHashableTurboEnvVarsFromOs(t *testing.T) {
}

func Test_isWorkspaceReference(t *testing.T) {
rootpath, err := filepath.Abs(filepath.FromSlash("/some/repo"))
if err != nil {
t.Fatalf("failed to create absolute root path %v", err)
}
pkgDir, err := filepath.Abs(filepath.FromSlash("/some/repo/packages/libA"))
if err != nil {
t.Fatalf("failed to create absolute pkgDir %v", err)
}
tests := []struct {
name string
packageVersion string
Expand Down Expand Up @@ -92,13 +101,25 @@ func Test_isWorkspaceReference(t *testing.T) {
dependencyVersion: "sometag",
want: true, // for backwards compatability with the code before versions were verified
},
{
name: "handles file:... inside repo",
packageVersion: "1.2.3",
dependencyVersion: "file:../libB",
want: true, // this is a sibling package
},
{
name: "handles file:... outside repo",
packageVersion: "1.2.3",
dependencyVersion: "file:../../../otherproject",
want: false, // this is not within the repo root
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isWorkspaceReference(tt.packageVersion, tt.dependencyVersion)
got := isWorkspaceReference(tt.packageVersion, tt.dependencyVersion, pkgDir, rootpath)
if got != tt.want {
t.Errorf("isWorkspaceReference() got = %v, want %v", got, tt.want)
t.Errorf("isWorkspaceReference(%v, %v, %v, %v) got = %v, want %v", tt.packageVersion, tt.dependencyVersion, pkgDir, rootpath, got, tt.want)
}
})
}
Expand Down
18 changes: 18 additions & 0 deletions cli/internal/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os"
"path/filepath"
"strings"
)

// https://github.com/thought-machine/please/blob/master/src/fs/fs.go
Expand All @@ -30,6 +31,23 @@ func EnsureDir(filename string) error {
return err
}

var nonRelativeSentinel string = ".." + string(filepath.Separator)

// DirContainsPath returns true if the path 'target' is contained within 'dir'
// Expects both paths to be absolute and does not verify that either path exists.
func DirContainsPath(dir string, target string) (bool, error) {
// In Go, filepath.Rel can return a path that starts with "../" or equivalent.
// Checking filesystem-level contains can get extremely complicated
// (see https://github.com/golang/dep/blob/f13583b555deaa6742f141a9c1185af947720d60/internal/fs/fs.go#L33)
// As a compromise, rely on the stdlib to generate a relative path and then check
// if the first step is "../".
rel, err := filepath.Rel(dir, target)
if err != nil {
return false, err
}
return !strings.HasPrefix(rel, nonRelativeSentinel), nil
}

// PathExists returns true if the given path exists, as a file or a directory.
func PathExists(filename string) bool {
_, err := os.Lstat(filename)
Expand Down
60 changes: 60 additions & 0 deletions cli/internal/fs/fs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package fs

import (
"path/filepath"
"testing"
)

func Test_DirContainsPath(t *testing.T) {
parent, err := filepath.Abs(filepath.Join("some", "path"))
if err != nil {
t.Fatalf("failed to construct parent path %v", err)
}
testcases := []struct {
target []string
want bool
}{
{
[]string{"..", "elsewhere"},
false,
},
{
[]string{"sibling"},
false,
},
{
// The same path as parent
[]string{"some", "path"},
true,
},
{
[]string{"some", "path", "..", "path", "inside", "parent"},
true,
},
{
[]string{"some", "path", "inside", "..", "inside", "parent"},
true,
},
{
[]string{"some", "path", "inside", "..", "..", "outside", "parent"},
false,
},
{
[]string{"some", "pathprefix"},
false,
},
}
for _, tc := range testcases {
target, err := filepath.Abs(filepath.Join(tc.target...))
if err != nil {
t.Fatalf("failed to construct path for %v: %v", tc.target, err)
}
got, err := DirContainsPath(parent, target)
if err != nil {
t.Fatalf("failed to check ")
}
if got != tc.want {
t.Errorf("DirContainsPath(%v, %v) got %v, want %v", parent, target, got, tc.want)
}
}
}