feat: add built_against field for ABI-sensitive dependencies
- Introduced a new field `built_against` in the InstalledPackageRecord struct to track concrete package names for ABI-sensitive dependencies. - Updated database schema to include `built_against` column in the packages table. - Modified package registration and listing functions to handle the new `built_against` field. - Implemented helper functions to format and parse the `built_against` data. - Enhanced tests to verify the correct handling of the `built_against` metadata during package registration and retrieval. - Updated resolver logic to utilize `built_against` for dependency resolution.
This commit is contained in:
@@ -1245,6 +1245,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1278,6 +1279,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1652,6 +1654,7 @@ foo: bar
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1686,6 +1689,7 @@ foo: bar
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1722,6 +1726,7 @@ foo: bar
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -1204,6 +1204,7 @@ mod tests {
|
|||||||
description: "".into(),
|
description: "".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -412,6 +412,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -555,6 +556,7 @@ depot_install_dev_pkg() {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -660,6 +662,7 @@ depot_install() {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -1050,6 +1050,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -1149,6 +1149,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -517,6 +517,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -791,6 +791,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ mod tests {
|
|||||||
description: String::new(),
|
description: String::new(),
|
||||||
homepage: String::new(),
|
homepage: String::new(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -603,6 +603,19 @@ fn parse_dependency_list(metadata: &toml::Value, kind: &str) -> Vec<String> {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_metadata_string_list(metadata: &toml::Value, key: &str) -> Vec<String> {
|
||||||
|
metadata
|
||||||
|
.get(key)
|
||||||
|
.and_then(|v| v.as_array())
|
||||||
|
.map(|arr| {
|
||||||
|
arr.iter()
|
||||||
|
.filter_map(|v| v.as_str())
|
||||||
|
.map(String::from)
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_keep_list(metadata: &toml::Value) -> Vec<String> {
|
fn parse_keep_list(metadata: &toml::Value) -> Vec<String> {
|
||||||
if let Some(s) = metadata.get("keep").and_then(|v| v.as_str()) {
|
if let Some(s) = metadata.get("keep").and_then(|v| v.as_str()) {
|
||||||
return vec![s.to_string()];
|
return vec![s.to_string()];
|
||||||
|
|||||||
@@ -386,6 +386,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "https://example.test".into(),
|
homepage: "https://example.test".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ fn package_spec_from_archive_metadata(metadata: &toml::Value) -> package::Packag
|
|||||||
.get("abi_breaking")
|
.get("abi_breaking")
|
||||||
.and_then(|v| v.as_bool())
|
.and_then(|v| v.as_bool())
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
|
built_against: super::super::parse_metadata_string_list(metadata, "built_against"),
|
||||||
license: super::super::parse_licenses_from_toml(metadata),
|
license: super::super::parse_licenses_from_toml(metadata),
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -118,6 +119,7 @@ pub(crate) fn package_spec_from_repo_record(
|
|||||||
description: record.description.clone().unwrap_or_default(),
|
description: record.description.clone().unwrap_or_default(),
|
||||||
homepage: record.homepage.clone().unwrap_or_default(),
|
homepage: record.homepage.clone().unwrap_or_default(),
|
||||||
abi_breaking: record.abi_breaking,
|
abi_breaking: record.abi_breaking,
|
||||||
|
built_against: record.built_against.clone(),
|
||||||
license: parse_license_list_from_repo(&record.license),
|
license: parse_license_list_from_repo(&record.license),
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ fn test_binary_repo_record(name: &str, filename: &str) -> db::repo::BinaryRepoPa
|
|||||||
version: "1.0".into(),
|
version: "1.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
filename: filename.into(),
|
filename: filename.into(),
|
||||||
size: 1,
|
size: 1,
|
||||||
@@ -173,6 +174,7 @@ fn test_package_spec(
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -436,6 +438,7 @@ fn binary_install_path_uses_repo_record_metadata_without_archive_metadata() -> R
|
|||||||
version: "1.0".into(),
|
version: "1.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
filename: archive_path
|
filename: archive_path
|
||||||
.file_name()
|
.file_name()
|
||||||
@@ -734,6 +737,7 @@ fn binary_archive_install_preserves_setuid_permissions() -> Result<()> {
|
|||||||
version: "1.0".into(),
|
version: "1.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
filename: archive_path
|
filename: archive_path
|
||||||
.file_name()
|
.file_name()
|
||||||
@@ -851,6 +855,7 @@ fn binary_archive_install_honors_replaces_from_metadata() -> Result<()> {
|
|||||||
description: "diffutils".into(),
|
description: "diffutils".into(),
|
||||||
homepage: "https://example.test/diffutils".into(),
|
homepage: "https://example.test/diffutils".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["GPL-3.0-or-later".into()],
|
license: vec!["GPL-3.0-or-later".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -955,6 +960,7 @@ fn plan_staged_install_reads_updates_from_rootfs_installed_db() -> Result<()> {
|
|||||||
description: "Base filesystem".into(),
|
description: "Base filesystem".into(),
|
||||||
homepage: "https://example.test".into(),
|
homepage: "https://example.test".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["Unlicense".into()],
|
license: vec!["Unlicense".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -997,6 +1003,7 @@ fn renamed_abi_updates_keep_versioned_shared_libraries() -> Result<()> {
|
|||||||
description: "libxml2 2.14".into(),
|
description: "libxml2 2.14".into(),
|
||||||
homepage: "https://example.test/libxml2".into(),
|
homepage: "https://example.test/libxml2".into(),
|
||||||
abi_breaking: true,
|
abi_breaking: true,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1032,6 +1039,7 @@ fn renamed_abi_updates_keep_versioned_shared_libraries() -> Result<()> {
|
|||||||
description: "libxml2 2.15".into(),
|
description: "libxml2 2.15".into(),
|
||||||
homepage: "https://example.test/libxml2".into(),
|
homepage: "https://example.test/libxml2".into(),
|
||||||
abi_breaking: true,
|
abi_breaking: true,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1142,6 +1150,7 @@ fn collect_update_candidates_matches_renamed_packages_by_real_name() -> Result<(
|
|||||||
description: "icu78".into(),
|
description: "icu78".into(),
|
||||||
homepage: "https://example.test/icu".into(),
|
homepage: "https://example.test/icu".into(),
|
||||||
abi_breaking: true,
|
abi_breaking: true,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1219,6 +1228,7 @@ fn update_candidate_prefers_binary_when_versions_match_and_config_does() {
|
|||||||
version: "1.0.0".into(),
|
version: "1.0.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
};
|
};
|
||||||
let source_spec = package::PackageSpec {
|
let source_spec = package::PackageSpec {
|
||||||
@@ -1230,6 +1240,7 @@ fn update_candidate_prefers_binary_when_versions_match_and_config_does() {
|
|||||||
description: "test".into(),
|
description: "test".into(),
|
||||||
homepage: "https://example.test".into(),
|
homepage: "https://example.test".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1273,6 +1284,7 @@ fn update_candidate_prefers_binary_when_versions_match_and_config_does() {
|
|||||||
version: "1.1.0".into(),
|
version: "1.1.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
filename: "pkg-1.1.0-1-x86_64.depot.pkg.tar.zst".into(),
|
filename: "pkg-1.1.0-1-x86_64.depot.pkg.tar.zst".into(),
|
||||||
size: 1,
|
size: 1,
|
||||||
@@ -1312,6 +1324,7 @@ fn select_update_candidate_uses_newer_timestamp_when_versions_match() {
|
|||||||
version: "1.0.0".into(),
|
version: "1.0.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: Some(100),
|
completed_at: Some(100),
|
||||||
};
|
};
|
||||||
let source_spec = package::PackageSpec {
|
let source_spec = package::PackageSpec {
|
||||||
@@ -1323,6 +1336,7 @@ fn select_update_candidate_uses_newer_timestamp_when_versions_match() {
|
|||||||
description: "test".into(),
|
description: "test".into(),
|
||||||
homepage: "https://example.test".into(),
|
homepage: "https://example.test".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1371,6 +1385,7 @@ fn select_update_candidate_prefers_replacement_candidate() {
|
|||||||
version: "4.9.0".into(),
|
version: "4.9.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: Some(100),
|
completed_at: Some(100),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1383,6 +1398,7 @@ fn select_update_candidate_prefers_replacement_candidate() {
|
|||||||
description: "findutils".into(),
|
description: "findutils".into(),
|
||||||
homepage: "https://example.test/findutils".into(),
|
homepage: "https://example.test/findutils".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1407,6 +1423,7 @@ fn select_update_candidate_prefers_replacement_candidate() {
|
|||||||
description: "busybox".into(),
|
description: "busybox".into(),
|
||||||
homepage: "https://example.test/busybox".into(),
|
homepage: "https://example.test/busybox".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["GPL-2.0-only".into()],
|
license: vec!["GPL-2.0-only".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1481,6 +1498,7 @@ fn install_planned_packages_to_rootfs_runs_post_hooks_after_batch_install() -> R
|
|||||||
description: "findutils".into(),
|
description: "findutils".into(),
|
||||||
homepage: "https://example.test/findutils".into(),
|
homepage: "https://example.test/findutils".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1510,6 +1528,7 @@ fn install_planned_packages_to_rootfs_runs_post_hooks_after_batch_install() -> R
|
|||||||
description: "alpha".into(),
|
description: "alpha".into(),
|
||||||
homepage: "https://example.test/alpha".into(),
|
homepage: "https://example.test/alpha".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1543,6 +1562,7 @@ fn install_planned_packages_to_rootfs_runs_post_hooks_after_batch_install() -> R
|
|||||||
description: "busybox".into(),
|
description: "busybox".into(),
|
||||||
homepage: "https://example.test/busybox".into(),
|
homepage: "https://example.test/busybox".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["GPL-2.0-only".into()],
|
license: vec!["GPL-2.0-only".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1635,6 +1655,7 @@ fn collect_update_candidates_skips_source_when_prefer_binary_is_enabled() -> Res
|
|||||||
description: "pkg".into(),
|
description: "pkg".into(),
|
||||||
homepage: "https://example.test".into(),
|
homepage: "https://example.test".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1806,6 +1827,7 @@ fn collect_missing_update_dependencies_skips_planned_provides_and_installed_deps
|
|||||||
description: "glibc".into(),
|
description: "glibc".into(),
|
||||||
homepage: "https://example.test".into(),
|
homepage: "https://example.test".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
+63
-4
@@ -41,6 +41,8 @@ pub struct InstalledPackageRecord {
|
|||||||
pub revision: u32,
|
pub revision: u32,
|
||||||
/// Whether renamed updates should retain versioned shared libraries.
|
/// Whether renamed updates should retain versioned shared libraries.
|
||||||
pub abi_breaking: bool,
|
pub abi_breaking: bool,
|
||||||
|
/// Concrete package names this package was built against for ABI-sensitive dependencies.
|
||||||
|
pub built_against: Vec<String>,
|
||||||
/// Package completion timestamp if known.
|
/// Package completion timestamp if known.
|
||||||
pub completed_at: Option<i64>,
|
pub completed_at: Option<i64>,
|
||||||
}
|
}
|
||||||
@@ -140,8 +142,8 @@ pub fn register_package_with_replacement(
|
|||||||
|
|
||||||
// Insert/update package without changing its primary key (UPSERT keeps the existing row).
|
// Insert/update package without changing its primary key (UPSERT keeps the existing row).
|
||||||
tx.execute(
|
tx.execute(
|
||||||
"INSERT INTO packages (name, real_name, version, revision, description, homepage, license, abi_breaking, completed_at)
|
"INSERT INTO packages (name, real_name, version, revision, description, homepage, license, abi_breaking, built_against, completed_at)
|
||||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)
|
||||||
ON CONFLICT(name) DO UPDATE SET
|
ON CONFLICT(name) DO UPDATE SET
|
||||||
real_name=excluded.real_name,
|
real_name=excluded.real_name,
|
||||||
version=excluded.version,
|
version=excluded.version,
|
||||||
@@ -150,6 +152,7 @@ pub fn register_package_with_replacement(
|
|||||||
homepage=excluded.homepage,
|
homepage=excluded.homepage,
|
||||||
license=excluded.license,
|
license=excluded.license,
|
||||||
abi_breaking=excluded.abi_breaking,
|
abi_breaking=excluded.abi_breaking,
|
||||||
|
built_against=excluded.built_against,
|
||||||
completed_at=excluded.completed_at",
|
completed_at=excluded.completed_at",
|
||||||
params![
|
params![
|
||||||
spec.package.name,
|
spec.package.name,
|
||||||
@@ -160,6 +163,7 @@ pub fn register_package_with_replacement(
|
|||||||
spec.package.homepage,
|
spec.package.homepage,
|
||||||
format_licenses(&spec.package.license),
|
format_licenses(&spec.package.license),
|
||||||
spec.package.abi_breaking,
|
spec.package.abi_breaking,
|
||||||
|
format_built_against(&spec.package.built_against),
|
||||||
completed_at,
|
completed_at,
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
@@ -575,6 +579,7 @@ fn init_db(conn: &Connection) -> Result<()> {
|
|||||||
homepage TEXT,
|
homepage TEXT,
|
||||||
license TEXT,
|
license TEXT,
|
||||||
abi_breaking INTEGER NOT NULL DEFAULT 0,
|
abi_breaking INTEGER NOT NULL DEFAULT 0,
|
||||||
|
built_against TEXT NOT NULL DEFAULT '',
|
||||||
completed_at INTEGER
|
completed_at INTEGER
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -632,6 +637,7 @@ fn init_db(conn: &Connection) -> Result<()> {
|
|||||||
ensure_packages_completed_at_column(conn)?;
|
ensure_packages_completed_at_column(conn)?;
|
||||||
ensure_packages_real_name_column(conn)?;
|
ensure_packages_real_name_column(conn)?;
|
||||||
ensure_packages_abi_breaking_column(conn)?;
|
ensure_packages_abi_breaking_column(conn)?;
|
||||||
|
ensure_packages_built_against_column(conn)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,6 +698,39 @@ fn ensure_packages_abi_breaking_column(conn: &Connection) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ensure_packages_built_against_column(conn: &Connection) -> Result<()> {
|
||||||
|
let has_built_against: bool = conn
|
||||||
|
.query_row(
|
||||||
|
"SELECT COUNT(*) FROM pragma_table_info('packages') WHERE name = 'built_against'",
|
||||||
|
[],
|
||||||
|
|row| {
|
||||||
|
let count: i64 = row.get(0)?;
|
||||||
|
Ok(count > 0)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.context("Failed to inspect installed package DB schema")?;
|
||||||
|
if !has_built_against {
|
||||||
|
conn.execute(
|
||||||
|
"ALTER TABLE packages ADD COLUMN built_against TEXT NOT NULL DEFAULT ''",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.context("Failed to add built_against column to installed package DB")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_built_against(packages: &[String]) -> String {
|
||||||
|
packages.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_built_against(raw: &str) -> Vec<String> {
|
||||||
|
raw.lines()
|
||||||
|
.map(str::trim)
|
||||||
|
.filter(|name| !name.is_empty())
|
||||||
|
.map(String::from)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn delete_package_rows(conn: &Connection, pkg_id: i64) -> Result<()> {
|
fn delete_package_rows(conn: &Connection, pkg_id: i64) -> Result<()> {
|
||||||
conn.execute("DELETE FROM files WHERE package_id = ?1", params![pkg_id])?;
|
conn.execute("DELETE FROM files WHERE package_id = ?1", params![pkg_id])?;
|
||||||
conn.execute(
|
conn.execute(
|
||||||
@@ -877,18 +916,20 @@ pub fn list_installed_package_records(db_path: &Path) -> Result<Vec<InstalledPac
|
|||||||
let conn = Connection::open(db_path)?;
|
let conn = Connection::open(db_path)?;
|
||||||
init_db(&conn)?;
|
init_db(&conn)?;
|
||||||
let mut stmt = conn.prepare(
|
let mut stmt = conn.prepare(
|
||||||
"SELECT name, real_name, version, revision, abi_breaking, completed_at
|
"SELECT name, real_name, version, revision, abi_breaking, built_against, completed_at
|
||||||
FROM packages
|
FROM packages
|
||||||
ORDER BY name",
|
ORDER BY name",
|
||||||
)?;
|
)?;
|
||||||
let rows = stmt.query_map([], |row| {
|
let rows = stmt.query_map([], |row| {
|
||||||
|
let built_against: String = row.get(5)?;
|
||||||
Ok(InstalledPackageRecord {
|
Ok(InstalledPackageRecord {
|
||||||
name: row.get(0)?,
|
name: row.get(0)?,
|
||||||
real_name: row.get(1)?,
|
real_name: row.get(1)?,
|
||||||
version: row.get(2)?,
|
version: row.get(2)?,
|
||||||
revision: row.get::<_, i64>(3)? as u32,
|
revision: row.get::<_, i64>(3)? as u32,
|
||||||
abi_breaking: row.get(4)?,
|
abi_breaking: row.get(4)?,
|
||||||
completed_at: row.get(5)?,
|
built_against: parse_built_against(&built_against),
|
||||||
|
completed_at: row.get(6)?,
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
Ok(rows.filter_map(|row| row.ok()).collect())
|
Ok(rows.filter_map(|row| row.ok()).collect())
|
||||||
@@ -1133,6 +1174,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1565,6 +1607,23 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn register_package_records_built_against_metadata() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let db_path = tmp.path().join("packages.db");
|
||||||
|
let dest = tmp.path().join("dest");
|
||||||
|
std::fs::create_dir_all(&dest).unwrap();
|
||||||
|
std::fs::write(dest.join("payload"), "x").unwrap();
|
||||||
|
|
||||||
|
let mut spec = mk_spec("app", "1.0");
|
||||||
|
spec.package.built_against = vec!["icu78".into()];
|
||||||
|
register_package(&db_path, &spec, &dest).unwrap();
|
||||||
|
|
||||||
|
let records = list_installed_package_records(&db_path).unwrap();
|
||||||
|
assert_eq!(records.len(), 1);
|
||||||
|
assert_eq!(records[0].built_against, vec!["icu78".to_string()]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn installed_group_helpers_round_trip_membership() {
|
fn installed_group_helpers_round_trip_membership() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
|||||||
+170
-28
@@ -32,6 +32,31 @@ fn parse_license_text(metadata: &toml::Value) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_string_array_metadata(metadata: &toml::Value, key: &str) -> Vec<String> {
|
||||||
|
metadata
|
||||||
|
.get(key)
|
||||||
|
.and_then(|v| v.as_array())
|
||||||
|
.map(|arr| {
|
||||||
|
arr.iter()
|
||||||
|
.filter_map(|v| v.as_str())
|
||||||
|
.map(String::from)
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_built_against(packages: &[String]) -> String {
|
||||||
|
packages.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_built_against(raw: &str) -> Vec<String> {
|
||||||
|
raw.lines()
|
||||||
|
.map(str::trim)
|
||||||
|
.filter(|name| !name.is_empty())
|
||||||
|
.map(String::from)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RepoManager {
|
pub struct RepoManager {
|
||||||
pub repo_dir: PathBuf,
|
pub repo_dir: PathBuf,
|
||||||
}
|
}
|
||||||
@@ -76,6 +101,7 @@ struct IndexedPackage {
|
|||||||
version: String,
|
version: String,
|
||||||
revision: u32,
|
revision: u32,
|
||||||
abi_breaking: bool,
|
abi_breaking: bool,
|
||||||
|
built_against: Vec<String>,
|
||||||
completed_at: Option<i64>,
|
completed_at: Option<i64>,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
homepage: Option<String>,
|
homepage: Option<String>,
|
||||||
@@ -116,6 +142,7 @@ pub struct BinaryRepoPackageRecord {
|
|||||||
pub version: String,
|
pub version: String,
|
||||||
pub revision: u32,
|
pub revision: u32,
|
||||||
pub abi_breaking: bool,
|
pub abi_breaking: bool,
|
||||||
|
pub built_against: Vec<String>,
|
||||||
pub completed_at: Option<i64>,
|
pub completed_at: Option<i64>,
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
@@ -301,6 +328,7 @@ impl RepoManager {
|
|||||||
version TEXT NOT NULL,
|
version TEXT NOT NULL,
|
||||||
revision INTEGER NOT NULL,
|
revision INTEGER NOT NULL,
|
||||||
abi_breaking INTEGER NOT NULL DEFAULT 0,
|
abi_breaking INTEGER NOT NULL DEFAULT 0,
|
||||||
|
built_against TEXT NOT NULL DEFAULT '',
|
||||||
completed_at INTEGER,
|
completed_at INTEGER,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
homepage TEXT,
|
homepage TEXT,
|
||||||
@@ -378,6 +406,7 @@ impl RepoManager {
|
|||||||
let mut version = String::new();
|
let mut version = String::new();
|
||||||
let mut revision = 1;
|
let mut revision = 1;
|
||||||
let mut abi_breaking = false;
|
let mut abi_breaking = false;
|
||||||
|
let mut built_against = Vec::new();
|
||||||
let mut completed_at = path_modified_unix_timestamp(pkg_path)?;
|
let mut completed_at = path_modified_unix_timestamp(pkg_path)?;
|
||||||
let mut description = None;
|
let mut description = None;
|
||||||
let mut homepage = None;
|
let mut homepage = None;
|
||||||
@@ -427,6 +456,7 @@ impl RepoManager {
|
|||||||
.get("abi_breaking")
|
.get("abi_breaking")
|
||||||
.and_then(|v| v.as_bool())
|
.and_then(|v| v.as_bool())
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
built_against = parse_string_array_metadata(&metadata, "built_against");
|
||||||
completed_at =
|
completed_at =
|
||||||
metadata_time::parse_completed_at_value(&metadata).or(completed_at);
|
metadata_time::parse_completed_at_value(&metadata).or(completed_at);
|
||||||
description = metadata
|
description = metadata
|
||||||
@@ -532,6 +562,7 @@ impl RepoManager {
|
|||||||
version,
|
version,
|
||||||
revision,
|
revision,
|
||||||
abi_breaking,
|
abi_breaking,
|
||||||
|
built_against,
|
||||||
completed_at,
|
completed_at,
|
||||||
description,
|
description,
|
||||||
homepage,
|
homepage,
|
||||||
@@ -557,6 +588,7 @@ impl RepoManager {
|
|||||||
version,
|
version,
|
||||||
revision,
|
revision,
|
||||||
abi_breaking,
|
abi_breaking,
|
||||||
|
built_against,
|
||||||
completed_at,
|
completed_at,
|
||||||
description,
|
description,
|
||||||
homepage,
|
homepage,
|
||||||
@@ -576,14 +608,15 @@ impl RepoManager {
|
|||||||
|
|
||||||
// Insert into database
|
// Insert into database
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO packages (name, real_name, version, revision, abi_breaking, completed_at, description, homepage, license, filename, size, sha256, sha512)
|
"INSERT INTO packages (name, real_name, version, revision, abi_breaking, built_against, completed_at, description, homepage, license, filename, size, sha256, sha512)
|
||||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)",
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)",
|
||||||
params![
|
params![
|
||||||
name,
|
name,
|
||||||
real_name,
|
real_name,
|
||||||
version,
|
version,
|
||||||
revision as i64,
|
revision as i64,
|
||||||
abi_breaking,
|
abi_breaking,
|
||||||
|
format_built_against(&built_against),
|
||||||
completed_at,
|
completed_at,
|
||||||
description,
|
description,
|
||||||
homepage,
|
homepage,
|
||||||
@@ -1675,6 +1708,19 @@ fn query_package_runtime_deps(conn: &Connection, package_id: i64) -> Result<Vec<
|
|||||||
Ok(rows.filter_map(|r| r.ok()).collect())
|
Ok(rows.filter_map(|r| r.ok()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn query_package_built_against(conn: &Connection, package_id: i64) -> Result<Vec<String>> {
|
||||||
|
if !repo_packages_have_built_against(conn)? {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let raw: String = conn.query_row(
|
||||||
|
"SELECT built_against FROM packages WHERE id = ?1",
|
||||||
|
params![package_id],
|
||||||
|
|row| row.get(0),
|
||||||
|
)?;
|
||||||
|
Ok(parse_built_against(&raw))
|
||||||
|
}
|
||||||
|
|
||||||
fn query_package_optional_deps(conn: &Connection, package_id: i64) -> Result<Vec<String>> {
|
fn query_package_optional_deps(conn: &Connection, package_id: i64) -> Result<Vec<String>> {
|
||||||
let has_dependencies_table: bool = conn
|
let has_dependencies_table: bool = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
@@ -1740,6 +1786,11 @@ fn find_cached_binary_repo_packages(
|
|||||||
} else {
|
} else {
|
||||||
"0"
|
"0"
|
||||||
};
|
};
|
||||||
|
let built_against_expr = if repo_packages_have_built_against(&conn)? {
|
||||||
|
"p.built_against"
|
||||||
|
} else {
|
||||||
|
"''"
|
||||||
|
};
|
||||||
let sql = format!(
|
let sql = format!(
|
||||||
"SELECT
|
"SELECT
|
||||||
p.id,
|
p.id,
|
||||||
@@ -1748,6 +1799,7 @@ fn find_cached_binary_repo_packages(
|
|||||||
p.version,
|
p.version,
|
||||||
p.revision,
|
p.revision,
|
||||||
{abi_breaking_expr},
|
{abi_breaking_expr},
|
||||||
|
{built_against_expr},
|
||||||
{completed_at_expr},
|
{completed_at_expr},
|
||||||
p.filename,
|
p.filename,
|
||||||
p.size,
|
p.size,
|
||||||
@@ -1758,6 +1810,7 @@ fn find_cached_binary_repo_packages(
|
|||||||
p.license
|
p.license
|
||||||
FROM packages p
|
FROM packages p
|
||||||
WHERE lower(p.name) = lower(?1)
|
WHERE lower(p.name) = lower(?1)
|
||||||
|
OR lower({real_name_expr}) = lower(?1)
|
||||||
OR EXISTS (
|
OR EXISTS (
|
||||||
SELECT 1 FROM replaces rp
|
SELECT 1 FROM replaces rp
|
||||||
WHERE rp.package_id = p.id
|
WHERE rp.package_id = p.id
|
||||||
@@ -1776,6 +1829,7 @@ fn find_cached_binary_repo_packages(
|
|||||||
AND lower(rp.name) = lower(?1)
|
AND lower(rp.name) = lower(?1)
|
||||||
) THEN 0
|
) THEN 0
|
||||||
WHEN lower(p.name) = lower(?1) THEN 1
|
WHEN lower(p.name) = lower(?1) THEN 1
|
||||||
|
WHEN lower({real_name_expr}) = lower(?1) THEN 2
|
||||||
ELSE 2
|
ELSE 2
|
||||||
END,
|
END,
|
||||||
p.name ASC"
|
p.name ASC"
|
||||||
@@ -1793,14 +1847,15 @@ fn find_cached_binary_repo_packages(
|
|||||||
version: row.get(3)?,
|
version: row.get(3)?,
|
||||||
revision: row.get::<_, i64>(4)? as u32,
|
revision: row.get::<_, i64>(4)? as u32,
|
||||||
abi_breaking: row.get(5)?,
|
abi_breaking: row.get(5)?,
|
||||||
completed_at: row.get(6)?,
|
built_against: parse_built_against(&row.get::<_, String>(6)?),
|
||||||
filename: row.get(7)?,
|
completed_at: row.get(7)?,
|
||||||
size: row.get::<_, i64>(8)? as u64,
|
filename: row.get(8)?,
|
||||||
sha256: row.get(9)?,
|
size: row.get::<_, i64>(9)? as u64,
|
||||||
sha512: row.get(10)?,
|
sha256: row.get(10)?,
|
||||||
description: row.get(11)?,
|
sha512: row.get(11)?,
|
||||||
homepage: row.get(12)?,
|
description: row.get(12)?,
|
||||||
license: row.get(13)?,
|
homepage: row.get(13)?,
|
||||||
|
license: row.get(14)?,
|
||||||
provides: Vec::new(),
|
provides: Vec::new(),
|
||||||
conflicts: Vec::new(),
|
conflicts: Vec::new(),
|
||||||
replaces: Vec::new(),
|
replaces: Vec::new(),
|
||||||
@@ -1818,6 +1873,7 @@ fn find_cached_binary_repo_packages(
|
|||||||
rec.conflicts = query_package_conflicts(&conn, package_id)?;
|
rec.conflicts = query_package_conflicts(&conn, package_id)?;
|
||||||
rec.replaces = query_package_replaces(&conn, package_id)?;
|
rec.replaces = query_package_replaces(&conn, package_id)?;
|
||||||
rec.runtime_dependencies = query_package_runtime_deps(&conn, package_id)?;
|
rec.runtime_dependencies = query_package_runtime_deps(&conn, package_id)?;
|
||||||
|
rec.built_against = query_package_built_against(&conn, package_id)?;
|
||||||
rec.optional_dependencies = query_package_optional_deps(&conn, package_id)?;
|
rec.optional_dependencies = query_package_optional_deps(&conn, package_id)?;
|
||||||
rec.groups = query_package_groups(&conn, package_id)?;
|
rec.groups = query_package_groups(&conn, package_id)?;
|
||||||
out.push(rec);
|
out.push(rec);
|
||||||
@@ -1862,6 +1918,11 @@ fn find_cached_binary_repo_packages_by_group(
|
|||||||
} else {
|
} else {
|
||||||
"0"
|
"0"
|
||||||
};
|
};
|
||||||
|
let built_against_expr = if repo_packages_have_built_against(&conn)? {
|
||||||
|
"p.built_against"
|
||||||
|
} else {
|
||||||
|
"''"
|
||||||
|
};
|
||||||
let sql = format!(
|
let sql = format!(
|
||||||
"SELECT
|
"SELECT
|
||||||
p.id,
|
p.id,
|
||||||
@@ -1870,6 +1931,7 @@ fn find_cached_binary_repo_packages_by_group(
|
|||||||
p.version,
|
p.version,
|
||||||
p.revision,
|
p.revision,
|
||||||
{abi_breaking_expr},
|
{abi_breaking_expr},
|
||||||
|
{built_against_expr},
|
||||||
{completed_at_expr},
|
{completed_at_expr},
|
||||||
p.filename,
|
p.filename,
|
||||||
p.size,
|
p.size,
|
||||||
@@ -1899,14 +1961,15 @@ fn find_cached_binary_repo_packages_by_group(
|
|||||||
version: row.get(3)?,
|
version: row.get(3)?,
|
||||||
revision: row.get::<_, i64>(4)? as u32,
|
revision: row.get::<_, i64>(4)? as u32,
|
||||||
abi_breaking: row.get(5)?,
|
abi_breaking: row.get(5)?,
|
||||||
completed_at: row.get(6)?,
|
built_against: parse_built_against(&row.get::<_, String>(6)?),
|
||||||
filename: row.get(7)?,
|
completed_at: row.get(7)?,
|
||||||
size: row.get::<_, i64>(8)? as u64,
|
filename: row.get(8)?,
|
||||||
sha256: row.get(9)?,
|
size: row.get::<_, i64>(9)? as u64,
|
||||||
sha512: row.get(10)?,
|
sha256: row.get(10)?,
|
||||||
description: row.get(11)?,
|
sha512: row.get(11)?,
|
||||||
homepage: row.get(12)?,
|
description: row.get(12)?,
|
||||||
license: row.get(13)?,
|
homepage: row.get(13)?,
|
||||||
|
license: row.get(14)?,
|
||||||
provides: Vec::new(),
|
provides: Vec::new(),
|
||||||
conflicts: Vec::new(),
|
conflicts: Vec::new(),
|
||||||
replaces: Vec::new(),
|
replaces: Vec::new(),
|
||||||
@@ -1924,6 +1987,7 @@ fn find_cached_binary_repo_packages_by_group(
|
|||||||
rec.conflicts = query_package_conflicts(&conn, package_id)?;
|
rec.conflicts = query_package_conflicts(&conn, package_id)?;
|
||||||
rec.replaces = query_package_replaces(&conn, package_id)?;
|
rec.replaces = query_package_replaces(&conn, package_id)?;
|
||||||
rec.runtime_dependencies = query_package_runtime_deps(&conn, package_id)?;
|
rec.runtime_dependencies = query_package_runtime_deps(&conn, package_id)?;
|
||||||
|
rec.built_against = query_package_built_against(&conn, package_id)?;
|
||||||
rec.optional_dependencies = query_package_optional_deps(&conn, package_id)?;
|
rec.optional_dependencies = query_package_optional_deps(&conn, package_id)?;
|
||||||
rec.groups = query_package_groups(&conn, package_id)?;
|
rec.groups = query_package_groups(&conn, package_id)?;
|
||||||
out.push(rec);
|
out.push(rec);
|
||||||
@@ -1953,6 +2017,11 @@ fn list_cached_binary_repo_packages(
|
|||||||
} else {
|
} else {
|
||||||
"0"
|
"0"
|
||||||
};
|
};
|
||||||
|
let built_against_expr = if repo_packages_have_built_against(&conn)? {
|
||||||
|
"p.built_against"
|
||||||
|
} else {
|
||||||
|
"''"
|
||||||
|
};
|
||||||
let sql = format!(
|
let sql = format!(
|
||||||
"SELECT
|
"SELECT
|
||||||
p.id,
|
p.id,
|
||||||
@@ -1961,6 +2030,7 @@ fn list_cached_binary_repo_packages(
|
|||||||
p.version,
|
p.version,
|
||||||
p.revision,
|
p.revision,
|
||||||
{abi_breaking_expr},
|
{abi_breaking_expr},
|
||||||
|
{built_against_expr},
|
||||||
{completed_at_expr},
|
{completed_at_expr},
|
||||||
p.filename,
|
p.filename,
|
||||||
p.size,
|
p.size,
|
||||||
@@ -1985,14 +2055,15 @@ fn list_cached_binary_repo_packages(
|
|||||||
version: row.get(3)?,
|
version: row.get(3)?,
|
||||||
revision: row.get::<_, i64>(4)? as u32,
|
revision: row.get::<_, i64>(4)? as u32,
|
||||||
abi_breaking: row.get(5)?,
|
abi_breaking: row.get(5)?,
|
||||||
completed_at: row.get(6)?,
|
built_against: parse_built_against(&row.get::<_, String>(6)?),
|
||||||
filename: row.get(7)?,
|
completed_at: row.get(7)?,
|
||||||
size: row.get::<_, i64>(8)? as u64,
|
filename: row.get(8)?,
|
||||||
sha256: row.get(9)?,
|
size: row.get::<_, i64>(9)? as u64,
|
||||||
sha512: row.get(10)?,
|
sha256: row.get(10)?,
|
||||||
description: row.get(11)?,
|
sha512: row.get(11)?,
|
||||||
homepage: row.get(12)?,
|
description: row.get(12)?,
|
||||||
license: row.get(13)?,
|
homepage: row.get(13)?,
|
||||||
|
license: row.get(14)?,
|
||||||
provides: Vec::new(),
|
provides: Vec::new(),
|
||||||
conflicts: Vec::new(),
|
conflicts: Vec::new(),
|
||||||
replaces: Vec::new(),
|
replaces: Vec::new(),
|
||||||
@@ -2010,6 +2081,7 @@ fn list_cached_binary_repo_packages(
|
|||||||
rec.conflicts = query_package_conflicts(&conn, package_id)?;
|
rec.conflicts = query_package_conflicts(&conn, package_id)?;
|
||||||
rec.replaces = query_package_replaces(&conn, package_id)?;
|
rec.replaces = query_package_replaces(&conn, package_id)?;
|
||||||
rec.runtime_dependencies = query_package_runtime_deps(&conn, package_id)?;
|
rec.runtime_dependencies = query_package_runtime_deps(&conn, package_id)?;
|
||||||
|
rec.built_against = query_package_built_against(&conn, package_id)?;
|
||||||
rec.optional_dependencies = query_package_optional_deps(&conn, package_id)?;
|
rec.optional_dependencies = query_package_optional_deps(&conn, package_id)?;
|
||||||
rec.groups = query_package_groups(&conn, package_id)?;
|
rec.groups = query_package_groups(&conn, package_id)?;
|
||||||
out.push(rec);
|
out.push(rec);
|
||||||
@@ -2053,6 +2125,18 @@ fn repo_packages_have_abi_breaking(conn: &Connection) -> Result<bool> {
|
|||||||
.context("Failed to inspect binary repo DB schema")
|
.context("Failed to inspect binary repo DB schema")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn repo_packages_have_built_against(conn: &Connection) -> Result<bool> {
|
||||||
|
conn.query_row(
|
||||||
|
"SELECT COUNT(*) FROM pragma_table_info('packages') WHERE name = 'built_against'",
|
||||||
|
[],
|
||||||
|
|row| {
|
||||||
|
let count: i64 = row.get(0)?;
|
||||||
|
Ok(count > 0)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.context("Failed to inspect binary repo DB schema")
|
||||||
|
}
|
||||||
|
|
||||||
fn path_modified_unix_timestamp(path: &Path) -> Result<Option<i64>> {
|
fn path_modified_unix_timestamp(path: &Path) -> Result<Option<i64>> {
|
||||||
let metadata = fs::metadata(path)
|
let metadata = fs::metadata(path)
|
||||||
.with_context(|| format!("Failed to read metadata for {}", path.display()))?;
|
.with_context(|| format!("Failed to read metadata for {}", path.display()))?;
|
||||||
@@ -2655,6 +2739,7 @@ real_name = "icu"
|
|||||||
version = "1.0"
|
version = "1.0"
|
||||||
revision = 1
|
revision = 1
|
||||||
abi_breaking = true
|
abi_breaking = true
|
||||||
|
built_against = ["icu78"]
|
||||||
description = "test description"
|
description = "test description"
|
||||||
homepage = "https://example.com"
|
homepage = "https://example.com"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -2692,6 +2777,7 @@ optional = []
|
|||||||
String,
|
String,
|
||||||
i64,
|
i64,
|
||||||
i64,
|
i64,
|
||||||
|
String,
|
||||||
Option<String>,
|
Option<String>,
|
||||||
Option<String>,
|
Option<String>,
|
||||||
Option<String>,
|
Option<String>,
|
||||||
@@ -2699,9 +2785,21 @@ optional = []
|
|||||||
String,
|
String,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (name, real_name, version, revision, abi_breaking, desc, home, lic, sha256, sha512): PackageRow = conn
|
let (
|
||||||
|
name,
|
||||||
|
real_name,
|
||||||
|
version,
|
||||||
|
revision,
|
||||||
|
abi_breaking,
|
||||||
|
built_against,
|
||||||
|
desc,
|
||||||
|
home,
|
||||||
|
lic,
|
||||||
|
sha256,
|
||||||
|
sha512,
|
||||||
|
): PackageRow = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT name, real_name, version, revision, abi_breaking, description, homepage, license, sha256, sha512 FROM packages",
|
"SELECT name, real_name, version, revision, abi_breaking, built_against, description, homepage, license, sha256, sha512 FROM packages",
|
||||||
[],
|
[],
|
||||||
|r| {
|
|r| {
|
||||||
Ok((
|
Ok((
|
||||||
@@ -2715,6 +2813,7 @@ optional = []
|
|||||||
r.get(7)?,
|
r.get(7)?,
|
||||||
r.get(8)?,
|
r.get(8)?,
|
||||||
r.get(9)?,
|
r.get(9)?,
|
||||||
|
r.get(10)?,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -2725,6 +2824,7 @@ optional = []
|
|||||||
assert_eq!(version, "1.0");
|
assert_eq!(version, "1.0");
|
||||||
assert_eq!(revision, 1);
|
assert_eq!(revision, 1);
|
||||||
assert_eq!(abi_breaking, 1);
|
assert_eq!(abi_breaking, 1);
|
||||||
|
assert_eq!(built_against, "icu78");
|
||||||
assert_eq!(desc, Some("test description".to_string()));
|
assert_eq!(desc, Some("test description".to_string()));
|
||||||
assert_eq!(home, Some("https://example.com".to_string()));
|
assert_eq!(home, Some("https://example.com".to_string()));
|
||||||
assert_eq!(lic, Some("MIT".to_string()));
|
assert_eq!(lic, Some("MIT".to_string()));
|
||||||
@@ -2965,6 +3065,46 @@ revision = 1
|
|||||||
assert_eq!(rec.filename, "foo-1.0-1.depot.pkg.tar.zst");
|
assert_eq!(rec.filename, "foo-1.0-1.depot.pkg.tar.zst");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_find_cached_binary_repo_packages_matches_real_name_and_built_against() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let db_path = tmp.path().join("repo.db");
|
||||||
|
let mut conn = Connection::open(&db_path).unwrap();
|
||||||
|
let manager = RepoManager::new(tmp.path().to_path_buf());
|
||||||
|
manager.init_repo_schema(&mut conn).unwrap();
|
||||||
|
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO packages (id, name, real_name, version, revision, abi_breaking, built_against, description, homepage, license, filename, size, sha256, sha512)
|
||||||
|
VALUES (1, 'icu78', 'icu', '78.1', 1, 0, '', NULL, NULL, NULL, 'icu78.pkg', 10, 'aa', 'bb')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO packages (id, name, real_name, version, revision, abi_breaking, built_against, description, homepage, license, filename, size, sha256, sha512)
|
||||||
|
VALUES (2, 'app', NULL, '1.0', 1, 0, 'icu78', NULL, NULL, NULL, 'app.pkg', 10, 'cc', 'dd')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO dependencies (package_id, kind, name) VALUES (2, 'runtime', 'icu')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
drop(conn);
|
||||||
|
|
||||||
|
let icu_matches = find_cached_binary_repo_packages("repo", &db_path, "icu").unwrap();
|
||||||
|
assert_eq!(icu_matches.len(), 1);
|
||||||
|
assert_eq!(icu_matches[0].name, "icu78");
|
||||||
|
assert_eq!(icu_matches[0].real_name.as_deref(), Some("icu"));
|
||||||
|
|
||||||
|
let app = find_cached_binary_repo_packages("repo", &db_path, "app")
|
||||||
|
.unwrap()
|
||||||
|
.pop()
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(app.runtime_dependencies, vec!["icu".to_string()]);
|
||||||
|
assert_eq!(app.built_against, vec!["icu78".to_string()]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_verify_binary_package_record_checksums_accepts_valid_hashes() {
|
fn test_verify_binary_package_record_checksums_accepts_valid_hashes() {
|
||||||
use sha2::{Digest, Sha256, Sha512};
|
use sha2::{Digest, Sha256, Sha512};
|
||||||
@@ -2991,6 +3131,7 @@ revision = 1
|
|||||||
version: "1.0".into(),
|
version: "1.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
filename: "pkg.depot.pkg.tar.zst".into(),
|
filename: "pkg.depot.pkg.tar.zst".into(),
|
||||||
size: 7,
|
size: 7,
|
||||||
@@ -3031,6 +3172,7 @@ revision = 1
|
|||||||
version: "1.0".into(),
|
version: "1.0".into(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
size: payload.len() as u64,
|
size: payload.len() as u64,
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -475,6 +476,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -525,6 +527,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -575,6 +578,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: vec![crate::package::PackageInfo {
|
packages: vec![crate::package::PackageInfo {
|
||||||
@@ -585,6 +589,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
}],
|
}],
|
||||||
alternatives: Default::default(),
|
alternatives: Default::default(),
|
||||||
|
|||||||
@@ -1567,6 +1567,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -692,6 +692,7 @@ pub fn create_interactive() -> Result<PackageSpec> {
|
|||||||
description,
|
description,
|
||||||
homepage,
|
homepage,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license,
|
license,
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1757,6 +1758,7 @@ mod tests {
|
|||||||
description: "A test".into(),
|
description: "A test".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1802,6 +1804,7 @@ mod tests {
|
|||||||
description: "A test".into(),
|
description: "A test".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: vec![PackageInfo {
|
packages: vec![PackageInfo {
|
||||||
@@ -1812,6 +1815,7 @@ mod tests {
|
|||||||
description: "dev files".into(),
|
description: "dev files".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
}],
|
}],
|
||||||
alternatives: Alternatives::default(),
|
alternatives: Alternatives::default(),
|
||||||
@@ -1850,6 +1854,7 @@ mod tests {
|
|||||||
description: "A test".into(),
|
description: "A test".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into(), "Apache-2.0".into()],
|
license: vec!["MIT".into(), "Apache-2.0".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1938,6 +1943,7 @@ mod tests {
|
|||||||
description: "A test".into(),
|
description: "A test".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -2019,6 +2025,7 @@ mod tests {
|
|||||||
description: "A test".into(),
|
description: "A test".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -2057,6 +2064,7 @@ mod tests {
|
|||||||
description: "A test".into(),
|
description: "A test".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -2125,6 +2133,7 @@ mod tests {
|
|||||||
description: "A test".into(),
|
description: "A test".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -2207,6 +2216,7 @@ mod tests {
|
|||||||
description: "Meta package".into(),
|
description: "Meta package".into(),
|
||||||
homepage: "".into(),
|
homepage: "".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -2249,6 +2259,7 @@ mod tests {
|
|||||||
description: "keyring".into(),
|
description: "keyring".into(),
|
||||||
homepage: "https://www.vertexlinux.net".into(),
|
homepage: "https://www.vertexlinux.net".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -184,6 +184,19 @@ impl Packager {
|
|||||||
"abi_breaking".to_string(),
|
"abi_breaking".to_string(),
|
||||||
toml::Value::Boolean(self.spec.package.abi_breaking),
|
toml::Value::Boolean(self.spec.package.abi_breaking),
|
||||||
);
|
);
|
||||||
|
if !self.spec.package.built_against.is_empty() {
|
||||||
|
map.insert(
|
||||||
|
"built_against".to_string(),
|
||||||
|
toml::Value::Array(
|
||||||
|
self.spec
|
||||||
|
.package
|
||||||
|
.built_against
|
||||||
|
.iter()
|
||||||
|
.map(|s| toml::Value::String(s.clone()))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
map.insert(
|
map.insert(
|
||||||
"license".to_string(),
|
"license".to_string(),
|
||||||
license_value(&self.spec.package.license),
|
license_value(&self.spec.package.license),
|
||||||
@@ -357,6 +370,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -528,6 +542,7 @@ mod tests {
|
|||||||
let mut packager = mk_packager(dest.to_path_buf());
|
let mut packager = mk_packager(dest.to_path_buf());
|
||||||
packager.spec.package.real_name = Some("icu".into());
|
packager.spec.package.real_name = Some("icu".into());
|
||||||
packager.spec.package.abi_breaking = true;
|
packager.spec.package.abi_breaking = true;
|
||||||
|
packager.spec.package.built_against = vec!["icu78".into()];
|
||||||
packager.generate_metadata_toml().unwrap();
|
packager.generate_metadata_toml().unwrap();
|
||||||
|
|
||||||
let meta_path = dest.join(".metadata.toml");
|
let meta_path = dest.join(".metadata.toml");
|
||||||
@@ -538,6 +553,11 @@ mod tests {
|
|||||||
val.get("abi_breaking").and_then(|v| v.as_bool()),
|
val.get("abi_breaking").and_then(|v| v.as_bool()),
|
||||||
Some(true)
|
Some(true)
|
||||||
);
|
);
|
||||||
|
let built_against = val
|
||||||
|
.get("built_against")
|
||||||
|
.and_then(|v| v.as_array())
|
||||||
|
.expect("built_against should be an array");
|
||||||
|
assert_eq!(built_against[0].as_str(), Some("icu78"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ pub struct PackageInfo {
|
|||||||
/// When true, renamed updates retain versioned shared libraries from the old package.
|
/// When true, renamed updates retain versioned shared libraries from the old package.
|
||||||
#[serde(default, alias = "abi-breaking")]
|
#[serde(default, alias = "abi-breaking")]
|
||||||
pub abi_breaking: bool,
|
pub abi_breaking: bool,
|
||||||
|
/// Concrete package names this package was built against for ABI-sensitive dependencies.
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
alias = "built-against",
|
||||||
|
deserialize_with = "deserialize_string_or_array"
|
||||||
|
)]
|
||||||
|
pub built_against: Vec<String>,
|
||||||
#[serde(
|
#[serde(
|
||||||
deserialize_with = "deserialize_licenses",
|
deserialize_with = "deserialize_licenses",
|
||||||
serialize_with = "serialize_licenses"
|
serialize_with = "serialize_licenses"
|
||||||
|
|||||||
@@ -40,6 +40,37 @@ type = "custom"
|
|||||||
assert_eq!(spec.spec_dir, tmp.path());
|
assert_eq!(spec.spec_dir, tmp.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_package_built_against_metadata() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let path = tmp.path().join("pkg.toml");
|
||||||
|
|
||||||
|
std::fs::write(
|
||||||
|
&path,
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0"
|
||||||
|
description = "d"
|
||||||
|
homepage = "h"
|
||||||
|
license = "MIT"
|
||||||
|
built-against = ["icu78"]
|
||||||
|
|
||||||
|
[source]
|
||||||
|
url = "https://example.com/foo.tar.gz"
|
||||||
|
sha256 = "skip"
|
||||||
|
extract_dir = "foo"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
type = "custom"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let spec = PackageSpec::from_file(&path).unwrap();
|
||||||
|
assert_eq!(spec.package.built_against, vec!["icu78".to_string()]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_source_array() {
|
fn parse_source_array() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
@@ -2358,6 +2389,7 @@ fn mk_spec(name: &str, version: &str) -> PackageSpec {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -472,6 +472,7 @@ impl ParsedStarbuild {
|
|||||||
description: primary_description,
|
description: primary_description,
|
||||||
homepage: homepage.clone(),
|
homepage: homepage.clone(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: self
|
license: self
|
||||||
.output_licenses
|
.output_licenses
|
||||||
.get(self.main_package_name())
|
.get(self.main_package_name())
|
||||||
@@ -497,6 +498,7 @@ impl ParsedStarbuild {
|
|||||||
.unwrap_or_else(|| primary.description.clone()),
|
.unwrap_or_else(|| primary.description.clone()),
|
||||||
homepage: homepage.clone(),
|
homepage: homepage.clone(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: self
|
license: self
|
||||||
.output_licenses
|
.output_licenses
|
||||||
.get(pkg_name)
|
.get(pkg_name)
|
||||||
|
|||||||
+194
-8
@@ -284,9 +284,24 @@ impl<'a> Resolver<'a> {
|
|||||||
requester_spec_path: Option<&Path>,
|
requester_spec_path: Option<&Path>,
|
||||||
requested_by: String,
|
requested_by: String,
|
||||||
) -> Result<Option<NodeIndex>> {
|
) -> Result<Option<NodeIndex>> {
|
||||||
if deps::is_dep_satisfied_in_db(dep, &self.db_path)? {
|
self.resolve_dep_node_with_preferred(dep, requester_spec_path, requested_by, &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_dep_node_with_preferred(
|
||||||
|
&mut self,
|
||||||
|
dep: &str,
|
||||||
|
requester_spec_path: Option<&Path>,
|
||||||
|
requested_by: String,
|
||||||
|
preferred_packages: &[String],
|
||||||
|
) -> Result<Option<NodeIndex>> {
|
||||||
|
if preferred_packages.is_empty() && deps::is_dep_satisfied_in_db(dep, &self.db_path)? {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
for preferred in preferred_packages {
|
||||||
|
if deps::is_dep_satisfied_in_db(preferred, &self.db_path)? {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let dep_name = deps::dep_name(dep);
|
let dep_name = deps::dep_name(dep);
|
||||||
let candidates = self.collect_candidates(dep_name, requester_spec_path)?;
|
let candidates = self.collect_candidates(dep_name, requester_spec_path)?;
|
||||||
@@ -304,7 +319,7 @@ impl<'a> Resolver<'a> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let chosen = self.choose_candidate(dep, &candidates)?;
|
let chosen = self.choose_candidate(dep, &candidates, preferred_packages)?;
|
||||||
let idx = match chosen.kind {
|
let idx = match chosen.kind {
|
||||||
CandidateKind::Source {
|
CandidateKind::Source {
|
||||||
ref path,
|
ref path,
|
||||||
@@ -345,9 +360,18 @@ impl<'a> Resolver<'a> {
|
|||||||
self.by_package.insert(record.name.clone(), idx);
|
self.by_package.insert(record.name.clone(), idx);
|
||||||
|
|
||||||
for dep in &record.runtime_dependencies {
|
for dep in &record.runtime_dependencies {
|
||||||
if let Some(dep_idx) =
|
let preferred = self.preferred_built_against_packages(dep, &record.built_against)?;
|
||||||
self.resolve_dep_node(dep, None, format!("{} needs {}", record.name, dep))?
|
let dep_label = if preferred.is_empty() {
|
||||||
{
|
dep.clone()
|
||||||
|
} else {
|
||||||
|
format!("{} (built against {})", dep, preferred.join(", "))
|
||||||
|
};
|
||||||
|
if let Some(dep_idx) = self.resolve_dep_node_with_preferred(
|
||||||
|
dep,
|
||||||
|
None,
|
||||||
|
format!("{} needs {}", record.name, dep_label),
|
||||||
|
&preferred,
|
||||||
|
)? {
|
||||||
self.add_dependency_edge(dep_idx, idx, &record.name)?;
|
self.add_dependency_edge(dep_idx, idx, &record.name)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,11 +380,50 @@ impl<'a> Resolver<'a> {
|
|||||||
Ok(idx)
|
Ok(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn choose_candidate(&self, dep: &str, candidates: &[Candidate]) -> Result<Candidate> {
|
fn preferred_built_against_packages(
|
||||||
|
&mut self,
|
||||||
|
dep: &str,
|
||||||
|
built_against: &[String],
|
||||||
|
) -> Result<Vec<String>> {
|
||||||
|
if built_against.is_empty() {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let dep_name = deps::dep_name(dep);
|
||||||
|
let candidates = self.collect_candidates(dep_name, None)?;
|
||||||
|
let mut preferred = Vec::new();
|
||||||
|
for built in built_against {
|
||||||
|
let built_name = deps::dep_name(built);
|
||||||
|
if candidates
|
||||||
|
.iter()
|
||||||
|
.any(|candidate| candidate.package.eq_ignore_ascii_case(built_name))
|
||||||
|
{
|
||||||
|
push_unique(&mut preferred, built.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(preferred)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_candidate(
|
||||||
|
&self,
|
||||||
|
dep: &str,
|
||||||
|
candidates: &[Candidate],
|
||||||
|
preferred_packages: &[String],
|
||||||
|
) -> Result<Candidate> {
|
||||||
let mut sorted = prune_replacement_fallback_candidates(dedupe_candidate_packages(
|
let mut sorted = prune_replacement_fallback_candidates(dedupe_candidate_packages(
|
||||||
sort_candidates(candidates, self.opts.prefer_binary),
|
sort_candidates(candidates, self.opts.prefer_binary),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
for preferred in preferred_packages {
|
||||||
|
let preferred_name = deps::dep_name(preferred);
|
||||||
|
if let Some(position) = sorted
|
||||||
|
.iter()
|
||||||
|
.position(|candidate| candidate.package.eq_ignore_ascii_case(preferred_name))
|
||||||
|
{
|
||||||
|
return Ok(sorted.remove(position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if sorted.len() == 1 {
|
if sorted.len() == 1 {
|
||||||
return Ok(sorted.remove(0));
|
return Ok(sorted.remove(0));
|
||||||
}
|
}
|
||||||
@@ -457,7 +520,12 @@ impl<'a> Resolver<'a> {
|
|||||||
) {
|
) {
|
||||||
Ok(records) => {
|
Ok(records) => {
|
||||||
for rec in records {
|
for rec in records {
|
||||||
let match_kind = if rec.name.eq_ignore_ascii_case(dep_name) {
|
let match_kind = if rec.name.eq_ignore_ascii_case(dep_name)
|
||||||
|
|| rec
|
||||||
|
.real_name
|
||||||
|
.as_deref()
|
||||||
|
.is_some_and(|name| name.eq_ignore_ascii_case(dep_name))
|
||||||
|
{
|
||||||
MatchKind::Exact
|
MatchKind::Exact
|
||||||
} else if rec
|
} else if rec
|
||||||
.replaces
|
.replaces
|
||||||
@@ -862,7 +930,7 @@ mod tests {
|
|||||||
dedupe_candidate_packages, prune_replacement_fallback_candidates, sort_candidates,
|
dedupe_candidate_packages, prune_replacement_fallback_candidates, sort_candidates,
|
||||||
source_deps_for_install,
|
source_deps_for_install,
|
||||||
};
|
};
|
||||||
use crate::config::Config;
|
use crate::config::{BinaryRepo, Config};
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::package::{
|
use crate::package::{
|
||||||
Alternatives, Build, BuildFlags, BuildType, Dependencies, PackageInfo, PackageSpec, Source,
|
Alternatives, Build, BuildFlags, BuildType, Dependencies, PackageInfo, PackageSpec, Source,
|
||||||
@@ -881,6 +949,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: vec![PackageInfo {
|
packages: vec![PackageInfo {
|
||||||
@@ -891,6 +960,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
}],
|
}],
|
||||||
alternatives: Alternatives::default(),
|
alternatives: Alternatives::default(),
|
||||||
@@ -958,6 +1028,7 @@ mod tests {
|
|||||||
version: "1.0.0".to_string(),
|
version: "1.0.0".to_string(),
|
||||||
revision: 1,
|
revision: 1,
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
completed_at: None,
|
completed_at: None,
|
||||||
filename: format!("{name}-1.0.0-1-x86_64.depot.pkg.tar.zst"),
|
filename: format!("{name}-1.0.0-1-x86_64.depot.pkg.tar.zst"),
|
||||||
size: 1024,
|
size: 1024,
|
||||||
@@ -1269,6 +1340,121 @@ version = "4.3.2"
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_compressed_repo_db(db_path: &Path, zst_path: &Path) {
|
||||||
|
let mut input = fs::File::open(db_path).unwrap();
|
||||||
|
let output = fs::File::create(zst_path).unwrap();
|
||||||
|
let mut encoder = zstd::stream::write::Encoder::new(output, 3).unwrap();
|
||||||
|
std::io::copy(&mut input, &mut encoder).unwrap();
|
||||||
|
encoder.finish().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn binary_plan_uses_built_against_concrete_dependency() {
|
||||||
|
let rootfs = tempfile::tempdir().unwrap();
|
||||||
|
let repo_dir = tempfile::tempdir().unwrap();
|
||||||
|
let cache_dir = tempfile::tempdir().unwrap();
|
||||||
|
let mut config = Config::for_rootfs(rootfs.path());
|
||||||
|
config.package_cache_dir = cache_dir.path().to_path_buf();
|
||||||
|
config.repo_settings.prefer_binary = true;
|
||||||
|
config.binary_repos.insert(
|
||||||
|
"core".into(),
|
||||||
|
BinaryRepo {
|
||||||
|
url: url::Url::from_directory_path(repo_dir.path())
|
||||||
|
.expect("file URL")
|
||||||
|
.to_string(),
|
||||||
|
allow_unsigned: true,
|
||||||
|
..BinaryRepo::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let installed_dest = rootfs.path().join("installed");
|
||||||
|
fs::create_dir_all(&installed_dest).unwrap();
|
||||||
|
let mut installed = mk_installed_spec("icu79", "79.1");
|
||||||
|
installed.package.real_name = Some("icu".into());
|
||||||
|
db::register_package(
|
||||||
|
&config.installed_db_path(rootfs.path()),
|
||||||
|
&installed,
|
||||||
|
&installed_dest,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let db_path = repo_dir.path().join("repo.db");
|
||||||
|
let conn = rusqlite::Connection::open(&db_path).unwrap();
|
||||||
|
conn.execute_batch(
|
||||||
|
"
|
||||||
|
CREATE TABLE packages (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
real_name TEXT,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
revision INTEGER NOT NULL,
|
||||||
|
abi_breaking INTEGER NOT NULL DEFAULT 0,
|
||||||
|
built_against TEXT NOT NULL DEFAULT '',
|
||||||
|
completed_at INTEGER,
|
||||||
|
description TEXT,
|
||||||
|
homepage TEXT,
|
||||||
|
license TEXT,
|
||||||
|
filename TEXT NOT NULL,
|
||||||
|
size INTEGER NOT NULL,
|
||||||
|
sha256 TEXT NOT NULL,
|
||||||
|
sha512 TEXT NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE provides (package_id INTEGER, name TEXT NOT NULL);
|
||||||
|
CREATE TABLE replaces (package_id INTEGER, name TEXT NOT NULL);
|
||||||
|
CREATE TABLE conflicts (package_id INTEGER, name TEXT NOT NULL);
|
||||||
|
CREATE TABLE dependencies (package_id INTEGER, kind TEXT NOT NULL, name TEXT NOT NULL);
|
||||||
|
CREATE TABLE groups (package_id INTEGER, name TEXT NOT NULL);
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO packages (id, name, real_name, version, revision, abi_breaking, built_against, completed_at, description, homepage, license, filename, size, sha256, sha512)
|
||||||
|
VALUES (1, 'app', NULL, '1.0', 1, 0, 'icu78', NULL, NULL, NULL, NULL, 'app.pkg', 1, 'aa', 'bb')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO dependencies (package_id, kind, name) VALUES (1, 'runtime', 'icu')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO packages (id, name, real_name, version, revision, abi_breaking, built_against, completed_at, description, homepage, license, filename, size, sha256, sha512)
|
||||||
|
VALUES (2, 'icu78', 'icu', '78.1', 1, 0, '', NULL, NULL, NULL, NULL, 'icu78.pkg', 1, 'cc', 'dd')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
conn.execute(
|
||||||
|
"INSERT INTO packages (id, name, real_name, version, revision, abi_breaking, built_against, completed_at, description, homepage, license, filename, size, sha256, sha512)
|
||||||
|
VALUES (3, 'icu79', 'icu', '79.1', 1, 0, '', NULL, NULL, NULL, NULL, 'icu79.pkg', 1, 'ee', 'ff')",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
drop(conn);
|
||||||
|
write_compressed_repo_db(&db_path, &repo_dir.path().join("repo.db.zst"));
|
||||||
|
fs::remove_file(&db_path).unwrap();
|
||||||
|
|
||||||
|
let plan = super::build_install_plan(
|
||||||
|
&config,
|
||||||
|
rootfs.path(),
|
||||||
|
super::InstallTarget::PackageName("app".into()),
|
||||||
|
PlannerOptions {
|
||||||
|
assume_yes: true,
|
||||||
|
prefer_binary: true,
|
||||||
|
local_sibling_root: None,
|
||||||
|
include_test_deps: false,
|
||||||
|
lib32_only_requested_specs: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let actionable: Vec<_> = plan
|
||||||
|
.actionable_steps()
|
||||||
|
.map(|step| step.package.as_str())
|
||||||
|
.collect();
|
||||||
|
assert_eq!(actionable, vec!["icu78", "app"]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_dependency_edge_skips_active_binary_cycle_back_edge() {
|
fn add_dependency_edge_skips_active_binary_cycle_back_edge() {
|
||||||
let rootfs = tempfile::tempdir().unwrap();
|
let rootfs = tempfile::tempdir().unwrap();
|
||||||
|
|||||||
@@ -712,6 +712,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -758,6 +758,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -817,6 +818,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -886,6 +888,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
|
|||||||
@@ -1753,6 +1753,7 @@ mod tests {
|
|||||||
description: "d".into(),
|
description: "d".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
},
|
},
|
||||||
packages: Vec::new(),
|
packages: Vec::new(),
|
||||||
@@ -1859,6 +1860,7 @@ mod tests {
|
|||||||
description: "dev".into(),
|
description: "dev".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
});
|
});
|
||||||
spec.build.flags.split_docs = true;
|
spec.build.flags.split_docs = true;
|
||||||
@@ -1930,6 +1932,7 @@ mod tests {
|
|||||||
description: "dev".into(),
|
description: "dev".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["MIT".into()],
|
license: vec!["MIT".into()],
|
||||||
});
|
});
|
||||||
spec.packages.push(PackageInfo {
|
spec.packages.push(PackageInfo {
|
||||||
@@ -1940,6 +1943,7 @@ mod tests {
|
|||||||
description: "extras".into(),
|
description: "extras".into(),
|
||||||
homepage: "h".into(),
|
homepage: "h".into(),
|
||||||
abi_breaking: false,
|
abi_breaking: false,
|
||||||
|
built_against: Vec::new(),
|
||||||
license: vec!["Apache-2.0".into()],
|
license: vec!["Apache-2.0".into()],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user