Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: go/src/infra/tools/drover/disambiguate.go

Issue 662113003: Drover's back, baby! (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git/+/master
Patch Set: more tests and refactors Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « go/src/infra/tools/drover/default_shell_windows.go ('k') | go/src/infra/tools/drover/main.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 package main
5
6 import (
7 "encoding/json"
8 "errors"
9 "fmt"
10 "net/http"
11 "reflect"
12 "sort"
13 "strings"
14
15 "infra/libs/gitiles"
16 )
17
18 const crRevAPI = "https://cr-rev.appspot.com/_ah/api/crrev/v1/"
19
20 /* Takes a user-suppiled commit specifier, and resolves it to a commit hash and
21 repo url.
22
23 Possible input formats:
24 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
25 "29345" # Cr-Commit-Position assuming refs/heads/master and src.git
26
27 The disambiguation is done by crrev.com, and so this function may return an
28 error if the service is not available.
29
30 Additionally, this function may return an error if the commit specifier is
31 not unambiguous.
32 */
33 func disambiguateCommit(commitSpec string) (commit, url string, err error) {
34 commit = commitSpec
35 url = ""
36
37 resp, err := http.Get(crRevAPI + "redirect/" + commitSpec)
38 if err != nil {
39 return
40 }
41 defer resp.Body.Close()
42
43 // TODO(iannucci,stip): generate this from endpoints source code
44 jsonData := make(map[string]string)
45 if err = json.NewDecoder(resp.Body).Decode(&jsonData); err != nil {
46 return
47 }
48 commit, ok := jsonData["git_sha"]
49 if !ok {
50 err = errors.New("disambiguateCommit: expected 'git_sha' key")
51 return
52 }
53
54 rawURL, ok := jsonData["redirect_url"]
55 if !ok {
56 err = errors.New("disambiguateCommit: expected 'redirect_url' ke y")
57 return
58 }
59
60 url = strings.Split(rawURL, "+")[0]
61 return
62 }
63
64 type sortKey struct {
65 inexactMatch bool
66 partialMatch bool
67 nonHead bool
68 refLength int
69 }
70
71 // Sorts refCandidate's so that the least one is the best one.
72 func (s *sortKey) less(other sortKey) bool {
73 return ((!s.inexactMatch && other.inexactMatch) ||
74 (!s.partialMatch && other.partialMatch) ||
75 (!s.nonHead && other.nonHead) ||
76 (s.refLength < other.refLength))
77 }
78
79 type refCandidate struct {
80 Ref string
81 Confident bool
82 SortKey sortKey
83 }
84
85 type sortableRefCandidates []refCandidate
86
87 func (r sortableRefCandidates) Len() int { return len(r) }
88 func (r sortableRefCandidates) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
89 func (r sortableRefCandidates) Less(i, j int) bool {
90 return r[i].SortKey.less(r[j].SortKey)
91 }
92
93 func disambiguateRef(gitiles *gitiles.Gitiles, commit, refFragment string) (ref string, err error) {
94 result, err := gitiles.JSON(map[string]map[string]string{}, "+refs")
95 if err != nil {
96 return
97 }
98 refs := *result.(*map[string]map[string]string)
99
100 reverse := func(s []string) (ret []string) {
101 ret = make([]string, len(s))
102 for idx, el := range s {
103 ret[len(ret)-idx-1] = el
104 }
105 return
106 }
107
108 targetParts := reverse(strings.Split(refFragment, "/"))
109
110 // guess that we'll have about 10
111 candidates := make(sortableRefCandidates, 0, 10)
112
113 for ref := range refs {
114 if strings.HasSuffix(ref, refFragment) {
115 refParts := reverse(strings.Split(ref, "/"))
116
117 exactMatch := reflect.DeepEqual(refParts, targetParts)
118 wholeMatch := true
119 shortest := -1
120 if len(refParts) < len(targetParts) {
121 shortest = len(refParts)
122 } else {
123 shortest = len(targetParts)
124 }
125 for i := 0; i < shortest; i++ {
126 if refParts[i] != targetParts[i] {
127 wholeMatch = false
128 break
129 }
130 }
131 hasHeads := strings.Contains(ref, "heads")
132
133 confident := exactMatch || (wholeMatch && hasHeads)
134
135 candidates = append(candidates, refCandidate{
136 Ref: ref,
137 Confident: confident,
138 SortKey: sortKey{
139 inexactMatch: !exactMatch,
140 partialMatch: !wholeMatch,
141 nonHead: !hasHeads,
142 refLength: len(ref),
143 },
144 })
145 }
146 }
147
148 if len(candidates) == 0 {
149 err = fmt.Errorf("disambiguateRef: no matching ref for %s", refF ragment)
150 return
151 }
152
153 sort.Sort(candidates)
154 // TODO(iannucci): if we have logging, it would be good to dump all
155 // candidates in debug mode.
156 if !candidates[0].Confident {
157 fmt.Printf("No confident matches for refs given '%s'. Candidates :\n",
158 refFragment)
159 for _, c := range candidates {
160 fmt.Printf(" %s\n", c.Ref)
161 }
162 err = errors.New("disambiguateRef: no confident refs")
163 }
164
165 ref = candidates[0].Ref
166 return
167 }
OLDNEW
« no previous file with comments | « go/src/infra/tools/drover/default_shell_windows.go ('k') | go/src/infra/tools/drover/main.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698