-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathbackup.go
More file actions
138 lines (119 loc) · 3.75 KB
/
backup.go
File metadata and controls
138 lines (119 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import (
"fmt"
"log"
"net/url"
"os/exec"
"path"
"sync"
"github.com/mitchellh/go-homedir"
"github.com/spf13/afero"
)
// We have them here so that we can override these in the tests
var execCommand = exec.Command
var appFS = afero.NewOsFs()
var gitCommand = "git"
var gethomeDir = homedir.Dir
var lookPath = exec.LookPath
// checkGitAvailability verifies that the git command is available in the system PATH
func checkGitAvailability() error {
_, err := lookPath(gitCommand)
if err != nil {
return fmt.Errorf("git command not found in PATH. Please install git to use gitbackup. Visit https://git-scm.com/downloads for installation instructions")
}
return nil
}
// Check if we have a copy of the repo already, if
// we do, we update the repo, else we do a fresh clone
func backUp(backupDir string, repo *Repository, bare bool, wg *sync.WaitGroup) ([]byte, error) {
defer wg.Done()
repoDir := getRepoDir(backupDir, repo, bare)
_, err := appFS.Stat(repoDir)
var stdoutStderr []byte
if err == nil {
stdoutStderr, err = updateExistingRepo(repoDir, repo.Name, bare)
} else {
stdoutStderr, err = cloneNewRepo(repoDir, repo, bare)
}
return stdoutStderr, err
}
// getRepoDir returns the directory path for a repository
func getRepoDir(backupDir string, repo *Repository, bare bool) string {
var dirName string
if bare {
dirName = repo.Name + ".git"
} else {
dirName = repo.Name
}
return path.Join(backupDir, repo.Namespace, dirName)
}
// updateExistingRepo updates an existing repository
func updateExistingRepo(repoDir, repoName string, bare bool) ([]byte, error) {
log.Printf("%s exists, updating. \n", repoName)
var cmd *exec.Cmd
if bare {
cmd = execCommand(gitCommand, "-C", repoDir, "remote", "update", "--prune")
} else {
cmd = execCommand(gitCommand, "-C", repoDir, "pull")
}
return cmd.CombinedOutput()
}
// cloneNewRepo clones a new repository
func cloneNewRepo(repoDir string, repo *Repository, bare bool) ([]byte, error) {
log.Printf("Cloning %s\n", repo.Name)
log.Printf("%#v\n", repo)
if repo.Private && ignorePrivate != nil && *ignorePrivate {
log.Printf("Skipping %s as it is a private repo.\n", repo.Name)
return nil, nil
}
cloneURL := repo.CloneURL
if useHTTPSClone != nil && *useHTTPSClone {
// Add username and token to the clone URL
// https://gitlab.com/amitsaha/testproject1 => https://amitsaha:token@gitlab.com/amitsaha/testproject1
u, err := url.Parse(repo.CloneURL)
if err != nil {
log.Fatalf("Invalid clone URL: %v\n", err)
}
cloneURL = u.Scheme + "://" + gitHostUsername + ":" + gitHostToken + "@" + u.Host + u.Path
}
var cmd *exec.Cmd
if bare {
cmd = execCommand(gitCommand, "clone", "--mirror", cloneURL, repoDir)
} else {
cmd = execCommand(gitCommand, "clone", cloneURL, repoDir)
}
return cmd.CombinedOutput()
}
// setupBackupDir determines and creates the backup directory path
// It uses the provided backupDir if set, otherwise defaults to ~/.gitbackup/<githost>
func setupBackupDir(backupDir, service, githostURL *string) string {
var gitHost, backupPath string
var err error
if len(*githostURL) != 0 {
u, err := url.Parse(*githostURL)
if err != nil {
panic(err)
}
gitHost = u.Host
} else {
gitHost = knownServices[*service]
}
if len(*backupDir) == 0 {
homeDir, err := gethomeDir()
if err == nil {
backupPath = path.Join(homeDir, ".gitbackup", gitHost)
} else {
log.Fatal("Could not determine home directory and backup directory not specified")
}
} else {
backupPath = path.Join(*backupDir, gitHost)
}
err = createBackupRootDirIfRequired(backupPath)
if err != nil {
log.Fatalf("Error creating backup directory: %s %v", backupPath, err)
}
return backupPath
}
func createBackupRootDirIfRequired(backupPath string) error {
return appFS.MkdirAll(backupPath, 0771)
}