Skip to content

Instantly share code, notes, and snippets.

@askn
Created December 19, 2013 21:30
Show Gist options
  • Save askn/8046560 to your computer and use it in GitHub Desktop.
Save askn/8046560 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
)
var (
SRCDIR string
)
func init() {
// default SRCDIR
if os.Getenv("SRCDIR") == "" {
SRCDIR = filepath.Join(os.Getenv("HOME"), "src")
} else {
SRCDIR = os.Getenv("SRCDIR")
}
}
type vcsPath struct {
prefix string // prefix this description applies to
re string // pattern for import path
repo string // repository to use (expand with match of re)
vcs string // version control system to use (expand with match of re)
check func(match map[string]string) error // additional checks
ping bool // ping for scheme to use to download repo
}
var github = &vcsPath{
prefix: "github.com/",
re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
check: noVCSSuffix,
}
type repoRoot struct {
vcs *vcsCmd
// repo is the repository URL, including scheme
repo string
// root is the import path corresponding to the root of the
// repository
root string
}
func git(url string, scheme string) (*repoRoot, error) {
// içeriyor mu
if strings.Contains(url, "://") {
// invalid import path
return nil, fmt.Errorf("hatalı url")
}
if !strings.HasPrefix(url, github.prefix) {
return nil, fmt.Errorf("Bilinmeyen site")
}
re := regexp.MustCompile(github.re)
m := re.FindStringSubmatch(url)
if m == nil {
return nil, fmt.Errorf("hatalı url")
}
match := map[string]string{
"prefix": github.prefix,
"import": url,
}
for i, name := range re.SubexpNames() {
if name != "" && match[name] == "" {
match[name] = m[i]
}
}
if github.vcs != "" {
match["vcs"] = expand(match, github.vcs)
}
if github.repo != "" {
match["repo"] = expand(match, github.repo)
}
if github.check != nil {
if err := github.check(match); err != nil {
return nil, err
}
}
if match["vcs"] != vcsGit.cmd {
return nil, fmt.Errorf("vcs hatası")
}
// fmt.Printf("%s\n", github.ping)
if github.ping {
fmt.Printf("%s\n", "askn")
if scheme != "" {
match["repo"] = scheme + "://" + match["repo"]
} else {
for _, scheme := range vcsGit.scheme {
if vcsGit.ping(scheme, match["repo"]) == nil {
match["repo"] = scheme + "://" + match["repo"]
break
}
}
}
}
rr := &repoRoot{
vcs: vcsGit,
repo: match["repo"],
root: match["root"],
}
return rr, nil
}
// run1 is the generalized implementation of run and runOutput.
func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
m := make(map[string]string)
for i := 0; i < len(keyval); i += 2 {
m[keyval[i]] = keyval[i+1]
}
args := strings.Fields(cmdline)
for i, arg := range args {
args[i] = expand(m, arg)
}
cmd := exec.Command(v.cmd, args...)
cmd.Dir = dir
var buf bytes.Buffer
cmd.Stdout = &buf
cmd.Stderr = &buf
err := cmd.Run()
out := buf.Bytes()
if err != nil {
return nil, err
}
return out, nil
}
// ping pings to determine scheme to use.
func (v *vcsCmd) ping(scheme, repo string) error {
return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)
}
func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
_, err := v.run1(dir, cmd, keyval, false)
return err
}
func expand(match map[string]string, s string) string {
for k, v := range match {
s = strings.Replace(s, "{"+k+"}", v, -1)
}
return s
}
type vcsCmd struct {
name string
cmd string // name of binary to invoke command
createCmd string // command to download a fresh copy of a repository
downloadCmd string // command to download updates into an existing repository
scheme []string
pingCmd string
}
var vcsGit = &vcsCmd{
name: "Git",
cmd: "git",
createCmd: "clone {repo} {dir}",
downloadCmd: "fetch",
scheme: []string{"git", "https", "http", "git+ssh"},
pingCmd: "ls-remote {scheme}://{repo}",
}
func noVCSSuffix(match map[string]string) error {
repo := match["repo"]
if strings.HasSuffix(repo, "."+vcsGit.cmd) {
return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
}
return nil
}
func x(url string) error {
rr, e := git(url, "")
if e != nil {
return e
}
// fmt.Println(rr)
vcs, repo, rootPath := rr.vcs, rr.repo, rr.root
root := filepath.Join(SRCDIR, rootPath)
meta := filepath.Join(root, "."+vcs.cmd)
st, e := os.Stat(meta)
if e != nil {
if _, err := os.Stat(root); err == nil {
return fmt.Errorf("checkout %s", st)
}
parent, _ := filepath.Split(root)
if err := os.MkdirAll(parent, 0777); err != nil {
return err
}
if err := vcs.create(root, repo); err != nil {
return err
}
} else {
// Metadata directory does exist; download incremental updates.
if err := vcs.download(root); err != nil {
return err
}
}
return nil
}
func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {
_, err := v.run1(dir, cmd, keyval, true)
return err
}
// create creates a new copy of repo in dir.
// The parent of dir must exist; dir must not.
func (v *vcsCmd) create(dir, repo string) error {
return v.run(".", v.createCmd, "dir", dir, "repo", repo)
}
// download downloads any new changes for the repo in dir.
func (v *vcsCmd) download(dir string) error {
return v.run(dir, v.downloadCmd)
}
func main() {
// fmt.Println(len(os.Args))
if len(os.Args) == 2 {
// e := x("github.com/askn/go_examples")
e := x(os.Args[1])
if e != nil {
fmt.Println(e)
}
} else {
fmt.Println("usage: program_name github.com/foo/bar")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment