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

Side by Side Diff: milo/git/history.go

Issue 2979153002: [milo] initial call to get git history (Closed)
Patch Set: fix nits Created 3 years, 5 months 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 | « milo/api/proto/pb.discovery.go ('k') | no next file » | 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 2017 The LUCI Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package git
16
17 import (
18 "bytes"
19 "compress/gzip"
20 "encoding/hex"
21 "fmt"
22 "io/ioutil"
23 "regexp"
24
25 "golang.org/x/net/context"
26
27 "github.com/golang/protobuf/proto"
28
29 "github.com/luci/gae/service/memcache"
30
31 "github.com/luci/luci-go/common/api/gitiles"
32 "github.com/luci/luci-go/common/errors"
33 "github.com/luci/luci-go/common/logging"
34 "github.com/luci/luci-go/common/proto/google"
35
36 milo "github.com/luci/luci-go/milo/api/proto"
37 )
38
39 var gitHash = regexp.MustCompile("[0-9a-fA-F]{40}")
40
41 // Resolve resolves a commitish to a git commit hash.
42 //
43 // This operation will assumed to be either fully local (in the case that
44 // commitish is already a git-hash-looking-thing), or local to the datastore (in
45 // the case that commitish is a fully-qualified-ref, ref tables are populated by
46 // a backend cron).
47 //
48 // If commitish is some other pattern (e.g. "HEAD~"), this will return the
49 // commitish as-is.
50 //
51 // `resolved` will be true if `commit` is, in fact, a git hash; if it's false,
52 // then higher layers should be careful about using it as part of a cache key.
53 func Resolve(c context.Context, url, commitish string) (commit string, resolved bool, err error) {
54 if gitHash.MatchString(commitish) {
55 return commitish, true, nil
56 }
57
58 // TODO(iannucci): actually do lookup and cache it. Maybe have a backend cron
59 // which refreshes the entire refs space?
60 return commitish, false, nil
61 }
62
63 // protoCache maintains a single memcache entry containing a gzipped
64 // proto.Message.
65 //
66 // Args:
67 // - enabled: if false, bypass the cache and return get() directly.
68 // - key: the memcache key to read/write
69 // - out: the proto.Message which should be populated from the cache. This is
70 // always a pointer-to-a-proto-struct.
71 // - get: populates `out` 'the slow way' returning an error if encountered.
72 //
73 // Example:
74 // useCache := cachingEnabled()
75 // obj := &mypb.Object{} // some protobuf object
76 // return obj, protoCache(c, useCache, "memcache_key", func() error {
77 // return PopulateFromNetwork(obj)
78 // })
79 func protoCache(c context.Context, enabled bool, key string, out proto.Message, get func() error) error {
80 if !enabled {
81 return get()
82 }
83
84 cacheEntry := memcache.NewItem(c, key+"|gz")
85 // try reading from cache
86 ok := func() bool {
87 switch err := memcache.Get(c, cacheEntry); err {
88 case nil:
89 r, err := gzip.NewReader(bytes.NewReader(cacheEntry.Valu e()))
90 if err != nil {
91 logging.WithError(err).Warningf(c, "making ungzi p reader for memcache entry")
92 return false
93 }
94
95 data, err := ioutil.ReadAll(r)
96 if err != nil {
97 logging.WithError(err).Warningf(c, "ungzipping m emcache entry")
98 return false
99 }
100
101 if err := proto.Unmarshal(data, out); err != nil {
102 logging.WithError(err).Warningf(c, "unmarshallin g cache entry")
103 return false
104 }
105
106 return true
107 case memcache.ErrCacheMiss:
108 default:
109 logging.WithError(err).Warningf(c, "memcache lookup")
110 }
111 return false
112 }()
113 if ok {
114 return nil
115 }
116
117 if err := get(); err != nil {
118 return err
119 }
120
121 data, err := proto.Marshal(out)
122 if err != nil {
123 logging.WithError(err).Warningf(c, "marshaling proto")
124 return nil
125 }
126
127 var buf bytes.Buffer
128 wr := gzip.NewWriter(&buf)
129 wr.Write(data) // err is buffered on the writer till Close
130 if err := wr.Close(); err != nil {
131 logging.WithError(err).Warningf(c, "gzipping proto")
132 return nil
133 }
134
135 cacheEntry.SetValue(buf.Bytes())
136 if err := memcache.Set(c, cacheEntry); err != nil {
137 logging.WithError(err).Warningf(c, "memcache set")
138 }
139
140 return nil
141 }
142
143 // GetHistory makes a (cached) call to gitiles to obtain the ConsoleGitInfo for
144 // the given url, commitish and limit.
145 func GetHistory(c context.Context, url, commitish string, limit int) (*milo.Cons oleGitInfo, error) {
146 commitish, useCache, err := Resolve(c, url, commitish)
147 if err != nil {
148 return nil, errors.Annotate(err, "resolving %q", commitish).Err( )
149 }
150
151 ret := &milo.ConsoleGitInfo{}
152 cacheKey := fmt.Sprintf("GetHistory|%s|%s|%d", url, commitish, limit)
153 err = protoCache(c, useCache, cacheKey, ret, func() error {
154 rawEntries, err := gitiles.Log(c, url, commitish, limit)
155 if err != nil {
156 return errors.Annotate(err, "GetHistory").Err()
157 }
158
159 ret.Commits = make([]*milo.ConsoleGitInfo_Commit, len(rawEntries ))
160
161 for i, e := range rawEntries {
162 commit := &milo.ConsoleGitInfo_Commit{}
163 if commit.Hash, err = hex.DecodeString(e.Commit); err != nil {
164 return errors.Annotate(err, "commit is not hex ( %q)", e.Commit).Err()
165 }
166
167 commit.AuthorName = e.Author.Name
168 commit.AuthorEmail = e.Author.Email
169
170 ts, err := e.Committer.GetTime()
171 if err != nil {
172 return errors.Annotate(err, "commit time unparsi ble (%q)", e.Committer.Time).Err()
173 }
174
175 commit.CommitTime = google.NewTimestamp(ts)
176 commit.Msg = e.Message
177
178 ret.Commits[i] = commit
179 }
180 return nil
181 })
182 return ret, err
183 }
OLDNEW
« no previous file with comments | « milo/api/proto/pb.discovery.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698