Skip to content

Commit 1358a56

Browse files
feat: Convert to camino and camino-tempfile (#9)
1 parent 7762b5b commit 1358a56

File tree

18 files changed

+149
-95
lines changed

18 files changed

+149
-95
lines changed

Cargo.lock

Lines changed: 25 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ members = [
33
"bin/icp-cli",
44
"lib/icp-identity",
55
"lib/icp-network",
6-
"lib/icp-fs"
6+
"lib/icp-fs",
77
]
88

99
resolver = "3"
1010

1111
[workspace.dependencies]
12+
camino = { version = "1.1.9", features = ["serde1"] }
1213
candid = "0.10.14"
1314
fd-lock = "4.0.4"
1415
hex = "0.4.3"

bin/icp-cli/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ name = "icp"
99
path = "src/main.rs"
1010

1111
[dependencies]
12+
camino = { workspace = true }
1213
clap = { version = "4.5.35", features = ["derive"] }
1314
icp-network = { path = "../../lib/icp-network" }
1415
icp-fs = { path = "../../lib/icp-fs" }
@@ -19,4 +20,4 @@ tokio = { workspace = true }
1920
assert_cmd = "2"
2021
predicates = "3"
2122
reqwest = { workspace = true }
22-
tempfile = "3"
23+
camino-tempfile = "1"

bin/icp-cli/src/commands/network/run.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
use crate::commands::network::run::RunNetworkCommandError::ProjectNotFound;
21
use crate::project::directory::ProjectDirectory;
2+
use crate::{
3+
commands::network::run::RunNetworkCommandError::ProjectNotFound,
4+
project::directory::FindProjectError,
5+
};
36
use clap::Parser;
47
use icp_network::{ManagedNetworkModel, RunNetworkError, run_network};
58
use snafu::Snafu;
@@ -10,11 +13,11 @@ pub struct Cmd {}
1013

1114
pub async fn exec(_cmd: Cmd) -> Result<(), RunNetworkCommandError> {
1215
let config = ManagedNetworkModel::default();
13-
let pd = ProjectDirectory::find().ok_or(ProjectNotFound)?;
16+
let pd = ProjectDirectory::find()?.ok_or(ProjectNotFound)?;
1417
let nd = pd.network("local");
1518

16-
eprintln!("Project root: {}", pd.structure().root().display());
17-
eprintln!("Network root: {}", nd.structure().network_root().display());
19+
eprintln!("Project root: {}", pd.structure().root());
20+
eprintln!("Network root: {}", nd.structure().network_root());
1821

1922
run_network(config, nd).await?;
2023

@@ -26,6 +29,9 @@ pub enum RunNetworkCommandError {
2629
#[snafu(display("no project (icp.yaml) found in current directory or its parents"))]
2730
ProjectNotFound,
2831

32+
#[snafu(transparent)]
33+
FindProjectError { source: FindProjectError },
34+
2935
#[snafu(transparent)]
3036
NetworkExecutionFailed { source: RunNetworkError },
3137
}

bin/icp-cli/src/project/directory.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
use crate::project::structure::ProjectDirectoryStructure;
2+
use camino::Utf8PathBuf;
23
use icp_network::NetworkDirectory;
4+
use snafu::{ResultExt, Snafu};
5+
use std::io;
36

47
pub struct ProjectDirectory {
58
structure: ProjectDirectoryStructure,
69
}
710

811
impl ProjectDirectory {
9-
pub fn find() -> Option<Self> {
10-
let current_dir = std::env::current_dir().ok()?;
12+
pub fn find() -> Result<Option<Self>, FindProjectError> {
13+
let current_dir = Utf8PathBuf::try_from(std::env::current_dir().context(AccessSnafu)?)
14+
.context(NonUtf8Snafu)?;
1115
let mut path = current_dir.clone();
1216
loop {
1317
let structure = ProjectDirectoryStructure::new(&path);
1418

1519
if structure.project_yaml_path().exists() {
16-
break Some(Self { structure });
20+
break Ok(Some(Self { structure }));
1721
}
1822
if !path.pop() {
19-
break None;
23+
break Ok(None);
2024
}
2125
}
2226
}
@@ -30,3 +34,11 @@ impl ProjectDirectory {
3034
NetworkDirectory::new(&network_root)
3135
}
3236
}
37+
38+
#[derive(Debug, Snafu)]
39+
pub enum FindProjectError {
40+
#[snafu(display("project path is non-UTF-8"))]
41+
NonUtf8 { source: camino::FromPathBufError },
42+
#[snafu(display("failed to access current directory"))]
43+
AccessError { source: io::Error },
44+
}
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
1-
use std::path::{Path, PathBuf};
1+
use camino::{Utf8Path, Utf8PathBuf};
22

33
pub struct ProjectDirectoryStructure {
4-
root: PathBuf,
4+
root: Utf8PathBuf,
55
}
66

77
impl ProjectDirectoryStructure {
8-
pub fn new(root: &Path) -> Self {
8+
pub fn new(root: &Utf8Path) -> Self {
99
let root = root.to_path_buf();
1010
Self { root }
1111
}
1212

13-
pub fn root(&self) -> &PathBuf {
13+
pub fn root(&self) -> &Utf8PathBuf {
1414
&self.root
1515
}
1616

17-
pub fn project_yaml_path(&self) -> PathBuf {
17+
pub fn project_yaml_path(&self) -> Utf8PathBuf {
1818
self.root.join("icp.yaml")
1919
}
2020

2121
#[allow(dead_code)]
22-
pub fn network_config_path(&self, name: &str) -> PathBuf {
22+
pub fn network_config_path(&self, name: &str) -> Utf8PathBuf {
2323
self.root.join("networks").join(format!("{name}.yaml"))
2424
}
2525

26-
fn work_dir(&self) -> PathBuf {
26+
fn work_dir(&self) -> Utf8PathBuf {
2727
self.root.join(".icp")
2828
}
2929

30-
pub fn network_root(&self, network_name: &str) -> PathBuf {
30+
pub fn network_root(&self, network_name: &str) -> Utf8PathBuf {
3131
self.work_dir().join("networks").join(network_name)
3232
}
3333
}

bin/icp-cli/tests/common/test_env.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
use crate::common::os::PATH_SEPARATOR;
22
use assert_cmd::Command;
3+
use camino::{Utf8Path, Utf8PathBuf};
4+
use camino_tempfile::Utf8TempDir;
35
use std::env;
46
use std::ffi::OsString;
57
use std::fs;
68
use std::fs::create_dir_all;
7-
use std::path::{Path, PathBuf};
8-
use tempfile::TempDir;
99

1010
pub struct TestEnv {
11-
home_dir: TempDir,
12-
bin_dir: PathBuf,
13-
dfx_path: Option<PathBuf>,
11+
home_dir: Utf8TempDir,
12+
bin_dir: Utf8PathBuf,
13+
dfx_path: Option<Utf8PathBuf>,
1414
os_path: OsString,
1515
}
1616

1717
impl TestEnv {
1818
pub fn new() -> Self {
19-
let home_dir = tempfile::tempdir().expect("failed to create temp home dir");
19+
let home_dir = camino_tempfile::tempdir().expect("failed to create temp home dir");
2020
let bin_dir = home_dir.path().join("bin");
2121
fs::create_dir(&bin_dir).expect("failed to create bin dir");
2222
let os_path = Self::build_os_path(&bin_dir);
23-
eprintln!(
24-
"Test environment home directory: {}",
25-
home_dir.path().display()
26-
);
23+
eprintln!("Test environment home directory: {}", home_dir.path());
2724

2825
Self {
2926
home_dir,
@@ -35,13 +32,12 @@ impl TestEnv {
3532

3633
/// Sets up `dfx` in the test environment by copying the binary from $ICPTEST_DFX_PATH
3734
pub fn with_dfx(mut self) -> Self {
38-
let dfx_path = std::env::var_os("ICPTEST_DFX_PATH")
35+
let dfx_path = std::env::var("ICPTEST_DFX_PATH")
3936
.expect("ICPTEST_DFX_PATH must be set to use with_dfx()");
40-
let src = PathBuf::from(dfx_path);
37+
let src = Utf8PathBuf::from(dfx_path);
4138
assert!(
4239
src.exists(),
43-
"ICPTEST_DFX_PATH points to non-existent file: {}",
44-
src.display()
40+
"ICPTEST_DFX_PATH points to non-existent file: {src}",
4541
);
4642

4743
let dest = self.bin_dir.join("dfx");
@@ -51,7 +47,7 @@ impl TestEnv {
5147
{
5248
use std::os::unix::fs::PermissionsExt;
5349
let mut perms = fs::metadata(&dest)
54-
.unwrap_or_else(|e| panic!("Failed to read metadata for {}: {}", dest.display(), e))
50+
.unwrap_or_else(|e| panic!("Failed to read metadata for {dest}: {e}"))
5551
.permissions();
5652
perms.set_mode(0o500);
5753
fs::set_permissions(&dest, perms).unwrap();
@@ -61,7 +57,7 @@ impl TestEnv {
6157
self
6258
}
6359

64-
pub fn home_path(&self) -> &Path {
60+
pub fn home_path(&self) -> &Utf8Path {
6561
self.home_dir.path()
6662
}
6763

@@ -88,7 +84,7 @@ impl TestEnv {
8884
cmd.env("PATH", self.os_path.clone());
8985
}
9086

91-
fn build_os_path(bin_dir: &Path) -> OsString {
87+
fn build_os_path(bin_dir: &Utf8Path) -> OsString {
9288
let old_path = env::var_os("PATH").unwrap_or_default();
9389
let mut new_path = bin_dir.as_os_str().to_os_string();
9490
new_path.push(PATH_SEPARATOR);

clippy.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
disallowed-types = [
2+
{ path = "std::path::PathBuf", replacement = "camino::Utf8PathBuf" },
3+
{ path = "std::path::Path", replacement = "camino::Utf8Path" },
4+
]

lib/icp-fs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version = "0.1.0"
44
edition = "2024"
55

66
[dependencies]
7+
camino = { workspace = true }
78
serde = { workspace = true }
89
serde_json = { workspace = true }
910
snafu = { workspace = true }

lib/icp-fs/src/fs.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,65 @@
1+
use camino::{Utf8Path, Utf8PathBuf};
12
use snafu::prelude::*;
2-
use std::path::{Path, PathBuf};
33

44
#[derive(Snafu, Debug)]
5-
#[snafu(display("failed to create directory {} and parents", path.display()))]
5+
#[snafu(display("failed to create directory {path} and parents"))]
66
pub struct CreateDirAllError {
7-
pub path: PathBuf,
7+
pub path: Utf8PathBuf,
88
pub source: std::io::Error,
99
}
1010

11-
pub fn create_dir_all(path: &Path) -> Result<(), CreateDirAllError> {
11+
pub fn create_dir_all(path: impl AsRef<Utf8Path>) -> Result<(), CreateDirAllError> {
12+
let path = path.as_ref();
1213
std::fs::create_dir_all(path).context(CreateDirAllSnafu { path })
1314
}
1415

1516
#[derive(Snafu, Debug)]
16-
#[snafu(display("failed to read {}", path.display()))]
17+
#[snafu(display("failed to read {path}"))]
1718
pub struct ReadFileError {
18-
pub path: PathBuf,
19+
pub path: Utf8PathBuf,
1920
pub source: std::io::Error,
2021
}
2122

22-
pub fn read<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, ReadFileError> {
23+
pub fn read<P: AsRef<Utf8Path>>(path: P) -> Result<Vec<u8>, ReadFileError> {
2324
let path = path.as_ref();
2425
std::fs::read(path).context(ReadFileSnafu { path })
2526
}
2627

2728
#[derive(Snafu, Debug)]
28-
#[snafu(display("failed to remove directory {} and contents", path.display()))]
29+
#[snafu(display("failed to remove directory {path} and contents"))]
2930
pub struct RemoveDirAllError {
30-
pub path: PathBuf,
31+
pub path: Utf8PathBuf,
3132
pub source: std::io::Error,
3233
}
3334

34-
pub fn remove_dir_all(path: &Path) -> Result<(), RemoveDirAllError> {
35+
pub fn remove_dir_all(path: impl AsRef<Utf8Path>) -> Result<(), RemoveDirAllError> {
36+
let path = path.as_ref();
3537
std::fs::remove_dir_all(path).context(RemoveDirAllSnafu { path })
3638
}
3739

3840
#[derive(Snafu, Debug)]
39-
#[snafu(display("failed to remove file {}", path.display()))]
41+
#[snafu(display("failed to remove file {path}"))]
4042
pub struct RemoveFileError {
41-
pub path: PathBuf,
43+
pub path: Utf8PathBuf,
4244
pub source: std::io::Error,
4345
}
4446

45-
pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<(), RemoveFileError> {
47+
pub fn remove_file<P: AsRef<Utf8Path>>(path: P) -> Result<(), RemoveFileError> {
4648
let path = path.as_ref();
4749
std::fs::remove_file(path).context(RemoveFileSnafu { path })
4850
}
4951

5052
#[derive(Snafu, Debug)]
51-
#[snafu(display("failed to write {}", path.display()))]
53+
#[snafu(display("failed to write {path}"))]
5254
pub struct WriteFileError {
53-
pub path: PathBuf,
55+
pub path: Utf8PathBuf,
5456
pub source: std::io::Error,
5557
}
5658

57-
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<(), WriteFileError> {
59+
pub fn write<P: AsRef<Utf8Path>, C: AsRef<[u8]>>(
60+
path: P,
61+
contents: C,
62+
) -> Result<(), WriteFileError> {
5863
let path = path.as_ref();
5964
std::fs::write(path, contents).context(WriteFileSnafu { path })
6065
}

0 commit comments

Comments
 (0)