Ticket #534: tahoe-534-bundle.dpatch

File tahoe-534-bundle.dpatch, 68.8 KB (added by francois, at 2009-04-29T16:36:10Z)
Line 
1Mon Apr 27 11:58:49 CEST 2009  francois@ctrlaltdel.ch
2  * cli: plumbing for unicode support
3
4Mon Apr 27 10:59:31 CEST 2009  francois@ctrlaltdel.ch
5  * cli: tahoe backup unicode support
6
7Mon Apr 27 11:01:44 CEST 2009  francois@ctrlaltdel.ch
8  * cli: tahoe manifest unicode support
9
10Mon Apr 27 11:18:50 CEST 2009  francois@ctrlaltdel.ch
11  * cli: tahoe ls unicode support
12
13Mon Apr 27 11:18:20 CEST 2009  francois@ctrlaltdel.ch
14  * cli: tahoe get unicode support
15
16Mon Apr 27 11:00:59 CEST 2009  francois@ctrlaltdel.ch
17  * cli: tahoe webopen unicode support
18
19Mon Apr 27 10:58:47 CEST 2009  francois@ctrlaltdel.ch
20  * cli: tahoe rm unicode support
21
22Mon Apr 27 10:59:13 CEST 2009  francois@ctrlaltdel.ch
23  * cli: tahoe ln unicode support
24
25Mon Apr 27 11:02:13 CEST 2009  francois@ctrlaltdel.ch
26  * cli: tahoe status unicode support
27
28Mon Apr 27 11:02:26 CEST 2009  francois@ctrlaltdel.ch
29  * cli: tahoe check unicode support
30
31Mon Apr 27 11:02:43 CEST 2009  francois@ctrlaltdel.ch
32  * cli: tahoe deep-check unicode support
33
34Mon Apr 27 11:10:47 CEST 2009  francois@ctrlaltdel.ch
35  * cli: tahoe mkdir unicode support
36
37Mon Apr 27 11:12:52 CEST 2009  francois@ctrlaltdel.ch
38  * docs: explain the current unicode support in CLI
39
40Mon Apr 27 15:52:03 CEST 2009  francois@ctrlaltdel.ch
41  * cli: tahoe cp unicode support
42
43Wed Apr 29 18:20:03 CEST 2009  francois@ctrlaltdel.ch
44  * cli: tahoe put unicode support + encode path elements using unicode_to_url
45 
46  Both changes (tahoe put and url encoding) had to be included in the same patch
47  to prevent failing tests.
48
49Mon Apr 27 11:58:07 CEST 2009  francois@ctrlaltdel.ch
50  * cli: aliases unicode support
51
52Mon Apr 27 15:52:39 CEST 2009  francois@ctrlaltdel.ch
53  * cli: previous cli related patches should fix #534
54
55New patches:
56
57[cli: plumbing for unicode support
58francois@ctrlaltdel.ch**20090427095849
59 Ignore-this: 9cc8871d8fe54cde0dba52912754e4f4
60] {
61hunk ./src/allmydata/scripts/cli.py 4
62 import os.path, re, sys, fnmatch
63 from twisted.python import usage
64 from allmydata.scripts.common import BaseOptions, get_aliases
65+from allmydata.util.stringutils import argv_to_unicode
66 
67 NODEURL_RE=re.compile("http://([^:]*)(:([1-9][0-9]*))?")
68 
69hunk ./src/allmydata/scripts/common.py 4
70 
71 import os, sys, urllib
72 from twisted.python import usage
73-
74+from allmydata.util.stringutils import unicode_to_url
75 
76 class BaseOptions:
77     # unit tests can override these to point at StringIO instances
78hunk ./src/allmydata/test/test_cli.py 9
79 import urllib
80 import re
81 import simplejson
82+import sys
83 
84 from allmydata.util import fileutil, hashutil, base32
85 from allmydata import uri
86addfile ./src/allmydata/util/stringutils.py
87hunk ./src/allmydata/util/stringutils.py 1
88+"""
89+Functions used to convert inputs from whatever encoding used in the system to
90+unicode and back.
91+
92+TODO:
93+  * Accept two cli arguments --argv-encoding and --filesystem-encoding
94+"""
95+
96+import sys
97+from allmydata.util.assertutil import precondition
98+from twisted.python import usage
99+
100+def argv_to_unicode(s):
101+    """
102+    Decode given argv element to unicode.
103+    """
104+    # sys.argv encoding detection in Python is not trivial so utf-8 is
105+    # currently used by default and an informative error message is given if
106+    # the argument cannot be correctly decoded.
107+
108+    precondition(isinstance(s, str), s)
109+    try:
110+        return unicode(s, 'utf-8')
111+    except UnicodeEncodeError:
112+        raise usageError("Argument '%s' cannot be decoded as UTF-8." % s)
113+
114+def fs_to_unicode(s):
115+    """
116+    Decode a filename (or a directory name) to unicode using the same encoding
117+    as the filesystem.
118+    """
119+    # Filename encoding detection is a little bit better thanks to
120+    # getfilesystemencoding() in the sys module. However, filenames can be
121+    # encoded using another encoding than the one used on the filesystem.
122+   
123+    precondition(isinstance(s, str), s)
124+    encoding = sys.getfilesystemencoding()
125+    try:
126+        return unicode(s, encoding)
127+    except UnicodeDecodeError:
128+        raise usage.UsageError("Filename '%s' cannot be decoded using the current encoding of your filesystem (%s). Please rename this file." % (s, encoding))
129+
130+def unicode_to_fs(s):
131+    """
132+    Encode an unicode object used in file or directoy name.
133+    """
134+
135+    precondition(isinstance(s, unicode), s)
136+    encoding = sys.getfilesystemencoding()
137+    try:
138+        return s.encode(encoding)
139+    except UnicodeEncodeError:
140+        raise usage.UsageError("Filename '%s' cannot be encoded using the current encoding of your filesystem (%s). Please configure your locale correctly or rename this file." % (s, encoding))
141+
142+def unicode_to_url(s):
143+    """
144+    Encode an unicode object used in an URL.
145+    """
146+    # According to RFC 2718, non-ascii characters in url's must be UTF-8 encoded.
147+
148+    precondition(isinstance(s, unicode), s)
149+    return s.encode('utf-8')
150+
151+def unicode_to_stdout(s):
152+    """
153+    Encode an unicode object for representation on stdout.
154+    """
155+
156+    precondition(isinstance(s, unicode), s)
157+    return s.encode(sys.stdout.encoding, 'replace')
158}
159[cli: tahoe backup unicode support
160francois@ctrlaltdel.ch**20090427085931
161 Ignore-this: 1270f10115dfbc6a1661678cce279072
162] {
163hunk ./src/allmydata/scripts/cli.py 225
164         self['exclude'] = set()
165 
166     def parseArgs(self, localdir, topath):
167-        self.from_dir = localdir
168-        self.to_dir = topath
169+        self.from_dir = argv_to_unicode(localdir)
170+        self.to_dir = argv_to_unicode(topath)
171 
172     def getSynopsis(Self):
173         return "%s backup FROM ALIAS:TO" % os.path.basename(sys.argv[0])
174hunk ./src/allmydata/scripts/tahoe_backup.py 7
175 import urllib
176 import simplejson
177 import datetime
178+import sys
179 from allmydata.scripts.common import get_alias, escape_path, DEFAULT_ALIAS
180 from allmydata.scripts.common_http import do_http
181 from allmydata import uri
182hunk ./src/allmydata/scripts/tahoe_backup.py 13
183 from allmydata.util import time_format
184 from allmydata.scripts import backupdb
185+from allmydata.util.stringutils import fs_to_unicode, unicode_to_fs, unicode_to_stdout
186+from allmydata.util.assertutil import precondition
187+from twisted.python import usage
188 
189 class HTTPError(Exception):
190     pass
191hunk ./src/allmydata/scripts/tahoe_backup.py 252
192 
193     def verboseprint(self, msg):
194         if self.verbosity >= 2:
195-            print >>self.options.stdout, msg
196+            print >>self.options.stdout, unicode_to_stdout(msg)
197 
198     def process(self, localpath, olddircap):
199hunk ./src/allmydata/scripts/tahoe_backup.py 255
200+        precondition(isinstance(localpath, unicode), localpath)
201         # returns newdircap
202 
203         self.verboseprint("processing %s, olddircap %s" % (localpath, olddircap))
204hunk ./src/allmydata/scripts/tahoe_backup.py 264
205             olddircontents = self.readdir(olddircap)
206 
207         newdircontents = {} # childname -> (type, rocap, metadata)
208-        for child in self.options.filter_listdir(os.listdir(localpath)):
209+        for child in self.options.filter_listdir(os.listdir(unicode_to_fs(localpath))):
210+            child = fs_to_unicode(child)
211             childpath = os.path.join(localpath, child)
212             if os.path.isdir(childpath):
213                 metadata = get_local_metadata(childpath)
214hunk ./src/allmydata/scripts/tahoe_backup.py 351
215         return contents
216 
217     def upload(self, childpath):
218+        precondition(isinstance(childpath, unicode), childpath)
219+
220         #self.verboseprint("uploading %s.." % childpath)
221         metadata = get_local_metadata(childpath)
222 
223hunk ./src/allmydata/scripts/tahoe_backup.py 361
224 
225         if must_upload:
226             self.verboseprint("uploading %s.." % childpath)
227-            infileobj = open(os.path.expanduser(childpath), "rb")
228+            infileobj = open(unicode_to_fs(os.path.expanduser(childpath)), "rb")
229             url = self.options['node-url'] + "uri"
230             resp = do_http("PUT", url, infileobj)
231             if resp.status not in (200, 201):
232hunk ./src/allmydata/test/test_cli.py 875
233         self.writeto("parent/subdir/bar.txt", "bar\n" * 1000)
234         self.writeto("parent/blah.txt", "blah")
235 
236+        if sys.getfilesystemencoding() == "ANSI_X3.4-1968":
237+            self.writeto(u"parent/artonwall.txt", "Marmelade Jacuzzi")
238+        else:
239+            self.writeto(u"parent/ärtonwall.txt", "Marmelade Jacuzzi")
240+
241         def do_backup(use_backupdb=True, verbose=False):
242             cmd = ["backup"]
243             if not have_bdb or not use_backupdb:
244hunk ./src/allmydata/test/test_cli.py 904
245             self.failUnlessEqual(err, "")
246             self.failUnlessEqual(rc, 0)
247             fu, fr, dc, dr = self.count_output(out)
248-            # foo.txt, bar.txt, blah.txt
249-            self.failUnlessEqual(fu, 3)
250+            # foo.txt, bar.txt, blah.txt, ärtonwall.txt
251+            self.failUnlessEqual(fu, 4)
252             self.failUnlessEqual(fr, 0)
253             # empty, home, home/parent, home/parent/subdir
254             self.failUnlessEqual(dc, 4)
255hunk ./src/allmydata/test/test_cli.py 954
256             self.failUnlessEqual(rc, 0)
257             if have_bdb:
258                 fu, fr, dc, dr = self.count_output(out)
259-                # foo.txt, bar.txt, blah.txt
260+                # foo.txt, bar.txt, blah.txt, ärtonwall.txt
261                 self.failUnlessEqual(fu, 0)
262hunk ./src/allmydata/test/test_cli.py 956
263-                self.failUnlessEqual(fr, 3)
264+                self.failUnlessEqual(fr, 4)
265                 # empty, home, home/parent, home/parent/subdir
266                 self.failUnlessEqual(dc, 0)
267                 self.failUnlessEqual(dr, 4)
268hunk ./src/allmydata/test/test_cli.py 984
269                 self.failUnlessEqual(rc, 0)
270                 fu, fr, dc, dr = self.count_output(out)
271                 fchecked, dchecked, dread = self.count_output2(out)
272-                self.failUnlessEqual(fchecked, 3)
273+                self.failUnlessEqual(fchecked, 4)
274                 self.failUnlessEqual(fu, 0)
275hunk ./src/allmydata/test/test_cli.py 986
276-                self.failUnlessEqual(fr, 3)
277+                self.failUnlessEqual(fr, 4)
278                 # TODO: backupdb doesn't do dirs yet; when it does, this will
279                 # change to dchecked=4, and maybe dread=0
280                 self.failUnlessEqual(dchecked, 0)
281hunk ./src/allmydata/test/test_cli.py 1032
282                 fu, fr, dc, dr = self.count_output(out)
283                 # new foo.txt, surprise file, subfile, empty
284                 self.failUnlessEqual(fu, 4)
285-                # old bar.txt
286-                self.failUnlessEqual(fr, 1)
287+                # old bar.txt, ärtonwall.txt
288+                self.failUnlessEqual(fr, 2)
289                 # home, parent, subdir, blah.txt, surprisedir
290                 self.failUnlessEqual(dc, 5)
291                 self.failUnlessEqual(dr, 0)
292hunk ./src/allmydata/test/test_cli.py 1072
293             self.failUnlessEqual(err, "")
294             self.failUnlessEqual(rc, 0)
295             fu, fr, dc, dr = self.count_output(out)
296-            self.failUnlessEqual(fu, 5)
297+            self.failUnlessEqual(fu, 6)
298             self.failUnlessEqual(fr, 0)
299             self.failUnlessEqual(dc, 0)
300             self.failUnlessEqual(dr, 5)
301}
302[cli: tahoe manifest unicode support
303francois@ctrlaltdel.ch**20090427090144
304 Ignore-this: d2d3ca0614d6cbf725a4b0a0f06f7694
305] {
306hunk ./src/allmydata/scripts/cli.py 289
307         ("raw", "r", "Display raw JSON data instead of parsed"),
308         ]
309     def parseArgs(self, where=''):
310-        self.where = where
311+        self.where = argv_to_unicode(where)
312 
313     def getSynopsis(self):
314         return "%s manifest [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
315hunk ./src/allmydata/scripts/tahoe_manifest.py 83
316                 try:
317                     print >>stdout, d["cap"], "/".join(d["path"])
318                 except UnicodeEncodeError:
319-                    print >>stdout, d["cap"], "/".join([p.encode("utf-8")
320+                    print >>stdout, d["cap"], "/".join([unicode_to_stdout(p)
321                                                         for p in d["path"]])
322 
323 def manifest(options):
324}
325[cli: tahoe ls unicode support
326francois@ctrlaltdel.ch**20090427091850
327 Ignore-this: 38257c3ddea0cbab857c2eb194c349ec
328] {
329hunk ./src/allmydata/scripts/cli.py 87
330         ("json", None, "Show the raw JSON output"),
331         ]
332     def parseArgs(self, where=""):
333-        self.where = where
334+        self.where = argv_to_unicode(where)
335 
336     longdesc = """List the contents of some portion of the virtual drive."""
337 
338hunk ./src/allmydata/scripts/tahoe_ls.py 6
339 import simplejson
340 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path
341 from allmydata.scripts.common_http import do_http
342+from allmydata.util.stringutils import unicode_to_stdout
343 
344 def list(options):
345     nodeurl = options['node-url']
346hunk ./src/allmydata/scripts/tahoe_ls.py 116
347             line.append(ctime_s)
348         if not options["classify"]:
349             classify = ""
350-        line.append(name + classify)
351+        line.append(unicode_to_stdout(name) + classify)
352         if options["uri"]:
353             line.append(uri)
354         if options["readonly-uri"]:
355}
356[cli: tahoe get unicode support
357francois@ctrlaltdel.ch**20090427091820
358 Ignore-this: 9cae48ab0055113379beab9d4ee504e5
359] hunk ./src/allmydata/scripts/cli.py 98
360         # tahoe get FOO bar              # write to local file
361         # tahoe get tahoe:FOO bar        # same
362 
363-        self.from_file = arg1
364-        self.to_file = arg2
365+        self.from_file = argv_to_unicode(arg1)
366+
367+        if arg2:
368+            self.to_file = argv_to_unicode(arg2)
369+        else:
370+            self.to_file = None
371+
372         if self.to_file == "-":
373             self.to_file = None
374 
375[cli: tahoe webopen unicode support
376francois@ctrlaltdel.ch**20090427090059
377 Ignore-this: 2b972b5f3f240dfbb7545b5acd388f81
378] hunk ./src/allmydata/scripts/cli.py 279
379 
380 class WebopenOptions(VDriveOptions):
381     def parseArgs(self, where=''):
382-        self.where = where
383+        self.where = argv_to_unicode(where)
384 
385     def getSynopsis(self):
386         return "%s webopen [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
387[cli: tahoe rm unicode support
388francois@ctrlaltdel.ch**20090427085847
389 Ignore-this: dadad2700725c85440b9c34d8ce3c68c
390] hunk ./src/allmydata/scripts/cli.py 197
391 
392 class MvOptions(VDriveOptions):
393     def parseArgs(self, frompath, topath):
394-        self.from_file = frompath
395-        self.to_file = topath
396+        self.from_file = argv_to_unicode(frompath)
397+        self.to_file = argv_to_unicode(topath)
398 
399     def getSynopsis(self):
400         return "%s mv FROM TO" % (os.path.basename(sys.argv[0]),)
401[cli: tahoe ln unicode support
402francois@ctrlaltdel.ch**20090427085913
403 Ignore-this: 82ced82ded50a925a5650ae6000b46a2
404] hunk ./src/allmydata/scripts/cli.py 205
405 
406 class LnOptions(VDriveOptions):
407     def parseArgs(self, frompath, topath):
408-        self.from_file = frompath
409-        self.to_file = topath
410+        self.from_file = argv_to_unicode(frompath)
411+        self.to_file = argv_to_unicode(topath)
412 
413     def getSynopsis(self):
414         return "%s ln FROM TO" % (os.path.basename(sys.argv[0]),)
415[cli: tahoe status unicode support
416francois@ctrlaltdel.ch**20090427090213
417 Ignore-this: 370469b0cea44162bfa8d11e58ee72d4
418] hunk ./src/allmydata/scripts/cli.py 306
419         ("raw", "r", "Display raw JSON data instead of parsed"),
420         ]
421     def parseArgs(self, where=''):
422-        self.where = where
423+        self.where = argv_to_unicode(where)
424 
425     def getSynopsis(self):
426         return "%s stats [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
427[cli: tahoe check unicode support
428francois@ctrlaltdel.ch**20090427090226
429 Ignore-this: 59700729d6dc91c77ae46f4d053e79ce
430] hunk ./src/allmydata/scripts/cli.py 321
431         ("add-lease", None, "Add/renew lease on all shares"),
432         ]
433     def parseArgs(self, where=''):
434-        self.where = where
435+        self.where = argv_to_unicode(where)
436 
437     def getSynopsis(self):
438         return "%s check [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
439[cli: tahoe deep-check unicode support
440francois@ctrlaltdel.ch**20090427090243
441 Ignore-this: 2d0bb5592ae8735a184e325bd1515dec
442] hunk ./src/allmydata/scripts/cli.py 337
443         ("verbose", "v", "Be noisy about what is happening."),
444         ]
445     def parseArgs(self, where=''):
446-        self.where = where
447+        self.where = argv_to_unicode(where)
448 
449     def getSynopsis(self):
450         return "%s deep-check [ALIAS:PATH]" % (os.path.basename(sys.argv[0]),)
451[cli: tahoe mkdir unicode support
452francois@ctrlaltdel.ch**20090427091047
453 Ignore-this: 1375e8ea621d862ed4e261a8fc6cd772
454] {
455hunk ./src/allmydata/scripts/cli.py 53
456 
457 class MakeDirectoryOptions(VDriveOptions):
458     def parseArgs(self, where=""):
459-        self.where = where
460+        self.where = argv_to_unicode(where)
461     longdesc = """Create a new directory, either unlinked or as a subdirectory."""
462 
463 class AddAliasOptions(VDriveOptions):
464hunk ./src/allmydata/scripts/tahoe_mkdir.py 5
465 import urllib
466 from allmydata.scripts.common_http import do_http, check_http_error
467 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS
468+from allmydata.util.stringutils import unicode_to_url
469 
470 def mkdir(options):
471     nodeurl = options['node-url']
472hunk ./src/allmydata/scripts/tahoe_mkdir.py 35
473         path = path[:-1]
474     # path (in argv) must be "/".join([s.encode("utf-8") for s in segments])
475     url = nodeurl + "uri/%s/%s?t=mkdir" % (urllib.quote(rootcap),
476-                                           urllib.quote(path))
477+                                           urllib.quote(unicode_to_url(path)))
478     resp = do_http("POST", url)
479     check_http_error(resp, stderr)
480     new_uri = resp.read().strip()
481hunk ./src/allmydata/test/test_cli.py 841
482                                               dn, "tahoe:"))
483         return d
484 
485+class Mkdir(GridTestMixin, CLITestMixin, unittest.TestCase):
486+    def test_unicode_mkdir(self):
487+        self.basedir = os.path.dirname(self.mktemp())
488+        self.set_up_grid()
489+
490+        d = self.do_cli("create-alias", "tahoe")
491+        d.addCallback(lambda res: self.do_cli("mkdir", "tahoe:Motörhead"))
492+
493+        return d
494+
495+
496 class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase):
497 
498     def writeto(self, path, data):
499}
500[docs: explain the current unicode support in CLI
501francois@ctrlaltdel.ch**20090427091252
502 Ignore-this: 42f2c3107c0c94172f878559944779ca
503] hunk ./docs/frontends/CLI.txt 94
504 These commands also use a table of "aliases" to figure out which directory
505 they ought to use a starting point. This is explained in more detail below.
506 
507-In Tahoe v1.3.0, passing non-ascii characters to the cli is not guaranteed to
508-work, although it might work on your platform, especially if your platform
509-uses utf-8 encoding.
510+As of Tahoe v1.3.1, filenames containing non-ascii characters are
511+supported on the commande line if your terminal is correctly configured
512+for UTF-8 support. This is usually the case on moderns GNU/Linux
513+distributions.
514+
515+If your terminal doesn't support UTF-8, you will still be able to list
516+directories but non-ascii characters will be replaced by a question mark
517+(?) on display.
518+
519+Reading from and writing to files whose name contain non-ascii
520+characters is also supported when your system correctly understand them.
521+Under Unix, this is usually handled by locale settings. If Tahoe cannot
522+correctly decode a filename, it will raise an error. In such case,
523+you'll need to correct the name of your file, possibly with help from
524+tools such as convmv.
525 
526 === Starting Directories ===
527 
528[cli: tahoe cp unicode support
529francois@ctrlaltdel.ch**20090427135203
530 Ignore-this: cd26cdd0753625d1c1252cffd976abd6
531] {
532hunk ./src/allmydata/scripts/cli.py 185
533     def parseArgs(self, *args):
534         if len(args) < 2:
535             raise usage.UsageError("cp requires at least two arguments")
536-        self.sources = args[:-1]
537-        self.destination = args[-1]
538+        self.sources = map(argv_to_unicode, args[:-1])
539+        self.destination = argv_to_unicode(args[-1])
540 
541 class RmOptions(VDriveOptions):
542     def parseArgs(self, where):
543hunk ./src/allmydata/scripts/cli.py 190
544-        self.where = where
545+        self.where = argv_to_unicode(where)
546 
547     def getSynopsis(self):
548         return "%s rm VDRIVE_FILE" % (os.path.basename(sys.argv[0]),)
549hunk ./src/allmydata/scripts/tahoe_cp.py 7
550 import simplejson
551 from cStringIO import StringIO
552 from twisted.python.failure import Failure
553+import sys
554 from allmydata.scripts.common import get_alias, escape_path, DefaultAliasMarker
555 from allmydata.scripts.common_http import do_http
556 from allmydata import uri
557hunk ./src/allmydata/scripts/tahoe_cp.py 11
558+from twisted.python import usage
559+from allmydata.util.stringutils import fs_to_unicode, unicode_to_fs, unicode_to_url
560+from allmydata.util.assertutil import precondition
561 
562 def ascii_or_none(s):
563     if s is None:
564hunk ./src/allmydata/scripts/tahoe_cp.py 76
565 
566 class LocalFileSource:
567     def __init__(self, pathname):
568+        precondition(isinstance(pathname, unicode), pathname)
569         self.pathname = pathname
570 
571     def need_to_copy_bytes(self):
572hunk ./src/allmydata/scripts/tahoe_cp.py 87
573 
574 class LocalFileTarget:
575     def __init__(self, pathname):
576+        precondition(isinstance(pathname, unicode), pathname)
577         self.pathname = pathname
578     def put_file(self, inf):
579         outf = open(self.pathname, "wb")
580hunk ./src/allmydata/scripts/tahoe_cp.py 100
581 
582 class LocalMissingTarget:
583     def __init__(self, pathname):
584+        precondition(isinstance(pathname, unicode), pathname)
585         self.pathname = pathname
586 
587     def put_file(self, inf):
588hunk ./src/allmydata/scripts/tahoe_cp.py 114
589 
590 class LocalDirectorySource:
591     def __init__(self, progressfunc, pathname):
592+        precondition(isinstance(pathname, unicode), pathname)
593+
594         self.progressfunc = progressfunc
595         self.pathname = pathname
596         self.children = None
597hunk ./src/allmydata/scripts/tahoe_cp.py 124
598         if self.children is not None:
599             return
600         self.children = {}
601-        children = os.listdir(self.pathname)
602+        children = os.listdir(unicode_to_fs(self.pathname))
603         for i,n in enumerate(children):
604hunk ./src/allmydata/scripts/tahoe_cp.py 126
605+            n = fs_to_unicode(n)
606             self.progressfunc("examining %d of %d" % (i, len(children)))
607             pn = os.path.join(self.pathname, n)
608             if os.path.isdir(pn):
609hunk ./src/allmydata/scripts/tahoe_cp.py 142
610 
611 class LocalDirectoryTarget:
612     def __init__(self, progressfunc, pathname):
613+        precondition(isinstance(pathname, unicode), pathname)
614+
615         self.progressfunc = progressfunc
616         self.pathname = pathname
617         self.children = None
618hunk ./src/allmydata/scripts/tahoe_cp.py 152
619         if self.children is not None:
620             return
621         self.children = {}
622-        children = os.listdir(self.pathname)
623+        children = os.listdir(unicode_to_fs(self.pathname))
624         for i,n in enumerate(children):
625hunk ./src/allmydata/scripts/tahoe_cp.py 154
626+            n = fs_to_unicode(n)
627             self.progressfunc("examining %d of %d" % (i, len(children)))
628             pn = os.path.join(self.pathname, n)
629             if os.path.isdir(pn):
630hunk ./src/allmydata/scripts/tahoe_cp.py 176
631         return LocalDirectoryTarget(self.progressfunc, pathname)
632 
633     def put_file(self, name, inf):
634+        precondition(isinstance(name, unicode), name)
635         pathname = os.path.join(self.pathname, name)
636hunk ./src/allmydata/scripts/tahoe_cp.py 178
637-        outf = open(pathname, "wb")
638+        outf = open(unicode_to_fs(pathname), "wb")
639         while True:
640             data = inf.read(32768)
641             if not data:
642hunk ./src/allmydata/scripts/tahoe_cp.py 367
643                 if self.writecap:
644                     url = self.nodeurl + "/".join(["uri",
645                                                    urllib.quote(self.writecap),
646-                                                   urllib.quote(name.encode('utf-8'))])
647+                                                   urllib.quote(unicode_to_url(name))])
648                 self.children[name] = TahoeFileTarget(self.nodeurl, mutable,
649                                                       writecap, readcap, url)
650             else:
651hunk ./src/allmydata/test/test_cli.py 799
652     def test_unicode_filename(self):
653         self.basedir = "cli/Cp/unicode_filename"
654         self.set_up_grid()
655+        d = self.do_cli("create-alias", "tahoe")
656+
657+        # Use unicode strings when calling os functions
658+        if sys.getfilesystemencoding() == "ANSI_X3.4-1968":
659+            fn1 = os.path.join(self.basedir, u"Artonwall")
660+        else:
661+            fn1 = os.path.join(self.basedir, u"Ärtonwall")
662 
663hunk ./src/allmydata/test/test_cli.py 807
664-        fn1 = os.path.join(self.basedir, "Ärtonwall")
665         DATA1 = "unicode file content"
666         open(fn1, "wb").write(DATA1)
667hunk ./src/allmydata/test/test_cli.py 809
668+        d.addCallback(lambda res: self.do_cli("cp", fn1.encode('utf-8'), "tahoe:Ärtonwall"))
669+
670+        d.addCallback(lambda res: self.do_cli("get", "tahoe:Ärtonwall"))
671+        d.addCallback(lambda (rc,out,err): self.failUnlessEqual(out, DATA1))
672+
673 
674hunk ./src/allmydata/test/test_cli.py 815
675-        fn2 = os.path.join(self.basedir, "Metallica")
676+        fn2 = os.path.join(self.basedir, u"Metallica")
677         DATA2 = "non-unicode file content"
678         open(fn2, "wb").write(DATA2)
679 
680hunk ./src/allmydata/test/test_cli.py 822
681         # Bug #534
682         # Assure that uploading a file whose name contains unicode character doesn't
683         # prevent further uploads in the same directory
684-        d = self.do_cli("create-alias", "tahoe")
685-        d.addCallback(lambda res: self.do_cli("cp", fn1, "tahoe:"))
686-        d.addCallback(lambda res: self.do_cli("cp", fn2, "tahoe:"))
687-
688-        d.addCallback(lambda res: self.do_cli("get", "tahoe:Ärtonwall"))
689-        d.addCallback(lambda (rc,out,err): self.failUnlessEqual(out, DATA1))
690+        d.addCallback(lambda res: self.do_cli("cp", fn2.encode('utf-8'), "tahoe:"))
691 
692         d.addCallback(lambda res: self.do_cli("get", "tahoe:Metallica"))
693         d.addCallback(lambda (rc,out,err): self.failUnlessEqual(out, DATA2))
694hunk ./src/allmydata/test/test_cli.py 827
695 
696+        d.addCallback(lambda res: self.do_cli("ls", "tahoe:"))
697+
698         return d
699     test_unicode_filename.todo = "This behavior is not yet supported, although it does happen to work (for reasons that are ill-understood) on many platforms.  See issue ticket #534."
700 
701}
702[cli: tahoe put unicode support + encode path elements using unicode_to_url
703francois@ctrlaltdel.ch**20090429162003
704 Ignore-this: 6285a8c89837290173e9a4d3744e1173
705 
706 Both changes (tahoe put and url encoding) had to be included in the same patch
707 to prevent failing tests.
708] {
709hunk ./src/allmydata/scripts/cli.py 140
710         # tahoe put bar tahoe:FOO        # same
711 
712         if arg1 is not None and arg2 is not None:
713-            self.from_file = arg1
714-            self.to_file = arg2
715+            self.from_file = argv_to_unicode(arg1)
716+            self.to_file =  argv_to_unicode(arg2)
717         elif arg1 is not None and arg2 is None:
718hunk ./src/allmydata/scripts/cli.py 143
719-            self.from_file = arg1 # might be "-"
720+            self.from_file = argv_to_unicode(arg1) # might be "-"
721             self.to_file = None
722         else:
723             self.from_file = None
724hunk ./src/allmydata/scripts/cli.py 148
725             self.to_file = None
726-        if self.from_file == "-":
727+        if self.from_file == u"-":
728             self.from_file = None
729 
730     def getSynopsis(self):
731hunk ./src/allmydata/scripts/common.py 166
732 
733 def escape_path(path):
734     segments = path.split("/")
735-    return "/".join([urllib.quote(s) for s in segments])
736+    return "/".join([urllib.quote(unicode_to_url(s)) for s in segments])
737hunk ./src/allmydata/test/test_cli.py 743
738         d.addCallback(lambda (rc,out,err): self.failUnlessEqual(out, DATA2))
739         return d
740 
741+    def test_immutable_from_file_unicode(self):
742+        # tahoe put file.txt "à trier.txt"
743+        self.basedir = os.path.dirname(self.mktemp())
744+        self.set_up_grid()
745+
746+        rel_fn = os.path.join(self.basedir, "DATAFILE")
747+        abs_fn = os.path.abspath(rel_fn)
748+        # we make the file small enough to fit in a LIT file, for speed
749+        DATA = "short file"
750+        f = open(rel_fn, "w")
751+        f.write(DATA)
752+        f.close()
753+
754+        d = self.do_cli("create-alias", "tahoe")
755+
756+        d.addCallback(lambda res:
757+                      self.do_cli("put", rel_fn, "à trier.txt"))
758+        def _uploaded((rc,stdout,stderr)):
759+            readcap = stdout.strip()
760+            self.failUnless(readcap.startswith("URI:LIT:"))
761+            self.failUnless("201 Created" in stderr, stderr)
762+            self.readcap = readcap
763+        d.addCallback(_uploaded)
764+
765+        d.addCallback(lambda res:
766+                      self.do_cli("get", "tahoe:à trier.txt"))
767+        d.addCallback(lambda (rc,stdout,stderr):
768+                      self.failUnlessEqual(stdout, DATA))
769+
770+        return d
771+
772 class List(GridTestMixin, CLITestMixin, unittest.TestCase):
773     def test_list(self):
774         self.basedir = "cli/List/list"
775}
776[cli: aliases unicode support
777francois@ctrlaltdel.ch**20090427095807
778 Ignore-this: e2c49f5851ab89819acc633a196cc3df
779] {
780hunk ./src/allmydata/scripts/cli.py 58
781 
782 class AddAliasOptions(VDriveOptions):
783     def parseArgs(self, alias, cap):
784-        self.alias = alias
785+        self.alias = argv_to_unicode(alias)
786         self.cap = cap
787 
788     def getSynopsis(self):
789hunk ./src/allmydata/scripts/cli.py 68
790 
791 class CreateAliasOptions(VDriveOptions):
792     def parseArgs(self, alias):
793-        self.alias = alias
794+        self.alias = argv_to_unicode(alias)
795 
796     def getSynopsis(self):
797         return "%s create-alias ALIAS" % (os.path.basename(sys.argv[0]),)
798hunk ./src/allmydata/scripts/common.py 3
799 
800 import os, sys, urllib
801+import codecs
802 from twisted.python import usage
803 from allmydata.util.stringutils import unicode_to_url
804 
805hunk ./src/allmydata/scripts/common.py 104
806     except EnvironmentError:
807         pass
808     try:
809-        f = open(aliasfile, "r")
810+        f = codecs.open(aliasfile, "r", "utf-8")
811         for line in f.readlines():
812             line = line.strip()
813             if line.startswith("#") or not line:
814hunk ./src/allmydata/scripts/common.py 111
815                 continue
816             name, cap = line.split(":", 1)
817             # normalize it: remove http: prefix, urldecode
818-            cap = cap.strip()
819+            cap = cap.strip().encode('ascii')
820             aliases[name] = uri.from_string_dirnode(cap).to_string()
821     except EnvironmentError:
822         pass
823hunk ./src/allmydata/scripts/tahoe_add_alias.py 3
824 
825 import os.path
826+import codecs
827+import sys
828 from allmydata import uri
829 from allmydata.scripts.common_http import do_http, check_http_error
830 from allmydata.scripts.common import get_aliases
831hunk ./src/allmydata/scripts/tahoe_add_alias.py 8
832+from allmydata.util.stringutils import unicode_to_stdout
833 
834 def add_alias(options):
835     nodedir = options['node-directory']
836hunk ./src/allmydata/scripts/tahoe_add_alias.py 58
837     new_uri = resp.read().strip()
838 
839     # probably check for others..
840-    f = open(aliasfile, "a")
841+    f = codecs.open(aliasfile, "a", "utf-8")
842     f.write("%s: %s\n" % (alias, new_uri))
843     f.close()
844hunk ./src/allmydata/scripts/tahoe_add_alias.py 61
845-    print >>stdout, "Alias '%s' created" % (alias,)
846+    print >>stdout, "Alias '%s' created" % (unicode_to_stdout(alias),)
847     return 0
848 
849 def list_aliases(options):
850hunk ./src/allmydata/test/test_cli.py 522
851             self._test_webopen(["two:"], self.two_url)
852         d.addCallback(_test_urls)
853 
854+        d.addCallback(lambda res: self.do_cli("create-alias", "études"))
855+        def _check_create_unicode((rc,stdout,stderr)):
856+            self.failUnlessEqual(rc, 0)
857+            self.failIf(stderr)
858+
859+            # If stdout only supports ascii, accentuated characters are
860+            # being replaced by '?'
861+            if sys.stdout.encoding == "ANSI_X3.4-1968":
862+                self.failUnless("Alias '?tudes' created" in stdout)
863+            else:
864+                self.failUnless("Alias 'études' created" in stdout)
865+
866+            aliases = get_aliases(self.get_clientdir())
867+            self.failUnless(aliases[u"études"].startswith("URI:DIR2:"))
868+        d.addCallback(_check_create_unicode)
869+
870+        d.addCallback(lambda res: self.do_cli("ls", "études:"))
871+        def _check_ls1((rc, stdout, stderr)):
872+            self.failUnlessEqual(rc, 0)
873+            self.failIf(stderr)
874+
875+            self.failUnlessEqual(stdout, "")
876+        d.addCallback(_check_ls1)
877+
878+        d.addCallback(lambda res: self.do_cli("put", "-", "études:uploaded.txt",
879+          stdin="Blah blah blah"))
880+
881+        d.addCallback(lambda res: self.do_cli("ls", "études:"))
882+        def _check_ls2((rc, stdout, stderr)):
883+            self.failUnlessEqual(rc, 0)
884+            self.failIf(stderr)
885+
886+            self.failUnlessEqual(stdout, "uploaded.txt\n")
887+        d.addCallback(_check_ls2)
888+
889+        d.addCallback(lambda res: self.do_cli("get", "études:uploaded.txt"))
890+        def _check_get((rc, stdout, stderr)):
891+            self.failUnlessEqual(rc, 0)
892+            self.failIf(stderr)
893+            self.failUnlessEqual(stdout, "Blah blah blah")
894+        d.addCallback(_check_get)
895+
896         return d
897 
898 class Put(GridTestMixin, CLITestMixin, unittest.TestCase):
899}
900[cli: previous cli related patches should fix #534
901francois@ctrlaltdel.ch**20090427135239
902 Ignore-this: 82709853d0d871651b6673929616ec08
903] hunk ./src/allmydata/test/test_cli.py 903
904         d.addCallback(lambda res: self.do_cli("ls", "tahoe:"))
905 
906         return d
907-    test_unicode_filename.todo = "This behavior is not yet supported, although it does happen to work (for reasons that are ill-understood) on many platforms.  See issue ticket #534."
908 
909     def test_dangling_symlink_vs_recursion(self):
910         if not hasattr(os, 'symlink'):
911
912Context:
913
914[docs: setup: Norm Hardy suggested that it would be easier if users realized that they already had Python (especially true for Mac users)
915zooko@zooko.com**20090325035459
916 Ignore-this: e1bb76a1be4d6d541090d8d9e7e73db9
917] 
918[expirer: include crawler progress in the JSON status output
919warner@allmydata.com**20090324205137
920 Ignore-this: f65ccc0a57ed7c5d9565131350d87d2d
921] 
922[docs/proposed: new Accounting overview, discuss in #666
923warner@allmydata.com**20090324015752
924 Ignore-this: 7379396536e85194b1c1bec21288adc7
925] 
926[docs/proposed: move old accounting docs out of the way
927warner@allmydata.com**20090324015457
928 Ignore-this: 196fe85ef3592f7ef8e58a101eed0494
929] 
930[move GC docs out of proposed/, since it's all implemented now. Add reference to configuration.txt . Add expire.*= suggestions to tahoe.cfg .
931warner@allmydata.com**20090323230820
932 Ignore-this: ce0ec977f49c4a3642cf3a7ea7789dc4
933] 
934[storage: use constant-time comparison for write-enablers and lease-secrets
935warner@lothar.com**20090323032128
936 Ignore-this: efbbb15242b3f306c32498aae7fd75d
937] 
938[hashutil: add constant-time comparison function, to avoid timing attacks when python's short-circuiting data-dependent == operator is used to, say, check a write-enabler
939warner@lothar.com**20090323032055
940 Ignore-this: c5c1f5e529ab1b352c949f3e0d9abf20
941] 
942[WUI: fix display of empty directories, it threw an exception before
943warner@allmydata.com**20090320235809
944 Ignore-this: e598bb806d75411d202ba90fc251ad2b
945] 
946[storage webstatus: insert spaces when we're configured to expire multiple sharetypes
947warner@allmydata.com**20090320224450
948 Ignore-this: 18f44396384c8598d984eaa11dc92cf7
949] 
950[expirer: tolerate empty buckets, refactor bucketsize-counting code a bit, don't increment -mutable/-immutable counters unless we actually know the sharetype
951warner@allmydata.com**20090320191816
952 Ignore-this: 16827fe12b874a0205b0a7fdb6b7f960
953] 
954[storage: improve wording of status message
955warner@allmydata.com**20090319184837
956 Ignore-this: 66684623d50c89fa02915665dbbfec98
957] 
958[parse_date: insist that it returns an int
959warner@allmydata.com**20090319184443
960 Ignore-this: a1f5ae0c16a151d218c06fc4411f03c1
961] 
962[storage status: report expiration-cutoff-date like 19-Mar-2009 (as opposed to the tahoe.cfg input format of 2009-03-19), for redundancy: someone who gets the month and day switched will have a better chance to spot the problem in the storage-status output if it's in a different format
963warner@allmydata.com**20090319180756
964 Ignore-this: df2c3778260c6389d32f4b47b004ab35
965] 
966[expirer: clean up constructor args, add tahoe.cfg controls, use cutoff_date instead of date_cutoff
967warner@allmydata.com**20090319010009
968 Ignore-this: 2b6aaa6d5e6ff9fd417f32978b443fd2
969] 
970[util/time_format: new routine to parse dates like 2009-03-18, switch expirer to use it. I'd prefer to use 18-Mar-2009, but it is surprisingly non-trivial to build a parser that will take UTC dates instead of local dates
971warner@allmydata.com**20090319005814
972 Ignore-this: 4f08b301c780a78084fa02a09b5dda3
973] 
974[expirer: change setup, config options, in preparation for adding tahoe.cfg controls
975warner@allmydata.com**20090319002138
976 Ignore-this: b23a53e97f2a9fb7a005e9fe40e83fac
977] 
978[expirer: track mutable-vs-immutable sharecounts and sizes, report them on the web status page for comparison
979warner@allmydata.com**20090318202504
980 Ignore-this: 87e809bf5dedef3f0bc8f4a7b90e42d2
981] 
982[add utility function to parse durations, for lease-expiration config
983warner@lothar.com**20090317070117
984 Ignore-this: 2f4fa4352c887b4767969f0ea7931644
985] 
986[expirer: add mode to expire only-mutable or only-immutable shares
987warner@lothar.com**20090317065118
988 Ignore-this: b0b25427e3b1516bdfe293528b8e4a4e
989] 
990[tahoe_ls.py: add comment about error cases to improve
991warner@lothar.com**20090317051206
992 Ignore-this: 7c678b92a55b2f7c6f0d96fb6ece74ed
993] 
994[GC: add date-cutoff -based expiration, add proposed docs
995warner@lothar.com**20090317051041
996 Ignore-this: a5c0ecbcc2666eb04f2daa67331d1948
997] 
998[test_deepcheck: remove the 10s timeout: our dapper buildslave requires 30s, and the reduced timeout was only there because this tests fails by timeout rather than explicitly
999warner@lothar.com**20090316005134
1000 Ignore-this: 4ce081283c26719be513b5ce8381a81a
1001] 
1002[tahoe cp -r: add --caps-only flag, to write filecaps into local files instead of actual file contents. Used only for debugging and as a quick tree-comparison tool.
1003warner@lothar.com**20090315231958
1004 Ignore-this: 8ecdf2b08601ae9e9fec5885bf640262
1005] 
1006[dirnode deep_traverse: insert a turn break (fireEventually) at least once every 100 files, otherwise a CHK followed by more than 158 LITs can overflow the stack, sort of like #237.
1007warner@allmydata.com**20090313233135
1008 Ignore-this: 39b78faa947ed9461f2d120f6843e59f
1009] 
1010[consolidate: remove pointless 'else' after for loop
1011warner@allmydata.com**20090313082751
1012 Ignore-this: 517f41316f7ae40b92b9eef8269a4b69
1013] 
1014[consolidate: add eta, flush stdout
1015warner@allmydata.com**20090313082451
1016 Ignore-this: 845f63adccc32557c6864ae6120ba836
1017] 
1018[consolidate: tolerate unicode dirnames
1019warner@allmydata.com**20090313065402
1020 Ignore-this: 7e65703ed3d12d4bd5ec14b693e5f61f
1021] 
1022[dirnode.py: when doing deep-traverse, walk each directory in alphabetical order, to make things like 'manifest' more predictable
1023warner@allmydata.com**20090313065046
1024 Ignore-this: 9a80055a93a6b11853d4e8202bacec14
1025] 
1026[consolidator: add progress to scan-old-directory passes
1027warner@allmydata.com**20090313054728
1028 Ignore-this: adc67a34f4f19fd58c5bc76301b3df36
1029] 
1030[consolidator: fix cycle detection to not trigger on merely shared directories, add snapshot counter to progress
1031warner@allmydata.com**20090313042229
1032 Ignore-this: eba2cf9f1b1364b8e4c5ae4fa030a99f
1033] 
1034[consolidator: re-use more directories, add total directories seen-vs-used counts
1035warner@allmydata.com**20090313034801
1036 Ignore-this: 6e743d2940a9fe129cee31008c894d70
1037] 
1038[tahoe_backup.py: tolerate more time formats
1039warner@allmydata.com**20090313011600
1040 Ignore-this: ca74f56f0dce7d19810c5a7a75bc623c
1041] 
1042[consolidator: add more verbose traversal of directories
1043warner@allmydata.com**20090312232900
1044 Ignore-this: 8ff0e17c6174566832a566a111032db4
1045] 
1046[consolidate: create multiple numbered backups of the original Archives directory, not just the first time
1047warner@allmydata.com**20090312230427
1048 Ignore-this: e4985f76969b584d099b050781aa561c
1049] 
1050[add 'tahoe debug consolidate' command, to merge directories created by repeated 'tahoe cp -r' or the allmydata win32 backup tool, into the form that would have been created by 'tahoe backup'.
1051warner@allmydata.com**20090312205606
1052 Ignore-this: 66569ca2190aa7b0f9199bcf09dcb27e
1053] 
1054[tahoe_cp.py: return 0 for success, instead of None
1055warner@allmydata.com**20090312205345
1056 Ignore-this: 808f6d8617f8c4e7fde455e6c7639fab
1057] 
1058[setup: specify in the debian/control files that tahoe is compatible with Python 2.6
1059zooko@zooko.com**20090311225902
1060 Ignore-this: d0793013e4c868d92793d932ef92a62d
1061] 
1062[setup: update the debian/copyright text to reflect the current licences
1063zooko@zooko.com**20090311152952
1064 Ignore-this: 806a95b1b79d6bb20507db5c7201af45
1065] 
1066[expirer: fix prediction math, thanks to Zandr for the catch
1067warner@allmydata.com**20090309204217
1068 Ignore-this: e20f784483ea1a15e35627fe95506272
1069] 
1070[storage.expirer: oops, fix upgrade-handler code
1071warner@lothar.com**20090309035516
1072 Ignore-this: af8bc0ea1c7f305b33c06f4a9bf58de3
1073] 
1074[storage.expirer: handle upgrades better
1075warner@lothar.com**20090309034220
1076 Ignore-this: dd654305b94bc3209426a3e008d57363
1077] 
1078[storage.expirer: exercise the last missing line of webstatus code
1079warner@lothar.com**20090309033828
1080 Ignore-this: fc4aa34734cae32eec1db623ca0b145b
1081] 
1082[expirer: tolerate corrupt shares, add them to the state and history for future examination
1083warner@lothar.com**20090309030840
1084 Ignore-this: 5ae7e68471ed700cc68beb408e0f303
1085] 
1086[storage/immutable: raise a specific error upon seeing a bad version number, instead of using assert. Also wrap to 80cols.
1087warner@lothar.com**20090309030732
1088 Ignore-this: 5331d9680ffceff029fbbbcdece7f282
1089] 
1090[storage: add test coverage for BucketReader.__repr__
1091warner@lothar.com**20090309030527
1092 Ignore-this: 60ce4e8c5200cc9885a3057f914e78b4
1093] 
1094[storage/mutable: raise a specific error upon seeing bad magic, instead of using assert
1095warner@lothar.com**20090309020201
1096 Ignore-this: 8daa77362902f5d6ef793e9602a1383b
1097] 
1098[nodeadmin: node stops itself if a hotline file hasn't been touched in 120 seconds now, instead of in 60 seconds
1099zooko@zooko.com**20090308025039
1100 Ignore-this: a9cfc605d3fcad912bd2d0b35d5143ec
1101 A test failed on draco (MacPPC) because it took 67.1 seconds to get around to running the test, and the node had already stopped itself when the hotline file was 60 seconds old.
1102] 
1103[expirer: make web display a bit more consistent
1104warner@lothar.com**20090307221442
1105 Ignore-this: 7fec9d9bffc0bddeb51c1baa8e7ea020
1106] 
1107[web/storage.py: tolerate unknown-future displays, I'm not sure why LeaseCrawler.test_unpredictable_future didn't catch this
1108warner@lothar.com**20090307220243
1109 Ignore-this: 3d4e5baa8cc6d5d26edcea29fda8593d
1110] 
1111[tahoe_cp.py: improve error reporting slightly: don't json-interpret HTTP errors, pass through tahoe webapi error messages
1112warner@lothar.com**20090307114051
1113 Ignore-this: a8beccb67adb082a92509d439b27d68e
1114] 
1115[test_cli.py: assert that 'ls' on an unrecoverable file now gives a better error message
1116warner@lothar.com**20090307110815
1117 Ignore-this: 18e9758e4d0ca7faeaf5bd481c2d72ff
1118] 
1119[test_web: test behavior of broken-dirnode GET, both html and json
1120warner@lothar.com**20090307105707
1121 Ignore-this: c0e5b45eee28959f899efa1bd189d6bd
1122] 
1123[web: when a dirnode can't be read, emit a regular HTML page but with the child-table and upload-forms replaced with an apologetic message. Make sure to include the 'get info' links so the user can do a filecheck
1124warner@lothar.com**20090307105601
1125 Ignore-this: f949d6bd58c0c2fd60fd5fa730115f3f
1126] 
1127[web/common: split out exception-to-explanation+code mapping to a separate humanize_failure() function, so it can be used by other code. Add explanation for mutable UnrecoverableFileError.
1128warner@lothar.com**20090307105408
1129 Ignore-this: 92f326804ba73bb446c5df5992b7d72e
1130] 
1131[test_cli: use explicit (and stable) testdirs, instead of using self.mktemp
1132warner@lothar.com**20090307090428
1133 Ignore-this: 7c58d159e4f33d01635c3445d9e591f9
1134] 
1135[test_storage: solaris doesn't appear to give the same block count as other platforms, so don't assert as much about 'diskbytes' recovered
1136warner@lothar.com**20090307084518
1137 Ignore-this: 55b35c094ce78c50c8ede42062c5ea13
1138] 
1139[tahoe_cp.py: don't be verbose unless --verbose is passed: default is one line of success
1140warner@lothar.com**20090307084421
1141 Ignore-this: f75bb818081e0c2993378154775a69d1
1142] 
1143[setup.cfg: use allmydata.org as a mirror for some of our necessary dependencies
1144warner@allmydata.com**20090307045753
1145 Ignore-this: ce174de4ad2dd96f184eadf4d62ea779
1146] 
1147[storage: add a lease-checker-and-expirer crawler, plus web status page.
1148warner@allmydata.com**20090307044517
1149 Ignore-this: 4355224f89b959c6f1a256a7e6c88c3b
1150 
1151 This walks slowly through all shares, examining their leases, deciding which
1152 are still valid and which have expired. Once enabled, it will then remove the
1153 expired leases, and delete shares which no longer have any valid leases. Note
1154 that there is not yet a tahoe.cfg option to enable lease-deletion: the
1155 current code is read-only. A subsequent patch will add a tahoe.cfg knob to
1156 control this, as well as docs. Some other minor items included in this patch:
1157 
1158  tahoe debug dump-share has a new --leases-only flag
1159  storage sharefile/leaseinfo code is cleaned up
1160  storage web status page (/storage) has more info, more tests coverage
1161  space-left measurement on OS-X should be more accurate (it was off by 2048x)
1162   (use stat .f_frsize instead of f_bsize)
1163] 
1164[setup: comment-out the use of the directory full of dependency packages on the test grid -- the test grid is too unreliable!  :-(
1165zooko@zooko.com**20090307044332
1166 Ignore-this: c09f2e5f0b383b4227df4b07c267cb05
1167] 
1168[setup: create a "make deb-lenny-head" target
1169zooko@zooko.com**20090306191057
1170 Ignore-this: 4b2ff187a3d08dcfe9318980ca92f097
1171 I made this patch by copying [20090305220021-92b7f-89d987c7d05306b5cb03a64f2956a652c10a7296] and changing the name from "intrepid" to "lenny".  I haven't tested it.
1172] 
1173[trivial: remove unused import detected by pyflakes, and remove trailing whitespace
1174zooko@zooko.com**20090305223204
1175 Ignore-this: 991001a50da1a357a519c3cb880d7ee1
1176] 
1177[setup: enable build of .debs for Ubuntu Intrepid, thanks to DarKNesS_WolF
1178zooko@zooko.com**20090305220021
1179 Ignore-this: 88dbb3f72c2446b7734ac437189b67df
1180] 
1181[trivial: use more specific function for ascii-encoding storage index
1182zooko@zooko.com**20090222175751
1183 Ignore-this: c1a78a71cf04d7dbd80a71106f9b21a1
1184] 
1185[doc: update how_to_make_a_tahoe_release.txt
1186zooko@zooko.com**20090222175739
1187 Ignore-this: 6a2e1592741b362bc170167a9cadc0b
1188] 
1189[test_cli: validate non-HTML error response of 'tahoe get' on an unrecoverable file
1190warner@lothar.com**20090304041146] 
1191[web: full patch for HTML-vs-plaintext traceback renderings, improve test coverage of exception rendering
1192warner@lothar.com**20090304035630] 
1193[web/common.py: use 'Accept:' header to control HTML-vs-text/plain traceback renderings
1194warner@lothar.com**20090304035457] 
1195[test/common: rearrange shouldHTTPError
1196warner@lothar.com**20090304014059] 
1197[web: move plural() to common.py
1198warner@lothar.com**20090304014019] 
1199[add more information to NotEnoughSharesError, split out new exceptions for no-servers and no-source-of-ueb-hash
1200warner@lothar.com**20090304013715] 
1201[test_web: move shouldHTTPError into common.WebErrorMixin
1202warner@lothar.com**20090303225620] 
1203[test_web: clean up shouldHTTPError methods
1204warner@lothar.com**20090303224604] 
1205[immutable checker add-lease: catch remote IndexError here too
1206warner@allmydata.com**20090227071724
1207 Ignore-this: 94ee6064ce26409381c6451cd50fdade
1208] 
1209[servermap add-lease: fix the code that's supposed to catch remote IndexErrors, I forgot that they present as ServerFailures instead. This should stop the deluge of Incidents that occur when you do add-lease against 1.3.0 servers
1210warner@allmydata.com**20090227070426
1211 Ignore-this: 3d7bc87d9587b51d44b27317d9eded23
1212] 
1213[rrefutil: add check_remote utility function
1214warner@allmydata.com**20090227065957
1215 Ignore-this: d859d0fae87b7e84ad3c2893350ed519
1216] 
1217[rrefutil: add trap_remote utility and friends
1218warner@allmydata.com**20090227065524
1219 Ignore-this: a594050cdd9bcca073d8029819dbc35
1220] 
1221[web: improve layout of storage status with a table
1222warner@allmydata.com**20090227015838
1223 Ignore-this: 5c12f5e296ad1cf224f85e307813eb09
1224] 
1225[crawler: add ETA to get_progress()
1226warner@allmydata.com**20090227014248
1227 Ignore-this: 27ae76c0530b83323209be70df3d8a4b
1228] 
1229[Fix for bug #645, correct path handling logic so that it works from sshfs
1230Alberto Berti <alberto@metapensiero.it>**20090226150237
1231 Ignore-this: e9c1b2d48ebf4ba68100d76e54154a78
1232] 
1233[wui: s/Provisioning/Reliability/ ; suggested by Terrell
1234zooko@zooko.com**20090226030904
1235 Ignore-this: f9559702e760dc3c57e2fc36f087d91e
1236] 
1237[startstop_node.py: when restarting, tolerate a stale pid too
1238warner@allmydata.com**20090226015245
1239 Ignore-this: 59197d3f400417be64fa0f91a64fae12
1240] 
1241[web: fix the ERROR: line to work the same in python2.4 and 2.5
1242warner@lothar.com**20090225074621] 
1243[test_cli/test_web: fix spurious test failure on solaris (maybe python2.4?) due to variations in the way that exceptions are stringified
1244warner@allmydata.com**20090225060128
1245 Ignore-this: 829fb7d67fd199babdde1443b64a5381
1246] 
1247[CLI: modify 'tahoe manifest' and 'tahoe deep-check' to report ERROR: properly. For #590.
1248warner@allmydata.com**20090225054415
1249 Ignore-this: 99162f894fdd24112a869e14848c3dea
1250] 
1251[webapi: modify streaming deep-manifest/deep-checker to emit an ERROR: line if they encounter an unrecoverable+untraversable directory. For #590.
1252warner@allmydata.com**20090225051335
1253 Ignore-this: e6bc49368fb0e7ada7cff477fd63ffe6
1254] 
1255[scripts/common: fix alias handling on windows again, emit slightly nicer error message in response to an unknown alias
1256warner@allmydata.com**20090225042136
1257 Ignore-this: 76df800d131aed6701b5c7408105b134
1258] 
1259[#165: make 'tahoe restart --force' the default behavior: warn but do not stop if restart is used on something that wasn't a running node, and always try to start it afterwards. This is particularly important for #315 (restart -m), because otherwise a single not-already-running node will prevent all nodes from being restarted, resulting in longer downtime than necessary
1260warner@allmydata.com**20090225034213
1261 Ignore-this: 26d8b0eea0279ca793faf23c5e948d90
1262] 
1263[test_deepcheck: switch deep-check tests to use no-network too. This cuts the runtime down by about 50%
1264warner@allmydata.com**20090225030457
1265 Ignore-this: b3a98ed18c5752c9016c047e95d42b
1266] 
1267[test_deepcheck: convert MutableChecker to no-network GridTest
1268warner@allmydata.com**20090225020010
1269 Ignore-this: eccba7fda129330b642886271a61a573
1270] 
1271[tests/no_network: move GET into the GridTestMixin class
1272warner@allmydata.com**20090225003300
1273 Ignore-this: 7779ad38c2d687ae328ba3cb6164a7a4
1274] 
1275[common_web.py: oops, add .fields to the other FakeRequest
1276warner@allmydata.com**20090225000459
1277 Ignore-this: 7144269b5e083553ee2c3e7afea00604
1278] 
1279[test_cli: exercise the recent tolerate-'c:\dir\file.txt' fix in scripts/common, recorded in a separate match to make it easier to merge the fix to prod
1280warner@allmydata.com**20090224235620
1281 Ignore-this: 2cae196dd4ccb578b2abae085376e0d7
1282] 
1283[scripts/common: on windows, tolerate paths like 'c:\dir\file.txt', by treating single-letter aliases on windows/cygwin as non-aliases
1284warner@allmydata.com**20090224235522
1285 Ignore-this: 96d37644b7f81ac768ff4a1d1915eb46
1286] 
1287[test/common_web.py: add a .fields attribute to our FakeRequest, since we support versions of Nevow that are old enough to not do it themselves
1288warner@allmydata.com**20090224232050
1289 Ignore-this: 239aaed746128e54e886762782541a1f
1290] 
1291[Two small fixes on documentation for cli backup command.
1292Alberto Berti <alberto@metapensiero.it>**20090224223634
1293 Ignore-this: 5634a6dadad6e4e43a112de7fe5c74c
1294] 
1295[test_web: add (disabled) test to see what happens when deep-check encounters an unrecoverable directory. We still need code changes to improve this behavior.
1296warner@lothar.com**20090224214017
1297 Ignore-this: e839f1b0ec40f53fedcd809c2a30d5f9
1298] 
1299[Add elapsed timestamp to cli backup command final summary.
1300Alberto Berti <alberto@metapensiero.it>**20090224171425
1301 Ignore-this: 9a042d11f95ee9f6858a5096d513c0bc
1302] 
1303[Added documentation for '--exclude' and friends cli backup command.
1304Alberto Berti <alberto@metapensiero.it>**20090224153049
1305 Ignore-this: bbc791fa56e38535bb82cc3077ffde90
1306] 
1307[test_repairer: change to use faster no_network.GridTestMixin, split Verifier tests into separate cases, refactor judgement funcs into shared methods
1308warner@lothar.com**20090224041506
1309 Ignore-this: 584ce72d6276da5edc00562793d4ee53
1310] 
1311[immutable/checker.py: trap ShareVersionIncompatible too. Also, use f.check
1312warner@lothar.com**20090224041405
1313 Ignore-this: b667e8d3192116293babcacdeed42898
1314 instead of examining the value returned by f.trap, because the latter appears
1315 to squash exception types down into their base classes (i.e. since
1316 ShareVersionIncompatible is a subclass of LayoutInvalid,
1317 f.trap(Failure(ShareVersionIncompatible)) == LayoutInvalid).
1318 
1319 All this resulted in 'incompatible' shares being misclassified as 'corrupt'.
1320] 
1321[immutable/layout.py: wrap to 80 cols, no functional changes
1322warner@lothar.com**20090224005837
1323 Ignore-this: 40019480180ec34141506a28d7711608
1324] 
1325[test_repairer: change Repairer to use much-faster no_network.GridTestMixin. As a side-effect, fix what I think was a bug: some of the assert-minimal-effort-expended checks were mixing write counts and allocate counts
1326warner@lothar.com**20090223234227
1327 Ignore-this: d58bd0a909f9939775730cda4a858cae
1328] 
1329[test/no_network.py: add a basic stats provider
1330warner@lothar.com**20090223233937
1331 Ignore-this: c9f3cc4eed99cfc36f68938ceff4162c
1332] 
1333[tests: stop using setUpClass/tearDownClass, since they've been deprecated in Twisted-8.2.0
1334warner@lothar.com**20090223204312
1335 Ignore-this: 24c6592141cf64103530c024f93a5b88
1336] 
1337[test_checker: improve test coverage for checker results
1338warner@lothar.com**20090223201943
1339 Ignore-this: 83e173602f0f4c811a7a9893d85385df
1340] 
1341[Fixed tests again so they will pass on windows.
1342Alberto Berti <alberto@metapensiero.it>**20090223003502
1343 Ignore-this: 80d5074e7153642a2fa2a77958bfb50d
1344] 
1345[misc/*: remove RuntimeError too
1346warner@lothar.com**20090222233401
1347 Ignore-this: b76f8a184f75bb28eb9d8002f957936a
1348] 
1349[scripts: stop using RuntimeError, for #639
1350warner@lothar.com**20090222233106
1351 Ignore-this: 686a424442670fffbd4d1816c284a601
1352] 
1353[mutable/publish: stop using RuntimeError, for #639
1354warner@lothar.com**20090222233056
1355 Ignore-this: 2a80a661c7850d97357caddad48c6e9d
1356] 
1357[remove more RuntimeError from unit tests, for #639
1358warner@lothar.com**20090222232855
1359 Ignore-this: 1a1c3e1457f3f29ba7101fe406ee5f43
1360] 
1361[stop using RuntimeError in unit tests, for #639
1362warner@lothar.com**20090222232722
1363 Ignore-this: 475ce0c0dcd7a1f5ed83ef460312efea
1364] 
1365[ftpd/sftpd: stop using RuntimeError, for #639
1366warner@lothar.com**20090222232426
1367 Ignore-this: 97001362c4ba9e94b2e254e229b79987
1368] 
1369[Added tests for the cse when listdir is an iterator
1370Alberto Berti <alberto@metapensiero.it>**20090222224356
1371 Ignore-this: 218fb2aba02c28b4b1e5324bdb5adeaa
1372] 
1373[Fixed tests so that they pass also on buildbots.
1374Alberto Berti <alberto@metapensiero.it>**20090222224311
1375 Ignore-this: fcb91cd6acf028382411d23d380a4576
1376] 
1377[Use failUnlessEqual instead of failUnless(a == b)
1378Alberto Berti <alberto@metapensiero.it>**20090222224214
1379 Ignore-this: 8f9144632e3ac9acb4726fb48a083bf4
1380] 
1381[Better implementation of filtering algorithm.
1382Alberto Berti <alberto@metapensiero.it>**20090222224049
1383 Ignore-this: 67a8bd2f99bcc87ca2443bef13370a87
1384] 
1385[Removed '.hgrags' from vcs excludes
1386Alberto Berti <alberto@metapensiero.it>**20090222223946
1387 Ignore-this: 3e94c22fc9d85f380ee11fb8bdb4d1e9
1388] 
1389[docs: CREDITS to Alberto Berti
1390zooko@zooko.com**20090222193314
1391 Ignore-this: 74d370ada3234cce9e58aec15d739f71
1392] 
1393[Added tests for the --exclude* options of backup command.
1394Alberto Berti <alberto@metapensiero.it>**20090222165106
1395 Ignore-this: f1b931cf2e7929ce47b737c022bca707
1396] 
1397[Added --exclude, --exclude-from and --exclude-vcs options to backup command.
1398Alberto Berti <alberto@metapensiero.it>**20090222170829
1399 Ignore-this: 4912890229cd54a2f61f14f06bc4afcc
1400 
1401 It is still impossible to specify absolute exclusion path, only
1402 relative. I must check with tar or rsync how they allow them to be
1403 specified.
1404] 
1405[Raise a more explanatory exception for errors encountered during backup processing.
1406Alberto Berti <alberto@metapensiero.it>**20090222170252
1407 Ignore-this: f6b8ffe2a903ba07a2c1c59130dac1e4
1408] 
1409[Added tests for the fixed alias related command's synopsis
1410Alberto Berti <alberto@metapensiero.it>**20090222163732
1411 Ignore-this: 4432b4e88e990ba53a5b3fe0f12db2ac
1412] 
1413[Add missing synopsis and descriptions for alias commands.
1414Alberto Berti <alberto@metapensiero.it>**20090221003106
1415 Ignore-this: 8aedd03d36d92d912102c7f29e4ca697
1416] 
1417[docs: move many specification-like documents into specifications/
1418warner@lothar.com**20090222054054
1419 Ignore-this: a4110cc478198c0611205aba1ccf54f4
1420] 
1421[test_web.py: increase test coverage of web.status.plural()
1422warner@lothar.com**20090222000116
1423 Ignore-this: 3138c9d5d2410d8e1121e9b2ed694169
1424] 
1425[crawler: fix performance problems: only save state once per timeslice (not after every bucket), don't start the crawler until 5 minutes after node startup
1426warner@lothar.com**20090221205649
1427 Ignore-this: e6551569982bd31d19779ff15c2d6f58
1428] 
1429[test_system: oops, don't assume that all files in storage/ are in a deep storage/shares/prefix/si/shnum path, since now the crawler pickle has a short path
1430warner@lothar.com**20090221061710
1431 Ignore-this: fde76d0e5cae853014d1bb18b5f17dae
1432] 
1433[crawler: tolerate low-resolution system clocks (i.e. windows)
1434warner@lothar.com**20090221061533
1435 Ignore-this: 57286a3abcaf44f6d1a78c3c1ad547a5
1436] 
1437[BucketCountingCrawler: store just the count, not cycle+count, since it's too easy to make usage mistakes otherwise
1438warner@lothar.com**20090221035831
1439 Ignore-this: 573b6f651af74380cdd64059fbbdda4b
1440] 
1441[test_storage: startService the server, as is now the standard practice
1442warner@lothar.com**20090221035755
1443 Ignore-this: 3999889bd628fe4039bbcf1b29160453
1444] 
1445[crawler: load state from the pickle in init, rather than waiting until startService, so get_state() can be called early
1446warner@lothar.com**20090221035720
1447 Ignore-this: ecd128a5f4364c0daf4b72d791340b66
1448] 
1449[BucketCountingCrawler: rename status and state keys to use 'bucket' instead of 'share', because the former is more accurate
1450warner@lothar.com**20090221034606
1451 Ignore-this: cf819f63fac9506c878d6c9715ce35b7
1452] 
1453[storage: also report space-free-for-root and space-free-for-nonroot, since that helps users understand the space-left-for-tahoe number better
1454warner@lothar.com**20090221032856
1455 Ignore-this: 9fdf0475f758acd98b73026677170b45
1456] 
1457[storage: add bucket-counting share crawler, add its output (number of files+directories maintained by a storage server) and status to the webapi /storage page
1458warner@lothar.com**20090221030408
1459 Ignore-this: 28761c5e076648026bc5f518506db65c
1460] 
1461[storage: move si_b2a/si_a2b/storage_index_to_dir out of server.py and into common.py
1462warner@lothar.com**20090221030309
1463 Ignore-this: 645056428ab797f0b542831c82bf192a
1464] 
1465[crawler: add get_progress, clean up get_state
1466warner@lothar.com**20090221002743
1467 Ignore-this: 9bea69f154c75b31a53425a8ea67789b
1468] 
1469[web/storage: make sure we can handle platforms without os.statvfs too
1470warner@lothar.com**20090220220353
1471 Ignore-this: 79d4cb8482a8543b9759dc949c86c587
1472] 
1473[crawler: provide for one-shot crawlers, which stop after their first full cycle, for share-upgraders and database-populaters
1474warner@lothar.com**20090220211911
1475 Ignore-this: fcdf72c5ffcafa374d376388be6fa5c5
1476] 
1477[web: add Storage status page, improve tests
1478warner@lothar.com**20090220202926
1479 Ignore-this: e34d5270dcf0237fe72f573f717c7a4
1480] 
1481[storage: include reserved_space in stats
1482warner@lothar.com**20090220202920
1483 Ignore-this: b5b480fe0abad0148ecad0c1fb47ecae
1484] 
1485[web/check_results: sort share identifiers in the sharemap display
1486warner@lothar.com**20090220182922
1487 Ignore-this: 5c7bfcee3e15c7082c3653eb8a460960
1488] 
1489[webapi: pass client through constructor arguments, remove IClient, should make it easier to test web renderers in isolation
1490warner@lothar.com**20090220181554
1491 Ignore-this: e7848cd1bee8faf2ce7aaf040b9bf8e3
1492] 
1493[test/no_network: do startService on the storage servers, make it easier to customize the storage servers
1494warner@lothar.com**20090220022254
1495 Ignore-this: e62f328721c007e4c5ee023a6efdf66d
1496] 
1497[crawler: modify API to support upcoming bucket-counting crawler
1498warner@lothar.com**20090220013142
1499 Ignore-this: 808f8382837b13082f8b245db2ebee06
1500] 
1501[test_backupdb: make the not-a-database file larger, since the older sqlite-2.3.2 on OS-X is easily fooled
1502warner@lothar.com**20090220000409
1503 Ignore-this: 694d2ca5053bb96e91670765d0cedf2e
1504] 
1505[web/reliability: add parameter descriptions, adapted from a patch from Terrell Russell.
1506warner@lothar.com**20090219222918
1507 Ignore-this: 835f5ab01e1aff31b2ff9febb9a51f3
1508] 
1509[test_crawler: hush pyflakes
1510warner@lothar.com**20090219202340
1511 Ignore-this: 765d22c9c9682cc86c5205dc130500af
1512] 
1513[test_crawler: disable the percentage-of-cpu-used test, since it is too unreliable on our slow buildslaves. But leave the code in place for developers to run by hand.
1514warner@lothar.com**20090219201654
1515 Ignore-this: ff7cf5cfa79c6f2ef0cf959495dd989a
1516] 
1517[reliability.py: fix the numpy conversion, it was completely broken. Thanks to Terrell Russell for the help.
1518warner@lothar.com**20090219195515
1519 Ignore-this: f2b1eb65855111b338e1487feee1bbcf
1520] 
1521[reliability: switch to NumPy, since Numeric is deprecated
1522warner@lothar.com**20090219074435
1523 Ignore-this: f588a68e9bcd3b0bc3653570882b6fd5
1524] 
1525[setup.py: fix pyflakes complaints
1526warner@lothar.com**20090219073643
1527 Ignore-this: a314e5456b0a796bc9f70232a119ec68
1528] 
1529[move show-tool-versions out of setup.py and into a separate script in misc/ , since setuptools is trying to build and install a bunch of stuff first
1530warner@lothar.com**20090219073558
1531 Ignore-this: 9e56bc43026379212e6b6671ed6a1fd4
1532] 
1533[test_crawler: don't require >=1 cycle on cygwin
1534warner@lothar.com**20090219065818
1535 Ignore-this: b8d2d40f26aeb30a7622479840a04635
1536] 
1537[setup.py: add show_tool_versions command, for the benefit of a new buildbot step
1538warner@lothar.com**20090219062436
1539 Ignore-this: 21d761c76a033e481831584bedc60c86
1540] 
1541[setup.py: wrap to 80 cols, no functional changes
1542warner@lothar.com**20090219055751
1543 Ignore-this: d29e57c6ee555f2ee435667b7e13e60b
1544] 
1545[crawler: use fileutil.move_info_place in preference to our own version
1546warner@lothar.com**20090219051342
1547 Ignore-this: ee4e46f3de965610503ba36b28184db9
1548] 
1549[fileutil: add move_into_place(), to perform the standard unix trick of atomically replacing a file, with a fallback for windows
1550warner@lothar.com**20090219051310
1551 Ignore-this: c1d35e8ca88fcb223ea194513611c511
1552] 
1553[crawler: fix problems on windows and our slow cygwin slave
1554warner@lothar.com**20090219042431
1555 Ignore-this: 8019cb0da79ba00c536183a6f57b4cab
1556] 
1557[#633: first version of a rate-limited interruptable share-crawler
1558warner@lothar.com**20090219034633
1559 Ignore-this: 5d2d30c743e3b096a8e775d5a9b33601
1560] 
1561[change StorageServer to take nodeid in the constructor, instead of assigning it later, since it's cleaner and because the original problem (Tubs not being ready until later) went away
1562warner@lothar.com**20090218222301
1563 Ignore-this: 740d582f20c93bebf60e21d9a446d3d2
1564] 
1565[test_system: split off checker tests to test_deepcheck.py, this file is too big
1566warner@lothar.com**20090218214234
1567 Ignore-this: 82bf8db81dfbc98224bbf694054a8761
1568] 
1569[break storage.py into smaller pieces in storage/*.py . No behavioral changes.
1570warner@lothar.com**20090218204655
1571 Ignore-this: 312d408d1cacc5a764d791b53ebf8f91
1572] 
1573[immutable/layout: minor change to repr name
1574warner@lothar.com**20090218204648
1575 Ignore-this: c8781ef15b7dea63b39236a1899b86ce
1576] 
1577[docs: add lease-tradeoffs diagram
1578warner@lothar.com**20090218204137
1579 Ignore-this: c22a589ad465dac846da834c30dc4083
1580] 
1581[interfaces.py: allow add/renew/cancel-lease to return Any, so that 1.3.1 clients (the first to use these calls) can tolerate future storage servers which might return something other than None
1582warner@lothar.com**20090218192903
1583 Ignore-this: dcbb704a05416ecc66d90fb486c3d75b
1584] 
1585[docs/debian.txt: minor edit
1586warner@lothar.com**20090218032212
1587 Ignore-this: 64ff1fb163ffca4bcfd920254f1cf866
1588] 
1589[add --add-lease to 'tahoe check', 'tahoe deep-check', and webapi.
1590warner@lothar.com**20090218013243
1591 Ignore-this: 176b2006cef5041adcb592ee83e084dd
1592] 
1593[change RIStorageServer.remote_add_lease to exit silently in case of no-such-bucket, instead of raising IndexError, because that makes the upcoming --add-lease feature faster and less noisy
1594warner@lothar.com**20090218013053
1595 Ignore-this: 6fdfcea2c832178f1ce72ab0ff510f3a
1596] 
1597[CLI #590: convert 'tahoe deep-check' to streaming form, improve display, add tests
1598warner@lothar.com**20090217231511
1599 Ignore-this: 6d88eb94b1c877eacc8c5ca7d0aac776
1600] 
1601[interfaces.py: document behavior of add_lease/renew_lease/cancel_lease, before I change it
1602warner@lothar.com**20090217194809
1603 Ignore-this: 703c6712926b8edb19d55d790b65a400
1604] 
1605[test_backupdb: improve error messages if the test fails
1606warner@lothar.com**20090217170838
1607 Ignore-this: ef657e87c66e4304d3e0aca9831b84c
1608] 
1609[webapi #590: add streaming deep-check. Still need a CLI tool to use it.
1610warner@lothar.com**20090217053553
1611 Ignore-this: a0edd3d2a531c48a64d8397f7e4b208c
1612] 
1613[test_web.Grid: change the CHECK() function to make it easier to test t= values with hyphens in them
1614warner@lothar.com**20090217050034
1615 Ignore-this: 410c08735347c2057df52f6716520228
1616] 
1617[test_web: improve checker-results coverage with a no-network -based test, enhance no-network harness to assist, fix some bugs in web/check_results.py that were exposed
1618warner@lothar.com**20090217041242
1619 Ignore-this: fe54bb66a9ae073c002a7af51cd1e18
1620] 
1621[web: fix handling of reliability page when Numeric is not available
1622warner@lothar.com**20090217015658
1623 Ignore-this: 9d329182f1b2e5f812e5e7eb5f4cf2ed
1624] 
1625[test/no_network: update comments with setup timing: no_network takes 50ms, SystemTestMixin takes 2s (on my laptop)
1626warner@lothar.com**20090217000643
1627 Ignore-this: cc778fa3219775b25057bfc9491f8f34
1628] 
1629[test_upload: rewrite in terms of no-network GridTestMixin, improve no_network.py as necessary
1630warner@lothar.com**20090216234457
1631 Ignore-this: 80a341d5aa3036d24de98e267499d70d
1632] 
1633[test_download: rewrite in terms of no-network GridTestMixin, improve no_network.py as necessary
1634warner@lothar.com**20090216233658
1635 Ignore-this: ec2febafd2403830519120fb3f3ca04e
1636] 
1637[test_dirnode.py: convert Deleter to new no-network gridtest
1638warner@lothar.com**20090216232348
1639 Ignore-this: 8041739442ec4db726675e48f9775ae9
1640] 
1641[test_cli.py: modify to use the new 'no-network' gridtest instead of SystemTestMixin, which speeds it up from 73s to 43s on my system
1642warner@lothar.com**20090216232005
1643 Ignore-this: ec6d010c9182aa72049d1fb894cf890e
1644] 
1645[tests: fix no_network framework to work with upload/download and checker
1646warner@lothar.com**20090216231947
1647 Ignore-this: 74b4dbd66b8384ae7c7544969fe4f744
1648] 
1649[client.py: improve docstring
1650warner@lothar.com**20090216231532
1651 Ignore-this: bbaa9e3f63fdb0048e3125c4681b2d1f
1652] 
1653[test_cli: add test coverage for help strings
1654warner@lothar.com**20090216210833
1655 Ignore-this: d2020849107f687448e159a19d0e5dab
1656] 
1657[test/no_network: new test harness, like system-test but doesn't use the network so it's faster
1658warner@lothar.com**20090216205844
1659 Ignore-this: 31678f7bdef30b0216fd657fc6145534
1660] 
1661[interfaces.py: minor docstring edit
1662warner@lothar.com**20090216205816
1663 Ignore-this: cec3855070197f7920b370f95e8b07bd
1664] 
1665[setup: if you sdist_dsc (to produce the input files for dpkg-buildpackage) then run darcsver first
1666zooko@zooko.com**20090216201558
1667 Ignore-this: b85be51b3d4a9a19a3366e690f1063e2
1668] 
1669[doc: a few edits to docs made after the 1.3.0 release
1670zooko@zooko.com**20090216201539
1671 Ignore-this: dbff3b929d88134d862f1dffd1ef068a
1672] 
1673[test_cli: improve test coverage slightly
1674warner@lothar.com**20090216030451
1675 Ignore-this: e01ccc6a6fb44aaa4fb14fe8669e2065
1676] 
1677[test_util: get almost full test coverage of dictutil, starting with the original pyutil tests as a base. The remaining three uncovered lines involve funny cases of ValueOrderedDict that I can't figure out how to get at
1678warner@lothar.com**20090216023210
1679 Ignore-this: dc1f0c6d8c003c0ade38bc8f8516b04d
1680] 
1681[provisioning/reliability: add tests, hush pyflakes, remove dead code, fix web links
1682warner@lothar.com**20090215222451
1683 Ignore-this: 7854df3e0130d9388f06efd4c797262f
1684] 
1685[util/statistics: add tests, fix mean_repair_cost
1686warner@lothar.com**20090215222326
1687 Ignore-this: c576eabc74c23b170702018fc3c122d9
1688] 
1689[test_repairer: hush pyflakes
1690warner@lothar.com**20090215222310
1691 Ignore-this: 875eb52e86077cda77efd02da77f8cfa
1692] 
1693[lossmodel.lyx: move draft paper into docs/proposed/, since it's unfinished
1694warner@lothar.com**20090215221905
1695 Ignore-this: 7f7ee204e47fd66932759c94deefe68
1696] 
1697[build a 'reliability' web page, with a simulation of file decay and repair over time
1698warner@lothar.com**20090213234234
1699 Ignore-this: 9e9623eaac7b0637bbd0071f082bd345
1700] 
1701[More lossmodel work, on repair.
1702Shawn Willden <shawn-tahoe@willden.org>**20090116025648] 
1703[Loss model work (temp1)
1704Shawn Willden <shawn@willden.org>**20090115030058] 
1705[Statistics module
1706Shawn Willden <shawn-tahoe@willden.org>**20090114021235
1707 
1708 Added a statistics module for calculating various facets of
1709 share survival statistics.
1710] 
1711[docs: relnotes-short.txt
1712zooko@zooko.com**20090215163510
1713 Ignore-this: 683649bb13499bbe0e5cea2e1716ff59
1714 linkedin.com imposed a strict limit on the number of characters I could post.  This forced me to prune and prune and edit and edit until relnotes.txt was a quarter of its former size.  Here's the short version.
1715] 
1716[TAG allmydata-tahoe-1.3.0
1717zooko@zooko.com**20090214000556
1718 Ignore-this: aa6c9a31a14a58ad2298cb7b08d3ea70
1719] 
1720Patch bundle hash:
17216422bf98b0a47e7b946934be2164e89ae0c9f6b2