Kiln » TortoiseHg » TortoiseHg
Clone URL:  
Pushed to one repository · View In Graph Contained in 0.9, 0.9.1, and 0.9.1.1

csinfo: introduce cache mechanism

2 cache layers; data and widget. Widgets cache is experimental feature.
It needs to polish more.

Changeset 3c6800bfc863

Parent 626dcfb2a3f5

by Yuki KODAMA

Changes to 6 files · Browse files at 3c6800bfc863 Showing diff from parent 626dcfb2a3f5 Diff from another changeset...

 
55
56
57
58
 
59
60
61
 
55
56
57
 
58
59
60
61
@@ -55,7 +55,7 @@
  # changeset info   style = csinfo.panelstyle(label=_('Changeset Description'),   margin=4, padding=2) - self.csetframe = csinfo.create(rev, style, repo) + self.csetframe = csinfo.create(repo, rev, style)   self.vbox.pack_start(self.csetframe, False, False, 2)     # backout commit message
 
390
391
392
 
393
394
 
395
396
397
 
390
391
392
393
394
 
395
396
397
398
@@ -390,8 +390,9 @@
  return gtklib.markup(text, weight='bold')   custom = csinfo.custom(athead={   'data': data_func, 'markup': markup_func}) + factory = csinfo.factory(self.repo, custom, style)   def add_parent(): - label = csinfo.create('tip', style, self.repo, custom) + label = factory()   parents_vbox.pack_start(label, False, False)   return label   self.parent1_label = add_parent()
 
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
 
64
65
66
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
69
70
71
72
73
74
75
76
 
 
77
78
 
79
80
81
82
83
84
 
 
85
86
87
 
98
99
100
101
 
102
103
104
 
107
108
109
110
111
112
 
 
 
113
114
115
 
116
117
118
 
120
121
122
123
124
 
 
125
126
127
 
128
129
130
 
139
140
141
142
 
143
144
145
146
 
 
147
148
149
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
151
 
 
152
153
154
155
156
157
 
158
159
160
 
 
161
162
163
 
169
170
171
172
173
 
 
174
175
176
 
206
207
208
209
 
210
211
212
 
 
213
214
215
 
217
218
219
220
221
 
 
222
223
224
225
226
 
227
228
229
 
18
19
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
22
23
 
 
 
 
 
 
 
 
 
 
 
 
24
25
26
27
28
 
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
111
112
113
114
115
116
117
 
 
 
 
118
119
120
 
121
122
123
124
125
 
 
126
127
128
129
130
 
141
142
143
 
144
145
146
147
 
150
151
152
 
 
 
153
154
155
156
157
 
158
159
160
161
 
163
164
165
 
 
166
167
168
169
 
170
171
172
173
 
182
183
184
 
185
186
187
 
 
188
189
190
191
 
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
 
 
243
 
244
245
 
 
246
247
248
249
250
 
256
257
258
 
 
259
260
261
262
263
 
293
294
295
 
296
297
 
 
298
299
300
301
302
 
304
305
306
 
 
307
308
309
310
311
312
 
313
314
315
316
@@ -18,40 +18,11 @@
   PANEL_DEFAULT = ('rev', 'summary', 'user', 'date', 'branch', 'tags')   -def create(rev, style=None, repo=None, custom=None): - if style is None: - style = panelstyle() - if repo is None: - try: - rpath = paths.find_root() - repo = hg.repository(ui.ui(), path=rpath) - except hglib.RepoError: - raise _('failed to get repo: %s') % rpath - if custom is None: - custom = {} - if 'type' in style: - type = style['type'] - if type == 'panel': - if 'contents' not in style: - style['contents'] = PANEL_DEFAULT - return ChangesetPanel(rev, style, repo, custom) - elif type == 'label': - return ChangesetLabel(rev, style, repo, custom) - raise _('unknown csinfo type: %s') % type - raise _('no csinfo type specified') +def create(repo, rev, style=None, custom=None): + return CachedFactory(repo, custom, style, rev)()   -def factory(*base, **kbase): - def bind(*over, **kover): - args = base + over - kargs = kbase.copy() - # override base options - kargs.update(kover) - if 'style' in kargs and 'style' in kover: - # override style options - kargs['style'] = kbase['style'].copy() - kargs['style'].update(kover['style']) - return create(*args, **kargs) - return bind +def factory(*args, **kargs): + return CachedFactory(*args, **kargs)    def panelstyle(**kargs):   kargs['type'] = 'panel' @@ -64,24 +35,96 @@
 def custom(**kargs):   return kargs   -class ChangesetWidget(object): +class CachedFactory(object): + + def __init__(self, repo=None, custom=None, style=None, rev=None, + widgetcache=False): + if repo is None: + try: + root = paths.find_root() + repo = hg.repository(ui.ui(), path=root) + except hglib.RepoError: + raise _('failed to get repo: %s') % root + self.repo = repo + if custom is None: + custom = {} + self.custom = custom + if style is None: + style = panelstyle(contents=PANEL_DEFAULT) + self.csstyle = style + if rev is None: + rev = 'tip' + self.rev = rev + self.info = CachedChangesetInfo() + + if widgetcache: + self.cache = {} + + def __call__(self, rev=None, style=None, custom=None, repo=None): + if rev is None: + rev = self.rev + if style is None: + style = self.csstyle + else: + # need to override styles + newstyle = self.csstyle.copy() + newstyle.update(style) + style = newstyle + if custom is None: + custom = self.custom + else: + # need to override customs + newcustom = self.custom.copy() + newcustom.update(custom) + custom = newcustom + if repo is None: + repo = self.repo + + # check cache + if hasattr(self, 'cache'): + key = style['type'] + str(rev) + str(style) + str(custom) + str(id(repo)) + try: + widget = self.cache[key] + return widget + except KeyError: + pass + + if 'type' in style: + args = (rev, style, custom, repo, self.info) + type = style['type'] + if type == 'panel': + if 'contents' not in style: + style['contents'] = PANEL_DEFAULT + panel = ChangesetPanel(*args) + if hasattr(self, 'cache'): + self.cache[key] = panel + return panel + elif type == 'label': + label = ChangesetLabel(*args) + if hasattr(self, 'cache'): + self.cache[key] = label + return label + else: + raise _("unknown 'type': %s") % type + else: + raise _("must be specified 'type' in style") + +class ChangesetInfo(object):     LABELS = {'rev': _('rev:'), 'revnum': _('rev:'), 'revid': _('rev:'),   'summary': _('summary:'), 'user': _('user:'),   'date': _('date:'), 'branch': _('branch:'), 'tags': _('tags:')}   - def __init__(self, rev, repo, custom): - self.rev = str(rev) - self.repo = repo - self.custom = custom + def __init__(self): + pass   - def get_data(self, item): + def get_data(self, item, rev, custom, repo):   def default_func(widget, ctx):   return None   def preset_func(widget, ctx):   if item == 'rev': - revnum = self.get_data('revnum') - revid = self.get_data('revid') + revnum = self.get_data('revnum', rev, custom, repo) + revid = self.get_data('revid', rev, custom, repo)   return '%s (%s)' % (revnum, revid)   elif item == 'revnum':   return str(ctx.rev()) @@ -98,7 +141,7 @@
  elif item == 'date':   return hglib.displaytime(ctx.date())   elif item == 'branch': - if ctx.node() in self.repo.branchtags().values(): + if ctx.node() in repo.branchtags().values():   return hglib.toutf(ctx.branch())   return None   elif item == 'tags': @@ -107,12 +150,12 @@
  return None   return value   return default_func(widget, ctx) - ctx = self.repo[self.rev] - if self.custom.has_key(item) and self.custom[item].has_key('data'): - return self.custom[item]['data'](self, ctx) + ctx = repo[rev] + if custom.has_key(item) and custom[item].has_key('data'): + return custom[item]['data'](self, ctx)   return preset_func(self, ctx)   - def get_label(self, item): + def get_label(self, item, rev, custom, repo):   def default_func(widget):   return ''   def preset_func(widget): @@ -120,11 +163,11 @@
  return self.LABELS[item]   except:   return default_func(widget) - if self.custom.has_key(item) and self.custom[item].has_key('label'): - return self.custom[item]['label'](self) + if custom.has_key(item) and custom[item].has_key('label'): + return custom[item]['label'](self)   return preset_func(self)   - def get_markup(self, item): + def get_markup(self, item, rev, custom, repo):   def default_func(widget, value):   return gtklib.markup_escape_text(value)   def preset_func(widget, value): @@ -139,25 +182,69 @@
  tags = [gtklib.markup(' %s ' % tag, **opts) for tag in tags]   return ' '.join(tags)   return default_func(widget, value) - value = self.get_data(item) + value = self.get_data(item, rev, custom, repo)   if value is None:   return None - if self.custom.has_key(item) and self.custom[item].has_key('markup'): - return self.custom[item]['markup'](self, value) + if custom.has_key(item) and custom[item].has_key('markup'): + return custom[item]['markup'](self, value)   return preset_func(self, value)   - def update(self, rev=None, repo=None, custom=None): +class CachedChangesetInfo(ChangesetInfo): + + def __init__(self): + ChangesetInfo.__init__(self) + self.cache = {} + + def try_cache(self, target, func, *args): + item, rev, custom, repo = args + key = target + item + str(rev) + str(custom) + str(id(repo)) + try: + return self.cache[key] + except KeyError: + pass + self.cache[key] = value = func(self, *args) + return value + + def get_data(self, *args): + return self.try_cache('data', ChangesetInfo.get_data, *args) + + def get_label(self, *args): + return self.try_cache('label', ChangesetInfo.get_label, *args) + + def get_markup(self, *args): + return self.try_cache('markup', ChangesetInfo.get_markup, *args) + +class ChangesetBase(object): + + def __init__(self, rev, custom, repo, info=None): + self.rev = str(rev) + self.custom = custom + self.repo = repo + if info is None: + info = ChangesetInfo() + self.info = info + + def get_data(self, item): + return self.info.get_data(item, self.rev, self.custom, self.repo) + + def get_label(self, item): + return self.info.get_label(item, self.rev, self.custom, self.repo) + + def get_markup(self, item): + return self.info.get_markup(item, self.rev, self.custom, self.repo) + + def update(self, rev=None, custom=None, repo=None):   if rev is not None:   self.rev = str(rev) + if custom is not None: + self.custom = custom   if repo is not None:   self.repo = repo - if custom is not None: - self.custom = custom   -class ChangesetPanel(ChangesetWidget, gtk.Frame): +class ChangesetPanel(ChangesetBase, gtk.Frame):   - def __init__(self, rev, style, repo, custom): - ChangesetWidget.__init__(self, rev, repo, custom) + def __init__(self, rev, style, custom, repo, info=None): + ChangesetBase.__init__(self, rev, custom, repo, info)   gtk.Frame.__init__(self)     self.set_shadow_type(gtk.SHADOW_NONE) @@ -169,8 +256,8 @@
    self.update()   - def update(self, rev=None, style=None, repo=None, custom=None): - ChangesetWidget.update(self, rev, repo, custom) + def update(self, rev=None, style=None, custom=None, repo=None): + ChangesetBase.update(self, rev, custom, repo)   if style is not None:   self.csstyle = style   @@ -206,10 +293,10 @@
  body.set_markup(text)   self.table.add_row(self.get_label(item), body)   -class ChangesetLabel(ChangesetWidget, gtk.Label): +class ChangesetLabel(ChangesetBase, gtk.Label):   - def __init__(self, rev, style, repo, custom): - ChangesetWidget.__init__(self, rev, repo, custom) + def __init__(self, rev, style, custom, repo, info=None): + ChangesetBase.__init__(self, rev, custom, repo, info)   gtk.Label.__init__(self)     self.set_alignment(0, 0.5) @@ -217,13 +304,13 @@
    self.update()   - def update(self, rev=None, style=None, repo=None, custom=None): - ChangesetWidget.update(self, rev, repo, custom) + def update(self, rev=None, style=None, custom=None, repo=None): + ChangesetBase.update(self, rev, custom, repo)   if style is not None:   self.csstyle = style     if 'selectable' in self.csstyle: - sel = self.csstylestyle['selectable'] + sel = self.csstyle['selectable']   assert isinstance(sel, bool)   self.set_selectable(sel)  
 
80
81
82
83
 
84
85
 
86
87
88
89
90
 
91
92
93
 
80
81
82
 
83
84
 
85
86
87
88
89
 
90
91
92
93
@@ -80,14 +80,14 @@
  return gtklib.markup(_('Not a head revision!'), weight='bold')   custom = csinfo.custom(ishead={   'data': data_func, 'markup': markup_func}) - createinfo = csinfo.factory(style=style, repo=repo, custom=custom) + factory = csinfo.factory(repo, custom, style)   - info = createinfo(rev1, style={'label': _('Merge target (other)')}) + info = factory(rev1, style={'label': _('Merge target (other)')})   self.vbox.pack_start(info, False, False)   self.otherframe = info   self.otherrev = info.get_data('revnum')   - info = createinfo(rev0, style={'label': _('Current revision (local)')}) + info = factory(rev0, style={'label': _('Current revision (local)')})   self.vbox.pack_start(info, False, False)   self.localframe = info   self.localrev = '???'
 
126
127
128
 
 
 
 
 
 
129
130
131
 
169
170
171
172
173
 
174
175
176
 
227
228
229
230
 
231
232
233
234
235
236
237
 
238
239
 
 
 
240
241
242
 
126
127
128
129
130
131
132
133
134
135
136
137
 
175
176
177
 
 
178
179
180
181
 
232
233
234
 
235
236
 
 
 
 
 
 
237
238
 
239
240
241
242
243
244
@@ -126,6 +126,12 @@
  self.revcombo.connect('changed', lambda c: self.preview(queue=True))   self.allbtn.connect('clicked', lambda b: self.preview(limit=False))   + # csetinfo factory + self.factory = csinfo.factory(repo, widgetcache=True) + self.lstyle = csinfo.labelstyle(contents=('%(revnum)s:', + ' %(branch)s', ' %(tags)s', ' %(summary)s')) + self.pstyle = csinfo.panelstyle() +   # prepare to show   self.preview()   self.stripbtn.grab_focus() @@ -169,8 +175,7 @@
    def preview(self, limit=True, queue=False, force=False):   def clear_preview(): - for child in self.resultbox.get_children(): - self.resultbox.remove(child) + self.resultbox.foreach(lambda c: c.parent.remove(c))   def update_info(num=None):   if num is None:   info = '<span weight="bold" foreground="#880000">%s</span>' \ @@ -227,16 +232,13 @@
  tostrip.append(r)   self.curnum = numtotal = len(tostrip)   - LIM = 50 + LIM = 100   compactview = self.compactopt.get_active() - if compactview: - style = csinfo.labelstyle(contents=('%(revnum)s:', ' %(branch)s', - ' %(tags)s', ' %(summary)s')) - else: - style = csinfo.panelstyle() - createinfo = csinfo.factory(style=style, repo=self.repo) + style = compactview and self.lstyle or self.pstyle   def add_csinfo(revnum): - info = createinfo(revnum) + info = self.factory(revnum, style) + if info.parent: + info.parent.remove(info)   self.resultbox.pack_start(info, False, False, 2)   def add_sep():   if not compactview:
 
84
85
86
87
 
88
89
90
 
91
92
93
94
 
95
96
97
98
99
100
 
101
102
103
 
84
85
86
 
87
88
89
 
90
91
92
93
 
94
95
96
97
98
99
 
100
101
102
103
@@ -84,20 +84,20 @@
  ## changeset summaries   style = csinfo.labelstyle(contents=('%(rev)s', ' %(branch)s',   ' %(tags)s', '\n%(summary)s'), selectable=True, width=350) - createinfo = csinfo.factory(style=style, repo=repo) + factory = csinfo.factory(repo, style=style)     ## summary of target revision - self.target_label = createinfo('tip') + self.target_label = factory()   table.add_row(_('Target:'), self.target_label)     ## summary of parent 1 revision - self.parent1_label = createinfo('tip') + self.parent1_label = factory()     ## summary of parent 2 revision if needs   self.ctxs = repo[None].parents()   if len(self.ctxs) == 2:   table.add_row(_('Parent 1:'), self.parent1_label) - self.parent2_label = createinfo('tip') + self.parent2_label = factory()   table.add_row(_('Parent 2:'), self.parent2_label)   else:   table.add_row(_('Parent:'), self.parent1_label)