diff --git a/pkg/docker/build.go b/pkg/docker/build.go index ebfabfa7a4..a332a1890e 100644 --- a/pkg/docker/build.go +++ b/pkg/docker/build.go @@ -1,9 +1,12 @@ package docker import ( + "bufio" "fmt" + "log" "os" "os/exec" + "path" "runtime" "strings" @@ -11,11 +14,47 @@ import ( "github.com/replicate/cog/pkg/util" "github.com/replicate/cog/pkg/util/console" + "github.com/replicate/cog/pkg/util/files" ) +func sanitiseDockerIgnore(dir string) error { + dockerIgnorePath := path.Join(dir, ".dockerignore") + fileExists, err := files.Exists(dockerIgnorePath) + if err != nil { + return err + } + if !fileExists { + return nil + } + + console.Debug("Sanitising .dockerignore.") + file, err := os.Open(dockerIgnorePath) + if err != nil { + log.Fatal(err) + } + + scanner := bufio.NewScanner(file) + newContents := "" + for scanner.Scan() { + line := scanner.Text() + if line == ".cog" { + continue + } + newContents += line + "\n" + } + file.Close() + if err := scanner.Err(); err != nil { + log.Fatal(err) + } + + return os.WriteFile(dockerIgnorePath, []byte(newContents), 0o644) +} + func Build(dir, dockerfile, imageName string, secrets []string, noCache bool, progressOutput string, epoch int64) error { var args []string + sanitiseDockerIgnore(dir) + args = append(args, "buildx", "build", ) diff --git a/test-integration/test_integration/fixtures/dockerignore-cog-project/.dockerignore b/test-integration/test_integration/fixtures/dockerignore-cog-project/.dockerignore new file mode 100644 index 0000000000..370ff3fb26 --- /dev/null +++ b/test-integration/test_integration/fixtures/dockerignore-cog-project/.dockerignore @@ -0,0 +1 @@ +.cog diff --git a/test-integration/test_integration/fixtures/dockerignore-cog-project/cog.yaml b/test-integration/test_integration/fixtures/dockerignore-cog-project/cog.yaml new file mode 100644 index 0000000000..ce622845eb --- /dev/null +++ b/test-integration/test_integration/fixtures/dockerignore-cog-project/cog.yaml @@ -0,0 +1,3 @@ +build: + python_version: "3.8" +predict: "predict.py:Predictor" diff --git a/test-integration/test_integration/fixtures/dockerignore-cog-project/predict.py b/test-integration/test_integration/fixtures/dockerignore-cog-project/predict.py new file mode 100644 index 0000000000..44f6992b01 --- /dev/null +++ b/test-integration/test_integration/fixtures/dockerignore-cog-project/predict.py @@ -0,0 +1,6 @@ +from cog import BasePredictor + + +class Predictor(BasePredictor): + def predict(self, s: str) -> str: + return "hello " + s diff --git a/test-integration/test_integration/test_build.py b/test-integration/test_integration/test_build.py index 1e25d37764..c34726acfc 100644 --- a/test-integration/test_integration/test_build.py +++ b/test-integration/test_integration/test_build.py @@ -315,3 +315,26 @@ def test_precompile(docker_image): capture_output=True, ) assert build_process.returncode == 0 + + +def test_dockerignore_dot_cog(docker_image): + project_dir = Path(__file__).parent / "fixtures/dockerignore-cog-project" + # We rewrite the .dockerignore file so preserve its contents across the test. + dockerignore_path = os.path.join(project_dir, ".dockerignore") + dockerignore_contents = "" + with open(dockerignore_path, encoding="utf-8") as handle: + dockerignore_contents = handle.read() + build_process = subprocess.run( + [ + "cog", + "build", + "-t", + docker_image, + ], + cwd=project_dir, + capture_output=True, + check=False, + ) + with open(dockerignore_path, "w", encoding="utf-8") as handle: + handle.write(dockerignore_contents) + assert build_process.returncode == 0