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

refactor: use Url in deno dir #2572

Merged

Conversation

bartlomieju
Copy link
Member

Follow-up to #2559 (and blocked by it)

Use Url instead of String for specifiers in //cli/deno_dir.rs

cli/deno_dir.rs Outdated Show resolved Hide resolved
@bartlomieju bartlomieju force-pushed the refactor-use_url_in_deno_dir branch 6 times, most recently from b23c971 to d52d870 Compare June 23, 2019 22:03
@bartlomieju
Copy link
Member Author

Note to self: our current resolving of paths (including ModuleSpecifier::resolve_root) is not 100% correct.

These specifiers are not resolved properly on windows:

// 1.
C:\deno\tests\006_url_imports.ts 
// result URL 
C:\\deno\\tests\\006_url_imports.ts
// expected URL
file:///C:/deno/tests/006_url_imports.ts

// this one fails completely
\deno\tests\006_url_imports.ts

Consider using NormalizedPath instead of Path that leverages normalize_path from deno_dir.rs - this will ensure that all paths passed around our code base use / (forward slash) instead of mixing forward and backward slashes. This is fine, because fs module can handle forward slashes on Windows.

@bartlomieju
Copy link
Member Author

Rebased on top of #2581

@bartlomieju bartlomieju force-pushed the refactor-use_url_in_deno_dir branch 2 times, most recently from 3367275 to 2f063ec Compare June 28, 2019 21:12
cli/deno_dir.rs Outdated Show resolved Hide resolved
@bartlomieju
Copy link
Member Author

@ry @kitsonk please review - this PR is meant to replace use of &str in favor of &Url in DenoDir. There are still some places where this should be changed (eg. ModuleMetaData uses module_name which has String type that is actually Url casted to string), but this PR is quite complex and touching crucial stuff already.

During work on this PR I've got pretty good idea how to rewrite DenoDir, but I'll write up my thoughts in appropriate issue. @kitsonk I'd very much would like to help you out during rewrite of you'd want.

@bartlomieju bartlomieju changed the title WIP refactor: use Url in deno dir refactor: use Url in deno dir Jun 29, 2019
cli/deno_dir.rs Outdated Show resolved Hide resolved
cli/deno_dir.rs Outdated Show resolved Hide resolved
match self.fetch_module_meta_data(script_name, true, true) {
// TODO: this method shouldn't issue `fetch_module_meta_data` - this is done for each line
// in JS stack trace so it's pretty slow - quick idea: store `ModuleMetaData` in one
// structure available to DenoDir so it's not fetched from disk everytime it's needed
Copy link
Member

Choose a reason for hiding this comment

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

👍

cli/deno_dir.rs Outdated Show resolved Hide resolved
@ry
Copy link
Member

ry commented Jun 29, 2019

@bartlomieju This is a great patch and it looks good except for a few nits

During work on this PR I've got pretty good idea how to rewrite DenoDir, but I'll write up my thoughts in appropriate issue

Great. I look forward to it.

cli/deno_dir.rs Outdated Show resolved Hide resolved
core/module_specifier.rs Outdated Show resolved Hide resolved
@bartlomieju
Copy link
Member Author

@piscisaureus I merged latest master

UnsupportedPathPrefix => write!(
f,
r"invalid path prefix, must be disk prefix (eg. C:/, C:\\)"
),
Copy link
Member Author

@bartlomieju bartlomieju Jun 30, 2019

Choose a reason for hiding this comment

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

Messages for these two variants should print out specifier and path respectively.

ImportPathPrefixMissing(ref specifier) => {
  write!(f, "Invalid import path: \"{}\". Relative import must be prefixed with / or ./ or ../", specifier.to_str().unwrap())
}
UnsupportedPathPrefix(ref path) => {
  write!(
    f,
    "Unsupported path prefix: \"{}\". Must be disk prefix (eg. C:/, C:\\\\)",
    path.to_str().unwrap()
  )
},

Trying to figure it out, but neither String nor PathBuf implement Copy trait... 🤔

@ry
Copy link
Member

ry commented Jul 1, 2019

LGTM from me.

@piscisaureus - approve and land when you're satisfied.

@piscisaureus
Copy link
Member

Still waiting for my windows machine. ETA now: tomorrow. Hang in there.

@bartlomieju
Copy link
Member Author

@piscisaureus any update?

@piscisaureus
Copy link
Member

I'm actually not so happy with the logic that decides whether a command-line argument is a path or a URL.
Especially since this requires encoding a lot of knowledge about windows path formats, and the heuristic that's uses is complex and hard to describe.

What I would suggest is the following

  • If the argument starts with something that looks like the 'scheme' part of a URL (it matches /^[a-z][a-z+-\.]+:/i`), treat it as a URL.
  • Otherwise, treat it as a path; make it absolute first then convert to a file URL.

With that you can remove all windows-specific path handling and let rust-std deal with it, which seems to do it well.

@bartlomieju
Copy link
Member Author

What I would suggest is the following

  • If the argument starts with something that looks like the 'scheme' part of a URL (it matches /^[a-z][a-z+-\.]+:/i`), treat it as a URL.
  • Otherwise, treat it as a path; make it absolute first then convert to a file URL.

With that you can remove all windows-specific path handling and let rust-std deal with it, which seems to do it well.

@piscisaureus that is exactly what happens at the moment. The only Windows-specific thing is ensure_valid_prefix which allows only disk prefixes that you suggested.

@piscisaureus
Copy link
Member

Sorry, but it's really not right. Take this change for example:

  /// Resolves module using this algorithm:
  /// https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier
  pub fn resolve(
    specifier: &str,
    base: &str,
  ) -> Result<ModuleSpecifier, ModuleResolutionError> {
    use ModuleResolutionError::*;

    // 1. Apply the URL parser to specifier. If the result is not failure, return
    //    the result.
    if let Ok(module_specifier) = ModuleSpecifier::resolve_absolute(specifier) {
      return Ok(module_specifier);
    }

    ...
}

ModuleSpecifier::resolve_absolute will first try to interpret the specifier as a path, and then fall back to parsing it as a URL only if that fails.
That's in direct contradiction of the spec.

@piscisaureus
Copy link
Member

I'll try to pump out a patch tonight that does it correctly.

@piscisaureus piscisaureus force-pushed the refactor-use_url_in_deno_dir branch 9 times, most recently from 562e61d to d034ff4 Compare July 8, 2019 09:10
/// We additionally require the scheme to be at least 2 characters long,
/// because otherwise a windows path like c:/foo would be treated as a URL,
/// while no schemes with a one-letter name actually exist.
fn specifier_has_uri_scheme(specifier: &str) -> bool {
Copy link
Member Author

Choose a reason for hiding this comment

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

I was gonna argue that trying path first before parsing URL was to handle Windows path prefixed with disk, but as always your solution is much more elegant 👍 kudos @piscisaureus

@piscisaureus piscisaureus force-pushed the refactor-use_url_in_deno_dir branch from d034ff4 to d0447c6 Compare July 8, 2019 09:48
@piscisaureus
Copy link
Member

piscisaureus commented Jul 8, 2019

@ry, @bartlomieju
I re-did the changes to the ModuleSpecifier resolution logic. PTAL at 9b1997b.
If that's alright with you guys then I think we can land this PR.

@piscisaureus piscisaureus force-pushed the refactor-use_url_in_deno_dir branch from dd42e3f to d0447c6 Compare July 8, 2019 10:29
piscisaureus and others added 2 commits July 8, 2019 13:07
The rules are now as follows:

* In `import` statements, as mandated by the WHATWG specification,
  the import specifier is always treated as a URL.
  If it is a relative URL, it must start with either / or ./ or ../

* A script name passed to deno as a command line argument may be either
  an absolute URL or a local path.
  - If the name starts with a valid URI scheme followed by a colon, e.g.
    'http:', 'https:', 'file:', 'foo+bar:', it always interpreted as a
    URL (even if Deno doesn't support the indicated protocol).
  - Otherwise, the script name is interpreted as a local path. The local
    path may be relative, and operating system semantics determine how
    it is resolved. Prefixing a relative path with ./ is not required.
@piscisaureus piscisaureus force-pushed the refactor-use_url_in_deno_dir branch from d0447c6 to 72d9045 Compare July 8, 2019 11:07
"file:///home/yeti/deno",
"file://server/some/dir/file",
),
// This test is disabled because the url crate does not follow the spec,
Copy link
Member

Choose a reason for hiding this comment

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

@bartlomieju
Copy link
Member Author

@piscisaureus LGTM. I like your solution to ModuleSpecifier 👍

@piscisaureus piscisaureus merged commit 72d9045 into denoland:master Jul 8, 2019
@bartlomieju bartlomieju deleted the refactor-use_url_in_deno_dir branch July 8, 2019 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants