github.com/april1989/origin-go-tools@v0.0.32/internal/proxydir/proxydir.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package proxydir provides functions for writing module data to a directory 6 // in proxy format, so that it can be used as a module proxy by setting 7 // GOPROXY="file://<dir>". 8 package proxydir 9 10 import ( 11 "archive/zip" 12 "fmt" 13 "io" 14 "io/ioutil" 15 "os" 16 "path/filepath" 17 "strings" 18 19 "github.com/april1989/origin-go-tools/internal/testenv" 20 ) 21 22 // WriteModuleVersion creates a directory in the proxy dir for a module. 23 func WriteModuleVersion(rootDir, module, ver string, files map[string][]byte) (rerr error) { 24 dir := filepath.Join(rootDir, module, "@v") 25 if err := os.MkdirAll(dir, 0755); err != nil { 26 return err 27 } 28 29 // The go command checks for versions by looking at the "list" file. Since 30 // we are supporting multiple versions, create this file if it does not exist 31 // or append the version number to the preexisting file. 32 f, err := os.OpenFile(filepath.Join(dir, "list"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 33 if err != nil { 34 return err 35 } 36 defer checkClose("list file", f, &rerr) 37 if _, err := f.WriteString(ver + "\n"); err != nil { 38 return err 39 } 40 41 // Serve the go.mod file on the <version>.mod url, if it exists. Otherwise, 42 // serve a stub. 43 modContents, ok := files["go.mod"] 44 if !ok { 45 modContents = []byte("module " + module) 46 } 47 if err := ioutil.WriteFile(filepath.Join(dir, ver+".mod"), modContents, 0644); err != nil { 48 return err 49 } 50 51 // info file, just the bare bones. 52 infoContents := []byte(fmt.Sprintf(`{"Version": "%v", "Time":"2017-12-14T13:08:43Z"}`, ver)) 53 if err := ioutil.WriteFile(filepath.Join(dir, ver+".info"), infoContents, 0644); err != nil { 54 return err 55 } 56 57 // zip of all the source files. 58 f, err = os.OpenFile(filepath.Join(dir, ver+".zip"), os.O_CREATE|os.O_WRONLY, 0644) 59 if err != nil { 60 return err 61 } 62 defer checkClose("zip file", f, &rerr) 63 z := zip.NewWriter(f) 64 defer checkClose("zip writer", z, &rerr) 65 for name, contents := range files { 66 zf, err := z.Create(module + "@" + ver + "/" + name) 67 if err != nil { 68 return err 69 } 70 if _, err := zf.Write(contents); err != nil { 71 return err 72 } 73 } 74 75 return nil 76 } 77 78 func checkClose(name string, closer io.Closer, err *error) { 79 if cerr := closer.Close(); cerr != nil && *err == nil { 80 *err = fmt.Errorf("closing %s: %v", name, cerr) 81 } 82 } 83 84 // ToURL returns the file uri for a proxy directory. 85 func ToURL(dir string) string { 86 if testenv.Go1Point() >= 13 { 87 // file URLs on Windows must start with file:///. See golang.org/issue/6027. 88 path := filepath.ToSlash(dir) 89 if !strings.HasPrefix(path, "/") { 90 path = "/" + path 91 } 92 return "file://" + path 93 } else { 94 // Prior to go1.13, the Go command on Windows only accepted GOPROXY file URLs 95 // of the form file://C:/path/to/proxy. This was incorrect: when parsed, "C:" 96 // is interpreted as the host. See golang.org/issue/6027. This has been 97 // fixed in go1.13, but we emit the old format for old releases. 98 return "file://" + filepath.ToSlash(dir) 99 } 100 }