|  | @@ -12,18 +12,29 @@ import (
 | 
	
		
			
			| 12 | 12 |  	gitssh "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh"
 | 
	
		
			
			| 13 | 13 |  )
 | 
	
		
			
			| 14 | 14 |  
 | 
	
		
			
			| 15 |  | -// Sync
 | 
	
		
			
			|  | 15 | +// Sync synchronises a Git repository using a given configuration. "synchronises"
 | 
	
		
			
			|  | 16 | +// means that, if the repo from the configuration isn't already cloned in the
 | 
	
		
			
			|  | 17 | +// directory specified in the configuration, it will clone the repository,
 | 
	
		
			
			|  | 18 | +// else it will simply pull it in order to be up to date with the remote.
 | 
	
		
			
			|  | 19 | +// Returns the go-git representation of the repository.
 | 
	
		
			
			|  | 20 | +// Returns an error if there was an issue loading the SSH private key, checking
 | 
	
		
			
			|  | 21 | +// whether the clone path already exists, or synchronising the repo with the
 | 
	
		
			
			|  | 22 | +// remote.
 | 
	
		
			
			| 16 | 23 |  func Sync(cfg config.GitSettings) (r *gogit.Repository, err error) {
 | 
	
		
			
			|  | 24 | +	// Generate an authentication structure instance from the user and private
 | 
	
		
			
			|  | 25 | +	// key
 | 
	
		
			
			| 17 | 26 |  	auth, err := getAuth(cfg.User, cfg.PrivateKeyPath)
 | 
	
		
			
			| 18 | 27 |  	if err != nil {
 | 
	
		
			
			| 19 | 28 |  		return
 | 
	
		
			
			| 20 | 29 |  	}
 | 
	
		
			
			| 21 | 30 |  
 | 
	
		
			
			|  | 31 | +	// Check whether the clone path already exists
 | 
	
		
			
			| 22 | 32 |  	exists, err := dirExists(cfg.ClonePath)
 | 
	
		
			
			| 23 | 33 |  	if err != nil {
 | 
	
		
			
			| 24 | 34 |  		return
 | 
	
		
			
			| 25 | 35 |  	}
 | 
	
		
			
			| 26 | 36 |  
 | 
	
		
			
			|  | 37 | +	// If the clone path already exists, pull from the remote, else clone it.
 | 
	
		
			
			| 27 | 38 |  	if exists {
 | 
	
		
			
			| 28 | 39 |  		r, err = pull(cfg.ClonePath, auth)
 | 
	
		
			
			| 29 | 40 |  	} else {
 | 
	
	
		
			
			|  | @@ -33,6 +44,10 @@ func Sync(cfg config.GitSettings) (r *gogit.Repository, err error) {
 | 
	
		
			
			| 33 | 44 |  	return
 | 
	
		
			
			| 34 | 45 |  }
 | 
	
		
			
			| 35 | 46 |  
 | 
	
		
			
			|  | 47 | +// getAuth returns the authentication structure instance needed to authenticate
 | 
	
		
			
			|  | 48 | +// on the remote, using a given user and private key path.
 | 
	
		
			
			|  | 49 | +// Returns an error if there was an issue reading the private key file or
 | 
	
		
			
			|  | 50 | +// parsing it.
 | 
	
		
			
			| 36 | 51 |  func getAuth(user string, privateKeyPath string) (*gitssh.PublicKeys, error) {
 | 
	
		
			
			| 37 | 52 |  	privateKey, err := ioutil.ReadFile(privateKeyPath)
 | 
	
		
			
			| 38 | 53 |  	if err != nil {
 | 
	
	
		
			
			|  | @@ -47,6 +62,9 @@ func getAuth(user string, privateKeyPath string) (*gitssh.PublicKeys, error) {
 | 
	
		
			
			| 47 | 62 |  	return &gitssh.PublicKeys{User: "git", Signer: signer}, nil
 | 
	
		
			
			| 48 | 63 |  }
 | 
	
		
			
			| 49 | 64 |  
 | 
	
		
			
			|  | 65 | +// clone clones a Git repository into a given path, using a given auth.
 | 
	
		
			
			|  | 66 | +// Returns the go-git representation of the Git repository.
 | 
	
		
			
			|  | 67 | +// Returns an error if there was an issue cloning the repository.
 | 
	
		
			
			| 50 | 68 |  func clone(repo string, clonePath string, auth *gitssh.PublicKeys) (*gogit.Repository, error) {
 | 
	
		
			
			| 51 | 69 |  	return gogit.PlainClone(clonePath, false, &gogit.CloneOptions{
 | 
	
		
			
			| 52 | 70 |  		URL:  repo,
 | 
	
	
		
			
			|  | @@ -54,22 +72,33 @@ func clone(repo string, clonePath string, auth *gitssh.PublicKeys) (*gogit.Repos
 | 
	
		
			
			| 54 | 72 |  	})
 | 
	
		
			
			| 55 | 73 |  }
 | 
	
		
			
			| 56 | 74 |  
 | 
	
		
			
			|  | 75 | +// pull opens the repository located at a given path, and pulls it from the
 | 
	
		
			
			|  | 76 | +// remote using a given auth, in order to be up to date with the remote.
 | 
	
		
			
			|  | 77 | +// Returns with the go-git representation of the repository.
 | 
	
		
			
			|  | 78 | +// Returns an error if there was an issue opening the repo, getting its work
 | 
	
		
			
			|  | 79 | +// tree or pulling from the remote. In the latter case, if the error is "already
 | 
	
		
			
			|  | 80 | +// up to date" or "non-fast-forward update", doesn't return any error.
 | 
	
		
			
			| 57 | 81 |  func pull(clonePath string, auth *gitssh.PublicKeys) (*gogit.Repository, error) {
 | 
	
		
			
			|  | 82 | +	// Open the repository
 | 
	
		
			
			| 58 | 83 |  	r, err := gogit.PlainOpen(clonePath)
 | 
	
		
			
			| 59 | 84 |  	if err != nil {
 | 
	
		
			
			| 60 | 85 |  		return nil, err
 | 
	
		
			
			| 61 | 86 |  	}
 | 
	
		
			
			| 62 | 87 |  
 | 
	
		
			
			|  | 88 | +	// Get its worktree
 | 
	
		
			
			| 63 | 89 |  	w, err := r.Worktree()
 | 
	
		
			
			| 64 | 90 |  	if err != nil {
 | 
	
		
			
			| 65 | 91 |  		return nil, err
 | 
	
		
			
			| 66 | 92 |  	}
 | 
	
		
			
			| 67 | 93 |  
 | 
	
		
			
			|  | 94 | +	// Pull from remote
 | 
	
		
			
			| 68 | 95 |  	err = w.Pull(&gogit.PullOptions{
 | 
	
		
			
			| 69 | 96 |  		RemoteName: "origin",
 | 
	
		
			
			| 70 | 97 |  		Auth:       auth,
 | 
	
		
			
			| 71 | 98 |  	})
 | 
	
		
			
			| 72 | 99 |  
 | 
	
		
			
			|  | 100 | +	// Don't return with an error for "already up to date" or "non-fast-forward
 | 
	
		
			
			|  | 101 | +	// update"
 | 
	
		
			
			| 73 | 102 |  	if err != nil {
 | 
	
		
			
			| 74 | 103 |  		if err == gogit.NoErrAlreadyUpToDate {
 | 
	
		
			
			| 75 | 104 |  			return r, nil
 | 
	
	
		
			
			|  | @@ -85,6 +114,10 @@ func pull(clonePath string, auth *gitssh.PublicKeys) (*gogit.Repository, error)
 | 
	
		
			
			| 85 | 114 |  	return r, err
 | 
	
		
			
			| 86 | 115 |  }
 | 
	
		
			
			| 87 | 116 |  
 | 
	
		
			
			|  | 117 | +// dirExists is a snippet checking if a directory exists on the disk.
 | 
	
		
			
			|  | 118 | +// Returns with a boolean set to true if the directory exists, false if not.
 | 
	
		
			
			|  | 119 | +// Returns with an error if there was an issue checking the directory's
 | 
	
		
			
			|  | 120 | +// existence.
 | 
	
		
			
			| 88 | 121 |  func dirExists(path string) (bool, error) {
 | 
	
		
			
			| 89 | 122 |  	_, err := os.Stat(path)
 | 
	
		
			
			| 90 | 123 |  
 | 
	
	
		
			
			|  | @@ -95,6 +128,12 @@ func dirExists(path string) (bool, error) {
 | 
	
		
			
			| 95 | 128 |  	return true, err
 | 
	
		
			
			| 96 | 129 |  }
 | 
	
		
			
			| 97 | 130 |  
 | 
	
		
			
			|  | 131 | +// Push uses a given repository and configuration to push the local history of
 | 
	
		
			
			|  | 132 | +// the said repository to the remote, using an authentication structure instance
 | 
	
		
			
			|  | 133 | +// created from the configuration to authenticate on the remote.
 | 
	
		
			
			|  | 134 | +// Returns with an error if there was an issue creating the authentication
 | 
	
		
			
			|  | 135 | +// structure instance or pushing to the remote. In the latter case, if the error
 | 
	
		
			
			|  | 136 | +// is "already up to date" or "non-fast-forward update", doesn't return any error.
 | 
	
		
			
			| 98 | 137 |  func Push(r *gogit.Repository, cfg config.GitSettings) error {
 | 
	
		
			
			| 99 | 138 |  	auth, err := getAuth(cfg.User, cfg.PrivateKeyPath)
 | 
	
		
			
			| 100 | 139 |  	if err != nil {
 |