Skip to content

Commit

Permalink
Add progress bar for 'Compiling' and 'Downloading'
Browse files Browse the repository at this point in the history
  • Loading branch information
ry committed May 8, 2019
1 parent ec9080f commit a6e01ef
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 39 deletions.
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);
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 @@ -600,9 +605,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 @@ -704,7 +710,10 @@ fn fetch_remote_source_async(
}
})
},
)
).then(move |r| {
drop(download_job);
r
})
}

/// Fetch remote source code.
Expand Down Expand Up @@ -897,8 +906,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
3 changes: 1 addition & 2 deletions cli/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,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 @@ -267,9 +266,9 @@ This command has implicit access to all permissions (equivalent to deno run --al
).arg(Arg::with_name("code").takes_value(true).required(true)),
)
}

/// 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
18 changes: 17 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,21 @@ 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(|completed, total, msg| {
// TODO(ry) Currently we print a \n after every progress message and then
// move the cursor up before printing the next line. This isn't ideal. We
// could instead print \r after every progress message and avoid moving the
// cursor up. This would only require knowing then the progress is complete
// and printing \n at that time, so that the output that follows doesn't
// continue on the same line.
if total != 0 {
eprint!("\x1B[F"); // Move up one line.
}
eprint!("\r[{}/{}] {}", completed, total, msg);
eprintln!("\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 @@ -850,19 +850,9 @@ fn op_chmod(
let path = PathBuf::from(&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 @@ -2003,6 +1993,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 @@ -122,7 +122,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
150 changes: 150 additions & 0 deletions cli/progress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use std::sync::Arc;
use std::sync::Mutex;

type Callback = dyn Fn(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, complete: usize, total: usize, msg: &str) {
if let Some(ref cb) = self.callback {
cb(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(complete, total, name);
}
}

#[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(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(s.complete, s.job_names.len() + 1, &name);
s.job_names.push(name);
Job {
id,
inner: self.0.clone(),
}
}
}

#[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 |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

0 comments on commit a6e01ef

Please sign in to comment.