refactor: bunpen: config/translate_opts: make the autodetect logic not pollute the hardcoded path ingestion quite so much
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
// ingest literal `cli_opts` into a more computer-friendly form
|
||||
|
||||
use errors;
|
||||
use errors::ext;
|
||||
use fs;
|
||||
use log;
|
||||
@@ -89,17 +90,38 @@ export fn ingest_cli_opts(opts: cli_opts) (cli_request | help) = {
|
||||
// if `allow_abs`, then paths with start with `/` are treated as absolute,
|
||||
// instead of as relative to `base`.
|
||||
fn ingest_paths(into: *[]path::buffer, from: []str, base: (str | void), allow_abs: bool = false, method: (void | autodetect) = void) void = {
|
||||
// enforce file mode requirements as per autodetect (if specified)
|
||||
let (allow_nonexistent, allow_file, allow_dir, allow_parent) = match (method) {
|
||||
case void => yield (true, true, true, false);
|
||||
case let detect: autodetect => yield switch (detect) {
|
||||
case autodetect::EXISTING => yield (false, true, true, false);
|
||||
case autodetect::EXISTING_FILE => yield (false, true, false, false);
|
||||
case autodetect::EXISTING_FILE_OR_PARENT => yield (false, true, false, true);
|
||||
case autodetect::EXISTING_OR_PARENT => yield (false, true, true, true);
|
||||
case autodetect::PARENT => yield (false, false, false, true);
|
||||
};
|
||||
};
|
||||
|
||||
for (let path_str .. from) {
|
||||
errors::ext::swallow("[config/path] omitting path {}",
|
||||
try_as_path(into, path_str, base, allow_abs, method),
|
||||
try_as_path(into, path_str, base, allow_abs, allow_nonexistent, allow_file, allow_dir, allow_parent),
|
||||
path_str
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
// consider the `path_arg` in the context of the autodetect `method`, and append
|
||||
// either that path, its parent, or neither.
|
||||
fn try_as_path(into: *[]path::buffer, path_arg: str, base: (str | void), allow_abs: bool, method: (void | autodetect)) (void | fs::error | path::error) = {
|
||||
// consider the `path_arg` in the context of the `allow_*` restrictions,
|
||||
// and append either that path, its parent, or neither.
|
||||
fn try_as_path(
|
||||
into: *[]path::buffer,
|
||||
path_arg: str,
|
||||
base: (str | void),
|
||||
allow_abs: bool,
|
||||
allow_nonexistent: bool,
|
||||
allow_file: bool,
|
||||
allow_dir: bool,
|
||||
allow_parent: bool,
|
||||
) (void | fs::error | path::error) = {
|
||||
let path_buf = if (allow_abs && path::abs(path_arg)) {
|
||||
yield path::init(path_arg)?;
|
||||
} else match (base) {
|
||||
@@ -109,48 +131,38 @@ fn try_as_path(into: *[]path::buffer, path_arg: str, base: (str | void), allow_a
|
||||
return path::not_prefix;
|
||||
};
|
||||
|
||||
// enforce file mode requirements as per autodetect (if specified),
|
||||
// possibly changes `path_buf` to point to its parent.
|
||||
match (method) {
|
||||
case void => void;
|
||||
case let detect: autodetect => switch (detect) {
|
||||
case autodetect::EXISTING =>
|
||||
check_exists(&path_buf, true)?;
|
||||
case autodetect::EXISTING_FILE =>
|
||||
check_exists(&path_buf, false)?;
|
||||
case autodetect::EXISTING_FILE_OR_PARENT =>
|
||||
match (check_exists(&path_buf, false)) {
|
||||
case void => void;
|
||||
case =>
|
||||
path::push(&path_buf, "..")?;
|
||||
check_exists(&path_buf, true)?;
|
||||
};
|
||||
case autodetect::EXISTING_OR_PARENT =>
|
||||
match (check_exists(&path_buf, true)) {
|
||||
case void => void;
|
||||
case =>
|
||||
path::push(&path_buf, "..")?;
|
||||
check_exists(&path_buf, true)?;
|
||||
};
|
||||
case autodetect::PARENT =>
|
||||
path::push(&path_buf, "..")?;
|
||||
check_exists(&path_buf, true)?;
|
||||
};
|
||||
if (allow_nonexistent)
|
||||
return append(into, path_buf);
|
||||
|
||||
// try the path
|
||||
let err = match (check_exists(&path_buf, allow_file, allow_dir)) {
|
||||
case void => return append(into, path_buf);
|
||||
case let err: (fs::error | path::error) => yield err;
|
||||
};
|
||||
|
||||
append(into, path_buf);
|
||||
// try the parent
|
||||
if (allow_parent) {
|
||||
path::push(&path_buf, "..")?;
|
||||
check_exists(&path_buf, false, true)?;
|
||||
return append(into, path_buf);
|
||||
};
|
||||
return err;
|
||||
};
|
||||
|
||||
// ensure that the specified path exists.
|
||||
// if it exists but not as a directory, succeed only if `dir_ok = true`.
|
||||
fn check_exists(pathbuf: *path::buffer, dir_ok: bool) (void | fs::error | path::error) = {
|
||||
fn check_exists(pathbuf: *path::buffer, file_ok: bool, dir_ok: bool) (void | fs::error | path::error) = {
|
||||
if (!file_ok && !dir_ok)
|
||||
return errors::invalid; // save a syscall for `--bunpen-autodetect parent`
|
||||
|
||||
// stat the path. in case of symlinks dereference to the underlying entity.
|
||||
let dereferenced = fs::realpath(os::cwd, path::string(pathbuf))?;
|
||||
let stat = fs::stat(os::cwd, dereferenced)?;
|
||||
let is_dir = (stat.mode & rt::S_IFDIR) != 0;
|
||||
|
||||
if (is_dir && !dir_ok) {
|
||||
log::printfln("[config/path/try] not adding path (wanted a file, but this is a directory): {}", path::string(pathbuf));
|
||||
if (is_dir && dir_ok || !is_dir && file_ok)
|
||||
return
|
||||
|
||||
log::printfln("[config/path/try] not adding path (exists, but as wrong type): {}", path::string(pathbuf));
|
||||
return fs::wrongtype;
|
||||
};
|
||||
};
|
||||
|
Reference in New Issue
Block a user