Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add progress bar #2309

Merged
merged 4 commits into from
May 11, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cli/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ fn lazy_start(parent_state: ThreadSafeState) -> ResourceId {
parent_state.flags.clone(),
parent_state.argv.clone(),
op_selector_compiler,
parent_state.progress.clone(),
);
let rid = child_state.resource.rid;
let resource = child_state.resource.clone();
Expand Down Expand Up @@ -192,6 +193,10 @@ pub fn compile_async(

let compiler_rid = lazy_start(parent_state.clone());

let compiling_job = parent_state
.progress
.add(format!("Compiling {}", module_meta_data_.module_name));

let (local_sender, local_receiver) =
oneshot::channel::<Result<ModuleMetaData, Option<JSError>>>();

Expand All @@ -218,6 +223,7 @@ pub fn compile_async(
let res_data = res["data"].as_object().expect(
"Error decoding compiler response: expected object field 'data'",
);
drop(compiling_job);
ry marked this conversation as resolved.
Show resolved Hide resolved
match res["success"].as_bool() {
Some(true) => Ok(ModuleMetaData {
maybe_output_code: res_data["outputCode"]
Expand Down
24 changes: 18 additions & 6 deletions cli/deno_dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::fs as deno_fs;
use crate::http_util;
use crate::js_errors::SourceMapGetter;
use crate::msg;
use crate::progress::Progress;
use crate::tokio_util;
use crate::version;
use dirs;
Expand Down Expand Up @@ -44,6 +45,8 @@ pub struct DenoDir {
/// The active configuration file contents (or empty array) which applies to
/// source code cached by `DenoDir`.
pub config: Vec<u8>,

pub progress: Progress,
}

impl DenoDir {
Expand All @@ -52,6 +55,7 @@ impl DenoDir {
pub fn new(
custom_root: Option<PathBuf>,
state_config: &Option<Vec<u8>>,
progress: Progress,
) -> std::io::Result<Self> {
// Only setup once.
let home_dir = dirs::home_dir().expect("Could not get home directory.");
Expand Down Expand Up @@ -85,6 +89,7 @@ impl DenoDir {
deps_http,
deps_https,
config,
progress,
};

// TODO Lazily create these directories.
Expand Down Expand Up @@ -578,9 +583,10 @@ fn fetch_remote_source_async(
filename: &str,
) -> impl Future<Item = Option<ModuleMetaData>, Error = DenoError> {
use crate::http_util::FetchOnceResult;
{
eprintln!("Downloading {}", module_name);
}

let download_job = deno_dir
.progress
.add(format!("Downloading {}", module_name));

let filename = filename.to_owned();
let module_name = module_name.to_owned();
Expand Down Expand Up @@ -682,7 +688,10 @@ fn fetch_remote_source_async(
}
})
},
)
).then(move |r| {
drop(download_job);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. What is this drop() thing needed for?

r
})
}

/// Fetch remote source code.
Expand Down Expand Up @@ -912,8 +921,11 @@ mod tests {
fn test_setup() -> (TempDir, DenoDir) {
let temp_dir = TempDir::new().expect("tempdir fail");
let config = Some(b"{}".to_vec());
let deno_dir = DenoDir::new(Some(temp_dir.path().to_path_buf()), &config)
.expect("setup fail");
let deno_dir = DenoDir::new(
Some(temp_dir.path().to_path_buf()),
&config,
Progress::new(),
).expect("setup fail");
(temp_dir, deno_dir)
}

Expand Down
2 changes: 0 additions & 2 deletions cli/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ macro_rules! svec {
($($x:expr),*) => (vec![$($x.to_string()),*]);
}

#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
#[derive(Clone, Debug, PartialEq, Default)]
pub struct DenoFlags {
pub log_debug: bool,
Expand Down Expand Up @@ -307,7 +306,6 @@ fn resolve_paths(paths: Vec<String>) -> Vec<String> {

/// Parse ArgMatches into internal DenoFlags structure.
/// This method should not make any side effects.
#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
pub fn parse_flags(matches: ArgMatches) -> DenoFlags {
let mut flags = DenoFlags::default();

Expand Down
13 changes: 12 additions & 1 deletion cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod msg;
pub mod msg_util;
pub mod ops;
pub mod permissions;
mod progress;
mod repl;
pub mod resolve_addr;
pub mod resources;
Expand All @@ -39,6 +40,7 @@ pub mod version;
pub mod worker;

use crate::errors::RustOrJsError;
use crate::progress::Progress;
use crate::state::ThreadSafeState;
use crate::worker::root_specifier_to_url;
use crate::worker::Worker;
Expand Down Expand Up @@ -134,7 +136,16 @@ fn create_worker_and_state(
flags: DenoFlags,
argv: Vec<String>,
) -> (Worker, ThreadSafeState) {
let state = ThreadSafeState::new(flags, argv, ops::op_selector_std);
let progress = Progress::new();
progress.set_callback(|done, completed, total, msg| {
if done {
eprintln!("");
} else {
eprint!("\r[{}/{}] {}", completed, total, msg);
eprint!("\x1B[K"); // Clear to end of line.
}
});
let state = ThreadSafeState::new(flags, argv, ops::op_selector_std, progress);
let worker = Worker::new(
"main".to_string(),
startup_data::deno_isolate_init(),
Expand Down
1 change: 0 additions & 1 deletion cli/msg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
#![allow(unused_imports)]
#![allow(dead_code)]
#![cfg_attr(
feature = "cargo-clippy",
Expand Down
11 changes: 1 addition & 10 deletions cli/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -859,19 +859,9 @@ fn op_chmod(
debug!("op_chmod {}", &path_);
// Still check file/dir exists on windows
let _metadata = fs::metadata(&path)?;
// Only work in unix
#[cfg(any(unix))]
{
// We need to use underscore to compile in Windows.
#[cfg_attr(
feature = "cargo-clippy",
allow(clippy::used_underscore_binding)
)]
let mut permissions = _metadata.permissions();
#[cfg_attr(
feature = "cargo-clippy",
allow(clippy::used_underscore_binding)
)]
permissions.set_mode(_mode);
fs::set_permissions(&path, permissions)?;
}
Expand Down Expand Up @@ -2049,6 +2039,7 @@ fn op_create_worker(
parent_state.flags.clone(),
parent_state.argv.clone(),
op_selector_std,
parent_state.progress.clone(),
);
let rid = child_state.resource.rid;
let name = format!("USER-WORKER-{}", specifier);
Expand Down
1 change: 0 additions & 1 deletion cli/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ impl Default for PermissionAccessor {
}
}

#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
#[derive(Debug, Default)]
pub struct DenoPermissions {
// Keep in sync with src/permissions.ts
Expand Down
161 changes: 161 additions & 0 deletions cli/progress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use std::sync::Arc;
use std::sync::Mutex;

#[derive(Clone, Default)]
pub struct Progress(Arc<Mutex<Inner>>);

impl Progress {
pub fn new() -> Self {
Progress::default()
}

pub fn set_callback<F>(&self, f: F)
where
F: Fn(bool, usize, usize, &str) + Send + Sync + 'static,
{
let mut s = self.0.lock().unwrap();
assert!(s.callback.is_none());
s.callback = Some(Arc::new(f));
}

/// Returns job counts: (complete, total)
pub fn progress(&self) -> (usize, usize) {
let s = self.0.lock().unwrap();
s.progress()
}

pub fn history(&self) -> Vec<String> {
let s = self.0.lock().unwrap();
s.job_names.clone()
}

pub fn add(&self, name: String) -> Job {
let mut s = self.0.lock().unwrap();
let id = s.job_names.len();
s.maybe_call_callback(false, s.complete, s.job_names.len() + 1, &name);
s.job_names.push(name);
Job {
id,
inner: self.0.clone(),
}
}

pub fn done(&self) {
let s = self.0.lock().unwrap();
s.maybe_call_callback(true, s.complete, s.job_names.len(), "");
}
}

type Callback = dyn Fn(bool, usize, usize, &str) + Send + Sync;

#[derive(Default)]
struct Inner {
job_names: Vec<String>,
complete: usize,
callback: Option<Arc<Callback>>,
}

impl Inner {
pub fn maybe_call_callback(
&self,
done: bool,
complete: usize,
total: usize,
msg: &str,
) {
if let Some(ref cb) = self.callback {
cb(done, complete, total, msg);
}
}

/// Returns job counts: (complete, total)
pub fn progress(&self) -> (usize, usize) {
let total = self.job_names.len();
(self.complete, total)
}
}

pub struct Job {
inner: Arc<Mutex<Inner>>,
id: usize,
}

impl Drop for Job {
fn drop(&mut self) {
let mut s = self.inner.lock().unwrap();
s.complete += 1;
let name = &s.job_names[self.id];
let (complete, total) = s.progress();
s.maybe_call_callback(false, complete, total, name);
ry marked this conversation as resolved.
Show resolved Hide resolved
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn progress() {
let p = Progress::new();
assert_eq!(p.progress(), (0, 0));
{
let _j1 = p.add("hello".to_string());
assert_eq!(p.progress(), (0, 1));
}
assert_eq!(p.progress(), (1, 1));
{
let _j2 = p.add("hello".to_string());
assert_eq!(p.progress(), (1, 2));
}
assert_eq!(p.progress(), (2, 2));
}

#[test]
fn history() {
let p = Progress::new();
let _a = p.add("a".to_string());
let _b = p.add("b".to_string());
assert_eq!(p.history(), vec!["a", "b"]);
}

#[test]
fn callback() {
let callback_history: Arc<Mutex<Vec<(usize, usize, String)>>> =
Arc::new(Mutex::new(Vec::new()));
{
let p = Progress::new();
let callback_history_ = callback_history.clone();

p.set_callback(move |_done, complete, total, msg| {
// println!("callback: {}, {}, {}", complete, total, msg);
let mut h = callback_history_.lock().unwrap();
h.push((complete, total, String::from(msg)));
});
{
let _a = p.add("a".to_string());
let _b = p.add("b".to_string());
}
let _c = p.add("c".to_string());
}

let h = callback_history.lock().unwrap();
assert_eq!(
h.to_vec(),
vec![
(0, 1, "a".to_string()),
(0, 2, "b".to_string()),
(1, 2, "b".to_string()),
(2, 2, "a".to_string()),
(2, 3, "c".to_string()),
(3, 3, "c".to_string()),
]
);
}

#[test]
fn thread_safe() {
fn f<S: Send + Sync>(_: S) {}
f(Progress::new());
}
}
1 change: 0 additions & 1 deletion cli/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,6 @@ pub fn get_message_stream_from_worker(rid: ResourceId) -> WorkerReceiverStream {
WorkerReceiverStream { rid }
}

#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
pub struct ChildResources {
pub child_rid: ResourceId,
pub stdin_rid: Option<ResourceId>,
Expand Down
Loading