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 anyhow::Context;
use cargo_util::Sha256;
use crate::core::PackageId;
use crate::sources::registry::make_dep_prefix;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{
RegistryConfig, CHECKSUM_TEMPLATE, CRATE_TEMPLATE, LOWER_PREFIX_TEMPLATE, PREFIX_TEMPLATE,
VERSION_TEMPLATE,
};
use crate::util::errors::CargoResult;
use crate::util::{Config, Filesystem};
use std::fmt::Write as FmtWrite;
use std::fs::{self, File, OpenOptions};
use std::io::prelude::*;
use std::io::SeekFrom;
use std::str;
pub(super) fn filename(pkg: PackageId) -> String {
format!("{}-{}.crate", pkg.name(), pkg.version())
}
pub(super) fn download(
cache_path: &Filesystem,
config: &Config,
pkg: PackageId,
checksum: &str,
registry_config: RegistryConfig,
) -> CargoResult<MaybeLock> {
let filename = filename(pkg);
let path = cache_path.join(&filename);
let path = config.assert_package_cache_locked(&path);
if let Ok(dst) = File::open(path) {
let meta = dst.metadata()?;
if meta.len() > 0 {
return Ok(MaybeLock::Ready(dst));
}
}
let mut url = registry_config.dl;
if !url.contains(CRATE_TEMPLATE)
&& !url.contains(VERSION_TEMPLATE)
&& !url.contains(PREFIX_TEMPLATE)
&& !url.contains(LOWER_PREFIX_TEMPLATE)
&& !url.contains(CHECKSUM_TEMPLATE)
{
write!(
url,
"/{}/{}/download",
pkg.name(),
pkg.version().to_string()
)
.unwrap();
} else {
let prefix = make_dep_prefix(&*pkg.name());
url = url
.replace(CRATE_TEMPLATE, &*pkg.name())
.replace(VERSION_TEMPLATE, &pkg.version().to_string())
.replace(PREFIX_TEMPLATE, &prefix)
.replace(LOWER_PREFIX_TEMPLATE, &prefix.to_lowercase())
.replace(CHECKSUM_TEMPLATE, checksum);
}
Ok(MaybeLock::Download {
url,
descriptor: pkg.to_string(),
})
}
pub(super) fn finish_download(
cache_path: &Filesystem,
config: &Config,
pkg: PackageId,
checksum: &str,
data: &[u8],
) -> CargoResult<File> {
let actual = Sha256::new().update(data).finish_hex();
if actual != checksum {
anyhow::bail!("failed to verify the checksum of `{}`", pkg)
}
let filename = filename(pkg);
cache_path.create_dir()?;
let path = cache_path.join(&filename);
let path = config.assert_package_cache_locked(&path);
let mut dst = OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(&path)
.with_context(|| format!("failed to open `{}`", path.display()))?;
let meta = dst.metadata()?;
if meta.len() > 0 {
return Ok(dst);
}
dst.write_all(data)?;
dst.seek(SeekFrom::Start(0))?;
Ok(dst)
}
pub(super) fn is_crate_downloaded(
cache_path: &Filesystem,
config: &Config,
pkg: PackageId,
) -> bool {
let path = cache_path.join(filename(pkg));
let path = config.assert_package_cache_locked(&path);
if let Ok(meta) = fs::metadata(path) {
return meta.len() > 0;
}
false
}