Skip to content

Commit 842ff87

Browse files
authored
added File.rename! (#377)
1 parent bc05713 commit 842ff87

File tree

6 files changed

+107
-19
lines changed

6 files changed

+107
-19
lines changed

ci/expect_scripts/file.exp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,28 @@ expect "Testing some File functions..." {
4949
# Test File.hard_link!
5050
expect "Testing File.hard_link!:" {
5151
expect "✓ Successfully created hard link: test_link_to_original.txt" {
52-
expect "Hard link inodes should be equal:" {
53-
expect "Bool.true" {
54-
expect "✓ Hard link contains same content as original" {
55-
56-
# Cleanup phase
57-
expect "Cleaning up test files..." {
58-
expect "✓ Deleted all files." {
59-
60-
# Final completion message
61-
expect "I ran all file function tests." {
62-
expect eof {
63-
check_exit_and_segfault
52+
expect "Hard link inodes should be equal: Bool.true" {
53+
expect "✓ Hard link contains same content as original" {
54+
55+
# Test File.rename!
56+
expect "Testing File.rename!:" {
57+
expect "✓ Successfully renamed test_rename_original.txt to test_rename_new.txt" {
58+
expect "✓ Original file test_rename_original.txt no longer exists" {
59+
expect "✓ Renamed file test_rename_new.txt exists" {
60+
expect "✓ Renamed file has correct content" {
61+
62+
# Cleanup phase
63+
expect "Cleaning up test files..." {
64+
expect "✓ Deleted all files." {
65+
66+
# Final completion message
67+
expect "I ran all file function tests." {
68+
expect eof {
69+
check_exit_and_segfault
70+
}
71+
}
72+
}
73+
}
6474
}
6575
}
6676
}

crates/roc_file/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,16 @@ pub fn file_time_created(roc_path: &RocList<u8>) -> RocResult<roc_std::U128, IOE
343343
}
344344
}
345345

346+
pub fn file_rename(from_path: &RocList<u8>, to_path: &RocList<u8>) -> RocResult<(), IOErr> {
347+
let rust_from_path = path_from_roc_path(from_path);
348+
let rust_to_path = path_from_roc_path(to_path);
349+
350+
match std::fs::rename(rust_from_path, rust_to_path) {
351+
Ok(()) => RocResult::ok(()),
352+
Err(err) => RocResult::err(err.into()),
353+
}
354+
}
355+
346356
pub fn dir_list(roc_path: &RocList<u8>) -> RocResult<RocList<RocList<u8>>, IOErr> {
347357
let path = path_from_roc_path(roc_path);
348358

crates/roc_host/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ pub fn init() {
324324
roc_fx_file_time_accessed as _,
325325
roc_fx_file_time_modified as _,
326326
roc_fx_file_time_created as _,
327+
roc_fx_file_rename as _,
327328
roc_fx_hard_link as _,
328329
roc_fx_cwd as _,
329330
roc_fx_posix_time as _,
@@ -568,6 +569,13 @@ pub extern "C" fn roc_fx_file_time_created(
568569
roc_file::file_time_created(roc_path)
569570
}
570571

572+
#[no_mangle]
573+
pub extern "C" fn roc_fx_file_rename(
574+
from_path: &RocList<u8>,
575+
to_path: &RocList<u8>,
576+
) -> RocResult<(), roc_io_error::IOErr> {
577+
roc_file::file_rename(from_path, to_path)
578+
}
571579

572580
#[no_mangle]
573581
pub extern "C" fn roc_fx_cwd() -> RocResult<RocList<u8>, ()> {

platform/File.roc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module [
1616
time_accessed!,
1717
time_modified!,
1818
time_created!,
19+
rename!,
1920
type!,
2021
open_reader!,
2122
open_reader_with_capacity!,
@@ -273,6 +274,16 @@ time_created! = |path_str|
273274
|> Result.map_ok(|time_u128| Num.to_i128(time_u128) |> Utc.from_nanos_since_epoch)
274275
|> Result.map_err(|err| PathErr(InternalIOErr.handle_err(err)))
275276

277+
## Renames a file or directory.
278+
##
279+
## This uses [rust's std::fs::rename](https://doc.rust-lang.org/std/fs/fn.rename.html).
280+
rename! : Str, Str => Result {} [PathErr IOErr]
281+
rename! = |from_str, to_str|
282+
from_bytes = InternalPath.to_bytes(Path.from_str(from_str))
283+
to_bytes = InternalPath.to_bytes(Path.from_str(to_str))
284+
Host.file_rename!(from_bytes, to_bytes)
285+
|> Result.map_err(|err| PathErr(InternalIOErr.handle_err(err)))
286+
276287
## Return the type of the path if the path exists on disk.
277288
## This uses [rust's std::path::is_symlink](https://doc.rust-lang.org/std/path/struct.Path.html#method.is_symlink).
278289
##

platform/Host.roc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ hosted [
2626
file_time_accessed!,
2727
file_time_modified!,
2828
file_time_created!,
29+
file_rename!,
2930
get_locale!,
3031
get_locales!,
3132
hard_link!,
@@ -80,6 +81,7 @@ file_is_writable! : List U8 => Result Bool InternalIOErr.IOErrFromHost
8081
file_time_accessed! : List U8 => Result U128 InternalIOErr.IOErrFromHost
8182
file_time_modified! : List U8 => Result U128 InternalIOErr.IOErrFromHost
8283
file_time_created! : List U8 => Result U128 InternalIOErr.IOErrFromHost
84+
file_rename! : List U8, List U8 => Result {} InternalIOErr.IOErrFromHost
8385

8486
FileReader := Box {}
8587
file_reader! : List U8, U64 => Result FileReader InternalIOErr.IOErrFromHost

tests/file.roc

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ main! = |_args|
2828
# Test hard link creation
2929
test_hard_link!({})?
3030
31+
# Test file rename
32+
test_file_rename!({})?
33+
34+
# Clean up test files
35+
cleanup_test_files!({})?
36+
3137
Stdout.line!("\nI ran all file function tests.")
3238
3339
test_basic_file_operations! : {} => Result {} _
@@ -150,15 +156,55 @@ test_hard_link! = |{}|
150156
link_content = File.read_utf8!("test_link_to_original.txt")?
151157
152158
if original_content == link_content then
153-
Stdout.line!("Hard link contains same content as original")?
159+
Stdout.line!("Hard link contains same content as original")
154160
else
155-
Stderr.line!("Hard link content differs from original")?
161+
Stderr.line!("Hard link content differs from original")
156162
157163
Err(err) ->
158-
Stderr.line!("Hard link creation failed: ${Inspect.to_str(err)}")?
164+
Stderr.line!("Hard link creation failed: ${Inspect.to_str(err)}")
159165

160-
# Clean up test files
161-
cleanup_test_files!({})
166+
test_file_rename! : {} => Result {} _
167+
test_file_rename! = |{}|
168+
Stdout.line!("\nTesting File.rename!:")?
169+
170+
# Create original file
171+
original_name = "test_rename_original.txt"
172+
new_name = "test_rename_new.txt"
173+
File.write_utf8!("Content for rename test", original_name)?
174+
175+
# Rename the file
176+
when File.rename!(original_name, new_name) is
177+
Ok({}) ->
178+
Stdout.line!("Successfully renamed ${original_name} to ${new_name}")?
179+
180+
# Verify original file no longer exists
181+
original_exists_after =
182+
when File.is_file!(original_name) is
183+
Ok(exists) -> exists
184+
Err(_) -> Bool.false
185+
186+
if original_exists_after then
187+
Stderr.line!("Original file ${original_name} still exists after rename")?
188+
else
189+
Stdout.line!("Original file ${original_name} no longer exists")?
190+
191+
# Verify new file exists and has correct content
192+
new_exists = File.is_file!(new_name)?
193+
if new_exists then
194+
Stdout.line!("Renamed file ${new_name} exists")?
195+
196+
content = File.read_utf8!(new_name)?
197+
if content == "Content for rename test" then
198+
Stdout.line!("Renamed file has correct content")?
199+
else
200+
Stderr.line!("Renamed file has incorrect content")?
201+
else
202+
Stderr.line!("Renamed file ${new_name} does not exist")?
203+
204+
Err(err) ->
205+
Stderr.line!("File rename failed: ${Inspect.to_str(err)}")?
206+
207+
Ok({})
162208

163209
cleanup_test_files! : {} => Result {} _
164210
cleanup_test_files! = |{}|
@@ -170,8 +216,9 @@ cleanup_test_files! = |{}|
170216
"test_write.json",
171217
"test_multiline.txt",
172218
"test_original_file.txt",
173-
"test_link_to_original.txt"
219+
"test_link_to_original.txt",
220+
"test_rename_new.txt"
174221
]
175222
176-
List.for_each_try!(test_files, |filename| File.delete!(filename))?
223+
List.for_each_try!(test_files, |filename| File.delete!(filename)) ? |err| FileDeletionFailed(err)
177224
Stdout.line!("Deleted all files.")

0 commit comments

Comments
 (0)