'Cannot COPY from previous stage in DockerFIle
This looks like a common issue so I checked a few SO posts but none of them solved my problem.
Here is my Dockerfile:
# MkDocs container
FROM python:3-alpine AS build-env
RUN apk add bash
RUN pip install --upgrade pip
RUN pip install pymdown-extensions \
&& pip install mkdocs \
&& pip install mkdocs-material \
&& pip install mkdocs-rtd-dropdown \
&& pip install mkdocs-git-revision-date-plugin \
&& pip install mkdocs-git-revision-date-localized-plugin \
&& pip install mkdocs-redirects
# executed at ~/Developer/MkDocs
RUN mkdir -p /home/mkdocs/
WORKDIR /home/mkdocs/
COPY . .
RUN mkdocs build -s
WORKDIR /
# Nginx container
FROM nginx:1.21.6-alpine
RUN apk add bash
EXPOSE 80
RUN cat /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/nginx.conf
WORKDIR /
RUN mkdir -p /home/mkdocs
COPY --from=build-env /home/mkdocs/site/ /home/mkdocs/
RUN mv /home/mkdocs/* /usr/share/nginx/html/
RUN chown nginx:nginx /usr/share/nginx/html/*
USER nginx:nginx
And here is the command to run docker:
docker run -it --name mkdocs -p 8789:80 nginx
Running localhost:8789 only shows the default nginx homepage, not the built one of MkDocs. I also run docker exec -it --user root <PID> bash to check the directory /usr/share/nginx/html/ but the copied files are not there.
My other checks:
First, I'm 100% sure that the files built in the first stage works and exists
Second, this is what completely frustrated me out. If I run the docker using
docker run -it --entrypoint=/bin/bash mkdocs:v1, I can actually see the built MkDocs files:
bash-5.1$ ls /usr/share/nginx/html
404.html 50x.html assets index.html search sitemap.xml sitemap.xml.gz
bash-5.1$
Solution 1:[1]
This isn't a Rust-specific problem, although the vocabulary may be a little different. The ideal way to solve a problem like this, not just with traits in Rust but in any language, is to add the desired behavior (foo_method in your example) to the abstract interface (Trait):
trait Trait {
fn trait_method(&self);
fn foo_method(&self) {} // does nothing by default
}
struct Foo;
impl Trait for Foo {
fn trait_method(&self) {
println!("In trait_method of Foo");
}
fn foo_method(&self) {
// override default behavior
println!("In foo_method");
}
}
struct Bar;
impl Trait for Bar {
fn trait_method(&self) {
println!("In trait_method of Bar");
}
}
fn main() {
let vec: Vec<Box<dyn Trait>> = vec![Box::new(Foo), Box::new(Bar)];
for e in &vec {
e.trait_method();
e.foo_method();
}
}
In this example, I have put a default implementation of foo_method in Trait which does nothing, so that you don't have to define it in every impl but only the one(s) where it applies. You should really attempt to make the above work before you resort to downcasting to a concrete type, which has serious drawbacks that all but erase the advantages of having trait objects in the first place.
That said, there are cases where downcasting may be necessary, and Rust does support it -- although the interface is a little clunky. You can downcast &Trait to &Foo by adding an intermediate upcast to &Any:
use std::any::Any;
trait Trait {
fn as_any(&self) -> &dyn Any;
}
struct Foo;
impl Trait for Foo {
fn as_any(&self) -> &dyn Any {
self
}
}
fn downcast<T: Trait + 'static>(this: &dyn Trait) -> Option<&T> {
this.as_any().downcast_ref()
}
as_any has to be a method in Trait because it needs access to the concrete type. Now you can attempt to call Foo methods on a Trait trait object like this (complete playground example):
if let Some(r) = downcast::<Foo>(&**e) {
r.foo_method();
}
To make this work, you have to specify what type you expect (::<Foo>) and use if let to handle what happens when the referenced object is not an instance of Foo. You can't downcast a trait object to a concrete type unless you know exactly what concrete type it is.
If you ever need to know the concrete type, trait objects are almost useless anyway! You probably should use an enum instead, so that you will get compile-time errors if you omit to handle a variant somewhere. Furthermore, you can't use Any with non-'static structs, so if any Foo might need to contain a reference, this design is a dead end. The best solution, if you can do it, is to add foo_method to the trait itself.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Shepmaster |
