Skip to content

Commit 5b6aca9

Browse files
committed
internal/fetch: use a ModuleGetter for FetchLocalModule
For golang/go#47780 Change-Id: I1259649c8a1d452ffad5e8a2a92943801a24b306 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/343212 Trust: Jonathan Amsterdam <[email protected]> Run-TryBot: Jonathan Amsterdam <[email protected]> TryBot-Result: kokoro <[email protected]> Reviewed-by: Julie Qiu <[email protected]>
1 parent ad7af84 commit 5b6aca9

File tree

2 files changed

+61
-84
lines changed

2 files changed

+61
-84
lines changed

internal/fetch/fetch.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ type ModuleGetter interface {
9494
// Info returns basic information about the module.
9595
Info(ctx context.Context, path, version string) (*proxy.VersionInfo, error)
9696
// Mod returns the contents of the module's go.mod file.
97+
// If the file does not exist, it returns a synthesized one.
9798
Mod(ctx context.Context, path, version string) ([]byte, error)
9899
// Zip returns a reader for the module's zip file.
99100
Zip(ctx context.Context, path, version string) (*zip.Reader, error)
100101
// ZipSize returns the approximate size of the zip file in bytes.
102+
// It is used only for load-shedding.
101103
ZipSize(ctx context.Context, path, version string) (int64, error)
102104
}
103105

@@ -160,6 +162,19 @@ func FetchModule(ctx context.Context, modulePath, requestedVersion string, mg Mo
160162
}
161163

162164
func fetchModule(ctx context.Context, fr *FetchResult, mg ModuleGetter, sourceClient *source.Client) (*FetchInfo, error) {
165+
// If the module path is empty, get it from the go.mod file. This should only happen when fetching
166+
// a local module.
167+
if fr.ModulePath == "" {
168+
goModBytes, err := mg.Mod(ctx, fr.ModulePath, fr.RequestedVersion)
169+
if err != nil {
170+
return nil, err
171+
}
172+
fr.ModulePath = modfile.ModulePath(goModBytes)
173+
if fr.ModulePath == "" {
174+
return nil, fmt.Errorf("go.mod has no module path: %w", derrors.BadModule)
175+
}
176+
}
177+
163178
info, err := GetInfo(ctx, fr.ModulePath, fr.RequestedVersion, mg)
164179
if err != nil {
165180
return nil, err

internal/fetch/fetchlocal.go

Lines changed: 46 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ import (
88
"archive/zip"
99
"bytes"
1010
"context"
11+
"errors"
1112
"fmt"
1213
"io"
1314
"io/ioutil"
14-
"net/http"
1515
"os"
1616
"path/filepath"
1717
"strings"
1818
"time"
1919

20-
"golang.org/x/mod/modfile"
2120
"golang.org/x/pkgsite/internal/derrors"
21+
"golang.org/x/pkgsite/internal/proxy"
2222
"golang.org/x/pkgsite/internal/source"
2323
)
2424

@@ -29,96 +29,58 @@ var (
2929
LocalCommitTime = time.Time{}
3030
)
3131

32-
// FetchLocalModule fetches a module from a local directory and process its contents
33-
// to return an internal.Module and other related information. modulePath is not necessary
34-
// if the module has a go.mod file, but if both exist, then they must match.
35-
// FetchResult.Error should be checked to verify that the fetch succeeded. Even if the
36-
// error is non-nil the result may contain useful data.
37-
func FetchLocalModule(ctx context.Context, modulePath, localPath string, sourceClient *source.Client) *FetchResult {
38-
fr := &FetchResult{
39-
ModulePath: modulePath,
40-
RequestedVersion: LocalVersion,
41-
ResolvedVersion: LocalVersion,
42-
Defer: func() {},
43-
}
44-
45-
var fi *FetchInfo
46-
defer func() {
47-
if fr.Error != nil {
48-
derrors.Wrap(&fr.Error, "FetchLocalModule(%q, %q)", modulePath, localPath)
49-
fr.Status = derrors.ToStatus(fr.Error)
50-
}
51-
if fr.Status == 0 {
52-
fr.Status = http.StatusOK
53-
}
54-
if fi != nil {
55-
finishFetchInfo(fi, fr.Status, fr.Error)
56-
}
57-
}()
32+
// A directoryModuleGetter is a ModuleGetter whose source is a directory in the file system that contains
33+
// a module's files.
34+
type directoryModuleGetter struct {
35+
dir string // the directory containing the module's files
36+
}
5837

59-
info, err := os.Stat(localPath)
60-
if err != nil {
61-
fr.Error = fmt.Errorf("%s: %w", err.Error(), derrors.NotFound)
62-
return fr
63-
}
38+
// NewDirectoryModuleGetter returns a ModuleGetter for reading a module from a directory.
39+
func NewDirectoryModuleGetter(dir string) ModuleGetter {
40+
return &directoryModuleGetter{dir: dir}
41+
}
6442

65-
if !info.IsDir() {
66-
fr.Error = fmt.Errorf("%s not a directory: %w", localPath, derrors.NotFound)
67-
return fr
68-
}
43+
// Info returns basic information about the module.
44+
func (g *directoryModuleGetter) Info(ctx context.Context, path, version string) (*proxy.VersionInfo, error) {
45+
return &proxy.VersionInfo{
46+
Version: LocalVersion,
47+
Time: LocalCommitTime,
48+
}, nil
49+
}
6950

70-
fi = &FetchInfo{
71-
ModulePath: fr.ModulePath,
72-
Version: fr.ResolvedVersion,
73-
Start: time.Now(),
74-
}
75-
startFetchInfo(fi)
76-
77-
// Options for module path are either the modulePath parameter or go.mod file.
78-
// Accepted cases:
79-
// - Both are given and are the same.
80-
// - Only one is given. Note that: if modulePath is given and there's no go.mod
81-
// file, then the package is assumed to be using GOPATH.
82-
// Errors:
83-
// - Both are given and are different.
84-
// - Neither is given.
85-
if goModBytes, err := ioutil.ReadFile(filepath.Join(localPath, "go.mod")); err != nil {
86-
fr.GoModPath = modulePath
87-
fr.HasGoMod = false
88-
} else {
89-
fr.HasGoMod = true
90-
fr.GoModPath = modfile.ModulePath(goModBytes)
91-
if fr.GoModPath != modulePath && modulePath != "" {
92-
fr.Error = fmt.Errorf("module path=%s, go.mod path=%s: %w", modulePath, fr.GoModPath, derrors.AlternativeModule)
93-
return fr
51+
// Mod returns the contents of the module's go.mod file.
52+
// If the file does not exist, it returns a synthesized one.
53+
func (g *directoryModuleGetter) Mod(ctx context.Context, path, version string) ([]byte, error) {
54+
data, err := ioutil.ReadFile(filepath.Join(g.dir, "go.mod"))
55+
if errors.Is(err, os.ErrNotExist) {
56+
if path == "" {
57+
return nil, fmt.Errorf("no module path: %w", derrors.BadModule)
9458
}
59+
return []byte(fmt.Sprintf("module %s\n", path)), nil
9560
}
61+
return data, err
62+
}
9663

97-
if fr.GoModPath == "" {
98-
fr.Error = fmt.Errorf("no module path: %w", derrors.BadModule)
99-
return fr
100-
}
101-
fr.ModulePath = fr.GoModPath
64+
// Zip returns a reader for the module's zip file.
65+
func (g *directoryModuleGetter) Zip(ctx context.Context, path, version string) (*zip.Reader, error) {
66+
return createZipReader(g.dir, path, LocalVersion)
67+
}
10268

103-
zipReader, err := createZipReader(localPath, fr.GoModPath, LocalVersion)
104-
if err != nil {
105-
fr.Error = fmt.Errorf("couldn't create a zip: %s, %w", err.Error(), derrors.BadModule)
106-
return fr
107-
}
69+
// ZipSize returns the approximate size of the zip file in bytes.
70+
func (g *directoryModuleGetter) ZipSize(ctx context.Context, path, version string) (int64, error) {
71+
return 0, errors.New("directoryModuleGetter.ZipSize unimplemented")
72+
}
10873

109-
mod, pvs, err := processZipFile(ctx, fr.GoModPath, LocalVersion, LocalVersion, LocalCommitTime, zipReader, sourceClient)
110-
if err != nil {
111-
fr.Error = err
112-
return fr
113-
}
114-
mod.HasGoMod = fr.HasGoMod
115-
fr.Module = mod
116-
fr.PackageVersionStates = pvs
117-
fr.Module.SourceInfo = nil // version is not known, so even if info is found it most likely is wrong.
118-
for _, state := range fr.PackageVersionStates {
119-
if state.Status != http.StatusOK {
120-
fr.Status = derrors.ToStatus(derrors.HasIncompletePackages)
121-
}
74+
// FetchLocalModule fetches a module from a local directory and process its contents
75+
// to return an internal.Module and other related information. modulePath is not necessary
76+
// if the module has a go.mod file, but if both exist, then they must match.
77+
// FetchResult.Error should be checked to verify that the fetch succeeded. Even if the
78+
// error is non-nil the result may contain useful data.
79+
func FetchLocalModule(ctx context.Context, modulePath, localPath string, sourceClient *source.Client) *FetchResult {
80+
g := NewDirectoryModuleGetter(localPath)
81+
fr := FetchModule(ctx, modulePath, LocalVersion, g, sourceClient)
82+
if fr.Error != nil {
83+
fr.Error = fmt.Errorf("FetchLocalModule(%q, %q): %w", modulePath, localPath, fr.Error)
12284
}
12385
return fr
12486
}

0 commit comments

Comments
 (0)