filemanager/gitwrapper.go (113 lines of code) (raw):
package filemanager
import (
"fmt"
"net/http"
"os"
"os/exec"
"strings"
)
var gitBinaryPath string
func gitPath() (string, error) {
if gitBinaryPath == "" {
resolvedPath, err := exec.LookPath("git")
if err != nil {
return "", err
}
gitBinaryPath = resolvedPath
}
return gitBinaryPath, nil
}
func (fm *FileManager) isGitRepository() *Error {
fi, err := os.Stat(fm.Path)
if os.IsNotExist(err) {
return &Error{code: http.StatusNotFound, err: fmt.Errorf("the path does not exist")}
}
if err != nil {
return &Error{code: http.StatusUnprocessableEntity, err: err}
}
if !fi.Mode().IsDir() {
return &Error{code: http.StatusUnprocessableEntity, err: fmt.Errorf("the path must be a directory")}
}
if err := fm.runGitRepositoryCheck(); err != nil {
return err
}
return nil
}
func (fm *FileManager) runGitRepositoryCheck() *Error {
cmd, customErr := fm.buildGitCommand("rev-parse", "--is-inside-work-tree")
if customErr != nil {
return customErr
}
if err := cmd.Run(); err != nil {
return &Error{code: http.StatusUnprocessableEntity, err: fmt.Errorf("the path is not a git repository")}
}
return nil
}
func (fm *FileManager) runGitFilesCheckout() *Error {
cmd, customErr := fm.buildGitCommand("checkout", ".")
if customErr != nil {
return customErr
}
if err := cmd.Run(); err != nil {
return &Error{code: http.StatusUnprocessableEntity, err: fmt.Errorf("error checking out files")}
}
return nil
}
func (fm *FileManager) runGitApply(diff string, check bool) *Error {
args := []string{"apply", "--cached"}
if check {
args = append(args, "--check")
}
cmd, customErr := fm.buildGitCommand(args...)
if customErr != nil {
return customErr
}
cmd.Stdin = strings.NewReader(diff)
if err := cmd.Run(); err != nil {
return &Error{code: http.StatusUnprocessableEntity, err: fmt.Errorf("error applying the patch")}
}
return nil
}
func (fm *FileManager) runGitResetHard() *Error {
args := []string{"reset", "--hard", "HEAD"}
cmd, customErr := fm.buildGitCommand(args...)
if customErr != nil {
return customErr
}
if err := cmd.Run(); err != nil {
return &Error{code: http.StatusUnprocessableEntity, err: fmt.Errorf("error resetting the repository")}
}
return nil
}
func (fm *FileManager) runCleanRepository() *Error {
cmd, customErr := fm.buildGitCommand("clean", "-ffdx")
if customErr != nil {
return customErr
}
if err := cmd.Run(); err != nil {
return &Error{code: http.StatusUnprocessableEntity, err: fmt.Errorf("error cleaning the repository")}
}
return nil
}
func (fm *FileManager) buildGitCommand(args ...string) (*exec.Cmd, *Error) {
gitBinary, err := gitPath()
if err != nil {
return nil, &Error{code: http.StatusInternalServerError, err: err}
}
cmd := exec.Command(gitBinary, args...)
cmd.Dir = fm.Path
return cmd, nil
}
func (fm *FileManager) runGitDelete(paths []string) *Error {
if len(paths) == 0 {
return nil
}
// Force flag is to delete files that have been already modified and cached
// Recursive flag is used to remove directories
cmd, customErr := fm.buildGitCommand(append([]string{"rm", "--force", "-r"}, paths...)...)
if customErr != nil {
return customErr
}
if err := cmd.Run(); err != nil {
return &Error{code: http.StatusUnprocessableEntity, err: fmt.Errorf("error deleting the files")}
}
return nil
}