зеркало из https://github.com/golang/dep.git
166 строки
3.7 KiB
Go
166 строки
3.7 KiB
Go
// Copyright 2017 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 gps
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
// A Solution is returned by a solver run. It is mostly just a Lock, with some
|
|
// additional methods that report information about the solve run.
|
|
type Solution interface {
|
|
Lock
|
|
// The name of the ProjectAnalyzer used in generating this solution.
|
|
AnalyzerName() string
|
|
// The version of the ProjectAnalyzer used in generating this solution.
|
|
AnalyzerVersion() int
|
|
// The name of the Solver used in generating this solution.
|
|
SolverName() string
|
|
// The version of the Solver used in generating this solution.
|
|
SolverVersion() int
|
|
Attempts() int
|
|
}
|
|
|
|
type solution struct {
|
|
// A list of the projects selected by the solver.
|
|
p []LockedProject
|
|
|
|
// The number of solutions that were attempted
|
|
att int
|
|
|
|
// The hash digest of the input opts
|
|
hd []byte
|
|
|
|
// The analyzer info
|
|
analyzerInfo ProjectAnalyzerInfo
|
|
|
|
// The solver used in producing this solution
|
|
solv Solver
|
|
}
|
|
|
|
const concurrentWriters = 16
|
|
|
|
// WriteDepTree takes a basedir and a Lock, and exports all the projects
|
|
// listed in the lock to the appropriate target location within the basedir.
|
|
//
|
|
// If the goal is to populate a vendor directory, basedir should be the absolute
|
|
// path to that vendor directory, not its parent (a project root, typically).
|
|
//
|
|
// It requires a SourceManager to do the work, and takes a flag indicating
|
|
// whether or not to strip vendor directories contained in the exported
|
|
// dependencies.
|
|
func WriteDepTree(basedir string, l Lock, sm SourceManager, sv bool, logger *log.Logger) error {
|
|
if l == nil {
|
|
return fmt.Errorf("must provide non-nil Lock to WriteDepTree")
|
|
}
|
|
|
|
if err := os.MkdirAll(basedir, 0777); err != nil {
|
|
return err
|
|
}
|
|
|
|
g, ctx := errgroup.WithContext(context.TODO())
|
|
lps := l.Projects()
|
|
sem := make(chan struct{}, concurrentWriters)
|
|
var cnt struct {
|
|
sync.Mutex
|
|
i int
|
|
}
|
|
|
|
for i := range lps {
|
|
p := lps[i] // per-iteration copy
|
|
|
|
g.Go(func() error {
|
|
err := func() error {
|
|
select {
|
|
case sem <- struct{}{}:
|
|
defer func() { <-sem }()
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
}
|
|
|
|
ident := p.Ident()
|
|
projectRoot := string(ident.ProjectRoot)
|
|
to := filepath.FromSlash(filepath.Join(basedir, projectRoot))
|
|
|
|
if err := sm.ExportProject(ctx, ident, p.Version(), to); err != nil {
|
|
return errors.Wrapf(err, "failed to export %s", projectRoot)
|
|
}
|
|
|
|
if sv {
|
|
if err := ctx.Err(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := filepath.Walk(to, stripVendor); err != nil {
|
|
return errors.Wrapf(err, "failed to strip vendor from %s", projectRoot)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
|
|
switch err {
|
|
case context.Canceled, context.DeadlineExceeded:
|
|
// Don't log "secondary" errors.
|
|
default:
|
|
msg := "Wrote"
|
|
if err != nil {
|
|
msg = "Failed to write"
|
|
}
|
|
|
|
// Log and increment atomically to prevent re-ordering.
|
|
cnt.Lock()
|
|
cnt.i++
|
|
logger.Printf("(%d/%d) %s %s@%s\n", cnt.i, len(lps), msg, p.Ident(), p.Version())
|
|
cnt.Unlock()
|
|
}
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
err := g.Wait()
|
|
if err != nil {
|
|
os.RemoveAll(basedir)
|
|
}
|
|
return errors.Wrap(err, "failed to write dep tree")
|
|
}
|
|
|
|
func (r solution) Projects() []LockedProject {
|
|
return r.p
|
|
}
|
|
|
|
func (r solution) Attempts() int {
|
|
return r.att
|
|
}
|
|
|
|
func (r solution) InputsDigest() []byte {
|
|
return r.hd
|
|
}
|
|
|
|
func (r solution) AnalyzerName() string {
|
|
return r.analyzerInfo.Name
|
|
}
|
|
|
|
func (r solution) AnalyzerVersion() int {
|
|
return r.analyzerInfo.Version
|
|
}
|
|
|
|
func (r solution) SolverName() string {
|
|
return r.solv.Name()
|
|
}
|
|
|
|
func (r solution) SolverVersion() int {
|
|
return r.solv.Version()
|
|
}
|