Use the HTTP Last-Modified http header as the mtime value for ADD cmd when present
Closes #8331 Signed-off-by: Doug Davis <dug@us.ibm.com>
This commit is contained in:
parent
6fcc9141d7
commit
2e482c86bc
3 changed files with 81 additions and 3 deletions
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -254,8 +255,21 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri
|
|||
fmt.Fprintf(b.OutStream, "\n")
|
||||
tmpFile.Close()
|
||||
|
||||
// Remove the mtime of the newly created tmp file
|
||||
if err := system.UtimesNano(tmpFileName, make([]syscall.Timespec, 2)); err != nil {
|
||||
// Set the mtime to the Last-Modified header value if present
|
||||
// Otherwise just remove atime and mtime
|
||||
times := make([]syscall.Timespec, 2)
|
||||
|
||||
lastMod := resp.Header.Get("Last-Modified")
|
||||
if lastMod != "" {
|
||||
mTime, err := http.ParseTime(lastMod)
|
||||
// If we can't parse it then just let it default to 'zero'
|
||||
// otherwise use the parsed time value
|
||||
if err == nil {
|
||||
times[1] = syscall.NsecToTimespec(mTime.UnixNano())
|
||||
}
|
||||
}
|
||||
|
||||
if err := system.UtimesNano(tmpFileName, times); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -376,7 +376,11 @@ destination container.
|
|||
All new files and directories are created with a UID and GID of 0.
|
||||
|
||||
In the case where `<src>` is a remote file URL, the destination will
|
||||
have permissions of 600.
|
||||
have permissions of 600. If the remote file being retrieved has an HTTP
|
||||
`Last-Modified` header, the timestamp from that header will be used
|
||||
to set the `mtime` on the destination file. Then, like any other file
|
||||
processed during an `ADD`, `mtime` will be included in the determination
|
||||
of whether or not the file has changed and the cache should be updated.
|
||||
|
||||
> **Note**:
|
||||
> If you build by passing a `Dockerfile` through STDIN (`docker
|
||||
|
|
|
@ -7,9 +7,11 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -2214,6 +2216,64 @@ func TestBuildADDRemoteFileWithoutCache(t *testing.T) {
|
|||
logDone("build - add remote file without cache")
|
||||
}
|
||||
|
||||
func TestBuildADDRemoteFileMTime(t *testing.T) {
|
||||
name := "testbuildaddremotefilemtime"
|
||||
defer deleteImages(name)
|
||||
|
||||
server, err := fakeStorage(map[string]string{"baz": "hello"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
ctx, err := fakeContext(fmt.Sprintf(`FROM scratch
|
||||
MAINTAINER dockerio
|
||||
ADD %s/baz /usr/lib/baz/quux`, server.URL), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ctx.Close()
|
||||
|
||||
id1, err := buildImageFromContext(name, ctx, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id2, err := buildImageFromContext(name, ctx, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if id1 != id2 {
|
||||
t.Fatal("The cache should have been used but wasn't - #1")
|
||||
}
|
||||
|
||||
// Now set baz's times to anything else and redo the build
|
||||
// This time the cache should not be used
|
||||
bazPath := path.Join(server.FakeContext.Dir, "baz")
|
||||
err = syscall.UtimesNano(bazPath, make([]syscall.Timespec, 2))
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting mtime on %q: %v", bazPath, err)
|
||||
}
|
||||
|
||||
id3, err := buildImageFromContext(name, ctx, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if id1 == id3 {
|
||||
t.Fatal("The cache should not have been used but was")
|
||||
}
|
||||
|
||||
// And for good measure do it again and make sure cache is used this time
|
||||
id4, err := buildImageFromContext(name, ctx, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if id3 != id4 {
|
||||
t.Fatal("The cache should have been used but wasn't - #2")
|
||||
}
|
||||
logDone("build - add remote file testing mtime")
|
||||
}
|
||||
|
||||
func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) {
|
||||
name := "testbuildaddlocalandremotefilewithcache"
|
||||
defer deleteImages(name)
|
||||
|
|
Loading…
Reference in a new issue