1use std::collections::HashMap;
2
3use failure::bail;
4use failure::ensure;
5use failure::err_msg;
6use failure::Error;
7use insideout::InsideOut;
8
9use super::deps::parse_dep;
10use super::deps::Dependency;
11use super::ident::Identity;
12use super::pkg;
13use super::vcs;
14use crate::rfc822;
15use crate::rfc822::RfcMapExt;
16use std::collections::HashSet;
17
18#[derive(Clone, Debug, PartialEq, Eq)]
20pub struct Source {
21 pub format: SourceFormat,
22
23 pub binaries: Vec<SourceBinary>,
24 pub files: Vec<SourceArchive>,
25 pub vcs: Vec<vcs::Vcs>,
26
27 pub directory: String,
28 pub standards_version: String,
29
30 pub build_dep: Vec<Dependency>,
31 pub build_dep_arch: Vec<Dependency>,
32 pub build_dep_indep: Vec<Dependency>,
33 pub build_conflict: Vec<Dependency>,
34 pub build_conflict_arch: Vec<Dependency>,
35 pub build_conflict_indep: Vec<Dependency>,
36
37 pub uploaders: Vec<Identity>,
38}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
43pub struct SourceArchive {
44 pub name: String,
45 pub size: u64,
46 pub md5: crate::checksum::MD5,
47 pub sha256: Option<crate::checksum::SHA256>,
48}
49
50#[derive(Clone, Debug, PartialEq, Eq)]
52pub struct SourceBinary {
53 pub name: String,
54 pub style: String,
55 pub section: String,
56
57 pub priority: pkg::Priority,
58 pub extras: Vec<String>,
59}
60
61#[derive(Copy, Clone, Debug, PartialEq, Eq)]
63pub enum SourceFormat {
64 Original,
65 Quilt3dot0,
66 Native3dot0,
67 Git3dot0,
68}
69
70pub(super) fn parse_src(map: &mut rfc822::Map) -> Result<Source, Error> {
71 Ok(Source {
72 format: parse_format(map.remove_value("Format").one_line_req()?)?,
73 binaries: take_package_list(map)?,
74 files: take_files(map)?,
75 directory: map.remove_value("Directory").one_line_req()?.to_string(),
76 vcs: super::vcs::extract(map)?,
77 standards_version: map
79 .remove_value("Standards-Version")
80 .one_line()?
81 .unwrap_or("")
82 .to_string(),
83 build_dep: parse_dep(&map.remove("Build-Depends").unwrap_or_else(Vec::new))?,
84 build_dep_arch: parse_dep(&map.remove("Build-Depends-Arch").unwrap_or_else(Vec::new))?,
85 build_dep_indep: parse_dep(&map.remove("Build-Depends-Indep").unwrap_or_else(Vec::new))?,
86 build_conflict: parse_dep(&map.remove("Build-Conflicts").unwrap_or_else(Vec::new))?,
87 build_conflict_arch: parse_dep(
88 &map.remove("Build-Conflicts-Arch").unwrap_or_else(Vec::new),
89 )?,
90 build_conflict_indep: parse_dep(
91 &map.remove("Build-Conflicts-Indep").unwrap_or_else(Vec::new),
92 )?,
93 uploaders: map
94 .remove_value("Uploaders")
95 .one_line()?
96 .map(|line| super::ident::read(line))
97 .inside_out()?
98 .unwrap_or_else(Vec::new),
99 })
100}
101
102pub(super) fn parse_format(string: &str) -> Result<SourceFormat, Error> {
103 Ok(match string {
104 "3.0 (quilt)" => SourceFormat::Quilt3dot0,
105 "1.0" => SourceFormat::Original,
106 "3.0 (git)" => SourceFormat::Git3dot0,
107 "3.0 (native)" => SourceFormat::Native3dot0,
108 other => bail!("unsupported source format: '{}'", other),
109 })
110}
111
112pub(super) fn take_package_list(map: &mut rfc822::Map) -> Result<Vec<SourceBinary>, Error> {
113 let package_list = match map.remove("Package-List") {
114 Some(list) => list,
115 None => {
116 return Ok(map
118 .remove_value("Binary")
119 .split_comma()?
120 .into_iter()
121 .map(|v| SourceBinary {
124 name: v.to_string(),
125 style: String::new(),
126 section: String::new(),
127 priority: super::Priority::Unknown,
128 extras: Vec::new(),
129 })
130 .collect());
131 }
132 };
133
134 let mut binary_names: HashSet<_> = map
135 .remove_value("Binary")
136 .split_comma()?
137 .into_iter()
138 .collect();
139
140 let mut binaries = Vec::with_capacity(package_list.len());
141
142 for line in package_list {
143 let parts: Vec<_> = line.split_whitespace().collect();
144 ensure!(parts.len() >= 4, "package list line too short: {:?}", line);
145 let name = parts[0];
146 ensure!(
147 binary_names.remove(name),
148 "{:?} in package list, but not in Binary",
149 name
150 );
151 binaries.push(SourceBinary {
152 name: name.to_string(),
153 style: parts[1].to_string(),
154 section: parts[2].to_string(),
155 priority: super::pkg::parse_priority(parts[3])?,
156 extras: parts[4..].into_iter().map(|s| s.to_string()).collect(),
157 });
158 }
159
160 ensure!(
161 binary_names.is_empty(),
162 "some binary names were not in Package-List: {:?}",
163 binary_names
164 );
165
166 Ok(binaries)
167}
168
169pub(super) fn take_files(map: &mut rfc822::Map) -> Result<Vec<SourceArchive>, Error> {
170 use crate::checksum::parse_md5;
171 use crate::checksum::parse_sha256;
172 use crate::release::take_checksums;
173 let file_and_size_to_md5 =
174 take_checksums(map, "Files")?.ok_or_else(|| err_msg("Files required"))?;
175 let mut file_and_size_to_sha256 =
176 take_checksums(map, "Checksums-Sha256")?.unwrap_or_else(HashMap::new);
177
178 let mut archives = Vec::with_capacity(file_and_size_to_md5.len());
179 for ((name, size), md5) in file_and_size_to_md5 {
180 let sha256 = file_and_size_to_sha256.remove(&(name, size));
181 archives.push(SourceArchive {
182 name: name.to_string(),
183 size,
184 md5: parse_md5(md5)?,
185 sha256: sha256.map(|v| parse_sha256(v)).inside_out()?,
186 })
187 }
188
189 ensure!(
190 file_and_size_to_sha256.is_empty(),
191 "sha256sum for a file which didn't exist: {:?}",
192 file_and_size_to_sha256
193 );
194
195 Ok(archives)
196}