Append an additional extension?

Let's say I have a Path: foo.bar, and I'd like to append an extension baz to get: foo.bar.baz. Right now there seem to be no easy way to do it.

2 Likes

Remember that Path is analogous to str and that PathBuf is likewise analogous to String, and you can build on it.

1 Like

How? I can't format! or append_str to a PathBuf. Everything is working on component level, plus couple of methods for extension and file stem. Am I missing something?

2 Likes

Well, if you want it in your format, then you can push and then replace on a .to_string call to replace / with .. I'm on mobile so I can't add a playground example

1 Like

No. I want a PathBuf. I need to rename a directory to a ${original_dir}.tmp, but the original_dir might already have dots in it.

1 Like

Why not try the following:

  1. Get the last component in path_buf.components() and cast it's as_os_str to an owned string
  2. Add what you want to it
  3. Call pop on path_buf
  4. Push your new string onto your path_buf

This is missing a check to make sure that it is a directory, so be sure that it either is, or run some checks on user input
Edit: it's actually abit more complicated than that because it doesn't go straight to String and instead its os variant, so that's something to keep in mind

Yeah, so I have something like this, but it's terribly clunky. I'm surprised that stdlib provided methods to replace the extension, but not append, which is usually what I would actually like (eg. for tmp files etc)

2 Likes

Oh, what about a cleaner way where you call into_os_string on the pathbuf and just append and form a new pathbuf?
I know that this isn't very non-clunky but I can't figure out another way without some better context

How do you append to OsString without converting to Vec<u8>?

You can push as better exemplified by the examples on the docs

1 Like

I've totally missed it. Thank you!

1 Like

Hi all,

I'm reviving this thread. There's a set_extension which replaces an extension but no add_extension .

For example:

    use std::path::PathBuf;

    let mut path = PathBuf::new();

    path.push("/var/log");
    path.push("kern.log");
    path.set_extension("gz");

    println!("{:?}", path);

prints out /var/log/kern.gz and not /var/log/kern.log.gz . Any clue ?

Thanks for your help.

I don't believe there's a function for it in std. How about this?

fn add_extension(path: &mut std::path::PathBuf, extension: impl AsRef<std::path::Path>) {
    match path.extension() {
        Some(ext) => {
            let mut ext = ext.to_os_string();
            ext.push(".");
            ext.push(extension.as_ref());
            path.set_extension(ext)
        }
        None => path.set_extension(extension.as_ref()),
    };
}

fn main() {
    let mut path = std::path::PathBuf::from("/var/log/kern.log");
    add_extension(&mut path, "gz");
    assert_eq!(path.as_os_str(), "/var/log/kern.log.gz");
}

If you only need to do it once, or you know for sure the path has an extension, you can do it without a function or in fewer lines.

4 Likes

@Heliozoa Thanks for your contribution.

I'm a little bit reluctant to move to strings, but if this is the only way I'll make it.

BTW, is this add_extension an opportunity for a PR ?

1 Like

As long as it's encapsulated in a function there shouldn't be any problem. A PathBuf is just a newtype wrapper around OsString which gives us methods specific to file paths, and the standard library deliberately exposes From<OsString> and Into<OsString> as an escape hatch for exactly these situations where the provided functionality is missing something.

Yep. I'd create an issue first to gauge interest, probably including a potential implementation, and iron out the edge cases (e.g. what happens if the path is empty, or if it's just pointing to the C: drive?).

1 Like

Reviving the thread again.
I went ahead to the issues tracker, but as of time of writing it recommends to start a discussion first, so I did: PathBuf has set_extension but no add_extension. Cannot cleanly turn .tar to .tar.gz - libs - Rust Internals

3 Likes

Reviving this thread again.

The lack of appropriate stdlib function has caused a bug for us so there's very much a need for add_extension or push_extension. It's causing real headaches.

There's now been quite a popular discussion with 1.6k views - which has unfortunately been closed due to being stale. What's the next step?

2 Likes

Make a pull request that adds the method.

It's a trivial change, so there's no need to go through the full RFC process or anything complex. From there, whoever is triaging your PR will be able to help you get it into nightly/stable.

4 Likes

This topic was automatically closed 30 days after the last reply. We invite you to open a new topic if you have further questions or comments.