summaryrefslogtreecommitdiff
path: root/cli/tools/standalone.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/standalone.rs')
-rw-r--r--cli/tools/standalone.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/cli/tools/standalone.rs b/cli/tools/standalone.rs
new file mode 100644
index 000000000..112169756
--- /dev/null
+++ b/cli/tools/standalone.rs
@@ -0,0 +1,146 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+
+use crate::flags::DenoSubcommand;
+use crate::flags::Flags;
+use deno_core::error::bail;
+use deno_core::error::AnyError;
+use deno_core::serde_json;
+use std::fs::read;
+use std::fs::File;
+use std::io::Read;
+use std::io::Seek;
+use std::io::SeekFrom;
+use std::io::Write;
+use std::path::PathBuf;
+
+use crate::standalone::Metadata;
+use crate::standalone::MAGIC_TRAILER;
+
+/// This functions creates a standalone deno binary by appending a bundle
+/// and magic trailer to the currently executing binary.
+pub async fn create_standalone_binary(
+ source_code: String,
+ flags: Flags,
+ output: PathBuf,
+) -> Result<(), AnyError> {
+ let mut source_code = source_code.as_bytes().to_vec();
+ let ca_data = match &flags.ca_file {
+ Some(ca_file) => Some(read(ca_file)?),
+ None => None,
+ };
+ let metadata = Metadata {
+ argv: flags.argv.clone(),
+ unstable: flags.unstable,
+ seed: flags.seed,
+ location: flags.location.clone(),
+ permissions: flags.clone().into(),
+ v8_flags: flags.v8_flags.clone(),
+ log_level: flags.log_level,
+ ca_data,
+ };
+ let mut metadata = serde_json::to_string(&metadata)?.as_bytes().to_vec();
+ let original_binary_path = std::env::current_exe()?;
+ let mut original_bin = tokio::fs::read(original_binary_path).await?;
+
+ let bundle_pos = original_bin.len();
+ let metadata_pos = bundle_pos + source_code.len();
+ let mut trailer = MAGIC_TRAILER.to_vec();
+ trailer.write_all(&bundle_pos.to_be_bytes())?;
+ trailer.write_all(&metadata_pos.to_be_bytes())?;
+
+ let mut final_bin =
+ Vec::with_capacity(original_bin.len() + source_code.len() + trailer.len());
+ final_bin.append(&mut original_bin);
+ final_bin.append(&mut source_code);
+ final_bin.append(&mut metadata);
+ final_bin.append(&mut trailer);
+
+ let output =
+ if cfg!(windows) && output.extension().unwrap_or_default() != "exe" {
+ PathBuf::from(output.display().to_string() + ".exe")
+ } else {
+ output
+ };
+
+ if output.exists() {
+ // If the output is a directory, throw error
+ if output.is_dir() {
+ bail!("Could not compile: {:?} is a directory.", &output);
+ }
+
+ // Make sure we don't overwrite any file not created by Deno compiler.
+ // Check for magic trailer in last 24 bytes.
+ let mut has_trailer = false;
+ let mut output_file = File::open(&output)?;
+ // This seek may fail because the file is too small to possibly be
+ // `deno compile` output.
+ if output_file.seek(SeekFrom::End(-24)).is_ok() {
+ let mut trailer = [0; 24];
+ output_file.read_exact(&mut trailer)?;
+ let (magic_trailer, _) = trailer.split_at(8);
+ has_trailer = magic_trailer == MAGIC_TRAILER;
+ }
+ if !has_trailer {
+ bail!("Could not compile: cannot overwrite {:?}.", &output);
+ }
+ }
+ tokio::fs::write(&output, final_bin).await?;
+ #[cfg(unix)]
+ {
+ use std::os::unix::fs::PermissionsExt;
+ let perms = std::fs::Permissions::from_mode(0o777);
+ tokio::fs::set_permissions(output, perms).await?;
+ }
+
+ Ok(())
+}
+
+/// Transform the flags passed to `deno compile` to flags that would be used at
+/// runtime, as if `deno run` were used.
+/// - Flags that affect module resolution, loading, type checking, etc. aren't
+/// applicable at runtime so are set to their defaults like `false`.
+/// - Other flags are inherited.
+pub fn compile_to_runtime_flags(
+ flags: Flags,
+ baked_args: Vec<String>,
+) -> Result<Flags, AnyError> {
+ // IMPORTANT: Don't abbreviate any of this to `..flags` or
+ // `..Default::default()`. That forces us to explicitly consider how any
+ // change to `Flags` should be reflected here.
+ Ok(Flags {
+ argv: baked_args,
+ subcommand: DenoSubcommand::Run {
+ script: "placeholder".to_string(),
+ },
+ allow_env: flags.allow_env,
+ allow_hrtime: flags.allow_hrtime,
+ allow_net: flags.allow_net,
+ allow_plugin: flags.allow_plugin,
+ allow_read: flags.allow_read,
+ allow_run: flags.allow_run,
+ allow_write: flags.allow_write,
+ cache_blocklist: vec![],
+ ca_file: flags.ca_file,
+ cached_only: false,
+ config_path: None,
+ coverage_dir: flags.coverage_dir,
+ ignore: vec![],
+ import_map_path: None,
+ inspect: None,
+ inspect_brk: None,
+ location: flags.location,
+ lock: None,
+ lock_write: false,
+ log_level: flags.log_level,
+ no_check: false,
+ no_prompts: flags.no_prompts,
+ no_remote: false,
+ reload: false,
+ repl: false,
+ seed: flags.seed,
+ unstable: flags.unstable,
+ v8_flags: flags.v8_flags,
+ version: false,
+ watch: false,
+ })
+}