|
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,21 @@ impl HttpServer {
|
637 | 638 | self.dl(&req)
|
638 | 639 | }
|
639 | 640 | }
|
| 641 | + // publish |
| 642 | + ("put", ["api", "v1", "crates", "new"]) => { |
| 643 | + if !authorized(true) { |
| 644 | + self.unauthorized(req) |
| 645 | + } else { |
| 646 | + self.publish(req) |
| 647 | + } |
| 648 | + } |
640 | 649 | // The remainder of the operators in the test framework do nothing other than responding 'ok'.
|
641 | 650 | //
|
642 |
| - // Note: We don't need to support anything real here because the testing framework publishes crates |
643 |
| - // by writing directly to the filesystem instead. If the test framework is changed to publish |
644 |
| - // via the HTTP API, then this should be made more complete. |
| 651 | + // Note: We don't need to support anything real here because there are no tests that |
| 652 | + // currently require anything other than publishing via the http api. |
645 | 653 |
|
646 |
| - // publish |
647 |
| - ("put", ["api", "v1", "crates", "new"]) |
648 | 654 | // yank
|
649 |
| - | ("delete", ["api", "v1", "crates", .., "yank"]) |
| 655 | + ("delete", ["api", "v1", "crates", .., "yank"]) |
650 | 656 | // unyank
|
651 | 657 | | ("put", ["api", "v1", "crates", .., "unyank"])
|
652 | 658 | // owners
|
@@ -754,6 +760,72 @@ impl HttpServer {
|
754 | 760 | }
|
755 | 761 | }
|
756 | 762 | }
|
| 763 | + |
| 764 | + fn publish(&self, req: &Request) -> Response { |
| 765 | + if let Some(body) = &req.body { |
| 766 | + // Get the metadata of the package |
| 767 | + let (len, remaining) = body.split_at(4); |
| 768 | + let json_len = u32::from_le_bytes(len.try_into().unwrap()); |
| 769 | + let (json, remaining) = remaining.split_at(json_len as usize); |
| 770 | + let new_crate = serde_json::from_slice::<crates_io::NewCrate>(json).unwrap(); |
| 771 | + // Get the `.crate` file |
| 772 | + let (len, remaining) = remaining.split_at(4); |
| 773 | + let file_len = u32::from_le_bytes(len.try_into().unwrap()); |
| 774 | + let (file, _remaining) = remaining.split_at(file_len as usize); |
| 775 | + |
| 776 | + // Write the `.crate` |
| 777 | + let dst = self |
| 778 | + .dl_path |
| 779 | + .join(&new_crate.name) |
| 780 | + .join(&new_crate.vers) |
| 781 | + .join("download"); |
| 782 | + t!(fs::create_dir_all(dst.parent().unwrap())); |
| 783 | + t!(fs::write(&dst, file)); |
| 784 | + |
| 785 | + let deps = new_crate |
| 786 | + .deps |
| 787 | + .iter() |
| 788 | + .map(|dep| { |
| 789 | + let (name, package) = match &dep.explicit_name_in_toml { |
| 790 | + Some(explicit) => (explicit.to_string(), Some(dep.name.to_string())), |
| 791 | + None => (dep.name.to_string(), None), |
| 792 | + }; |
| 793 | + serde_json::json!({ |
| 794 | + "name": name, |
| 795 | + "req": dep.version_req, |
| 796 | + "features": dep.features, |
| 797 | + "default_features": true, |
| 798 | + "target": dep.target, |
| 799 | + "optional": dep.optional, |
| 800 | + "kind": dep.kind, |
| 801 | + "registry": dep.registry, |
| 802 | + "package": package, |
| 803 | + }) |
| 804 | + }) |
| 805 | + .collect::<Vec<_>>(); |
| 806 | + |
| 807 | + let line = create_index_line( |
| 808 | + serde_json::json!(new_crate.name), |
| 809 | + &new_crate.vers, |
| 810 | + deps, |
| 811 | + &cksum(file), |
| 812 | + new_crate.features, |
| 813 | + false, |
| 814 | + new_crate.links, |
| 815 | + None, |
| 816 | + ); |
| 817 | + |
| 818 | + write_to_index(&self.registry_path, &new_crate.name, line, false); |
| 819 | + |
| 820 | + self.ok(&req) |
| 821 | + } else { |
| 822 | + Response { |
| 823 | + code: 400, |
| 824 | + headers: vec![], |
| 825 | + body: b"The request was missing a body".to_vec(), |
| 826 | + } |
| 827 | + } |
| 828 | + } |
757 | 829 | }
|
758 | 830 |
|
759 | 831 | impl Package {
|
@@ -999,66 +1071,24 @@ impl Package {
|
999 | 1071 | } else {
|
1000 | 1072 | serde_json::json!(self.name)
|
1001 | 1073 | };
|
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); |
| 1074 | + let line = create_index_line( |
| 1075 | + name, |
| 1076 | + &self.vers, |
| 1077 | + deps, |
| 1078 | + &cksum, |
| 1079 | + self.features.clone(), |
| 1080 | + self.yanked, |
| 1081 | + self.links.clone(), |
| 1082 | + self.v, |
| 1083 | + ); |
1023 | 1084 |
|
1024 | 1085 | let registry_path = if self.alternative {
|
1025 | 1086 | alt_registry_path()
|
1026 | 1087 | } else {
|
1027 | 1088 | registry_path()
|
1028 | 1089 | };
|
1029 | 1090 |
|
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 |
| - } |
| 1091 | + write_to_index(®istry_path, &self.name, line, self.local); |
1062 | 1092 |
|
1063 | 1093 | cksum
|
1064 | 1094 | }
|
@@ -1279,21 +1309,3 @@ impl Dependency {
|
1279 | 1309 | self
|
1280 | 1310 | }
|
1281 | 1311 | }
|
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