1use std::io::Read;
5use std::fs::File;
6use std::path::{Path, PathBuf};
7use std::result::Result as StdResult;
8
9use failure::err_msg;
10use tar::Archive;
11use version_compare::Version;
12use xz2::read::XzDecoder;
13
14use Provide;
15use error::{ParseError, Result};
16
17#[derive(Clone, Debug, Eq, Hash, PartialEq)]
20pub struct Package {
21 pub filename: PathBuf,
22 pub meta: MetaPackage
23}
24
25impl Package {
26 pub fn load(filename: impl AsRef<Path>) -> Result<Package> {
28 let tarball_file = File::open(&filename)?;
29 let xz_decoder = XzDecoder::new(tarball_file);
30 let mut tar_decoder = Archive::new(xz_decoder);
31 for entry in tar_decoder.entries()? {
32 let mut entry = entry?;
33 if entry.path()? == Path::new(".PKGINFO") {
34 let mut data = String::new();
35 entry.read_to_string(&mut data)?;
36 let meta_package = MetaPackage::parse_pkginfo(data)?;
37 let package = Package {
38 filename: filename.as_ref().to_path_buf(),
39 meta: meta_package
40 };
41 return Ok(package);
42 }
43 }
44 Err(err_msg("tarball missing a .PKGINFO entry"))
45 }
46}
47
48#[derive(Clone, Debug, Eq, Hash, PartialEq)]
54pub struct MetaPackage {
55 pub name: String,
56 version: String,
57 pub description: String,
58 pub url: String,
60 pub packager: String,
62 pub architecture: String,
65 pub groups: Vec<String>,
66 pub licenses: Vec<String>,
67 pub depends: Vec<String>,
68 pub optdepends: Vec<String>,
69 pub makedepends: Vec<String>,
70 pub conflicts: Vec<String>,
71 pub replaces: Vec<String>,
72 pub provides: Vec<Provide>,
73 pub backups: Vec<String>
74}
75macro_rules! empty_meta_pkg {
114 () => {
115 MetaPackage {
116 name: String::new(),
117 version: String::new(),
118 description: String::new(),
119 url: String::new(),
120 packager: String::new(),
121 architecture: String::new(),
122
123 groups: Vec::new(),
124 licenses: Vec::new(),
125 depends: Vec::new(),
126 optdepends: Vec::new(),
127 makedepends: Vec::new(),
128 conflicts: Vec::new(),
129 replaces: Vec::new(),
130 provides: Vec::new(),
131 backups: Vec::new()
132 }
133 }
134}
135
136impl MetaPackage {
137 pub(crate) fn parse_pkginfo(pkginfo_data: String) -> StdResult<MetaPackage, ParseError> {
139 let mut pkg = empty_meta_pkg!();
140
141 let mut line_num = 0;
142
143 for line in pkginfo_data.lines() {
144 line_num += 1;
145
146 let line = line.trim();
147 if line.starts_with("#") || line.len() == 0 {
148 continue
149 }
150 let mut pair = line.splitn(2, '=');
151 let key = pair.next()
152 .ok_or(ParseError::MissingKey(line_num))?
153 .trim().to_string();
154 let value = pair.next()
155 .ok_or(ParseError::MissingValue(line_num, key.to_string()))?
156 .trim().to_string();
157
158 macro_rules! load_value {
159 ($var:expr) => (if $var.len() == 0 {
160 $var = value;
161 } else {
162 return Err(ParseError::MultipleKeys(line_num, key.to_string()));
163 })
164 }
165
166 match key.as_str() {
167 "pkgname" => load_value!(pkg.name),
168 "pkgbase" => {}, "pkgver" => load_value!(pkg.version),
170 "pkgdesc" => load_value!(pkg.description),
171 "group" => pkg.groups.push(value),
172 "url" => load_value!(pkg.url),
173 "builddate" => {}, "packager" => load_value!(pkg.packager),
175 "size" => {}, "arch" => load_value!(pkg.architecture),
177 "license" => pkg.licenses.push(value),
178 "depend" => pkg.depends.push(value),
179 "optdepend" => pkg.optdepends.push(value),
180 "makedepend" => pkg.makedepends.push(value),
181 "conflict" => pkg.conflicts.push(value),
182 "replaces" => pkg.replaces.push(value),
183 "provides" => pkg.provides.push(Provide::parse(&value)
185 .expect(&format!("Invalid Provide: {}", value))),
186 "backup" => pkg.backups.push(value),
187 "force" => {}, "makepkgopt" => {}, &_ => return Err(ParseError::UnknownKey(line_num, key.to_string()))
191 }
192 }
193 Ok(pkg)
194 }
195
196 pub(crate) fn parse_pkgdesc(desc_data: String) -> StdResult<MetaPackage, ParseError> {
200 let mut pkg = empty_meta_pkg!();
201 let mut line_num: u32 = 0;
204
205 for entry in desc_data.split("\n\n") {
206 line_num += 1;
207 let mut lines = entry.lines();
208 if let Some(key) = lines.next() {
210 line_num += 1;
211
212 if key == "" {
213 continue;
214 }
215
216 macro_rules! load_value {
217 ($field:ident, $required:expr) => {
218 if let Some(val) = lines.next() {
219 line_num += 1;
220 pkg.$field = val.to_string();
221 } else if !$required {
222 line_num += 1;
223 } else {
224 return Err(ParseError::MissingValue(line_num, key.to_string()))
225 }
226 }
227 }
228
229 macro_rules! load_value_all {
230 ($field:ident) => {
231 pkg.$field = lines.map(|line| line.to_string() ).collect()
232 }
233 }
234
235 match key {
237 "%NAME%" => load_value!(name, true),
238 "%VERSION%" => load_value!(version, true),
239 "%FILENAME%" => {} "%BASE%" => {}, "%DESC%" => load_value!(description, false),
242 "%GROUPS%" => load_value_all!(groups),
243 "%URL%" => load_value!(url, false),
244 "%LICENSE%" => load_value_all!(licenses),
245 "%ARCH%" => load_value!(architecture, true),
246 "%BUILDDATE%" => {}, "%INSTALLDATE%" => {}, "%REASON%" => {}, "%PACKAGER%" => load_value!(packager, true),
250 "%SIZE%" => {}, "%CSIZE%" => {}, "%ISIZE%" => {}, "%MD5SUM%" => {}, "%SHA256SUM%" => {}, "%PGPSIG%" => {}, "%VALIDATION%" => {}, "%REPLACES%" => load_value_all!(replaces),
258 "%DEPENDS%" => load_value_all!(depends),
259 "%OPTDEPENDS%" => load_value_all!(optdepends),
260 "%MAKEDEPENDS%" => load_value_all!(makedepends),
261 "%CHECKDEPENDS%" => {}, "%CONFLICTS%" => load_value_all!(conflicts),
263 "%PROVIDES%" => pkg.provides = lines
265 .map(|line| Provide::parse(line)
266 .expect(&format!("Invalid Provide: {}", line)))
267 .collect(),
268 "%DELTAS%" => {}, "%FILES%" => {}, &_ => return Err(ParseError::UnknownKey(line_num, key.to_string()))
272 }
273 }
274 }
275 Ok(pkg)
277 }
278
279 pub fn version(&self) -> Option<Version> {
281 Version::from(&self.version)
282 }
283
284 pub fn satisfies(&self, other: &Provide) -> bool {
287 let self_provide = Provide::parse(format!("{}={}", self.name, self.version))
289 .expect(&format!("{:?} does not have a name", self));
290
291 self_provide.satisfies(other) || self.provides.iter()
292 .any(|provide| provide.satisfies(other) )
293 }
294}