github.com/nemith/go-gitlog@v0.0.2-0.20180205151741-6c79beb2287b/gitlog.go (about)

     1  // Package gitlog is providing a means to handle git-log.
     2  package gitlog
     3  
     4  import (
     5  	"os"
     6  	"path/filepath"
     7  
     8  	gitcmd "github.com/tsuyoshiwada/go-gitcmd"
     9  )
    10  
    11  const (
    12  	hashField      = "HASH"
    13  	treeField      = "TREE"
    14  	authorField    = "AUTHOR"
    15  	committerField = "COMMITTER"
    16  	subjectField   = "SUBJECT"
    17  	bodyField      = "BODY"
    18  	tagField       = "TAG"
    19  
    20  	hashFormat      = hashField + ":%H %h"
    21  	treeFormat      = treeField + ":%T %t"
    22  	authorFormat    = authorField + ":%an<%ae>[%at]"
    23  	committerFormat = committerField + ":%cn<%ce>[%ct]"
    24  	subjectFormat   = subjectField + ":%s"
    25  	bodyFormat      = bodyField + ":%b"
    26  	tagFormat       = tagField + ":%D"
    27  
    28  	separator = "@@__GIT_LOG_SEPARATOR__@@"
    29  	delimiter = "@@__GIT_LOG_DELIMITER__@@"
    30  
    31  	logFormat = separator +
    32  		hashFormat + delimiter +
    33  		treeFormat + delimiter +
    34  		authorFormat + delimiter +
    35  		committerFormat + delimiter +
    36  		tagFormat + delimiter +
    37  		subjectFormat + delimiter +
    38  		bodyFormat
    39  )
    40  
    41  // Config for getting git-log
    42  type Config struct {
    43  	Bin  string // default "git"
    44  	Path string // default "."
    45  }
    46  
    47  // Params for getting git-log
    48  type Params struct {
    49  	MergesOnly   bool
    50  	IgnoreMerges bool
    51  	Reverse      bool
    52  }
    53  
    54  // GitLog is an interface for git-log acquisition
    55  type GitLog interface {
    56  	Log(RevArgs, *Params) ([]*Commit, error)
    57  }
    58  
    59  type gitLogImpl struct {
    60  	client gitcmd.Client
    61  	parser *parser
    62  	config *Config
    63  }
    64  
    65  // New GitLog interface
    66  func New(config *Config) GitLog {
    67  	bin := "git"
    68  	path := "path"
    69  
    70  	if config != nil {
    71  		if config.Bin != "" {
    72  			bin = config.Bin
    73  		}
    74  
    75  		if config.Path != "" {
    76  			path = config.Path
    77  		}
    78  	}
    79  
    80  	return &gitLogImpl{
    81  		client: gitcmd.New(&gitcmd.Config{
    82  			Bin: bin,
    83  		}),
    84  		parser: &parser{},
    85  		config: &Config{
    86  			Bin:  bin,
    87  			Path: path,
    88  		},
    89  	}
    90  }
    91  
    92  // workingdir is go to the temporary working directory
    93  func (gitLog *gitLogImpl) workdir() (func() error, error) {
    94  	cwd, err := filepath.Abs(".")
    95  
    96  	back := func() error {
    97  		return os.Chdir(cwd)
    98  	}
    99  
   100  	if err != nil {
   101  		return back, err
   102  	}
   103  
   104  	dir, err := filepath.Abs(gitLog.config.Path)
   105  	if err != nil {
   106  		return back, err
   107  	}
   108  
   109  	err = os.Chdir(dir)
   110  	if err != nil {
   111  		return back, err
   112  	}
   113  
   114  	return back, nil
   115  }
   116  
   117  // Build command line args
   118  func (gitLog *gitLogImpl) buildArgs(rev RevArgs, params *Params) []string {
   119  	args := []string{
   120  		"--no-decorate",
   121  		"--pretty=\"" + logFormat + "\"",
   122  	}
   123  
   124  	if params != nil {
   125  		if params.MergesOnly {
   126  			args = append(args, "--merges")
   127  		}
   128  
   129  		if params.IgnoreMerges {
   130  			args = append(args, "--no-merges")
   131  		}
   132  
   133  		if params.Reverse {
   134  			args = append(args, "--reverse")
   135  		}
   136  	}
   137  
   138  	if rev != nil {
   139  		revisions := rev.Args()
   140  		args = append(args, revisions...)
   141  	}
   142  
   143  	return args
   144  }
   145  
   146  // Log internally uses the git command to get a list of git-logs
   147  // func (gitLog *gitLogImpl) Log(ref string, rev RevArgs) ([]*Commit, error) {
   148  func (gitLog *gitLogImpl) Log(rev RevArgs, params *Params) ([]*Commit, error) {
   149  	// Can execute the git command?
   150  	if err := gitLog.client.CanExec(); err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	// To repository path
   155  	back, err := gitLog.workdir()
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	defer back()
   160  
   161  	// Check inside work tree
   162  	err = gitLog.client.InsideWorkTree()
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	// Dump git-log
   168  	args := gitLog.buildArgs(rev, params)
   169  
   170  	out, err := gitLog.client.Exec("log", args...)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	commits, err := gitLog.parser.parse(&out)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	return commits, nil
   181  }