import * as $filepath from "../filepath/filepath.mjs"; import * as $bit_array from "../gleam_stdlib/gleam/bit_array.mjs"; import * as $int from "../gleam_stdlib/gleam/int.mjs"; import * as $list from "../gleam_stdlib/gleam/list.mjs"; import * as $result from "../gleam_stdlib/gleam/result.mjs"; import * as $set from "../gleam_stdlib/gleam/set.mjs"; import * as $string from "../gleam_stdlib/gleam/string.mjs"; import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend, CustomType as $CustomType, makeError, toBitArray, } from "./gleam.mjs"; import { fileInfo as file_info, linkInfo as link_info, readBits as read_bits, writeBits as write_bits, delete_ as delete$, deleteFile as delete_file, appendBits as append_bits, isDirectory as is_directory, createDirectory as create_directory, createSymlink as create_symlink, createLink as create_link, readDirectory as read_directory, isFile as is_file, isSymlink as is_symlink, createDirAll as do_create_dir_all, copyFile as do_copy_file, renameFile as rename_file, renameFile as rename, setPermissionsOctal as set_permissions_octal, currentDirectory as current_directory, } from "./simplifile_js.mjs"; export { append_bits, create_directory, create_link, create_symlink, current_directory, delete$, delete_file, file_info, is_directory, is_file, is_symlink, link_info, read_bits, read_directory, rename, rename_file, set_permissions_octal, write_bits, }; const FILEPATH = "src/simplifile.gleam"; /** * Permission denied. */ export class Eacces extends $CustomType {} export const FileError$Eacces = () => new Eacces(); export const FileError$isEacces = (value) => value instanceof Eacces; /** * Resource temporarily unavailable. */ export class Eagain extends $CustomType {} export const FileError$Eagain = () => new Eagain(); export const FileError$isEagain = (value) => value instanceof Eagain; /** * Bad file number */ export class Ebadf extends $CustomType {} export const FileError$Ebadf = () => new Ebadf(); export const FileError$isEbadf = (value) => value instanceof Ebadf; /** * Bad message. */ export class Ebadmsg extends $CustomType {} export const FileError$Ebadmsg = () => new Ebadmsg(); export const FileError$isEbadmsg = (value) => value instanceof Ebadmsg; /** * File busy. */ export class Ebusy extends $CustomType {} export const FileError$Ebusy = () => new Ebusy(); export const FileError$isEbusy = (value) => value instanceof Ebusy; /** * Resource deadlock avoided. */ export class Edeadlk extends $CustomType {} export const FileError$Edeadlk = () => new Edeadlk(); export const FileError$isEdeadlk = (value) => value instanceof Edeadlk; /** * On most architectures, same as `Edeadlk`. On some architectures, it * means "File locking deadlock error." */ export class Edeadlock extends $CustomType {} export const FileError$Edeadlock = () => new Edeadlock(); export const FileError$isEdeadlock = (value) => value instanceof Edeadlock; /** * Disk quota exceeded. */ export class Edquot extends $CustomType {} export const FileError$Edquot = () => new Edquot(); export const FileError$isEdquot = (value) => value instanceof Edquot; /** * File already exists. */ export class Eexist extends $CustomType {} export const FileError$Eexist = () => new Eexist(); export const FileError$isEexist = (value) => value instanceof Eexist; /** * Bad address in system call argument. */ export class Efault extends $CustomType {} export const FileError$Efault = () => new Efault(); export const FileError$isEfault = (value) => value instanceof Efault; /** * File too large. */ export class Efbig extends $CustomType {} export const FileError$Efbig = () => new Efbig(); export const FileError$isEfbig = (value) => value instanceof Efbig; /** * Inappropriate file type or format. Usually caused by trying to set the * "sticky bit" on a regular file (not a directory). */ export class Eftype extends $CustomType {} export const FileError$Eftype = () => new Eftype(); export const FileError$isEftype = (value) => value instanceof Eftype; /** * Interrupted system call. */ export class Eintr extends $CustomType {} export const FileError$Eintr = () => new Eintr(); export const FileError$isEintr = (value) => value instanceof Eintr; /** * Invalid argument. */ export class Einval extends $CustomType {} export const FileError$Einval = () => new Einval(); export const FileError$isEinval = (value) => value instanceof Einval; /** * I/O error. */ export class Eio extends $CustomType {} export const FileError$Eio = () => new Eio(); export const FileError$isEio = (value) => value instanceof Eio; /** * Illegal operation on a directory. */ export class Eisdir extends $CustomType {} export const FileError$Eisdir = () => new Eisdir(); export const FileError$isEisdir = (value) => value instanceof Eisdir; /** * Too many levels of symbolic links. */ export class Eloop extends $CustomType {} export const FileError$Eloop = () => new Eloop(); export const FileError$isEloop = (value) => value instanceof Eloop; /** * Too many open files. */ export class Emfile extends $CustomType {} export const FileError$Emfile = () => new Emfile(); export const FileError$isEmfile = (value) => value instanceof Emfile; /** * Too many links. */ export class Emlink extends $CustomType {} export const FileError$Emlink = () => new Emlink(); export const FileError$isEmlink = (value) => value instanceof Emlink; /** * Multihop attempted. */ export class Emultihop extends $CustomType {} export const FileError$Emultihop = () => new Emultihop(); export const FileError$isEmultihop = (value) => value instanceof Emultihop; /** * Filename too long */ export class Enametoolong extends $CustomType {} export const FileError$Enametoolong = () => new Enametoolong(); export const FileError$isEnametoolong = (value) => value instanceof Enametoolong; /** * File table overflow */ export class Enfile extends $CustomType {} export const FileError$Enfile = () => new Enfile(); export const FileError$isEnfile = (value) => value instanceof Enfile; /** * No buffer space available. */ export class Enobufs extends $CustomType {} export const FileError$Enobufs = () => new Enobufs(); export const FileError$isEnobufs = (value) => value instanceof Enobufs; /** * No such device. */ export class Enodev extends $CustomType {} export const FileError$Enodev = () => new Enodev(); export const FileError$isEnodev = (value) => value instanceof Enodev; /** * No locks available. */ export class Enolck extends $CustomType {} export const FileError$Enolck = () => new Enolck(); export const FileError$isEnolck = (value) => value instanceof Enolck; /** * Link has been severed. */ export class Enolink extends $CustomType {} export const FileError$Enolink = () => new Enolink(); export const FileError$isEnolink = (value) => value instanceof Enolink; /** * No such file or directory. */ export class Enoent extends $CustomType {} export const FileError$Enoent = () => new Enoent(); export const FileError$isEnoent = (value) => value instanceof Enoent; /** * Not enough memory. */ export class Enomem extends $CustomType {} export const FileError$Enomem = () => new Enomem(); export const FileError$isEnomem = (value) => value instanceof Enomem; /** * No space left on device. */ export class Enospc extends $CustomType {} export const FileError$Enospc = () => new Enospc(); export const FileError$isEnospc = (value) => value instanceof Enospc; /** * No STREAM resources. */ export class Enosr extends $CustomType {} export const FileError$Enosr = () => new Enosr(); export const FileError$isEnosr = (value) => value instanceof Enosr; /** * Not a STREAM. */ export class Enostr extends $CustomType {} export const FileError$Enostr = () => new Enostr(); export const FileError$isEnostr = (value) => value instanceof Enostr; /** * Function not implemented. */ export class Enosys extends $CustomType {} export const FileError$Enosys = () => new Enosys(); export const FileError$isEnosys = (value) => value instanceof Enosys; /** * Block device required. */ export class Enotblk extends $CustomType {} export const FileError$Enotblk = () => new Enotblk(); export const FileError$isEnotblk = (value) => value instanceof Enotblk; /** * Not a directory. */ export class Enotdir extends $CustomType {} export const FileError$Enotdir = () => new Enotdir(); export const FileError$isEnotdir = (value) => value instanceof Enotdir; /** * Operation not supported. */ export class Enotsup extends $CustomType {} export const FileError$Enotsup = () => new Enotsup(); export const FileError$isEnotsup = (value) => value instanceof Enotsup; /** * No such device or address. */ export class Enxio extends $CustomType {} export const FileError$Enxio = () => new Enxio(); export const FileError$isEnxio = (value) => value instanceof Enxio; /** * Operation not supported on socket. */ export class Eopnotsupp extends $CustomType {} export const FileError$Eopnotsupp = () => new Eopnotsupp(); export const FileError$isEopnotsupp = (value) => value instanceof Eopnotsupp; /** * Value too large to be stored in data type. */ export class Eoverflow extends $CustomType {} export const FileError$Eoverflow = () => new Eoverflow(); export const FileError$isEoverflow = (value) => value instanceof Eoverflow; /** * Not owner. */ export class Eperm extends $CustomType {} export const FileError$Eperm = () => new Eperm(); export const FileError$isEperm = (value) => value instanceof Eperm; /** * Broken pipe. */ export class Epipe extends $CustomType {} export const FileError$Epipe = () => new Epipe(); export const FileError$isEpipe = (value) => value instanceof Epipe; /** * Result too large. */ export class Erange extends $CustomType {} export const FileError$Erange = () => new Erange(); export const FileError$isErange = (value) => value instanceof Erange; /** * Read-only file system. */ export class Erofs extends $CustomType {} export const FileError$Erofs = () => new Erofs(); export const FileError$isErofs = (value) => value instanceof Erofs; /** * Invalid seek. */ export class Espipe extends $CustomType {} export const FileError$Espipe = () => new Espipe(); export const FileError$isEspipe = (value) => value instanceof Espipe; /** * No such process. */ export class Esrch extends $CustomType {} export const FileError$Esrch = () => new Esrch(); export const FileError$isEsrch = (value) => value instanceof Esrch; /** * Stale remote file handle. */ export class Estale extends $CustomType {} export const FileError$Estale = () => new Estale(); export const FileError$isEstale = (value) => value instanceof Estale; /** * Text file busy. */ export class Etxtbsy extends $CustomType {} export const FileError$Etxtbsy = () => new Etxtbsy(); export const FileError$isEtxtbsy = (value) => value instanceof Etxtbsy; /** * Cross-domain link. */ export class Exdev extends $CustomType {} export const FileError$Exdev = () => new Exdev(); export const FileError$isExdev = (value) => value instanceof Exdev; /** * File was requested to be read as UTF-8, but is not UTF-8 encoded. */ export class NotUtf8 extends $CustomType {} export const FileError$NotUtf8 = () => new NotUtf8(); export const FileError$isNotUtf8 = (value) => value instanceof NotUtf8; /** * Any error not accounted for by this type */ export class Unknown extends $CustomType { constructor(inner) { super(); this.inner = inner; } } export const FileError$Unknown = (inner) => new Unknown(inner); export const FileError$isUnknown = (value) => value instanceof Unknown; export const FileError$Unknown$inner = (value) => value.inner; export const FileError$Unknown$0 = (value) => value.inner; export class FileInfo extends $CustomType { constructor(size, mode, nlinks, inode, user_id, group_id, dev, atime_seconds, mtime_seconds, ctime_seconds) { super(); this.size = size; this.mode = mode; this.nlinks = nlinks; this.inode = inode; this.user_id = user_id; this.group_id = group_id; this.dev = dev; this.atime_seconds = atime_seconds; this.mtime_seconds = mtime_seconds; this.ctime_seconds = ctime_seconds; } } export const FileInfo$FileInfo = (size, mode, nlinks, inode, user_id, group_id, dev, atime_seconds, mtime_seconds, ctime_seconds) => new FileInfo(size, mode, nlinks, inode, user_id, group_id, dev, atime_seconds, mtime_seconds, ctime_seconds); export const FileInfo$isFileInfo = (value) => value instanceof FileInfo; export const FileInfo$FileInfo$size = (value) => value.size; export const FileInfo$FileInfo$0 = (value) => value.size; export const FileInfo$FileInfo$mode = (value) => value.mode; export const FileInfo$FileInfo$1 = (value) => value.mode; export const FileInfo$FileInfo$nlinks = (value) => value.nlinks; export const FileInfo$FileInfo$2 = (value) => value.nlinks; export const FileInfo$FileInfo$inode = (value) => value.inode; export const FileInfo$FileInfo$3 = (value) => value.inode; export const FileInfo$FileInfo$user_id = (value) => value.user_id; export const FileInfo$FileInfo$4 = (value) => value.user_id; export const FileInfo$FileInfo$group_id = (value) => value.group_id; export const FileInfo$FileInfo$5 = (value) => value.group_id; export const FileInfo$FileInfo$dev = (value) => value.dev; export const FileInfo$FileInfo$6 = (value) => value.dev; export const FileInfo$FileInfo$atime_seconds = (value) => value.atime_seconds; export const FileInfo$FileInfo$7 = (value) => value.atime_seconds; export const FileInfo$FileInfo$mtime_seconds = (value) => value.mtime_seconds; export const FileInfo$FileInfo$8 = (value) => value.mtime_seconds; export const FileInfo$FileInfo$ctime_seconds = (value) => value.ctime_seconds; export const FileInfo$FileInfo$9 = (value) => value.ctime_seconds; /** * A regular file */ export class File extends $CustomType {} export const FileType$File = () => new File(); export const FileType$isFile = (value) => value instanceof File; /** * A directory */ export class Directory extends $CustomType {} export const FileType$Directory = () => new Directory(); export const FileType$isDirectory = (value) => value instanceof Directory; /** * A symbolic link */ export class Symlink extends $CustomType {} export const FileType$Symlink = () => new Symlink(); export const FileType$isSymlink = (value) => value instanceof Symlink; /** * Another special file type present on some systems, lika a socket or device */ export class Other extends $CustomType {} export const FileType$Other = () => new Other(); export const FileType$isOther = (value) => value instanceof Other; export class Read extends $CustomType {} export const Permission$Read = () => new Read(); export const Permission$isRead = (value) => value instanceof Read; export class Write extends $CustomType {} export const Permission$Write = () => new Write(); export const Permission$isWrite = (value) => value instanceof Write; export class Execute extends $CustomType {} export const Permission$Execute = () => new Execute(); export const Permission$isExecute = (value) => value instanceof Execute; export class FilePermissions extends $CustomType { constructor(user, group, other) { super(); this.user = user; this.group = group; this.other = other; } } export const FilePermissions$FilePermissions = (user, group, other) => new FilePermissions(user, group, other); export const FilePermissions$isFilePermissions = (value) => value instanceof FilePermissions; export const FilePermissions$FilePermissions$user = (value) => value.user; export const FilePermissions$FilePermissions$0 = (value) => value.user; export const FilePermissions$FilePermissions$group = (value) => value.group; export const FilePermissions$FilePermissions$1 = (value) => value.group; export const FilePermissions$FilePermissions$other = (value) => value.other; export const FilePermissions$FilePermissions$2 = (value) => value.other; /** * Convert an error into a human-readable description * ## Example * ```gleam * let assert "Input/output error" = describe_error(Eio) * ``` */ export function describe_error(error) { if (error instanceof Eacces) { return "Permission denied"; } else if (error instanceof Eagain) { return "Resource temporarily unavailable"; } else if (error instanceof Ebadf) { return "Bad file descriptor"; } else if (error instanceof Ebadmsg) { return "Bad message"; } else if (error instanceof Ebusy) { return "Resource busy"; } else if (error instanceof Edeadlk) { return "Resource deadlock avoided"; } else if (error instanceof Edeadlock) { return "Resource deadlock avoided"; } else if (error instanceof Edquot) { return "Disc quota exceeded"; } else if (error instanceof Eexist) { return "File exists"; } else if (error instanceof Efault) { return "Bad address"; } else if (error instanceof Efbig) { return "File too large"; } else if (error instanceof Eftype) { return "Inappropriate file type or format"; } else if (error instanceof Eintr) { return "Interrupted system call"; } else if (error instanceof Einval) { return "Invalid argument"; } else if (error instanceof Eio) { return "Input/output error"; } else if (error instanceof Eisdir) { return "Is a directory"; } else if (error instanceof Eloop) { return "Too many levels of symbolic links"; } else if (error instanceof Emfile) { return "Too many open files"; } else if (error instanceof Emlink) { return "Too many links"; } else if (error instanceof Emultihop) { return "Multihop attempted"; } else if (error instanceof Enametoolong) { return "File name too long"; } else if (error instanceof Enfile) { return "Too many open files in system"; } else if (error instanceof Enobufs) { return "No buffer space available"; } else if (error instanceof Enodev) { return "Operation not supported by device"; } else if (error instanceof Enolck) { return "No locks available"; } else if (error instanceof Enolink) { return "Link has been severed"; } else if (error instanceof Enoent) { return "No such file or directory"; } else if (error instanceof Enomem) { return "Cannot allocate memory"; } else if (error instanceof Enospc) { return "No space left on device"; } else if (error instanceof Enosr) { return "No STREAM resources"; } else if (error instanceof Enostr) { return "Not a STREAM"; } else if (error instanceof Enosys) { return "Function not implemented"; } else if (error instanceof Enotblk) { return "Block device required"; } else if (error instanceof Enotdir) { return "Not a directory"; } else if (error instanceof Enotsup) { return "Operation not supported"; } else if (error instanceof Enxio) { return "Device not configured"; } else if (error instanceof Eopnotsupp) { return "Operation not supported on socket"; } else if (error instanceof Eoverflow) { return "Value too large to be stored in data type"; } else if (error instanceof Eperm) { return "Operation not permitted"; } else if (error instanceof Epipe) { return "Broken pipe"; } else if (error instanceof Erange) { return "Result too large"; } else if (error instanceof Erofs) { return "Read-only file system"; } else if (error instanceof Espipe) { return "Illegal seek"; } else if (error instanceof Esrch) { return "No such process"; } else if (error instanceof Estale) { return "Stale NFS file handle"; } else if (error instanceof Etxtbsy) { return "Text file busy"; } else if (error instanceof Exdev) { return "Cross-device link"; } else if (error instanceof NotUtf8) { return "File not UTF-8 encoded"; } else { let inner = error.inner; return "Unknown error: " + inner; } } /** * Extract the file permissions from a given FileInfo value in their octal representation. * * ## Example * ```gleam * use info <- result.try(simplifile.file_info("src/app.gleam")) * simplifile.file_info_permissions_octal(info) * // --> 0o644 * ``` */ export function file_info_permissions_octal(file_info) { return $int.bitwise_and(file_info.mode, 0o777); } function integer_to_permissions(integer) { let $ = $int.bitwise_and(integer, 7); if ($ === 7) { return $set.from_list(toList([new Read(), new Write(), new Execute()])); } else if ($ === 6) { return $set.from_list(toList([new Read(), new Write()])); } else if ($ === 5) { return $set.from_list(toList([new Read(), new Execute()])); } else if ($ === 3) { return $set.from_list(toList([new Write(), new Execute()])); } else if ($ === 4) { return $set.from_list(toList([new Read()])); } else if ($ === 2) { return $set.from_list(toList([new Write()])); } else if ($ === 1) { return $set.from_list(toList([new Execute()])); } else if ($ === 0) { return $set.new$(); } else { throw makeError( "panic", FILEPATH, "simplifile", 674, "integer_to_permissions", "`panic` expression evaluated.", {} ) } } function octal_to_file_permissions(octal) { return new FilePermissions( (() => { let _pipe = octal; let _pipe$1 = $int.bitwise_shift_right(_pipe, 6); return integer_to_permissions(_pipe$1); })(), (() => { let _pipe = octal; let _pipe$1 = $int.bitwise_shift_right(_pipe, 3); return integer_to_permissions(_pipe$1); })(), (() => { let _pipe = octal; return integer_to_permissions(_pipe); })(), ); } /** * Extract the `FilePermissions` from a given FileInfo value. */ export function file_info_permissions(file_info) { return octal_to_file_permissions(file_info_permissions_octal(file_info)); } /** * Extract the file type from a given FileInfo value. * * ## Example * ```gleam * use info <- result.try(simplifile.file_info("src/app.gleam")) * simplifile.file_info_type(info) * // --> simplifile.File * ``` */ export function file_info_type(file_info) { let $ = $int.bitwise_and(file_info.mode, 0o170000); if ($ === 32768) { return new File(); } else if ($ === 16384) { return new Directory(); } else if ($ === 40960) { return new Symlink(); } else { return new Other(); } } /** * Read a files contents as a string * ## Example * ```gleam * let assert Ok(records) = read(from: "./users.csv") * ``` */ export function read(filepath) { let $ = read_bits(filepath); if ($ instanceof Ok) { let bits = $[0]; let $1 = $bit_array.to_string(bits); if ($1 instanceof Ok) { return $1; } else { return new Error(new NotUtf8()); } } else { return $; } } /** * Write a string to a file at the given path * ## Example * ```gleam * let assert Ok(Nil) = write(to: "./hello_world.txt", contents: "Hello, World!") * ``` */ export function write(filepath, contents) { let _pipe = contents; let _pipe$1 = $bit_array.from_string(_pipe); return write_bits(filepath, _pipe$1); } /** * Delete all files/directories specified in a list of paths. * Recursively deletes provided directories. * Does not return an error if one or more of the provided paths * do not exist. */ export function delete_all(loop$paths) { while (true) { let paths = loop$paths; if (paths instanceof $Empty) { return new Ok(undefined); } else { let path = paths.head; let rest = paths.tail; let $ = delete$(path); if ($ instanceof Ok) { loop$paths = rest; } else { let $1 = $[0]; if ($1 instanceof Enoent) { loop$paths = rest; } else { return $; } } } } } /** * Append a string to the contents of a file at the given path * ## Example * ```gleam * let assert Ok(Nil) = append(to: "./needs_more_text.txt", contents: "more text") * ``` */ export function append(filepath, contents) { let _pipe = contents; let _pipe$1 = $bit_array.from_string(_pipe); return append_bits(filepath, _pipe$1); } /** * Creates an empty file at the given filepath. Returns an `Error(Eexist)` * if the file already exists. */ export function create_file(filepath) { let $ = (() => { let _pipe = filepath; return is_file(_pipe); })(); let $1 = (() => { let _pipe = filepath; return is_directory(_pipe); })(); if ($ instanceof Ok) { let $2 = $[0]; if ($2) { return new Error(new Eexist()); } else if ($1 instanceof Ok) { let $3 = $1[0]; if ($3) { return new Error(new Eexist()); } else { return write_bits(filepath, toBitArray([])); } } else { return write_bits(filepath, toBitArray([])); } } else if ($1 instanceof Ok) { let $2 = $1[0]; if ($2) { return new Error(new Eexist()); } else { return write_bits(filepath, toBitArray([])); } } else { return write_bits(filepath, toBitArray([])); } } /** * Recursively creates necessary directories for a given directory * path. Note that if you pass a path that "looks like" a file, i.e. * `./a/b.txt`, a folder named `b.txt` will be created, so be sure * to pass only the path to the required directory. */ export function create_directory_all(dirpath) { return do_create_dir_all(dirpath + "/"); } function do_copy_directory(src, dest) { return $result.try$( read_directory(src), (segments) => { let _pipe = segments; $list.each( _pipe, (segment) => { let src_path = $filepath.join(src, segment); let dest_path = $filepath.join(dest, segment); return $result.try$( file_info(src_path), (src_info) => { let $ = file_info_type(src_info); if ($ instanceof File) { return $result.try$( read_bits(src_path), (content) => { let _pipe$1 = content; return write_bits(dest_path, _pipe$1); }, ); } else if ($ instanceof Directory) { return $result.try$( create_directory(dest_path), (_) => { return do_copy_directory(src_path, dest_path); }, ); } else if ($ instanceof Symlink) { return new Error( new Unknown( "This is an internal bug where the `file_info` is somehow returning info about a simlink. Please file an issue on the simplifile repo.", ), ); } else { return new Error( new Unknown( "Unknown file type (not file, directory, or simlink)", ), ); } }, ); }, ); return new Ok(undefined); }, ); } /** * Copy a directory recursively */ export function copy_directory(src, dest) { return $result.try$( create_directory_all(dest), (_) => { return do_copy_directory(src, dest); }, ); } /** * Copy a file at a given path to another path. * Note: destination should include the filename, not just the directory */ export function copy_file(src, dest) { let _pipe = do_copy_file(src, dest); return $result.replace(_pipe, undefined); } /** * Copy a file or a directory to a new path. Copies directories recursively. * * ### Performance Note * This function does work to determine if the src path * points to a file or a directory. Consider using one of the the dedicated * functions `copy_file` or `copy_directory` if you already know which one you need. */ export function copy(src, dest) { return $result.try$( file_info(src), (src_info) => { let $ = file_info_type(src_info); if ($ instanceof File) { return copy_file(src, dest); } else if ($ instanceof Directory) { return copy_directory(src, dest); } else if ($ instanceof Symlink) { return new Error( new Unknown( "This is an internal bug where the `file_info` is somehow returning info about a simlink. Please file an issue on the simplifile repo.", ), ); } else { return new Error( new Unknown("Unknown file type (not file, directory, or simlink)"), ); } }, ); } /** * Copy a directory recursively and then delete the old one. */ export function rename_directory(src, dest) { return $result.try$( copy_directory(src, dest), (_) => { return delete$(src); }, ); } /** * Clear the contents of a directory, deleting all files and directories within * but leaving the top level directory in place. */ export function clear_directory(path) { return $result.try$( read_directory(path), (paths) => { let _pipe = paths; let _pipe$1 = $list.map( _pipe, (_capture) => { return $filepath.join(path, _capture); }, ); return delete_all(_pipe$1); }, ); } /** * Returns a list of filepaths for every file in the directory, including nested * files. */ export function get_files(directory) { return $result.try$( read_directory(directory), (contents) => { return $list.try_fold( contents, toList([]), (acc, content) => { let path = $filepath.join(directory, content); return $result.try$( file_info(path), (info) => { let $ = file_info_type(info); if ($ instanceof File) { return new Ok(listPrepend(path, acc)); } else if ($ instanceof Directory) { return $result.try$( get_files(path), (nested_files) => { return new Ok($list.append(acc, nested_files)); }, ); } else { return new Ok(acc); } }, ); }, ); }, ); } function permission_to_integer(permission) { if (permission instanceof Read) { return 0o4; } else if (permission instanceof Write) { return 0o2; } else { return 0o1; } } export function file_permissions_to_octal(permissions) { let make_permission_digit = (permissions) => { let _pipe = permissions; let _pipe$1 = $set.to_list(_pipe); let _pipe$2 = $list.map(_pipe$1, permission_to_integer); return $int.sum(_pipe$2); }; return (make_permission_digit(permissions.user) * 64 + make_permission_digit( permissions.group, ) * 8) + make_permission_digit(permissions.other); } /** * Sets the permissions for a given file * * # Example * ```gleam * let all = set.from_list([Read, Write, Execute]) * let all = FilePermissions(user: all, group: all, other: all) * let assert Ok(Nil) = set_permissions("./script.sh", all) * ``` */ export function set_permissions(filepath, permissions) { return set_permissions_octal(filepath, file_permissions_to_octal(permissions)); }