Skip to content

Commit 8d9ae08

Browse files
ianmclindenIan McLinden
authored andcommitted
[realpath] first implementation
1 parent 9800f57 commit 8d9ae08

File tree

5 files changed

+174
-1
lines changed

5 files changed

+174
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ Because it is a FAQ, the major differences between this project and uutils are:
146146
- [x] logger
147147
- [x] printf
148148
- [x] ps
149+
- [x] realpath
149150
- [x] stty
150151
- [x] tabs
151152
- [x] test
@@ -213,7 +214,6 @@ Because it is a FAQ, the major differences between this project and uutils are:
213214
- [ ] newgrp
214215
- [ ] patch
215216
- [ ] pax
216-
- [ ] realpath
217217
- [ ] sed
218218
- [ ] sh
219219
- [ ] talk

misc/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ path = "./false.rs"
2424
name = "test"
2525
path = "./test.rs"
2626

27+
[[bin]]
28+
name = "realpath"
29+
path = "./realpath.rs"

misc/realpath.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// Copyright (c) 2024 Ian McLinden
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
10+
use gettextrs::{bind_textdomain_codeset, gettext, setlocale, textdomain, LocaleCategory};
11+
use plib::PROJECT_NAME;
12+
13+
fn main() -> Result<(), Box<dyn std::error::Error>> {
14+
let mut args: Vec<String> = std::env::args().skip(1).collect();
15+
16+
setlocale(LocaleCategory::LcAll, "");
17+
textdomain(PROJECT_NAME)?;
18+
bind_textdomain_codeset(PROJECT_NAME, "UTF-8")?;
19+
20+
if args.is_empty() {
21+
args.push(String::from("."));
22+
}
23+
24+
let mut exit_code = 0;
25+
for path in args {
26+
match std::fs::canonicalize(&path) {
27+
Ok(p) => println!("{}", p.to_string_lossy()),
28+
Err(e) => {
29+
eprintln!("{path:?}: {}", gettext(e.to_string()));
30+
exit_code |= 1;
31+
}
32+
}
33+
}
34+
35+
std::process::exit(exit_code);
36+
}

misc/tests/misc-tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
//
99

1010
mod r#false;
11+
mod realpath;
1112
mod test;
1213
mod r#true;

misc/tests/realpath/mod.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//
2+
// Copyright (c) 2024 Ian McLinden
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
10+
use plib::{run_test, TestPlan};
11+
12+
fn realpath_test(args: &[&str], output: &str, expected_code: i32) {
13+
let str_args: Vec<String> = args.iter().map(|s| String::from(*s)).collect();
14+
15+
run_test(TestPlan {
16+
cmd: String::from("realpath"),
17+
args: str_args,
18+
stdin_data: String::new(),
19+
expected_out: output.to_string(),
20+
expected_err: String::new(),
21+
expected_exit_code: expected_code,
22+
});
23+
}
24+
25+
#[test]
26+
fn realpath_current_directory() {
27+
let curr_dir = std::env::current_dir().unwrap();
28+
let out_str = &format!("{}\n", curr_dir.to_str().unwrap());
29+
30+
realpath_test(&["."], out_str, 0);
31+
realpath_test(&["./"], out_str, 0);
32+
realpath_test(&["./."], out_str, 0);
33+
}
34+
35+
#[test]
36+
fn realpath_parent_directory() {
37+
let curr_dir = std::env::current_dir().unwrap();
38+
let parent_dir = curr_dir.parent().unwrap();
39+
let out_str = format!("{}\n", parent_dir.to_str().unwrap());
40+
41+
realpath_test(&[".."], &out_str, 0);
42+
realpath_test(&["../"], &out_str, 0);
43+
realpath_test(&["../."], &out_str, 0);
44+
realpath_test(&["./.."], &out_str, 0);
45+
realpath_test(&["./../"], &out_str, 0);
46+
realpath_test(&["./../."], &out_str, 0);
47+
}
48+
49+
#[test]
50+
fn realpath_endless_parent() {
51+
realpath_test(
52+
&["../../../../../../../../../../../../../../../../../../../.."],
53+
"/\n",
54+
0,
55+
);
56+
realpath_test(
57+
&["../../../../../../../../../../../../../../../../../../../../"],
58+
"/\n",
59+
0,
60+
);
61+
realpath_test(
62+
&["../../../../../../../../../../../../../../../../../../../../."],
63+
"/\n",
64+
0,
65+
);
66+
realpath_test(
67+
&["./../../../../../../../../../../../../../../../../../../../.."],
68+
"/\n",
69+
0,
70+
);
71+
realpath_test(
72+
&["./../../../../../../../../../../../../../../../../../../../../"],
73+
"/\n",
74+
0,
75+
);
76+
realpath_test(
77+
&["./../../../../../../../../../../../../../../../../../../../../."],
78+
"/\n",
79+
0,
80+
);
81+
}
82+
83+
#[test]
84+
fn realpath_relative_directory() {
85+
let curr_dir = std::env::current_dir().unwrap();
86+
let curr_dir_name = curr_dir.file_name().unwrap();
87+
let out_str = &format!("{}\n", curr_dir.to_str().unwrap());
88+
89+
let in_str = &format!("../{}", curr_dir_name.to_str().unwrap());
90+
realpath_test(&[in_str], out_str, 0);
91+
92+
let in_str = &format!("./../{}", curr_dir_name.to_str().unwrap());
93+
realpath_test(&[in_str], out_str, 0);
94+
95+
let in_str = &format!(
96+
"{}/../{}",
97+
curr_dir.to_str().unwrap(),
98+
curr_dir_name.to_str().unwrap()
99+
);
100+
realpath_test(&[in_str], out_str, 0);
101+
}
102+
103+
#[test]
104+
fn realpath_multiple_args() {
105+
let curr_dir = std::env::current_dir().unwrap();
106+
let parent_dir = curr_dir.parent().unwrap();
107+
let out_str = &format!(
108+
"{}\n{}\n/\n",
109+
curr_dir.to_str().unwrap(),
110+
parent_dir.to_str().unwrap()
111+
);
112+
realpath_test(&[".", "..", "/"], out_str, 0);
113+
}
114+
115+
#[test]
116+
fn realpath_no_args() {
117+
let curr_dir = std::env::current_dir().unwrap();
118+
let out_str = format!("{}\n", curr_dir.to_str().unwrap());
119+
120+
realpath_test(&[], &out_str, 0);
121+
}
122+
123+
#[test]
124+
fn realpath_empty_path() {
125+
run_test(TestPlan {
126+
cmd: String::from("realpath"),
127+
args: vec![String::new()],
128+
stdin_data: String::new(),
129+
expected_out: String::new(),
130+
expected_err: String::from("\"\": No such file or directory (os error 2)\n"),
131+
expected_exit_code: 1,
132+
});
133+
}

0 commit comments

Comments
 (0)