2022-01-08 03:09:52 +00:00
|
|
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
2021-01-08 02:08:51 +00:00
|
|
|
|
2021-01-19 02:40:22 +00:00
|
|
|
use crate::deno_dir::DenoDir;
|
2021-11-29 22:23:30 +00:00
|
|
|
use crate::flags::CheckFlag;
|
2021-01-08 02:08:51 +00:00
|
|
|
use crate::flags::DenoSubcommand;
|
|
|
|
use crate::flags::Flags;
|
2021-09-03 23:33:35 +00:00
|
|
|
use crate::flags::RunFlags;
|
2022-02-24 13:28:00 +00:00
|
|
|
use crate::standalone::Metadata;
|
|
|
|
use crate::standalone::MAGIC_TRAILER;
|
|
|
|
use crate::ProcState;
|
2021-11-16 14:02:28 +00:00
|
|
|
use deno_core::anyhow::bail;
|
2022-02-24 13:28:00 +00:00
|
|
|
use deno_core::anyhow::Context;
|
2021-01-08 02:08:51 +00:00
|
|
|
use deno_core::error::AnyError;
|
|
|
|
use deno_core::serde_json;
|
2022-02-24 13:28:00 +00:00
|
|
|
use deno_core::url::Url;
|
2022-02-15 12:33:46 +00:00
|
|
|
use deno_graph::ModuleSpecifier;
|
2021-01-19 02:40:22 +00:00
|
|
|
use deno_runtime::deno_fetch::reqwest::Client;
|
2022-02-24 13:28:00 +00:00
|
|
|
use deno_runtime::permissions::Permissions;
|
2021-01-19 02:40:22 +00:00
|
|
|
use std::env;
|
2021-01-08 02:08:51 +00:00
|
|
|
use std::fs::read;
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io::Read;
|
|
|
|
use std::io::Seek;
|
|
|
|
use std::io::SeekFrom;
|
|
|
|
use std::io::Write;
|
2021-01-19 02:40:22 +00:00
|
|
|
use std::path::Path;
|
2021-01-08 02:08:51 +00:00
|
|
|
use std::path::PathBuf;
|
|
|
|
|
2021-01-19 02:40:22 +00:00
|
|
|
pub async fn get_base_binary(
|
|
|
|
deno_dir: &DenoDir,
|
|
|
|
target: Option<String>,
|
|
|
|
) -> Result<Vec<u8>, AnyError> {
|
2021-04-26 17:28:38 +00:00
|
|
|
if target.is_none() {
|
2021-01-19 02:40:22 +00:00
|
|
|
let path = std::env::current_exe()?;
|
|
|
|
return Ok(tokio::fs::read(path).await?);
|
|
|
|
}
|
|
|
|
|
|
|
|
let target = target.unwrap_or_else(|| env!("TARGET").to_string());
|
2021-04-26 17:28:38 +00:00
|
|
|
let binary_name = format!("deno-{}.zip", target);
|
2021-01-19 02:40:22 +00:00
|
|
|
|
|
|
|
let binary_path_suffix = if crate::version::is_canary() {
|
|
|
|
format!("canary/{}/{}", crate::version::GIT_COMMIT_HASH, binary_name)
|
|
|
|
} else {
|
|
|
|
format!("release/v{}/{}", env!("CARGO_PKG_VERSION"), binary_name)
|
|
|
|
};
|
|
|
|
|
|
|
|
let download_directory = deno_dir.root.join("dl");
|
|
|
|
let binary_path = download_directory.join(&binary_path_suffix);
|
|
|
|
|
|
|
|
if !binary_path.exists() {
|
|
|
|
download_base_binary(&download_directory, &binary_path_suffix).await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let archive_data = tokio::fs::read(binary_path).await?;
|
2021-07-07 18:59:39 +00:00
|
|
|
let base_binary_path =
|
|
|
|
crate::tools::upgrade::unpack(archive_data, target.contains("windows"))?;
|
2021-01-19 02:40:22 +00:00
|
|
|
let base_binary = tokio::fs::read(base_binary_path).await?;
|
|
|
|
Ok(base_binary)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn download_base_binary(
|
|
|
|
output_directory: &Path,
|
|
|
|
binary_path_suffix: &str,
|
|
|
|
) -> Result<(), AnyError> {
|
|
|
|
let download_url = format!("https://dl.deno.land/{}", binary_path_suffix);
|
|
|
|
|
|
|
|
let client_builder = Client::builder();
|
|
|
|
let client = client_builder.build()?;
|
|
|
|
|
|
|
|
println!("Checking {}", &download_url);
|
|
|
|
|
|
|
|
let res = client.get(&download_url).send().await?;
|
|
|
|
|
|
|
|
let binary_content = if res.status().is_success() {
|
|
|
|
println!("Download has been found");
|
|
|
|
res.bytes().await?.to_vec()
|
|
|
|
} else {
|
|
|
|
println!("Download could not be found, aborting");
|
|
|
|
std::process::exit(1)
|
|
|
|
};
|
|
|
|
|
|
|
|
std::fs::create_dir_all(&output_directory)?;
|
|
|
|
let output_path = output_directory.join(binary_path_suffix);
|
|
|
|
std::fs::create_dir_all(&output_path.parent().unwrap())?;
|
|
|
|
tokio::fs::write(output_path, binary_content).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-08 02:08:51 +00:00
|
|
|
/// This functions creates a standalone deno binary by appending a bundle
|
|
|
|
/// and magic trailer to the currently executing binary.
|
2022-02-24 13:28:00 +00:00
|
|
|
pub async fn create_standalone_binary(
|
2021-01-19 02:40:22 +00:00
|
|
|
mut original_bin: Vec<u8>,
|
2022-02-15 12:33:46 +00:00
|
|
|
eszip: eszip::EszipV2,
|
|
|
|
entrypoint: ModuleSpecifier,
|
2021-01-08 02:08:51 +00:00
|
|
|
flags: Flags,
|
2022-02-24 13:28:00 +00:00
|
|
|
ps: ProcState,
|
2021-01-19 02:40:22 +00:00
|
|
|
) -> Result<Vec<u8>, AnyError> {
|
2022-02-15 12:33:46 +00:00
|
|
|
let mut eszip_archive = eszip.into_bytes();
|
|
|
|
|
2021-01-08 02:08:51 +00:00
|
|
|
let ca_data = match &flags.ca_file {
|
|
|
|
Some(ca_file) => Some(read(ca_file)?),
|
|
|
|
None => None,
|
|
|
|
};
|
2022-02-24 13:28:00 +00:00
|
|
|
let maybe_import_map: Option<(Url, String)> = match flags
|
|
|
|
.import_map_path
|
|
|
|
.as_ref()
|
|
|
|
{
|
|
|
|
None => None,
|
|
|
|
Some(import_map_url) => {
|
|
|
|
let import_map_specifier = deno_core::resolve_url_or_path(import_map_url)
|
|
|
|
.context(format!("Bad URL (\"{}\") for import map.", import_map_url))?;
|
|
|
|
let file = ps
|
|
|
|
.file_fetcher
|
|
|
|
.fetch(&import_map_specifier, &mut Permissions::allow_all())
|
|
|
|
.await
|
|
|
|
.context(format!(
|
|
|
|
"Unable to load '{}' import map",
|
|
|
|
import_map_specifier
|
|
|
|
))?;
|
|
|
|
|
|
|
|
Some((import_map_specifier, file.source.to_string()))
|
|
|
|
}
|
|
|
|
};
|
2021-01-08 02:08:51 +00:00
|
|
|
let metadata = Metadata {
|
|
|
|
argv: flags.argv.clone(),
|
|
|
|
unstable: flags.unstable,
|
|
|
|
seed: flags.seed,
|
|
|
|
location: flags.location.clone(),
|
2022-02-11 19:04:31 +00:00
|
|
|
permissions: flags.permissions_options(),
|
2021-01-08 02:08:51 +00:00
|
|
|
v8_flags: flags.v8_flags.clone(),
|
2021-08-10 11:19:45 +00:00
|
|
|
unsafely_ignore_certificate_errors: flags
|
|
|
|
.unsafely_ignore_certificate_errors
|
2021-08-09 14:53:21 +00:00
|
|
|
.clone(),
|
2021-01-08 02:08:51 +00:00
|
|
|
log_level: flags.log_level,
|
2021-08-07 12:49:38 +00:00
|
|
|
ca_stores: flags.ca_stores,
|
2021-01-08 02:08:51 +00:00
|
|
|
ca_data,
|
2022-02-15 12:33:46 +00:00
|
|
|
entrypoint,
|
2022-02-24 13:28:00 +00:00
|
|
|
maybe_import_map,
|
2021-01-08 02:08:51 +00:00
|
|
|
};
|
|
|
|
let mut metadata = serde_json::to_string(&metadata)?.as_bytes().to_vec();
|
|
|
|
|
2022-02-15 12:33:46 +00:00
|
|
|
let eszip_pos = original_bin.len();
|
|
|
|
let metadata_pos = eszip_pos + eszip_archive.len();
|
2021-01-08 02:08:51 +00:00
|
|
|
let mut trailer = MAGIC_TRAILER.to_vec();
|
2022-02-15 12:33:46 +00:00
|
|
|
trailer.write_all(&eszip_pos.to_be_bytes())?;
|
2021-01-08 02:08:51 +00:00
|
|
|
trailer.write_all(&metadata_pos.to_be_bytes())?;
|
|
|
|
|
2022-02-15 12:33:46 +00:00
|
|
|
let mut final_bin = Vec::with_capacity(
|
|
|
|
original_bin.len() + eszip_archive.len() + trailer.len(),
|
|
|
|
);
|
2021-01-08 02:08:51 +00:00
|
|
|
final_bin.append(&mut original_bin);
|
2022-02-15 12:33:46 +00:00
|
|
|
final_bin.append(&mut eszip_archive);
|
2021-01-08 02:08:51 +00:00
|
|
|
final_bin.append(&mut metadata);
|
|
|
|
final_bin.append(&mut trailer);
|
|
|
|
|
2021-01-19 02:40:22 +00:00
|
|
|
Ok(final_bin)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This function writes out a final binary to specified path. If output path
|
|
|
|
/// is not already standalone binary it will return error instead.
|
|
|
|
pub async fn write_standalone_binary(
|
|
|
|
output: PathBuf,
|
2021-03-07 13:20:01 +00:00
|
|
|
target: Option<String>,
|
2021-01-19 02:40:22 +00:00
|
|
|
final_bin: Vec<u8>,
|
|
|
|
) -> Result<(), AnyError> {
|
2021-03-07 13:20:01 +00:00
|
|
|
let output = match target {
|
|
|
|
Some(target) => {
|
|
|
|
if target.contains("windows") {
|
2022-01-11 04:24:39 +00:00
|
|
|
output.with_extension("exe")
|
2021-03-07 13:20:01 +00:00
|
|
|
} else {
|
|
|
|
output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
if cfg!(windows) && output.extension().unwrap_or_default() != "exe" {
|
2022-01-11 04:24:39 +00:00
|
|
|
output.with_extension("exe")
|
2021-03-07 13:20:01 +00:00
|
|
|
} else {
|
|
|
|
output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2021-01-08 02:08:51 +00:00
|
|
|
|
|
|
|
if output.exists() {
|
|
|
|
// If the output is a directory, throw error
|
|
|
|
if output.is_dir() {
|
2022-03-18 23:18:50 +00:00
|
|
|
bail!(
|
|
|
|
concat!(
|
|
|
|
"Could not compile to file '{}' because a directory exists with ",
|
|
|
|
"the same name. You can use the `--output <file-path>` flag to ",
|
|
|
|
"provide an alternative name."
|
|
|
|
),
|
|
|
|
output.display()
|
|
|
|
);
|
2021-01-08 02:08:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2022-03-18 23:18:50 +00:00
|
|
|
bail!(
|
|
|
|
concat!(
|
|
|
|
"Could not compile to file '{}' because the file already exists ",
|
|
|
|
"and cannot be overwritten. Please delete the existing file or ",
|
|
|
|
"use the `--output <file-path` flag to provide an alternative name."
|
|
|
|
),
|
|
|
|
output.display()
|
|
|
|
);
|
2021-01-08 02:08:51 +00:00
|
|
|
}
|
2021-04-23 10:33:45 +00:00
|
|
|
|
|
|
|
// Remove file if it was indeed a deno compiled binary, to avoid corruption
|
|
|
|
// (see https://github.com/denoland/deno/issues/10310)
|
|
|
|
std::fs::remove_file(&output)?;
|
2022-01-11 04:24:39 +00:00
|
|
|
} else {
|
|
|
|
let output_base = &output.parent().unwrap();
|
|
|
|
if output_base.exists() && output_base.is_file() {
|
2022-03-18 23:18:50 +00:00
|
|
|
bail!(
|
|
|
|
concat!(
|
|
|
|
"Could not compile to file '{}' because its parent directory ",
|
|
|
|
"is an existing file. You can use the `--output <file-path>` flag to ",
|
|
|
|
"provide an alternative name.",
|
|
|
|
),
|
|
|
|
output_base.display(),
|
|
|
|
);
|
2022-01-11 04:24:39 +00:00
|
|
|
}
|
|
|
|
tokio::fs::create_dir_all(output_base).await?;
|
2021-01-08 02:08:51 +00:00
|
|
|
}
|
2022-01-11 04:24:39 +00:00
|
|
|
|
2021-01-08 02:08:51 +00:00
|
|
|
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(
|
2022-02-11 19:04:31 +00:00
|
|
|
flags: &Flags,
|
2021-01-08 02:08:51 +00:00
|
|
|
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,
|
2021-09-03 23:33:35 +00:00
|
|
|
subcommand: DenoSubcommand::Run(RunFlags {
|
2021-01-08 02:08:51 +00:00
|
|
|
script: "placeholder".to_string(),
|
2021-09-03 23:33:35 +00:00
|
|
|
}),
|
2022-01-10 14:22:03 +00:00
|
|
|
allow_all: flags.allow_all,
|
2022-02-11 19:04:31 +00:00
|
|
|
allow_env: flags.allow_env.clone(),
|
2021-01-08 02:08:51 +00:00
|
|
|
allow_hrtime: flags.allow_hrtime,
|
2022-02-11 19:04:31 +00:00
|
|
|
allow_net: flags.allow_net.clone(),
|
|
|
|
allow_ffi: flags.allow_ffi.clone(),
|
|
|
|
allow_read: flags.allow_read.clone(),
|
|
|
|
allow_run: flags.allow_run.clone(),
|
|
|
|
allow_write: flags.allow_write.clone(),
|
|
|
|
ca_stores: flags.ca_stores.clone(),
|
|
|
|
ca_file: flags.ca_file.clone(),
|
2021-07-23 14:31:16 +00:00
|
|
|
cache_blocklist: vec![],
|
2021-07-27 21:25:09 +00:00
|
|
|
cache_path: None,
|
2021-01-08 02:08:51 +00:00
|
|
|
cached_only: false,
|
|
|
|
config_path: None,
|
2022-02-11 19:04:31 +00:00
|
|
|
coverage_dir: flags.coverage_dir.clone(),
|
2021-07-23 14:31:16 +00:00
|
|
|
enable_testing_features: false,
|
2021-01-08 02:08:51 +00:00
|
|
|
ignore: vec![],
|
2022-02-24 13:28:00 +00:00
|
|
|
import_map_path: flags.import_map_path.clone(),
|
2021-01-08 02:08:51 +00:00
|
|
|
inspect_brk: None,
|
2021-07-23 14:31:16 +00:00
|
|
|
inspect: None,
|
2022-02-11 19:04:31 +00:00
|
|
|
location: flags.location.clone(),
|
2021-01-08 02:08:51 +00:00
|
|
|
lock_write: false,
|
2021-07-23 14:31:16 +00:00
|
|
|
lock: None,
|
2021-01-08 02:08:51 +00:00
|
|
|
log_level: flags.log_level,
|
2021-11-29 22:23:30 +00:00
|
|
|
check: CheckFlag::All,
|
2021-10-04 23:35:55 +00:00
|
|
|
compat: flags.compat,
|
2021-08-10 11:19:45 +00:00
|
|
|
unsafely_ignore_certificate_errors: flags
|
2022-02-11 19:04:31 +00:00
|
|
|
.unsafely_ignore_certificate_errors
|
|
|
|
.clone(),
|
2021-01-08 02:08:51 +00:00
|
|
|
no_remote: false,
|
2022-02-13 03:13:21 +00:00
|
|
|
no_prompt: flags.no_prompt,
|
2021-01-08 02:08:51 +00:00
|
|
|
reload: false,
|
|
|
|
repl: false,
|
|
|
|
seed: flags.seed,
|
|
|
|
unstable: flags.unstable,
|
2022-02-11 19:04:31 +00:00
|
|
|
v8_flags: flags.v8_flags.clone(),
|
2021-01-08 02:08:51 +00:00
|
|
|
version: false,
|
2021-12-15 21:04:43 +00:00
|
|
|
watch: None,
|
2022-01-31 16:39:39 +00:00
|
|
|
no_clear_screen: false,
|
2021-01-08 02:08:51 +00:00
|
|
|
})
|
|
|
|
}
|