mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
feat(cli/installer): Add missing flags for deno install (#7601)
This commit adds support for following flags: - deno install --importmap - deno install --no-remote - deno install --lock - deno install --lock-write - deno install --cached-only - deno install --v8-flags - deno install --seed
This commit is contained in:
parent
9d664f8375
commit
3f5513758d
9 changed files with 110 additions and 167 deletions
151
cli/flags.rs
151
cli/flags.rs
|
@ -110,7 +110,7 @@ pub struct Flags {
|
|||
pub import_map_path: Option<String>,
|
||||
pub inspect: Option<SocketAddr>,
|
||||
pub inspect_brk: Option<SocketAddr>,
|
||||
pub lock: Option<String>,
|
||||
pub lock: Option<PathBuf>,
|
||||
pub lock_write: bool,
|
||||
pub log_level: Option<Level>,
|
||||
pub net_allowlist: Vec<String>,
|
||||
|
@ -372,11 +372,7 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
|||
}
|
||||
|
||||
fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||
permission_args_parse(flags, matches);
|
||||
config_arg_parse(flags, matches);
|
||||
reload_arg_parse(flags, matches);
|
||||
ca_file_arg_parse(flags, matches);
|
||||
no_check_arg_parse(flags, matches);
|
||||
runtime_args_parse(flags, matches, true);
|
||||
|
||||
let root = if matches.is_present("root") {
|
||||
let install_root = matches.value_of("root").unwrap();
|
||||
|
@ -501,7 +497,7 @@ fn cache_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
|||
fn lock_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||
if matches.is_present("lock") {
|
||||
let lockfile = matches.value_of("lock").unwrap();
|
||||
flags.lock = Some(lockfile.to_string());
|
||||
flags.lock = Some(PathBuf::from(lockfile));
|
||||
}
|
||||
if matches.is_present("lock-write") {
|
||||
flags.lock_write = true;
|
||||
|
@ -725,7 +721,7 @@ fn repl_subcommand<'a, 'b>() -> App<'a, 'b> {
|
|||
}
|
||||
|
||||
fn install_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
permission_args(SubCommand::with_name("install"))
|
||||
runtime_args(SubCommand::with_name("install"), true)
|
||||
.setting(AppSettings::TrailingVarArg)
|
||||
.arg(
|
||||
Arg::with_name("cmd")
|
||||
|
@ -751,10 +747,6 @@ fn install_subcommand<'a, 'b>() -> App<'a, 'b> {
|
|||
.short("f")
|
||||
.help("Forcefully overwrite existing installation")
|
||||
.takes_value(false))
|
||||
.arg(no_check_arg())
|
||||
.arg(reload_arg())
|
||||
.arg(ca_file_arg())
|
||||
.arg(config_arg())
|
||||
.about("Install script as an executable")
|
||||
.long_about(
|
||||
"Installs a script as an executable in the installation root's bin directory.
|
||||
|
@ -1348,6 +1340,7 @@ fn importmap_arg<'a, 'b>() -> Arg<'a, 'b> {
|
|||
Arg::with_name("importmap")
|
||||
.long("importmap")
|
||||
.value_name("FILE")
|
||||
.requires("unstable")
|
||||
.help("UNSTABLE: Load import map file")
|
||||
.long_help(
|
||||
"UNSTABLE:
|
||||
|
@ -2120,7 +2113,7 @@ mod tests {
|
|||
config_path: Some("tsconfig.json".to_string()),
|
||||
no_check: true,
|
||||
reload: true,
|
||||
lock: Some("lock.json".to_string()),
|
||||
lock: Some(PathBuf::from("lock.json")),
|
||||
lock_write: true,
|
||||
ca_file: Some("example.crt".to_string()),
|
||||
cached_only: true,
|
||||
|
@ -2174,7 +2167,7 @@ mod tests {
|
|||
config_path: Some("tsconfig.json".to_string()),
|
||||
no_check: true,
|
||||
reload: true,
|
||||
lock: Some("lock.json".to_string()),
|
||||
lock: Some(PathBuf::from("lock.json")),
|
||||
lock_write: true,
|
||||
ca_file: Some("example.crt".to_string()),
|
||||
cached_only: true,
|
||||
|
@ -2337,7 +2330,7 @@ mod tests {
|
|||
out_file: None,
|
||||
},
|
||||
lock_write: true,
|
||||
lock: Some("lock.json".to_string()),
|
||||
lock: Some(PathBuf::from("lock.json")),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -2365,6 +2358,7 @@ mod tests {
|
|||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"run",
|
||||
"--unstable",
|
||||
"--importmap=importmap.json",
|
||||
"script.ts"
|
||||
]);
|
||||
|
@ -2374,6 +2368,7 @@ mod tests {
|
|||
subcommand: DenoSubcommand::Run {
|
||||
script: "script.ts".to_string(),
|
||||
},
|
||||
unstable: true,
|
||||
import_map_path: Some("importmap.json".to_owned()),
|
||||
..Flags::default()
|
||||
}
|
||||
|
@ -2385,6 +2380,7 @@ mod tests {
|
|||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"info",
|
||||
"--unstable",
|
||||
"--importmap=importmap.json",
|
||||
"script.ts"
|
||||
]);
|
||||
|
@ -2395,6 +2391,7 @@ mod tests {
|
|||
file: Some("script.ts".to_string()),
|
||||
json: false,
|
||||
},
|
||||
unstable: true,
|
||||
import_map_path: Some("importmap.json".to_owned()),
|
||||
..Flags::default()
|
||||
}
|
||||
|
@ -2406,6 +2403,7 @@ mod tests {
|
|||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"cache",
|
||||
"--unstable",
|
||||
"--importmap=importmap.json",
|
||||
"script.ts"
|
||||
]);
|
||||
|
@ -2415,6 +2413,7 @@ mod tests {
|
|||
subcommand: DenoSubcommand::Cache {
|
||||
files: svec!["script.ts"],
|
||||
},
|
||||
unstable: true,
|
||||
import_map_path: Some("importmap.json".to_owned()),
|
||||
..Flags::default()
|
||||
}
|
||||
|
@ -2426,6 +2425,7 @@ mod tests {
|
|||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"doc",
|
||||
"--unstable",
|
||||
"--importmap=importmap.json",
|
||||
"script.ts"
|
||||
]);
|
||||
|
@ -2438,6 +2438,7 @@ mod tests {
|
|||
json: false,
|
||||
filter: None,
|
||||
},
|
||||
unstable: true,
|
||||
import_map_path: Some("importmap.json".to_owned()),
|
||||
..Flags::default()
|
||||
}
|
||||
|
@ -2522,87 +2523,32 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn install_with_args() {
|
||||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"install",
|
||||
"--reload",
|
||||
"--allow-net",
|
||||
"--allow-read",
|
||||
"-n",
|
||||
"file_server",
|
||||
"https://deno.land/std/http/file_server.ts"
|
||||
]);
|
||||
fn install_with_flags() {
|
||||
#[rustfmt::skip]
|
||||
let r = flags_from_vec_safe(svec!["deno", "install", "--unstable", "--importmap", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--name", "file_server", "--root", "/foo", "--force", "https://deno.land/std/http/file_server.ts", "foo", "bar"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Install {
|
||||
name: Some("file_server".to_string()),
|
||||
module_url: "https://deno.land/std/http/file_server.ts".to_string(),
|
||||
args: vec![],
|
||||
root: None,
|
||||
force: false,
|
||||
},
|
||||
reload: true,
|
||||
allow_net: true,
|
||||
allow_read: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_with_config() {
|
||||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"install",
|
||||
"--config",
|
||||
"tsconfig.json",
|
||||
"https://deno.land/std/examples/colors.ts"
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Install {
|
||||
name: None,
|
||||
module_url: "https://deno.land/std/examples/colors.ts".to_string(),
|
||||
args: svec![],
|
||||
root: None,
|
||||
force: false,
|
||||
},
|
||||
config_path: Some("tsconfig.json".to_owned()),
|
||||
..Flags::default()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_with_args_and_dir_and_force() {
|
||||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"install",
|
||||
"--root",
|
||||
"/usr/local",
|
||||
"-f",
|
||||
"--allow-net",
|
||||
"--allow-read",
|
||||
"-n",
|
||||
"file_server",
|
||||
"https://deno.land/std/http/file_server.ts",
|
||||
"arg1",
|
||||
"arg2"
|
||||
]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Install {
|
||||
name: Some("file_server".to_string()),
|
||||
module_url: "https://deno.land/std/http/file_server.ts".to_string(),
|
||||
args: svec!["arg1", "arg2"],
|
||||
root: Some(PathBuf::from("/usr/local")),
|
||||
args: svec!["foo", "bar"],
|
||||
root: Some(PathBuf::from("/foo")),
|
||||
force: true,
|
||||
},
|
||||
unstable: true,
|
||||
import_map_path: Some("import_map.json".to_string()),
|
||||
no_remote: true,
|
||||
config_path: Some("tsconfig.json".to_string()),
|
||||
no_check: true,
|
||||
reload: true,
|
||||
lock: Some(PathBuf::from("lock.json")),
|
||||
lock_write: true,
|
||||
ca_file: Some("example.crt".to_string()),
|
||||
cached_only: true,
|
||||
v8_flags: Some(svec!["--help", "--random-seed=1"]),
|
||||
seed: Some(1),
|
||||
inspect: Some("127.0.0.1:9229".parse().unwrap()),
|
||||
allow_net: true,
|
||||
allow_read: true,
|
||||
..Flags::default()
|
||||
|
@ -2858,7 +2804,7 @@ mod tests {
|
|||
script: "script.ts".to_string(),
|
||||
},
|
||||
lock_write: true,
|
||||
lock: Some("lock.json".to_string()),
|
||||
lock: Some(PathBuf::from("lock.json")),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -3060,33 +3006,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_with_cafile() {
|
||||
let r = flags_from_vec_safe(svec![
|
||||
"deno",
|
||||
"install",
|
||||
"--cert",
|
||||
"example.crt",
|
||||
"-n",
|
||||
"deno_colors",
|
||||
"https://deno.land/std/examples/colors.ts"
|
||||
]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Install {
|
||||
name: Some("deno_colors".to_string()),
|
||||
module_url: "https://deno.land/std/examples/colors.ts".to_string(),
|
||||
args: vec![],
|
||||
root: None,
|
||||
force: false,
|
||||
},
|
||||
ca_file: Some("example.crt".to_owned()),
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doc() {
|
||||
let r =
|
||||
|
|
|
@ -81,17 +81,6 @@ deno {} "$@"
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_config_file(
|
||||
file_path: PathBuf,
|
||||
config_file_name: String,
|
||||
) -> Result<(), io::Error> {
|
||||
let config_file_copy_path = get_config_file_path(&file_path);
|
||||
let cwd = std::env::current_dir().unwrap();
|
||||
let config_file_path = cwd.join(config_file_name);
|
||||
fs::copy(config_file_path, config_file_copy_path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_installer_root() -> Result<PathBuf, io::Error> {
|
||||
if let Ok(env_dir) = env::var("DENO_INSTALL_ROOT") {
|
||||
if !env_dir.is_empty() {
|
||||
|
@ -189,6 +178,8 @@ pub fn install(
|
|||
));
|
||||
};
|
||||
|
||||
let mut extra_files: Vec<(PathBuf, String)> = vec![];
|
||||
|
||||
let mut executable_args = vec!["run".to_string()];
|
||||
executable_args.extend_from_slice(&flags.to_permission_args());
|
||||
if let Some(ca_file) = flags.ca_file {
|
||||
|
@ -219,21 +210,65 @@ pub fn install(
|
|||
executable_args.push("--unstable".to_string());
|
||||
}
|
||||
|
||||
if flags.config_path.is_some() {
|
||||
let config_file_path = get_config_file_path(&file_path);
|
||||
let config_file_path_option = config_file_path.to_str();
|
||||
if let Some(config_file_path_string) = config_file_path_option {
|
||||
executable_args.push("--config".to_string());
|
||||
executable_args.push(config_file_path_string.to_string());
|
||||
if flags.no_remote {
|
||||
executable_args.push("--no-remote".to_string());
|
||||
}
|
||||
|
||||
if flags.lock_write {
|
||||
executable_args.push("--lock-write".to_string());
|
||||
}
|
||||
|
||||
if flags.cached_only {
|
||||
executable_args.push("--cached_only".to_string());
|
||||
}
|
||||
|
||||
if let Some(v8_flags) = flags.v8_flags {
|
||||
executable_args.push(format!("--v8-flags={}", v8_flags.join(",")));
|
||||
}
|
||||
|
||||
if let Some(seed) = flags.seed {
|
||||
executable_args.push("--seed".to_string());
|
||||
executable_args.push(seed.to_string());
|
||||
}
|
||||
|
||||
if let Some(inspect) = flags.inspect {
|
||||
executable_args.push(format!("--inspect={}", inspect.to_string()));
|
||||
}
|
||||
|
||||
if let Some(inspect_brk) = flags.inspect_brk {
|
||||
executable_args.push(format!("--inspect-brk={}", inspect_brk.to_string()));
|
||||
}
|
||||
|
||||
if let Some(import_map_path) = flags.import_map_path {
|
||||
let mut copy_path = file_path.clone();
|
||||
copy_path.set_extension("import_map.json");
|
||||
executable_args.push("--importmap".to_string());
|
||||
executable_args.push(copy_path.to_str().unwrap().to_string());
|
||||
extra_files.push((copy_path, fs::read_to_string(import_map_path)?));
|
||||
}
|
||||
|
||||
if let Some(config_path) = flags.config_path {
|
||||
let mut copy_path = file_path.clone();
|
||||
copy_path.set_extension("tsconfig.json");
|
||||
executable_args.push("--config".to_string());
|
||||
executable_args.push(copy_path.to_str().unwrap().to_string());
|
||||
extra_files.push((copy_path, fs::read_to_string(config_path)?));
|
||||
}
|
||||
|
||||
if let Some(lock_path) = flags.lock {
|
||||
let mut copy_path = file_path.clone();
|
||||
copy_path.set_extension("lock.json");
|
||||
executable_args.push("--lock".to_string());
|
||||
executable_args.push(copy_path.to_str().unwrap().to_string());
|
||||
extra_files.push((copy_path, fs::read_to_string(lock_path)?));
|
||||
}
|
||||
|
||||
executable_args.push(module_url.to_string());
|
||||
executable_args.extend_from_slice(&args);
|
||||
|
||||
generate_executable_file(file_path.to_owned(), executable_args)?;
|
||||
if let Some(config_path) = flags.config_path {
|
||||
generate_config_file(file_path.to_owned(), config_path)?;
|
||||
for (path, contents) in extra_files {
|
||||
fs::write(path, contents)?;
|
||||
}
|
||||
|
||||
println!("✅ Successfully installed {}", name);
|
||||
|
@ -263,12 +298,6 @@ fn is_in_path(dir: &PathBuf) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
fn get_config_file_path(file_path: &PathBuf) -> PathBuf {
|
||||
let mut config_file_copy_path = PathBuf::from(file_path);
|
||||
config_file_copy_path.set_extension("tsconfig.json");
|
||||
config_file_copy_path
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -588,6 +617,7 @@ mod tests {
|
|||
|
||||
assert!(file_path.exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
dbg!(&content);
|
||||
assert!(content.contains(r#""run" "--allow-read" "--allow-net" "--quiet" "--no-check" "http://localhost:4545/cli/tests/echo_server.ts" "--foobar""#));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,18 +4,17 @@ use deno_core::serde_json;
|
|||
use deno_core::serde_json::json;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Result;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Lockfile {
|
||||
write: bool,
|
||||
map: BTreeMap<String, String>,
|
||||
pub filename: String,
|
||||
pub filename: PathBuf,
|
||||
}
|
||||
|
||||
impl Lockfile {
|
||||
pub fn new(filename: String, write: bool) -> Result<Lockfile> {
|
||||
debug!("lockfile \"{}\", write: {}", filename, write);
|
||||
|
||||
pub fn new(filename: PathBuf, write: bool) -> Result<Lockfile> {
|
||||
let map = if write {
|
||||
BTreeMap::new()
|
||||
} else {
|
||||
|
@ -46,7 +45,7 @@ impl Lockfile {
|
|||
.open(&self.filename)?;
|
||||
use std::io::Write;
|
||||
f.write_all(s.as_bytes())?;
|
||||
debug!("lockfile write {}", self.filename);
|
||||
debug!("lockfile write {}", self.filename.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -93,7 +92,7 @@ mod tests {
|
|||
use std::io::Write;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn setup() -> (TempDir, String) {
|
||||
fn setup() -> (TempDir, PathBuf) {
|
||||
let temp_dir = TempDir::new().expect("could not create temp dir");
|
||||
|
||||
let file_path = temp_dir.path().join("valid_lockfile.json");
|
||||
|
@ -106,8 +105,7 @@ mod tests {
|
|||
|
||||
file.write_all(value.to_string().as_bytes()).unwrap();
|
||||
|
||||
let file_path_buf = temp_dir.path().join("valid_lockfile.json");
|
||||
let file_path = file_path_buf.to_str().expect("file path fail").to_string();
|
||||
let file_path = temp_dir.path().join("valid_lockfile.json");
|
||||
|
||||
(temp_dir, file_path)
|
||||
}
|
||||
|
@ -118,7 +116,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn new_nonexistent_lockfile() {
|
||||
let file_path = String::from("nonexistent_lock_file.json");
|
||||
let file_path = PathBuf::from("nonexistent_lock_file.json");
|
||||
assert!(Lockfile::new(file_path, false).is_err());
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,10 @@ async fn install_command(
|
|||
root: Option<PathBuf>,
|
||||
force: bool,
|
||||
) -> Result<(), AnyError> {
|
||||
let program_state = ProgramState::new(flags.clone())?;
|
||||
let mut preload_flags = flags.clone();
|
||||
preload_flags.inspect = None;
|
||||
preload_flags.inspect_brk = None;
|
||||
let program_state = ProgramState::new(preload_flags)?;
|
||||
let main_module = ModuleSpecifier::resolve_url_or_path(&module_url)?;
|
||||
let mut worker = MainWorker::new(&program_state, main_module.clone());
|
||||
// First, fetch and compile the module; this step ensures that the module exists.
|
||||
|
|
|
@ -615,7 +615,8 @@ impl Graph2 {
|
|||
let valid = lockfile.check_or_insert(&specifier, &module.source);
|
||||
if !valid {
|
||||
return Err(
|
||||
InvalidSource(ms.clone(), lockfile.filename.clone()).into(),
|
||||
InvalidSource(ms.clone(), lockfile.filename.display().to_string())
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1243,8 +1244,7 @@ pub mod tests {
|
|||
let fixtures = c.join("tests/module_graph");
|
||||
let lockfile_path = fixtures.join("lockfile.json");
|
||||
let lockfile =
|
||||
Lockfile::new(lockfile_path.to_string_lossy().to_string(), false)
|
||||
.expect("could not load lockfile");
|
||||
Lockfile::new(lockfile_path, false).expect("could not load lockfile");
|
||||
let maybe_lockfile = Some(Mutex::new(lockfile));
|
||||
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
|
||||
fixtures,
|
||||
|
@ -1269,8 +1269,7 @@ pub mod tests {
|
|||
let fixtures = c.join("tests/module_graph");
|
||||
let lockfile_path = fixtures.join("lockfile_fail.json");
|
||||
let lockfile =
|
||||
Lockfile::new(lockfile_path.to_string_lossy().to_string(), false)
|
||||
.expect("could not load lockfile");
|
||||
Lockfile::new(lockfile_path, false).expect("could not load lockfile");
|
||||
let maybe_lockfile = Some(Mutex::new(lockfile));
|
||||
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
|
||||
fixtures,
|
||||
|
|
|
@ -175,7 +175,8 @@ impl ProgramState {
|
|||
if !check_passed {
|
||||
eprintln!(
|
||||
"Subresource integrity check failed --lock={}\n{}",
|
||||
g.filename, graph_file.url
|
||||
g.filename.display(),
|
||||
graph_file.url
|
||||
);
|
||||
std::process::exit(10);
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Unstable API '--importmap'. The --unstable flag must be provided.
|
|
@ -1812,13 +1812,6 @@ itest!(_033_import_map {
|
|||
output: "033_import_map.out",
|
||||
});
|
||||
|
||||
itest!(import_map_no_unstable {
|
||||
args:
|
||||
"run --quiet --reload --importmap=importmaps/import_map.json importmaps/test.ts",
|
||||
output: "import_map_no_unstable.out",
|
||||
exit_code: 70,
|
||||
});
|
||||
|
||||
itest!(_034_onload {
|
||||
args: "run --quiet --reload 034_onload/main.ts",
|
||||
output: "034_onload.out",
|
||||
|
|
|
@ -586,7 +586,8 @@ impl TsCompiler {
|
|||
if !check_passed {
|
||||
eprintln!(
|
||||
"Subresource integrity check failed --lock={}\n{}",
|
||||
g.filename, graph_file.url
|
||||
g.filename.display(),
|
||||
graph_file.url
|
||||
);
|
||||
std::process::exit(10);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue