Civboot's unix system library
Civix contains standard unix functions that exist in most language's "sys"
library such as
sleep,
epoch etc. It also contains a powerful
Sh{} type
and convieience
sh() function for executing system shell commands, either
synchronously or asynchronously using the LAP protocol (see
#Package_lap.
$ lua
> sh = require'civix'.sh
> print(sh'ls some/path')
> -- cat /var/log/syslog | grep "netgroup: version"
> out = sh{stdin=io.open'/var/log/syslog', 'grep', 'netgroup: version'}
> for line in require'ds'.lines(out) do ... something per line ... end
Civix depends on the
#Package_fd library for async file descriptors and
other filedescriptor functionality.
civix: unix-like OS utilities.
Types: B Walk Sh ShFin
Functions
- fn mkdir(path)
- fn dir(path)
- fn rmdir(path)
- fn exists(path)
- fn pathtype(path)
- fn rm(path) -> nil
remove file.
- fn statModifiedEq(fs1, fs2) -> boolean
return whether two Stat's have equal modification times
- fn stat(v) -> Stat?, errmsg?
Given a path|File|Stat return a Stat
- fn modifiedEq(a, b)
return whether two path|File|Stat have equal modification times
- fn getpagesize() -> 4096
- fn ls(dir) -> list[str]
Return the entries in a dir as a list.
They are sorted to put the directories first.
- fn mv(old, new)
Move path from old -> new, throwing an error on failure.
- fn fdWrite(to, from, sz--[[=BLOCK_SZ]]) -> (to, from)
Read data from fd from and write to fd to, then flush.
- fn cp(from, to)
copy data from from to to. Their types can be either
a string (path) or a file descriptor.
- fn swap(a, b, ext)
swap paths a <-> b
- fn setModified(f, sec, nsec) -> ok, errmsg?
set the modified time of the path|file
- fn quote(str)
quote the str if it's possible
- fn sleep(d) -> nil
Sleep for the specified duration
- fn epoch() -> ds.Epoch(lib.epoch())
Return the Epoch/Mono time
Time according to realtime clock
- fn mono() -> ds.Duration(lib.mono())
Duration according to monotomically incrementing clock.
- fn monoSec() -> M.mono():asSeconds()
- fn pathEq(path1, path2)
return if the contents of the two paths are equal.
If both are directories return true (do not recurse).
If both don't exist return true
- fn isFile(path) -> M.pathtype(path) == 'file'
- fn isDir(path) -> M.pathtype(path) == 'dir'
- fn walk(paths, ftypeFns, maxDepth)
TODO: remove this, use Walk instead.
walk the paths up to depth, calling ftypeFns[ftype] for
each item encountered.
If depth is nil/false then the depth is infinite.
ftypeFns must be a table of ftypes (file, dir) and:
- default: called as fallback (if missing ftype key)
- error: called if determining the type caused an error,
typically due to the file not existing.
the call is: error(path, errstr)
- dirDone: called AFTER the directory has been walked
The Fn signatures are: (path, ftype) -> stopWalk
If either return true then the walk is ended immediately
If dirFn returns 'skip' then the directory is skipped
- fn cpRecursive(from, to, except)
recursively copy from/ to new to/ directory.
- fn rmRecursive(path)
- fn mkDirs(path)
- fn mkDir(path, parents)
- fn forceCp(from, to)
copy from to to, creating the directory structure if necessary.
- fn forceWrite(path, text)
write text to path, creating the directory structure if necessary.
- fn forceMv(old, new)
Force move a file or directory, creating directory structure
if necessary.
- fn mkTree(dir, tree, parents)
mkTree(tree) builds a tree of files and dirs at `dir`
- Dirs are tables.
- Files are string or fd -- which are read+closed.
Example: tree = {
a = {
['a1.txt'] = 'stuff in a1.txt',
['a2.txt'] = 'stuff in a.txt',
a3 = {
['a4.txt'] = io.open'some/file.txt',
}
}
}
Builds a tree like a/a1.txt # content: stuff in a1.txt
a/a2.txt # content: stuff in a2.txt
a/a3/a4.txt # content: stuff in a3.txt
- fn Lap()
- fn sh(M,'sh') -> out, err, Sh
Execute the command in another process via execvp (system shell). Throws an
error if the command fails.
if cmd is a table, the following keys are treated as special. If you need any
of these then you must use M.Sh directly (recommendation: use Plumb)
- stdin[string|file] the process's stdin. If string it will be sent to stdin.
- stdout[file] the process's stdout. out will be nil if this is set
- stderr[file] the process's stderr (default=io.stderr)
- ENV [table] the process's environment.
- CWD [table] the process's current directory.
- rc [bool] if true allow non-zero return codes (else throw error).
You can get the rc with sh:rc() (method on 3rd return argument).
Note: use Plumb{...}:run() if you want to pipe multiple shells together.
| Command Bash |
| sh'ls foo/bar' |
ls foo/bar |
| sh{'ls', 'foo/bar', 'dir w spc/'} |
ls foo/bar "dir w spc/" |
| sh{stdin='sent to stdin', 'cat'} |
echo "sent to stdin" | cat |
- fn isRoot() -> os.getenv'EUID' == '0'
Several (but not all) functions in this module are used for civ.lua.
However, native modules especially cannot be loaded before the
bulid system is bootstrapped (at least not easily), so there are
a few of these checks for NOLIB in this library which will use
civix.B (bootstrap) instead in that case.
Clients should typically not use civix.B.
Functions
Walk the directory tree as a iterator of
path, ftype. Can walk either a
single path
Walk'path/' or a list of paths
Walk{'a/', 'b.txt'}.
- Note: all ftype=='dir' paths end in /.
- Warning: you may want to handle ftype=='error'
Fields:
- .maxDepthmaximum depth to walk (default=infinite)
- .pi =0the current (root) path index being walked
Methods
- fn depth(w) -> #w._dirs
- get the depth of the current directory being walked
- fn skip(w._dirs)
skip the current directory level
Start args on the shell
Suggestion: use civix.sh instead.
Sh:start() kicks off a subprocess which start the shell using the fds
you pass in or creating them if you set them to true. Created file
descriptors will be stored in the associated name.
Why? This means that :close() will only close filedescriptors created
by the shell itself, and you won't accidentially close
io.stdout/etc.
Examples (see civix.sh for more examples):
| Lua |
Bash |
| Sh({'ls', 'foo/bar'}, {stdout=io.stdout}):start() |
ls foo/bar |
| v = Sh{'ls foo/bar', stdout=true}:start():read'a' |
v=$(ls foo/bar) |
Fields:
- .argsarguments to pass to shell
- .stdinshell's stdin to send (default=empty)
- .stdoutshell's stdout (default=empty)
- .stderrshell's stderr (default=empty)
- .envshell's environment {'FOO=bar', ...}
- .cwdcurrent working directory
Methods
Fields:
test runners and helpers for civix
Functions