use crate::errors::{error, nil, New};
use crate::types::{int, slice, string};
#[allow(non_snake_case)]
pub fn Args() -> slice<string> {
std::env::args().collect()
}
#[allow(non_snake_case)]
pub fn Getenv(key: impl AsRef<str>) -> string {
std::env::var(key.as_ref()).unwrap_or_default()
}
#[allow(non_snake_case)]
pub fn LookupEnv(key: impl AsRef<str>) -> (string, bool) {
match std::env::var(key.as_ref()) {
Ok(v) => (v, true),
Err(_) => (String::new(), false),
}
}
#[allow(non_snake_case)]
pub fn Setenv(key: impl AsRef<str>, val: impl AsRef<str>) -> error {
unsafe {
std::env::set_var(key.as_ref(), val.as_ref());
}
nil
}
#[allow(non_snake_case)]
pub fn Unsetenv(key: impl AsRef<str>) -> error {
unsafe {
std::env::remove_var(key.as_ref());
}
nil
}
#[allow(non_snake_case)]
pub fn Exit(code: int) -> ! {
std::process::exit(code as i32)
}
#[allow(non_snake_case)]
pub fn Hostname() -> (string, error) {
if let Ok(v) = std::env::var("HOSTNAME") {
if !v.is_empty() {
return (v, nil);
}
}
match std::fs::read_to_string("/etc/hostname") {
Ok(s) => (s.trim().to_string(), nil),
Err(e) => (String::new(), New(&format!("os.Hostname: {}", e))),
}
}
#[allow(non_snake_case)]
pub fn Getwd() -> (string, error) {
match std::env::current_dir() {
Ok(p) => (p.to_string_lossy().into_owned(), nil),
Err(e) => (String::new(), New(&format!("os.Getwd: {}", e))),
}
}
#[allow(non_snake_case)]
pub fn Chdir(path: impl AsRef<str>) -> error {
match std::env::set_current_dir(path.as_ref()) {
Ok(()) => nil,
Err(e) => New(&format!("os.Chdir: {}", e)),
}
}
#[allow(non_snake_case)]
pub fn ReadFile(path: impl AsRef<str>) -> (Vec<crate::types::byte>, error) {
match std::fs::read(path.as_ref()) {
Ok(b) => (b, nil),
Err(e) => (Vec::new(), New(&format!("os.ReadFile: {}", e))),
}
}
#[allow(non_snake_case)]
pub fn WriteFile(path: impl AsRef<str>, data: &[crate::types::byte], _perm: u32) -> error {
match std::fs::write(path.as_ref(), data) {
Ok(()) => nil,
Err(e) => New(&format!("os.WriteFile: {}", e)),
}
}
#[allow(non_snake_case)]
pub fn Remove(path: impl AsRef<str>) -> error {
let p = path.as_ref();
match std::fs::remove_file(p) {
Ok(()) => nil,
Err(_) => match std::fs::remove_dir(p) {
Ok(()) => nil,
Err(e) => New(&format!("os.Remove: {}", e)),
},
}
}
#[allow(non_snake_case)]
pub fn RemoveAll(path: impl AsRef<str>) -> error {
let p = path.as_ref();
let md = match std::fs::metadata(p) {
Ok(m) => m,
Err(_) => return nil, };
let r = if md.is_dir() {
std::fs::remove_dir_all(p)
} else {
std::fs::remove_file(p)
};
match r {
Ok(()) => nil,
Err(e) => New(&format!("os.RemoveAll: {}", e)),
}
}
#[allow(non_snake_case)]
pub fn Mkdir(path: impl AsRef<str>, _perm: u32) -> error {
match std::fs::create_dir(path.as_ref()) {
Ok(()) => nil,
Err(e) => New(&format!("os.Mkdir: {}", e)),
}
}
#[allow(non_snake_case)]
pub fn MkdirAll(path: impl AsRef<str>, _perm: u32) -> error {
match std::fs::create_dir_all(path.as_ref()) {
Ok(()) => nil,
Err(e) => New(&format!("os.MkdirAll: {}", e)),
}
}
#[allow(non_snake_case)]
pub fn TempDir() -> string {
std::env::temp_dir().to_string_lossy().into_owned()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn args_has_at_least_program_name() {
let a = Args();
assert!(!a.is_empty());
}
#[test]
fn getenv_missing_returns_empty() {
let v = Getenv("GOISH_DEFINITELY_NOT_SET_12345");
assert_eq!(v, "");
}
#[test]
fn setenv_getenv_roundtrip() {
let key = "GOISH_TEST_SETENV_1";
let _ = Setenv(key, "hello");
assert_eq!(Getenv(key), "hello");
let _ = Unsetenv(key);
assert_eq!(Getenv(key), "");
}
#[test]
fn lookupenv_ok_flag() {
let key = "GOISH_TEST_LOOKUP_1";
let (_, ok) = LookupEnv(key);
assert!(!ok);
let _ = Setenv(key, "x");
let (v, ok) = LookupEnv(key);
assert!(ok);
assert_eq!(v, "x");
let _ = Unsetenv(key);
}
#[test]
fn getwd_not_empty() {
let (dir, err) = Getwd();
assert!(err == nil);
assert!(!dir.is_empty());
}
#[test]
fn write_read_remove_file() {
let tmp = TempDir();
let path = format!("{}/goish_test_os_rw.txt", tmp);
let err = WriteFile(&path, b"hello goish", 0o644);
assert!(err == nil);
let (data, err) = ReadFile(&path);
assert!(err == nil);
assert_eq!(data, b"hello goish");
let err = Remove(&path);
assert!(err == nil);
}
#[test]
fn mkdir_removeall_roundtrip() {
let tmp = TempDir();
let path = format!("{}/goish_test_os_mkdir/nested/deep", tmp);
let err = MkdirAll(&path, 0o755);
assert!(err == nil);
let top = format!("{}/goish_test_os_mkdir", tmp);
let err = RemoveAll(&top);
assert!(err == nil);
}
}