Skip to main content

polars_io/utils/
mkdir.rs

1use std::io;
2use std::path::{Path, PathBuf};
3
4use polars_error::PolarsResult;
5use polars_utils::io::_limit_path_len_io_err;
6use polars_utils::pl_path::PlRefPath;
7
8use crate::path_utils::resolve_homedir;
9
10/// Creates the directory `path` will be written into.
11///
12/// Does nothing for paths with a scheme; object stores have no directories to create.
13pub fn mkdir_recursive(path: &PlRefPath) -> PolarsResult<()> {
14    let Some(parent) = writable_parent(path)? else {
15        return Ok(());
16    };
17
18    std::fs::DirBuilder::new()
19        .recursive(true)
20        .create(&parent)
21        .map_err(|err| _limit_path_len_io_err(&parent, err))
22}
23
24/// Async counterpart of [`mkdir_recursive`].
25pub async fn tokio_mkdir_recursive(path: &PlRefPath) -> PolarsResult<()> {
26    let Some(parent) = writable_parent(path)? else {
27        return Ok(());
28    };
29
30    tokio::fs::DirBuilder::new()
31        .recursive(true)
32        .create(&parent)
33        .await
34        .map_err(|err| _limit_path_len_io_err(&parent, err))
35}
36
37/// The local directory that must exist before `path` can be opened for writing, or `None`
38/// when there is nothing to create.
39fn writable_parent(path: &PlRefPath) -> PolarsResult<Option<PathBuf>> {
40    if path.has_scheme() {
41        return Ok(None);
42    }
43
44    let Some(parent) = path.parent() else {
45        return Err(io::Error::other(format!("path is not a file: {path}")).into());
46    };
47
48    // A path with a single component has no directory to create.
49    if parent.is_empty() {
50        return Ok(None);
51    }
52
53    Ok(Some(resolve_homedir(Path::new(parent)).into_owned()))
54}