Skip to content
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

Bugfix - Dir - Windows: Paths not loaded correctly #251

Merged

Conversation

bryphe
Copy link
Contributor

@bryphe bryphe commented May 5, 2020

Issue: @glennsl and I started experimenting with using dir and fp in Onivim 2, in this PR: onivim/oni2#1703 - the API is perfect for us!

However, we hit a difficult-to-troubleshoot crash on startup when we integrated dir, and it wasn't clear what was going wrong - it was crashing before we even ran our CLI parsing or initialized our logging system.

It turned out, there were a couple of problems we hit:

First, there this was this exception:

(Invalid_argument "First token in path C:\\Users\\bryphe is not absolute.")
Raised at file "src/fp/Fp.re", line 220, characters 6-98
Called from file "src/dir/Dir.re", line 117, characters 16-35
Called from file "src/dir/Dir.re", line 187, characters 13-48
Called from file "src/dir/Dir.re", line 341, characters 8-20

This came from Fp, because it doesn't handle the windows back-slashes currently (this is documented limitation, but it's problematic with Dir - because it by default picks up windows-style paths for the directories, and breaks when it uses Fp to manipulate paths on windows).

I fixed this by normalizing the paths prior to sending to Fp (similar to what we do in esy) - however, the best longer-term fix would be to have Fp handle back-slashes too.

After fixing that, there was still a crash, and this time it was a native crash - not from OCaml. It turns out the sh_get_folder_path c stub wasn't actually returning the path string, so the runtime would crash natively when trying to process the Val_unit result as a string. I fixed this by returning a constructed option(string) from the API.

Lastly, I tweaked the API - because the directory construction methods have the possibility of throwing, I changed them to be deferred - it'll construct and give out the paths on request. This is preferable for use case, because we'd like to initialize our logging infra prior to anything that can throw, so if there is an error or exception, we can capture it and drop a crash log.

@facebook-github-bot facebook-github-bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label May 5, 2020
@kyldvs
Copy link
Contributor

kyldvs commented May 5, 2020

This looks great! Thanks for debugging. I'll let @jordwalke take a look before merging since he wrote most of this.

@bryphe
Copy link
Contributor Author

bryphe commented May 6, 2020

Thanks @kyldvs ! Just chatted with @jordwalke - I realized I need to update the dir test cases to pick up the new API. It's also curious why the native crash wasn't manifesting on Windows - I would've expected a crash in Dir.home, so I'll take a look at that too.

@kyldvs
Copy link
Contributor

kyldvs commented May 6, 2020

It's possible windows CI just isn't actually running things, for example our test cmd is a no-op in windows so it always passes, but it will run in bash environments:

https://github.com/facebookexperimental/reason-native/blob/master/scripts/test-ci.cmd

src/dir/Dir.re Outdated Show resolved Hide resolved
@jordwalke
Copy link
Member

The test errors seem unrelated? It looks like refmterr tests behaving differently. Not sure how your changes could have caused that. I'll merge anyways if possible.

src/dir/dir.c Show resolved Hide resolved
@jordwalke
Copy link
Member

Looks like one of the test outputs has "because it is in the condition of an if-statement" in one of the error messages, which doesn't match what is expected, but that was likely added in a new ocaml compiler. I wonder if it's not using the lockfile to install / run tests.

Comment on lines 73 to 77
- script: "esy x TestDev.exe --filter Dir"
displayName: "TEMPORARY: Run subset of tests cross-platform"
# TODO: Fix full test run!
# - script: "esy test"
# displayName: "Test command"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since it looks like there are several other failures that are unrelated - I tweaked the CI to just run a subset of tests that are known-good across all platforms:
image

Wanted to see a green CI run for Dir/Fs/(Fp|Path) on all platforms. But I'm happy to revert this.

I'm not sure that the script is working as intended - it may be simpler to just run the test runner directly, and see if any of the ambient environment variables like REASON_NATIVE_ROOT that are needed could be inferred within the executable, rather than a wrapper script.

Copy link
Member

Choose a reason for hiding this comment

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

Okay thanks - this should unblock the merge and then I'll look into the failures asynchronously.

Copy link
Member

@jordwalke jordwalke May 7, 2020

Choose a reason for hiding this comment

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

Does --filter Dir only run the Dir tests? Is that what you wanted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, they're the only tests I know that work cross-plat at the moment. (It looks like it runs Path, Fs too) - so I was just picking up the subset that works cross-plat. Ideally the next step would be to unblock the remaining tests, so we can remove the --filter and just run esy x TestCI on all platforms as part of the continuous integration builds.

Comment on lines 12 to 17
let normalizePathSeparator = {
let backSlashRegex = Str.regexp("\\\\");
pathStr => pathStr |> Str.global_replace(backSlashRegex, "/");
};

let unresolvedExePath = Fp.absoluteExn(Sys.executable_name |> normalizePathSeparator);
Copy link
Contributor Author

@bryphe bryphe May 6, 2020

Choose a reason for hiding this comment

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

This was also blocked Windows - the same issue that I set up for Dir - when we get a raw-windows-path-with-backslashes, we crash.

It makes me think that, maybe for now, we should update the Fp.absoluteExn API like:

let absoluteExn = (~normalizeBackSlashes=Sys.win32, path) => {
....
};

At least in the mean-time, it would work OK for both Dir and these test cases - and the normalization behavior could be overridden if desired. LMK what you think, @jordwalke

Copy link
Member

Choose a reason for hiding this comment

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

I agree. Though I would be okay with making the complexity of cross platform paths front and center, at the time they parse the string. So that could be something like splitting the path parsing entrypoints into a couple of different named functions that make them acknowledge what they are doing. That is a little annoying, but the point is that once you get things into Paths, you never ever have to think about this stuff again.

let absoluteCurrentPlatformPathExn = (path) => {
....
};
let absolutePlatformPathExn = (~fromPlatform, path) => {
....
};

The second having no default argument. What do you think? Too annoying? These should be seldom used - but maybe in reality, it's not the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems reasonable (although maybe a bit verbose) - but at least this is only needed at 'ingestion' of paths. And if you use Dir - you shouldn't really need to touch these very often (especially if we provide the executingDirectory and currentWorkingDirectory as well somewhere).

The only other issue I see is that right now Fp doesn't have a concept of platform - so we'll just have to bring that over from Dir. But seems OK! I'll give it a shot and see what you think.

@jordwalke
Copy link
Member

I think that this is needed in the esy.json file to make the tests pass. We run them internally with that version and they pass, but the esy.json here doesn't have that. Want to try adding that and seeing if it makes them pass?

  "devDependencies": {
    "ocaml": "~4.7.1"
  }

@bryphe
Copy link
Contributor Author

bryphe commented May 15, 2020

Hey sorry for the slow reply @jordwalke ! Thanks for the tip re: 4.7.1 - I ran on OSX and almost everything passes, except for the refmterr test:

 FAIL  refmterr
  • refmterr › file_SyntaxError

    expect.string(received).toEqual(expected)
    
    Expected value to equal:
      "\027[27m\027[24m\027[2m\027[1m# Unformatted Error Output:\027[27m\027[24m\027[22m
      \027[2m# \027[22m\027[2mFile \"tests/__tests__/refmterr/__fixtures__/file_SyntaxError/file_SyntaxError_7.re\", line 20, characters 22-23:\027[22m
      \027[2m# \027[22m\027[2mError: Syntax error: ')' expected\027[22m
...
    Received:
      "\027[27m\027[24m\027[2m\027[1m# Unformatted Error Output:\027[27m\027[24m\027[22m
      \027[2m# \027[22m\027[2mFile \"tests/__tests__/refmterr/__fixtures__/file_SyntaxError/file_SyntaxError_7.re\", line 20, characters 22-23:\027[22m
      \027[2m# \027[22m\027[2mError: Unclosed \"{\" (opened line 10, column 4)\027[22m
...
    Difference:
      # Unformatted Error Output:
      # File "tests/__tests__/refmterr/__fixtures__/file_SyntaxError/file_SyntaxError_7.re", line 20, characters 22-23:
      # Error: Unclosed "{" (opened line 10, column 4)# Unformatted Error Output:
      # File "tests/__tests__/refmterr/__fixtures__/file_SyntaxError/file_SyntaxError_7.re", line 20, characters 22-23:
      # Error: Syntax error: ')' expected22m

I'll push up the change and the test command w/o the filter and we'll see what happens - maybe it's just an issue on my local machine 🤞

@kyldvs
Copy link
Contributor

kyldvs commented May 16, 2020

@bryphe I recall having issues with this refmterr test when updating things, it might just be a bad test that we can disable.

@bryphe
Copy link
Contributor Author

bryphe commented May 26, 2020

@bryphe I recall having issues with this refmterr test when updating things, it might just be a bad test that we can disable.

Thanks @kyldvs ! I disabled that test on Windows. Linux / macOS are green now.

Looks like, unfortunately, there are still failures on Windows, though (besides the Dir/Fp modules that were fixed in this PR).

@bryphe
Copy link
Contributor Author

bryphe commented May 27, 2020

I just applied the --filter Dir for the Windows test - so we can run the subset that were unblocked here. As a next step - we can start to unblock more and enable the full test suite

Copy link
Member

@jordwalke jordwalke left a comment

Choose a reason for hiding this comment

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

Let's try to remove the dependency on unix/str (at least for fp) so that fp can work as a compile-to-js path library as well.

@jordwalke jordwalke merged commit aec0ac6 into reasonml:master Feb 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Do not delete this pull request or issue due to inactivity.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants