Merge lp:~spiv/bzr-usertest/network-suite into lp:~bzr/bzr-usertest/trunk-old

Proposed by Andrew Bennetts
Status: Work in progress
Proposed branch: lp:~spiv/bzr-usertest/network-suite
Merge into: lp:~bzr/bzr-usertest/trunk-old
Diff against target: 1424 lines (+537/-204)
14 files modified
__init__.py (+21/-7)
archiveutil.py (+1/-1)
compare.py (+47/-24)
datadump.py (+8/-2)
dirutil.py (+7/-0)
scripts/script_commit.py (+34/-0)
scripts/script_common.py (+142/-59)
scripts/script_log.py (+45/-45)
scripts/script_logplus.py (+6/-6)
scripts/script_network.py (+64/-12)
statistics.py (+34/-6)
suiterunner.py (+66/-14)
tests/test_archiveutil.py (+21/-16)
userscript.py (+41/-12)
To merge this branch: bzr merge lp:~spiv/bzr-usertest/network-suite
Reviewer Review Type Date Requested Status
Martin Pool (community) none Needs Fixing
Bazaar Developers Pending
Review via email: mp+1335@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Andrew Bennetts (spiv) wrote :

This adds the most interesting cases from http://bazaar-vcs.org/SmartPushAnalysis1.4 to script_network.py.

lp:~spiv/bzr-usertest/network-suite updated
124. By Andrew Bennetts

Fix thinko.

Revision history for this message
Martin Pool (mbp) wrote :

 class AnotherBranchTask(ScriptTask):

+ def __init__(self, branch_name='-anotherBranch'):
+ self._branch_name = branch_name
+ super(AnotherBranchTask, self).__init__()
+
+ def id(self):
+ return super(AnotherBranchTask, self).id() + self._branch_name
+
+ def name(self):
+ return super(AnotherBranchTask, self).name() + self._branch_name
+
     def load(self):
         self.compile_default("""
             cd ..
- $tool clone $repo_read_url/trunk ${work_basename}-anotherBranch
- cd ${work_basename}-anotherBranch
- """)
- # Go up an extra level for Bazaar to get outside the shared repo
- self.compile_for_tools([TOOL_BZR], """
- cd ..
- cd ..
- $tool clone $repo_read_url/trunk ${work_basename}-anotherBranch
- cd ${work_basename}-anotherBranch
- """)
+ $tool clone $repo_read_url/trunk ${work_basename}%(branch_name)s
+ cd ${work_basename}%(branch_name)s
+ """ % {'branch_name': self._branch_name})

So it looks like you're doing variable substitution into this string through both ${} and %()s. That's not necessarily wrong and it seems syntactically valid, but I do wonder if it's good style. Is there a reason you can't feed the branch name in through the same mechanism that the rest of usertest apparently uses?

review: Needs Fixing (none)
Revision history for this message
Andrew Bennetts (spiv) wrote :

Martin Pool wrote:
> def load(self):
[...]
> + $tool clone $repo_read_url/trunk ${work_basename}%(branch_name)s
> + cd ${work_basename}%(branch_name)s
> + """ % {'branch_name': self._branch_name})
>
> So it looks like you're doing variable substitution into this string through both ${} and %()s. That's not necessarily wrong and it seems syntactically valid, but I do wonder if it's good style. Is there a reason you can't feed the branch name in through the same mechanism that the rest of usertest apparently uses?

Yes, they need to happen at different times.

I want to paramaterise branch_name when creating the script, so that I can reuse
this script snippet multiple times in the overall script built by the
script_suite function.

usertest then takes that complete script suite and runs it once for each tool
(and possibly repeats if it has been instructed to do so). work_basename needs
to vary by run.

I could use string.Template for my per-script substitution instead of the %
operator, like per-run substitution, but I think that the double-escaping of
${work_basename} that would require would be no better, and more verbose.

Revision history for this message
Martin Pool (mbp) wrote :

On Mon, Nov 3, 2008 at 4:33 PM, Andrew Bennetts
<email address hidden> wrote:
> Martin Pool wrote:
>> def load(self):
> [...]
>> + $tool clone $repo_read_url/trunk ${work_basename}%(branch_name)s
>> + cd ${work_basename}%(branch_name)s
>> + """ % {'branch_name': self._branch_name})
>>
>> So it looks like you're doing variable substitution into this string through both ${} and %()s. That's not necessarily wrong and it seems syntactically valid, but I do wonder if it's good style. Is there a reason you can't feed the branch name in through the same mechanism that the rest of usertest apparently uses?
>
> Yes, they need to happen at different times. [snip]

OK, maybe a comment here would be worthwhile?

--
Martin <http://launchpad.net/~mbp/>

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Is this still in progress?

lp:~spiv/bzr-usertest/network-suite updated
125. By Andrew Bennetts

Merge trunk.

126. By Andrew Bennetts

Remove a touch of duplication.

127. By Andrew Bennetts

Merge fix-tests.

128. By Andrew Bennetts

Fix handling config var substitution for network suite.

Unmerged revisions

128. By Andrew Bennetts

Fix handling config var substitution for network suite.

127. By Andrew Bennetts

Merge fix-tests.

126. By Andrew Bennetts

Remove a touch of duplication.

125. By Andrew Bennetts

Merge trunk.

124. By Andrew Bennetts

Fix thinko.

123. By Andrew Bennetts

Extend script_network to cover the significant cases from http://bazaar-vcs.org/SmartPushAnalysis1.4

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '__init__.py'
2--- __init__.py 2009-03-27 06:17:04 +0000
3+++ __init__.py 2011-02-16 06:18:13 +0000
4@@ -1,4 +1,4 @@
5-# Copyright (C) 2007 Canonical Ltd
6+# Copyright (C) 2007, 2009 Canonical Ltd
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10@@ -295,6 +295,7 @@
11 user_params = params_dict
12 if config_file is None:
13 per_tree_params = None
14+ dynamic_user_params = None
15 else:
16 config = ConfigParser.SafeConfigParser()
17 try:
18@@ -304,6 +305,7 @@
19 return 1
20 config.readfp(cfg_fp)
21 user_params.update(dict(config.items('DEFAULT')))
22+ dynamic_user_params = dict(config.items('DYNAMIC'))
23 per_tree_params = {}
24 for tree in trees_list:
25 basename = os.path.basename(tree)
26@@ -350,8 +352,8 @@
27 measures_list, data_file, dry_run=dry_run,
28 keep_dirs=keep_dirs, verbose=verbose, profiler=prof,
29 prof_out_template=prof_out_template,
30- dynamic_params=user_params, per_tree_params=per_tree_params,
31- strict=strict, url=url)
32+ user_params=user_params, per_tree_params=per_tree_params,
33+ dynamic_user_params=dynamic_user_params, strict=strict, url=url)
34 finally:
35 data_file.close()
36 return result
37@@ -369,13 +371,20 @@
38 trees = dict(config.items('DEFAULT'))
39 default_tree = trees.get("default")
40 relpath = trees.get(tool_name, default_tree)
41+ if relpath is None:
42+ raise errors.BzrCommandError(
43+ "no archive defined for tool '%s' in lookup file '%s'"
44+ % (tool_name,ini_file))
45 tree_path = osutils.pathjoin(basepath, relpath)
46 tool_params = {}
47 for sect in config.sections():
48 if not sect.startswith("parameter:"):
49 continue
50 param_name = sect[len('parameter:'):].strip()
51- tool_params[param_name] = config.get(sect, tool_name)
52+ try:
53+ tool_params[param_name] = config.get(sect, tool_name)
54+ except ConfigParser.NoOptionError:
55+ tool_params[param_name] = config.get(sect, 'default')
56 cfg_fp.close()
57 return tree_path, tool_params
58
59@@ -418,9 +427,14 @@
60 class cmd_usertestcompare(Command):
61 """Generate a comparison report on csv data produced by userteststats.
62
63- The CSV files must have names of the form $tool-$suite-$scenario.csv
64- (where the components do not contain dashes) and the suite name corresponds
65- to the usertest suite used to generate the data, e.g. "common" or "log".
66+ The CSV files must have names of the form $tool-$suite-$scenario.csv:
67+
68+ * $tool is the name of the tool used in the run, like "bzr-1.12". It
69+ may optionally have a version, separated by a dash.
70+ * $suite is the usertest suite used to generate the data, e.g. "common"
71+ or "log"; it must not contain a dash.
72+ * $scenario is an arbitrary name for the scenario being tested, again
73+ containing no dashes.
74 """
75 hidden = True
76 takes_args = ['csv_files+']
77
78=== modified file 'archiveutil.py'
79--- archiveutil.py 2009-04-02 12:10:24 +0000
80+++ archiveutil.py 2011-02-16 06:18:13 +0000
81@@ -81,7 +81,7 @@
82 # need to specially construct a root and ensure all files go in there.
83 members.sort()
84 if not members[0].isdir():
85- root_dir == ''
86+ root_dir = ''
87 shared_root = False
88 else:
89 root_dir = members[0].name
90
91=== modified file 'compare.py'
92--- compare.py 2009-04-02 13:42:24 +0000
93+++ compare.py 2011-02-16 06:18:13 +0000
94@@ -78,11 +78,7 @@
95
96 # Collect the additional info for the report: headings, etc.
97 hdgs = order * column_count
98- # If we're comparing different tools (e.g. bzr vs hg), then it might be
99- # better to make the descriptions show both commands. For now, assume
100- # we're mostly benching one bzr release vs another so just the first
101- # tool is good enough.
102- action_descriptions = get_action_descriptions(suite, tools[0], labels)
103+ action_descriptions = get_action_descriptions(suite, tools, labels)
104
105 # Build the cross-file report
106 if html:
107@@ -108,24 +104,43 @@
108 return result
109
110
111-def get_action_descriptions(suite_name, tool, labels):
112+def get_action_descriptions(suite_name, tools, labels):
113 """Get the dictionary of action descriptions indexed by labels for a suite."""
114 suite = suiterunner.get_suite_by_name(suite_name)
115- essential_params = {}
116 descriptions = {}
117 for script in suite.iter_scripts():
118 script_id = script.name()
119 if script_id .endswith("Task"):
120 script_id = script_id[:-4]
121- real_tool = usertool.get_tool_by_fuzzy_name(tool)[0].name
122- cmds_by_labels = script.get_commands_by_label(real_tool,
123- essential_params)
124+ cmds_by_labels = _get_cmds_for_labels(script, tools)
125 for label in cmds_by_labels:
126 compound_name = "%s:%s" % (script_id,label)
127 descriptions[compound_name] = cmds_by_labels[label]
128 return descriptions
129
130
131+def _get_cmds_for_labels(script, tools):
132+ result = {}
133+ # Collect the cmds as lists indexed by labels
134+ for tool in tools:
135+ essential_params = {}
136+ real_tool = usertool.get_tool_by_fuzzy_name(tool)[0].name
137+ cmds = script.get_commands_by_label(real_tool, essential_params)
138+ for label, cmd in cmds.items():
139+ if label in result:
140+ result[label].append(cmd)
141+ else:
142+ result[label] = [cmd]
143+
144+ # Now collapse the lists we can
145+ for label, cmds in result.items():
146+ # Split out the parameters from the command name
147+ params = set([cmd.split(" ", 1)[-1] for cmd in cmds])
148+ if len(params) == 1:
149+ result[label] = "$tool %s" % (params.pop(),)
150+ return result
151+
152+
153 class ReportFormatter(object):
154
155 def format(self, hdgs, labels, data, projects, action_descriptions):
156@@ -165,6 +180,8 @@
157 if c.find('.') != -1:
158 c = "%.1f" % float(c)
159 s += c.rjust(10)
160+ if isinstance(desc, list):
161+ desc = "; ".join(desc)
162 s += " %s" % desc
163 return s
164
165@@ -190,7 +207,7 @@
166 return "<tr>" + s + "</tr>"
167
168 def _columns(self, label, cols, desc, columns_per_project):
169- s = '<td align="left">%s</td>' % label
170+ s = '<td align="left" valign="top">%s</td>' % label
171 for i, c in enumerate(cols):
172 if i % columns_per_project == 0:
173 first = None
174@@ -201,21 +218,26 @@
175 c = "%.1f" % value
176 if first is None:
177 first = value
178- elif abs(value - first) < 0.1:
179+ elif abs(value - first) < 0.15:
180 # difference too small to highlight
181 pass
182- elif value > first * 1.05:
183- colour = "red"
184- elif value > first:
185- colour = "yellow"
186+ elif value > first * 2.00:
187+ colour = "OrangeRed"
188+ elif value > first * 1.33:
189+ colour = "Orange"
190+ elif value > first * 1.06:
191+ colour = "Yellow"
192 elif value < first * 0.50:
193 colour = "Cyan"
194 elif value < first * 0.75:
195 colour = "SkyBlue"
196 elif value < first * 0.95:
197 colour = "LightGreen"
198- s += '<td align="right" bgcolor="%s">%s</td>' % (colour, c)
199+ s += '<td align="right" valign="top" bgcolor="%s">%s</td>' % \
200+ (colour, c)
201 if desc is not None:
202+ if isinstance(desc, list):
203+ desc = "<br>".join(desc)
204 s += '<td>&nbsp;</td><td align="left">%s</td>' % desc
205 return "<tr>" + s + "</tr>"
206
207@@ -226,19 +248,20 @@
208 print "<html>\n<body>"
209 print "<table>"
210 print self._heading_columns("Projects:", project_hdgs, "")
211- print self._heading_columns("Action", hdgs, "Description")
212+ print self._heading_columns("Action", hdgs, "Commands")
213 for label in labels:
214 desc = action_descriptions.get(label, "")
215 print self._columns(label, data[label], desc, columns_per_project)
216 print "</table>"
217 print "<p></p>"
218 print "<table>"
219- print "<th>Legend:</th>%s%s%s%s%s</tr>" % (
220- '<td bgcolor="red">slower &gt; 5%</td>',
221- '<td bgcolor="yellow">slower</td>',
222- '<td bgcolor="LightGreen">faster &gt; 5%</td>',
223- '<td bgcolor="SkyBlue">faster &gt; 25%</td>',
224- '<td bgcolor="Cyan">faster &gt; 50%</td>',
225+ print "<th>Legend:</th>%s%s%s%s%s%s</tr>" % (
226+ '<td bgcolor="OrangeRed">worse &gt; 2x</td>',
227+ '<td bgcolor="Orange">worse &gt; 1.33x</td>',
228+ '<td bgcolor="Yellow">worse &gt; 1.06x</td>',
229+ '<td bgcolor="LightGreen">better &gt; 5%</td>',
230+ '<td bgcolor="SkyBlue">better &gt; 25%</td>',
231+ '<td bgcolor="Cyan">better &gt; 50%</td>',
232 )
233 print "</table>"
234 print "</body>\n</html>"
235
236=== modified file 'datadump.py'
237--- datadump.py 2008-02-29 03:33:24 +0000
238+++ datadump.py 2011-02-16 06:18:13 +0000
239@@ -75,7 +75,7 @@
240 file_writer = csv.writer(data_file)
241 # Dump a header
242 time_str = time.asctime()
243- file_count = unpack_stats.get('file_count', '??')
244+ file_count = unpack_stats.get('other_count', '??')
245 header = "suite %s on tree %s at %s (%s files)" % \
246 (suite, tree, time_str, file_count)
247 data_file.write("--run %d: %s\n" % (run_id,header))
248@@ -85,6 +85,8 @@
249 _nice_time_report(stdout, csv_data)
250 # Collect and report the disk space used by each tool
251 disk_usage_dict = _get_disk_usage_of_subdirs(work_root)
252+ disk_usage_dict[':control-directory:'] = unpack_stats['control_size']
253+ disk_usage_dict[':working-tree:'] = unpack_stats['other_size']
254 disk_usage_data = _dict_to_csv(disk_usage_dict, "Directory", "MB",
255 value_formatter=_disk_size_as_str)
256 if disk_usage_data is not None:
257@@ -192,7 +194,11 @@
258 stdout.write("%s\t%s\t%s\n" % ("Old:New", "MB", "Directory"))
259 for key in keys:
260 new_size = disk_usage_dict[key]
261- ratio = new_size * 1.0 / baseline_dir_size
262+ if key[0] == ':' and key[-1] == ':':
263+ # special statistic
264+ ratio = 0
265+ else:
266+ ratio = new_size * 1.0 / baseline_dir_size
267 size_in_mbytes = _disk_size_as_str(new_size)
268 stdout.write("%.3f\t%s\t%s\n" % (ratio,size_in_mbytes,key))
269
270
271=== modified file 'dirutil.py'
272--- dirutil.py 2009-02-23 03:46:54 +0000
273+++ dirutil.py 2011-02-16 06:18:13 +0000
274@@ -64,6 +64,13 @@
275 error("%d problems removing %s - manual clean-up may be required" %
276 (_cleanup_error_count,path))
277
278+def dir_count(start):
279+ """Get the number of files in a directory tree."""
280+ total = 0L
281+ for root, dirs, files in os.walk(start):
282+ total += len(dirs) + len(files)
283+ return total
284+
285
286 def dir_used_size(start):
287 "Get bytes used by files in a directory."
288
289=== added file 'scripts/script_commit.py'
290--- scripts/script_commit.py 1970-01-01 00:00:00 +0000
291+++ scripts/script_commit.py 2011-02-16 06:18:13 +0000
292@@ -0,0 +1,34 @@
293+# Copyright (C) 2007, 2008 Canonical Ltd
294+#
295+# This program is free software; you can redistribute it and/or modify
296+# it under the terms of the GNU General Public License as published by
297+# the Free Software Foundation; either version 2 of the License, or
298+# (at your option) any later version.
299+#
300+# This program is distributed in the hope that it will be useful,
301+# but WITHOUT ANY WARRANTY; without even the implied warranty of
302+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
303+# GNU General Public License for more details.
304+#
305+# You should have received a copy of the GNU General Public License
306+# along with this program; if not, write to the Free Software
307+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
308+
309+"""Script covering commit operations in Bazaar."""
310+
311+from bzrlib.plugins.usertest.userscript import ScriptTask, ScriptSuite
312+import script_common
313+
314+
315+## Suite ##
316+
317+def script_suite():
318+
319+ suite = ScriptSuite()
320+ # Setup
321+ suite.add(script_common.SetupSuite())
322+ # Work
323+ suite.add(script_common.AddTask())
324+ suite.add(script_common.ChangeTask())
325+ suite.add(script_common.ChangeFileTask())
326+ return suite
327
328=== modified file 'scripts/script_common.py'
329--- scripts/script_common.py 2009-03-25 23:59:10 +0000
330+++ scripts/script_common.py 2011-02-16 06:18:13 +0000
331@@ -24,6 +24,12 @@
332
333 * 'additional' tasks are ones that other VCS tools might support
334 but we're only interested in their speed on Bazaar.
335+
336+The following variables need to be set before calling this script:
337+
338+ * file - the file to use for file-specific logging
339+
340+This variable is used in the log, annotate and cat tasks.
341 """
342
343 from bzrlib.plugins.usertest.userscript import ScriptTask, ScriptSuite
344@@ -72,6 +78,10 @@
345 once_only = True
346
347 def load(self):
348+ # To trigger this, run a script called bzr-current
349+ self.compile_for_versions(TOOL_BZR, "current", """
350+ $tool upgrade --1.9
351+ """)
352 # To trigger this, run a script called bzr-btree
353 self.compile_for_versions(TOOL_BZR, "btree", """
354 $tool upgrade --1.9
355@@ -80,29 +90,9 @@
356 self.compile_for_versions(TOOL_BZR, "development", """
357 $tool upgrade --development
358 """)
359- # To trigger this, run a script called bzr-dev5plain
360- self.compile_for_versions(TOOL_BZR, "dev5plain", """
361- $tool upgrade --development5
362- """)
363- # To trigger this, run a script called bzr-dev5h16
364- self.compile_for_versions(TOOL_BZR, "dev5h16", """
365- $tool upgrade --development5-hash16
366- """)
367- # To trigger this, run a script called bzr-dev5h255
368- self.compile_for_versions(TOOL_BZR, "dev5h255", """
369- $tool upgrade --development5-hash255
370- """)
371- # To trigger this, run a script called bzr-gcnrr
372- self.compile_for_versions(TOOL_BZR, "gcnrr", """
373- $tool upgrade --gc-no-rich-root
374- """)
375- # To trigger this, run a script called bzr-gcchk16
376- self.compile_for_versions(TOOL_BZR, "gcchk16", """
377- $tool upgrade --gc-chk16
378- """)
379- # To trigger this, run a script called bzr-gcchk255
380- self.compile_for_versions(TOOL_BZR, "gcchk255", """
381- $tool upgrade --gc-chk255
382+ # To trigger this, run a script called bzr-dev6
383+ self.compile_for_versions(TOOL_BZR, "dev6", """
384+ $tool upgrade --development6-rich-root
385 """, exit_codes={'upgrade': [0, 3]})
386 # To trigger this, run a script called bzr-gcchk255
387 self.compile_for_versions(TOOL_BZR, "gcchk255big", """
388@@ -124,24 +114,36 @@
389 def load(self):
390 self.compile_for_tools([TOOL_BZR], """
391 cd ..
392- $tool init-repo repo --${format}
393- $tool branch $work_basename repo/${work_basename} ## unshared
394- cd repo
395- $tool branch $work_basename fix ## shared
396- $tool branch fix fix2 --no-tree ## sharedNoTree
397- cd $work_basename
398- """)
399- self.compile_for_tools([TOOL_GIT, TOOL_HG], """
400- cd ..
401- $tool clone $work_basename ${work_basename}-branchAndFix ## unshared
402- cd ${work_basename}-branchAndFix
403+ $tool init-repo project --${format}
404+ $tool branch $work_basename project/trunk ## unshared
405+ cd project
406+ $tool branch trunk fix ## shared
407+ $tool branch fix fix2 --no-tree ## sharedNoTree
408+ cd fix
409+ """)
410+ self.compile_for_tools([TOOL_HG], """
411+ cd ..
412+ mkdir project
413+ $tool clone --pull $work_basename project/trunk ## unshared
414+ cd project
415+ $tool clone trunk fix ## shared
416+ $tool clone -U fix fix2 ## sharedNoTree
417+ cd fix
418+ """)
419+ self.compile_for_tools([TOOL_GIT], """
420+ cd ..
421+ mkdir project
422+ $tool clone $work_basename project/trunk ## unshared
423+ cd project
424+ $tool clone trunk fix ## shared
425+ cd fix
426 """)
427
428
429 class AddTask(ScriptTask):
430
431 def load(self):
432- self.compile_default("""
433+ self.compile_for_tools([TOOL_BZR], """
434 mkdir zzzDir
435 echo "# junk" > zzzDir/zzzFile
436 $tool add
437@@ -149,6 +151,16 @@
438 $tool diff
439 $tool commit -m "testing add"
440 """, exit_codes={'diff': 1})
441+ # hg is the same except for the diff exit code
442+ self.compile_for_tools([TOOL_HG], """
443+ mkdir zzzDir
444+ echo "# junk" > zzzDir/zzzFile
445+ $tool add
446+ $tool status
447+ $tool diff
448+ $tool commit -m "testing add"
449+ """)
450+ # git needs an extra option to diff as well
451 self.compile_for_tools([TOOL_GIT], """
452 mkdir zzzDir
453 echo "# junk" > zzzDir/zzzFile
454@@ -162,12 +174,20 @@
455 class ChangeTask(ScriptTask):
456
457 def load(self):
458- self.compile_default("""
459+ self.compile_for_tools([TOOL_BZR], """
460 echo "# more junk" >> zzzDir/zzzFile
461 $tool status
462 $tool diff
463 $tool commit -m "testing change"
464 """, exit_codes={'diff': 1})
465+ # hg is the same except for the diff exit code
466+ self.compile_for_tools([TOOL_HG], """
467+ echo "# more junk" >> zzzDir/zzzFile
468+ $tool status
469+ $tool diff
470+ $tool commit -m "testing change"
471+ """)
472+ # git needs an explicit add and different diff cli
473 self.compile_for_tools([TOOL_GIT], """
474 echo "# more junk" >> zzzDir/zzzFile
475 $tool add
476@@ -177,24 +197,54 @@
477 """)
478
479
480+class ChangeFileTask(ScriptTask):
481+
482+ def load(self):
483+ self.compile_for_tools([TOOL_BZR], """
484+ echo "# more junk" >> zzzDir/zzzFile
485+ $tool status zzzDir/zzzFile
486+ $tool diff zzzDir/zzzFile
487+ $tool commit -m "testing change file" zzzDir/zzzFile
488+ """, exit_codes={'diff': 1})
489+ # hg is the same except for the diff exit code
490+ self.compile_for_tools([TOOL_HG], """
491+ echo "# more junk" >> zzzDir/zzzFile
492+ $tool status zzzDir/zzzFile
493+ $tool diff zzzDir/zzzFile
494+ $tool commit -m "testing change file" zzzDir/zzzFile
495+ """)
496+ # git needs an explicit add and different diff cli
497+ self.compile_for_tools([TOOL_GIT], """
498+ echo "# more junk" >> zzzDir/zzzFile
499+ $tool add zzzDir/zzzFile
500+ $tool status
501+ $tool diff --cached
502+ $tool commit -m "testing change file"
503+ """)
504+
505+
506 class BranchAddChangeSuite(ScriptSuite):
507
508 def load(self):
509 self.add(BranchTask())
510 self.add(AddTask())
511 self.add(ChangeTask())
512+ self.add(ChangeFileTask())
513
514
515 ## Work Scripts - Additional ##
516
517-class BundleTask(ScriptTask):
518+class SendTask(ScriptTask):
519
520 def load(self):
521 # This can fail if there's no submit branch, which there isn't
522 # if we're excluding the BranchTask during a run say
523 self.compile_for_tools([TOOL_BZR], """
524- $tool send -o zzzBundle.path
525+ $tool send -o zzzBundle.patch
526 """, exit_codes={'send': [0, 3]})
527+ self.compile_for_tools([TOOL_HG], """
528+ $tool bundle zzzBundle.patch ../trunk ## send
529+ """)
530
531
532 class RemoveTask(ScriptTask):
533@@ -235,8 +285,13 @@
534 class TagTask(ScriptTask):
535
536 def load(self):
537- self.compile_default("""
538- $tool tag BETA-1
539+ self.compile_for_tools([TOOL_BZR, TOOL_HG], """
540+ $tool tag BETA-1
541+ $tool tags
542+ """)
543+ self.compile_for_tools([TOOL_GIT], """
544+ $tool tag BETA-1
545+ $tool tag ## tags
546 """)
547
548
549@@ -287,13 +342,32 @@
550 def load(self):
551 self.compile_default("""
552 $tool log
553- $tool log zzzDir/zzzFile ## oneFile
554- """)
555- self.compile_for_tools([TOOL_BZR], """
556- $tool log
557- $tool log zzzDir/zzzFile ## oneFile
558- $tool log -n1 ## mainline
559- $tool log -n1 zzzDir/zzzFile ## mainlineOneFile
560+ """)
561+ self.compile_for_tools([TOOL_BZR], """
562+ $tool log
563+ $tool log -n0 ## detailed
564+ """)
565+ self.compile_for_tools([TOOL_HG], """
566+ $tool log
567+ $tool log --follow ## detailed
568+ """)
569+
570+
571+class LogFileTask(ScriptTask):
572+
573+ run_if_defined = ['file']
574+
575+ def load(self):
576+ self.compile_default("""
577+ $tool log $file
578+ """)
579+ self.compile_for_tools([TOOL_BZR], """
580+ $tool log $file
581+ $tool log -n0 $file ## detailed
582+ """)
583+ self.compile_for_tools([TOOL_HG], """
584+ $tool log $file
585+ $tool log --follow $file ## detailed
586 """)
587
588
589@@ -308,9 +382,11 @@
590
591 class AnnotateTask(ScriptTask):
592
593+ run_if_defined = ['file']
594+
595 def load(self):
596 self.compile_default("""
597- $tool annotate zzzDir/zzzFile
598+ $tool annotate $file
599 """)
600
601
602@@ -355,9 +431,11 @@
603
604 class FileContentTask(ScriptTask):
605
606+ run_if_defined = ['file']
607+
608 def load(self):
609 self.compile_for_tools([TOOL_BZR], """
610- $tool cat -r -1 zzzDir/zzzFile
611+ $tool cat -r -1 $file
612 """)
613
614
615@@ -365,11 +443,20 @@
616
617 def load(self):
618 self.compile_for_tools([TOOL_BZR], """
619- $tool status -r -2..-1
620- $tool diff -r -2..-1
621- $tool ls -r -1 --non-recursive ## listRoot
622- $tool ls -r -1 ## listAll
623+ $tool log -r -1
624+ $tool status -c -1
625+ $tool diff -c -1
626+ $tool ls -r -1 ## list
627+ $tool ls -r -1 --recursive ## listAll
628 """, exit_codes={'diff': 1})
629+ # Note: hg locate has no way of limiting recusion down
630+ self.compile_for_tools([TOOL_HG], """
631+ $tool tip ## log
632+ $tool status -r tip
633+ $tool diff -r tip
634+ $tool locate -r tip ## list
635+ $tool locate -r tip ## listAll
636+ """)
637
638
639
640@@ -461,14 +548,10 @@
641 suite.add(SetupSuite())
642 # Work
643 suite.add(BranchAddChangeSuite())
644- suite.add(BundleTask()) # TODO: remove once default script = local
645- # Admin
646- suite.add(TagTask())
647+ suite.add(SendTask())
648 # Info
649- suite.add(HelpTask())
650- suite.add(ChangeInfoTask())
651 suite.add(LogTask())
652+ suite.add(LogFileTask())
653 suite.add(AnnotateTask())
654- suite.add(TagsTask())
655 suite.add(HistoryTask())
656 return suite
657
658=== modified file 'scripts/script_log.py'
659--- scripts/script_log.py 2009-04-02 13:52:55 +0000
660+++ scripts/script_log.py 2011-02-16 06:18:13 +0000
661@@ -64,43 +64,43 @@
662 def load(self):
663 # Note: do not add log -v below - it belongs in the logplus suite
664 self.compile_for_tools([TOOL_BZR], """
665- $tool log --short ## mainline
666- $tool log --short $file ## mainline-file
667- $tool log --long ## merges
668- $tool log --long $file ## merges-file
669+ $tool log ## mainline
670+ $tool log $file ## mainline-file
671+ $tool log -n0 ## merges
672+ $tool log -n0 $file ## merges-file
673 """)
674
675 class LogRecentTask(ScriptTask):
676
677 def load(self):
678 self.compile_for_tools([TOOL_BZR], """
679- $tool log -r-10.. --short ## mainline
680- $tool log -r-10.. --short --forward ## mainline-forward
681- $tool log -r-10.. --short $file ## mainline-file
682- $tool log -r-10.. --short -v ## mainline-delta
683- $tool log -r-10.. --long ## merges
684- $tool log -r-10.. --long $file ## merges-file
685- $tool log -r-10.. --long -v ## merges-delta
686+ $tool log -r-10.. ## mainline
687+ $tool log -r-10.. --forward ## mainline-forward
688+ $tool log -r-10.. $file ## mainline-file
689+ $tool log -r-10.. -v ## mainline-delta
690+ $tool log -r-10.. -n0 ## merges
691+ $tool log -r-10.. -n0 $file ## merges-file
692+ $tool log -r-10.. -n0 -v ## merges-delta
693 """)
694
695 class LogTipTask(ScriptTask):
696
697 def load(self):
698 self.compile_for_tools([TOOL_BZR], """
699- $tool log -r-1 --short ## top
700- $tool log -r-1 --short -v ## top-delta
701- $tool log -r-1 --long ## merges
702- $tool log -r-1 --long -v ## merges-delta
703+ $tool log -r-1 ## top
704+ $tool log -r-1 -v ## top-delta
705+ $tool log -r-1 -n0 ## merges
706+ $tool log -r-1 -n0 -v ## merges-delta
707 """)
708
709 class LogMainlineTask(ScriptTask):
710
711 def load(self):
712 self.compile_for_tools([TOOL_BZR], """
713- $tool log -r-10 --short ## top
714- $tool log -r-10 --short -v ## top-delta
715- $tool log -r-10 --long ## merges
716- $tool log -r-10 --long -v ## merges-delta
717+ $tool log -r-10 ## top
718+ $tool log -r-10 -v ## top-delta
719+ $tool log -r-10 -n0 ## merges
720+ $tool log -r-10 -n0 -v ## merges-delta
721 """)
722
723 class LogMergeRevisionTask(ScriptTask):
724@@ -109,30 +109,30 @@
725
726 def load(self):
727 self.compile_for_tools([TOOL_BZR], """
728- $tool log -r$merge_revision --short ## top
729- $tool log -r$merge_revision --short -v ## top-delta
730- $tool log -r$merge_revision --long ## merges
731- $tool log -r$merge_revision --long -v ## merges-delta
732+ $tool log -r$merge_revision ## top
733+ $tool log -r$merge_revision -v ## top-delta
734+ $tool log -r$merge_revision -n0 ## merges
735+ $tool log -r$merge_revision -n0 -v ## merges-delta
736 """)
737
738 class LogInitialTask(ScriptTask):
739
740 def load(self):
741 self.compile_for_tools([TOOL_BZR], """
742- $tool log -r1 --short ## top
743- $tool log -r1 --short -v ## top-delta
744- $tool log -r1 --long ## merges
745- $tool log -r1 --long -v ## merges-delta
746+ $tool log -r1 ## top
747+ $tool log -r1 -v ## top-delta
748+ $tool log -r1 -n0 ## merges
749+ $tool log -r1 -n0 -v ## merges-delta
750 """)
751
752 class LogEarlyTask(ScriptTask):
753
754 def load(self):
755 self.compile_for_tools([TOOL_BZR], """
756- $tool log -r..10 --short ## mainline
757- $tool log -r..10 --short -v ## mainline-delta
758- $tool log -r..10 --long ## merges
759- $tool log -r..10 --long -v ## merges-delta
760+ $tool log -r..10 ## mainline
761+ $tool log -r..10 -v ## mainline-delta
762+ $tool log -r..10 -n0 ## merges
763+ $tool log -r..10 -n0 -v ## merges-delta
764 """)
765
766 class LogEarlyFileTask(ScriptTask):
767@@ -141,32 +141,32 @@
768
769 def load(self):
770 self.compile_for_tools([TOOL_BZR], """
771- $tool log -r..10 --short $early_file ## mainline-file
772- $tool log -r..10 --long $early_file ## merges-file
773+ $tool log -r..10 $early_file ## mainline-file
774+ $tool log -r..10 -n0 $early_file ## merges-file
775 """)
776
777 class LogIncrementalAllTask(ScriptTask):
778
779 def load(self):
780 self.compile_for_tools([TOOL_BZR], """
781- $tool log -l5 --short ## mainline
782- $tool log -l5 --short $file ## mainline-file
783- $tool log -l5 --short -v ## mainline-delta
784- $tool log -l5 --long ## merges
785- $tool log -l5 --long $file ## merges-file
786- $tool log -l5 --long -v ## merges-delta
787+ $tool log -l5 ## mainline
788+ $tool log -l5 $file ## mainline-file
789+ $tool log -l5 -v ## mainline-delta
790+ $tool log -l5 -n0 ## merges
791+ $tool log -l5 -n0 $file ## merges-file
792+ $tool log -l5 -n0 -v ## merges-delta
793 """)
794
795 class LogIncrementalRecentTask(ScriptTask):
796
797 def load(self):
798 self.compile_for_tools([TOOL_BZR], """
799- $tool log -l5 -r-10.. --short ## mainline
800- $tool log -l5 -r-10.. --short $file ## mainline-file
801- $tool log -l5 -r-10.. --short -v ## mainline-delta
802- $tool log -l5 -r-10.. --long ## merges
803- $tool log -l5 -r-10.. --long $file ## merges-file
804- $tool log -l5 -r-10.. --long -v ## merges-delta
805+ $tool log -l5 -r-10.. ## mainline
806+ $tool log -l5 -r-10.. $file ## mainline-file
807+ $tool log -l5 -r-10.. -v ## mainline-delta
808+ $tool log -l5 -r-10.. -n0 ## merges
809+ $tool log -l5 -r-10.. -n0 $file ## merges-file
810+ $tool log -l5 -r-10.. -n0 -v ## merges-delta
811 """)
812
813
814
815=== modified file 'scripts/script_logplus.py'
816--- scripts/script_logplus.py 2009-04-02 07:21:04 +0000
817+++ scripts/script_logplus.py 2011-02-16 06:18:13 +0000
818@@ -38,24 +38,24 @@
819
820 def load(self):
821 self.compile_for_tools([TOOL_BZR], """
822- $tool log --short -v ## mainline
823- $tool log --long -v ## merges
824+ $tool log -n1 -v ## mainline
825+ $tool log -n0 -v ## merges
826 """)
827
828 class LogPatchesTask(ScriptTask):
829
830 def load(self):
831 self.compile_for_tools([TOOL_BZR], """
832- $tool log --short -p ## mainline
833- $tool log --long -p ## merges
834+ $tool log -n1 -p ## mainline
835+ $tool log -n0 -p ## merges
836 """)
837
838 class LogDirectoryTask(ScriptTask):
839
840 def load(self):
841 self.compile_for_tools([TOOL_BZR], """
842- $tool log --short $dir ## mainline
843- $tool log --long $dir ## merges
844+ $tool log -n1 $dir ## mainline
845+ $tool log -n0 $dir ## merges
846 """)
847
848
849
850=== modified file 'scripts/script_network.py'
851--- scripts/script_network.py 2009-02-14 07:17:15 +0000
852+++ scripts/script_network.py 2011-02-16 06:18:13 +0000
853@@ -64,6 +64,7 @@
854 ## Scripts ##
855
856 class InitialPushTask(ScriptTask):
857+ """Push into a new shared repository."""
858
859 def load(self):
860 self.compile_for_tools([TOOL_BZR], """
861@@ -107,48 +108,99 @@
862
863 class AnotherBranchTask(ScriptTask):
864
865+ def __init__(self, branch_name='-anotherBranch'):
866+ self._branch_name = branch_name
867+ super(AnotherBranchTask, self).__init__()
868+
869+ def id(self):
870+ return super(AnotherBranchTask, self).id() + self._branch_name
871+
872+ def name(self):
873+ return super(AnotherBranchTask, self).name() + self._branch_name
874+
875 def load(self):
876- self.compile_default("""
877+ script = ("""
878 cd ..
879- $tool clone $repo_read_url/trunk ${work_basename}-anotherBranch
880- cd ${work_basename}-anotherBranch
881- """)
882+ $tool clone $repo_read_url/trunk ${work_basename}%(branch_name)s
883+ cd ${work_basename}%(branch_name)s
884+ """ % {'branch_name': self._branch_name})
885+ self.compile_default(script)
886 # Go up an extra level for Bazaar to get outside the shared repo
887 self.compile_for_tools([TOOL_BZR], """
888- cd ..
889- cd ..
890- $tool clone $repo_read_url/trunk ${work_basename}-anotherBranch
891- cd ${work_basename}-anotherBranch
892- """)
893+ cd ..""" + script)
894
895
896 class AnotherPushTask(ScriptTask):
897-
898+ """Push a branch into an existing shared repository."""
899+
900+ def __init__(self, expect_diverged_error=False, label=''):
901+ self._expect_diverged_error = expect_diverged_error
902+ self._label = label
903+ super(AnotherPushTask, self).__init__()
904+
905+ def id(self):
906+ return super(AnotherPushTask, self).id() + self._label
907+
908+ def name(self):
909+ return super(AnotherPushTask, self).name() + self._label
910+
911 def load(self):
912+ if self._expect_diverged_error:
913+ exit_codes = {'bzrpush': 3}
914+ else:
915+ exit_codes = {}
916 self.compile_default("""
917 $tool push $repo_write_url/anotherBranch
918 """)
919 self.compile_for_tools([TOOL_BZR], """
920- $tool push --create-prefix $repo_write_url/anotherBranch
921- """)
922+ $tool push --create-prefix $repo_write_url/anotherBranch ## bzrpush
923+ """, exit_codes=exit_codes)
924 # Hg doesn't support push over sftp out of the box
925 self.compile_for_tools([TOOL_HG, TOOL_GIT], """
926 scp -r . $repo_server:$repo_dir/anotherBranch
927 """)
928
929
930+class PushOverwriteTask(ScriptTask):
931+ """Push a branch into an existing shared repository."""
932+
933+ def load(self):
934+ self.compile_for_tools([TOOL_BZR], """
935+ $tool push --overwrite $repo_write_url/anotherBranch
936+ """)
937+
938+
939+class DivergeTask(ScriptTask):
940+ """Make a branch that diverges."""
941+
942+ def load(self):
943+ self.compile_default("""
944+ $tool push $repo_write_url/anotherBranch
945+ """)
946+
947 ## Suite ##
948
949 def script_suite():
950
951 suite = ScriptSuite()
952+ # Initialise: make standalone 'trunk' locally
953 suite.add(script_common.SetupSuite())
954+ # Push branch into empty shared repo
955 suite.add(InitialPushTask())
956+ # Push one new revision onto existing remote branch
957 suite.add(script_common.BranchTask())
958 suite.add(script_common.AddTask())
959 suite.add(PushChangesTask())
960+ # Pull that one new revision back to local 'trunk'
961 suite.add(RefreshMirrorTask())
962+ # Push a new branch to shared repo with one new revision.
963 suite.add(AnotherBranchTask())
964 suite.add(script_common.ChangeTask())
965 suite.add(AnotherPushTask())
966+ # Push to a diverged branch, resulting in error.
967+ suite.add(AnotherBranchTask(branch_name='-divergedBranch'))
968+ suite.add(script_common.ChangeTask())
969+ suite.add(AnotherPushTask(expect_diverged_error=True, label='-diverged'))
970+ # Push to diverged branch, with overwrite.
971+ suite.add(PushOverwriteTask())
972 return suite
973
974=== modified file 'statistics.py'
975--- statistics.py 2009-02-23 03:46:54 +0000
976+++ statistics.py 2011-02-16 06:18:13 +0000
977@@ -52,9 +52,12 @@
978 self.slow_counts = {}
979 self.vslow_counts = {}
980 self.vvslow_counts = {}
981+ self.space_originals = {}
982 self.space_totals = {}
983 self.space_ratios = {}
984 self.file_counts = {}
985+ self.control_spaces = {}
986+ self.working_spaces = {}
987
988
989 def get_project_run(report_name):
990@@ -99,8 +102,11 @@
991 vslow_count = 0
992 vvslow_count = 0
993 space_ratio = 0
994+ space_original = 0
995 space_total = 0
996 file_count = 0
997+ control_space = 0
998+ working_space = 0
999 looking_for_times = True
1000 found_times = False
1001 looking_for_space = False
1002@@ -137,8 +143,15 @@
1003 elif found_space:
1004 # accumulate the space usage data if on multiple lines
1005 (dir_ratio,dir_total,dir) = line.split()
1006- space_ratio += float(dir_ratio)
1007- space_total += float(dir_total)
1008+ if dir.startswith(':control'):
1009+ control_space = float(dir_total)
1010+ elif dir.startswith(':working'):
1011+ working_space = float(dir_total)
1012+ else:
1013+ space_ratio += float(dir_ratio)
1014+ space_total += float(dir_total)
1015+ if space_original == 0:
1016+ space_original = space_total / space_ratio
1017 elif found_times:
1018 (seconds,action) = line.split()
1019 if not verbose:
1020@@ -173,18 +186,24 @@
1021 stats.slow_counts[project][run] = slow_count
1022 stats.vslow_counts[project][run] = vslow_count
1023 stats.vvslow_counts[project][run] = vvslow_count
1024+ stats.space_originals[project][run] = space_original
1025 stats.space_totals[project][run] = space_total
1026 stats.space_ratios[project][run] = space_ratio
1027 stats.file_counts[project][run] = file_count
1028+ stats.control_spaces[project][run] = control_space
1029+ stats.working_spaces[project][run] = working_space
1030 else:
1031 project_runs[project] = {run: total}
1032 stats.fast_counts[project] = {run: fast_count}
1033 stats.slow_counts[project] = {run: slow_count}
1034 stats.vslow_counts[project] = {run: vslow_count}
1035 stats.vvslow_counts[project] = {run: vvslow_count}
1036+ stats.space_originals[project] = {run: space_original}
1037 stats.space_totals[project] = {run: space_total}
1038 stats.space_ratios[project] = {run: space_ratio}
1039 stats.file_counts[project] = {run: file_count}
1040+ stats.control_spaces[project] = {run: control_space}
1041+ stats.working_spaces[project] = {run: working_space}
1042
1043 return all_actions, times, project_runs, stats
1044
1045@@ -228,6 +247,10 @@
1046 # Prepare statistics
1047 files_data = [str(stats.file_counts[p][best_run[p]]) for p in projects]
1048 files_label = "File count:"
1049+ working_data = [str(stats.working_spaces[p][best_run[p]]) for p in projects]
1050+ working_label = "Working space in MB:"
1051+ control_data = [str(stats.control_spaces[p][best_run[p]]) for p in projects]
1052+ control_label = "Control space in MB:"
1053 fast_data = [str(stats.fast_counts[p][best_run[p]]) for p in projects]
1054 fast_label = "Actions <= %d seconds:" % SLOW_THRESHHOLD
1055 slow_data = [str(stats.slow_counts[p][best_run[p]]) for p in projects]
1056@@ -237,19 +260,24 @@
1057 vvslow_data = [str(stats.vvslow_counts[p][best_run[p]]) for p in projects]
1058 vvslow_label = "Actions > %d seconds:" % VVSLOW_THRESHHOLD
1059 sp_ratio_data = [str(stats.space_ratios[p][best_run[p]]) for p in projects]
1060- sp_ratio_label = "Used space vs original:"
1061+ sp_ratio_label = "Final space vs original:"
1062+ sp_original_data = [str(stats.space_originals[p][best_run[p]]) for p in projects]
1063+ sp_original_label = "Original space in MB:"
1064 sp_total_data = [str(stats.space_totals[p][best_run[p]]) for p in projects]
1065- sp_total_label = "Total space in MB:"
1066+ sp_total_label = "Final space in MB:"
1067
1068 # Dump the data
1069 print "Action," + ",".join(projects)
1070 print "%s,%s" % (files_label, ",".join(files_data))
1071+ print "%s,%s" % (working_label, ",".join(working_data))
1072+ print "%s,%s" % (control_label, ",".join(control_data))
1073+ print "%s,%s" % (sp_original_label, ",".join(sp_original_data))
1074+ print "%s,%s" % (sp_total_label, ",".join(sp_total_data))
1075+ print "%s,%s" % (sp_ratio_label, ",".join(sp_ratio_data))
1076 print "%s,%s" % (fast_label, ",".join(fast_data))
1077 print "%s,%s" % (slow_label, ",".join(slow_data))
1078 print "%s,%s" % (vslow_label, ",".join(vslow_data))
1079 print "%s,%s" % (vvslow_label, ",".join(vvslow_data))
1080- print "%s,%s" % (sp_ratio_label, ",".join(sp_ratio_data))
1081- print "%s,%s" % (sp_total_label, ",".join(sp_total_data))
1082 for action in actions:
1083 data = [str(times.get((p,best_run[p],action), "")) for p in projects]
1084 print "%s,%s" % (action, ",".join(data))
1085
1086=== modified file 'suiterunner.py'
1087--- suiterunner.py 2009-04-02 07:21:04 +0000
1088+++ suiterunner.py 2011-02-16 06:18:13 +0000
1089@@ -18,13 +18,13 @@
1090
1091 import os
1092 import random
1093-import shutil
1094 import string
1095 import subprocess
1096 import sys
1097 import time
1098
1099-from bzrlib.trace import info, warning, error
1100+from bzrlib import osutils
1101+from bzrlib.trace import info, log_exception_quietly
1102 import archiveutil
1103 import datadump
1104 import dirutil
1105@@ -36,7 +36,8 @@
1106
1107 def get_suite_names():
1108 # TODO: use reflection to look these up (walk sys.path)
1109- return ['common', 'local', 'network', 'history', 'log', 'logplus', 'mega']
1110+ return ['common', 'local', 'network', 'history', 'log', 'logplus', 'mega',
1111+ 'commit']
1112
1113
1114 def get_suite_by_name(name):
1115@@ -58,7 +59,7 @@
1116 try:
1117 module = __import__(module_name, globals(), locals())
1118 except ImportError, e:
1119- # TODO: log exception properly
1120+ log_exception_quietly()
1121 info("failed to find module %s\nerror: %s" % (module_name, e))
1122 return None
1123 else:
1124@@ -66,7 +67,7 @@
1125 module = getattr(module, part)
1126 fn = getattr(module, 'script_suite', None)
1127 if fn is None:
1128- # TODO: log exception properly
1129+ log_exception_quietly()
1130 info("failed to find script_suite() in %s" % module)
1131 return None
1132 return fn()
1133@@ -99,9 +100,57 @@
1134 os.mkdir(dest)
1135 else:
1136 archiveutil.unpack_archive(tree, dest_dirs, verbose, unpack_stats)
1137+ sample_tool, sample_dir = dirs_by_tool.items()[0]
1138+ control_dir = _control_dir_for(sample_tool)
1139+ unpack_stats.update(_collect_archive_stats(sample_dir, control_dir))
1140 return (work_root,already_there,dirs_by_tool,run_id, unpack_stats)
1141
1142
1143+def _control_dir_for(tool):
1144+ real_tool, version_id = usertool.get_tool_by_fuzzy_name(tool)
1145+ if real_tool is not None:
1146+ return "." + real_tool.name
1147+ else:
1148+ raise AssertionError("unknown control directory for tool %s" % tool)
1149+
1150+
1151+def _collect_archive_stats(work_dir, control_dir):
1152+ """Collect statistics from an unpacked archive.
1153+
1154+ :param work_dir: name of directory to analyze
1155+ :param control_dir: name of control directory, e.g. .bzr, .hg
1156+ :return: a dictionary with keys of:
1157+ * total_count - the # of files in the work directory
1158+ * control_count - the # of files in the control directory
1159+ * other_count - the # of files in the other directories
1160+ * total_size - the size in bytes of the work directory
1161+ * control_size - the size in bytes of the control directory
1162+ * other_size - the size in bytes of the other directories
1163+ """
1164+ # TODO: It would be nice to work out the repo revision count
1165+ # as well, though the logic for that is obviously tool dependent.
1166+ result = {}
1167+ total_count = dirutil.dir_count(work_dir)
1168+ total_size = dirutil.dir_size(work_dir)
1169+ control_path = osutils.pathjoin(work_dir, control_dir)
1170+ if os.path.isdir(control_path):
1171+ control_count = dirutil.dir_count(control_path)
1172+ control_size = dirutil.dir_size(control_path)
1173+ else:
1174+ control_count = 0
1175+ control_size = 0
1176+ result = {
1177+ 'total_count': total_count,
1178+ 'control_count': control_count,
1179+ 'other_count': total_count - control_count,
1180+ 'total_size': total_size,
1181+ 'control_size': control_size,
1182+ 'other_size': total_size - control_size,
1183+ }
1184+ #info("archive stats are: %s" % (result,))
1185+ return result
1186+
1187+
1188 def _run_task_on_dirs(task, dirs_by_tool, measures, initial_params=None,
1189 profiler=None, prof_out_template=None, dry_run=False, tools=None,
1190 dynamic_params=None, per_tree_params=None, verbose=False, strict=False):
1191@@ -191,8 +240,9 @@
1192
1193 def run_suite(self, suite, trees, tools, measures, data_file,
1194 dry_run=False, keep_dirs=False, verbose=False,
1195- profiler=None, prof_out_template=None, dynamic_params=None,
1196- per_tree_params=None, strict=False, url=False):
1197+ profiler=None, prof_out_template=None, user_params=None,
1198+ per_tree_params=None, dynamic_user_params=None, strict=False,
1199+ url=False):
1200 if url:
1201 tree_label = "url"
1202 else:
1203@@ -212,13 +262,13 @@
1204 tree_label: tree,
1205 'tree_id': usertestutil.tree_short_name(tree),
1206 }
1207- all_dynamic_params = {}
1208- if dynamic_params:
1209- all_dynamic_params.update(dynamic_params)
1210+ if user_params:
1211+ initial_params.update(user_params)
1212 if per_tree_params:
1213 tree_params = per_tree_params.get(tree)
1214 if tree_params:
1215- all_dynamic_params.update(tree_params)
1216+ initial_params.update(tree_params)
1217+ dynamic_params = dynamic_user_params.copy()
1218
1219 # Baseline the size of a tree - use last tool to max. cache usage
1220 if not dry_run:
1221@@ -238,14 +288,16 @@
1222 if len(top_level_dirs) == 2 and '.bzr' in top_level_dirs:
1223 top_level_dirs.remove('.bzr')
1224 branch_dir = top_level_dirs[0]
1225- info("found shared repo with branch %s" % branch_dir)
1226- work_dir = os.path.join(work_dir, branch_dir)
1227+ if (os.path.isdir(branch_dir)
1228+ and '.bzr' in os.listdir(branch_dir)):
1229+ info("found shared repo with branch %s" % branch_dir)
1230+ work_dir = os.path.join(work_dir, branch_dir)
1231 dirs_by_tool[tool] = work_dir
1232 temp_dirs = set()
1233 temp_dirs.add(work_root)
1234 csv_data = self.run_tests(suite, dirs_by_tool, measures,
1235 initial_params, profiler, prof_out_template, dry_run, tools,
1236- all_dynamic_params, verbose=verbose, strict=strict)
1237+ dynamic_params, verbose=verbose, strict=strict)
1238 os.chdir(original_dir)
1239 if not dry_run:
1240 datadump.dump_summary(data_file, sys.stdout, suite, tree,
1241
1242=== modified file 'tests/test_archiveutil.py'
1243--- tests/test_archiveutil.py 2009-03-18 17:24:05 +0000
1244+++ tests/test_archiveutil.py 2011-02-16 06:18:13 +0000
1245@@ -37,7 +37,7 @@
1246 class TestEmptyArchive(TestArchive):
1247
1248 def _make_tarfile(self):
1249- self.tarname = "tmp%d.tar.gz" % (random.uniform(9000,9999))
1250+ self.tarname = "empty.tar.gz"
1251 tar = tarfile.open(self.tarname, "w:gz")
1252 tar.close()
1253
1254@@ -49,36 +49,41 @@
1255 class TestArchiveWithOneRoot(TestArchive):
1256
1257 def _make_tarfile(self):
1258- self.root_dir = "root%d" % (random.uniform(10,99))
1259+ self.root_dir = "root"
1260 os.mkdir(self.root_dir)
1261- self.addCleanup(shutil.rmtree, self.root_dir)
1262- self.tarname = "tmp%d.tar.gz" % (random.uniform(9000,9999))
1263+ self.tarname = "abc-in-root.tar.gz"
1264+ for item in ['a', 'b', 'c']:
1265+ filename = os.path.join(self.root_dir, item)
1266+ f = open(filename, "w")
1267+ try:
1268+ f.write("%s rocks\n" % item)
1269+ finally:
1270+ f.close()
1271 tar = tarfile.open(self.tarname, "w:gz")
1272 try:
1273- for item in ['a', 'b', 'c']:
1274- filename = os.path.join(self.root_dir,item)
1275- f = open(filename, "w")
1276- try:
1277- f.write("%s rocks\n" % item)
1278- finally:
1279- f.close()
1280- tar.add(filename)
1281+ tar.add(self.root_dir)
1282 finally:
1283 tar.close()
1284
1285+ def assertPathExists(self, path):
1286+ self.assertTrue(os.path.exists(path), "%r does not exist" % (path,))
1287+
1288+ def assertPathExistsInRoot(self, path):
1289+ self.assertTrue(os.path.exists(os.path.join(self.root_dir,path)),
1290+ "%r does not exist in root_dir %r" % (path, self.root_dir))
1291+
1292 def test_dir_there(self):
1293 work_roots = archiveutil.unpack_archive(self.tarname)
1294 self.assertEqual([], work_roots)
1295 for item in ['a', 'b', 'c']:
1296- self.assertTrue(os.path.exists(os.path.join(self.root_dir,item)))
1297+ self.assertPathExistsInRoot(item)
1298
1299 def test_dir_not_there(self):
1300 shutil.rmtree(self.root_dir)
1301 work_roots = archiveutil.unpack_archive(self.tarname)
1302 self.assertEqual([self.root_dir], work_roots)
1303 for item in ['a', 'b', 'c']:
1304- self.assertTrue(os.path.exists(os.path.join(self.root_dir,item)))
1305-
1306+ self.assertPathExistsInRoot(item)
1307
1308 def test_multiple_destinations(self):
1309 shutil.rmtree(self.root_dir)
1310@@ -87,7 +92,7 @@
1311 self.assertEqual(dests, work_roots)
1312 for dest in dests:
1313 for item in ['a', 'b', 'c']:
1314- self.assertTrue(os.path.exists(os.path.join(dest,item)))
1315+ self.assertPathExists(os.path.join(dest, item))
1316
1317
1318 class TestArchiveWithNoSharedRoot(TestArchive):
1319
1320=== modified file 'userscript.py'
1321--- userscript.py 2009-04-02 13:42:24 +0000
1322+++ userscript.py 2011-02-16 06:18:13 +0000
1323@@ -23,7 +23,7 @@
1324 import unittest
1325
1326 from bzrlib.errors import BzrError
1327-from bzrlib.trace import info
1328+from bzrlib.trace import info, note
1329 from bzrlib.tests import TestUtil
1330
1331 import usermeasure
1332@@ -73,8 +73,37 @@
1333 self.default_script = None
1334 self.scripts_by_tool = {}
1335 self.title = None
1336+ # Indexed by (tool, version) or tool or 'default', then label
1337 self.exit_codes = {}
1338
1339+ def _set_exit_codes(self, tool, codes_by_label, version=None):
1340+ """Set the map of expected exit codes for a tool and version."""
1341+ if codes_by_label is None:
1342+ return
1343+ #note("saving exit-codes %s for tool=%s, version=%s"
1344+ # % (codes_by_label, tool, version))
1345+ if version is None:
1346+ key = tool
1347+ else:
1348+ key = (tool, version)
1349+ if key not in self.exit_codes:
1350+ self.exit_codes[key] = codes_by_label
1351+ else:
1352+ self.exit_codes[key].update(codes_by_label)
1353+
1354+ def _expected_exit_code(self, tool, label, version=None):
1355+ """Get the expected exit code for a 'command'."""
1356+ # When looking up exit codes, if it's not found for a
1357+ # tool+version combination, fall back to the one defined for the tool
1358+ tv_key = (tool, version)
1359+ if tv_key in self.exit_codes:
1360+ return self.exit_codes[tv_key].get(label, 0)
1361+ elif tool in self.exit_codes:
1362+ return self.exit_codes[tool].get(label, 0)
1363+ elif 'default' in self.exit_codes:
1364+ return self.exit_codes['default'].get(label, 0)
1365+ return 0
1366+
1367 def _compile_template(self, template):
1368 if template is None:
1369 return None
1370@@ -92,15 +121,13 @@
1371 def compile_default(self, template, exit_codes=None):
1372 "Compile the default script to be used."
1373 self.default_script = self._compile_template(template)
1374- if exit_codes:
1375- self.exit_codes.update(exit_codes)
1376+ self._set_exit_codes('default', exit_codes)
1377
1378 def compile_for_tools(self, tools_mask, template, exit_codes=None):
1379 "Compile the script to be used for just the tools named."
1380 for tool in tools_mask:
1381 self.compile_for_versions(tool, None, template)
1382- if exit_codes:
1383- self.exit_codes.update(exit_codes)
1384+ self._set_exit_codes(tool, exit_codes)
1385
1386 def compile_for_versions(self, tool, version_pattern, template,
1387 exit_codes=None):
1388@@ -109,8 +136,7 @@
1389 templates_by_version = self.scripts_by_tool.get(tool, {})
1390 templates_by_version[version_pattern] = compiled_template
1391 self.scripts_by_tool[tool] = templates_by_version
1392- if exit_codes:
1393- self.exit_codes.update(exit_codes)
1394+ self._set_exit_codes(tool, exit_codes, version_pattern)
1395
1396 def _get_raw_script_for(self, tool, params, version=None,
1397 missing_params_ok=False):
1398@@ -250,7 +276,7 @@
1399 return actions
1400
1401 def get_commands_by_label(self, tool, params={}):
1402- """Get the mapping fron labels to commands."""
1403+ """Get the mapping from labels to commands."""
1404 script, exceptions = self._get_raw_script_for(tool, params,
1405 missing_params_ok=True)
1406 if script is None:
1407@@ -314,10 +340,13 @@
1408 (sout,serr) = process.communicate()
1409 exit_code = process.returncode
1410 if strict:
1411- if self.exit_codes:
1412- expected_exit_code = self.exit_codes.get(label, 0)
1413- else:
1414- expected_exit_code = 0
1415+ real_tool,version_id = usertool.get_tool_by_fuzzy_name(tool)
1416+ if real_tool is not None:
1417+ real_tool = real_tool.name
1418+ expected_exit_code = self._expected_exit_code(real_tool,
1419+ label, version=version_id)
1420+ #note("expected-exit-code is %s for tool=%s, label=%s, version=%s"
1421+ # % (expected_exit_code, real_tool, label, version_id))
1422 if (isinstance(expected_exit_code, int)
1423 and expected_exit_code != exit_code or
1424 isinstance(expected_exit_code, list)

Subscribers

People subscribed via source and target branches

to all changes: