1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

feat: deno compile --icon <ico> (#25039)

Add `--icon` flag to set deno compile'd executable icon on Windows.

```
deno compile --icon icon.ico game.tsx
```

Depends on https://github.com/denoland/sui/pull/24

<img width="447" alt="image"
src="https://github.com/user-attachments/assets/7f6f3aa0-6872-4975-ae9d-06701b7684b8">

Closes https://github.com/denoland/deno/issues/8912
This commit is contained in:
Divy Srivastava 2024-08-14 21:42:23 -07:00 committed by GitHub
parent e92a05b551
commit 7ca95fc999
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 38 additions and 7 deletions

4
Cargo.lock generated
View file

@ -4169,9 +4169,9 @@ dependencies = [
[[package]] [[package]]
name = "libsui" name = "libsui"
version = "0.1.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2fedcf6cb4dd935f94a90e1c4300c727fe7112b8455615e902828c7401f84d" checksum = "2d0f34a58599483cd44a31ff3622dbcca0c50679af60f98b705069dc729e70cf"
dependencies = [ dependencies = [
"editpe", "editpe",
"libc", "libc",

View file

@ -79,7 +79,7 @@ deno_semver = "=0.5.10"
deno_task_shell = "=0.17.0" deno_task_shell = "=0.17.0"
deno_terminal.workspace = true deno_terminal.workspace = true
eszip = "=0.73.0" eszip = "=0.73.0"
libsui = "0.1.0" libsui = "0.3.0"
napi_sym.workspace = true napi_sym.workspace = true
node_resolver.workspace = true node_resolver.workspace = true

View file

@ -121,6 +121,7 @@ pub struct CompileFlags {
pub args: Vec<String>, pub args: Vec<String>,
pub target: Option<String>, pub target: Option<String>,
pub no_terminal: bool, pub no_terminal: bool,
pub icon: Option<String>,
pub include: Vec<String>, pub include: Vec<String>,
} }
@ -1769,6 +1770,12 @@ supported in canary.
.help("Hide terminal on Windows") .help("Hide terminal on Windows")
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg(
Arg::new("icon")
.long("icon")
.help("Set the icon of the executable on Windows (.ico)")
.value_parser(value_parser!(String))
)
.arg(executable_ext_arg()) .arg(executable_ext_arg())
.arg(env_file_arg()) .arg(env_file_arg())
.arg(script_arg().required(true).trailing_var_arg(true)) .arg(script_arg().required(true).trailing_var_arg(true))
@ -3891,6 +3898,7 @@ fn compile_parse(flags: &mut Flags, matches: &mut ArgMatches) {
let args = script.collect(); let args = script.collect();
let output = matches.remove_one::<String>("output"); let output = matches.remove_one::<String>("output");
let target = matches.remove_one::<String>("target"); let target = matches.remove_one::<String>("target");
let icon = matches.remove_one::<String>("icon");
let no_terminal = matches.get_flag("no-terminal"); let no_terminal = matches.get_flag("no-terminal");
let include = match matches.remove_many::<String>("include") { let include = match matches.remove_many::<String>("include") {
Some(f) => f.collect(), Some(f) => f.collect(),
@ -3904,6 +3912,7 @@ fn compile_parse(flags: &mut Flags, matches: &mut ArgMatches) {
args, args,
target, target,
no_terminal, no_terminal,
icon,
include, include,
}); });
} }
@ -9554,6 +9563,7 @@ mod tests {
args: vec![], args: vec![],
target: None, target: None,
no_terminal: false, no_terminal: false,
icon: None,
include: vec![] include: vec![]
}), }),
type_check_mode: TypeCheckMode::Local, type_check_mode: TypeCheckMode::Local,
@ -9565,7 +9575,7 @@ mod tests {
#[test] #[test]
fn compile_with_flags() { fn compile_with_flags() {
#[rustfmt::skip] #[rustfmt::skip]
let r = flags_from_vec(svec!["deno", "compile", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--no-terminal", "--output", "colors", "--env=.example.env", "https://examples.deno.land/color-logging.ts", "foo", "bar", "-p", "8080"]); let r = flags_from_vec(svec!["deno", "compile", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--no-terminal", "--icon", "favicon.ico", "--output", "colors", "--env=.example.env", "https://examples.deno.land/color-logging.ts", "foo", "bar", "-p", "8080"]);
assert_eq!( assert_eq!(
r.unwrap(), r.unwrap(),
Flags { Flags {
@ -9576,6 +9586,7 @@ mod tests {
args: svec!["foo", "bar", "-p", "8080"], args: svec!["foo", "bar", "-p", "8080"],
target: None, target: None,
no_terminal: true, no_terminal: true,
icon: Some(String::from("favicon.ico")),
include: vec![] include: vec![]
}), }),
import_map_path: Some("import_map.json".to_string()), import_map_path: Some("import_map.json".to_string()),

View file

@ -187,10 +187,19 @@ fn write_binary_bytes(
let target = compile_flags.resolve_target(); let target = compile_flags.resolve_target();
if target.contains("linux") { if target.contains("linux") {
libsui::Elf::new(&original_bin).append(&writer, &mut file_writer)?; libsui::Elf::new(&original_bin).append(
"d3n0l4nd",
&writer,
&mut file_writer,
)?;
} else if target.contains("windows") { } else if target.contains("windows") {
libsui::PortableExecutable::from(&original_bin)? let mut pe = libsui::PortableExecutable::from(&original_bin)?;
.write_resource("d3n0l4nd", writer)? if let Some(icon) = compile_flags.icon.as_ref() {
let icon = std::fs::read(icon)?;
pe = pe.set_icon(&icon)?;
}
pe.write_resource("d3n0l4nd", writer)?
.build(&mut file_writer)?; .build(&mut file_writer)?;
} else if target.contains("darwin") { } else if target.contains("darwin") {
libsui::Macho::from(original_bin)? libsui::Macho::from(original_bin)?
@ -370,6 +379,15 @@ impl<'a> DenoCompileBinaryWriter<'a> {
} }
set_windows_binary_to_gui(&mut original_binary)?; set_windows_binary_to_gui(&mut original_binary)?;
} }
if compile_flags.icon.is_some() {
let target = compile_flags.resolve_target();
if !target.contains("windows") {
bail!(
"The `--icon` flag is only available when targeting Windows (current: {})",
target,
)
}
}
self.write_standalone_binary( self.write_standalone_binary(
writer, writer,
original_binary, original_binary,

View file

@ -361,6 +361,7 @@ mod test {
args: Vec::new(), args: Vec::new(),
target: Some("x86_64-unknown-linux-gnu".to_string()), target: Some("x86_64-unknown-linux-gnu".to_string()),
no_terminal: false, no_terminal: false,
icon: None,
include: vec![], include: vec![],
}, },
&std::env::current_dir().unwrap(), &std::env::current_dir().unwrap(),
@ -385,6 +386,7 @@ mod test {
args: Vec::new(), args: Vec::new(),
target: Some("x86_64-pc-windows-msvc".to_string()), target: Some("x86_64-pc-windows-msvc".to_string()),
include: vec![], include: vec![],
icon: None,
no_terminal: false, no_terminal: false,
}, },
&std::env::current_dir().unwrap(), &std::env::current_dir().unwrap(),