src-d/gogit使用

14190 ワード

次はコードの様子で、フォルダとファイルを追加して、フォルダを削除して、commit、pushを含みます
package ormopt
import (
	"strings"
	"fmt"
	git "gopkg.in/src-d/go-git.v4"
	. "gopkg.in/src-d/go-git.v4/_examples"
	"gopkg.in/src-d/go-git.v4/plumbing/object"
	githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
	"io/ioutil"
	"os"
	"path/filepath"
	"github.com/astaxie/beego"
	"time"
)

/**
* @author xiaolong.li
* @time 2018-09-10
* @desc        git 
*/
func GitAddFileAndCmmit (folder string, filePath string, fileName string, fileByte []byte) (error) {
	rootPath := beego.AppConfig.String("jksfile.dir")
	r, err := git.PlainOpen(rootPath)
	if err != nil {
		return err
	}

	w, err := r.Worktree()
	if err != nil {
		return err
	}

	directory := rootPath + filePath + "/"
	fileDir := directory
	exist, err := PathExists(fileDir)
	if err != nil {
		fmt.Println("PathExists.error:" + err.Error())
	}
	if !exist { //
		err = os.Mkdir(fileDir, os.ModePerm)
		if err != nil {
			return err
		}
	}

	if folder != "" {
	    fileDir = directory + folder + "/"
	    exist, err := PathExists(fileDir)
		if err != nil {
			fmt.Println("PathExists.error:" + err.Error())
		}
		if !exist { //
			err = os.Mkdir(fileDir, os.ModePerm)
			if err != nil {
				return err
			}
		}
	}
	
	filename := filepath.Join(fileDir, fileName)
	err = ioutil.WriteFile(filename, fileByte, 1024)
	if err != nil {
		return err
	}

	// Adds the new file to the staging area.
	Info("git add all files= " + filePath + "/")
	_, err = w.Add(filePath + "/")
	if err != nil {
		return err
	}

	// We can verify the current status of the worktree using the method Status.
	Info("git status --porcelain")
	_, err = w.Status()
	if err != nil {
		return err
	}

	Info("git commit -m \"create git-task commit\"")
	commit, err := w.Commit("create git-task commit", &git.CommitOptions{
		Author: &object.Signature{
			Name:  "pass-sys",
			Email: "pass-sys",
			When:  time.Now(),
		},
	})

	if err != nil {
		return err
	}

	// Prints the current HEAD to verify that all worked well.
	Info("git show -s")
	_, err = r.CommitObject(commit)
	//logs.Info(obj.ToString())
	if err != nil {
	   return err
	}
	return nil
}


/**
* @author xiaolong.li
* @time 2018-09-10
* @desc     git      
*/
func DelGitFiles(directory string) (error) {
	path := beego.AppConfig.String("jksfile.dir")
	// Opens an already existent repository.
	r, err := git.PlainOpen(path)
	if err != nil {
		return err
	}

	w, err := r.Worktree()
	if err != nil {
		return err
	}

	// del the file to the staging area.
	Info("git delete git-file")
	_, err = w.Remove(directory + "/")
	if err != nil {
		return err
	}

	// We can verify the current status of the worktree using the method Status.
	Info("git status --porcelain")
	status, err := w.Status()
	if err != nil {
		return err
	}

	fmt.Println(status)

	// Commits the current staging are to the repository, with the new file
	// just created. We should provide the object.Signature of Author of the
	// commit.
	Info("git commit -am \"delete go-git commit\"")
	commit, err := w.Commit("delete go-git commit", &git.CommitOptions{
		Author: &object.Signature{
			Name:  "pass-sys",
			Email: "pass-sys",
			When:  time.Now(),
		},
	})

	if err != nil {
		return err
	}

	// Prints the current HEAD to verify that all worked well.
	Info("git show -s")
	obj, err := r.CommitObject(commit)
	if err != nil {
		return err
	}

	fmt.Println(obj)
	return nil
}


/**
* @author xiaolong.li
* @time 2018-09-10
* @desc     git      
*/
func DelGitListFolder (listPath []string) (error) {
	path := beego.AppConfig.String("jksfile.dir")
	r, err := git.PlainOpen(path)
	if err != nil {
		return err
	}
	w, err := r.Worktree()
	if err != nil {
		return err
	}
	// del the file to the staging area.
	Info("git delete git-file")
	for _, filePath := range listPath {
		directory := path + filePath + "/"
		isExist, err := PathExists(directory)
		if err != nil {
		   fmt.Println("PathExists.error:" + err.Error())
	    }
		if isExist {
			_, err = w.Remove(filePath + "/")
			if err != nil {
				return err
			}
		}
	}
	// We can verify the current status of the worktree using the method Status.
	Info("git status --porcelain")
	_, err = w.Status()
	if err != nil {
		return err
	}

	Info("git commit -am \"delete go-git commit\"")
	commit, err := w.Commit("delete go-git commit", &git.CommitOptions{
		Author: &object.Signature{
			Name:  "pass-sys",
			Email: "pass-sys",
			When:  time.Now(),
		},
	})

	if err != nil {
		return err
	}

	// Prints the current HEAD to verify that all worked well.
	Info("git show -s")
	_, err = r.CommitObject(commit)
	if err != nil {
		return err
	}

	return nil
}

/**
* @author xiaolong.li
* @time 2018-09-10
* @desc push  git
*/
func GitPush () (error) {
	rootPath := beego.AppConfig.String("jksfile.dir")
	r, err := git.PlainOpen(rootPath)
	if err != nil {
		return err
	}

	Info("git push")
	//ssh agent
	//currentUser, err := user.Current()
	//sshAuth, err := ssh.NewPublicKeysFromFile("git", currentUser.HomeDir+"/.ssh/id_rsa", "")
	sshAuth := &githttp.BasicAuth{Username: beego.AppConfig.String("gitlab.user"), Password: beego.AppConfig.String("gitlab.password")}
	// push using default options
	err = r.Push(&git.PushOptions{
		Auth: sshAuth,
	})

	if err != nil {
	   errorMsg := err.Error()
	   if strings.Contains(errorMsg, "non-fast-forward") {
		  w, err := r.Worktree()
		  if err != nil {
		  	 fmt.Printf("git.Worktree.err=" + err.Error())
			 return err
		  }
	      err = w.Pull(&git.PullOptions{
			  RemoteName:        "origin",
			  RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
			  Auth:              sshAuth,
		  })
		  if err != nil {
		  	 fmt.Printf("git.pull.err=" + err.Error())
			 return err
		  }
		  //  push
		  err = r.Push(&git.PushOptions{
			 Auth: sshAuth,
		  })

		  if err != nil {
			 return err
		  }
		  return nil
		}
		return err
	}
	return nil
}
ファイルおよびディレクトリの追加は、WorkTreeのAdd()メソッドを呼び出すことです.まず、Addメソッドがどのファイルにあるかを見て、WorkTreeを見つけます.goにはありません.AddがLiteIDE(go開発のide)しか使用できないことをすばやく見つけるには、メソッドが存在するファイルworktree_に直接接続できます.status.go.
次にremoveメソッドがあります.
func (w *Worktree) Add(path string) (plumbing.Hash, error) {
	// TODO(mcuadros): remove plumbing.Hash from signature at v5.
	s, err := w.Status()
	if err != nil {
		return plumbing.ZeroHash, err
	}

	idx, err := w.r.Storer.Index()
	if err != nil {
		return plumbing.ZeroHash, err
	}

	var h plumbing.Hash
	var added bool

	fi, err := w.Filesystem.Lstat(path)
	if err != nil || !fi.IsDir() {
		added, h, err = w.doAddFile(idx, s, path)
	} else {
		added, err = w.doAddDirectory(idx, s, path)
	}

	if err != nil {
		return h, err
	}

	if !added {
		return h, nil
	}

	return h, w.r.Storer.SetIndex(idx)
}

func (w *Worktree) doAddDirectory(idx *index.Index, 
s Status, directory string) (added bool, err error) {
	files, err := w.Filesystem.ReadDir(directory)
	if err != nil {
		return false, err
	}

	for _, file := range files {
		name := path.Join(directory, file.Name())

		var a bool
		if file.IsDir() {
			if file.Name() == GitDirName {
				// ignore special git directory
				continue
			}
			a, err = w.doAddDirectory(idx, s, name)
		} else {
			a, _, err = w.doAddFile(idx, s, name)
		}

		if err != nil {
			return
		}

		if !added && a {
			added = true
		}
	}

	return
}

// AddGlob adds all paths, matching pattern, to the index. If pattern matches a
// directory path, all directory contents are added to the index recursively. No
// error is returned if all matching paths are already staged in index.
func (w *Worktree) AddGlob(pattern string) error {
	files, err := util.Glob(w.Filesystem, pattern)
	if err != nil {
		return err
	}

	if len(files) == 0 {
		return ErrGlobNoMatches
	}

	s, err := w.Status()
	if err != nil {
		return err
	}

	idx, err := w.r.Storer.Index()
	if err != nil {
		return err
	}

	var saveIndex bool
	for _, file := range files {
		fi, err := w.Filesystem.Lstat(file)
		if err != nil {
			return err
		}

		var added bool
		if fi.IsDir() {
			added, err = w.doAddDirectory(idx, s, file)
		} else {
			added, _, err = w.doAddFile(idx, s, file)
		}

		if err != nil {
			return err
		}

		if !saveIndex && added {
			saveIndex = true
		}
	}

	if saveIndex {
		return w.r.Storer.SetIndex(idx)
	}

	return nil
}

// doAddFile create a new blob from path and update the index, added is true if
// the file added is different from the index.
func (w *Worktree) doAddFile(idx *index.Index, 
s Status, path string) (added bool, h plumbing.Hash, err error) {
	if s.File(path).Worktree == Unmodified {
		return false, h, nil
	}

	h, err = w.copyFileToStorage(path)
	if err != nil {
		if os.IsNotExist(err) {
			added = true
			h, err = w.deleteFromIndex(idx, path)
		}

		return
	}

	if err := w.addOrUpdateFileToIndex(idx, path, h); err != nil {
		return false, h, err
	}

	return true, h, err
}

func (w *Worktree) copyFileToStorage(path string) 
(hash plumbing.Hash, err error) {
	fi, err := w.Filesystem.Lstat(path)
	if err != nil {
		return plumbing.ZeroHash, err
	}

	obj := w.r.Storer.NewEncodedObject()
	obj.SetType(plumbing.BlobObject)
	obj.SetSize(fi.Size())

	writer, err := obj.Writer()
	if err != nil {
		return plumbing.ZeroHash, err
	}

	defer ioutil.CheckClose(writer, &err)

	if fi.Mode()&os.ModeSymlink != 0 {
		err = w.fillEncodedObjectFromSymlink(writer, path, fi)
	} else {
		err = w.fillEncodedObjectFromFile(writer, path, fi)
	}

	if err != nil {
		return plumbing.ZeroHash, err
	}

	return w.r.Storer.SetEncodedObject(obj)
}

func (w *Worktree) fillEncodedObjectFromFile(dst io.Writer,
 path string, fi os.FileInfo) (err error) {
	src, err := w.Filesystem.Open(path)
	if err != nil {
		return err
	}

	defer ioutil.CheckClose(src, &err)

	if _, err := io.Copy(dst, src); err != nil {
		return err
	}

	return err
}

func (w *Worktree) fillEncodedObjectFromSymlink(dst io.Writer, path string, 
fi os.FileInfo) error {
	target, err := w.Filesystem.Readlink(path)
	if err != nil {
		return err
	}

	_, err = dst.Write([]byte(target))
	return err
}

func (w *Worktree) addOrUpdateFileToIndex(idx *index.Index, filename string,
 h plumbing.Hash) error {
	e, err := idx.Entry(filename)
	if err != nil && err != index.ErrEntryNotFound {
		return err
	}

	if err == index.ErrEntryNotFound {
		return w.doAddFileToIndex(idx, filename, h)
	}

	return w.doUpdateFileToIndex(e, filename, h)
}

func (w *Worktree) doAddFileToIndex(idx *index.Index, 
filename string, h plumbing.Hash) error {
	return w.doUpdateFileToIndex(idx.Add(filename), filename, h)
}

func (w *Worktree) doUpdateFileToIndex(e *index.Entry, filename string,
 h plumbing.Hash) error {
	info, err := w.Filesystem.Lstat(filename)
	if err != nil {
		return err
	}

	e.Hash = h
	e.ModifiedAt = info.ModTime()
	e.Mode, err = filemode.NewFromOSFileMode(info.Mode())
	if err != nil {
		return err
	}

	if e.Mode.IsRegular() {
		e.Size = uint32(info.Size())
	}

	fillSystemInfo(e, info.Sys())
	return nil
}

// Remove removes files from the working tree and from the index.
func (w *Worktree) Remove(path string) (plumbing.Hash, error) {
	// TODO(mcuadros): remove plumbing.Hash from signature at v5.
	idx, err := w.r.Storer.Index()
	if err != nil {
		return plumbing.ZeroHash, err
	}

	var h plumbing.Hash

	fi, err := w.Filesystem.Lstat(path)
	if err != nil || !fi.IsDir() {
		h, err = w.doRemoveFile(idx, path)
	} else {
		_, err = w.doRemoveDirectory(idx, path)
	}
	if err != nil {
		return h, err
	}

	return h, w.r.Storer.SetIndex(idx)
}

func (w *Worktree) doRemoveDirectory(idx *index.Index, 
directory string) (removed bool, err error) {
	files, err := w.Filesystem.ReadDir(directory)
	if err != nil {
		return false, err
	}

	for _, file := range files {
		name := path.Join(directory, file.Name())

		var r bool
		if file.IsDir() {
			r, err = w.doRemoveDirectory(idx, name)
		} else {
			_, err = w.doRemoveFile(idx, name)
			if err == index.ErrEntryNotFound {
				err = nil
			}
		}

		if err != nil {
			return
		}

		if !removed && r {
			removed = true
		}
	}

	err = w.removeEmptyDirectory(directory)
	return
}

func (w *Worktree) removeEmptyDirectory(path string) error {
	files, err := w.Filesystem.ReadDir(path)
	if err != nil {
		return err
	}

	if len(files) != 0 {
		return nil
	}

	return w.Filesystem.Remove(path)
}

func (w *Worktree) doRemoveFile(idx *index.Index, path string) 
(plumbing.Hash, error) {
	hash, err := w.deleteFromIndex(idx, path)
	if err != nil {
		return plumbing.ZeroHash, err
	}

	return hash, w.deleteFromFilesystem(path)
}

func (w *Worktree) deleteFromIndex(idx *index.Index, path string) 
(plumbing.Hash, error) {
	e, err := idx.Remove(path)
	if err != nil {
		return plumbing.ZeroHash, err
	}

	return e.Hash, nil
}

func (w *Worktree) deleteFromFilesystem(path string) error {
	err := w.Filesystem.Remove(path)
	if os.IsNotExist(err) {
		return nil
	}

	return err
}

// RemoveGlob removes all paths, matching pattern, from the index. If pattern
// matches a directory path, all directory contents are removed from the index
// recursively.
func (w *Worktree) RemoveGlob(pattern string) error {
	idx, err := w.r.Storer.Index()
	if err != nil {
		return err
	}

	entries, err := idx.Glob(pattern)
	if err != nil {
		return err
	}

	for _, e := range entries {
		file := filepath.FromSlash(e.Name)
		if _, err := w.Filesystem.Lstat(file); err != nil 
         && !os.IsNotExist(err) {
			return err
		}

		if _, err := w.doRemoveFile(idx, file); err != nil {
			return err
		}

		dir, _ := filepath.Split(file)
		if err := w.removeEmptyDirectory(dir); err != nil {
			return err
		}
	}

	return w.r.Storer.SetIndex(idx)
}

removeを呼び出してcommitすればいい!!