From 0f9077b51de26861af755c7067a4c3dba2cc4285 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Sun, 9 Apr 2023 20:37:52 +0800 Subject: [PATCH 1/6] implement patch manually without using external software --- sys/Cargo.toml | 2 ++ sys/build.rs | 68 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/sys/Cargo.toml b/sys/Cargo.toml index a9b229c72..c7a619e0a 100644 --- a/sys/Cargo.toml +++ b/sys/Cargo.toml @@ -12,6 +12,8 @@ repository = "https://github.com/DelSkayn/rquickjs.git" [build-dependencies] cc = "1" +diffy = "0.3.0" +newline-converter = "0.3.0" [build-dependencies.bindgen-rs] package = "bindgen" diff --git a/sys/build.rs b/sys/build.rs index bf66b7900..16b5a849b 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -1,9 +1,7 @@ -use std::{ - env, fs, - io::Write, - path::Path, - process::{Command, Stdio}, -}; +use std::{env, fs, path::Path}; + +use diffy::{apply, Patch}; +use newline_converter::dos2unix; fn main() { #[cfg(feature = "logging")] @@ -129,21 +127,55 @@ fn feature_to_define(name: impl AsRef) -> String { } fn patch, P: AsRef>(out_dir: D, patch: P) { - let mut child = Command::new("patch") - .arg("-p1") - .stdin(Stdio::piped()) - .current_dir(out_dir) - .spawn() - .expect("Unable to execute patch, you may need to install it: {}"); + struct Patches<'a>(&'a str); + + // A backtracking attempt to find a valid diff when there are multiple patches in one file (also known as patchset) + impl<'a> Iterator for Patches<'a> { + type Item = Patch<'a, str>; + fn next(&mut self) -> Option { + let mut range = self.0.len(); + loop { + match diffy::Patch::from_str(&self.0[..range]) { + Ok(x) if x.hunks().is_empty() => break None, + Err(_) if range < 1 => break None, + Ok(x) => { + self.0 = &self.0[range..]; + break Some(x); + } + Err(_) => range -= 1, + } + } + } + } + println!("Appliyng patch {}", patch.as_ref().display()); { - let patch = fs::read(patch).expect("Unable to read patch"); - - let stdin = child.stdin.as_mut().unwrap(); - stdin.write_all(&patch).expect("Unable to apply patch"); + let out_dir = out_dir.as_ref(); + let patch = fs::read_to_string(patch).expect("Unable to read patch"); + let patch = dos2unix(&patch); + for patch in Patches(&patch) { + let original = patch + .original() + .and_then(|x| x.split_once('/').map(|(_, b)| b)) + .expect("Cannot find original file name"); + let modified = patch + .modified() + .and_then(|x| x.split_once('/').map(|(_, b)| b)) + .expect("Cannot find modified file name"); + + // for now + assert_eq!(original, modified); + + let original = + fs::read_to_string(out_dir.join(original)).expect("Unable to read original file"); + let original = dos2unix(&original); + match apply(&original, &patch) { + Ok(patched) => fs::write(out_dir.join(modified), patched) + .expect("Unable to write the patched content"), + Err(e) => eprintln!("Unable to write the patched content: {}", e), + } + } } - - child.wait_with_output().expect("Unable to apply patch"); } #[cfg(not(feature = "bindgen"))] From 5bb47a1177c074e7b99cb5a83b0384029016157c Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Sun, 9 Apr 2023 20:46:03 +0800 Subject: [PATCH 2/6] use the old content for the original and modified file name if no slash can be found --- sys/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/build.rs b/sys/build.rs index 16b5a849b..a7715db19 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -157,10 +157,12 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { let original = patch .original() .and_then(|x| x.split_once('/').map(|(_, b)| b)) + .or(patch.original()) .expect("Cannot find original file name"); let modified = patch .modified() .and_then(|x| x.split_once('/').map(|(_, b)| b)) + .or(patch.modified()) .expect("Cannot find modified file name"); // for now From e23a672221055be0cc754b38b6b8e2a2a81d4f54 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Sun, 9 Apr 2023 20:53:24 +0800 Subject: [PATCH 3/6] remove extra diffy reference --- sys/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/build.rs b/sys/build.rs index a7715db19..888812d5d 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -135,7 +135,7 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { fn next(&mut self) -> Option { let mut range = self.0.len(); loop { - match diffy::Patch::from_str(&self.0[..range]) { + match Patch::from_str(&self.0[..range]) { Ok(x) if x.hunks().is_empty() => break None, Err(_) if range < 1 => break None, Ok(x) => { From d56820c622ae34238eea43cd6f76a6103ac1c703 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Sat, 23 Dec 2023 17:39:33 +0800 Subject: [PATCH 4/6] handle extra /dev/null case --- sys/build.rs | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/sys/build.rs b/sys/build.rs index 43fdcc6ab..43fd39868 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -136,8 +136,15 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { type Item = Patch<'a, str>; fn next(&mut self) -> Option { let mut range = self.0.len(); + loop { - match Patch::from_str(&self.0[..range]) { + let input = if let Some(input) = self.0.get(..range) { + input + } else { + range -= 1; + continue; + }; + match Patch::from_str(input) { Ok(x) if x.hunks().is_empty() => break None, Err(_) if range < 1 => break None, Ok(x) => { @@ -167,15 +174,25 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { .or(patch.modified()) .expect("Cannot find modified file name"); - // for now - assert_eq!(original, modified); + let original_path = out_dir.join(original); + let modified_path = out_dir.join(modified); - let original = - fs::read_to_string(out_dir.join(original)).expect("Unable to read original file"); + let original = if !original_path.exists() && !modified_path.exists() { + String::new() + } else { + fs::read_to_string(original_path).expect("Unable to read original file") + }; let original = dos2unix(&original); match apply(&original, &patch) { - Ok(patched) => fs::write(out_dir.join(modified), patched) - .expect("Unable to write the patched content"), + Ok(patched) => { + if let Some(parent) = modified_path.parent() { + if !parent.exists() { + fs::create_dir_all(parent).unwrap(); + } + } + fs::write(modified_path, patched) + .expect("Unable to write the patched content") + }, Err(e) => eprintln!("Unable to write the patched content: {}", e), } } From 3b88c453aa7f152f297eadf99d38d9c678421f55 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Sat, 23 Dec 2023 17:43:59 +0800 Subject: [PATCH 5/6] add path absolutize to prevent canonicalization error --- sys/Cargo.toml | 1 + sys/build.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/Cargo.toml b/sys/Cargo.toml index a946e3198..123501719 100644 --- a/sys/Cargo.toml +++ b/sys/Cargo.toml @@ -14,6 +14,7 @@ repository = "https://github.com/DelSkayn/rquickjs.git" cc = "1" diffy = "0.3.0" newline-converter = "0.3.0" +path-absolutize = "3.1.1" [build-dependencies.bindgen-rs] package = "bindgen" diff --git a/sys/build.rs b/sys/build.rs index 43fd39868..ca1f3fdb7 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -2,6 +2,7 @@ use std::{env, fs, path::Path}; use diffy::{apply, Patch}; use newline_converter::dos2unix; +use path_absolutize::Absolutize; fn main() { #[cfg(feature = "logging")] @@ -174,8 +175,8 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { .or(patch.modified()) .expect("Cannot find modified file name"); - let original_path = out_dir.join(original); - let modified_path = out_dir.join(modified); + let original_path = out_dir.join(original).absolutize().unwrap().to_path_buf(); + let modified_path = out_dir.join(modified).absolutize().unwrap().to_path_buf(); let original = if !original_path.exists() && !modified_path.exists() { String::new() From 3085bf15180ab900ca1d828d387acc6ba99919b5 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Sat, 23 Dec 2023 17:55:18 +0800 Subject: [PATCH 6/6] fixup! add path absolutize to prevent canonicalization error --- sys/build.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/sys/build.rs b/sys/build.rs index ca1f3fdb7..9ef86a761 100644 --- a/sys/build.rs +++ b/sys/build.rs @@ -1,4 +1,7 @@ -use std::{env, fs, path::Path}; +use std::{ + env, fs, + path::{Path, PathBuf}, +}; use diffy::{apply, Patch}; use newline_converter::dos2unix; @@ -166,7 +169,13 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { for patch in Patches(&patch) { let original = patch .original() - .and_then(|x| x.split_once('/').map(|(_, b)| b)) + .and_then(|x| { + if x.chars().next().unwrap_or_default() == '/' { + Some(x) + } else { + x.split_once('/').map(|(_, b)| b) + } + }) .or(patch.original()) .expect("Cannot find original file name"); let modified = patch @@ -175,10 +184,18 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { .or(patch.modified()) .expect("Cannot find modified file name"); - let original_path = out_dir.join(original).absolutize().unwrap().to_path_buf(); + let original_path = if original.chars().next().unwrap_or_default() == '/' { + PathBuf::new() + } else { + out_dir.to_path_buf() + } + .join(original) + .absolutize() + .unwrap() + .to_path_buf(); let modified_path = out_dir.join(modified).absolutize().unwrap().to_path_buf(); - let original = if !original_path.exists() && !modified_path.exists() { + let original = if !original_path.exists() { String::new() } else { fs::read_to_string(original_path).expect("Unable to read original file") @@ -191,9 +208,8 @@ fn patch, P: AsRef>(out_dir: D, patch: P) { fs::create_dir_all(parent).unwrap(); } } - fs::write(modified_path, patched) - .expect("Unable to write the patched content") - }, + fs::write(modified_path, patched).expect("Unable to write the patched content") + } Err(e) => eprintln!("Unable to write the patched content: {}", e), } }