mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
feat(cli): json option for "deno info" (#6372)
This commit is contained in:
parent
a2bf61d1ae
commit
cbbd944359
7 changed files with 213 additions and 93 deletions
41
cli/flags.rs
41
cli/flags.rs
|
@ -41,6 +41,7 @@ pub enum DenoSubcommand {
|
|||
},
|
||||
Help,
|
||||
Info {
|
||||
json: bool,
|
||||
file: Option<String>,
|
||||
},
|
||||
Install {
|
||||
|
@ -454,10 +455,11 @@ fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
|||
fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||
ca_file_arg_parse(flags, matches);
|
||||
unstable_arg_parse(flags, matches);
|
||||
let json = matches.is_present("json");
|
||||
no_check_arg_parse(flags, matches);
|
||||
|
||||
flags.subcommand = DenoSubcommand::Info {
|
||||
file: matches.value_of("file").map(|f| f.to_string()),
|
||||
json,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -824,6 +826,12 @@ TypeScript compiler cache: Subdirectory containing TS compiler output.",
|
|||
.arg(ca_file_arg())
|
||||
.arg(no_check_arg())
|
||||
.arg(unstable_arg())
|
||||
.arg(
|
||||
Arg::with_name("json")
|
||||
.long("json")
|
||||
.help("Outputs the information in JSON format")
|
||||
.takes_value(false),
|
||||
)
|
||||
}
|
||||
|
||||
fn cache_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
|
@ -1784,6 +1792,19 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Info {
|
||||
json: false,
|
||||
file: Some("script.ts".to_string()),
|
||||
},
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec_safe(svec!["deno", "info", "--json", "script.ts"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Info {
|
||||
json: true,
|
||||
file: Some("script.ts".to_string()),
|
||||
},
|
||||
..Flags::default()
|
||||
|
@ -1794,7 +1815,22 @@ mod tests {
|
|||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Info { file: None },
|
||||
subcommand: DenoSubcommand::Info {
|
||||
json: false,
|
||||
file: None
|
||||
},
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec_safe(svec!["deno", "info", "--json"]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Info {
|
||||
json: true,
|
||||
file: None
|
||||
},
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
@ -2790,6 +2826,7 @@ mod tests {
|
|||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Info {
|
||||
json: false,
|
||||
file: Some("https://example.com".to_string()),
|
||||
},
|
||||
ca_file: Some("example.crt".to_owned()),
|
||||
|
|
163
cli/main.rs
163
cli/main.rs
|
@ -81,6 +81,7 @@ use crate::permissions::Permissions;
|
|||
use crate::tsc::TargetLib;
|
||||
use crate::worker::MainWorker;
|
||||
use deno_core::v8_set_flags;
|
||||
use deno_core::Deps;
|
||||
use deno_core::ErrBox;
|
||||
use deno_core::EsIsolate;
|
||||
use deno_core::ModuleSpecifier;
|
||||
|
@ -91,6 +92,7 @@ use futures::Future;
|
|||
use log::Level;
|
||||
use log::Metadata;
|
||||
use log::Record;
|
||||
use state::exit_unstable;
|
||||
use std::env;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
|
@ -140,22 +142,47 @@ fn write_to_stdout_ignore_sigpipe(bytes: &[u8]) -> Result<(), std::io::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_cache_info(state: &GlobalState) {
|
||||
println!(
|
||||
"{} {:?}",
|
||||
colors::bold("DENO_DIR location:"),
|
||||
state.dir.root
|
||||
);
|
||||
println!(
|
||||
"{} {:?}",
|
||||
colors::bold("Remote modules cache:"),
|
||||
state.file_fetcher.http_cache.location
|
||||
);
|
||||
println!(
|
||||
"{} {:?}",
|
||||
colors::bold("TypeScript compiler cache:"),
|
||||
state.dir.gen_cache.location
|
||||
);
|
||||
fn write_json_to_stdout<T>(value: &T) -> Result<(), ErrBox>
|
||||
where
|
||||
T: ?Sized + serde::ser::Serialize,
|
||||
{
|
||||
let writer = std::io::BufWriter::new(std::io::stdout());
|
||||
serde_json::to_writer_pretty(writer, value).map_err(ErrBox::from)
|
||||
}
|
||||
|
||||
fn print_cache_info(state: &GlobalState, json: bool) -> Result<(), ErrBox> {
|
||||
let deno_dir = &state.dir.root;
|
||||
let modules_cache = &state.file_fetcher.http_cache.location;
|
||||
let typescript_cache = &state.dir.gen_cache.location;
|
||||
if json {
|
||||
let output = json!({
|
||||
"denoDir": deno_dir,
|
||||
"modulesCache": modules_cache,
|
||||
"typescriptCache": typescript_cache,
|
||||
});
|
||||
write_json_to_stdout(&output)
|
||||
} else {
|
||||
println!("{} {:?}", colors::bold("DENO_DIR location:"), deno_dir);
|
||||
println!(
|
||||
"{} {:?}",
|
||||
colors::bold("Remote modules cache:"),
|
||||
modules_cache
|
||||
);
|
||||
println!(
|
||||
"{} {:?}",
|
||||
colors::bold("TypeScript compiler cache:"),
|
||||
typescript_cache
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct FileInfoOutput<'a> {
|
||||
local: &'a str,
|
||||
file_type: &'a str,
|
||||
compiled: Option<String>,
|
||||
map: Option<String>,
|
||||
deps: Option<Deps>,
|
||||
}
|
||||
|
||||
// TODO(bartlomieju): this function de facto repeats
|
||||
|
@ -163,6 +190,7 @@ fn print_cache_info(state: &GlobalState) {
|
|||
async fn print_file_info(
|
||||
worker: &MainWorker,
|
||||
module_specifier: ModuleSpecifier,
|
||||
json: bool,
|
||||
) -> Result<(), ErrBox> {
|
||||
let global_state = worker.state.borrow().global_state.clone();
|
||||
|
||||
|
@ -171,17 +199,13 @@ async fn print_file_info(
|
|||
.fetch_source_file(&module_specifier, None, Permissions::allow_all())
|
||||
.await?;
|
||||
|
||||
println!(
|
||||
"{} {}",
|
||||
colors::bold("local:"),
|
||||
out.filename.to_str().unwrap()
|
||||
);
|
||||
|
||||
println!(
|
||||
"{} {}",
|
||||
colors::bold("type:"),
|
||||
msg::enum_name_media_type(out.media_type)
|
||||
);
|
||||
let mut output = FileInfoOutput {
|
||||
local: out.filename.to_str().unwrap(),
|
||||
file_type: msg::enum_name_media_type(out.media_type),
|
||||
compiled: None,
|
||||
map: None,
|
||||
deps: None,
|
||||
};
|
||||
|
||||
let module_specifier_ = module_specifier.clone();
|
||||
|
||||
|
@ -208,12 +232,8 @@ async fn print_file_info(
|
|||
.ts_compiler
|
||||
.get_compiled_source_file(&out.url)
|
||||
.unwrap();
|
||||
|
||||
println!(
|
||||
"{} {}",
|
||||
colors::bold("compiled:"),
|
||||
compiled_source_file.filename.to_str().unwrap(),
|
||||
);
|
||||
output.compiled =
|
||||
compiled_source_file.filename.to_str().map(|s| s.to_owned());
|
||||
}
|
||||
|
||||
if let Ok(source_map) = global_state
|
||||
|
@ -221,31 +241,48 @@ async fn print_file_info(
|
|||
.ts_compiler
|
||||
.get_source_map_file(&module_specifier)
|
||||
{
|
||||
println!(
|
||||
"{} {}",
|
||||
colors::bold("map:"),
|
||||
source_map.filename.to_str().unwrap()
|
||||
);
|
||||
output.map = source_map.filename.to_str().map(|s| s.to_owned());
|
||||
}
|
||||
|
||||
let es_state_rc = EsIsolate::state(&worker.isolate);
|
||||
let es_state = es_state_rc.borrow();
|
||||
|
||||
if let Some(deps) = es_state.modules.deps(&module_specifier) {
|
||||
println!("{}{}", colors::bold("deps:\n"), deps.name);
|
||||
if let Some(ref depsdeps) = deps.deps {
|
||||
for d in depsdeps {
|
||||
println!("{}", d);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"{} cannot retrieve full dependency graph",
|
||||
colors::bold("deps:"),
|
||||
);
|
||||
output.deps = Some(deps);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
if json {
|
||||
let output = json!({
|
||||
"local": output.local,
|
||||
"fileType": output.file_type,
|
||||
"compiled": output.compiled,
|
||||
"map": output.map,
|
||||
"deps": output.deps.map(|x| x.to_json())
|
||||
});
|
||||
write_json_to_stdout(&output)
|
||||
} else {
|
||||
println!("{} {}", colors::bold("local:"), output.local);
|
||||
println!("{} {}", colors::bold("type:"), output.file_type);
|
||||
if let Some(compiled) = output.compiled {
|
||||
println!("{} {}", colors::bold("compiled:"), compiled);
|
||||
}
|
||||
if let Some(map) = output.map {
|
||||
println!("{} {}", colors::bold("map:"), map);
|
||||
}
|
||||
if let Some(deps) = output.deps {
|
||||
println!("{}{}", colors::bold("deps:\n"), deps.name);
|
||||
if let Some(ref depsdeps) = deps.deps {
|
||||
for d in depsdeps {
|
||||
println!("{}", d);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"{} cannot retrieve full dependency graph",
|
||||
colors::bold("deps:"),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_types(unstable: bool) -> String {
|
||||
|
@ -270,18 +307,21 @@ fn get_types(unstable: bool) -> String {
|
|||
async fn info_command(
|
||||
flags: Flags,
|
||||
file: Option<String>,
|
||||
json: bool,
|
||||
) -> Result<(), ErrBox> {
|
||||
if json && !flags.unstable {
|
||||
exit_unstable("--json");
|
||||
}
|
||||
let global_state = GlobalState::new(flags)?;
|
||||
// If it was just "deno info" print location of caches and exit
|
||||
if file.is_none() {
|
||||
print_cache_info(&global_state);
|
||||
return Ok(());
|
||||
print_cache_info(&global_state, json)
|
||||
} else {
|
||||
let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?;
|
||||
let mut worker = MainWorker::create(global_state, main_module.clone())?;
|
||||
worker.preload_module(&main_module).await?;
|
||||
print_file_info(&worker, main_module.clone(), json).await
|
||||
}
|
||||
|
||||
let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?;
|
||||
let mut worker = MainWorker::create(global_state, main_module.clone())?;
|
||||
worker.preload_module(&main_module).await?;
|
||||
print_file_info(&worker, main_module.clone()).await
|
||||
}
|
||||
|
||||
async fn install_command(
|
||||
|
@ -525,8 +565,7 @@ async fn doc_command(
|
|||
};
|
||||
|
||||
if json {
|
||||
let writer = std::io::BufWriter::new(std::io::stdout());
|
||||
serde_json::to_writer_pretty(writer, &doc_nodes).map_err(ErrBox::from)
|
||||
write_json_to_stdout(&doc_nodes)
|
||||
} else {
|
||||
let details = if let Some(filter) = maybe_filter {
|
||||
let nodes =
|
||||
|
@ -691,7 +730,9 @@ pub fn main() {
|
|||
DenoSubcommand::Fmt { check, files } => {
|
||||
fmt::format(files, check).boxed_local()
|
||||
}
|
||||
DenoSubcommand::Info { file } => info_command(flags, file).boxed_local(),
|
||||
DenoSubcommand::Info { file, json } => {
|
||||
info_command(flags, file, json).boxed_local()
|
||||
}
|
||||
DenoSubcommand::Install {
|
||||
module_url,
|
||||
args,
|
||||
|
|
25
cli/tests/055_info_file_json.out
Normal file
25
cli/tests/055_info_file_json.out
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"local": "[WILDCARD]005_more_imports.ts",
|
||||
"fileType": "TypeScript",
|
||||
"compiled": "[WILDCARD]005_more_imports.ts.js",
|
||||
"map": null,
|
||||
"deps": [
|
||||
"file://[WILDCARD]/005_more_imports.ts",
|
||||
[
|
||||
[
|
||||
"file://[WILDCARD]/subdir/mod1.ts",
|
||||
[
|
||||
[
|
||||
"file://[WILDCARD]/subdir/subdir2/mod2.ts",
|
||||
[
|
||||
[
|
||||
"file://[WILDCARD]/subdir/print_hello.ts",
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
5
cli/tests/info_json.out
Normal file
5
cli/tests/info_json.out
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"denoDir": "[WILDCARD]",
|
||||
"modulesCache": "[WILDCARD]deps",
|
||||
"typescriptCache": "[WILDCARD]gen"
|
||||
}
|
|
@ -1499,6 +1499,11 @@ itest!(_041_info_flag {
|
|||
output: "041_info_flag.out",
|
||||
});
|
||||
|
||||
itest!(info_json {
|
||||
args: "info --json --unstable",
|
||||
output: "info_json.out",
|
||||
});
|
||||
|
||||
itest!(_042_dyn_import_evalcontext {
|
||||
args: "run --quiet --allow-read --reload 042_dyn_import_evalcontext.ts",
|
||||
output: "042_dyn_import_evalcontext.ts.out",
|
||||
|
@ -1552,6 +1557,12 @@ itest!(_054_info_local_imports {
|
|||
exit_code: 0,
|
||||
});
|
||||
|
||||
itest!(_055_info_file_json {
|
||||
args: "info --quiet --json --unstable 005_more_imports.ts",
|
||||
output: "055_info_file_json.out",
|
||||
exit_code: 0,
|
||||
});
|
||||
|
||||
itest!(_056_make_temp_file_write_perm {
|
||||
args:
|
||||
"run --quiet --allow-read --allow-write=./subdir/ 056_make_temp_file_write_perm.ts",
|
||||
|
|
|
@ -36,6 +36,7 @@ pub use crate::es_isolate::EsIsolateState;
|
|||
pub use crate::flags::v8_set_flags;
|
||||
pub use crate::module_specifier::ModuleResolutionError;
|
||||
pub use crate::module_specifier::ModuleSpecifier;
|
||||
pub use crate::modules::Deps;
|
||||
pub use crate::modules::ModuleId;
|
||||
pub use crate::modules::ModuleLoadId;
|
||||
pub use crate::modules::ModuleLoader;
|
||||
|
|
|
@ -484,20 +484,14 @@ impl Deps {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> String {
|
||||
let mut children = "[".to_string();
|
||||
|
||||
if let Some(ref deps) = self.deps {
|
||||
for d in deps {
|
||||
children.push_str(&d.to_json());
|
||||
if !d.is_last {
|
||||
children.push_str(",");
|
||||
}
|
||||
}
|
||||
pub fn to_json(&self) -> serde_json::Value {
|
||||
let children;
|
||||
if let Some(deps) = &self.deps {
|
||||
children = deps.iter().map(|c| c.to_json()).collect();
|
||||
} else {
|
||||
children = Vec::new()
|
||||
}
|
||||
children.push_str("]");
|
||||
|
||||
format!("[\"{}\",{}]", self.name, children)
|
||||
serde_json::json!([&self.name, children])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1056,6 +1050,29 @@ mod tests {
|
|||
assert!(modules.deps(&specifier).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deps_to_json() {
|
||||
fn dep(name: &str, deps: Option<Vec<Deps>>) -> Deps {
|
||||
Deps {
|
||||
name: name.to_string(),
|
||||
deps,
|
||||
prefix: "".to_string(),
|
||||
is_last: false,
|
||||
}
|
||||
}
|
||||
let deps = dep(
|
||||
"a",
|
||||
Some(vec![
|
||||
dep("b", Some(vec![dep("b2", None)])),
|
||||
dep("c", Some(vec![])),
|
||||
]),
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::json!(["a", [["b", [["b2", []]]], ["c", []]]]),
|
||||
deps.to_json()
|
||||
);
|
||||
}
|
||||
|
||||
/* TODO(bartlomieju): reenable
|
||||
#[test]
|
||||
fn deps() {
|
||||
|
@ -1076,22 +1093,5 @@ mod tests {
|
|||
assert_eq!(bar_deps.deps, Some(vec![]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deps_to_json() {
|
||||
let mut modules = Modules::new();
|
||||
modules.register(1, "foo");
|
||||
modules.register(2, "bar");
|
||||
modules.register(3, "baz");
|
||||
modules.register(4, "zuh");
|
||||
modules.add_child(1, "bar");
|
||||
modules.add_child(1, "baz");
|
||||
modules.add_child(3, "zuh");
|
||||
let maybe_deps = modules.deps("foo");
|
||||
assert!(maybe_deps.is_some());
|
||||
assert_eq!(
|
||||
"[\"foo\",[[\"bar\",[]],[\"baz\",[[\"zuh\",[]]]]]]",
|
||||
maybe_deps.unwrap().to_json()
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue