bovarys.me/fudge@v0.4.0/git/git.go (about)

     1  package git
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/dustin/go-humanize"
    12  	"gopkg.in/src-d/go-git.v4"
    13  	"gopkg.in/src-d/go-git.v4/plumbing/object"
    14  )
    15  
    16  type Blob struct {
    17  	Name     string
    18  	IsBinary bool
    19  	Size     string // The blob humanized size
    20  	Reader   io.ReadCloser
    21  }
    22  
    23  type TreeObject struct {
    24  	Name   string
    25  	IsFile bool
    26  	Size   string // The object humanized size
    27  }
    28  
    29  func isNotCandidate(path string) bool {
    30  	file, err := os.Stat(path)
    31  	isRegularFile := !os.IsNotExist(err) && !file.IsDir()
    32  
    33  	return isRegularFile || os.IsNotExist(err)
    34  }
    35  
    36  // OpenRepository opens a Git repository from the given root path and dirname.
    37  // If strict is set to false, OpenRepository will try to open dirname first,
    38  // then dirname with a ".git" suffix.
    39  func OpenRepository(root, dirname string, strict bool) (*git.Repository, error) {
    40  	path := filepath.Join(root, dirname)
    41  
    42  	if isNotCandidate(path) {
    43  		if strict {
    44  			return nil, git.ErrRepositoryNotExists
    45  		}
    46  
    47  		path = filepath.Join(root, dirname+".git")
    48  		if isNotCandidate(path) {
    49  			return nil, git.ErrRepositoryNotExists
    50  		}
    51  	}
    52  
    53  	repository, err := git.PlainOpen(path)
    54  
    55  	return repository, err
    56  }
    57  
    58  func GetRepositoryNames(root string) ([]string, error) {
    59  	files, err := ioutil.ReadDir(root)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	var names []string
    65  
    66  	for _, file := range files {
    67  		if !file.IsDir() {
    68  			continue
    69  		}
    70  
    71  		_, err := OpenRepository(root, file.Name(), true)
    72  		if err == git.ErrRepositoryNotExists {
    73  			continue
    74  		}
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  
    79  		name := strings.TrimSuffix(file.Name(), ".git")
    80  
    81  		names = append(names, name)
    82  	}
    83  
    84  	return names, nil
    85  }
    86  
    87  func GetRepositoryCommits(r *git.Repository) ([]*object.Commit, error) {
    88  	iter, err := r.Log(&git.LogOptions{})
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	var commits []*object.Commit
    94  
    95  	err = iter.ForEach(func(c *object.Commit) error {
    96  		// XXX
    97  		c.Message = strings.Split(c.Message, "\n")[0]
    98  		commits = append(commits, c)
    99  
   100  		return nil
   101  	})
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	return commits, nil
   107  }
   108  
   109  func GetRepositoryLastCommit(r *git.Repository) (*object.Commit, error) {
   110  	head, err := r.Head()
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	commit, err := r.CommitObject(head.Hash())
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	// XXX
   121  	commit.Message = strings.Split(commit.Message, "\n")[0]
   122  
   123  	return commit, nil
   124  }
   125  
   126  func GetRepositoryTree(r *git.Repository, path string) (*object.Tree, error) {
   127  	head, err := r.Head()
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	commit, err := r.CommitObject(head.Hash())
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	tree, err := commit.Tree()
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	if path != "" {
   143  		tree, err = tree.Tree(path)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  	}
   148  
   149  	return tree, nil
   150  }
   151  
   152  func GetRepositoryBlob(r *git.Repository, path string) (*Blob, error) {
   153  	dir := filepath.Dir(path)
   154  	if dir == "." {
   155  		dir = ""
   156  	}
   157  
   158  	tree, err := GetRepositoryTree(r, dir)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	filename := filepath.Base(path)
   164  	file, err := tree.File(filename)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	isBinary, err := file.IsBinary()
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	reader, err := file.Blob.Reader()
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	blob := &Blob{
   180  		Name:     file.Name,
   181  		IsBinary: isBinary,
   182  		Size:     humanize.Bytes(uint64(file.Blob.Size)),
   183  		Reader:   reader,
   184  	}
   185  
   186  	return blob, nil
   187  }
   188  
   189  func GetTreeObjects(tree *object.Tree) ([]*TreeObject, error) {
   190  	var objects []*TreeObject
   191  
   192  	walker := object.NewTreeWalker(tree, false, nil)
   193  
   194  	for {
   195  		name, entry, err := walker.Next()
   196  		if err == io.EOF {
   197  			break
   198  		}
   199  		if err != nil {
   200  			return nil, err
   201  		}
   202  
   203  		size, err := tree.Size(name)
   204  		if err != nil {
   205  			return nil, err
   206  		}
   207  
   208  		o := &TreeObject{
   209  			Name:   name,
   210  			IsFile: entry.Mode.IsFile(),
   211  			Size:   humanize.Bytes(uint64(size)),
   212  		}
   213  
   214  		objects = append(objects, o)
   215  	}
   216  
   217  	sort.Slice(objects, func(i, j int) bool {
   218  		// Order the objects by non-file status then name
   219  		if !objects[i].IsFile && objects[j].IsFile {
   220  			return true
   221  		}
   222  
   223  		if objects[i].IsFile && !objects[j].IsFile {
   224  			return false
   225  		}
   226  
   227  		return objects[i].Name < objects[j].Name
   228  	})
   229  
   230  	return objects, nil
   231  }