1
0
Fork 0
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:
Emmanuel 2020-07-08 16:50:12 +02:00 committed by GitHub
parent a2bf61d1ae
commit cbbd944359
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 213 additions and 93 deletions

View file

@ -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()),

View file

@ -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,

View 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
View file

@ -0,0 +1,5 @@
{
"denoDir": "[WILDCARD]",
"modulesCache": "[WILDCARD]deps",
"typescriptCache": "[WILDCARD]gen"
}

View file

@ -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",

View file

@ -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;

View file

@ -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()
);
}
*/
}