github.com/purpleclay/gitz@v0.8.2-0.20240515052600-43f80eea2fe1/status.go (about) 1 package git 2 3 import ( 4 "bufio" 5 "fmt" 6 "strings" 7 ) 8 9 // FileStatusIndicator contains a single character that represents 10 // a files status within a git repository. Based on the git 11 // specification: https://git-scm.com/docs/git-status#_output 12 type FileStatusIndicator byte 13 14 const ( 15 Added FileStatusIndicator = 'A' 16 Copied FileStatusIndicator = 'C' 17 Deleted FileStatusIndicator = 'D' 18 Ignored FileStatusIndicator = '!' 19 Modified FileStatusIndicator = 'M' 20 Renamed FileStatusIndicator = 'R' 21 TypeChanged FileStatusIndicator = 'T' 22 Updated FileStatusIndicator = 'U' 23 Unmodified FileStatusIndicator = ' ' 24 Untracked FileStatusIndicator = '?' 25 ) 26 27 // FileStatus represents the status of a file within a repository 28 type FileStatus struct { 29 // Indicators is a two character array that contains 30 // the current status of a file within both the current index 31 // and the working repository tree. 32 // 33 // Examples: 34 // 35 // '??' - a file that is not tracked 36 // ' A' - a file that has been added to the working tree 37 // 'M ' - a file that has been modified within the index 38 Indicators [2]FileStatusIndicator 39 40 // Path of the file relative to the root of the 41 // current repository 42 Path string 43 } 44 45 // String representation of a file status that adheres to the 46 // porcelain v1 format 47 func (f FileStatus) String() string { 48 return fmt.Sprintf("%c%c %s", f.Indicators[0], f.Indicators[1], f.Path) 49 } 50 51 // PorcelainStatus identifies if there are any changes within the current 52 // repository (working directory) and returns them in the parseable 53 // porcelain v1 format 54 func (c *Client) PorcelainStatus() ([]FileStatus, error) { 55 log, err := c.exec("git status --porcelain") 56 if err != nil { 57 return nil, err 58 } 59 60 return parsePorcelainV1(log), nil 61 } 62 63 // Clean determines if the current repository (working directory) is in 64 // a clean state. A repository is deemed clean, if it contains no changes 65 func (c *Client) Clean() (bool, error) { 66 statuses, err := c.PorcelainStatus() 67 return len(statuses) == 0, err 68 } 69 70 func parsePorcelainV1(log string) []FileStatus { 71 var statuses []FileStatus 72 73 scanner := bufio.NewScanner(strings.NewReader(log)) 74 scanner.Split(bufio.ScanLines) 75 76 for scanner.Scan() { 77 line := scanner.Text() 78 statuses = append(statuses, FileStatus{ 79 Indicators: [2]FileStatusIndicator{ 80 FileStatusIndicator(line[0]), 81 FileStatusIndicator(line[1]), 82 }, 83 Path: line[3:], 84 }) 85 } 86 87 return statuses 88 }