Skip to content

Commit c29f258

Browse files
Merge pull request #12 from zirco-lang/copilot/update-zircon-build-process
Delegate zrc build and install to hook scripts
2 parents fe06734 + feba067 commit c29f258

8 files changed

Lines changed: 145 additions & 256 deletions

File tree

src/build.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
//! Build operations for compiling zrc
1+
//! Build operations for compiling Rust projects
22
3-
use std::path::Path;
4-
use std::process::Command;
3+
use std::{path::Path, process::Command};
54

6-
/// Build zrc using cargo
7-
pub fn build_zrc(source_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
8-
println!("Building zrc (this may take several minutes)...");
5+
/// Build a Rust project using cargo
6+
pub fn build_rust_project(source_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
7+
println!("Building (this may take several minutes)...");
98

109
let status = Command::new("cargo")
1110
.arg("build")
@@ -15,7 +14,7 @@ pub fn build_zrc(source_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
1514

1615
if !status.success() {
1716
let exit_code = status.code().unwrap_or(-1);
18-
return Err(format!("Failed to build zrc (exit code: {})", exit_code).into());
17+
return Err(format!("Build failed (exit code: {})", exit_code).into());
1918
}
2019

2120
println!("Build complete!");

src/cmds/build_cmds.rs

Lines changed: 89 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Commands for building zrc toolchains
22
3+
use std::{error::Error, process::Command};
4+
35
use clap::Parser;
4-
use std::error::Error;
56

6-
use crate::cli::DispatchCommand;
7-
use crate::{build, deps, git_utils, installer, paths};
7+
use crate::{cli::DispatchCommand, deps, git_utils, paths};
88

99
/// Build a specific version of zrc
1010
#[derive(Parser)]
@@ -54,56 +54,104 @@ impl DispatchCommand for BuildCmd {
5454

5555
println!("Building version: {}", version);
5656

57-
// Check if cargo is available
58-
build::check_cargo()?;
59-
60-
// Build zrc
61-
build::build_zrc(&source_dir)?;
62-
6357
// Create toolchain directory
6458
let toolchain_dir = paths::toolchain_dir(&version);
65-
let toolchain_bin_dir = paths::toolchain_bin_dir(&version);
66-
let toolchain_include_dir = paths::toolchain_include_dir(&version);
67-
68-
std::fs::create_dir_all(&toolchain_bin_dir)?;
69-
std::fs::create_dir_all(&toolchain_include_dir)?;
70-
71-
// Install binary
72-
installer::install_zrc_binary(&source_dir, &toolchain_bin_dir)?;
73-
74-
// Install zircop binary if it exists
75-
let has_zircop = installer::install_zircop_binary(&source_dir, &toolchain_bin_dir)?;
59+
std::fs::create_dir_all(&toolchain_dir)?;
7660

77-
// Install include files
78-
installer::install_include_files(&source_dir, &toolchain_include_dir)?;
61+
// Execute the hook script from the zrc repo
62+
// The hook handles building and installing to the toolchain directory
63+
run_build_hook(&source_dir, &toolchain_dir)?;
7964

8065
// Update current symlink
8166
let current_link = paths::current_toolchain_link();
8267
paths::create_link(&toolchain_dir, &current_link)?;
8368

84-
// Create/update bin links
85-
let zrc_link = paths::zrc_binary_link();
86-
let zrc_binary = paths::toolchain_zrc_binary(&version);
87-
paths::create_link(&zrc_binary, &zrc_link)?;
88-
89-
// Create/update zircop bin link if it exists
90-
if has_zircop {
91-
let zircop_link = paths::zircop_binary_link();
92-
let zircop_binary = paths::toolchain_zircop_binary(&version);
93-
paths::create_link(&zircop_binary, &zircop_link)?;
94-
}
95-
96-
// Create/update include link
97-
let include_link = paths::include_dir_link();
98-
paths::create_link(&toolchain_include_dir, &include_link)?;
99-
10069
println!("\n✓ Successfully built and installed zrc {}", version);
10170
println!(" Toolchain location: {}", toolchain_dir.display());
102-
println!("\nTo use zrc, add to your PATH:");
103-
println!(" export PATH=\"{}:$PATH\"", paths::bin_dir().display());
104-
println!("\nOr run:");
71+
println!("\nTo use zrc, run:");
10572
println!(" source <(zircon env)");
10673

10774
Ok(())
10875
}
10976
}
77+
78+
/// Run the build hook script from the zrc repository
79+
#[cfg(unix)]
80+
fn run_build_hook(
81+
source_dir: &std::path::Path,
82+
toolchain_dir: &std::path::Path,
83+
) -> Result<(), Box<dyn Error>> {
84+
let hook_script = source_dir.join("hooks").join("zircon.sh");
85+
if !hook_script.exists() {
86+
return Err(format!(
87+
"Hook script not found at {}. This version of zrc may not support zircon hooks.",
88+
hook_script.display()
89+
)
90+
.into());
91+
}
92+
93+
println!("Running zrc build hook...");
94+
let status = Command::new("bash")
95+
.arg(&hook_script)
96+
.env("ZIRCON_TOOLCHAIN_DIR", toolchain_dir)
97+
.current_dir(source_dir)
98+
.status()?;
99+
100+
if !status.success() {
101+
let exit_code = status.code().unwrap_or(-1);
102+
return Err(format!("Hook script failed (exit code: {})", exit_code).into());
103+
}
104+
105+
Ok(())
106+
}
107+
108+
/// Run the build hook script from the zrc repository (Windows)
109+
#[cfg(windows)]
110+
fn run_build_hook(
111+
source_dir: &std::path::Path,
112+
toolchain_dir: &std::path::Path,
113+
) -> Result<(), Box<dyn Error>> {
114+
// Check for PowerShell script first, then batch file
115+
let ps_hook = source_dir.join("hooks").join("zircon.ps1");
116+
let bat_hook = source_dir.join("hooks").join("zircon.bat");
117+
118+
if ps_hook.exists() {
119+
println!("Running zrc build hook (PowerShell)...");
120+
// Use Bypass to run local scripts regardless of system execution policy.
121+
// This is safe because the script is part of the zrc repo the user cloned.
122+
let status = Command::new("powershell")
123+
.args(["-ExecutionPolicy", "Bypass", "-File"])
124+
.arg(&ps_hook)
125+
.env("ZIRCON_TOOLCHAIN_DIR", toolchain_dir)
126+
.current_dir(source_dir)
127+
.status()?;
128+
129+
if !status.success() {
130+
let exit_code = status.code().unwrap_or(-1);
131+
return Err(format!("Hook script failed (exit code: {})", exit_code).into());
132+
}
133+
} else if bat_hook.exists() {
134+
println!("Running zrc build hook (batch)...");
135+
let status = Command::new("cmd")
136+
.args(["/C"])
137+
.arg(&bat_hook)
138+
.env("ZIRCON_TOOLCHAIN_DIR", toolchain_dir)
139+
.current_dir(source_dir)
140+
.status()?;
141+
142+
if !status.success() {
143+
let exit_code = status.code().unwrap_or(-1);
144+
return Err(format!("Hook script failed (exit code: {})", exit_code).into());
145+
}
146+
} else {
147+
return Err(format!(
148+
"No Windows hook script found at {} or {}. \
149+
This version of zrc may not support Windows builds via zircon hooks.",
150+
ps_hook.display(),
151+
bat_hook.display()
152+
)
153+
.into());
154+
}
155+
156+
Ok(())
157+
}

src/cmds/env_cmds.rs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
//! Commands for environment configuration
22
3+
use std::{error::Error, path::Path};
4+
35
use clap::Parser;
4-
use std::error::Error;
5-
use std::path::Path;
66

7-
use crate::cli::DispatchCommand;
8-
use crate::paths;
7+
use crate::{cli::DispatchCommand, paths};
98

109
/// Output shell environment configuration
1110
#[derive(Parser)]
@@ -18,7 +17,6 @@ pub struct EnvCmd {
1817
impl DispatchCommand for EnvCmd {
1918
fn dispatch(self) -> Result<(), Box<dyn Error>> {
2019
let bin_dir = paths::bin_dir();
21-
let include_dir = paths::include_dir_link();
2220

2321
// Determine shell type
2422
let shell_type = self
@@ -30,45 +28,55 @@ impl DispatchCommand for EnvCmd {
3028
// Fish shell syntax - use double quotes and escape internal quotes
3129
let bin_escaped = escape_for_fish(&bin_dir);
3230
println!("set -gx PATH {} $PATH;", bin_escaped);
33-
if include_dir.exists() {
34-
let include_escaped = escape_for_fish(&include_dir);
35-
println!("set -gx ZIRCO_INCLUDE_PATH {};", include_escaped);
31+
// Source the toolchain's env.sh if it exists
32+
let toolchain_env_sh = paths::current_toolchain_env_sh();
33+
if toolchain_env_sh.exists() {
34+
let env_sh_escaped = escape_for_fish(&toolchain_env_sh);
35+
println!("source {};", env_sh_escaped);
3636
}
3737
}
3838
"powershell" | "pwsh" => {
3939
// PowerShell syntax - double-quote and escape internal double quotes
4040
let bin_escaped = escape_for_powershell(&bin_dir);
4141
println!("$env:Path = \"{};$env:Path\";", bin_escaped);
42-
if include_dir.exists() {
43-
let include_escaped = escape_for_powershell(&include_dir);
44-
println!("$env:ZIRCO_INCLUDE_PATH = \"{}\";", include_escaped);
42+
// Source the toolchain's env.ps1 if it exists (PowerShell uses . for sourcing)
43+
let toolchain_env_ps1 = paths::current_toolchain_env_ps1();
44+
if toolchain_env_ps1.exists() {
45+
let env_ps1_escaped = escape_for_powershell(&toolchain_env_ps1);
46+
println!(". \"{}\";", env_ps1_escaped);
4547
}
4648
}
4749
"cmd" => {
4850
// Windows CMD syntax - escape percent signs and carets
4951
let bin_escaped = escape_for_cmd(&bin_dir);
5052
println!("set PATH={};%PATH%", bin_escaped);
51-
if include_dir.exists() {
52-
let include_escaped = escape_for_cmd(&include_dir);
53-
println!("set ZIRCO_INCLUDE_PATH={}", include_escaped);
53+
// Source the toolchain's env.bat if it exists (CMD uses call)
54+
let toolchain_env_bat = paths::current_toolchain_env_bat();
55+
if toolchain_env_bat.exists() {
56+
let env_bat_escaped = escape_for_cmd(&toolchain_env_bat);
57+
println!("call {}", env_bat_escaped);
5458
}
5559
}
5660
"zsh" | "bash" | "sh" => {
5761
// Bash/Zsh syntax - use single quotes and escape internal single quotes
5862
let bin_escaped = escape_for_posix_shell(&bin_dir);
5963
println!("export PATH={}:$PATH;", bin_escaped);
60-
if include_dir.exists() {
61-
let include_escaped = escape_for_posix_shell(&include_dir);
62-
println!("export ZIRCO_INCLUDE_PATH={};", include_escaped);
64+
// Source the toolchain's env.sh if it exists
65+
let toolchain_env_sh = paths::current_toolchain_env_sh();
66+
if toolchain_env_sh.exists() {
67+
let env_sh_escaped = escape_for_posix_shell(&toolchain_env_sh);
68+
println!("source {};", env_sh_escaped);
6369
}
6470
}
6571
_ => {
6672
// Default for unknown shells - use POSIX syntax
6773
let bin_escaped = escape_for_posix_shell(&bin_dir);
6874
println!("export PATH={}:$PATH;", bin_escaped);
69-
if include_dir.exists() {
70-
let include_escaped = escape_for_posix_shell(&include_dir);
71-
println!("export ZIRCO_INCLUDE_PATH={};", include_escaped);
75+
// Source the toolchain's env.sh if it exists
76+
let toolchain_env_sh = paths::current_toolchain_env_sh();
77+
if toolchain_env_sh.exists() {
78+
let env_sh_escaped = escape_for_posix_shell(&toolchain_env_sh);
79+
println!("source {};", env_sh_escaped);
7280
}
7381
}
7482
}
@@ -89,7 +97,8 @@ fn escape_for_posix_shell(path: &Path) -> String {
8997
/// Uses double quotes or falls back to proper escaping
9098
fn escape_for_fish(path: &Path) -> String {
9199
let path_str = path.display().to_string();
92-
// For fish, we can use double quotes and escape internal double quotes, backslashes, and dollar signs
100+
// For fish, we can use double quotes and escape internal double quotes,
101+
// backslashes, and dollar signs
93102
let escaped = path_str
94103
.replace('\\', "\\\\")
95104
.replace('"', "\\\"")

src/cmds/self_cmds.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
33
mod cmd_version;
44

5-
use std::error::Error;
6-
use std::fs;
5+
use std::{error::Error, fs};
76

87
use clap::{Parser, Subcommand};
98

@@ -57,7 +56,7 @@ fn cmd_self_update(reference: &str) -> Result<(), Box<dyn Error>> {
5756

5857
println!("Building Zircon...");
5958
build::check_cargo()?;
60-
build::build_zrc(&zircon_source)?; // Reuse the build function, it just runs cargo build --release
59+
build::build_rust_project(&zircon_source)?;
6160

6261
// Copy the new binary
6362
let binary_name = if cfg!(windows) {

src/cmds/toolchain_cmds.rs

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Commands for managing toolchains
22
3-
use clap::Parser;
43
use std::error::Error;
54

6-
use crate::cli::DispatchCommand;
7-
use crate::{paths, toolchains};
5+
use clap::Parser;
6+
7+
use crate::{cli::DispatchCommand, paths, toolchains};
88

99
/// Switch to a different installed toolchain version
1010
#[derive(Parser)]
@@ -31,28 +31,6 @@ impl DispatchCommand for SwitchCmd {
3131
let current_link = paths::current_toolchain_link();
3232
paths::create_link(&toolchain_dir, &current_link)?;
3333

34-
// Update bin links
35-
let zrc_link = paths::zrc_binary_link();
36-
let zrc_binary = paths::toolchain_zrc_binary(&self.version);
37-
paths::create_link(&zrc_binary, &zrc_link)?;
38-
39-
// Update zircop bin link if it exists in the toolchain
40-
let zircop_link = paths::zircop_binary_link();
41-
let zircop_binary = paths::toolchain_zircop_binary(&self.version);
42-
if zircop_binary.exists() {
43-
paths::create_link(&zircop_binary, &zircop_link)?;
44-
} else {
45-
// Remove zircop link if it exists but the new toolchain doesn't have it
46-
if zircop_link.exists() || zircop_link.read_link().is_ok() {
47-
std::fs::remove_file(&zircop_link).ok();
48-
}
49-
}
50-
51-
// Update include link
52-
let include_link = paths::include_dir_link();
53-
let toolchain_include_dir = paths::toolchain_include_dir(&self.version);
54-
paths::create_link(&toolchain_include_dir, &include_link)?;
55-
5634
println!("✓ Switched to toolchain: {}", self.version);
5735

5836
Ok(())

0 commit comments

Comments
 (0)