Skip to content

Commit fee3dd9

Browse files
authored
feat: add deno install --compile (#32046)
Compiled executables tend to be faster and do not depend on a Deno installation.
1 parent 7a98888 commit fee3dd9

File tree

6 files changed

+163
-4
lines changed

6 files changed

+163
-4
lines changed

cli/args/flags.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ pub struct InstallFlagsGlobal {
312312
pub name: Option<String>,
313313
pub root: Option<String>,
314314
pub force: bool,
315+
pub compile: bool,
315316
}
316317

317318
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -3427,6 +3428,13 @@ These must be added to the path manually if required."), UnstableArgsConfig::Res
34273428
.help("Forcefully overwrite existing installation")
34283429
.action(ArgAction::SetTrue),
34293430
)
3431+
.arg(
3432+
Arg::new("compile")
3433+
.long("compile")
3434+
.requires("global")
3435+
.help("Install the script as a compiled executable")
3436+
.action(ArgAction::SetTrue),
3437+
)
34303438
.arg(
34313439
Arg::new("global")
34323440
.long("global")
@@ -6356,6 +6364,7 @@ fn install_parse(
63566364
if global {
63576365
let root = matches.remove_one::<String>("root");
63586366
let force = matches.get_flag("force");
6367+
let compile = matches.get_flag("compile");
63596368
let name = matches.remove_one::<String>("name");
63606369
let module_urls = matches
63616370
.remove_many::<String>("cmd")
@@ -6376,13 +6385,28 @@ fn install_parse(
63766385
));
63776386
}
63786387

6388+
if compile && module_urls.len() > 1 {
6389+
return Err(clap::Error::raw(
6390+
clap::error::ErrorKind::InvalidValue,
6391+
format!(
6392+
"Cannot compile multiple packages ({}).",
6393+
module_urls.join(", ")
6394+
),
6395+
));
6396+
}
6397+
6398+
if compile {
6399+
flags.type_check_mode = TypeCheckMode::Local;
6400+
}
6401+
63796402
flags.subcommand =
63806403
DenoSubcommand::Install(InstallFlags::Global(InstallFlagsGlobal {
63816404
name,
63826405
module_urls,
63836406
args,
63846407
root,
63856408
force,
6409+
compile,
63866410
}));
63876411

63886412
return Ok(());
@@ -10449,6 +10473,7 @@ mod tests {
1044910473
args: vec![],
1045010474
root: None,
1045110475
force: false,
10476+
compile: false,
1045210477
}
1045310478
),),
1045410479
..Flags::default()
@@ -10471,6 +10496,7 @@ mod tests {
1047110496
args: vec![],
1047210497
root: None,
1047310498
force: false,
10499+
compile: false,
1047410500
}
1047510501
),),
1047610502
..Flags::default()
@@ -10492,6 +10518,7 @@ mod tests {
1049210518
args: svec!["foo", "bar"],
1049310519
root: Some("/foo".to_string()),
1049410520
force: true,
10521+
compile: false,
1049510522
}
1049610523
),),
1049710524
import_map_path: Some("import_map.json".to_string()),

cli/tools/installer/mod.rs

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ use regex::RegexBuilder;
3535

3636
pub use self::bin_name_resolver::BinNameResolver;
3737
use crate::args::AddFlags;
38+
use crate::args::CompileFlags;
3839
use crate::args::ConfigFlag;
40+
use crate::args::DenoSubcommand;
3941
use crate::args::Flags;
4042
use crate::args::InstallEntrypointsFlags;
4143
use crate::args::InstallFlags;
@@ -387,8 +389,8 @@ pub async fn uninstall(
387389
let mut removed = remove_file_if_exists(&file_path)?;
388390

389391
if cfg!(windows) {
390-
let file_path = file_path.with_extension("cmd");
391-
removed |= remove_file_if_exists(&file_path)?;
392+
removed |= remove_file_if_exists(&file_path.with_extension("cmd"))?;
393+
removed |= remove_file_if_exists(&file_path.with_extension("exe"))?;
392394
}
393395

394396
if !removed {
@@ -800,13 +802,13 @@ pub async fn install_command(
800802
) -> Result<(), AnyError> {
801803
match install_flags {
802804
InstallFlags::Global(global_flags) => {
803-
install_global(flags, global_flags).await
805+
Box::pin(install_global(flags, global_flags)).await
804806
}
805807
InstallFlags::Local(local_flags) => {
806808
if let InstallFlagsLocal::Add(add_flags) = &local_flags {
807809
check_if_installs_a_single_package_globally(Some(add_flags))?;
808810
}
809-
install_local(flags, local_flags).await
811+
Box::pin(install_local(flags, local_flags)).await
810812
}
811813
}
812814
}
@@ -857,6 +859,11 @@ async fn install_global(
857859
);
858860
}
859861

862+
if install_flags_global.compile {
863+
return Box::pin(install_global_compiled(flags, install_flags_global))
864+
.await;
865+
}
866+
860867
for (i, module_url) in install_flags_global.module_urls.iter().enumerate() {
861868
let entry_text = module_url;
862869
if !cli_options.initial_cwd().join(entry_text).exists() {
@@ -931,6 +938,78 @@ async fn install_global(
931938
Ok(())
932939
}
933940

941+
async fn install_global_compiled(
942+
flags: Arc<Flags>,
943+
install_flags_global: InstallFlagsGlobal,
944+
) -> Result<(), AnyError> {
945+
let cwd = std::env::current_dir().context("Unable to get CWD")?;
946+
let install_dir =
947+
get_installer_bin_dir(&cwd, install_flags_global.root.as_deref())?;
948+
949+
if let Ok(metadata) = fs::metadata(&install_dir) {
950+
if !metadata.is_dir() {
951+
return Err(anyhow!("Installation path is not a directory"));
952+
}
953+
} else {
954+
fs::create_dir_all(&install_dir)?;
955+
}
956+
957+
let source_file = install_flags_global
958+
.module_urls
959+
.first()
960+
.ok_or_else(|| anyhow!("No module URL provided"))?
961+
.clone();
962+
963+
// Determine the output path
964+
let output = if let Some(ref name) = install_flags_global.name {
965+
let mut output_path = install_dir.join(name);
966+
if cfg!(windows) {
967+
output_path = output_path.with_extension("exe");
968+
}
969+
output_path.to_string_lossy().into_owned()
970+
} else {
971+
format!("{}/", install_dir.to_string_lossy())
972+
};
973+
974+
let output_path = PathBuf::from(&output);
975+
if output_path.is_file() && !install_flags_global.force {
976+
return Err(anyhow!(
977+
"Existing installation found. Aborting (Use -f to overwrite).",
978+
));
979+
}
980+
981+
let compile_flags = CompileFlags {
982+
source_file,
983+
output: Some(output.clone()),
984+
args: install_flags_global.args,
985+
target: None,
986+
no_terminal: false,
987+
icon: None,
988+
include: vec![],
989+
exclude: vec![],
990+
eszip: false,
991+
};
992+
993+
let mut new_flags = flags.as_ref().clone();
994+
new_flags.subcommand = DenoSubcommand::Compile(compile_flags.clone());
995+
996+
crate::tools::compile::compile(new_flags, compile_flags).await?;
997+
998+
log::info!("Successfully installed {}", output);
999+
1000+
if !is_in_path(&install_dir) {
1001+
let installation_dir_str = install_dir.to_string_lossy();
1002+
log::info!("Add {} to PATH", installation_dir_str);
1003+
if cfg!(windows) {
1004+
log::info!(" set PATH=%PATH%;{}", installation_dir_str);
1005+
} else {
1006+
log::info!(" export PATH=\"{}:$PATH\"", installation_dir_str);
1007+
}
1008+
}
1009+
1010+
Ok(())
1011+
}
1012+
9341013
async fn create_install_shim(
9351014
bin_name_resolver: &BinNameResolver<'_>,
9361015
cwd: &Path,
@@ -1273,6 +1352,7 @@ mod tests {
12731352
name: Some("echo_test".to_string()),
12741353
root: Some(temp_dir.path().to_string()),
12751354
force: false,
1355+
compile: false,
12761356
},
12771357
)
12781358
.await
@@ -1309,6 +1389,7 @@ mod tests {
13091389
name: None,
13101390
root: Some(env::temp_dir().to_string_lossy().into_owned()),
13111391
force: false,
1392+
compile: false,
13121393
},
13131394
)
13141395
.await
@@ -1331,6 +1412,7 @@ mod tests {
13311412
name: None,
13321413
root: Some(env::temp_dir().to_string_lossy().into_owned()),
13331414
force: false,
1415+
compile: false,
13341416
},
13351417
)
13361418
.await
@@ -1359,6 +1441,7 @@ mod tests {
13591441
name: None,
13601442
root: Some(env::temp_dir().to_string_lossy().into_owned()),
13611443
force: false,
1444+
compile: false,
13621445
},
13631446
)
13641447
.await
@@ -1387,6 +1470,7 @@ mod tests {
13871470
name: None,
13881471
root: Some(env::temp_dir().to_string_lossy().into_owned()),
13891472
force: false,
1473+
compile: false,
13901474
},
13911475
)
13921476
.await
@@ -1413,6 +1497,7 @@ mod tests {
14131497
name: None,
14141498
root: Some(env::temp_dir().to_string_lossy().into_owned()),
14151499
force: false,
1500+
compile: false,
14161501
},
14171502
)
14181503
.await
@@ -1439,6 +1524,7 @@ mod tests {
14391524
name: Some("echo_test".to_string()),
14401525
root: Some(env::temp_dir().to_string_lossy().into_owned()),
14411526
force: false,
1527+
compile: false,
14421528
},
14431529
)
14441530
.await
@@ -1470,6 +1556,7 @@ mod tests {
14701556
name: Some("echo_test".to_string()),
14711557
root: Some(env::temp_dir().to_string_lossy().into_owned()),
14721558
force: false,
1559+
compile: false,
14731560
},
14741561
)
14751562
.await
@@ -1506,6 +1593,7 @@ mod tests {
15061593
name: Some("echo_test".to_string()),
15071594
root: Some(env::temp_dir().to_string_lossy().into_owned()),
15081595
force: false,
1596+
compile: false,
15091597
},
15101598
)
15111599
.await
@@ -1538,6 +1626,7 @@ mod tests {
15381626
name: Some("echo_test".to_string()),
15391627
root: Some(env::temp_dir().to_string_lossy().into_owned()),
15401628
force: false,
1629+
compile: false,
15411630
},
15421631
)
15431632
.await
@@ -1571,6 +1660,7 @@ mod tests {
15711660
name: None,
15721661
root: Some(temp_dir.to_string_lossy().into_owned()),
15731662
force: false,
1663+
compile: false,
15741664
},
15751665
)
15761666
.await
@@ -1608,6 +1698,7 @@ mod tests {
16081698
name: None,
16091699
root: Some(env::temp_dir().to_string_lossy().into_owned()),
16101700
force: false,
1701+
compile: false,
16111702
},
16121703
)
16131704
.await
@@ -1643,6 +1734,7 @@ mod tests {
16431734
name: Some("echo_test".to_string()),
16441735
root: Some(temp_dir.path().to_string()),
16451736
force: false,
1737+
compile: false,
16461738
},
16471739
)
16481740
.await
@@ -1672,6 +1764,7 @@ mod tests {
16721764
name: Some("echo_test".to_string()),
16731765
root: Some(temp_dir.path().to_string()),
16741766
force: false,
1767+
compile: false,
16751768
},
16761769
)
16771770
.await
@@ -1692,6 +1785,7 @@ mod tests {
16921785
name: Some("echo_test".to_string()),
16931786
root: Some(temp_dir.path().to_string()),
16941787
force: false,
1788+
compile: false,
16951789
},
16961790
)
16971791
.await;
@@ -1715,6 +1809,7 @@ mod tests {
17151809
name: Some("echo_test".to_string()),
17161810
root: Some(temp_dir.path().to_string()),
17171811
force: true,
1812+
compile: false,
17181813
},
17191814
)
17201815
.await;
@@ -1745,6 +1840,7 @@ mod tests {
17451840
name: Some("echo_test".to_string()),
17461841
root: Some(temp_dir.path().to_string()),
17471842
force: true,
1843+
compile: false,
17481844
},
17491845
)
17501846
.await;
@@ -1774,6 +1870,7 @@ mod tests {
17741870
name: Some("echo_test".to_string()),
17751871
root: Some(temp_dir.path().to_string()),
17761872
force: false,
1873+
compile: false,
17771874
},
17781875
)
17791876
.await
@@ -1814,6 +1911,7 @@ mod tests {
18141911
name: Some("echo_test".to_string()),
18151912
root: Some(temp_dir.path().to_string()),
18161913
force: false,
1914+
compile: false,
18171915
},
18181916
)
18191917
.await
@@ -1859,6 +1957,7 @@ mod tests {
18591957
name: Some("echo_test".to_string()),
18601958
root: Some(temp_dir.path().to_string()),
18611959
force: true,
1960+
compile: false,
18621961
},
18631962
)
18641963
.await;
@@ -1901,6 +2000,7 @@ mod tests {
19012000
name: Some("echo_test".to_string()),
19022001
root: Some(temp_dir.path().to_string()),
19032002
force: true,
2003+
compile: false,
19042004
},
19052005
)
19062006
.await;

0 commit comments

Comments
 (0)