Copyright 2020 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package fetch

import (
	
	
	
	
	
	
	
	
	
	
	

	
	
	
)
Version and commit time are pre specified when fetching a local module, as these fields are normally obtained from a proxy.
var (
	LocalVersion    = "v0.0.0"
	LocalCommitTime = time.Time{}
)
FetchLocalModule fetches a module from a local directory and process its contents to return an internal.Module and other related information. modulePath is not necessary if the module has a go.mod file, but if both exist, then they must match. FetchResult.Error should be checked to verify that the fetch succeeded. Even if the error is non-nil the result may contain useful data.
func ( context.Context, ,  string,  *source.Client) *FetchResult {
	 := &FetchResult{
		ModulePath:       ,
		RequestedVersion: LocalVersion,
		ResolvedVersion:  LocalVersion,
		Defer:            func() {},
	}

	var  *FetchInfo
	defer func() {
		if .Error != nil {
			derrors.Wrap(&.Error, "FetchLocalModule(%q, %q)", , )
			.Status = derrors.ToStatus(.Error)
		}
		if .Status == 0 {
			.Status = http.StatusOK
		}
		if  != nil {
			finishFetchInfo(, .Status, .Error)
		}
	}()

	,  := os.Stat()
	if  != nil {
		.Error = fmt.Errorf("%s: %w", .Error(), derrors.NotFound)
		return 
	}

	if !.IsDir() {
		.Error = fmt.Errorf("%s not a directory: %w", , derrors.NotFound)
		return 
	}

	 = &FetchInfo{
		ModulePath: .ModulePath,
		Version:    .ResolvedVersion,
		Start:      time.Now(),
	}
	startFetchInfo()
Options for module path are either the modulePath parameter or go.mod file. Accepted cases: - Both are given and are the same. - Only one is given. Note that: if modulePath is given and there's no go.mod file, then the package is assumed to be using GOPATH. Errors: - Both are given and are different. - Neither is given.
	if ,  := ioutil.ReadFile(filepath.Join(, "go.mod"));  != nil {
		.GoModPath = 
		.HasGoMod = false
	} else {
		.HasGoMod = true
		.GoModPath = modfile.ModulePath()
		if .GoModPath !=  &&  != "" {
			.Error = fmt.Errorf("module path=%s, go.mod path=%s: %w", , .GoModPath, derrors.AlternativeModule)
			return 
		}
	}

	if .GoModPath == "" {
		.Error = fmt.Errorf("no module path: %w", derrors.BadModule)
		return 
	}
	.ModulePath = .GoModPath

	,  := createZipReader(, .GoModPath, LocalVersion)
	if  != nil {
		.Error = fmt.Errorf("couldn't create a zip: %s, %w", .Error(), derrors.BadModule)
		return 
	}

	, ,  := processZipFile(, .GoModPath, LocalVersion, LocalCommitTime, , )
	if  != nil {
		.Error = 
		return 
	}
	.HasGoMod = .HasGoMod
	.Module = 
	.PackageVersionStates = 
	.Module.SourceInfo = nil // version is not known, so even if info is found it most likely is wrong.
	for ,  := range .PackageVersionStates {
		if .Status != http.StatusOK {
			.Status = derrors.ToStatus(derrors.HasIncompletePackages)
		}
	}
	return 
}
createZipReader creates a zip file from a directory given a local path and returns a zip.Reader to be passed to processZipFile. The purpose of the function is to transform a local go module into a zip file to be processed by existing functions.
func (, ,  string) (*zip.Reader, error) {
	 := new(bytes.Buffer)
	 := zip.NewWriter()
	 := filepath.Walk(, func( string,  os.FileInfo,  error) error {
		if  != nil {
			return 
		}
		if .IsDir() {
			return nil
		}

		,  := os.Open()
		if  != nil {
			return 
		}
		defer .Close()

		,  := .Create(filepath.Join(moduleVersionDir(, ), strings.TrimPrefix(, )))
		if  != nil {
			return 
		}

		_,  = io.Copy(, )
		return 
	})
	if  != nil {
		return nil, 
	}
	if  := .Close();  != nil {
		return nil, 
	}

	 := bytes.NewReader(.Bytes())
	return zip.NewReader(, .Size())