chipsenkbeil / typed-path

Provides typed variants of Path and PathBuf for Unix and Windows
38 stars 6 forks source link

Support absolutizing paths #8

Closed cbgbt closed 1 year ago

cbgbt commented 1 year ago

I'm interested in absolutizing paths in a platform-agnostic way. For our project, we have been using path-absolutize to support absolutizing paths in URIs on unix systems; which works great. We'd like to support that behavior on Windows, but cannot use std::path.

I opened a similar issue in the path-absolutize repository, https://github.com/magiclen/path-absolutize/issues/15.

I'm not sure if the best way forward would be to provide implementations of the Absolutize trait here behind a feature flag, or to implement the trait on these types in path-absolutize. For now I am considering implementing the trait on a newtype to solve the problem.

chipsenkbeil commented 1 year ago

I'm not opposed to implementing a method to do this within this crate. You're also welcome to incorporate this crate into path-absolutize and use the encoding to denote which way to approach making an absolute path.

If you want to add it here, feel free to create a PR and I'll review it.

chipsenkbeil commented 1 year ago

@cbgbt I've added a PR myself to add a normalize method, which almost does what you want for the absolutize method, but in the case of a relative path it does not prepend the path with the std::env::current_dir. I'm assuming that's functionality you would like as well?

cbgbt commented 1 year ago

Wow, that was super fast, thank you! I'll take a look.

In my case, I was looking to absolutize_from a reference path. Here's my hacked up version that I've been iterating on where I butchered the Absolutize trait and applied it to UnixPath specifically.

chipsenkbeil commented 1 year ago

Okay, the challenge remaining here is

  1. Getting the current working directory into a typed path. You can fairly easily do this with NativePathBuf or Utf8NativePathBuf.
  2. Converting the native type into your desired encoding. This is a bit trickier. The naive thing to do is get the components of the path, convert them into the components of the other encoding, and then build up a. new path. Problem is if you go from Windows to Unix and Windows has a prefix like C:, there is no equivalent component. Do you drop it?

I was fiddling with an absolutize equivalent after writing up a utility module that gets the current working directory as a typed path:

pub fn absolutize(&self) -> io::Result<Utf8PathBuf<T>> {
    let path = self.normalize();

    if path.is_absolute() {
        Ok(path)
    } else {
        // Get the cwd as a native path
        let cwd = typed_path::utils::utf8_current_dir()?;

        // Convert native path to this encoding
        let cwd: Utf8PathBuf<T> = todo!();

        Ok(cwd.join(path))
    }
}

Not sure how I want to tackle the conversion between encodings yet. I think dropping the prefix would make sense, just got to have a way to support converting an encoding to itself without losing extra components like the prefix.

cbgbt commented 1 year ago

I'm still catching up, so excuse me if I've missed something! I'm also realizing that my specific use-case is even more simple, I had just gotten a bit wrapped up in the general solution. I think normalize basically solves my problem.

In my case, I'm always absolutizing from a known path which is already encoded correctly (specifically, from /, heh). I'm pretty sure this means I can just Utf8Path::new("/").join(path).normalize(), and in the general case if cwd is known and doesn't need to be discovered and bring on the difficulty of correcting the encoding, that same algorithm will work (properly_encoded_cwd.join(path).normalize())

chipsenkbeil commented 1 year ago

Yeah, if you already have a prefix to use that is properly encoded, you're good to go. I've got a half-finished bit of code to support converting encodings.

If you're up for it, try pointing to the git commit of this crate to see if normalize will work as you'd expect. If so, I can get a release out in the next day or two.

[dependencies]
typed-path = { git = "https://github.com/chipsenkbeil/typed-path.git", rev = "14a7ec1249e76f179be6436a135a2f2132cfd681" }
chipsenkbeil commented 1 year ago

I've also merged in a potential implementation of absolutize and to_encoding alongside the ability to retrieve the current working directory as a native encoding.

Like above, you can point the dependency to the repository (with a newer commit) to test this out. If it suites your needs, I'll release 0.4.0 of the crate.

cbgbt commented 1 year ago

Just finished running normalize() through CI on Linux and Windows, everything passes! Given that we aren't using cwd here, I don't think I have a route to run absolutize through the same tests, but I'll let you know if I think of a way to help test here.

I'm extremely grateful for your effort here. Thank you!

chipsenkbeil commented 1 year ago

Cool. Version 0.4.0 has been published to crates.io and tagged in this repository. Going to close this out.