summaryrefslogtreecommitdiff
path: root/cli/main.rs
blob: b6cd49d0e0bbb14b68c010b182413db923f1b399 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate serde_json;
extern crate clap;
extern crate deno;

mod ansi;
pub mod compiler;
pub mod deno_dir;
pub mod errors;
pub mod flags;
mod fs;
mod global_timer;
mod http_body;
mod http_util;
pub mod js_errors;
pub mod msg;
pub mod msg_util;
pub mod ops;
pub mod permissions;
mod repl;
pub mod resolve_addr;
pub mod resources;
mod startup_data;
pub mod state;
mod tokio_util;
mod tokio_write;
pub mod version;
pub mod worker;

use crate::errors::RustOrJsError;
use crate::state::ThreadSafeState;
use crate::worker::root_specifier_to_url;
use crate::worker::Worker;
use futures::lazy;
use futures::Future;
use log::{LevelFilter, Metadata, Record};
use std::env;

static LOGGER: Logger = Logger;

struct Logger;

impl log::Log for Logger {
  fn enabled(&self, metadata: &Metadata) -> bool {
    metadata.level() <= log::max_level()
  }

  fn log(&self, record: &Record) {
    if self.enabled(record.metadata()) {
      println!("{} RS - {}", record.level(), record.args());
    }
  }
  fn flush(&self) {}
}

fn print_err_and_exit(err: RustOrJsError) {
  eprintln!("{}", err.to_string());
  std::process::exit(1);
}

fn js_check<E>(r: Result<(), E>)
where
  E: Into<RustOrJsError>,
{
  if let Err(err) = r {
    print_err_and_exit(err.into());
  }
}

// TODO(ry) Move this to main.rs
pub fn print_file_info(worker: &Worker, url: &str) {
  let maybe_out =
    worker::fetch_module_meta_data_and_maybe_compile(&worker.state, url, ".");
  if let Err(err) = maybe_out {
    println!("{}", err);
    return;
  }
  let out = maybe_out.unwrap();

  println!("{} {}", ansi::bold("local:".to_string()), &(out.filename));

  println!(
    "{} {}",
    ansi::bold("type:".to_string()),
    msg::enum_name_media_type(out.media_type)
  );

  if out.maybe_output_code_filename.is_some() {
    println!(
      "{} {}",
      ansi::bold("compiled:".to_string()),
      out.maybe_output_code_filename.as_ref().unwrap(),
    );
  }

  if out.maybe_source_map_filename.is_some() {
    println!(
      "{} {}",
      ansi::bold("map:".to_string()),
      out.maybe_source_map_filename.as_ref().unwrap()
    );
  }

  let deps = worker.modules.deps(&out.module_name);
  println!("{}{}", ansi::bold("deps:\n".to_string()), deps.name);
  if let Some(ref depsdeps) = deps.deps {
    for d in depsdeps {
      println!("{}", d);
    }
  }
}

fn main() {
  #[cfg(windows)]
  ansi_term::enable_ansi_support().ok(); // For Windows 10

  log::set_logger(&LOGGER).unwrap();
  let args = env::args().collect();
  let (mut flags, mut rest_argv) =
    flags::set_flags(args).unwrap_or_else(|err| {
      eprintln!("{}", err);
      std::process::exit(1)
    });

  log::set_max_level(if flags.log_debug {
    LevelFilter::Debug
  } else {
    LevelFilter::Warn
  });

  if flags.fmt {
    rest_argv.insert(1, "https://deno.land/std/prettier/main.ts".to_string());
    flags.allow_read = true;
    flags.allow_write = true;
  }

  let should_prefetch = flags.prefetch || flags.info;
  let should_display_info = flags.info;

  let state = ThreadSafeState::new(flags, rest_argv, ops::op_selector_std);
  let mut worker = Worker::new(
    "main".to_string(),
    startup_data::deno_isolate_init(),
    state.clone(),
  );

  // TODO(ry) somehow combine the two branches below. They're very similar but
  // it's difficult to get the types to workout.

  if state.flags.eval {
    let main_future = lazy(move || {
      js_check(worker.execute("denoMain()"));
      // Wrap provided script in async function so asynchronous methods
      // work. This is required until top-level await is not supported.
      let js_source = format!(
        "async function _topLevelWrapper(){{
          {}
        }}
        _topLevelWrapper();
        ",
        &state.argv[1]
      );
      // ATM imports in `deno eval` are not allowed
      // TODO Support ES modules once Worker supports evaluating anonymous modules.
      js_check(worker.execute(&js_source));
      worker.then(|result| {
        js_check(result);
        Ok(())
      })
    });
    tokio_util::run(main_future);
  } else if let Some(main_module) = state.main_module() {
    // Normal situation of executing a module.

    let main_future = lazy(move || {
      // Setup runtime.
      js_check(worker.execute("denoMain()"));
      debug!("main_module {}", main_module);

      let main_url = root_specifier_to_url(&main_module).unwrap();

      worker
        .execute_mod_async(&main_url, should_prefetch)
        .and_then(move |worker| {
          if should_display_info {
            // Display file info and exit. Do not run file
            print_file_info(&worker, &main_module);
            std::process::exit(0);
          }
          worker.then(|result| {
            js_check(result);
            Ok(())
          })
        }).map_err(|(err, _worker)| print_err_and_exit(err))
    });
    tokio_util::run(main_future);
  } else {
    // REPL situation.
    let main_future = lazy(move || {
      // Setup runtime.
      js_check(worker.execute("denoMain()"));
      worker
        .then(|result| {
          js_check(result);
          Ok(())
        }).map_err(|(err, _worker): (RustOrJsError, Worker)| {
          print_err_and_exit(err)
        })
    });
    tokio_util::run(main_future);
  }
}