1 use crate::versions::PkgType;
3 use serde::{Serialize, Serializer};
4 use std::collections::BTreeMap;
5 use std::path::{Path, PathBuf};
8 #[serde(rename_all = "kebab-case")]
9 pub(crate) struct Manifest {
10 pub(crate) manifest_version: String,
11 pub(crate) date: String,
12 pub(crate) pkg: BTreeMap<String, Package>,
13 pub(crate) artifacts: BTreeMap<String, Artifact>,
14 pub(crate) renames: BTreeMap<String, Rename>,
15 pub(crate) profiles: BTreeMap<String, Vec<String>>,
19 pub(crate) fn add_artifact(&mut self, name: &str, f: impl FnOnce(&mut Artifact)) {
20 let mut artifact = Artifact { target: BTreeMap::new() };
22 self.artifacts.insert(name.to_string(), artifact);
27 pub(crate) struct Package {
28 pub(crate) version: String,
29 pub(crate) git_commit_hash: Option<String>,
30 pub(crate) target: BTreeMap<String, Target>,
34 pub(crate) struct Rename {
35 pub(crate) to: String,
39 pub(crate) struct Artifact {
40 pub(crate) target: BTreeMap<String, Vec<ArtifactFile>>,
44 pub(crate) fn add_file(&mut self, builder: &mut Builder, target: &str, path: &str) {
45 if let Some(path) = record_shipped_file(builder, builder.input.join(path)) {
46 self.target.entry(target.into()).or_insert_with(Vec::new).push(ArtifactFile {
47 url: builder.url(&path),
48 hash_sha256: FileHash::Missing(path),
53 pub(crate) fn add_tarball(&mut self, builder: &mut Builder, target: &str, base_path: &str) {
54 let files = self.target.entry(target.into()).or_insert_with(Vec::new);
55 let base_path = builder.input.join(base_path);
56 for compression in &["gz", "xz"] {
57 if let Some(tarball) = tarball_variant(builder, &base_path, compression) {
58 files.push(ArtifactFile {
59 url: builder.url(&tarball),
60 hash_sha256: FileHash::Missing(tarball),
68 #[serde(rename_all = "kebab-case")]
69 pub(crate) struct ArtifactFile {
70 pub(crate) url: String,
71 pub(crate) hash_sha256: FileHash,
74 #[derive(Serialize, Default)]
75 pub(crate) struct Target {
76 pub(crate) available: bool,
77 pub(crate) url: Option<String>,
78 pub(crate) hash: Option<FileHash>,
79 pub(crate) xz_url: Option<String>,
80 pub(crate) xz_hash: Option<FileHash>,
81 pub(crate) components: Option<Vec<Component>>,
82 pub(crate) extensions: Option<Vec<Component>>,
86 pub(crate) fn from_compressed_tar(builder: &mut Builder, base_path: &str) -> Self {
87 let base_path = builder.input.join(base_path);
88 let gz = tarball_variant(builder, &base_path, "gz");
89 let xz = tarball_variant(builder, &base_path, "xz");
92 return Self::unavailable();
100 url: gz.as_ref().map(|path| builder.url(path)),
101 hash: gz.map(FileHash::Missing),
103 xz_url: xz.as_ref().map(|path| builder.url(path)),
104 xz_hash: xz.map(FileHash::Missing),
108 pub(crate) fn unavailable() -> Self {
114 pub(crate) struct Component {
115 pub(crate) pkg: String,
116 pub(crate) target: String,
120 pub(crate) fn from_pkg(pkg: &PkgType, target: &str) -> Self {
121 Self { pkg: pkg.manifest_component_name(), target: target.to_string() }
126 pub(crate) enum FileHash {
131 impl Serialize for FileHash {
132 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
134 FileHash::Missing(path) => Err(serde::ser::Error::custom(format!(
135 "can't serialize a missing hash for file {}",
138 FileHash::Present(inner) => inner.serialize(serializer),
143 fn tarball_variant(builder: &mut Builder, base: &Path, ext: &str) -> Option<PathBuf> {
144 let mut path = base.to_path_buf();
145 path.set_extension(ext);
146 record_shipped_file(builder, path)
149 fn record_shipped_file(builder: &mut Builder, path: PathBuf) -> Option<PathBuf> {
151 builder.shipped_files.insert(
153 .expect("missing filename")
155 .expect("non-utf-8 filename")
164 pub(crate) fn visit_file_hashes(manifest: &mut Manifest, mut f: impl FnMut(&mut FileHash)) {
165 for pkg in manifest.pkg.values_mut() {
166 for target in pkg.target.values_mut() {
167 if let Some(hash) = &mut target.hash {
170 if let Some(hash) = &mut target.xz_hash {
176 for artifact in manifest.artifacts.values_mut() {
177 for target in artifact.target.values_mut() {
179 f(&mut file.hash_sha256);