From 0415b63ab49310a23b9296e65447fbb297cbb099 Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Thu, 29 Jan 2015 15:39:51 -0800 Subject: [PATCH] contrib/git-sync: remove sync loop, simplify logic --- contrib/git-sync/README.md | 6 +- contrib/git-sync/main.go | 149 ++++++++++--------------------------- 2 files changed, 41 insertions(+), 114 deletions(-) diff --git a/contrib/git-sync/README.md b/contrib/git-sync/README.md index 52bf2c655d9..f8faa4a0cd1 100644 --- a/contrib/git-sync/README.md +++ b/contrib/git-sync/README.md @@ -1,6 +1,6 @@ # git-sync -git-sync is a command that periodically sync a git repository to a local directory. +git-sync is a command that pull a git repository to a local directory. It can be used to source a container volume with the content of a git repo. @@ -10,7 +10,7 @@ It can be used to source a container volume with the content of a git repo. # build the container docker build -t git-sync . # run the git-sync container -docker run -d -e GIT_SYNC_INTERVAL=1s -e GIT_SYNC_REPO=https://github.com/GoogleCloudPlatform/kubernetes -e GIT_SYNC_BRANCH=gh-pages -v /git-data:/git git-sync +docker run -d GIT_SYNC_REPO=https://github.com/GoogleCloudPlatform/kubernetes -e GIT_SYNC_BRANCH=gh-pages -r HEAD -v /git-data:/git git-sync # run a nginx container to serve sync'ed content -docker run -d -p 8080:80 -v /git-data/HEAD:/usr/share/nginx/html nginx +docker run -d -p 8080:80 -v /git-data:/usr/share/nginx/html nginx ``` diff --git a/contrib/git-sync/main.go b/contrib/git-sync/main.go index b0aff6179b5..355c0e1bc7e 100644 --- a/contrib/git-sync/main.go +++ b/contrib/git-sync/main.go @@ -14,27 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -// git-sync is a command that periodically sync a git repository to a local directory. +// git-sync is a command that pull a git repository to a local directory. -package main // import "github.com/GoogleCloudPlatform/kubernetes/git-sync" +package main // import "github.com/GoogleCloudPlatform/kubernetes/contrib/git-sync" import ( "flag" "fmt" "log" - "net/http" "os" "os/exec" "path" "strings" - "time" ) -var interval = flag.String("interval", env("GIT_SYNC_INTERVAL", "60s"), "git pull interval") -var repo = flag.String("repo", env("GIT_SYNC_REPO", ""), "git repo url") -var branch = flag.String("branch", env("GIT_SYNC_BRANCH", "master"), "git branch") -var handler = flag.String("handler", env("GIT_SYNC_HANDLER", "/"), "web hook handler") -var dest = flag.String("dest", env("GIT_SYNC_DEST", ""), "destination path") +var flRepo = flag.String("repo", env("GIT_SYNC_REPO", ""), "git repo url") +var flBranch = flag.String("branch", env("GIT_SYNC_BRANCH", "master"), "git branch") +var flRev = flag.String("rev", env("GIT_SYNC_BRANCH", "HEAD"), "git rev") +var flDest = flag.String("dest", env("GIT_SYNC_DEST", ""), "destination path") func env(key, def string) string { if env := os.Getenv(key); env != "" { @@ -43,125 +40,55 @@ func env(key, def string) string { return def } -const usage = "usage: GIT_SYNC_REPO= GIT_SYNC_DEST= [GIT_SYNC_INTERVAL= GIT_SYNC_BRANCH= GIT_SYNC_HANDLER=] git-sync -repo GIT_REPO_URL -dest PATH [-interval -branch -handler]" +const usage = "usage: GIT_SYNC_REPO= GIT_SYNC_DEST= [GIT_SYNC_BRANCH=] git-sync -repo GIT_REPO_URL -dest PATH [-branch]" func main() { flag.Parse() - if *repo == "" || *dest == "" { + if *flRepo == "" || *flDest == "" { flag.Usage() log.Fatal(usage) } - pullInterval, err := time.ParseDuration(*interval) - if err != nil { - log.Fatalf("error parsing time duration %q: %v", *interval, err) - } if _, err := exec.LookPath("git"); err != nil { log.Fatalf("required git executable not found: %v", err) } - repo, err := NewRepo() - if err != nil { - log.Fatalf("error creating repo: %v", err) + if err := syncRepo(*flRepo, *flDest, *flBranch, *flRev); err != nil { + log.Fatalf("error syncing repo: %v", err) } - syncc := make(chan struct{}) - tick := time.Tick(pullInterval) - go func() { - for { - repo.Sync() - select { - case <-tick: - case <-syncc: - } +} + +// syncRepo syncs the branch of a given repository to the destination at the given rev. +func syncRepo(repo, dest, branch, rev string) error { + gitRepoPath := path.Join(dest, ".git") + _, err := os.Stat(gitRepoPath) + switch { + case os.IsNotExist(err): + // clone repo + cmd := exec.Command("git", "clone", "--no-checkout", "-b", branch, repo, dest) + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("error cloning repo %q: %v: %s", strings.Join(cmd.Args, " "), err, string(output)) } - }() - http.HandleFunc(*handler, func(w http.ResponseWriter, r *http.Request) { - syncc <- struct{}{} - }) - log.Fatal(http.ListenAndServe(":8080", nil)) -} - -type Repo struct { - basePath string - mirrorPath string - lastRev string -} - -// NewRepo initalize a local bare repository mirror. -func NewRepo() (*Repo, error) { - mirrorRepoPath := path.Join(*dest, ".git") - _, err := os.Stat(mirrorRepoPath) - if err == nil { - log.Printf("found existing mirror repo %q", mirrorRepoPath) - return &Repo{ - basePath: *dest, - mirrorPath: mirrorRepoPath, - }, nil + log.Printf("clone %q: %s", repo, string(output)) + case err != nil: + return fmt.Errorf("error checking if repo exist %q: %v", gitRepoPath, err) } - if !os.IsNotExist(err) { - return nil, fmt.Errorf("error checking repo %q: %v", mirrorRepoPath, err) - } - cmd := exec.Command("git", "clone", "--mirror", "-b", *branch, *repo, mirrorRepoPath) + + // fetch branch + cmd := exec.Command("git", "fetch", "origin", branch) + cmd.Dir = dest output, err := cmd.CombinedOutput() if err != nil { - return nil, fmt.Errorf("error cloning repo %q: %v:", strings.Join(cmd.Args, " "), err) + return fmt.Errorf("error running command %q: %v: %s", strings.Join(cmd.Args, " "), err, string(output)) } - log.Printf("clone %q: %s", *repo, string(output)) - return &Repo{ - basePath: *dest, - mirrorPath: mirrorRepoPath, - }, nil -} + log.Printf("fetch %q: %s", branch, string(output)) -// Sync fetch new revision from the origin remote in the bare repository -// create a new checkout named after the revision -// update HEAD symlink to point to the new revision -func (r *Repo) Sync() { - cmd := exec.Command("git", "fetch", "origin", *branch) - cmd.Dir = r.mirrorPath - output, err := cmd.CombinedOutput() - if err != nil { - log.Printf("error running command %q: %v", strings.Join(cmd.Args, " "), err) - return - } - log.Printf("fetch: %s", string(output)) - cmd = exec.Command("git", "rev-parse", "HEAD") - cmd.Dir = r.mirrorPath + // reset working copy + cmd = exec.Command("git", "reset", "--hard", rev) + cmd.Dir = dest output, err = cmd.CombinedOutput() if err != nil { - log.Printf("error running command %q: %v", strings.Join(cmd.Args, " "), err) - return - } - rev := strings.TrimSpace(string(output)) - if rev == r.lastRev { - log.Printf("no new rev since last check %q", rev) - return - } - r.lastRev = rev - log.Printf("HEAD is: %q", rev) - repoPath := path.Join(r.basePath, rev) - _, err = os.Stat(repoPath) - if err == nil { - log.Printf("found existing repo: %q", repoPath) - return - } - if !os.IsNotExist(err) { - log.Printf("error stating repo %q: %v", repoPath, err) - return - } - cmd = exec.Command("git", "clone", r.mirrorPath, repoPath) - output, err = cmd.CombinedOutput() - if err != nil { - log.Printf("error running command %q : %v", strings.Join(cmd.Args, " "), err) - return - } - log.Printf("clone %q: %v", repoPath, string(output)) - tempPath := path.Join(r.basePath, "HEAD."+rev) - if err := os.Symlink(rev, tempPath); err != nil { - log.Printf("error creating temporary symlink %q: %v", tempPath, err) - return - } - linkPath := path.Join(r.basePath, "HEAD") - if err := os.Rename(tempPath, linkPath); err != nil { - log.Printf("error moving symlink %q: %v", linkPath, err) - return + return fmt.Errorf("error running command %q : %v: %s", strings.Join(cmd.Args, " "), err, string(output)) } + log.Printf("reset %q: %v", rev, string(output)) + return nil }