diff --git a/src/stdlib/Os.fs b/src/stdlib/Os.fs index d366bce..198029b 100644 --- a/src/stdlib/Os.fs +++ b/src/stdlib/Os.fs @@ -30,6 +30,12 @@ type IExports = /// Return the value of the environment variable key or default if not set /// See https://docs.python.org/3/library/os.html#os.getenv abstract getenv: key: string * ``default``: string -> string + /// Return the current process id. + /// See https://docs.python.org/3/library/os.html#os.getpid + abstract getpid: unit -> int + /// Return the parent process id. + /// See https://docs.python.org/3/library/os.html#os.getppid + abstract getppid: unit -> int /// Send signal sig to the process pid /// See https://docs.python.org/3/library/os.html#os.kill abstract kill: pid: int * ``sig``: int -> unit @@ -42,8 +48,14 @@ type IExports = /// Recursive directory creation function /// See https://docs.python.org/3/library/os.html#os.makedirs abstract makedirs: path: string -> unit - /// Recursive directory creation with optional mode and exist_ok flag + /// Recursive directory creation, creating parent directories as needed. + /// Raises FileExistsError if the directory already exists and exist_ok is false. /// See https://docs.python.org/3/library/os.html#os.makedirs + [] + abstract makedirs: path: string * exist_ok: bool -> unit + /// Recursive directory creation with explicit mode and exist_ok flag. + /// See https://docs.python.org/3/library/os.html#os.makedirs + [] abstract makedirs: path: string * mode: int * exist_ok: bool -> unit /// Set the environment variable named key to the string value /// See https://docs.python.org/3/library/os.html#os.putenv @@ -60,6 +72,15 @@ type IExports = /// Remove (delete) the directory path /// See https://docs.python.org/3/library/os.html#os.rmdir abstract rmdir: path: string -> unit + /// Walk a directory tree, yielding (dirpath, dirnames, filenames) for each directory. + /// When topdown is true (the default) the caller can modify the dirnames list in-place + /// to prune the search or impose a specific visiting order. + /// See https://docs.python.org/3/library/os.html#os.walk + abstract walk: top: string -> seq * ResizeArray> + /// Walk a directory tree top-down or bottom-up (topdown=false). + /// See https://docs.python.org/3/library/os.html#os.walk + [] + abstract walk: top: string * topdown: bool -> seq * ResizeArray> /// Test whether a path exists /// See https://docs.python.org/3/library/os.path.html#os.path.exists abstract path: PathModule @@ -96,6 +117,18 @@ and [] PathModule = /// Split the pathname path into a pair (root, ext) /// See https://docs.python.org/3/library/os.path.html#os.path.splitext abstract splitext: path: string -> string * string + /// Return True if path is an absolute pathname + /// See https://docs.python.org/3/library/os.path.html#os.path.isabs + abstract isabs: path: string -> bool + /// Return True if path refers to a symbolic link + /// See https://docs.python.org/3/library/os.path.html#os.path.islink + abstract islink: path: string -> bool + /// Return the canonical path of the specified filename, resolving symlinks + /// See https://docs.python.org/3/library/os.path.html#os.path.realpath + abstract realpath: path: string -> string + /// Return the size, in bytes, of path + /// See https://docs.python.org/3/library/os.path.html#os.path.getsize + abstract getsize: path: string -> int64 /// Miscellaneous operating system interfaces diff --git a/test/TestOs.fs b/test/TestOs.fs index 07a1488..a4f4045 100644 --- a/test/TestOs.fs +++ b/test/TestOs.fs @@ -58,3 +58,72 @@ let ``test os.listdir works`` () = let entries = os.listdir "." // Current directory should have at least some entries entries.Length > 0 |> equal true + +[] +let ``test os.path.isabs works`` () = + os.path.isabs "/absolute/path" |> equal true + os.path.isabs "relative/path" |> equal false + os.path.isabs "." |> equal false + +[] +let ``test os.path.realpath works`` () = + let real = os.path.realpath "." + real.StartsWith("/") |> equal true + // realpath should not contain symlink components; at minimum equal to abspath for "." + real.Length > 0 |> equal true + +[] +let ``test os.path.islink works`` () = + // "." is never a symlink + os.path.islink "." |> equal false + +[] +let ``test os.path.getsize works`` () = + // The test directory itself has a positive size + os.path.getsize "." > 0L |> equal true + +[] +let ``test os.getpid works`` () = + let pid = os.getpid () + pid > 0 |> equal true + +[] +let ``test os.getppid works`` () = + let ppid = os.getppid () + ppid > 0 |> equal true + +[] +let ``test os.makedirs with exist_ok works`` () = + let dir = sprintf "/tmp/fable_test_makedirs_%d" (os.getpid ()) + os.makedirs (dir, true) + os.path.isdir dir |> equal true + // Second call must not raise when exist_ok=true + os.makedirs (dir, true) + os.path.isdir dir |> equal true + os.rmdir dir + +[] +let ``test os.walk yields entries`` () = + let entries = os.walk "." |> Seq.truncate 1 |> Seq.toList + entries.Length |> equal 1 + let dirpath, subdirs, files = entries.[0] + dirpath |> equal "." + // The first walk entry's dirnames + filenames should equal listdir of the root + let walkAll = Seq.append subdirs files |> Seq.sort |> Seq.toList + let listdirAll = os.listdir "." |> Array.sort |> Array.toList + walkAll |> equal listdirAll + +[] +let ``test os.walk with topdown=false works`` () = + let root = sprintf "/tmp/fable_test_walk_%d" (os.getpid ()) + let nested = os.path.join (root, "nested") + os.makedirs (nested, true) + let entries = os.walk (root, false) |> Seq.toList + // Bottom-up: deepest dir is yielded first, root is yielded last + entries.Length |> equal 2 + let firstDir, _, _ = entries.[0] + let lastDir, _, _ = List.last entries + firstDir |> equal nested + lastDir |> equal root + os.rmdir nested + os.rmdir root