Ticket #1555: check-miscaptures-v3.darcs.patch

File check-miscaptures-v3.darcs.patch, 40.6 KB (added by davidsarah, at 2011-10-09T19:34:20Z)

Various improvements: also check while loops and list comprehensions; fewer false positives; say "assigned" instance of "declared"; report number of files not analysed.

Line 
16 patches for repository /home/davidsarah/tahoe/1.9alpha2:
2
3Fri Oct  7 08:41:21 BST 2011  david-sarah@jacaranda.org
4  * Add misc/coding_tools/check-miscaptures.py to detect incorrect captures of variables declared in a for loop, and a 'make check-miscaptures' Makefile target to run it. (It is also run by 'make code-checks'.) This is a rewritten version that reports much fewer false positives, by determining captured variables more accurately. fixes #1555
5
6Sun Oct  9 05:40:22 BST 2011  david-sarah@jacaranda.org
7  * check-miscaptures.py: check while loops and list comprehensions as well as for loops. Also fix a pyflakes warning. refs #1555
8
9Sun Oct  9 05:47:10 BST 2011  david-sarah@jacaranda.org
10  * check-miscaptures.py: handle destructuring function arguments correctly. refs #1555
11
12Sun Oct  9 05:48:00 BST 2011  david-sarah@jacaranda.org
13  * check-miscaptures.py: Python doesn't really have declarations; report the topmost assignment. refs #1555
14
15Sun Oct  9 05:50:23 BST 2011  david-sarah@jacaranda.org
16  * check-miscaptures.py: handle corner cases around default arguments correctly. Also make a minor optimization when there are no assigned variables to consider. refs #1555
17
18Sun Oct  9 06:03:01 BST 2011  david-sarah@jacaranda.org
19  * check-miscaptures.py: report the number of files that were not analysed due to syntax errors (and don't count them in the number of suspicious captures). refs #1555
20
21New patches:
22
23[Add misc/coding_tools/check-miscaptures.py to detect incorrect captures of variables declared in a for loop, and a 'make check-miscaptures' Makefile target to run it. (It is also run by 'make code-checks'.) This is a rewritten version that reports much fewer false positives, by determining captured variables more accurately. fixes #1555
24david-sarah@jacaranda.org**20111007074121
25 Ignore-this: 51318e9678d132c374ea557ab955e79e
26] {
27hunk ./Makefile 124
28        false
29 endif
30 
31-code-checks: build version-and-path check-interfaces -find-trailing-spaces -check-umids pyflakes
32+code-checks: build version-and-path check-interfaces check-miscaptures -find-trailing-spaces -check-umids pyflakes
33 
34 version-and-path:
35        $(TAHOE) --version-and-path
36hunk ./Makefile 133
37        $(TAHOE) @misc/coding_tools/check-interfaces.py 2>&1 |tee violations.txt
38        @echo
39 
40+check-miscaptures:
41+       $(PYTHON) misc/coding_tools/check-miscaptures.py $(SOURCES) 2>&1 |tee miscaptures.txt
42+       @echo
43+
44 pyflakes:
45        $(PYTHON) -OOu `which pyflakes` $(SOURCES) |sort |uniq
46        @echo
47addfile ./misc/coding_tools/check-miscaptures.py
48hunk ./misc/coding_tools/check-miscaptures.py 1
49+#! /usr/bin/python
50+
51+import os, sys, compiler, traceback
52+from compiler.ast import Node, For, AssName, Name, Lambda, Function
53+
54+
55+def check_source(source):
56+    return check_thing(compiler.parse, source)
57+
58+def check_file(path):
59+    return check_thing(compiler.parseFile, path)
60+
61+def check_thing(parser, thing):
62+    try:
63+        ast = parser(thing)
64+    except SyntaxError, e:
65+        return [e]
66+    else:
67+        results = []
68+        check_ast(ast, results)
69+        return results
70+
71+def check_ast(ast, results):
72+    """Check a node outside a 'for' loop."""
73+    if isinstance(ast, For):
74+        check_for(ast, results)
75+    else:
76+        for child in ast.getChildNodes():
77+            if isinstance(ast, Node):
78+                check_ast(child, results)
79+
80+def check_for(ast, results):
81+    """Check a particular outer 'for' loop."""
82+
83+    declared = {}  # maps name to lineno of declaration
84+    nested = set()
85+    collect_declared_and_nested(ast, declared, nested)
86+
87+    # For each nested function...
88+    for funcnode in nested:
89+        # Check for captured variables in this function.
90+        captured = set()
91+        collect_captured(funcnode, declared, captured)
92+        for name in captured:
93+            # We want to report the outermost capturing function
94+            # (since that is where the workaround will need to be
95+            # added), and the variable declaration. Just one report
96+            # per capturing function per variable will do.
97+            results.append(make_result(funcnode, name, declared[name]))
98+
99+        # Check each node in the function body in case it
100+        # contains another 'for' loop.
101+        childnodes = funcnode.getChildNodes()[len(funcnode.defaults):]
102+        for child in childnodes:
103+            check_ast(funcnode, results)
104+
105+def collect_declared_and_nested(ast, declared, nested):
106+    """
107+    Collect the names declared in this 'for' loop, not including
108+    names declared in nested functions. Also collect the nodes of
109+    functions that are nested one level deep.
110+    """
111+    if isinstance(ast, AssName):
112+        declared[ast.name] = ast.lineno
113+    else:
114+        childnodes = ast.getChildNodes()
115+        if isinstance(ast, (Lambda, Function)):
116+            nested.add(ast)
117+
118+            # The default argument expressions are "outside" the
119+            # function, even though they are children of the
120+            # Lambda or Function node.
121+            childnodes = childnodes[:len(ast.defaults)]
122+
123+        for child in childnodes:
124+            if isinstance(ast, Node):
125+                collect_declared_and_nested(child, declared, nested)
126+
127+def collect_captured(ast, declared, captured):
128+    """Collect any captured variables that are also in declared."""
129+    if isinstance(ast, Name):
130+        if ast.name in declared:
131+            captured.add(ast.name)
132+    else:
133+        childnodes = ast.getChildNodes()
134+
135+        if isinstance(ast, (Lambda, Function)):
136+            # Formal parameters of the function are excluded from
137+            # captures we care about in subnodes of the function body.
138+            declared = declared.copy()
139+            for argname in ast.argnames:
140+                if argname in declared:
141+                    del declared[argname]
142+
143+            for child in childnodes[len(ast.defaults):]:
144+                collect_captured(child, declared, captured)
145+
146+            # The default argument expressions are "outside" the
147+            # function, even though they are children of the
148+            # Lambda or Function node.
149+            childnodes = childnodes[:len(ast.defaults)]
150+
151+        for child in childnodes:
152+            if isinstance(ast, Node):
153+                collect_captured(child, declared, captured)
154+
155+
156+def make_result(funcnode, var_name, var_lineno):
157+    if hasattr(funcnode, 'name'):
158+        func_name = 'function %r' % (funcnode.name,)
159+    else:
160+        func_name = '<lambda>'
161+    return (funcnode.lineno, func_name, var_name, var_lineno)
162+
163+def report(out, path, results):
164+    for r in results:
165+        if isinstance(r, SyntaxError):
166+            print >>out, path + (" NOT ANALYSED due to syntax error: %s" % r)
167+        else:
168+            print >>out, path + (":%r %s captures %r declared at line %d" % r)
169+
170+def check(sources, out):
171+    class Counts:
172+        n = 0
173+        processed_files = 0
174+        suspect_files = 0
175+    counts = Counts()
176+
177+    def _process(path):
178+        results = check_file(path)
179+        report(out, path, results)
180+        counts.n += len(results)
181+        counts.processed_files += 1
182+        if len(results) > 0:
183+            counts.suspect_files += 1
184+
185+    for source in sources:
186+        print >>out, "Checking %s..." % (source,)
187+        if os.path.isfile(source):
188+            _process(source)
189+        else:
190+            for (dirpath, dirnames, filenames) in os.walk(source):
191+                for fn in filenames:
192+                    (basename, ext) = os.path.splitext(fn)
193+                    if ext == '.py':
194+                        _process(os.path.join(dirpath, fn))
195+
196+    print >>out, ("%d suspiciously captured variables in %d out of %d files"
197+                  % (counts.n, counts.suspect_files, counts.processed_files))
198+    return counts.n
199+
200+
201+sources = ['src']
202+if len(sys.argv) > 1:
203+    sources = sys.argv[1:]
204+if check(sources, sys.stderr) > 0:
205+    sys.exit(1)
206+
207+
208+# TODO: self-tests
209}
210[check-miscaptures.py: check while loops and list comprehensions as well as for loops. Also fix a pyflakes warning. refs #1555
211david-sarah@jacaranda.org**20111009044022
212 Ignore-this: 6526e4e315ca6461b1fbc2da5568e444
213] {
214hunk ./misc/coding_tools/check-miscaptures.py 3
215 #! /usr/bin/python
216 
217-import os, sys, compiler, traceback
218-from compiler.ast import Node, For, AssName, Name, Lambda, Function
219+import os, sys, compiler
220+from compiler.ast import Node, For, While, ListComp, AssName, Name, Lambda, Function
221 
222 
223 def check_source(source):
224hunk ./misc/coding_tools/check-miscaptures.py 24
225         return results
226 
227 def check_ast(ast, results):
228-    """Check a node outside a 'for' loop."""
229-    if isinstance(ast, For):
230-        check_for(ast, results)
231+    """Check a node outside a loop."""
232+    if isinstance(ast, (For, While, ListComp)):
233+        check_loop(ast, results)
234     else:
235         for child in ast.getChildNodes():
236             if isinstance(ast, Node):
237hunk ./misc/coding_tools/check-miscaptures.py 32
238                 check_ast(child, results)
239 
240-def check_for(ast, results):
241-    """Check a particular outer 'for' loop."""
242+def check_loop(ast, results):
243+    """Check a particular outer loop."""
244+
245+    # List comprehensions have a poorly designed AST of the form
246+    # ListComp(exprNode, [ListCompFor(...), ...]), in which the
247+    # result expression is outside the ListCompFor node even though
248+    # it is logically inside the loop(s).
249+    # There may be multiple ListCompFor nodes (in cases such as
250+    #   [lambda: (a,b) for a in ... for b in ...]
251+    # ), and that case they are not nested in the AST. But these
252+    # warts (nonobviously) happen not to matter for our analysis.
253 
254     declared = {}  # maps name to lineno of declaration
255     nested = set()
256}
257[check-miscaptures.py: handle destructuring function arguments correctly. refs #1555
258david-sarah@jacaranda.org**20111009044710
259 Ignore-this: f9de7d95e94446507a206c88d3f98a23
260] {
261hunk ./misc/coding_tools/check-miscaptures.py 99
262         if isinstance(ast, (Lambda, Function)):
263             # Formal parameters of the function are excluded from
264             # captures we care about in subnodes of the function body.
265-            declared = declared.copy()
266-            for argname in ast.argnames:
267-                if argname in declared:
268-                    del declared[argname]
269+            new_declared = declared.copy()
270+            remove_argnames(ast.argnames, new_declared)
271 
272             for child in childnodes[len(ast.defaults):]:
273                 collect_captured(child, declared, captured)
274hunk ./misc/coding_tools/check-miscaptures.py 115
275                 collect_captured(child, declared, captured)
276 
277 
278+def remove_argnames(names, fromset):
279+    for element in names:
280+        if element in fromset:
281+            del fromset[element]
282+        elif isinstance(element, (tuple, list)):
283+            remove_argnames(element, fromset)
284+
285+
286 def make_result(funcnode, var_name, var_lineno):
287     if hasattr(funcnode, 'name'):
288         func_name = 'function %r' % (funcnode.name,)
289}
290[check-miscaptures.py: Python doesn't really have declarations; report the topmost assignment. refs #1555
291david-sarah@jacaranda.org**20111009044800
292 Ignore-this: 4905c9dfe7726f433333e216a6760a4b
293] {
294hunk ./misc/coding_tools/check-miscaptures.py 44
295     # ), and that case they are not nested in the AST. But these
296     # warts (nonobviously) happen not to matter for our analysis.
297 
298-    declared = {}  # maps name to lineno of declaration
299+    declared = {}  # maps name to lineno of topmost assignment
300     nested = set()
301     collect_declared_and_nested(ast, declared, nested)
302 
303hunk ./misc/coding_tools/check-miscaptures.py 56
304         for name in captured:
305             # We want to report the outermost capturing function
306             # (since that is where the workaround will need to be
307-            # added), and the variable declaration. Just one report
308-            # per capturing function per variable will do.
309+            # added), and the topmost assignment to the variable.
310+            # Just one report per capturing function per variable
311+            # will do.
312             results.append(make_result(funcnode, name, declared[name]))
313 
314         # Check each node in the function body in case it
315hunk ./misc/coding_tools/check-miscaptures.py 69
316 
317 def collect_declared_and_nested(ast, declared, nested):
318     """
319-    Collect the names declared in this 'for' loop, not including
320-    names declared in nested functions. Also collect the nodes of
321-    functions that are nested one level deep.
322+    Collect the names declared in this loop, not including names
323+    declared in nested functions. Also collect the nodes of functions
324+    that are nested one level deep.
325     """
326     if isinstance(ast, AssName):
327hunk ./misc/coding_tools/check-miscaptures.py 74
328-        declared[ast.name] = ast.lineno
329+        if ast.name not in declared or declared[ast.name] > ast.lineno:
330+            declared[ast.name] = ast.lineno
331     else:
332         childnodes = ast.getChildNodes()
333         if isinstance(ast, (Lambda, Function)):
334hunk ./misc/coding_tools/check-miscaptures.py 97
335             captured.add(ast.name)
336     else:
337         childnodes = ast.getChildNodes()
338-
339         if isinstance(ast, (Lambda, Function)):
340             # Formal parameters of the function are excluded from
341             # captures we care about in subnodes of the function body.
342replace ./misc/coding_tools/check-miscaptures.py [A-Za-z_0-9] collect_declared_and_nested collect_assigned_and_nested
343replace ./misc/coding_tools/check-miscaptures.py [A-Za-z_0-9] declared assigned
344replace ./misc/coding_tools/check-miscaptures.py [A-Za-z_0-9] new_declared new_assigned
345}
346[check-miscaptures.py: handle corner cases around default arguments correctly. Also make a minor optimization when there are no assigned variables to consider. refs #1555
347david-sarah@jacaranda.org**20111009045023
348 Ignore-this: f49ece515620081da1d745ae6da19d21
349] {
350hunk ./misc/coding_tools/check-miscaptures.py 52
351     for funcnode in nested:
352         # Check for captured variables in this function.
353         captured = set()
354-        collect_captured(funcnode, assigned, captured)
355+        collect_captured(funcnode, assigned, captured, False)
356         for name in captured:
357             # We want to report the outermost capturing function
358             # (since that is where the workaround will need to be
359hunk ./misc/coding_tools/check-miscaptures.py 90
360             if isinstance(ast, Node):
361                 collect_assigned_and_nested(child, assigned, nested)
362 
363-def collect_captured(ast, assigned, captured):
364+def collect_captured(ast, assigned, captured, in_function_yet):
365     """Collect any captured variables that are also in assigned."""
366     if isinstance(ast, Name):
367         if ast.name in assigned:
368hunk ./misc/coding_tools/check-miscaptures.py 103
369             new_assigned = assigned.copy()
370             remove_argnames(ast.argnames, new_assigned)
371 
372-            for child in childnodes[len(ast.defaults):]:
373-                collect_captured(child, assigned, captured)
374+            if len(new_assigned) > 0:
375+                for child in childnodes[len(ast.defaults):]:
376+                    collect_captured(child, new_assigned, captured, True)
377 
378hunk ./misc/coding_tools/check-miscaptures.py 107
379-            # The default argument expressions are "outside" the
380-            # function, even though they are children of the
381-            # Lambda or Function node.
382+            # The default argument expressions are "outside" *this*
383+            # function, even though they are children of the Lambda or
384+            # Function node.
385+            if not in_function_yet:
386+                return
387             childnodes = childnodes[:len(ast.defaults)]
388 
389         for child in childnodes:
390hunk ./misc/coding_tools/check-miscaptures.py 116
391             if isinstance(ast, Node):
392-                collect_captured(child, assigned, captured)
393+                collect_captured(child, assigned, captured, True)
394 
395 
396 def remove_argnames(names, fromset):
397}
398[check-miscaptures.py: report the number of files that were not analysed due to syntax errors (and don't count them in the number of suspicious captures). refs #1555
399david-sarah@jacaranda.org**20111009050301
400 Ignore-this: 62ee03f4b8a96c292e75c097ad87d52e
401] {
402hunk ./misc/coding_tools/check-miscaptures.py 17
403     try:
404         ast = parser(thing)
405     except SyntaxError, e:
406-        return [e]
407+        return e
408     else:
409         results = []
410         check_ast(ast, results)
411hunk ./misc/coding_tools/check-miscaptures.py 136
412 
413 def report(out, path, results):
414     for r in results:
415-        if isinstance(r, SyntaxError):
416-            print >>out, path + (" NOT ANALYSED due to syntax error: %s" % r)
417-        else:
418-            print >>out, path + (":%r %s captures %r assigned at line %d" % r)
419+        print >>out, path + (":%r %s captures %r assigned at line %d" % r)
420 
421 def check(sources, out):
422     class Counts:
423hunk ./misc/coding_tools/check-miscaptures.py 143
424         n = 0
425         processed_files = 0
426         suspect_files = 0
427+        error_files = 0
428     counts = Counts()
429 
430     def _process(path):
431hunk ./misc/coding_tools/check-miscaptures.py 148
432         results = check_file(path)
433-        report(out, path, results)
434-        counts.n += len(results)
435-        counts.processed_files += 1
436-        if len(results) > 0:
437-            counts.suspect_files += 1
438+        if isinstance(results, SyntaxError):
439+            print >>out, path + (" NOT ANALYSED due to syntax error: %s" % results)
440+            counts.error_files += 1
441+        else:
442+            report(out, path, results)
443+            counts.n += len(results)
444+            counts.processed_files += 1
445+            if len(results) > 0:
446+                counts.suspect_files += 1
447 
448     for source in sources:
449         print >>out, "Checking %s..." % (source,)
450hunk ./misc/coding_tools/check-miscaptures.py 169
451                     if ext == '.py':
452                         _process(os.path.join(dirpath, fn))
453 
454-    print >>out, ("%d suspiciously captured variables in %d out of %d files"
455+    print >>out, ("%d suspiciously captured variables in %d out of %d file(s)."
456                   % (counts.n, counts.suspect_files, counts.processed_files))
457hunk ./misc/coding_tools/check-miscaptures.py 171
458+    if counts.error_files > 0:
459+        print >>out, ("%d file(s) not processed due to syntax errors."
460+                      % (counts.error_files,))
461     return counts.n
462 
463 
464}
465
466Context:
467
468[immutable/literal.py: add pauseProducing method to LiteralProducer. refs #1537
469david-sarah@jacaranda.org**20111003195239
470 Ignore-this: 385ee3379a2819381937357f1eac457
471]
472[no_network.py: Clean up whitespace around code changed by previous patch.
473david-sarah@jacaranda.org**20111004010407
474 Ignore-this: 647ec8a9346dca1a41212ab250619b72
475]
476[no_network.py: Fix potential bugs in some tests due to capture of slots in for loops.
477david-sarah@jacaranda.org**20111004010231
478 Ignore-this: 9c496877613a3befd54979e5de6e63d2
479]
480[test/test_runner.py: BinTahoe.test_path has rare nondeterministic failures; this patch probably fixes a problem where the actual cause of failure is masked by a string conversion error.
481david-sarah@jacaranda.org**20110927225336
482 Ignore-this: 6f1ad68004194cc9cea55ace3745e4af
483]
484[docs/configuration.rst: add section about the types of node, and clarify when setting web.port enables web-API service. fixes #1444
485zooko@zooko.com**20110926203801
486 Ignore-this: ab94d470c68e720101a7ff3c207a719e
487]
488[TAG allmydata-tahoe-1.9.0a2
489warner@lothar.com**20110925234811
490 Ignore-this: e9649c58f9c9017a7d55008938dba64f
491]
492[NEWS: tidy up a little bit, reprioritize some items, hide some non-user-visible items
493warner@lothar.com**20110925233529
494 Ignore-this: 61f334cc3fa2539742c3e5d2801aee81
495]
496[docs: fix some broken .rst links. refs #1542
497david-sarah@jacaranda.org**20110925051001
498 Ignore-this: 5714ee650abfcaab0914537e1f206972
499]
500[mutable/publish.py: fix an unused import. refs #1542
501david-sarah@jacaranda.org**20110925052206
502 Ignore-this: 2d69ac9e605e789c0aedfecb8877b7d7
503]
504[NEWS: fix .rst formatting.
505david-sarah@jacaranda.org**20110925050119
506 Ignore-this: aa1d20acd23bdb8f8f6d0fa048ea0277
507]
508[NEWS: updates for 1.9alpha2.
509david-sarah@jacaranda.org**20110925045343
510 Ignore-this: d2c44e4e05d2ed662b7adfd2e43928bc
511]
512[mutable/layout.py: make unpack_sdmf_checkstring and unpack_mdmf_checkstring more similar, and change an assert to give a more useful message if it fails. refs #1540
513david-sarah@jacaranda.org**20110925023651
514 Ignore-this: 977aaa8cb16e06a6dcc3e27cb6e23956
515]
516[mutable/publish: handle unknown mutable share formats when handling errors
517kevan@isnotajoke.com**20110925004305
518 Ignore-this: 4d5fa44ef7d777c432eb10c9584ad51f
519]
520[mutable/layout: break unpack_checkstring into unpack_mdmf_checkstring and unpack_sdmf_checkstring, add distinguisher function for checkstrings
521kevan@isnotajoke.com**20110925004134
522 Ignore-this: 57f49ed5a72e418a69c7286a225cc8fb
523]
524[test/test_mutable: reenable mdmf publish surprise test
525kevan@isnotajoke.com**20110924235415
526 Ignore-this: f752e47a703684491305cc83d16248fb
527]
528[mutable/publish: use unpack_mdmf_checkstring and unpack_sdmf_checkstring instead of unpack_checkstring. fixes #1540
529kevan@isnotajoke.com**20110924235137
530 Ignore-this: 52ca3d9627b8b0ba758367b2bd6c7085
531]
532[misc/coding_tools/check_interfaces.py: report all violations rather than only one for a given class, by including a forked version of verifyClass. refs #1474
533david-sarah@jacaranda.org**20110916223450
534 Ignore-this: 927efeecf4d12588316826a4b3479aa9
535]
536[misc/coding_tools/check_interfaces.py: use os.walk instead of FilePath, since this script shouldn't really depend on Twisted. refs #1474
537david-sarah@jacaranda.org**20110916212633
538 Ignore-this: 46eeb4236b34375227dac71ef53f5428
539]
540[misc/coding_tools/check-interfaces.py: reduce false-positives by adding Dummy* to the set of excluded classnames, and bench-* to the set of excluded basenames. refs #1474
541david-sarah@jacaranda.org**20110916212624
542 Ignore-this: 4e78f6e6fe6c0e9be9df826a0e206804
543]
544[Add a script 'misc/coding_tools/check-interfaces.py' that checks whether zope interfaces are enforced. Also add 'check-interfaces', 'version-and-path', and 'code-checks' targets to the Makefile. fixes #1474
545david-sarah@jacaranda.org**20110915161532
546 Ignore-this: 32d9bdc5bc4a86d21e927724560ad4b4
547]
548[mutable/publish.py: copy the self.writers dict before iterating over it, since we remove elements from it during the iteration. refs #393
549david-sarah@jacaranda.org**20110924211208
550 Ignore-this: 76d4066b55d50ace2a34b87443b39094
551]
552[mutable/publish.py: simplify by refactoring self.outstanding to self.num_outstanding. refs #393
553david-sarah@jacaranda.org**20110924205004
554 Ignore-this: 902768cfc529ae13ae0b7f67768a3643
555]
556[test_mutable.py: update SkipTest message for test_publish_surprise_mdmf to reference the right ticket number. refs #1540.
557david-sarah@jacaranda.org**20110923211622
558 Ignore-this: 44f16a6817a6b75930bbba18b0a516be
559]
560[control.py: unbreak speed-test: overwrite() wants a MutableData, not str
561Brian Warner <warner@lothar.com>**20110923073748
562 Ignore-this: 7dad7aff3d66165868a64ae22d225fa3
563 
564 Really, all the upload/modify APIs should take a string or a filehandle, and
565 internally wrap it as needed. Callers should not need to be aware of
566 Uploadable() or MutableData() classes.
567]
568[test_mutable.py: skip test_publish_surprise_mdmf, which is causing an error. refs #1534, #393
569david-sarah@jacaranda.org**20110920183319
570 Ignore-this: 6fb020e09e8de437cbcc2c9f57835b31
571]
572[test/test_mutable: write publish surprise test for MDMF, rename existing test_publish_surprise to clarify that it is for SDMF
573kevan@isnotajoke.com**20110918003657
574 Ignore-this: 722c507e8f5b537ff920e0555951059a
575]
576[test/test_mutable: refactor publish surprise test into common test fixture, rewrite test_publish_surprise to use test fixture
577kevan@isnotajoke.com**20110918003533
578 Ignore-this: 6f135888d400a99a09b5f9a4be443b6e
579]
580[mutable/publish: add errback immediately after write, don't consume errors from other parts of the publisher
581kevan@isnotajoke.com**20110917234708
582 Ignore-this: 12bf6b0918a5dc5ffc30ece669fad51d
583]
584[.darcs-boringfile: minor cleanups.
585david-sarah@jacaranda.org**20110920154918
586 Ignore-this: cab78e30d293da7e2832207dbee2ffeb
587]
588[uri.py: fix two interface violations in verifier URI classes. refs #1474
589david-sarah@jacaranda.org**20110920030156
590 Ignore-this: 454ddd1419556cb1d7576d914cb19598
591]
592[Make platform-detection code tolerate linux-3.0, patch by zooko.
593Brian Warner <warner@lothar.com>**20110915202620
594 Ignore-this: af63cf9177ae531984dea7a1cad03762
595 
596 Otherwise address-autodetection can't find ifconfig. refs #1536
597]
598[test_web.py: fix a bug in _count_leases that was causing us to check only the lease count of one share file, not of all share files as intended.
599david-sarah@jacaranda.org**20110915185126
600 Ignore-this: d96632bc48d770b9b577cda1bbd8ff94
601]
602[docs: insert a newline at the beginning of known_issues.rst to see if this makes it render more nicely in trac
603zooko@zooko.com**20110914064728
604 Ignore-this: aca15190fa22083c5d4114d3965f5d65
605]
606[docs: remove the coding: utf-8 declaration at the to of known_issues.rst, since the trac rendering doesn't hide it
607zooko@zooko.com**20110914055713
608 Ignore-this: 941ed32f83ead377171aa7a6bd198fcf
609]
610[docs: more cleanup of known_issues.rst -- now it passes "rst2html --verbose" without comment
611zooko@zooko.com**20110914055419
612 Ignore-this: 5505b3d76934bd97d0312cc59ed53879
613]
614[docs: more formatting improvements to known_issues.rst
615zooko@zooko.com**20110914051639
616 Ignore-this: 9ae9230ec9a38a312cbacaf370826691
617]
618[docs: reformatting of known_issues.rst
619zooko@zooko.com**20110914050240
620 Ignore-this: b8be0375079fb478be9d07500f9aaa87
621]
622[docs: fix formatting error in docs/known_issues.rst
623zooko@zooko.com**20110914045909
624 Ignore-this: f73fe74ad2b9e655aa0c6075acced15a
625]
626[merge Tahoe-LAFS v1.8.3 release announcement with trunk
627zooko@zooko.com**20110913210544
628 Ignore-this: 163f2c3ddacca387d7308e4b9332516e
629]
630[docs: release notes for Tahoe-LAFS v1.8.3
631zooko@zooko.com**20110913165826
632 Ignore-this: 84223604985b14733a956d2fbaeb4e9f
633]
634[tests: bump up the timeout in this test that fails on FreeStorm's CentOS in order to see if it is just very slow
635zooko@zooko.com**20110913024255
636 Ignore-this: 6a86d691e878cec583722faad06fb8e4
637]
638[interfaces: document that the 'fills-holes-with-zero-bytes' key should be used to detect whether a storage server has that behavior. refs #1528
639david-sarah@jacaranda.org**20110913002843
640 Ignore-this: 1a00a6029d40f6792af48c5578c1fd69
641]
642[CREDITS: more CREDITS for Kevan and David-Sarah
643zooko@zooko.com**20110912223357
644 Ignore-this: 4ea8f0d6f2918171d2f5359c25ad1ada
645]
646[merge NEWS about the mutable file bounds fixes with NEWS about work-in-progress
647zooko@zooko.com**20110913205521
648 Ignore-this: 4289a4225f848d6ae6860dd39bc92fa8
649]
650[doc: add NEWS item about fixes to potential palimpsest issues in mutable files
651zooko@zooko.com**20110912223329
652 Ignore-this: 9d63c95ddf95c7d5453c94a1ba4d406a
653 ref. #1528
654]
655[merge the NEWS about the security fix (#1528) with the work-in-progress NEWS
656zooko@zooko.com**20110913205153
657 Ignore-this: 88e88a2ad140238c62010cf7c66953fc
658]
659[doc: add NEWS entry about the issue which allows unauthorized deletion of shares
660zooko@zooko.com**20110912223246
661 Ignore-this: 77e06d09103d2ef6bb51ea3e5d6e80b0
662 ref. #1528
663]
664[doc: add entry in known_issues.rst about the issue which allows unauthorized deletion of shares
665zooko@zooko.com**20110912223135
666 Ignore-this: b26c6ea96b6c8740b93da1f602b5a4cd
667 ref. #1528
668]
669[storage: more paranoid handling of bounds and palimpsests in mutable share files
670zooko@zooko.com**20110912222655
671 Ignore-this: a20782fa423779ee851ea086901e1507
672 * storage server ignores requests to extend shares by sending a new_length
673 * storage server fills exposed holes (created by sending a write vector whose offset begins after the end of the current data) with 0 to avoid "palimpsest" exposure of previous contents
674 * storage server zeroes out lease info at the old location when moving it to a new location
675 ref. #1528
676]
677[storage: test that the storage server ignores requests to extend shares by sending a new_length, and that the storage server fills exposed holes with 0 to avoid "palimpsest" exposure of previous contents
678zooko@zooko.com**20110912222554
679 Ignore-this: 61ebd7b11250963efdf5b1734a35271
680 ref. #1528
681]
682[immutable: prevent clients from reading past the end of share data, which would allow them to learn the cancellation secret
683zooko@zooko.com**20110912222458
684 Ignore-this: da1ebd31433ea052087b75b2e3480c25
685 Declare explicitly that we prevent this problem in the server's version dict.
686 fixes #1528 (there are two patches that are each a sufficient fix to #1528 and this is one of them)
687]
688[storage: remove the storage server's "remote_cancel_lease" function
689zooko@zooko.com**20110912222331
690 Ignore-this: 1c32dee50e0981408576daffad648c50
691 We're removing this function because it is currently unused, because it is dangerous, and because the bug described in #1528 leaks the cancellation secret, which allows anyone who knows a file's storage index to abuse this function to delete shares of that file.
692 fixes #1528 (there are two patches that are each a sufficient fix to #1528 and this is one of them)
693]
694[storage: test that the storage server does *not* have a "remote_cancel_lease" function
695zooko@zooko.com**20110912222324
696 Ignore-this: 21c652009704652d35f34651f98dd403
697 We're removing this function because it is currently unused, because it is dangerous, and because the bug described in #1528 leaks the cancellation secret, which allows anyone who knows a file's storage index to abuse this function to delete shares of that file.
698 ref. #1528
699]
700[immutable: test whether the server allows clients to read past the end of share data, which would allow them to learn the cancellation secret
701zooko@zooko.com**20110912221201
702 Ignore-this: 376e47b346c713d37096531491176349
703 Also test whether the server explicitly declares that it prevents this problem.
704 ref #1528
705]
706[Retrieve._activate_enough_peers: rewrite Verify logic
707Brian Warner <warner@lothar.com>**20110909181150
708 Ignore-this: 9367c11e1eacbf025f75ce034030d717
709]
710[Retrieve: implement/test stopProducing
711Brian Warner <warner@lothar.com>**20110909181150
712 Ignore-this: 47b2c3df7dc69835e0a066ca12e3c178
713]
714[move DownloadStopped from download.common to interfaces
715Brian Warner <warner@lothar.com>**20110909181150
716 Ignore-this: 8572acd3bb16e50341dbed8eb1d90a50
717]
718[retrieve.py: remove vestigal self._validated_readers
719Brian Warner <warner@lothar.com>**20110909181150
720 Ignore-this: faab2ec14e314a53a2ffb714de626e2d
721]
722[Retrieve: rewrite flow-control: use a top-level loop() to catch all errors
723Brian Warner <warner@lothar.com>**20110909181150
724 Ignore-this: e162d2cd53b3d3144fc6bc757e2c7714
725 
726 This ought to close the potential for dropped errors and hanging downloads.
727 Verify needs to be examined, I may have broken it, although all tests pass.
728]
729[Retrieve: merge _validate_active_prefixes into _add_active_peers
730Brian Warner <warner@lothar.com>**20110909181150
731 Ignore-this: d3ead31e17e69394ae7058eeb5beaf4c
732]
733[Retrieve: remove the initial prefix-is-still-good check
734Brian Warner <warner@lothar.com>**20110909181150
735 Ignore-this: da66ee51c894eaa4e862e2dffb458acc
736 
737 This check needs to be done with each fetch from the storage server, to
738 detect when someone has changed the share (i.e. our servermap goes stale).
739 Doing it just once at the beginning of retrieve isn't enough: a write might
740 occur after the first segment but before the second, etc.
741 
742 _try_to_validate_prefix() was not removed: it will be used by the future
743 check-with-each-fetch code.
744 
745 test_mutable.Roundtrip.test_corrupt_all_seqnum_late was disabled, since it
746 fails until this check is brought back. (the corruption it applies only
747 touches the prefix, not the block data, so the check-less retrieve actually
748 tolerates it). Don't forget to re-enable it once the check is brought back.
749]
750[MDMFSlotReadProxy: remove the queue
751Brian Warner <warner@lothar.com>**20110909181150
752 Ignore-this: 96673cb8dda7a87a423de2f4897d66d2
753 
754 This is a neat trick to reduce Foolscap overhead, but the need for an
755 explicit flush() complicates the Retrieve path and makes it prone to
756 lost-progress bugs.
757 
758 Also change test_mutable.FakeStorageServer to tolerate multiple reads of the
759 same share in a row, a limitation exposed by turning off the queue.
760]
761[rearrange Retrieve: first step, shouldn't change order of execution
762Brian Warner <warner@lothar.com>**20110909181149
763 Ignore-this: e3006368bfd2802b82ea45c52409e8d6
764]
765[CLI: test_cli.py -- remove an unnecessary call in test_mkdir_mutable_type. refs #1527
766david-sarah@jacaranda.org**20110906183730
767 Ignore-this: 122e2ffbee84861c32eda766a57759cf
768]
769[CLI: improve test for 'tahoe mkdir --mutable-type='. refs #1527
770david-sarah@jacaranda.org**20110906183020
771 Ignore-this: f1d4598e6c536f0a2b15050b3bc0ef9d
772]
773[CLI: make the --mutable-type option value for 'tahoe put' and 'tahoe mkdir' case-insensitive, and change --help for these commands accordingly. fixes #1527
774david-sarah@jacaranda.org**20110905020922
775 Ignore-this: 75a6df0a2df9c467d8c010579e9a024e
776]
777[cli: make --mutable-type imply --mutable in 'tahoe put'
778Kevan Carstensen <kevan@isnotajoke.com>**20110903190920
779 Ignore-this: 23336d3c43b2a9554e40c2a11c675e93
780]
781[SFTP: add a comment about a subtle interaction between OverwriteableFileConsumer and GeneralSFTPFile, and test the case it is commenting on.
782david-sarah@jacaranda.org**20110903222304
783 Ignore-this: 980c61d4dd0119337f1463a69aeebaf0
784]
785[improve the storage/mutable.py asserts even more
786warner@lothar.com**20110901160543
787 Ignore-this: 5b2b13c49bc4034f96e6e3aaaa9a9946
788]
789[storage/mutable.py: special characters in struct.foo arguments indicate standard as opposed to native sizes, we should be using these characters in these asserts
790wilcoxjg@gmail.com**20110901084144
791 Ignore-this: 28ace2b2678642e4d7269ddab8c67f30
792]
793[docs/write_coordination.rst: fix formatting and add more specific warning about access via sshfs.
794david-sarah@jacaranda.org**20110831232148
795 Ignore-this: cd9c851d3eb4e0a1e088f337c291586c
796]
797[test_mutable.Version: consolidate some tests, reduce runtime from 19s to 15s
798warner@lothar.com**20110831050451
799 Ignore-this: 64815284d9e536f8f3798b5f44cf580c
800]
801[mutable/retrieve: handle the case where self._read_length is 0.
802Kevan Carstensen <kevan@isnotajoke.com>**20110830210141
803 Ignore-this: fceafbe485851ca53f2774e5a4fd8d30
804 
805 Note that the downloader will still fetch a segment for a zero-length
806 read, which is wasteful. Fixing that isn't specifically required to fix
807 #1512, but it should probably be fixed before 1.9.
808]
809[NEWS: added summary of all changes since 1.8.2. Needs editing.
810Brian Warner <warner@lothar.com>**20110830163205
811 Ignore-this: 273899b37a899fc6919b74572454b8b2
812]
813[test_mutable.Update: only upload the files needed for each test. refs #1500
814Brian Warner <warner@lothar.com>**20110829072717
815 Ignore-this: 4d2ab4c7523af9054af7ecca9c3d9dc7
816 
817 This first step shaves 15% off the runtime: from 139s to 119s on my laptop.
818 It also fixes a couple of places where a Deferred was being dropped, which
819 would cause two tests to run in parallel and also confuse error reporting.
820]
821[Let Uploader retain History instead of passing it into upload(). Fixes #1079.
822Brian Warner <warner@lothar.com>**20110829063246
823 Ignore-this: 3902c58ec12bd4b2d876806248e19f17
824 
825 This consistently records all immutable uploads in the Recent Uploads And
826 Downloads page, regardless of code path. Previously, certain webapi upload
827 operations (like PUT /uri/$DIRCAP/newchildname) failed to pass the History
828 object and were left out.
829]
830[Fix mutable publish/retrieve timing status displays. Fixes #1505.
831Brian Warner <warner@lothar.com>**20110828232221
832 Ignore-this: 4080ce065cf481b2180fd711c9772dd6
833 
834 publish:
835 * encrypt and encode times are cumulative, not just current-segment
836 
837 retrieve:
838 * same for decrypt and decode times
839 * update "current status" to include segment number
840 * set status to Finished/Failed when download is complete
841 * set progress to 1.0 when complete
842 
843 More improvements to consider:
844 * progress is currently 0% or 100%: should calculate how many segments are
845   involved (remembering retrieve can be less than the whole file) and set it
846   to a fraction
847 * "fetch" time is fuzzy: what we want is to know how much of the delay is not
848   our own fault, but since we do decode/decrypt work while waiting for more
849   shares, it's not straightforward
850]
851[Teach 'tahoe debug catalog-shares about MDMF. Closes #1507.
852Brian Warner <warner@lothar.com>**20110828080931
853 Ignore-this: 56ef2951db1a648353d7daac6a04c7d1
854]
855[debug.py: remove some dead comments
856Brian Warner <warner@lothar.com>**20110828074556
857 Ignore-this: 40e74040dd4d14fd2f4e4baaae506b31
858]
859[hush pyflakes
860Brian Warner <warner@lothar.com>**20110828074254
861 Ignore-this: bef9d537a969fa82fe4decc4ba2acb09
862]
863[MutableFileNode.set_downloader_hints: never depend upon order of dict.values()
864Brian Warner <warner@lothar.com>**20110828074103
865 Ignore-this: caaf1aa518dbdde4d797b7f335230faa
866 
867 The old code was calculating the "extension parameters" (a list) from the
868 downloader hints (a dictionary) with hints.values(), which is not stable, and
869 would result in corrupted filecaps (with the 'k' and 'segsize' hints
870 occasionally swapped). The new code always uses [k,segsize].
871]
872[layout.py: fix MDMF share layout documentation
873Brian Warner <warner@lothar.com>**20110828073921
874 Ignore-this: 3f13366fed75b5e31b51ae895450a225
875]
876[teach 'tahoe debug dump-share' about MDMF and offsets. refs #1507
877Brian Warner <warner@lothar.com>**20110828073834
878 Ignore-this: 3a9d2ef9c47a72bf1506ba41199a1dea
879]
880[test_mutable.Version.test_debug: use splitlines() to fix buildslaves
881Brian Warner <warner@lothar.com>**20110828064728
882 Ignore-this: c7f6245426fc80b9d1ae901d5218246a
883 
884 Any slave running in a directory with spaces in the name was miscounting
885 shares, causing the test to fail.
886]
887[test_mutable.Version: exercise 'tahoe debug find-shares' on MDMF. refs #1507
888Brian Warner <warner@lothar.com>**20110828005542
889 Ignore-this: cb20bea1c28bfa50a72317d70e109672
890 
891 Also changes NoNetworkGrid to put shares in storage/shares/ .
892]
893[test_mutable.py: oops, missed a .todo
894Brian Warner <warner@lothar.com>**20110828002118
895 Ignore-this: fda09ae86481352b7a627c278d2a3940
896]
897[test_mutable: merge davidsarah's patch with my Version refactorings
898warner@lothar.com**20110827235707
899 Ignore-this: b5aaf481c90d99e33827273b5d118fd0
900]
901[Make the immutable/read-only constraint checking for MDMF URIs identical to that for SSK URIs. refs #393
902david-sarah@jacaranda.org**20110823012720
903 Ignore-this: e1f59d7ff2007c81dbef2aeb14abd721
904]
905[Additional tests for MDMF URIs and for zero-length files. refs #393
906david-sarah@jacaranda.org**20110823011532
907 Ignore-this: a7cc0c09d1d2d72413f9cd227c47a9d5
908]
909[Additional tests for zero-length partial reads and updates to mutable versions. refs #393
910david-sarah@jacaranda.org**20110822014111
911 Ignore-this: 5fc6f4d06e11910124e4a277ec8a43ea
912]
913[test_mutable.Version: factor out some expensive uploads, save 25% runtime
914Brian Warner <warner@lothar.com>**20110827232737
915 Ignore-this: ea37383eb85ea0894b254fe4dfb45544
916]
917[SDMF: update filenode with correct k/N after Retrieve. Fixes #1510.
918Brian Warner <warner@lothar.com>**20110827225031
919 Ignore-this: b50ae6e1045818c400079f118b4ef48
920 
921 Without this, we get a regression when modifying a mutable file that was
922 created with more shares (larger N) than our current tahoe.cfg . The
923 modification attempt creates new versions of the (0,1,..,newN-1) shares, but
924 leaves the old versions of the (newN,..,oldN-1) shares alone (and throws a
925 assertion error in SDMFSlotWriteProxy.finish_publishing in the process).
926 
927 The mixed versions that result (some shares with e.g. N=10, some with N=20,
928 such that both versions are recoverable) cause problems for the Publish code,
929 even before MDMF landed. Might be related to refs #1390 and refs #1042.
930]
931[layout.py: annotate assertion to figure out 'tahoe backup' failure
932Brian Warner <warner@lothar.com>**20110827195253
933 Ignore-this: 9b92b954e3ed0d0f80154fff1ff674e5
934]
935[Add 'tahoe debug dump-cap' support for MDMF, DIR2-CHK, DIR2-MDMF. refs #1507.
936Brian Warner <warner@lothar.com>**20110827195048
937 Ignore-this: 61c6af5e33fc88e0251e697a50addb2c
938 
939 This also adds tests for all those cases, and fixes an omission in uri.py
940 that broke parsing of DIR2-MDMF-Verifier and DIR2-CHK-Verifier.
941]
942[MDMF: more writable/writeable consistentifications
943warner@lothar.com**20110827190602
944 Ignore-this: 22492a9e20c1819ddb12091062888b55
945]
946[MDMF: s/Writable/Writeable/g, for consistency with existing SDMF code
947warner@lothar.com**20110827183357
948 Ignore-this: 9dd312acedbdb2fc2f7bef0d0fb17c0b
949]
950[setup.cfg: remove no-longer-supported test_mac_diskimage alias. refs #1479
951david-sarah@jacaranda.org**20110826230345
952 Ignore-this: 40e908b8937322a290fb8012bfcad02a
953]
954[test_mutable.Update: increase timeout from 120s to 400s, slaves are failing
955Brian Warner <warner@lothar.com>**20110825230140
956 Ignore-this: 101b1924a30cdbda9b2e419e95ca15ec
957]
958[tests: fix check_memory test
959zooko@zooko.com**20110825201116
960 Ignore-this: 4d66299fa8cb61d2ca04b3f45344d835
961 fixes #1503
962]
963[TAG allmydata-tahoe-1.9.0a1
964warner@lothar.com**20110825161122
965 Ignore-this: 3cbf49f00dbda58189f893c427f65605
966]
967Patch bundle hash:
968b48f36aa306bef5a2df8b972db237a44a6f56aab