mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-15 23:03:40 +00:00
contrib/git-sync: remove sync loop, simplify logic
This commit is contained in:
parent
79dd775d72
commit
0415b63ab4
@ -1,6 +1,6 @@
|
|||||||
# git-sync
|
# 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.
|
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
|
# build the container
|
||||||
docker build -t git-sync .
|
docker build -t git-sync .
|
||||||
# run the git-sync container
|
# 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
|
# 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
|
||||||
```
|
```
|
||||||
|
@ -14,27 +14,24 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
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 (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var interval = flag.String("interval", env("GIT_SYNC_INTERVAL", "60s"), "git pull interval")
|
var flRepo = flag.String("repo", env("GIT_SYNC_REPO", ""), "git repo url")
|
||||||
var repo = flag.String("repo", env("GIT_SYNC_REPO", ""), "git repo url")
|
var flBranch = flag.String("branch", env("GIT_SYNC_BRANCH", "master"), "git branch")
|
||||||
var branch = flag.String("branch", env("GIT_SYNC_BRANCH", "master"), "git branch")
|
var flRev = flag.String("rev", env("GIT_SYNC_BRANCH", "HEAD"), "git rev")
|
||||||
var handler = flag.String("handler", env("GIT_SYNC_HANDLER", "/"), "web hook handler")
|
var flDest = flag.String("dest", env("GIT_SYNC_DEST", ""), "destination path")
|
||||||
var dest = flag.String("dest", env("GIT_SYNC_DEST", ""), "destination path")
|
|
||||||
|
|
||||||
func env(key, def string) string {
|
func env(key, def string) string {
|
||||||
if env := os.Getenv(key); env != "" {
|
if env := os.Getenv(key); env != "" {
|
||||||
@ -43,125 +40,55 @@ func env(key, def string) string {
|
|||||||
return def
|
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() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *repo == "" || *dest == "" {
|
if *flRepo == "" || *flDest == "" {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
log.Fatal(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 {
|
if _, err := exec.LookPath("git"); err != nil {
|
||||||
log.Fatalf("required git executable not found: %v", err)
|
log.Fatalf("required git executable not found: %v", err)
|
||||||
}
|
}
|
||||||
repo, err := NewRepo()
|
if err := syncRepo(*flRepo, *flDest, *flBranch, *flRev); err != nil {
|
||||||
if err != nil {
|
log.Fatalf("error syncing repo: %v", err)
|
||||||
log.Fatalf("error creating repo: %v", err)
|
|
||||||
}
|
}
|
||||||
syncc := make(chan struct{})
|
}
|
||||||
tick := time.Tick(pullInterval)
|
|
||||||
go func() {
|
// syncRepo syncs the branch of a given repository to the destination at the given rev.
|
||||||
for {
|
func syncRepo(repo, dest, branch, rev string) error {
|
||||||
repo.Sync()
|
gitRepoPath := path.Join(dest, ".git")
|
||||||
select {
|
_, err := os.Stat(gitRepoPath)
|
||||||
case <-tick:
|
switch {
|
||||||
case <-syncc:
|
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))
|
||||||
}
|
}
|
||||||
}()
|
log.Printf("clone %q: %s", repo, string(output))
|
||||||
http.HandleFunc(*handler, func(w http.ResponseWriter, r *http.Request) {
|
case err != nil:
|
||||||
syncc <- struct{}{}
|
return fmt.Errorf("error checking if repo exist %q: %v", gitRepoPath, err)
|
||||||
})
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
return nil, fmt.Errorf("error checking repo %q: %v", mirrorRepoPath, err)
|
// fetch branch
|
||||||
}
|
cmd := exec.Command("git", "fetch", "origin", branch)
|
||||||
cmd := exec.Command("git", "clone", "--mirror", "-b", *branch, *repo, mirrorRepoPath)
|
cmd.Dir = dest
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
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))
|
log.Printf("fetch %q: %s", branch, string(output))
|
||||||
return &Repo{
|
|
||||||
basePath: *dest,
|
|
||||||
mirrorPath: mirrorRepoPath,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync fetch new revision from the origin remote in the bare repository
|
// reset working copy
|
||||||
// create a new checkout named after the revision
|
cmd = exec.Command("git", "reset", "--hard", rev)
|
||||||
// update HEAD symlink to point to the new revision
|
cmd.Dir = dest
|
||||||
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
|
|
||||||
output, err = cmd.CombinedOutput()
|
output, err = cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error running command %q: %v", strings.Join(cmd.Args, " "), err)
|
return fmt.Errorf("error running command %q : %v: %s", strings.Join(cmd.Args, " "), err, string(output))
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
log.Printf("reset %q: %v", rev, string(output))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user