diff --git a/src/cmd/go.mod b/src/cmd/go.mod index b12d1991b9..362d33445b 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -7,7 +7,7 @@ require ( github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect - golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61 + golang.org/x/mod v0.5.1-0.20210827163434-4029241eb1d5 golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151 diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 1db50ca302..6e8b02d8dc 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -9,8 +9,8 @@ golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjc golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61 h1:gQY3CVezomIImcWCpxp6Mhj+fXCOZ+gD8/88326LVqw= -golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1-0.20210827163434-4029241eb1d5 h1:BJ9Nc92Yf5inqB18HHrMgflMJKHraE07Z29Vjc+Z/Mk= +golang.org/x/mod v0.5.1-0.20210827163434-4029241eb1d5/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/src/cmd/vendor/golang.org/x/mod/module/module.go b/src/cmd/vendor/golang.org/x/mod/module/module.go index ba97ac356e..89bd3ede27 100644 --- a/src/cmd/vendor/golang.org/x/mod/module/module.go +++ b/src/cmd/vendor/golang.org/x/mod/module/module.go @@ -286,12 +286,7 @@ func fileNameOK(r rune) bool { if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' { return true } - for i := 0; i < len(allowed); i++ { - if rune(allowed[i]) == r { - return true - } - } - return false + return strings.ContainsRune(allowed, r) } // It may be OK to add more ASCII punctuation here, but only carefully. // For example Windows disallows < > \, and macOS disallows :, so we must not allow those. diff --git a/src/cmd/vendor/golang.org/x/mod/zip/zip.go b/src/cmd/vendor/golang.org/x/mod/zip/zip.go index 5b401ad4d8..40606d6da5 100644 --- a/src/cmd/vendor/golang.org/x/mod/zip/zip.go +++ b/src/cmd/vendor/golang.org/x/mod/zip/zip.go @@ -53,6 +53,7 @@ import ( "io" "io/ioutil" "os" + "os/exec" "path" "path/filepath" "strings" @@ -192,8 +193,10 @@ func CheckFiles(files []File) (CheckedFiles, error) { } // checkFiles implements CheckFiles and also returns lists of valid files and -// their sizes, corresponding to cf.Valid. These lists are used in Crewate to -// avoid repeated calls to File.Lstat. +// their sizes, corresponding to cf.Valid. It omits files in submodules, files +// in vendored packages, symlinked files, and various other unwanted files. +// +// The lists returned are used in Create to avoid repeated calls to File.Lstat. func checkFiles(files []File) (cf CheckedFiles, validFiles []File, validSizes []int64) { errPaths := make(map[string]struct{}) addError := func(path string, omitted bool, err error) { @@ -254,10 +257,12 @@ func checkFiles(files []File) (cf CheckedFiles, validFiles []File, validSizes [] continue } if isVendoredPackage(p) { + // Skip files in vendored packages. addError(p, true, errVendored) continue } if inSubmodule(p) { + // Skip submodule files. addError(p, true, errSubmoduleFile) continue } @@ -551,7 +556,7 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) { if zerr, ok := err.(*zipError); ok { zerr.path = dir } else if err != nil { - err = &zipError{verb: "create zip", path: dir, err: err} + err = &zipError{verb: "create zip from directory", path: dir, err: err} } }() @@ -563,6 +568,116 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) { return Create(w, m, files) } +// CreateFromVCS creates a module zip file for module m from the contents of a +// VCS repository stored locally. The zip content is written to w. +// +// repo must be an absolute path to the base of the repository, such as +// "/Users/some-user/my-repo". +// +// revision is the revision of the repository to create the zip from. Examples +// include HEAD or SHA sums for git repositories. +// +// subdir must be the relative path from the base of the repository, such as +// "sub/dir". To create a zip from the base of the repository, pass an empty +// string. +func CreateFromVCS(w io.Writer, m module.Version, repo, revision, subdir string) (err error) { + defer func() { + if zerr, ok := err.(*zipError); ok { + zerr.path = repo + } else if err != nil { + err = &zipError{verb: "create zip from version control system", path: repo, err: err} + } + }() + + var filesToCreate []File + + switch { + case isGitRepo(repo): + files, err := filesInGitRepo(repo, revision, subdir) + if err != nil { + return err + } + + filesToCreate = files + default: + return fmt.Errorf("%q does not use a recognised version control system", repo) + } + + return Create(w, m, filesToCreate) +} + +// filterGitIgnored filters out any files that are git ignored in the directory. +func filesInGitRepo(dir, rev, subdir string) ([]File, error) { + stderr := bytes.Buffer{} + stdout := bytes.Buffer{} + + // Incredibly, git produces different archives depending on whether + // it is running on a Windows system or not, in an attempt to normalize + // text file line endings. Setting -c core.autocrlf=input means only + // translate files on the way into the repo, not on the way out (archive). + // The -c core.eol=lf should be unnecessary but set it anyway. + // + // Note: We use git archive to understand which files are actually included, + // ignoring things like .gitignore'd files. We could also use other + // techniques like git ls-files, but this approach most closely matches what + // the Go command does, which is beneficial. + // + // Note: some of this code copied from https://go.googlesource.com/go/+/refs/tags/go1.16.5/src/cmd/go/internal/modfetch/codehost/git.go#826. + cmd := exec.Command("git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", rev) + if subdir != "" { + cmd.Args = append(cmd.Args, subdir) + } + cmd.Dir = dir + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("error running `git archive`: %w, %s", err, stderr.String()) + } + + rawReader := bytes.NewReader(stdout.Bytes()) + zipReader, err := zip.NewReader(rawReader, int64(stdout.Len())) + if err != nil { + return nil, err + } + + var fs []File + for _, zf := range zipReader.File { + if !strings.HasPrefix(zf.Name, subdir) || strings.HasSuffix(zf.Name, "/") { + continue + } + + n := strings.TrimPrefix(zf.Name, subdir) + if n == "" { + continue + } + n = strings.TrimPrefix(n, string(filepath.Separator)) + + fs = append(fs, zipFile{ + name: n, + f: zf, + }) + } + + return fs, nil +} + +// isGitRepo reports whether the given directory is a git repo. +func isGitRepo(dir string) bool { + stdout := &bytes.Buffer{} + cmd := exec.Command("git", "rev-parse", "--git-dir") + cmd.Dir = dir + cmd.Stdout = stdout + if err := cmd.Run(); err != nil { + return false + } + gitDir := strings.TrimSpace(string(stdout.Bytes())) + if !filepath.IsAbs(gitDir) { + gitDir = filepath.Join(dir, gitDir) + } + wantDir := filepath.Join(dir, ".git") + return wantDir == gitDir +} + type dirFile struct { filePath, slashPath string info os.FileInfo @@ -572,6 +687,15 @@ func (f dirFile) Path() string { return f.slashPath } func (f dirFile) Lstat() (os.FileInfo, error) { return f.info, nil } func (f dirFile) Open() (io.ReadCloser, error) { return os.Open(f.filePath) } +type zipFile struct { + name string + f *zip.File +} + +func (f zipFile) Path() string { return f.name } +func (f zipFile) Lstat() (os.FileInfo, error) { return f.f.FileInfo(), nil } +func (f zipFile) Open() (io.ReadCloser, error) { return f.f.Open() } + // isVendoredPackage attempts to report whether the given filename is contained // in a package whose import path contains (but does not end with) the component // "vendor". diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index eed06a9f50..4d48b87a87 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm ## explicit; go 1.17 golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 -# golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61 +# golang.org/x/mod v0.5.1-0.20210827163434-4029241eb1d5 ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile