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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use clap::Parser;
use std::{net::IpAddr, path::PathBuf};
mod crates;
mod crates_index;
mod download;
mod mirror;
mod progress_bar;
mod rustup;
mod serve;
mod verify;
/// Mirror rustup and crates.io repositories, for offline Rust and cargo usage.
#[derive(Debug, Parser)]
enum Panamax {
/// Create a new mirror directory.
Init {
#[arg(value_parser)]
path: PathBuf,
/// set [rustup] sync = false
#[arg(long)]
ignore_rustup: bool,
},
/// Update an existing mirror directory.
Sync {
/// Mirror directory.
#[arg(value_parser)]
path: PathBuf,
/// cargo-vendor directory.
#[arg(value_parser)]
vendor_path: Option<PathBuf>,
},
/// Rewrite the config.json within crates.io-index.
///
/// This can be used if rewriting config.json is
/// required to be an extra step after syncing.
#[command(name = "rewrite")]
Rewrite {
/// Mirror directory.
#[arg(value_parser)]
path: PathBuf,
/// Base URL used for rewriting. Overrides value in mirror.toml.
#[arg(short, long)]
base_url: Option<String>,
},
/// Serve a mirror directory.
#[command(name = "serve")]
Serve {
/// Mirror directory.
#[arg(value_parser)]
path: PathBuf,
/// IP address to listen on. Defaults to listening on everything.
#[arg(short, long)]
listen: Option<IpAddr>,
/// Port to listen on.
/// Defaults to 8080, or 8443 if TLS certificate provided.
#[arg(short, long)]
port: Option<u16>,
/// Path to a TLS certificate file. This enables TLS.
/// Also requires key_path.
#[arg(long)]
cert_path: Option<PathBuf>,
/// Path to a TLS key file.
/// Also requires cert_path.
#[arg(long)]
key_path: Option<PathBuf>,
},
/// List platforms currently available.
///
/// This is useful for finding what can be used for
/// limiting platforms in mirror.toml.
#[command(name = "list-platforms")]
ListPlatforms {
#[arg(long, default_value = "https://static.rust-lang.org")]
source: String,
#[arg(long, default_value = "nightly")]
channel: String,
},
/// Verify coherence between local mirror and local crates.io-index.
/// If any missing crate is found, ask to user before downloading by default.
#[command(name = "verify", alias = "check")]
Verify {
/// Mirror directory.
#[arg(value_parser)]
path: PathBuf,
/// Dry run, i.e. no change will be made to the mirror.
/// Missing crates are just printed to stdout, not downloaded.
#[arg(long)]
dry_run: bool,
/// Assume yes from user.
/// Ignored if dry-run is supplied.
#[arg(long)]
assume_yes: bool,
},
}
#[tokio::main]
async fn main() {
env_logger::init();
let opt = Panamax::parse();
match opt {
Panamax::Init {
path,
ignore_rustup,
} => mirror::init(&path, ignore_rustup),
Panamax::Sync { path, vendor_path } => mirror::sync(&path, vendor_path).await,
Panamax::Rewrite { path, base_url } => mirror::rewrite(&path, base_url),
Panamax::Serve {
path,
listen,
port,
cert_path,
key_path,
} => mirror::serve(path, listen, port, cert_path, key_path).await,
Panamax::ListPlatforms { source, channel } => mirror::list_platforms(source, channel).await,
Panamax::Verify {
path,
dry_run,
assume_yes,
} => mirror::verify(path, dry_run, assume_yes).await,
}
.unwrap_or_else(|e| eprintln!("Panamax command failed! {e}"));
}