Giter Club home page Giter Club logo

vcs's Introduction

VCS Repository Management for Go

Manage repos in varying version control systems with ease through a common interface.

Linux Tests Go Report Card Windows Tests Docs

Note: Module names are case sensitive. Please be sure to use github.com/Masterminds/vcs with the capital M.

Quick Usage

Quick usage:

remote := "https://github.com/Masterminds/vcs"
local, _ := ioutil.TempDir("", "go-vcs")
repo, err := NewRepo(remote, local)

In this case NewRepo will detect the VCS is Git and return a GitRepo. All of the repos implement the Repo interface with a common set of features between them.

Supported VCS

Git, SVN, Bazaar (Bzr), and Mercurial (Hg) are currently supported. They each have their own type (e.g., GitRepo) that follow a simple naming pattern. Each type implements the Repo interface and has a constructor (e.g., NewGitRepo). The constructors have the same signature as NewRepo.

Features

  • Clone or checkout a repository depending on the version control system.
  • Pull updates to a repository.
  • Get the currently checked out commit id.
  • Checkout a commit id, branch, or tag (depending on the availability in the VCS).
  • Get a list of tags and branches in the VCS.
  • Check if a string value is a valid reference within the VCS.
  • More...

For more details see the documentation.

Motivation

The package golang.org/x/tools/go/vcs provides some valuable functionality for working with packages in repositories in varying source control management systems. That package, while useful and well tested, is designed with a specific purpose in mind. Our uses went beyond the scope of that package. To implement our scope we built a package that went beyond the functionality and scope of golang.org/x/tools/go/vcs.

vcs's People

Contributors

aleksi avatar chonthu avatar cyrilleverrier avatar dt avatar guywithnose avatar hellograyson avatar hmarr avatar kevinburke avatar m0j0hn avatar mattfarina avatar sdboyer avatar technosophos avatar tony avatar wmarbut avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vcs's Issues

Retrieve Tags For A Commit

The idea is to retrieve a list of tags associated with a commit.

In Git you can use git describe --tags --exact-match <COMMIT ID>

In Bzr you can use bzr tags -r <COMMIT ID>

In Hg you can use hg log -r <COMMIT ID> --style=xml. A tag will be present if one is associated with the commit.

In SVN we aren't supporting tags since they are part of the path.

Potential Mercury Bug

Hi,

A tool I'm using is looking up some repository information using this library. I kept on getting a "The remote does not match the VCS endpoint" error so I investigated a bit.

Turns out that this library is getting called as follows: repo, err := vcs.NewRepo("", repoRoot). Notice the empty remote address which works fine for Git repositories but it seems to fail for Mercurial.

I think this is a bug in https://github.com/Masterminds/vcs/blob/master/hg.go#L47:

m := hgDetectURL.FindStringSubmatch(string(out))
if m[1] != "" && m[1] != remote {
        return nil, ErrWrongRemote
}

should be instead:

m := hgDetectURL.FindStringSubmatch(string(out))
if remote != "" && m[1] != remote {
        return nil, ErrWrongRemote
}

I just wanted to ask if this is intended behaviour or a bug. In case this is a bug, I'd be happy to open a PR.

Difference in behavior depending on version of Git installed

Continuing with our work to get glide working on Windows, @davecgh and I noticed that the identical commands were producing different results, with mine working and his failing. We believe the root cause of this issue is the differences in our git installs. I use http://git-for-windows.github.io/ while he is using git installed through msys2's pacman. My git understands Windows paths, while his does not.

When this vcs package makes a call to, e.g. clone a git repo, it appends the local path as the last argument of the command. On windows, this will be a windows path. This works with my git, but his throws errors such as:

[WARN] Update failed for github.com/btcsuite/btclog: fatal: could not create work tree dir 'D:\tmpgo\src\github.com\btcsuite\btcd\vendor\github.com\btcsuite\btclog': No such file or directory : exit status 128

which appears to be from git's stderr.

We took a look at how go (the tool) itself handled this when exec'ing git for 'go get' commands. They don't add the local path to the end of the arguments at all and instead change the relative directory:

https://github.com/golang/go/blob/e35901fd65a9c0f475de260a79b7b628d9d07ebf/src/cmd/go/vcs.go#L345-L347

Commands like Get, Init, Update can't retrieve live out/err?

In git, initial checkout and pulls, these are often "buffered". That information is valuable in my case (www.github.com/tony/vcsync) because I want to forward the progress of the update to stdout. Ideally, a couple of repos at a time.

At the present time, Get, Init and Update is hard-coded to use CombinedOutput, which runs the command and waits for completion. This lends me no ability run the command and observe the live output of a git pull, and due to the command and error handling for the (Get/Init/Update) on the repo being tightly-coupled, I can't trivially compose a command for my case without duplicating 90% of the code.

I'm going to present a PR for this for your opinion.

trim on carriage return at svn.go func detectRemoteFromInfoCommand

The func detectRemoteFromInfoCommand(infoOut string) (string, error) returns a remote with a trailing "cariagge return".
If this remote is used the commands issued to svn will always respond with an error.

My solution ..

func detectRemoteFromInfoCommand(infoOut string) (string, error) {
sBytes := []byte(infoOut)
urlIndex := strings.Index(infoOut, "URL: ")
if urlIndex == -1 {
return "", fmt.Errorf("Remote not specified in svn info")
}
urlEndIndex := strings.Index(string(sBytes[urlIndex:]), "\n")
if urlEndIndex == -1 {
urlEndIndex = strings.Index(string(sBytes[urlIndex:]), "\r")
if urlEndIndex == -1 {
return "", fmt.Errorf("Unable to parse remote URL for svn info")
}
}

// bugfix : there is a carriage return at the end we need to remove from the string
// original ..
// return string(sBytes[(urlIndex + 5):(urlIndex + urlEndIndex)]), nil

return string(sBytes[(urlIndex + 5):(urlIndex + urlEndIndex) - 1]), nil

}

Get Current version

This is a loose "version" and is different from the Version method which returns a revision. For example, in Git if you're on a branch that name would be returned. If on a tag that name would be returned. Otherwise a revision is returned.

This is a little more difficult in other VCS and am still working out the details if it's possible.

Git

  1. Run git symbolic-ref HEAD to see if this is a branch and get the name. If not use Version() to get the revision and TagsFromCommit() to get a tag if one is present.
  2. Similar to the first but instead read directly from the file .git/HEAD for the first step.

Hg

  1. Run hg parent -T "{node}" to get current commit. Then compare that to hg parent -r tip -T "{node}" to see if on the tip of the branch. If so, hg branch to get the name. Otherwise, use TagsFromCommit() to see if on a tag to return. Or, return commit id.

TODO:

  • Bzr
  • Strategy for Svn

Running commands hang forever

This happens when enabling ControlMaster in openssh. Seems to be related to golang/go#13155.

~/.ssh/config looks like this:

ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p
ControlPersist 10m

`file:` URLs aren't supported

Maybe I'm doing it wrong, but I expected something like this to work:

package main

import (
  "github.com/Masterminds/vcs"
  "io/ioutil"
  "fmt"
)

func main() {
//remote := "https://github.com/Masterminds/vcs"  // works
remote := "file:///Users/pburkholder/tmp/vcs" // panics
local, _ := ioutil.TempDir("", "go-vcs")
fmt.Println(local)

repo, _ := vcs.NewRepo(remote, local)
// Returns: instance of GitRepo

repo.Vcs()
// Returns Git as this is a Git repo

err := repo.Get()
// Pulls down a repo, or a checkout in the case of SVN, and returns an
// error if that didn't happen successfully.
if err != nil {
    fmt.Println(err)
    }

    err = repo.UpdateVersion("master")
    // Checkouts out a specific version. In most cases this can be a commit
    // id,
    // branch, or tag.
    if err != nil {
        fmt.Println(err)
    }
}

but I get

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0xb0 pc=0x21d7]

goroutine 1 [running]:
panic(0x3c2c60, 0xc82000a0f0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/panic.go:481 +0x3e6
main.main()
    /Users/pburkholder/tmp/t/t.go:18 +0x197
exit status 2

For a downstream project I'd find it useful to reference repositories by local filesystem paths, so that this package works similarly to:

git clone file:///Users/pburkholder/tmp/vcs
# and
git clone https://github.com/Masterminds/vcs

Thanks, Peter

isDetachedHead fails with non-english locales

isDetachedHead parses git status output and looks for "HEAD detached at" Obviously, this fails for any non-english locale. I don't want to be a dick, but this is insanely brittle ๐Ÿ˜

A possible improvement would be resetting LANG before running git. An even better solution would be checking the contents of .git/HEAD โ€” this would avoid breakage from future changes of this message. I can provide a pull request if any of these changes would be OK with you.

VCS-74: Add +build tags to tests, to allow selectively running suites for different VCSs

As a developer, I would like to be able to selectively run tests, so I do not test code I did not modify.

As a developer, I would like to be able to selectively run tests, so I do not need to install tools I do not normally use (BZR, SVN, et al) just so I can get tests to pass when testing locally.

AC: "+build" tags added to *_test.go files, and CI config files to test all by default.

commit count between current local and HEAD

Hello,

How would you calculate the count difference between the current local commit and last commit on HEAD?

I can do a simple Fetch with RunFromDir, but I see no commit history functions.
(Great piece of library BTW ๐Ÿ‘ )

hg not cloning and checking out

The Get function on hg should get and checkout the codebase. This has caused an issue on Masterminds/glide#65.

The issue is that Get isn't checking out the codebase. Also, the update command isn't pulling the latest changes if they exist.

Version() returns string when it should return an error

I'm running Version() on a repo and it should return an error but it doesn't.

Running this at the console reveals:

$ hg --debug identify
*** failed to import extension hggit from ~/code/hg-git/hggit: [Errno 2] No such file or directory: '/Users/kevin/code/hg-git/hggit'
a5494ba2177ff9ef26feb3c155dfecc350b1a8ef

Version() returns "***". The first line is printed to stderr, so filtering out stderr should be sufficient, or returning an error, either seems like it should suffice.

Submodule cleanup is broken

Bug description

When glide tries to perform submodule cleanup, it fails with

    git_test.go:440: checking out needed version failed with err: msg: Unexpected error while defensively cleaning up after possible derelict nested submodule directories: exit status 128
        orig: exit status 128
        out: Entering 'subm1'
        error: unknown switch `x'
        usage: git submodule--helper foreach [--quiet] [--recursive] [--] <command>
        
            -q, --quiet           Suppress output of entering each submodule command
            --recursive           Recurse into nested submodules
        
        fatal: run_command returned non-zero status while recursing in the nested submodules of subm1

Responsible code

The responsible code seems to be at:

vcs/git.go

Line 184 in b4f5583

out, err = s.RunFromDir("git", "submodule", "foreach", "--recursive", "git", "clean", "-x", "-d", "-f", "-f")

Findings from debugging

I tried to build the tests and run them and they do fail, too:

$ go test -c ./...
$ ./vcs.test --test.run "TestGit.*"
--- FAIL: TestGitSubmoduleHandling (8.48s)
    git_test.go:440: checking out needed version failed with err: msg: Unexpected error while defensively cleaning up after possible derelict nested submodule directories: exit status 128
        orig: exit status 128
        out: Entering 'subm1'
        error: unknown switch `x'
        usage: git submodule--helper foreach [--quiet] [--recursive] [--] <command>
        
            -q, --quiet           Suppress output of entering each submodule command
            --recursive           Recurse into nested submodules
        
        fatal: run_command returned non-zero status while recursing in the nested submodules of subm1
        .
--- FAIL: TestGitSubmoduleHandling2 (3.64s)
    git_test.go:551: Unexpected error while defensively cleaning up after possible derelict nested submodule directories: exit status 128
FAIL

It almost seemed like the error would be in os/exec but I when I compile and run the following, it does not fail like the above:

package main

import (
  "os/exec"
  "fmt"
)

func main() {
    cmd := "git"
    args := []string{"submodule", "foreach", "--recursive", "git", "clean", "-x", "-d", "-f", "-f"}
	c := exec.Command(cmd, args...)
	out, err := c.CombinedOutput()
    fmt.Printf("out: %v\n", out)
    fmt.Printf("err: %v\n", err)

Therefore the failure seems to be somewhere else.

System details

Details about my system:

$ uname -ar
Linux standa-arch 5.1.15-arch1-1-ARCH #1 SMP PREEMPT Tue Jun 25 04:49:39 UTC 2019 x86_64 GNU/Linux
$ git --version
git version 2.22.0
$ go version
go version go1.12.6 linux/amd64

Improve VCS detection

Hi,

Thanks for the great work on glide! It seems pretty streaigh-forward to me and helps really a lot to manage dependecies.
There is one thing I've noticed about the VCS detection. I have some dependendies of my project in private repositories and Glide cannot detect the vcs from the package name. I can fix this by specifying repo and vcs in the glide.yml, but I think it could be done automatically. The go-import header in the HTML fetched afterwards (see https://github.com/Masterminds/vcs/blob/master/vcs_remote_lookup.go#L107) contains the right VCS. The HTML is just not fetched, because the function returns the error before. By changing the flow here, the usibility could be improved without breaking anything.

Best regards

Have svn return *something* from `Branches()` and `Tags()`

Even though branches and tags in svn are just convention, it seems like it'd still be useful to enumerate those tags/branches that follow the basic convention.

As it stands, not having data reported back from there makes it nigh-impossible (in [vsolver][https://github.com/sdboyer/vsolver]-land, anyway) to have dependencies on such repos at all.

...ofc, we could also basically just ignore svn... :)

VCS-76: Something hosed w git submodules handling

I am trying to use Glide on Linux and Windows, and for one of my modules with submodules, it's failing on Windows. Some Googling revealed Glide issue #745, which referenced line 388 in git.go.
After manually trying the underlying git commands on my Windows, I think root cause is that "git submodule foreach ... --prefix=..." passes the prefix string as a doublequote delimited string to Windows bash, and the trailing '' (Windows PathDelimiter) escapes the closing doublequote, which Breaks Things (tm). My inelegant solution is to create helper function which is used to conditionally rewrite the path string on Windows by tripling every PathDelimiter, i.e., '' becomes '\' - and this seems to solve the problem. I also added another test using a publicly accessible repo which exercised the original problem which led me to work on this in the first place.

Error: Unable to update checked out version: exit status 128

Hi,

helm is using this go library for installing plugins.

I got an error today, if there is a branch name which has the same name as a local file:


% helm plugin install "https://github.com/jkroepke/helm-secrets" --version "dockerfile"
Error: Unable to update checked out version: exit status 128
% ls Dockerfile
Dockerfile
% git checkout dockerfile
fatal: 'dockerfile' could be both a local file and a tracking branch.
Please use -- (and optionally --no-guess) to disambiguate

To fix this, add 2 hypen at the end of the command, for example:

% git checkout dockerfile --
branch 'dockerfile' set up to track 'origin/dockerfile'.
Switched to a new branch 'dockerfile'

See: https://stackoverflow.com/questions/25322335/git-change-branch-when-file-of-same-name-is-present

Code, needs to be changed:

vcs/git.go

Line 161 in 7d3c358

out, err := s.RunFromDir("git", "checkout", version)

Git Version: git version 2.39.1

Go redirect matching isn't working

When trying to retrieve golang.org/x/net/context it's failing because the prefix to match is golang.org/x/net and it's looking for an exact match.

running concurrent checks on multiple repos does not always work

I'm trying to work with multiple git repos at the same but am having issues.
3 git repos all hosted on github.

package main

import (
    "log"
    "sync"

    "github.com/Masterminds/vcs"
)

var (
    base = "/srv/apps/"
)

func main() {
    var (
        dirs    = []string{"a", "b", "c"}
        release = "release/4.1.0"
        remotes = map[string]string{
            "a": "[email protected]:fake/a.git",
            "b": "[email protected]:fake/b.git",
            "c": "git@fake/c.git",
        }
    )

    pg := new(sync.WaitGroup)
    for _, val := range dirs {
        pg.Add(1)
        go updateRepo(val, remotes[val], release, pg)
    }
    pg.Wait()
}

func updateRepo(local string, remote string, rel string, pg *sync.WaitGroup) {
    local = base + local

    log.Printf("%s -- %s -- %s\n", local, remote, rel)

    repo, err := vcs.NewGitRepo(remote, local)
    if err != nil {
        log.Printf("In Error: %s -- %s -- %s\n", local, remote, rel)
        log.Fatalln(err)
    }
    if repo.CheckLocal() {
        log.Printf("Local good: %s\n", local)
    }

    pg.Done()
}

I would expect this output everytime(assuming all git repos are there)

2015/10/19 11:59:02 /srv/apps/c -- [email protected]:fake/c.git -- release/4.1.0
2015/10/19 11:59:02 /srv/apps/a -- [email protected]:fake/a.git -- release/4.1.0
2015/10/19 11:59:02 /srv/apps/b -- [email protected]:fake/b.git -- release/4.1.0
2015/10/19 11:59:02 Local good: /srv/apps/c
2015/10/19 11:59:02 Local good: /srv/apps/a
2015/10/19 11:59:02 Local good: /srv/apps/b

However I sometimes I get this:

2015/10/19 11:58:40 /srv/apps/c -- [email protected]:fake/c.git -- release/4.1.0
2015/10/19 11:58:40 /srv/apps/a -- [email protected]:fake/a.git -- release/4.1.0
2015/10/19 11:58:40 /srv/apps/valuation -- [email protected]:fake/b.git -- release/4.1.0
2015/10/19 11:58:40 Local good: /srv/apps/c
2015/10/19 11:58:40 In Error: /srv/apps/a -- [email protected]:fake/a.git -- release/4.1.0
2015/10/19 11:58:40 The Remote does not match the VCS endpoint

Git sparse checkout based on VCS url

Is it possible to execute a sparse checkout based on the full remote URL path to a folder within a Git repo? Similarly to how go get ... works. Might be related to #68

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.