Skip to content

Commit 3e4b3c2

Browse files
committed
refactor: breakout config into its own file for readability
1 parent 88c9cf4 commit 3e4b3c2

File tree

6 files changed

+146
-146
lines changed

6 files changed

+146
-146
lines changed

src/config.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use anyhow::{anyhow, Result};
2+
use clap::{App, Arg};
3+
4+
use crate::runtime;
5+
6+
pub const VERSION: &str = "0.4.0";
7+
8+
#[derive(Debug)]
9+
pub struct Config {
10+
// List of images
11+
pub image: String,
12+
// Where the download files should be saved on the filesystem. Default "."
13+
pub download_path: String,
14+
// Where the content (files) are in the container filesystem. Default "/"
15+
pub content_path: String,
16+
// Option to write to stdout instead of the local filesystem.
17+
pub write_to_stdout: bool,
18+
// What level of logs to output
19+
pub log_level: String,
20+
// Username for singing into a private registry
21+
pub username: String,
22+
// Password for signing into a private registry
23+
pub password: String,
24+
// Force a pull even if the image is present locally
25+
pub force_pull: bool,
26+
// Specify a custom socket to utilize for the runtime
27+
pub socket: String,
28+
}
29+
30+
pub fn get_args() -> Result<Config> {
31+
let matches = App::new("dcp")
32+
.version(VERSION)
33+
.author("exdx")
34+
.about("docker cp made easy")
35+
.arg(
36+
Arg::with_name("image")
37+
.value_name("IMAGE")
38+
.help("Container image to extract content from")
39+
.required(true),
40+
)
41+
.arg(
42+
Arg::with_name("download-path")
43+
.value_name("DOWNLOAD-PATH")
44+
.help("Where the image contents should be saved on the filesystem")
45+
.default_value(".")
46+
.short("d")
47+
.long("download-path"),
48+
)
49+
.arg(
50+
Arg::with_name("content-path")
51+
.value_name("CONTENT-PATH")
52+
.help("Where in the container filesystem the content to extract is")
53+
.short("c")
54+
.default_value("/")
55+
.long("content-path"),
56+
)
57+
.arg(
58+
Arg::with_name("write-to-stdout")
59+
.value_name("WRITE-TO-STDOUT")
60+
.help("Whether to write to stdout instead of the filesystem")
61+
.takes_value(false)
62+
.short("w")
63+
.long("write-to-stdout"),
64+
)
65+
.arg(
66+
Arg::with_name("username")
67+
.value_name("USERNAME")
68+
.help("Username used for singing into a private registry.")
69+
.short("u")
70+
.long("username")
71+
.default_value(""),
72+
73+
)
74+
.arg(
75+
Arg::with_name("password")
76+
.value_name("PASSWORD")
77+
.help("Password used for signing into a private registry. * WARNING *: Writing credentials to your terminal is risky. Be sure you are okay with them showing up in your history")
78+
.short("p")
79+
.long("password")
80+
.default_value(""),
81+
82+
)
83+
.arg(
84+
Arg::with_name("log-level")
85+
.value_name("LOG-LEVEL")
86+
.help("What level of logs to output. Accepts: [info, debug, trace, error, warn]")
87+
.short("l")
88+
.long("log-level")
89+
.default_value("debug"),
90+
)
91+
.arg(
92+
Arg::with_name("force-pull")
93+
.value_name("FORCE-PULL")
94+
.help("Force a pull even if the image is present locally")
95+
.takes_value(false)
96+
.long("force-pull")
97+
.short("f")
98+
)
99+
.arg(
100+
Arg::with_name("socket")
101+
.value_name("SOCKET")
102+
.help("Specify a custom socket to utilize for the runtime")
103+
.long("socket")
104+
.short("s")
105+
.default_value(runtime::DEFAULT_SOCKET)
106+
)
107+
.get_matches();
108+
109+
let image = matches.value_of("image").unwrap().to_string();
110+
let download_path = matches.value_of("download-path").unwrap().to_string();
111+
let content_path = matches.value_of("content-path").unwrap().to_string();
112+
let write_to_stdout = matches.is_present("write-to-stdout");
113+
let force_pull = matches.is_present("force-pull");
114+
let log_level = matches.value_of("log-level").unwrap().to_string();
115+
let socket = matches.value_of("socket").unwrap().to_string();
116+
// TODO (tyslaton): Need to come up with a way for this to be extracted from the docker config to be more secure locally.
117+
let username = matches.value_of("username").unwrap().to_string();
118+
let password = matches.value_of("password").unwrap().to_string();
119+
120+
if write_to_stdout {
121+
return Err(anyhow!("❌ writing to stdout is not currently implemented"));
122+
};
123+
124+
Ok(Config {
125+
image,
126+
download_path,
127+
content_path,
128+
write_to_stdout,
129+
log_level,
130+
username,
131+
password,
132+
force_pull,
133+
socket,
134+
})
135+
}

src/lib.rs

Lines changed: 7 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,32 @@
11
use anyhow::{anyhow, Result};
2-
use clap::{App, Arg};
32

3+
pub mod config;
44
mod runtime;
55

66
extern crate pretty_env_logger;
77
#[macro_use]
88
extern crate log;
99

10-
pub const VERSION: &str = "0.4.0";
11-
12-
#[derive(Debug)]
13-
pub struct Config {
14-
// List of images
15-
image: String,
16-
// Where the download files should be saved on the filesystem. Default "."
17-
download_path: String,
18-
// Where the content (files) are in the container filesystem. Default "/"
19-
content_path: String,
20-
// Option to write to stdout instead of the local filesystem.
21-
write_to_stdout: bool,
22-
// What level of logs to output
23-
log_level: String,
24-
// Username for singing into a private registry
25-
username: String,
26-
// Password for signing into a private registry
27-
password: String,
28-
// Force a pull even if the image is present locally
29-
force_pull: bool,
30-
// Specify a custom socket to utilize for the runtime
31-
socket: String,
32-
}
33-
34-
pub fn get_args() -> Result<Config> {
35-
let matches = App::new("dcp")
36-
.version(VERSION)
37-
.author("exdx")
38-
.about("docker cp made easy")
39-
.arg(
40-
Arg::with_name("image")
41-
.value_name("IMAGE")
42-
.help("Container image to extract content from")
43-
.required(true),
44-
)
45-
.arg(
46-
Arg::with_name("download-path")
47-
.value_name("DOWNLOAD-PATH")
48-
.help("Where the image contents should be saved on the filesystem")
49-
.default_value(".")
50-
.short("d")
51-
.long("download-path"),
52-
)
53-
.arg(
54-
Arg::with_name("content-path")
55-
.value_name("CONTENT-PATH")
56-
.help("Where in the container filesystem the content to extract is")
57-
.short("c")
58-
.default_value("/")
59-
.long("content-path"),
60-
)
61-
.arg(
62-
Arg::with_name("write-to-stdout")
63-
.value_name("WRITE-TO-STDOUT")
64-
.help("Whether to write to stdout instead of the filesystem")
65-
.takes_value(false)
66-
.short("w")
67-
.long("write-to-stdout"),
68-
)
69-
.arg(
70-
Arg::with_name("username")
71-
.value_name("USERNAME")
72-
.help("Username used for singing into a private registry.")
73-
.short("u")
74-
.long("username")
75-
.default_value(""),
76-
77-
)
78-
.arg(
79-
Arg::with_name("password")
80-
.value_name("PASSWORD")
81-
.help("Password used for signing into a private registry. * WARNING *: Writing credentials to your terminal is risky. Be sure you are okay with them showing up in your history")
82-
.short("p")
83-
.long("password")
84-
.default_value(""),
85-
86-
)
87-
.arg(
88-
Arg::with_name("log-level")
89-
.value_name("LOG-LEVEL")
90-
.help("What level of logs to output. Accepts: [info, debug, trace, error, warn]")
91-
.short("l")
92-
.long("log-level")
93-
.default_value("debug"),
94-
)
95-
.arg(
96-
Arg::with_name("force-pull")
97-
.value_name("FORCE-PULL")
98-
.help("Force a pull even if the image is present locally")
99-
.takes_value(false)
100-
.long("force-pull")
101-
.short("f")
102-
)
103-
.arg(
104-
Arg::with_name("socket")
105-
.value_name("SOCKET")
106-
.help("Specify a custom socket to utilize for the runtime")
107-
.long("socket")
108-
.short("s")
109-
.default_value(runtime::DEFAULT_SOCKET)
110-
)
111-
.get_matches();
112-
113-
let image = matches.value_of("image").unwrap().to_string();
114-
let download_path = matches.value_of("download-path").unwrap().to_string();
115-
let content_path = matches.value_of("content-path").unwrap().to_string();
116-
let write_to_stdout = matches.is_present("write-to-stdout");
117-
let force_pull = matches.is_present("force-pull");
118-
let log_level = matches.value_of("log-level").unwrap().to_string();
119-
let socket = matches.value_of("socket").unwrap().to_string();
120-
// TODO (tyslaton): Need to come up with a way for this to be extracted from the docker config to be more secure locally.
121-
let username = matches.value_of("username").unwrap().to_string();
122-
let password = matches.value_of("password").unwrap().to_string();
123-
124-
if write_to_stdout {
125-
return Err(anyhow!(
126-
"❌ error: writing to stdout is not currently implemented"
127-
));
128-
};
129-
130-
Ok(Config {
131-
image,
132-
download_path,
133-
content_path,
134-
write_to_stdout,
135-
log_level,
136-
username,
137-
password,
138-
force_pull,
139-
socket,
140-
})
141-
}
142-
14310
/// Run runs a sequence of events with the provided image
14411
/// Run supports copying container filesystems running on both the docker and podman runtimes
14512
/// 1. Pull down the image
14613
/// 2. Create a container, receiving the container id as a response
14714
/// 3. Copy the container content to the specified directory
14815
/// 4. Delete the container
149-
pub async fn run(config: Config) -> Result<()> {
16+
pub async fn run(cfg: config::Config) -> Result<()> {
15017
pretty_env_logger::formatted_builder()
151-
.parse_filters(&config.log_level.clone())
18+
.parse_filters(&cfg.log_level.clone())
15219
.init();
15320

15421
// Build the runtime
155-
let rt = if let Some(runtime) = runtime::set(&config.socket).await {
22+
let rt = if let Some(runtime) = runtime::set(&cfg.socket).await {
15623
runtime
15724
} else {
15825
return Err(anyhow!("❌ no valid container runtime"));
15926
};
16027

16128
// Build the image struct
162-
let container = match runtime::container::new(config.image, rt) {
29+
let container = match runtime::container::new(cfg.image, rt) {
16330
Ok(i) => i,
16431
Err(e) => {
16532
return Err(anyhow!("❌ error building the image: {}", e));
@@ -168,7 +35,7 @@ pub async fn run(config: Config) -> Result<()> {
16835

16936
// Pull the image
17037
match container
171-
.pull(config.username, config.password, config.force_pull)
38+
.pull(cfg.username, cfg.password, cfg.force_pull)
17239
.await
17340
{
17441
Ok(_) => {}
@@ -179,11 +46,7 @@ pub async fn run(config: Config) -> Result<()> {
17946

18047
// Copy files from the image
18148
match container
182-
.copy_files(
183-
config.content_path,
184-
config.download_path,
185-
config.write_to_stdout,
186-
)
49+
.copy_files(cfg.content_path, cfg.download_path, cfg.write_to_stdout)
18750
.await
18851
{
18952
Ok(_) => {}

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ extern crate log;
66

77
#[tokio::main]
88
async fn main() -> Result<()> {
9-
match dcp::get_args() {
9+
match dcp::config::get_args() {
1010
Err(e) => {
1111
error!("❌ error reading arguments {}", e);
1212
std::process::exit(1)

src/runtime/docker.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ impl Container for Image {
146146
Ok(())
147147
}
148148

149+
// present_locally determines if this container's image is pulled locally
149150
async fn present_locally(&self) -> bool {
150151
debug!("📦 Searching for image {} locally", self.image);
151152
match self.runtime.images().list(&Default::default()).await {

src/runtime/podman.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ impl Container for Image {
138138
Ok(())
139139
}
140140

141+
// present_locally determines if this container's image is pulled locally
141142
async fn present_locally(&self) -> bool {
142143
debug!("📦 Searching for image {} locally", self.image);
143144
match self.runtime.images().list(&Default::default()).await {

tests/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use assert_cmd::Command;
2-
use dcp::VERSION;
2+
use dcp::config::VERSION;
33
use predicates::prelude::*;
44
use rand::{thread_rng, Rng};
55
use std::error::Error;

0 commit comments

Comments
 (0)