/
annotate.go
110 lines (102 loc) · 3.57 KB
/
annotate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package cmd
import (
"net/http"
"strings"
"github.com/spf13/cobra"
"github.com/treeverse/lakefs/pkg/api/apigen"
"github.com/treeverse/lakefs/pkg/api/apiutil"
)
const (
annotateTemplate = `{{ $val := .Commit}}{{ $.Object|ljust 15}} {{ $val.Committer|ljust 20 }} {{ $val.Id | printf "%.16s"|ljust 20 }} {{if $val.CreationDate}}{{ $val.CreationDate|date}}{{end}} {{ $.CommitMessage }}
`
annotateMessageSize = 200
ellipsis = "..."
)
type objectCommitData struct {
Object string
Commit apigen.Commit
CommitMessage string
}
var annotateCmd = &cobra.Command{
Use: "annotate <path URI>",
Short: "List entries under a given path, annotating each with the latest modifying commit",
Aliases: []string{"blame"},
Args: cobra.ExactArgs(1),
ValidArgsFunction: ValidArgsRepository,
Run: func(cmd *cobra.Command, args []string) {
pathURI := MustParsePathURI("path URI", args[0])
recursive := Must(cmd.Flags().GetBool(recursiveFlagName))
firstParent := Must(cmd.Flags().GetBool("first-parent"))
client := getClient()
pfx := apigen.PaginationPrefix(*pathURI.Path)
context := cmd.Context()
resp, err := client.ListObjectsWithResponse(context, pathURI.Repository, pathURI.Ref, &apigen.ListObjectsParams{Prefix: &pfx})
DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK)
if resp.JSON200 == nil {
Die("Bad response from server", 1)
}
var listObjectsDelimiter apigen.PaginationDelimiter
if !recursive {
listObjectsDelimiter = PathDelimiter
}
var from string
limit := true
for {
params := &apigen.ListObjectsParams{
Prefix: &pfx,
After: apiutil.Ptr(apigen.PaginationAfter(from)),
Delimiter: &listObjectsDelimiter,
}
listObjectsResp, err := client.ListObjectsWithResponse(context, pathURI.Repository, pathURI.Ref, params)
DieOnErrorOrUnexpectedStatusCode(listObjectsResp, err, http.StatusOK)
if resp.JSON200 == nil {
Die("Bad response from server", 1)
}
for _, obj := range listObjectsResp.JSON200.Results {
logCommitsParams := &apigen.LogCommitsParams{
Amount: apiutil.Ptr(apigen.PaginationAmount(1)),
Limit: &limit,
FirstParent: &firstParent,
}
if recursive {
logCommitsParams.Objects = &[]string{obj.Path}
} else {
logCommitsParams.Prefixes = &[]string{obj.Path}
}
logCommitsResp, err := client.LogCommitsWithResponse(context, pathURI.Repository, pathURI.Ref, logCommitsParams)
DieOnErrorOrUnexpectedStatusCode(logCommitsResp, err, http.StatusOK)
if resp.JSON200 == nil {
Die("Bad response from server", 1)
}
data := objectCommitData{
Object: obj.Path,
}
if len(logCommitsResp.JSON200.Results) > 0 {
data.Commit = logCommitsResp.JSON200.Results[0]
data.CommitMessage = splitOnNewLine(stringTrimLen(logCommitsResp.JSON200.Results[0].Message, annotateMessageSize))
}
Write(annotateTemplate, data)
}
pagination := listObjectsResp.JSON200.Pagination
if !pagination.HasMore {
break
}
from = pagination.NextOffset
}
},
}
func stringTrimLen(str string, size int) string {
if len(str) > size && size > len(ellipsis) {
str = str[:size-len(ellipsis)] + ellipsis
}
return str
}
func splitOnNewLine(str string) string {
return strings.SplitN(str, "\\n", 2)[0] //nolint: gomnd
}
//nolint:gochecknoinits
func init() {
rootCmd.AddCommand(annotateCmd)
withRecursiveFlag(annotateCmd, "recursively annotate all entries under a given path or prefix")
annotateCmd.Flags().Bool("first-parent", false, "follow only the first parent commit upon seeing a merge commit")
}