Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit abdd1db

Browse files
authored
Don't try to update devcontainers (#946)
1 parent 2585156 commit abdd1db

File tree

1 file changed

+109
-104
lines changed

1 file changed

+109
-104
lines changed

src/steps/containers.rs

Lines changed: 109 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,109 @@
1-
use anyhow::Result;
2-
3-
use crate::error::{self, TopgradeError};
4-
use crate::executor::CommandExt;
5-
use crate::terminal::print_separator;
6-
use crate::{execution_context::ExecutionContext, utils::require};
7-
use log::{debug, error, warn};
8-
use std::path::Path;
9-
use std::process::Command;
10-
11-
// A string found in the output of docker for containers that weren't found in
12-
// the docker registry. We use this to gracefully handle and skip containers
13-
// that cannot be pulled, likely because they don't exist in the registry in
14-
// the first place. This happens e.g. when the user tags an image locally
15-
// themselves or when using docker-compose.
16-
const NONEXISTENT_REPO: &str = "repository does not exist";
17-
18-
/// Returns a Vector of all containers, with Strings in the format
19-
/// "REGISTRY/[PATH/]CONTAINER_NAME:TAG"
20-
fn list_containers(crt: &Path) -> Result<Vec<String>> {
21-
debug!(
22-
"Querying '{} image ls --format \"{{{{.Repository}}}}:{{{{.Tag}}}}\"' for containers",
23-
crt.display()
24-
);
25-
let output = Command::new(crt)
26-
.args(&["image", "ls", "--format", "{{.Repository}}:{{.Tag}}"])
27-
.output()?;
28-
let output_str = String::from_utf8(output.stdout)?;
29-
30-
let mut retval = vec![];
31-
for line in output_str.lines() {
32-
if line.starts_with("localhost") {
33-
// Don't know how to update self-built containers
34-
debug!("Skipping self-built container '{}'", line);
35-
continue;
36-
}
37-
38-
if line.contains("<none>") {
39-
// Bogus/dangling container or intermediate layer
40-
debug!("Skipping bogus container '{}'", line);
41-
continue;
42-
}
43-
44-
debug!("Using container '{}'", line);
45-
retval.push(String::from(line));
46-
}
47-
48-
Ok(retval)
49-
}
50-
51-
pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
52-
// Prefer podman, fall back to docker if not present
53-
let crt = require("podman").or_else(|_| require("docker"))?;
54-
debug!("Using container runtime '{}'", crt.display());
55-
56-
print_separator("Containers");
57-
let mut success = true;
58-
let containers = list_containers(&crt)?;
59-
debug!("Containers to inspect: {:?}", containers);
60-
61-
for container in containers.iter() {
62-
debug!("Pulling container '{}'", container);
63-
let args = vec!["pull", &container[..]];
64-
let mut exec = ctx.run_type().execute(&crt);
65-
66-
if let Err(e) = exec.args(&args).check_run() {
67-
error!("Pulling container '{}' failed: {}", container, e);
68-
69-
// Find out if this is 'skippable'
70-
// This is necessary e.g. for docker, because unlike podman docker doesn't tell from
71-
// which repository a container originates (such as `docker.io`). This has the
72-
// practical consequence that all containers, whether self-built, created by
73-
// docker-compose or pulled from the docker hub, look exactly the same to us. We can
74-
// only find out what went wrong by manually parsing the output of the command...
75-
if match exec.check_output() {
76-
Ok(s) => s.contains(NONEXISTENT_REPO),
77-
Err(e) => match e.downcast_ref::<TopgradeError>() {
78-
Some(TopgradeError::ProcessFailedWithOutput(_, stderr)) => stderr.contains(NONEXISTENT_REPO),
79-
_ => false,
80-
},
81-
} {
82-
warn!("Skipping unknown container '{}'", container);
83-
continue;
84-
}
85-
86-
success = false;
87-
}
88-
}
89-
90-
if ctx.config().cleanup() {
91-
// Remove dangling images
92-
debug!("Removing dangling images");
93-
if let Err(e) = ctx.run_type().execute(&crt).args(&["image", "prune", "-f"]).check_run() {
94-
error!("Removing dangling images failed: {}", e);
95-
success = false;
96-
}
97-
}
98-
99-
if success {
100-
Ok(())
101-
} else {
102-
Err(anyhow::anyhow!(error::StepFailed))
103-
}
104-
}
1+
use anyhow::Result;
2+
3+
use crate::error::{self, TopgradeError};
4+
use crate::executor::CommandExt;
5+
use crate::terminal::print_separator;
6+
use crate::{execution_context::ExecutionContext, utils::require};
7+
use log::{debug, error, warn};
8+
use std::path::Path;
9+
use std::process::Command;
10+
11+
// A string found in the output of docker for containers that weren't found in
12+
// the docker registry. We use this to gracefully handle and skip containers
13+
// that cannot be pulled, likely because they don't exist in the registry in
14+
// the first place. This happens e.g. when the user tags an image locally
15+
// themselves or when using docker-compose.
16+
const NONEXISTENT_REPO: &str = "repository does not exist";
17+
18+
/// Returns a Vector of all containers, with Strings in the format
19+
/// "REGISTRY/[PATH/]CONTAINER_NAME:TAG"
20+
fn list_containers(crt: &Path) -> Result<Vec<String>> {
21+
debug!(
22+
"Querying '{} image ls --format \"{{{{.Repository}}}}:{{{{.Tag}}}}\"' for containers",
23+
crt.display()
24+
);
25+
let output = Command::new(crt)
26+
.args(&["image", "ls", "--format", "{{.Repository}}:{{.Tag}}"])
27+
.output()?;
28+
let output_str = String::from_utf8(output.stdout)?;
29+
30+
let mut retval = vec![];
31+
for line in output_str.lines() {
32+
if line.starts_with("localhost") {
33+
// Don't know how to update self-built containers
34+
debug!("Skipping self-built container '{}'", line);
35+
continue;
36+
}
37+
38+
if line.contains("<none>") {
39+
// Bogus/dangling container or intermediate layer
40+
debug!("Skipping bogus container '{}'", line);
41+
continue;
42+
}
43+
44+
if line.starts_with("vsc-") {
45+
debug!("Skipping visual studio code dev container '{}'", line);
46+
continue;
47+
}
48+
49+
debug!("Using container '{}'", line);
50+
retval.push(String::from(line));
51+
}
52+
53+
Ok(retval)
54+
}
55+
56+
pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
57+
// Prefer podman, fall back to docker if not present
58+
let crt = require("podman").or_else(|_| require("docker"))?;
59+
debug!("Using container runtime '{}'", crt.display());
60+
61+
print_separator("Containers");
62+
let mut success = true;
63+
let containers = list_containers(&crt)?;
64+
debug!("Containers to inspect: {:?}", containers);
65+
66+
for container in containers.iter() {
67+
debug!("Pulling container '{}'", container);
68+
let args = vec!["pull", &container[..]];
69+
let mut exec = ctx.run_type().execute(&crt);
70+
71+
if let Err(e) = exec.args(&args).check_run() {
72+
error!("Pulling container '{}' failed: {}", container, e);
73+
74+
// Find out if this is 'skippable'
75+
// This is necessary e.g. for docker, because unlike podman docker doesn't tell from
76+
// which repository a container originates (such as `docker.io`). This has the
77+
// practical consequence that all containers, whether self-built, created by
78+
// docker-compose or pulled from the docker hub, look exactly the same to us. We can
79+
// only find out what went wrong by manually parsing the output of the command...
80+
if match exec.check_output() {
81+
Ok(s) => s.contains(NONEXISTENT_REPO),
82+
Err(e) => match e.downcast_ref::<TopgradeError>() {
83+
Some(TopgradeError::ProcessFailedWithOutput(_, stderr)) => stderr.contains(NONEXISTENT_REPO),
84+
_ => false,
85+
},
86+
} {
87+
warn!("Skipping unknown container '{}'", container);
88+
continue;
89+
}
90+
91+
success = false;
92+
}
93+
}
94+
95+
if ctx.config().cleanup() {
96+
// Remove dangling images
97+
debug!("Removing dangling images");
98+
if let Err(e) = ctx.run_type().execute(&crt).args(&["image", "prune", "-f"]).check_run() {
99+
error!("Removing dangling images failed: {}", e);
100+
success = false;
101+
}
102+
}
103+
104+
if success {
105+
Ok(())
106+
} else {
107+
Err(anyhow::anyhow!(error::StepFailed))
108+
}
109+
}

0 commit comments

Comments
 (0)