Getting the absolute path from a PathBuf

Solution 1:

Rust 1.5.0 added std::fs::canonicalize, which sounds pretty close to what you want:

Returns the canonical form of a path with all intermediate components normalized and symbolic links resolved.

Note that, unlike the accepted answer, this removes the ./ from the returned path.


A simple example from my machine:

use std::fs;
use std::path::PathBuf;

fn main() {
    let srcdir = PathBuf::from("./src");
    println!("{:?}", fs::canonicalize(&srcdir));

    let solardir = PathBuf::from("./../solarized/.");
    println!("{:?}", fs::canonicalize(&solardir));
}
Ok("/Users/alexwlchan/Developer/so-example/src")
Ok("/Users/alexwlchan/Developer/solarized")

Solution 2:

You can do this quite nicely using the path-clean crate and std::env::current_dir. The benefit of this method over the other answers is that it resolves . and .. and it works even when the path doesn't exist.

use std::env;
use std::io;
use std::path::{PathBuf, Path};

use path_clean::PathClean;

pub fn absolute_path(path: impl AsRef<Path>) -> io::Result<PathBuf> {
    let path = path.as_ref();

    let absolute_path = if path.is_absolute() {
        path.to_path_buf()
    } else {
        env::current_dir()?.join(path)
    }.clean();

    Ok(absolute_path)
}

Solution 3:

If I understand the PathBuf documentation correctly it does not treat "./" as a special start to a path that says its relative.

You can however turn a relative path into an absolute one with std::env::current_dir:

let relative_path = PathBuf::from("cargo_home");
let mut absolute_path = try!(std::env::current_dir());
absolute_path.push(relative_path)

This assumes that your relative path is relative to your current directory.

Solution 4:

There is https://crates.io/crates/path-absolutize now, for handling non-existent paths.