Phase 6: IDE-Exportanbindung abschließen und Change archivieren
This commit is contained in:
@@ -345,6 +345,46 @@ pub fn publish(
|
||||
cancelled: &dyn Fn() -> bool,
|
||||
prepare: impl FnOnce(&Path) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
prepare_publication(path, overwrite, protected, cancelled, prepare)?.publish(cancelled)
|
||||
}
|
||||
|
||||
/// Fertiges Staging-Ergebnis. Drop verwirft es; nur der Auftragseigner veröffentlicht.
|
||||
pub struct PreparedPublication {
|
||||
path: PathBuf,
|
||||
protected: Vec<PathBuf>,
|
||||
initial: Option<Vec<u8>>,
|
||||
temporary: Temporary,
|
||||
}
|
||||
impl PreparedPublication {
|
||||
pub fn publish(self, cancelled: &dyn Fn() -> bool) -> Result<()> {
|
||||
let Self {
|
||||
path,
|
||||
protected,
|
||||
initial,
|
||||
temporary,
|
||||
} = self;
|
||||
ensure!(!cancelled(), "Export abgebrochen");
|
||||
ensure!(
|
||||
destination(&path, &protected)? == initial,
|
||||
"Ziel wurde während des Exports verändert"
|
||||
);
|
||||
if initial.is_some() {
|
||||
fs::rename(&temporary.0, &path)?;
|
||||
} else {
|
||||
fs::hard_link(&temporary.0, &path)
|
||||
.context("Ziel inzwischen belegt oder Veröffentlichung nicht möglich")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_publication(
|
||||
path: &Path,
|
||||
overwrite: bool,
|
||||
protected: &[PathBuf],
|
||||
cancelled: &dyn Fn() -> bool,
|
||||
prepare: impl FnOnce(&Path) -> Result<()>,
|
||||
) -> Result<PreparedPublication> {
|
||||
ensure!(!cancelled(), "Export abgebrochen");
|
||||
let initial = destination(path, protected)?;
|
||||
ensure!(
|
||||
@@ -371,29 +411,38 @@ pub fn publish(
|
||||
prepare(&temporary.0)?;
|
||||
fs::File::open(&temporary.0)?.sync_all()?;
|
||||
ensure!(!cancelled(), "Export abgebrochen");
|
||||
ensure!(
|
||||
destination(path, protected)? == initial,
|
||||
"Ziel wurde während des Exports verändert"
|
||||
);
|
||||
if initial.is_some() {
|
||||
fs::rename(&temporary.0, path)?;
|
||||
} else {
|
||||
fs::hard_link(&temporary.0, path)
|
||||
.context("Ziel inzwischen belegt oder Veröffentlichung nicht möglich")?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(PreparedPublication {
|
||||
path: path.into(),
|
||||
protected: protected.into(),
|
||||
initial,
|
||||
temporary,
|
||||
})
|
||||
}
|
||||
|
||||
fn codesign(path: &Path, args: &[&str]) -> Result<()> {
|
||||
fn codesign(path: &Path, args: &[&str], cancelled: &dyn Fn() -> bool) -> Result<()> {
|
||||
ensure!(
|
||||
cfg!(target_os = "macos"),
|
||||
"macOS-Finalisierung benötigt macOS mit /usr/bin/codesign"
|
||||
);
|
||||
let result = std::process::Command::new("/usr/bin/codesign")
|
||||
let mut child = std::process::Command::new("/usr/bin/codesign")
|
||||
.args(args)
|
||||
.arg(path)
|
||||
.output()
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.context("Finalisierung: /usr/bin/codesign fehlt oder ist nicht ausführbar")?;
|
||||
loop {
|
||||
if cancelled() {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
bail!("Export abgebrochen");
|
||||
}
|
||||
if child.try_wait()?.is_some() {
|
||||
break;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
}
|
||||
let result = child.wait_with_output()?;
|
||||
ensure!(
|
||||
result.status.success(),
|
||||
"Finalisierung fehlgeschlagen: {}",
|
||||
@@ -464,6 +513,12 @@ pub struct Export<'a> {
|
||||
pub protected: &'a [PathBuf],
|
||||
}
|
||||
pub fn export(request: Export<'_>, cancelled: &dyn Fn() -> bool) -> Result<()> {
|
||||
prepare_export(request, cancelled)?.publish(cancelled)
|
||||
}
|
||||
pub fn prepare_export(
|
||||
request: Export<'_>,
|
||||
cancelled: &dyn Fn() -> bool,
|
||||
) -> Result<PreparedPublication> {
|
||||
let mut b = template(request.template, request.target)?;
|
||||
let mut protected = request.protected.to_vec();
|
||||
protected.extend([
|
||||
@@ -477,7 +532,7 @@ pub fn export(request: Export<'_>, cancelled: &dyn Fn() -> bool) -> Result<()> {
|
||||
.iter()
|
||||
.map(|s| PathBuf::from(&s.path)),
|
||||
);
|
||||
publish(
|
||||
prepare_publication(
|
||||
request.output,
|
||||
request.overwrite,
|
||||
&protected,
|
||||
@@ -485,7 +540,7 @@ pub fn export(request: Export<'_>, cancelled: &dyn Fn() -> bool) -> Result<()> {
|
||||
|temp| {
|
||||
if request.target == Target::MacosArm64 {
|
||||
fs::write(temp, &b)?;
|
||||
codesign(temp, &["--remove-signature"])?;
|
||||
codesign(temp, &["--remove-signature"], cancelled)?;
|
||||
b = fs::read(temp)?;
|
||||
}
|
||||
append_payload(&mut b, request.module, request.target)?;
|
||||
@@ -496,8 +551,12 @@ pub fn export(request: Export<'_>, cancelled: &dyn Fn() -> bool) -> Result<()> {
|
||||
fs::set_permissions(temp, fs::Permissions::from_mode(0o755))?;
|
||||
}
|
||||
if request.target == Target::MacosArm64 {
|
||||
codesign(temp, &["--force", "--sign", "-", "--timestamp=none"])?;
|
||||
codesign(temp, &["--verify", "--strict"])?;
|
||||
codesign(
|
||||
temp,
|
||||
&["--force", "--sign", "-", "--timestamp=none"],
|
||||
cancelled,
|
||||
)?;
|
||||
codesign(temp, &["--verify", "--strict"], cancelled)?;
|
||||
}
|
||||
embedded(&fs::read(temp)?, request.target)?;
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user