]> git.lizzy.rs Git - rust.git/blob - src/tools/build-manifest/src/manifest.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / src / tools / build-manifest / src / manifest.rs
1 use crate::versions::PkgType;
2 use crate::Builder;
3 use serde::{Serialize, Serializer};
4 use std::collections::BTreeMap;
5 use std::path::{Path, PathBuf};
6
7 #[derive(Serialize)]
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>>,
16 }
17
18 impl Manifest {
19     pub(crate) fn add_artifact(&mut self, name: &str, f: impl FnOnce(&mut Artifact)) {
20         let mut artifact = Artifact { target: BTreeMap::new() };
21         f(&mut artifact);
22         self.artifacts.insert(name.to_string(), artifact);
23     }
24 }
25
26 #[derive(Serialize)]
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>,
31 }
32
33 #[derive(Serialize)]
34 pub(crate) struct Rename {
35     pub(crate) to: String,
36 }
37
38 #[derive(Serialize)]
39 pub(crate) struct Artifact {
40     pub(crate) target: BTreeMap<String, Vec<ArtifactFile>>,
41 }
42
43 impl Artifact {
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),
49             });
50         }
51     }
52
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),
61                 });
62             }
63         }
64     }
65 }
66
67 #[derive(Serialize)]
68 #[serde(rename_all = "kebab-case")]
69 pub(crate) struct ArtifactFile {
70     pub(crate) url: String,
71     pub(crate) hash_sha256: FileHash,
72 }
73
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>>,
83 }
84
85 impl Target {
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");
90
91         if gz.is_none() {
92             return Self::unavailable();
93         }
94
95         Self {
96             available: true,
97             components: None,
98             extensions: None,
99             // .gz
100             url: gz.as_ref().map(|path| builder.url(path)),
101             hash: gz.map(FileHash::Missing),
102             // .xz
103             xz_url: xz.as_ref().map(|path| builder.url(path)),
104             xz_hash: xz.map(FileHash::Missing),
105         }
106     }
107
108     pub(crate) fn unavailable() -> Self {
109         Self::default()
110     }
111 }
112
113 #[derive(Serialize)]
114 pub(crate) struct Component {
115     pub(crate) pkg: String,
116     pub(crate) target: String,
117 }
118
119 impl Component {
120     pub(crate) fn from_pkg(pkg: &PkgType, target: &str) -> Self {
121         Self { pkg: pkg.manifest_component_name(), target: target.to_string() }
122     }
123 }
124
125 #[allow(unused)]
126 pub(crate) enum FileHash {
127     Missing(PathBuf),
128     Present(String),
129 }
130
131 impl Serialize for FileHash {
132     fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
133         match self {
134             FileHash::Missing(path) => Err(serde::ser::Error::custom(format!(
135                 "can't serialize a missing hash for file {}",
136                 path.display()
137             ))),
138             FileHash::Present(inner) => inner.serialize(serializer),
139         }
140     }
141 }
142
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)
147 }
148
149 fn record_shipped_file(builder: &mut Builder, path: PathBuf) -> Option<PathBuf> {
150     if path.is_file() {
151         builder.shipped_files.insert(
152             path.file_name()
153                 .expect("missing filename")
154                 .to_str()
155                 .expect("non-utf-8 filename")
156                 .to_string(),
157         );
158         Some(path)
159     } else {
160         None
161     }
162 }
163
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 {
168                 f(hash);
169             }
170             if let Some(hash) = &mut target.xz_hash {
171                 f(hash);
172             }
173         }
174     }
175
176     for artifact in manifest.artifacts.values_mut() {
177         for target in artifact.target.values_mut() {
178             for file in target {
179                 f(&mut file.hash_sha256);
180             }
181         }
182     }
183 }