Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal: add error handling for fs #102

Merged
merged 2 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,15 @@ jobs:
run: |
moon test --target all --serial --release
moon test --target all --serial
moon test --target native --release
moon test --target native

- name: moon test(native)
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 5
command: |
moon test --target native --release
moon test --target native

- name: moon check
run: moon check --deny-warn
Expand Down Expand Up @@ -111,8 +118,15 @@ jobs:
run: |
moon test --target all --serial --release
moon test --target all --serial
moon test --target native --release
moon test --target native

- name: moon test(native)
uses: nick-fields/retry@v3
with:
timeout_minutes: 30
max_attempts: 5
command: |
moon test --target native --release
moon test --target native

- name: moon check
run: moon check --deny-warn
Expand Down
51 changes: 51 additions & 0 deletions fs/blackbox_test.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
test "write_and_read" {
let path_1 = "./fs/test_1.txt"
let path_2 = "./fs/test_2.txt"
let content_1 = "Hello, World"
let content_2 = "Hello, MoonBit"
@fs.write_bytes_to_file!(path_1, content_1.to_bytes())
let res_1 = @fs.read_file_to_bytes!(path_1)
inspect!(res_1.to_unchecked_string(), content=content_1)
@fs.write_string_to_file!(path_2, content_2)
let res_2 = @fs.read_file_to_string!(path_2)
inspect!(res_2, content=content_2)
}

///|
test "read_dir" {
let path = "./fs"
let files = @fs.read_dir!(path)..sort()
inspect!(
files,
content=
#|["fs.mbt", "fs.mbti", "fs_js.mbt", "test_1.txt", "test_2.txt", "fs_wasm.mbt", "fs_native.mbt", "moon.pkg.json", "blackbox_test.mbt"]
,
)
}

///|
test "create_dir_and_remove_dir" {
let path = "./fs/test_dir"
assert_false!(@fs.path_exists(path))
@fs.create_dir!(path)
assert_true!(@fs.path_exists(path))
assert_true!(@fs.is_dir!(path))
assert_false!(@fs.is_file!(path))
@fs.remove_dir!(path)
assert_false!(@fs.path_exists(path))
}
121 changes: 57 additions & 64 deletions fs/fs.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,77 +13,74 @@
// limitations under the License.

///|
pub(all) type! IOError {
NotFound(String)
}
pub type! IOError String derive(Show)

///|
pub impl Show for IOError with output(self, logger) {
logger.write_string(self.to_string())
}

///|
fn IOError::to_string(self : IOError) -> String {
match self {
IOError::NotFound(path) => "`\{path}` does not exist"
}
}

///| Writes a string to a file.
///| Reads the content of a file specified by the given path and returns its
/// content as `Bytes`
///
/// # Parameters
/// - `path`: A `String` representing the file path.
/// - `content`: A `String` containing the content to be written to the file.
pub fn write_string_to_file(path~ : String, content~ : String) -> Unit {
@ffi.write_string_to_file(path, content)
///
/// - `path` : The path to the file to be read.
///
/// # Returns
///
/// - A `Bytes` representing the content of the file.
pub fn read_file_to_bytes(path : String) -> Bytes! {
read_file_to_bytes_internal!(path)
}

///| Writes an array of bytes to a file at the specified path.
///| Reads the content of a file specified by the given path and returns its
/// content as `String`.
///
/// # Parameters
///
/// - `path` : The path to the file where the bytes will be written.
/// - `content` : An array of bytes to be written to the file.
pub fn write_bytes_to_file(path~ : String, content~ : Bytes) -> Unit {
@ffi.write_bytes_to_file(path, content)
/// - `path` : The path to the file to be read.
/// - `encoding~` : The encoding of the file. Only support `utf8` for now.
///
/// # Returns
///
/// - A `String` representing the content of the file.
pub fn read_file_to_string(
path : String,
encoding~ : String = "utf8"
) -> String! {
read_file_to_string_internal!(path, encoding~)
}

///| Checks if a path exists.
///| Writes a `Bytes` to a file at the specified path.
///
/// # Parameters
/// - `path`: A `String` representing the file path.
///
/// # Returns
/// A boolean indicating whether the path exists.
pub fn path_exists(path~ : String) -> Bool {
@ffi.path_exists(path)
/// - `path` : The path to the file where the bytes will be written.
/// - `content` : A `Bytes` to be written to the file.
pub fn write_bytes_to_file(path : String, content : Bytes) -> Unit! {
write_bytes_to_file_internal!(path, content)
}

///| Reads the entire contents of a file into a string.
///| Writes a `String` to a file at the specified path.
///
/// # Parameters
/// - `path`: A `String` representing the file path.
///
/// # Returns
/// A `String` containing the file contents if the file exists, otherwise raises an error.
pub fn read_file_to_string(path~ : String) -> String! {
guard path_exists(path~) else { raise IOError::NotFound(path) }
@ffi.read_file_to_string(path)
/// - `path` : The path to the file where the string will be written.
/// - `content` : A `String` to be written to the file.
/// - `encoding~` : The encoding of the file. Only support `utf8` for now.
pub fn write_string_to_file(
path : String,
content : String,
encoding~ : String = "utf8"
) -> Unit! {
write_string_to_file_internal!(path, content, encoding~)
}

///| Reads the content of a file specified by the given path and returns its
/// content as an array of bytes. If the file does not exist, an error is raised.
///| Checks if a path exists.
///
/// # Parameters
///
/// - `path` : The path to the file to be read.
/// - `path`: A `String` representing the file path.
///
/// # Returns
///
/// - An array of bytes representing the content of the file.
pub fn read_file_to_bytes(path~ : String) -> Bytes! {
guard path_exists(path~) else { raise IOError::NotFound(path) }
@ffi.read_file_to_bytes(path)
/// A boolean indicating whether the path exists.
pub fn path_exists(path : String) -> Bool {
path_exists_internal(path)
}

///| Reads the contents of a directory and returns an array of filenames.
Expand All @@ -95,9 +92,8 @@ pub fn read_file_to_bytes(path~ : String) -> Bytes! {
/// # Returns
///
/// - An array of strings representing the file name and directory name in the directory.
pub fn read_dir(path~ : String) -> Array[String]! {
guard path_exists(path~) else { raise IOError::NotFound(path) }
@ffi.read_dir(path)
pub fn read_dir(path : String) -> Array[String]! {
read_dir_internal!(path)
}

///| Creates a directory at the specified path.
Expand All @@ -106,8 +102,9 @@ pub fn read_dir(path~ : String) -> Array[String]! {
/// # Parameters
///
/// - `path` : The path where the directory should be created.
pub fn create_dir(path~ : String) -> Unit {
@ffi.create_dir(path)
/// - `mode~` : The mode of the directory. Default is `777`.
pub fn create_dir(path : String) -> Unit! {
create_dir_internal!(path)
}

///| Checks if the given path is a directory.
Expand All @@ -119,9 +116,8 @@ pub fn create_dir(path~ : String) -> Unit {
/// # Returns
///
/// - `Bool` : `true` if the path is a directory, `false` otherwise.
pub fn is_dir(path~ : String) -> Bool! {
guard path_exists(path~) else { raise IOError::NotFound(path) }
@ffi.is_dir(path)
pub fn is_dir(path : String) -> Bool! {
is_dir_internal!(path)
}

///| Check if the given path points to a file.
Expand All @@ -133,27 +129,24 @@ pub fn is_dir(path~ : String) -> Bool! {
/// # Returns
///
/// - `Bool` : `true` if the path points to a file, `false` otherwise.
pub fn is_file(path~ : String) -> Bool! {
guard path_exists(path~) else { raise IOError::NotFound(path) }
@ffi.is_file(path)
pub fn is_file(path : String) -> Bool! {
is_file_internal!(path)
}

///| Removes a directory at the specified path.
///
/// # Parameters
///
/// - `path` : The string path to the directory that needs to be removed.
pub fn remove_dir(path~ : String) -> Unit! {
guard path_exists(path~) else { raise IOError::NotFound(path) }
@ffi.remove_dir(path)
pub fn remove_dir(path : String) -> Unit! {
remove_dir_internal!(path)
}

///| Removes a file at the specified path.
///
/// # Parameters
///
/// - `path` : The path to the file that needs to be removed.
pub fn remove_file(path~ : String) -> Unit! {
guard path_exists(path~) else { raise IOError::NotFound(path) }
@ffi.remove_file(path)
pub fn remove_file(path : String) -> Unit! {
remove_file_internal!(path)
}
26 changes: 12 additions & 14 deletions fs/fs.mbti
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
package moonbitlang/x/fs

// Values
fn create_dir(path~ : String) -> Unit
fn create_dir(String) -> Unit!

fn is_dir(path~ : String) -> Bool!
fn is_dir(String) -> Bool!

fn is_file(path~ : String) -> Bool!
fn is_file(String) -> Bool!

fn path_exists(path~ : String) -> Bool
fn path_exists(String) -> Bool

fn read_dir(path~ : String) -> Array[String]!
fn read_dir(String) -> Array[String]!

fn read_file_to_bytes(path~ : String) -> Bytes!
fn read_file_to_bytes(String) -> Bytes!

fn read_file_to_string(path~ : String) -> String!
fn read_file_to_string(String, encoding~ : String = ..) -> String!

fn remove_dir(path~ : String) -> Unit!
fn remove_dir(String) -> Unit!

fn remove_file(path~ : String) -> Unit!
fn remove_file(String) -> Unit!

fn write_bytes_to_file(path~ : String, content~ : Bytes) -> Unit
fn write_bytes_to_file(String, Bytes) -> Unit!

fn write_string_to_file(path~ : String, content~ : String) -> Unit
fn write_string_to_file(String, String, encoding~ : String = ..) -> Unit!

// Types and methods
pub(all) type! IOError {
NotFound(String)
}
pub type! IOError String
impl Show for IOError

// Type aliases
Expand Down
Loading
Loading