github.com/golang/dep@v0.5.4/gps/maybe_source.go (about)

     1  // Copyright 2017 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 gps
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"net/url"
    11  	"os"
    12  	"path/filepath"
    13  
    14  	"github.com/Masterminds/vcs"
    15  )
    16  
    17  // A maybeSource represents a set of information that, given some
    18  // typically-expensive network effort, could be transformed into a proper source.
    19  //
    20  // Wrapping these up as their own type achieves two goals:
    21  //
    22  // * Allows control over when deduction logic triggers network activity
    23  // * Makes it easy to attempt multiple URLs for a given import path
    24  type maybeSource interface {
    25  	// try tries to set up a source.
    26  	try(ctx context.Context, cachedir string) (source, error)
    27  	URL() *url.URL
    28  	fmt.Stringer
    29  }
    30  
    31  type maybeSources []maybeSource
    32  
    33  func (mbs maybeSources) possibleURLs() []*url.URL {
    34  	urlslice := make([]*url.URL, len(mbs))
    35  	for i, mb := range mbs {
    36  		urlslice[i] = mb.URL()
    37  	}
    38  	return urlslice
    39  }
    40  
    41  // sourceCachePath returns a url-sanitized source cache dir path.
    42  func sourceCachePath(cacheDir, sourceURL string) string {
    43  	return filepath.Join(cacheDir, "sources", sanitizer.Replace(sourceURL))
    44  }
    45  
    46  type maybeGitSource struct {
    47  	url *url.URL
    48  }
    49  
    50  func (m maybeGitSource) try(ctx context.Context, cachedir string) (source, error) {
    51  	ustr := m.url.String()
    52  	path := sourceCachePath(cachedir, ustr)
    53  
    54  	r, err := vcs.NewGitRepo(ustr, path)
    55  	if err != nil {
    56  		os.RemoveAll(path)
    57  		r, err = vcs.NewGitRepo(ustr, path)
    58  		if err != nil {
    59  			return nil, unwrapVcsErr(err)
    60  		}
    61  	}
    62  
    63  	return &gitSource{
    64  		baseVCSSource: baseVCSSource{
    65  			repo: &gitRepo{r},
    66  		},
    67  	}, nil
    68  }
    69  
    70  func (m maybeGitSource) URL() *url.URL {
    71  	return m.url
    72  }
    73  
    74  func (m maybeGitSource) String() string {
    75  	return fmt.Sprintf("%T: %s", m, ufmt(m.url))
    76  }
    77  
    78  type maybeGopkginSource struct {
    79  	// the original gopkg.in import path. this is used to create the on-disk
    80  	// location to avoid duplicate resource management - e.g., if instances of
    81  	// a gopkg.in project are accessed via different schemes, or if the
    82  	// underlying github repository is accessed directly.
    83  	opath string
    84  	// the actual upstream URL - always github
    85  	url *url.URL
    86  	// the major version to apply for filtering
    87  	major uint64
    88  	// whether or not the source package is "unstable"
    89  	unstable bool
    90  }
    91  
    92  func (m maybeGopkginSource) try(ctx context.Context, cachedir string) (source, error) {
    93  	// We don't actually need a fully consistent transform into the on-disk path
    94  	// - just something that's unique to the particular gopkg.in domain context.
    95  	// So, it's OK to just dumb-join the scheme with the path.
    96  	aliasURL := m.url.Scheme + "://" + m.opath
    97  	path := sourceCachePath(cachedir, aliasURL)
    98  	ustr := m.url.String()
    99  
   100  	r, err := vcs.NewGitRepo(ustr, path)
   101  	if err != nil {
   102  		os.RemoveAll(path)
   103  		r, err = vcs.NewGitRepo(ustr, path)
   104  		if err != nil {
   105  			return nil, unwrapVcsErr(err)
   106  		}
   107  	}
   108  
   109  	return &gopkginSource{
   110  		gitSource: gitSource{
   111  			baseVCSSource: baseVCSSource{
   112  				repo: &gitRepo{r},
   113  			},
   114  		},
   115  		major:    m.major,
   116  		unstable: m.unstable,
   117  		aliasURL: aliasURL,
   118  	}, nil
   119  }
   120  
   121  func (m maybeGopkginSource) URL() *url.URL {
   122  	return &url.URL{
   123  		Scheme: m.url.Scheme,
   124  		Path:   m.opath,
   125  	}
   126  }
   127  
   128  func (m maybeGopkginSource) String() string {
   129  	return fmt.Sprintf("%T: %s (v%v) %s ", m, m.opath, m.major, ufmt(m.url))
   130  }
   131  
   132  type maybeBzrSource struct {
   133  	url *url.URL
   134  }
   135  
   136  func (m maybeBzrSource) try(ctx context.Context, cachedir string) (source, error) {
   137  	ustr := m.url.String()
   138  	path := sourceCachePath(cachedir, ustr)
   139  
   140  	r, err := vcs.NewBzrRepo(ustr, path)
   141  	if err != nil {
   142  		os.RemoveAll(path)
   143  		r, err = vcs.NewBzrRepo(ustr, path)
   144  		if err != nil {
   145  			return nil, unwrapVcsErr(err)
   146  		}
   147  	}
   148  
   149  	return &bzrSource{
   150  		baseVCSSource: baseVCSSource{
   151  			repo: &bzrRepo{r},
   152  		},
   153  	}, nil
   154  }
   155  
   156  func (m maybeBzrSource) URL() *url.URL {
   157  	return m.url
   158  }
   159  
   160  func (m maybeBzrSource) String() string {
   161  	return fmt.Sprintf("%T: %s", m, ufmt(m.url))
   162  }
   163  
   164  type maybeHgSource struct {
   165  	url *url.URL
   166  }
   167  
   168  func (m maybeHgSource) try(ctx context.Context, cachedir string) (source, error) {
   169  	ustr := m.url.String()
   170  	path := sourceCachePath(cachedir, ustr)
   171  
   172  	r, err := vcs.NewHgRepo(ustr, path)
   173  	if err != nil {
   174  		os.RemoveAll(path)
   175  		r, err = vcs.NewHgRepo(ustr, path)
   176  		if err != nil {
   177  			return nil, unwrapVcsErr(err)
   178  		}
   179  	}
   180  
   181  	return &hgSource{
   182  		baseVCSSource: baseVCSSource{
   183  			repo: &hgRepo{r},
   184  		},
   185  	}, nil
   186  }
   187  
   188  func (m maybeHgSource) URL() *url.URL {
   189  	return m.url
   190  }
   191  
   192  func (m maybeHgSource) String() string {
   193  	return fmt.Sprintf("%T: %s", m, ufmt(m.url))
   194  }
   195  
   196  // borrow from stdlib
   197  // more useful string for debugging than fmt's struct printer
   198  func ufmt(u *url.URL) string {
   199  	var user, pass interface{}
   200  	if u.User != nil {
   201  		user = u.User.Username()
   202  		if p, ok := u.User.Password(); ok {
   203  			pass = p
   204  		}
   205  	}
   206  	return fmt.Sprintf("host=%q, path=%q, opaque=%q, scheme=%q, user=%#v, pass=%#v, rawpath=%q, rawq=%q, frag=%q",
   207  		u.Host, u.Path, u.Opaque, u.Scheme, user, pass, u.RawPath, u.RawQuery, u.Fragment)
   208  }