|
|
@ -6,8 +6,7 @@ package git |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"os" |
|
|
|
"path" |
|
|
|
"path/filepath" |
|
|
|
|
|
|
|
"sort" |
|
|
|
"sort" |
|
|
|
"strconv" |
|
|
|
"strconv" |
|
|
|
"strings" |
|
|
|
"strings" |
|
|
@ -149,7 +148,7 @@ func (tes Entries) Sort() { |
|
|
|
// getCommitInfoState transient state for getting commit info for entries
|
|
|
|
// getCommitInfoState transient state for getting commit info for entries
|
|
|
|
type getCommitInfoState struct { |
|
|
|
type getCommitInfoState struct { |
|
|
|
entries map[string]*TreeEntry // map from filepath to entry
|
|
|
|
entries map[string]*TreeEntry // map from filepath to entry
|
|
|
|
commits map[string]*Commit // map from entry name to commit
|
|
|
|
commits map[string]*Commit // map from filepath to commit
|
|
|
|
lastCommitHash string |
|
|
|
lastCommitHash string |
|
|
|
lastCommit *Commit |
|
|
|
lastCommit *Commit |
|
|
|
treePath string |
|
|
|
treePath string |
|
|
@ -160,7 +159,10 @@ type getCommitInfoState struct { |
|
|
|
func initGetCommitInfoState(entries Entries, headCommit *Commit, treePath string) *getCommitInfoState { |
|
|
|
func initGetCommitInfoState(entries Entries, headCommit *Commit, treePath string) *getCommitInfoState { |
|
|
|
entriesByPath := make(map[string]*TreeEntry, len(entries)) |
|
|
|
entriesByPath := make(map[string]*TreeEntry, len(entries)) |
|
|
|
for _, entry := range entries { |
|
|
|
for _, entry := range entries { |
|
|
|
entriesByPath[filepath.Join(treePath, entry.Name())] = entry |
|
|
|
entriesByPath[path.Join(treePath, entry.Name())] = entry |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if treePath = path.Clean(treePath); treePath == "." { |
|
|
|
|
|
|
|
treePath = "" |
|
|
|
} |
|
|
|
} |
|
|
|
return &getCommitInfoState{ |
|
|
|
return &getCommitInfoState{ |
|
|
|
entries: entriesByPath, |
|
|
|
entries: entriesByPath, |
|
|
@ -180,7 +182,7 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interfac |
|
|
|
|
|
|
|
|
|
|
|
commitsInfo := make([][]interface{}, len(tes)) |
|
|
|
commitsInfo := make([][]interface{}, len(tes)) |
|
|
|
for i, entry := range tes { |
|
|
|
for i, entry := range tes { |
|
|
|
commit = state.commits[filepath.Join(treePath, entry.Name())] |
|
|
|
commit = state.commits[path.Join(treePath, entry.Name())] |
|
|
|
switch entry.Type { |
|
|
|
switch entry.Type { |
|
|
|
case ObjectCommit: |
|
|
|
case ObjectCommit: |
|
|
|
subModuleURL := "" |
|
|
|
subModuleURL := "" |
|
|
@ -211,22 +213,23 @@ func (state *getCommitInfoState) commit() (*Commit, error) { |
|
|
|
return state.lastCommit, err |
|
|
|
return state.lastCommit, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (state *getCommitInfoState) update(path string) error { |
|
|
|
func (state *getCommitInfoState) update(entryPath string) error { |
|
|
|
relPath, err := filepath.Rel(state.treePath, path) |
|
|
|
var entryNameStartIndex int |
|
|
|
if err != nil { |
|
|
|
if len(state.treePath) > 0 { |
|
|
|
return nil |
|
|
|
entryNameStartIndex = len(state.treePath) + 1 |
|
|
|
} |
|
|
|
} |
|
|
|
var entryPath string |
|
|
|
|
|
|
|
if index := strings.IndexRune(relPath, os.PathSeparator); index >= 0 { |
|
|
|
if index := strings.IndexByte(entryPath[entryNameStartIndex:], '/'); index >= 0 { |
|
|
|
entryPath = filepath.Join(state.treePath, relPath[:index]) |
|
|
|
entryPath = entryPath[:entryNameStartIndex+index] |
|
|
|
} else { |
|
|
|
|
|
|
|
entryPath = path |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if _, ok := state.entries[entryPath]; !ok { |
|
|
|
if _, ok := state.entries[entryPath]; !ok { |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} else if _, ok := state.commits[entryPath]; ok { |
|
|
|
} else if _, ok := state.commits[entryPath]; ok { |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var err error |
|
|
|
state.commits[entryPath], err = state.commit() |
|
|
|
state.commits[entryPath], err = state.commit() |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
@ -251,17 +254,17 @@ func getNextCommitInfos(state *getCommitInfoState) error { |
|
|
|
state.nextCommit(lines[i]) |
|
|
|
state.nextCommit(lines[i]) |
|
|
|
i++ |
|
|
|
i++ |
|
|
|
for ; i < len(lines); i++ { |
|
|
|
for ; i < len(lines); i++ { |
|
|
|
path := lines[i] |
|
|
|
entryPath := lines[i] |
|
|
|
if path == "" { |
|
|
|
if entryPath == "" { |
|
|
|
break |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
if path[0] == '"' { |
|
|
|
if entryPath[0] == '"' { |
|
|
|
path, err = strconv.Unquote(path) |
|
|
|
entryPath, err = strconv.Unquote(entryPath) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return fmt.Errorf("Unquote: %v", err) |
|
|
|
return fmt.Errorf("Unquote: %v", err) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
state.update(path) |
|
|
|
state.update(entryPath) |
|
|
|
} |
|
|
|
} |
|
|
|
i++ // skip blank line
|
|
|
|
i++ // skip blank line
|
|
|
|
if len(state.entries) == len(state.commits) { |
|
|
|
if len(state.entries) == len(state.commits) { |
|
|
@ -284,9 +287,9 @@ func logCommand(exclusiveStartHash string, state *getCommitInfoState) *Command { |
|
|
|
searchSize := (numRemainingEntries + 1) / 2 |
|
|
|
searchSize := (numRemainingEntries + 1) / 2 |
|
|
|
command = NewCommand("log", prettyLogFormat, "--name-only", |
|
|
|
command = NewCommand("log", prettyLogFormat, "--name-only", |
|
|
|
"-"+strconv.Itoa(searchSize), commitHash, "--") |
|
|
|
"-"+strconv.Itoa(searchSize), commitHash, "--") |
|
|
|
for path, entry := range state.entries { |
|
|
|
for entryPath := range state.entries { |
|
|
|
if _, ok := state.commits[entry.Name()]; !ok { |
|
|
|
if _, ok := state.commits[entryPath]; !ok { |
|
|
|
command.AddArguments(path) |
|
|
|
command.AddArguments(entryPath) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|