From 0df85b2b046b891d361181a21aedbd8c17ce00dc Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 7 Mar 2025 05:12:51 +0000 Subject: [PATCH 1/7] Adding ability to generate nuget packages This will help solve https://github.com/asg017/sqlite-vec/issues/193 --- Cargo.lock | 19 +++++++ Cargo.toml | 7 +-- src/main.rs | 11 ++++ src/nuget.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/spec.rs | 4 ++ 5 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 src/nuget.rs diff --git a/Cargo.lock b/Cargo.lock index c024374..c821fe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -765,6 +765,18 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-xml-rs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65162e9059be2f6a3421ebbb4fef3e74b7d9e7c60c50a0e292c6239f19f1edfa" +dependencies = [ + "log", + "serde", + "thiserror", + "xml-rs", +] + [[package]] name = "serde_derive" version = "1.0.197" @@ -843,6 +855,7 @@ dependencies = [ "insta-cmd", "semver", "serde", + "serde-xml-rs", "serde_json", "sha2", "tar", @@ -1244,6 +1257,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "xml-rs" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 3e6c9dc..4fb9d2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,13 +6,13 @@ repository = "https://github.com/asg017/sqlite-dist" [dependencies] -base16ct = {version="0.2.0", features=["alloc"]} +base16ct = { version = "0.2.0", features = ["alloc"] } base64 = "0.21.7" chrono = "0.4.34" clap = "4.5.1" flate2 = "1.0.28" -semver = {version="1.0.22", features = ["serde"]} -serde = {version="1.0", features = ["derive"]} +semver = { version = "1.0.22", features = ["serde"] } +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sha2 = "0.10.8" tar = "0.4.40" @@ -20,6 +20,7 @@ thiserror = "1.0.57" toml = "0.8.10" ureq = "2.9.6" zip = "0.6.6" +serde-xml-rs = "0.5.1" [profile.dist] inherits = "release" diff --git a/src/main.rs b/src/main.rs index cd7d80d..a9918e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod gh_releases; mod installer_sh; mod manifest; mod npm; +mod nuget; mod pip; mod spec; mod spm; @@ -138,6 +139,7 @@ enum GeneratedAssetKind { Spm, Amalgamation, Manifest, + Nuget, } impl ToString for GeneratedAssetKind { @@ -154,6 +156,7 @@ impl ToString for GeneratedAssetKind { GeneratedAssetKind::Spm => "spm".to_owned(), GeneratedAssetKind::Amalgamation => "amalgamation".to_owned(), GeneratedAssetKind::Manifest => "sqlite-dist-manifest".to_owned(), + GeneratedAssetKind::Nuget => "nuget".to_owned(), } } } @@ -541,6 +544,14 @@ fn build(matches: ArgMatches) -> Result<(), BuildError> { std::fs::create_dir(&gem_path)?; generated_assets.extend(gem::write_gems(&project, &gem_path, gem_config)?); }; + if project.spec.targets.nuget.is_some() { + let nuget_output_directory = output_dir.join("nuget"); + std::fs::create_dir(&nuget_output_directory)?; + generated_assets.extend(nuget::write_nuget_packages( + &project, + &nuget_output_directory, + )?); + } let github_releases_checksums_txt = generated_assets .iter() diff --git a/src/nuget.rs b/src/nuget.rs new file mode 100644 index 0000000..9c63feb --- /dev/null +++ b/src/nuget.rs @@ -0,0 +1,147 @@ +use crate::{Cpu, GeneratedAsset, GeneratedAssetKind, Os, Project}; +use serde::{Deserialize, Serialize}; +use std::{ + io::{self, Cursor, Write}, + path::Path, +}; +use zip::{write::FileOptions, ZipWriter}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Nuspec { + pub metadata: Metadata, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Metadata { + pub id: String, + pub version: String, + pub title: String, + pub authors: String, + pub owners: String, + pub require_license_acceptance: bool, + pub description: String, +} + +impl Nuspec { + fn new(project: &Project) -> Self { + let author = project.spec.package.authors.first().unwrap(); + Self { + metadata: Metadata { + id: project.spec.package.name.clone(), + version: project.version.to_string(), + title: project.spec.package.name.clone(), + authors: author.clone(), + owners: author.clone(), + require_license_acceptance: false, + description: project.spec.package.description.clone(), + }, + } + } + + fn to_xml(&self) -> String { + format!( + r#" + + + {} + {} + {} + {} + {} + {} + {} + +"#, + self.metadata.id, + self.metadata.version, + self.metadata.title, + self.metadata.authors, + self.metadata.owners, + self.metadata.require_license_acceptance, + self.metadata.description + ) + } +} + +pub struct NugetPackage { + zip: ZipWriter>>, +} + +impl NugetPackage { + pub fn new() -> io::Result { + let buffer = Vec::new(); + let cursor = Cursor::new(buffer); + let mut zip = ZipWriter::new(cursor); + zip.start_file("[Content_Types].xml", FileOptions::default())?; + zip.write_all(Self::content_types().as_bytes())?; + Ok(Self { zip }) + } + + fn content_types() -> String { + r#" + + + + + +"#.to_string() + } + + pub fn add_nuspec(&mut self, nuspec: &Nuspec) -> io::Result<()> { + let nuspec_file_name = format!("{}.nuspec", nuspec.metadata.id); + let nuspec_content = nuspec.to_xml(); + self.zip + .start_file(&nuspec_file_name, FileOptions::default())?; + self.zip.write_all(nuspec_content.as_bytes())?; + Ok(()) + } + + pub fn add_files(&mut self, project: &Project) -> io::Result<()> { + for platform_dir in &project.platform_directories { + if !(matches!(platform_dir.os, Os::Linux | Os::Macos | Os::Windows) + && matches!(platform_dir.cpu, Cpu::X86_64 | Cpu::Aarch64)) + { + continue; + } + for loadable_file in &platform_dir.loadable_files { + let file_path = format!( + "runtimes/{}-{}/{}", + platform_dir.os.to_string().to_lowercase(), + platform_dir.cpu.to_string().to_lowercase(), + loadable_file.file.name + ); + self.zip.start_file(&file_path, FileOptions::default())?; + self.zip.write_all(&loadable_file.file.data)?; + } + } + Ok(()) + } + + pub fn finish(mut self) -> io::Result> { + let result = self.zip.finish()?; + Ok(result.into_inner()) + } +} + +pub(crate) fn write_nuget_packages( + project: &Project, + nuget_output_directory: &Path, +) -> io::Result> { + let mut assets = vec![]; + let nuspec = Nuspec::new(project); + let mut package = NugetPackage::new()?; + package.add_nuspec(&nuspec)?; + package.add_files(project)?; + let buffer = package.finish()?; + let output_path = nuget_output_directory.join(format!( + "{}.{}.nupkg", + nuspec.metadata.id, nuspec.metadata.version + )); + std::fs::write(&output_path, &buffer)?; + assets.push(GeneratedAsset::from( + GeneratedAssetKind::Nuget, + &output_path, + &buffer, + )?); + Ok(assets) +} diff --git a/src/spec.rs b/src/spec.rs index ffa39e6..02be2ac 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -51,6 +51,9 @@ pub struct TargetAmalgamation { pub include: Vec, } +#[derive(Deserialize)] +pub struct TargetNuget {} + #[derive(Deserialize)] pub struct Targets { pub github_releases: Option, @@ -62,6 +65,7 @@ pub struct Targets { pub npm: Option, pub gem: Option, pub amalgamation: Option, + pub nuget: Option, } #[derive(Deserialize)] pub struct Spec { From 58300b594ff8384b9382e7e6d6aaa22d2b00c6f3 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 7 Mar 2025 05:57:09 +0000 Subject: [PATCH 2/7] Fixing how the runtime identifiers are mapped in the nuget package The folders output in builds might not match the way we store RIDs in .NET, so we'll map them across --- src/nuget.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/nuget.rs b/src/nuget.rs index 9c63feb..fa32ea3 100644 --- a/src/nuget.rs +++ b/src/nuget.rs @@ -104,12 +104,21 @@ impl NugetPackage { continue; } for loadable_file in &platform_dir.loadable_files { - let file_path = format!( - "runtimes/{}-{}/{}", - platform_dir.os.to_string().to_lowercase(), - platform_dir.cpu.to_string().to_lowercase(), - loadable_file.file.name - ); + let os = match platform_dir.os { + Os::Windows => "win", + Os::Linux => "linux", + Os::Macos => "osx", + Os::Android => "android", + Os::Ios => "ios", + Os::IosSimulator => "ios-simulator", + }; + let cpu = match platform_dir.cpu { + Cpu::Aarch64 => "arm64", + Cpu::X86_64 => "x64", + Cpu::I686 => "x86", + Cpu::Armv7a => "armv7", + }; + let file_path = format!("runtimes/{}-{}/{}", os, cpu, loadable_file.file.name); self.zip.start_file(&file_path, FileOptions::default())?; self.zip.write_all(&loadable_file.file.data)?; } From 231e7997b213de0c5bf64097d58a795483561f4c Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 7 Mar 2025 20:47:55 +1100 Subject: [PATCH 3/7] Update src/nuget.rs Co-authored-by: Krzysztof Wicher --- src/nuget.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nuget.rs b/src/nuget.rs index fa32ea3..3b8127a 100644 --- a/src/nuget.rs +++ b/src/nuget.rs @@ -118,7 +118,7 @@ impl NugetPackage { Cpu::I686 => "x86", Cpu::Armv7a => "armv7", }; - let file_path = format!("runtimes/{}-{}/{}", os, cpu, loadable_file.file.name); + let file_path = format!("runtimes/{}-{}/native/{}", os, cpu, loadable_file.file.name); self.zip.start_file(&file_path, FileOptions::default())?; self.zip.write_all(&loadable_file.file.data)?; } From 0432fb0544896d0fe7a9b405a62dbc819bf43c9b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 12 Mar 2025 23:31:12 +0000 Subject: [PATCH 4/7] Adding the props and targets files for the nuget package This will enable support for netfx --- src/nuget.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/nuget.rs b/src/nuget.rs index 3b8127a..63bd851 100644 --- a/src/nuget.rs +++ b/src/nuget.rs @@ -68,12 +68,21 @@ pub struct NugetPackage { } impl NugetPackage { - pub fn new() -> io::Result { + pub fn new(package_id: &str) -> io::Result { let buffer = Vec::new(); let cursor = Cursor::new(buffer); let mut zip = ZipWriter::new(cursor); zip.start_file("[Content_Types].xml", FileOptions::default())?; zip.write_all(Self::content_types().as_bytes())?; + // add props_file to the folder buildTransitive\net46 + let props_file_name = format!("buildTransitive/net46/{}.props", package_id); + zip.start_file(&props_file_name, FileOptions::default())?; + zip.write_all(Self::props_file().as_bytes())?; + + // add targets_file to the folder buildTransitive\net46 + let targets_file_name = format!("buildTransitive/net46/{}.targets", package_id); + zip.start_file(&targets_file_name, FileOptions::default())?; + zip.write_all(Self::targets_file(package_id).as_bytes())?; Ok(Self { zip }) } @@ -87,6 +96,70 @@ impl NugetPackage { "#.to_string() } + fn props_file() -> String { + r#" + + + + + PreserveNewest + false + %(Filename)%(Extension) + + + + PreserveNewest + false + %(Filename)%(Extension) + + + + PreserveNewest + false + %(Filename)%(Extension) + + + +"# + .to_string() + } + + fn targets_file(package_id: &str) -> String { + format!( + r#" + + + true + + + + + + + + +"#, + package_id + ) + } + pub fn add_nuspec(&mut self, nuspec: &Nuspec) -> io::Result<()> { let nuspec_file_name = format!("{}.nuspec", nuspec.metadata.id); let nuspec_content = nuspec.to_xml(); @@ -118,7 +191,8 @@ impl NugetPackage { Cpu::I686 => "x86", Cpu::Armv7a => "armv7", }; - let file_path = format!("runtimes/{}-{}/native/{}", os, cpu, loadable_file.file.name); + let file_path = + format!("runtimes/{}-{}/native/{}", os, cpu, loadable_file.file.name); self.zip.start_file(&file_path, FileOptions::default())?; self.zip.write_all(&loadable_file.file.data)?; } @@ -138,7 +212,7 @@ pub(crate) fn write_nuget_packages( ) -> io::Result> { let mut assets = vec![]; let nuspec = Nuspec::new(project); - let mut package = NugetPackage::new()?; + let mut package = NugetPackage::new(&nuspec.metadata.id)?; package.add_nuspec(&nuspec)?; package.add_files(project)?; let buffer = package.finish()?; From 7197da7612548f059168d8b7bb33feb18ab739f1 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Sun, 16 Mar 2025 10:13:25 +1100 Subject: [PATCH 5/7] Apply suggestions from code review Co-authored-by: Krzysztof Wicher --- src/nuget.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nuget.rs b/src/nuget.rs index 63bd851..d70fce5 100644 --- a/src/nuget.rs +++ b/src/nuget.rs @@ -75,12 +75,12 @@ impl NugetPackage { zip.start_file("[Content_Types].xml", FileOptions::default())?; zip.write_all(Self::content_types().as_bytes())?; // add props_file to the folder buildTransitive\net46 - let props_file_name = format!("buildTransitive/net46/{}.props", package_id); + let props_file_name = format!("build/netstandard2.0/{}.props", package_id); zip.start_file(&props_file_name, FileOptions::default())?; zip.write_all(Self::props_file().as_bytes())?; // add targets_file to the folder buildTransitive\net46 - let targets_file_name = format!("buildTransitive/net46/{}.targets", package_id); + let targets_file_name = format!("build/netstandard2.0/{}.targets", package_id); zip.start_file(&targets_file_name, FileOptions::default())?; zip.write_all(Self::targets_file(package_id).as_bytes())?; Ok(Self { zip }) @@ -137,11 +137,11 @@ impl NugetPackage { r#" - true + true