2020-02-20 08:31:22 +01:00
|
|
|
package project
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"net/url"
|
2020-04-07 08:27:44 +02:00
|
|
|
"os"
|
|
|
|
"strings"
|
2020-02-20 08:31:22 +01:00
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"gopkg.in/src-d/go-billy.v4"
|
|
|
|
"gopkg.in/src-d/go-billy.v4/memfs"
|
|
|
|
git "gopkg.in/src-d/go-git.v4"
|
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing/transport"
|
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing/transport/http"
|
|
|
|
"gopkg.in/src-d/go-git.v4/storage/memory"
|
|
|
|
)
|
|
|
|
|
|
|
|
const GitScheme = "git"
|
2020-04-07 08:42:27 +02:00
|
|
|
const HTTPScheme = "http"
|
|
|
|
const HTTPSScheme = "https"
|
2020-02-20 08:31:22 +01:00
|
|
|
|
|
|
|
type GitFetcher struct{}
|
|
|
|
|
|
|
|
func (f *GitFetcher) Fetch(url *url.URL) (billy.Filesystem, error) {
|
|
|
|
fs := memfs.New()
|
|
|
|
|
|
|
|
var auth transport.AuthMethod
|
|
|
|
|
|
|
|
if user := url.User; user != nil {
|
|
|
|
user := url.User
|
|
|
|
basicAuth := &http.BasicAuth{
|
|
|
|
Username: user.Username(),
|
|
|
|
}
|
|
|
|
|
|
|
|
password, exists := user.Password()
|
|
|
|
if exists {
|
|
|
|
basicAuth.Password = password
|
|
|
|
}
|
|
|
|
|
|
|
|
auth = basicAuth
|
|
|
|
}
|
|
|
|
|
|
|
|
if url.Scheme == "" {
|
|
|
|
url.Scheme = "https"
|
|
|
|
}
|
|
|
|
|
|
|
|
branchName := plumbing.NewBranchReferenceName("master")
|
|
|
|
if url.Fragment != "" {
|
|
|
|
branchName = plumbing.NewBranchReferenceName(url.Fragment)
|
|
|
|
url.Fragment = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("Cloning repository '%s'...", url.String())
|
|
|
|
|
|
|
|
repo, err := git.Clone(memory.NewStorage(), fs, &git.CloneOptions{
|
|
|
|
URL: url.String(),
|
|
|
|
Auth: auth,
|
|
|
|
ReferenceName: branchName,
|
2020-04-07 08:27:44 +02:00
|
|
|
Progress: os.Stdout,
|
2020-02-20 08:31:22 +01:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
if err == transport.ErrRepositoryNotFound {
|
|
|
|
return nil, errors.Wrapf(err, "could not find repository")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, errors.Wrap(err, "could not clone repository")
|
|
|
|
}
|
|
|
|
|
|
|
|
worktree, err := repo.Worktree()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not retrieve worktree")
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("Checking out branch '%s'...", branchName)
|
|
|
|
|
|
|
|
err = worktree.Checkout(&git.CheckoutOptions{
|
|
|
|
Force: true,
|
|
|
|
Branch: branchName,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "could not checkout branch '%s'", branchName)
|
|
|
|
}
|
|
|
|
|
|
|
|
return fs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *GitFetcher) Match(url *url.URL) bool {
|
|
|
|
if url.Scheme == GitScheme {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-04-07 08:42:27 +02:00
|
|
|
if (url.Scheme == HTTPSScheme || url.Scheme == HTTPScheme) && strings.HasSuffix(url.Path, ".git") {
|
2020-04-07 08:27:44 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-02-20 08:31:22 +01:00
|
|
|
isFilesystemPath := isFilesystemPath(url.Path)
|
|
|
|
if url.Scheme == "" && !isFilesystemPath {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewGitFetcher() *GitFetcher {
|
|
|
|
return &GitFetcher{}
|
|
|
|
}
|