1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use rustc_serialize::{Encodable, Decodable};
use toml::{self, Encoder, Value};
use core::{Resolve, resolver, Package, SourceId};
use util::{CargoResult, ChainError, human, paths};
use util::toml as cargo_toml;
pub fn load_pkg_lockfile(pkg: &Package) -> CargoResult<Option<Resolve>> {
let lockfile = pkg.root().join("Cargo.lock");
let source_id = pkg.package_id().source_id();
load_lockfile(&lockfile, source_id).chain_error(|| {
human(format!("failed to parse lock file at: {}", lockfile.display()))
})
}
pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
let mut f = match File::open(path) {
Ok(f) => f,
Err(_) => return Ok(None)
};
let mut s = String::new();
try!(f.read_to_string(&mut s));
let table = toml::Value::Table(try!(cargo_toml::parse(&s, path)));
let mut d = toml::Decoder::new(table);
let v: resolver::EncodableResolve = try!(Decodable::decode(&mut d));
Ok(Some(try!(v.to_resolve(sid))))
}
pub fn write_pkg_lockfile(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {
let loc = pkg.root().join("Cargo.lock");
write_lockfile(&loc, resolve)
}
pub fn write_lockfile(dst: &Path, resolve: &Resolve) -> CargoResult<()> {
let mut e = Encoder::new();
resolve.encode(&mut e).unwrap();
let mut out = String::new();
let root = e.toml.get(&"root".to_string()).unwrap();
out.push_str("[root]\n");
emit_package(root.as_table().unwrap(), &mut out);
let deps = e.toml.get(&"package".to_string()).unwrap().as_slice().unwrap();
for dep in deps.iter() {
let dep = dep.as_table().unwrap();
out.push_str("[[package]]\n");
emit_package(dep, &mut out);
}
match e.toml.get(&"metadata".to_string()) {
Some(metadata) => {
out.push_str("[metadata]\n");
out.push_str(&metadata.to_string());
}
None => {}
}
if let Ok(orig) = paths::read(dst) {
if has_crlf_line_endings(&orig) {
out = out.replace("\n", "\r\n");
}
if out == orig {
return Ok(())
}
}
try!(paths::write(dst, out.as_bytes()));
Ok(())
}
fn has_crlf_line_endings(s: &str) -> bool {
if let Some(lf) = s.find('\n') {
s[..lf].ends_with('\r')
} else {
false
}
}
fn emit_package(dep: &toml::Table, out: &mut String) {
out.push_str(&format!("name = {}\n", lookup(dep, "name")));
out.push_str(&format!("version = {}\n", lookup(dep, "version")));
if dep.contains_key("source") {
out.push_str(&format!("source = {}\n", lookup(dep, "source")));
}
if let Some(ref s) = dep.get("dependencies") {
let slice = Value::as_slice(*s).unwrap();
if !slice.is_empty() {
out.push_str("dependencies = [\n");
for child in slice.iter() {
out.push_str(&format!(" {},\n", child));
}
out.push_str("]\n");
}
out.push_str("\n");
}
}
fn lookup<'a>(table: &'a toml::Table, key: &str) -> &'a toml::Value {
table.get(key).expect(&format!("didn't find {}", key))
}