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

Path casts #2077

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 6 commits into from
Sep 27, 2022
Merged

Path casts #2077

merged 6 commits into from
Sep 27, 2022

Conversation

nathanhammond
Copy link
Contributor

@nathanhammond nathanhammond commented Sep 26, 2022

@gsoltis (correctly! as proven by this PR) has a vendetta against casts.

This PR removes most casts to turbopath.* in the repository with explicit exceptions for strings and t.TempDir().

The regex used to identify casts, of which, 100% have been manually reviewed:
turbopath\.(Absolute|Anchored|Relative)(Unix|System)Path\(

Of the remaining 13 that do not fall into the above "string" or t.TempDir() exceptions, 7 fall outside of the fs package:
turbopath\.(Absolute|Anchored|Relative)(Unix|System)Path\((?!("|t\.TempDir))

7 results - 4 files

cli/internal/cache/cache_http.go:
  280  		// FIXME: THIS IS A BUG.
  281: 		restoredName := turbopath.AnchoredUnixPath(hdr.Name)
  282  		files = append(files, restoredName.ToSystemPath())

cli/internal/hashing/package_deps_hash_test.go:
  20  	cwd, _ := os.Getwd()
  21: 	root := turbopath.AbsoluteSystemPath(filepath.VolumeName(cwd) + string(os.PathSeparator))
  22: 	checking := turbopath.AbsoluteSystemPath(cwd)
  23  

  32  			for _, file := range files {
  33: 				fileName := turbopath.RelativeSystemPath(file.Name())
  34  				if strings.Index(fileName.ToString(), fmt.Sprintf("%02d-", id)) == 0 {
  35: 					return turbopath.AbsoluteSystemPath(fixtureDirectory.Join(fileName))
  36  				}

cli/internal/lockfile/berry_lockfile.go:
  305  		if isPatch && !strings.HasPrefix(patchPath, "~") && !_builtinRegexp.MatchString(patchPath) {
  306: 			patches = append(patches, turbopath.AnchoredUnixPath(patchPath))
  307  		}

cli/internal/lockfile/pnpm_lockfile.go:
  251  	for _, patch := range p.PatchedDependencies {
  252: 		patches[i] = turbopath.AnchoredUnixPath(patch.Path)
  253  		i++

Of these 7:

  • One is a bug resolved by cache-to-tar.
  • Four are in a single test utility function. That should get cleaned up but is very low priority.
  • Two are in application code for berry and pnpm patches. I'll pass that off to @chris-olszewski since I'm not 100% certain that I can safely slap turbopath.AnchoredUnixPathFromUpstream() on them.

@vercel
Copy link

vercel bot commented Sep 26, 2022

@nathanhammond is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor Author

@nathanhammond nathanhammond left a comment

Choose a reason for hiding this comment

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

Notes to reviewers.

turbopath.AnchoredSystemPath(filepath.Join("..", "root.json")),
turbopath.AnchoredSystemPath("child.json"),
turbopath.AnchoredSystemPath(filepath.Join("grandchild", "grandchild.json")),
turbopath.AnchoredUnixPath("../root.json").ToSystemPath(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This actually breaks one of the rules intended to exist for Anchored(System|Unix)Paths: that they're io/fs safe. I'm not going to address this now because it's an issue with our entire hashing story.

packageJSONs := make(map[interface{}]*fs.PackageJSON)
graph := &dag.AcyclicGraph{}
graph.Add("@foo/bar")
packageJSONs["@foo/bar"] = &fs.PackageJSON{
Name: "@foo/bar",
Dir: turbopath.AnchoredSystemPath(filepath.Join(root, "packages", "bar")),
Dir: rootPath.UntypedJoin("packages", "bar"),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is actually a problem; we're alternately supplying this with Anchored and Absolute paths. We still need to address this (which is why this PR presently is in Draft).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I've confirmed that this is definitely supposed to be a Anchored 100% of the time: https://github.com/vercel/turborepo/blob/main/cli/internal/run/run.go#L906

I'm changing all instances of this to match.

@@ -57,28 +57,28 @@ func TestResolvePackages(t *testing.T) {
graph.Connect(dag.BasicEdge("app2-a", "libC"))
packagesInfos := map[interface{}]*fs.PackageJSON{
"app0": {
Dir: turbopath.AnchoredSystemPath(filepath.FromSlash("app/app0")),
Dir: turbopath.AnchoredUnixPath("app/app0").ToSystemPath(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should be our preferred pattern for creating AnchoredSystemPaths in tests: use AnchoredUnixPath and then convert it to an AnchoredSystemPath.

Copy link
Member

Choose a reason for hiding this comment

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

Do we want a SystemPathFromUnixString to avoid forgetful devs (me) from trying to directly create a system path from a string with unix separators?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I want to write a linter that checks for \ in strings passed to Unix, and either of \ or / in strings passed to System. Creating a function will not prevent us from making mistakes as we have seen multiple clever ways of accidentally failing this in just my last two PRs.

Problem: low priority.

TURBO-336

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(On numerous occasions we have failed to satisfy the XTypeFromYSource constraint, so we should stop relying on fallible humans to do the right thing.)

Comment on lines -94 to -95
prefix := pkgName + "/"
prefixLen := len(prefix)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test was accidentally platform dependent, but the upstream code appears to have gracefully handled the garbage in.

if err != nil {
t.Fatalf("failed to calculate manual hashes: %v", err)
}
for path, spec := range files {
if strings.HasPrefix(path.ToString(), prefix.ToString()) {
if path.ToSystemPath().HasPrefix(pkgName) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was previously comparing an AnchoredUnixPath and an AnchoredSystemPath. 🤦‍♂️

So now we have a utility function to stop doing that.

@vercel
Copy link

vercel bot commented Sep 26, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
turbo-site ✅ Ready (Inspect) Visit Preview Sep 27, 2022 at 7:12AM (UTC)

@chris-olszewski
Copy link
Member

Both of the exceptions in the lockfile files will be fixed up when I properly add patch support to Yarn 2+ and revamp the pnpm patch support. I'm pretty sure AnchoredUnixPathFromUpstream will be the correct answer, but I'll go through the each package manager and verify.


// otherPath is definitely shorter than p.
// We need to confirm that p[len(otherPath)] is a system separator.
return os.IsPathSeparator(p[prefixLen])
Copy link
Member

Choose a reason for hiding this comment

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

Won't this return true for "foo/bar".HasPrefix("baz/") or for any prefix that has a length that happens to line up with a path separator?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup. Totally missed a step here.

@chris-olszewski chris-olszewski added the pr: fixship A PR which is approved with notes and does not require re-review. label Sep 26, 2022
Copy link
Member

@chris-olszewski chris-olszewski left a comment

Choose a reason for hiding this comment

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

Only thing I think needs to get fixed is the implementation of HasPrefix

@@ -25,9 +25,9 @@ func (p AnchoredUnixPath) ToUnixPath() AnchoredUnixPath {
}

// RelativeTo calculates the relative path between two `AnchoredUnixPath`s.
func (p AnchoredUnixPath) RelativeTo(basePath AnchoredUnixPath) (AnchoredUnixPath, error) {
func (p AnchoredUnixPath) RelativeTo(basePath AnchoredUnixPath) (AnchoredSystemPath, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the callsites immediately convert to AnchoredUnixPath. Maybe this function should do that, rather than change types?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The correct answer here is actually to avoid triggering FromSlash or ToSlash as those calls are cross-platform unsafe. It's usually not a problem because most people on POSIX systems don't create file names like this\is\going\to\go\badly.txt but it's an unfortunate edge case.

I want to actually fix this, but it's not something I can justify doing in our current world.

In the mean time I'm going to drop this function and address the call sites with string manipulation.

@nathanhammond nathanhammond added pr: automerge Kodiak will merge these automatically after checks pass and removed pr: fixship A PR which is approved with notes and does not require re-review. labels Sep 27, 2022
@kodiakhq kodiakhq bot merged commit f3f6aee into vercel:main Sep 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: automerge Kodiak will merge these automatically after checks pass
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants