|
1 | 1 | use crate::git::repo;
|
2 | 2 | use crate::paths;
|
| 3 | +use crate::publish::{create_index_line, write_to_index}; |
3 | 4 | use cargo_util::paths::append;
|
4 |
| -use cargo_util::{registry::make_dep_path, Sha256}; |
| 5 | +use cargo_util::Sha256; |
5 | 6 | use flate2::write::GzEncoder;
|
6 | 7 | use flate2::Compression;
|
7 | 8 | use std::collections::{BTreeMap, HashMap};
|
8 | 9 | use std::fmt;
|
9 | 10 | use std::fs::{self, File};
|
10 | 11 | use std::io::{BufRead, BufReader, Read, Write};
|
11 | 12 | use std::net::{SocketAddr, TcpListener, TcpStream};
|
12 |
| -use std::path::{Path, PathBuf}; |
| 13 | +use std::path::PathBuf; |
13 | 14 | use std::thread;
|
14 | 15 | use tar::{Builder, Header};
|
15 | 16 | use url::Url;
|
@@ -389,7 +390,7 @@ pub struct Package {
|
389 | 390 | v: Option<u32>,
|
390 | 391 | }
|
391 | 392 |
|
392 |
| -type FeatureMap = BTreeMap<String, Vec<String>>; |
| 393 | +pub(crate) type FeatureMap = BTreeMap<String, Vec<String>>; |
393 | 394 |
|
394 | 395 | #[derive(Clone)]
|
395 | 396 | pub struct Dependency {
|
@@ -637,16 +638,72 @@ impl HttpServer {
|
637 | 638 | self.dl(&req)
|
638 | 639 | }
|
639 | 640 | }
|
| 641 | + // publish |
| 642 | + ("put", ["api", "v1", "crates", "new"]) => { |
| 643 | + if !authorized(true) { |
| 644 | + return self.unauthorized(req) |
| 645 | + } |
| 646 | + if let Some(body) = &req.body { |
| 647 | + // Get the metadata of the package |
| 648 | + let (len, remaining) = body.split_at(4); |
| 649 | + let json_len = u32::from_le_bytes(len.try_into().unwrap()); |
| 650 | + let (json, remaining) = remaining.split_at(json_len as usize); |
| 651 | + let new_crate = serde_json::from_slice::<crates_io::NewCrate>(json).unwrap(); |
| 652 | + // Get the `.crate` file |
| 653 | + let (len, remaining) = remaining.split_at(4); |
| 654 | + let file_len = u32::from_le_bytes(len.try_into().unwrap()); |
| 655 | + let (file, _remaining) = remaining.split_at(file_len as usize); |
| 656 | + |
| 657 | + // Write the `.crate` |
| 658 | + let dst = self.dl_path.join(&new_crate.name).join(&new_crate.vers).join("download"); |
| 659 | + t!(fs::create_dir_all(dst.parent().unwrap())); |
| 660 | + let mut f = t!(File::create(&dst)); |
| 661 | + t!(f.write_all(file)); |
| 662 | + |
| 663 | + let deps = new_crate.deps.iter().map(|dep| { |
| 664 | + serde_json::json!({ |
| 665 | + "name": dep.name, |
| 666 | + "req": dep.version_req, |
| 667 | + "features": dep.features, |
| 668 | + "default_features": true, |
| 669 | + "target": dep.target, |
| 670 | + "optional": dep.optional, |
| 671 | + "kind": dep.kind, |
| 672 | + "registry": dep.registry, |
| 673 | + "package": dep.explicit_name_in_toml, |
| 674 | + }) |
| 675 | + }).collect::<Vec<_>>(); |
| 676 | + |
| 677 | + let line = create_index_line( |
| 678 | + serde_json::json!(new_crate.name), |
| 679 | + &new_crate.vers, |
| 680 | + deps, |
| 681 | + &cksum(file), |
| 682 | + new_crate.features, |
| 683 | + false, |
| 684 | + new_crate.links, |
| 685 | + None, |
| 686 | + ); |
| 687 | + |
| 688 | + write_to_index(&self.registry_path, &new_crate.name, line, false); |
| 689 | + |
| 690 | + self.ok(&req) |
| 691 | + } else { |
| 692 | + Response { |
| 693 | + code: 400, |
| 694 | + headers: vec![], |
| 695 | + body: b"The request was missing a body".to_vec(), |
| 696 | + } |
| 697 | + } |
| 698 | + } |
640 | 699 | // The remainder of the operators in the test framework do nothing other than responding 'ok'.
|
641 | 700 | //
|
642 | 701 | // Note: We don't need to support anything real here because the testing framework publishes crates
|
643 | 702 | // by writing directly to the filesystem instead. If the test framework is changed to publish
|
644 | 703 | // via the HTTP API, then this should be made more complete.
|
645 | 704 |
|
646 |
| - // publish |
647 |
| - ("put", ["api", "v1", "crates", "new"]) |
648 | 705 | // yank
|
649 |
| - | ("delete", ["api", "v1", "crates", .., "yank"]) |
| 706 | + ("delete", ["api", "v1", "crates", .., "yank"]) |
650 | 707 | // unyank
|
651 | 708 | | ("put", ["api", "v1", "crates", .., "unyank"])
|
652 | 709 | // owners
|
@@ -999,66 +1056,24 @@ impl Package {
|
999 | 1056 | } else {
|
1000 | 1057 | serde_json::json!(self.name)
|
1001 | 1058 | };
|
1002 |
| - // This emulates what crates.io may do in the future. |
1003 |
| - let (features, features2) = split_index_features(self.features.clone()); |
1004 |
| - let mut json = serde_json::json!({ |
1005 |
| - "name": name, |
1006 |
| - "vers": self.vers, |
1007 |
| - "deps": deps, |
1008 |
| - "cksum": cksum, |
1009 |
| - "features": features, |
1010 |
| - "yanked": self.yanked, |
1011 |
| - "links": self.links, |
1012 |
| - }); |
1013 |
| - if let Some(f2) = &features2 { |
1014 |
| - json["features2"] = serde_json::json!(f2); |
1015 |
| - json["v"] = serde_json::json!(2); |
1016 |
| - } |
1017 |
| - if let Some(v) = self.v { |
1018 |
| - json["v"] = serde_json::json!(v); |
1019 |
| - } |
1020 |
| - let line = json.to_string(); |
1021 |
| - |
1022 |
| - let file = make_dep_path(&self.name, false); |
| 1059 | + let line = create_index_line( |
| 1060 | + name, |
| 1061 | + &self.vers, |
| 1062 | + deps, |
| 1063 | + &cksum, |
| 1064 | + self.features.clone(), |
| 1065 | + self.yanked, |
| 1066 | + self.links.clone(), |
| 1067 | + self.v, |
| 1068 | + ); |
1023 | 1069 |
|
1024 | 1070 | let registry_path = if self.alternative {
|
1025 | 1071 | alt_registry_path()
|
1026 | 1072 | } else {
|
1027 | 1073 | registry_path()
|
1028 | 1074 | };
|
1029 | 1075 |
|
1030 |
| - // Write file/line in the index. |
1031 |
| - let dst = if self.local { |
1032 |
| - registry_path.join("index").join(&file) |
1033 |
| - } else { |
1034 |
| - registry_path.join(&file) |
1035 |
| - }; |
1036 |
| - let prev = fs::read_to_string(&dst).unwrap_or_default(); |
1037 |
| - t!(fs::create_dir_all(dst.parent().unwrap())); |
1038 |
| - t!(fs::write(&dst, prev + &line[..] + "\n")); |
1039 |
| - |
1040 |
| - // Add the new file to the index. |
1041 |
| - if !self.local { |
1042 |
| - let repo = t!(git2::Repository::open(®istry_path)); |
1043 |
| - let mut index = t!(repo.index()); |
1044 |
| - t!(index.add_path(Path::new(&file))); |
1045 |
| - t!(index.write()); |
1046 |
| - let id = t!(index.write_tree()); |
1047 |
| - |
1048 |
| - // Commit this change. |
1049 |
| - let tree = t!(repo.find_tree(id)); |
1050 |
| - let sig = t!(repo.signature()); |
1051 |
| - let parent = t!(repo.refname_to_id("refs/heads/master")); |
1052 |
| - let parent = t!(repo.find_commit(parent)); |
1053 |
| - t!(repo.commit( |
1054 |
| - Some("HEAD"), |
1055 |
| - &sig, |
1056 |
| - &sig, |
1057 |
| - "Another commit", |
1058 |
| - &tree, |
1059 |
| - &[&parent] |
1060 |
| - )); |
1061 |
| - } |
| 1076 | + write_to_index(®istry_path, &self.name, line, self.local); |
1062 | 1077 |
|
1063 | 1078 | cksum
|
1064 | 1079 | }
|
@@ -1279,21 +1294,3 @@ impl Dependency {
|
1279 | 1294 | self
|
1280 | 1295 | }
|
1281 | 1296 | }
|
1282 |
| - |
1283 |
| -fn split_index_features(mut features: FeatureMap) -> (FeatureMap, Option<FeatureMap>) { |
1284 |
| - let mut features2 = FeatureMap::new(); |
1285 |
| - for (feat, values) in features.iter_mut() { |
1286 |
| - if values |
1287 |
| - .iter() |
1288 |
| - .any(|value| value.starts_with("dep:") || value.contains("?/")) |
1289 |
| - { |
1290 |
| - let new_values = values.drain(..).collect(); |
1291 |
| - features2.insert(feat.clone(), new_values); |
1292 |
| - } |
1293 |
| - } |
1294 |
| - if features2.is_empty() { |
1295 |
| - (features, None) |
1296 |
| - } else { |
1297 |
| - (features, Some(features2)) |
1298 |
| - } |
1299 |
| -} |
0 commit comments