1 patch for repository davidsarah@dev.allmydata.org:/home/darcs/tahoe/trunk:

Fri Jan 21 05:36:10 GMT Standard Time 2011  david-sarah@jacaranda.org
  * Refactor _auto_deps.py and __init__.py, adding more robust checking of dependency versions, and not trusting pkg_resources to get the versions right. refs #1258, #1287

New patches:

[Refactor _auto_deps.py and __init__.py, adding more robust checking of dependency versions, and not trusting pkg_resources to get the versions right. refs #1258, #1287
david-sarah@jacaranda.org**20110121053610
 Ignore-this: b36d03e725ea9eb3362417e322019ebe
] {
hunk ./src/allmydata/__init__.py 7
 community web site: U{http://tahoe-lafs.org/}
 """
 
-# We want to call require_auto_deps() before other imports, because the setuptools
-# docs claim that if a distribution is installed with --multi-version, it might not
-# be importable until after pkg_resources.require() has been called for it. We don't
-# have an example of this happening at this time. It is possible that require() isn't
-# actually needed because we set __requires__ in the generated startup script, but
-# that would be an undocumented property of the setuptools implementation.
-
-from allmydata import _auto_deps
-_auto_deps.require_auto_deps()
-
-# This is just to suppress DeprecationWarnings from nevow and twisted.
-# See http://allmydata.org/trac/tahoe/ticket/859 and
-# http://divmod.org/trac/ticket/2994 .
-import warnings
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="the sha module is deprecated; use the hashlib module instead",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="object.__new__\(\) takes no parameters",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="The popen2 module is deprecated.  Use the subprocess module.",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="the md5 module is deprecated; use hashlib instead",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="twisted.web.error.NoResource is deprecated since Twisted 9.0.  See twisted.web.resource.NoResource.",
-    append=True)
-try:
-    import nevow
-    from twisted.persisted import sob
-    from twisted.python import filepath
-    hush_pyflakes = (nevow, sob, filepath)
-    del hush_pyflakes
-finally:
-    warnings.filters.pop()
-    warnings.filters.pop()
-    warnings.filters.pop()
-    warnings.filters.pop()
-    # Don't pop the filter for the sha module warning because it is also generated
-    # by pycrypto (which we don't want to import unless needed).
-    # warnings.filters.pop()
-
-# This warning is generated by twisted, PyRex, and possibly other packages,
-# but can happen at any time, not only when they are imported. See
-# http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1129 .
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="BaseException.message has been deprecated as of Python 2.6",
-    append=True)
+class PackagingError(EnvironmentError):
+    """
+    Raised when there is an error in packaging of Tahoe-LAFS or its
+    dependencies which makes it impossible to proceed safely.
+    """
+    pass
 
 __version__ = "unknown"
 try:
hunk ./src/allmydata/__init__.py 134
     else:
         return platform.platform()
 
-def get_package_versions_from_setuptools():
-    import pkg_resources
-    return dict([(p.project_name, (p.version, p.location)) for p in pkg_resources.require(__appname__)])
 
hunk ./src/allmydata/__init__.py 135
-def package_dir(srcfile):
-    return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
+from allmydata.util import verlib
+def normalized_version(verstr):
+    return verlib.NormalizedVersion(verlib.suggest_normalized_version(verstr))
+
 
 def get_package_versions_and_locations():
hunk ./src/allmydata/__init__.py 141
-    # because there are a few dependencies that are outside setuptools's ken
-    # (Python and platform, and sqlite3 if you are on Python >= 2.5), and
-    # because setuptools might fail to find something even though import
-    # finds it:
-    import OpenSSL, allmydata, foolscap.api, nevow, platform, pycryptopp, setuptools, simplejson, twisted, zfec, zope.interface
-    pysqlitever = None
-    pysqlitefile = None
-    sqlitever = None
+    import warnings
+    from _auto_deps import package_imports, deprecation_messages, deprecation_imports
+
+    def package_dir(srcfile):
+        return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
+
+    # pkg_resources.require returns the distribution that pkg_resources attempted to put
+    # on sys.path, which can differ from the one that we actually import due to #1258,
+    # or any other bug that causes sys.path to be set up incorrectly. Therefore we
+    # must import the packages in order to check their versions and paths.
+
+    # This warning is generated by twisted, PyRex, and possibly other packages,
+    # but can happen at any time, not only when they are imported. See
+    # http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1129 .
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="BaseException.message has been deprecated as of Python 2.6",
+        append=True)
+
+    # This is to suppress various DeprecationWarnings that occur when modules are imported.
+    # See http://allmydata.org/trac/tahoe/ticket/859 and http://divmod.org/trac/ticket/2994 .
+
+    for msg in deprecation_messages:
+        warnings.filterwarnings("ignore", category=DeprecationWarning, message=msg, append=True)
     try:
hunk ./src/allmydata/__init__.py 165
-        import sqlite3
-    except ImportError:
-        try:
-            from pysqlite2 import dbapi2
-        except ImportError:
-            pass
+        for modulename in deprecation_imports:
+            try:
+                __import__(modulename)
+            except ImportError:
+                pass
+    finally:
+        for ign in deprecation_messages:
+            warnings.filters.pop()
+
+    packages = []
+
+    def get_version(module, attr):
+        return str(getattr(module, attr, 'unknown'))
+
+    for pkgname, modulename in [(__appname__, 'allmydata')] + package_imports:
+        if modulename:
+            try:
+                __import__(modulename)
+                module = sys.modules[modulename]
+            except ImportError:
+                packages.append((pkgname, (None, modulename)))
+            else:
+                if 'sqlite' in pkgname:
+                    packages.append( (pkgname,  (get_version(module, 'version'),        package_dir(module.__file__))) )
+                    packages.append( ('sqlite', (get_version(module, 'sqlite_version'), package_dir(module.__file__))) )
+                else:
+                    packages.append( (pkgname,  (get_version(module, '__version__'),    package_dir(module.__file__))) )
+        elif pkgname == 'python':
+            packages.append( (pkgname, (platform.python_version(), sys.executable)) )
+        elif pkgname == 'platform':
+            packages.append( (pkgname, (get_platform(), None)) )
+
+    return packages
+
+
+def check_requirement(req, vers_and_locs):
+    # TODO: check [] options
+    # We support only disjunctions of >= and ==
+
+    reqlist = req.split(',')
+    name = reqlist[0].split('>=')[0].split('==')[0].strip(' ').split('[')[0]
+    if name not in vers_and_locs:
+        raise PackagingError("no version info for %s" % (name,))
+    if req.strip(' ') == name:
+        return
+    (actual, location) = vers_and_locs[name]
+    if actual is None:
+        raise ImportError("could not import %r for requirement %r" % (location, req))
+    if actual == 'unknown':
+        return
+    actualver = normalized_version(actual)
+
+    for r in reqlist:
+        s = r.split('>=')
+        if len(s) == 2:
+            required = s[1].strip(' ')
+            if actualver >= normalized_version(required):
+                return  # minimum requirement met
         else:
hunk ./src/allmydata/__init__.py 224
-            pysqlitever = dbapi2.version
-            pysqlitefile = package_dir(dbapi2.__file__)
-            sqlitever = dbapi2.sqlite_version
-    else:
-        pysqlitever = sqlite3.version
-        pysqlitefile = package_dir(sqlite3.__file__)
-        sqlitever = sqlite3.sqlite_version
+            s = r.split('==')
+            if len(s) == 2:
+                required = s[1].strip(' ')
+                if actualver == normalized_version(required):
+                    return  # exact requirement met
+            else:
+                raise PackagingError("no version info or could not understand requirement %r" % (req,))
+
+    msg = ("We require %s, but could only find version %s.\n" % (req, actual))
+    if location and location != 'unknown':
+        msg += "The version we found is from %r.\n" % (location,)
+    msg += ("To resolve this problem, uninstall that version, either using your\n"
+            "operating system's package manager or by moving aside the directory.")
+    raise PackagingError(msg)
+
+
+_vers_and_locs_list = get_package_versions_and_locations()
 
hunk ./src/allmydata/__init__.py 242
-    d1 = {
-        'pyOpenSSL': (OpenSSL.__version__, package_dir(OpenSSL.__file__)),
-        __appname__: (allmydata.__version__, package_dir(allmydata.__file__)),
-        'foolscap': (foolscap.api.__version__, package_dir(foolscap.__file__)),
-        'Nevow': (nevow.__version__, package_dir(nevow.__file__)),
-        'pycryptopp': (pycryptopp.__version__, package_dir(pycryptopp.__file__)),
-        'setuptools': (setuptools.__version__, package_dir(setuptools.__file__)),
-        'simplejson': (simplejson.__version__, package_dir(simplejson.__file__)),
-        'pysqlite': (pysqlitever, pysqlitefile),
-        'sqlite': (sqlitever, 'unknown'),
-        'zope.interface': ('unknown', package_dir(zope.interface.__file__)),
-        'Twisted': (twisted.__version__, package_dir(twisted.__file__)),
-        'zfec': (zfec.__version__, package_dir(zfec.__file__)),
-        'python': (platform.python_version(), sys.executable),
-        'platform': (get_platform(), None),
-        }
+
+def cross_check_pkg_resources_versus_import():
+    """This function returns a list of errors due to any failed cross-checks."""
 
hunk ./src/allmydata/__init__.py 246
-    # But we prefer to get all the dependencies as known by setuptools:
     import pkg_resources
hunk ./src/allmydata/__init__.py 247
-    try:
-        d2 = get_package_versions_from_setuptools()
-    except pkg_resources.DistributionNotFound:
-        # See docstring in _auto_deps.require_auto_deps() to explain why it makes sense to ignore this exception.
-        pass
+    from _auto_deps import install_requires
+
+    errors = []
+    not_pkg_resourceable = set(['sqlite', 'sqlite3', 'python', 'platform', __appname__.lower()])
+    not_import_versionable = set(['zope.interface', 'mock', 'pyasn1'])
+    ignorable = set(['argparse', 'pyutil', 'zbase32'])
+
+    pkg_resources_vers_and_locs = dict([(p.project_name.lower(), (str(p.version), p.location))
+                                        for p in pkg_resources.require(install_requires)])
+
+    for name, (imp_ver, imp_loc) in _vers_and_locs_list:
+        name = name.lower()
+        if name not in not_pkg_resourceable:
+            if name not in pkg_resources_vers_and_locs:
+                errors.append("Warning: dependency %s (version %s imported from %r) was not found by pkg_resources."
+                              % (name, imp_ver, imp_loc))
+
+            pr_ver, pr_loc = pkg_resources_vers_and_locs[name]
+            try:
+                pr_normver = normalized_version(pr_ver)
+            except Exception, e:
+                errors.append("Warning: version number %s found for dependency %s by pkg_resources could not be parsed. "
+                              "The version found by import was %s from %r. "
+                              "pkg_resources thought it should be found at %r. "
+                              "The exception was %s: %s"
+                              % (pr_ver, name, imp_ver, imp_loc, pr_loc, e.__class__.name, e))
+            else:
+                if imp_ver == 'unknown':
+                    if name not in not_import_versionable:
+                        errors.append("Warning: unexpectedly could not find a version number for dependency %s imported from %r. "
+                                      "pkg_resources thought it should be version %s at %r."
+                                      % (name, imp_loc, pr_ver, pr_loc))
+                else:
+                    try:
+                        imp_normver = normalized_version(imp_ver)
+                    except Exception, e:
+                        errors.append("Warning: version number %s found for dependency %s (imported from %r) could not be parsed. "
+                                      "pkg_resources thought it should be version %s at %r. "
+                                      "The exception was %s: %s"
+                                      % (imp_ver, name, imp_loc, pr_ver, pr_loc, e.__class__.name, e))
+                    else:
+                        if pr_ver == 'unknown' or (pr_normver != imp_normver):
+                            if not os.path.normpath(os.path.realpath(pr_loc)) == os.path.normpath(os.path.realpath(imp_loc)):
+                                errors.append("Warning: dependency %s found to have version number %s (normalized to %s, from %r) "
+                                              "by pkg_resources, but version %s (normalized to %s, from %r) by import."
+                                              % (name, pr_ver, str(pr_normver), pr_loc, imp_ver, str(imp_normver), imp_loc))
+
+    imported_packages = set([p.lower() for (p, _) in _vers_and_locs_list])
+    for pr_name, (pr_ver, pr_loc) in pkg_resources_vers_and_locs.iteritems():
+        if pr_name not in imported_packages and pr_name not in ignorable:
+            errors.append("Warning: dependency %s (version %s) found by pkg_resources not found by import."
+                          % (pr_name, pr_ver))
+
+    return errors
+
+
+def get_error_string(errors):
+    from allmydata._auto_deps import install_requires
+
+    return ("\n%s\n\n"
+            "For debugging purposes, the PYTHONPATH was\n"
+            "  %r\n"
+            "install_requires was\n"
+            "  %r\n"
+            "sys.path after importing pkg_resources was\n"
+            "  %s\n"
+            % ("\n".join(errors), os.environ.get('PYTHONPATH'), install_requires, (os.pathsep+"\n  ").join(sys.path)) )
+
+def check_all_requirements():
+    """This function returns a list of errors due to any failed checks."""
+
+    from allmydata._auto_deps import install_requires
+
+    errors = []
+
+    # we require 2.4.4 on non-UCS-2, non-Redhat builds to avoid <http://www.python.org/news/security/PSF-2006-001/>
+    # we require 2.4.3 on non-UCS-2 Redhat, because 2.4.3 is common on Redhat-based distros and will have patched the above bug
+    # we require at least 2.4.2 in any case to avoid a bug in the base64 module: <http://bugs.python.org/issue1171487>
+    if sys.maxunicode == 65535:
+        if sys.version_info < (2, 4, 2) or sys.version_info[0] > 2:
+            errors.append("Tahoe-LAFS current requires Python v2.4.2 or greater "
+                          "for a UCS-2 build (but less than v3), not %r" %
+                          (sys.version_info,))
+    elif platform.platform().lower().find('redhat') >= 0:
+        if sys.version_info < (2, 4, 3) or sys.version_info[0] > 2:
+            errors.append("Tahoe-LAFS current requires Python v2.4.3 or greater "
+                          "on Redhat-based distributions (but less than v3), not %r" %
+                          (sys.version_info,))
     else:
hunk ./src/allmydata/__init__.py 336
-        d1.update(d2)
+        if sys.version_info < (2, 4, 4) or sys.version_info[0] > 2:
+            errors.append("Tahoe-LAFS current requires Python v2.4.4 or greater "
+                          "for a non-UCS-2 build (but less than v3), not %r" %
+                          (sys.version_info,))
+
+    vers_and_locs = dict(_vers_and_locs_list)
+    for requirement in install_requires:
+        try:
+            check_requirement(requirement, vers_and_locs)
+        except Exception, e:
+            errors.append("%s: %s" % (e.__class__.__name__, e))
+
+    if errors:
+        raise PackagingError(get_error_string(errors))
+
+check_all_requirements()
 
hunk ./src/allmydata/__init__.py 353
-    return d1
 
 def get_package_versions():
hunk ./src/allmydata/__init__.py 355
-    return dict([(k, v) for k, (v, l) in get_package_versions_and_locations().iteritems()])
+    return dict([(k, v) for k, (v, l) in _vers_and_locs_list])
 
 def get_package_locations():
hunk ./src/allmydata/__init__.py 358
-    return dict([(k, l) for k, (v, l) in get_package_versions_and_locations().iteritems()])
+    return dict([(k, l) for k, (v, l) in _vers_and_locs_list])
 
 def get_package_versions_string(show_paths=False):
hunk ./src/allmydata/__init__.py 361
-    vers_and_locs = get_package_versions_and_locations()
     res = []
hunk ./src/allmydata/__init__.py 362
-    for p in [__appname__, "foolscap", "pycryptopp", "zfec", "Twisted", "Nevow", "zope.interface", "python", "platform"]:
-        (ver, loc) = vers_and_locs.get(p, ('UNKNOWN', 'UNKNOWN'))
-        info = str(p) + ": " + str(ver)
-        if show_paths:
-            info = info + " (%s)" % str(loc)
-        res.append(info)
-        if vers_and_locs.has_key(p):
-            del vers_and_locs[p]
-
-    for p, (v, loc) in vers_and_locs.iteritems():
+    for p, (v, loc) in _vers_and_locs_list:
         info = str(p) + ": " + str(v)
         if show_paths:
             info = info + " (%s)" % str(loc)
hunk ./src/allmydata/__init__.py 367
         res.append(info)
-    return ', '.join(res)
+
+    output = ",\n".join(res) + "\n"
+
+    if not hasattr(sys, 'frozen'):
+        errors = cross_check_pkg_resources_versus_import()
+        if errors:
+            output += get_error_string(errors)
+
+    return output
hunk ./src/allmydata/_auto_deps.py 1
-# Note: do not import any module from Tahoe-LAFS itself in this
-# file. Also please avoid importing modules from other packages than
-# the Python Standard Library if at all possible (exception: we rely
-# on importing pkg_resources, which is provided by setuptools,
-# zetuptoolz, distribute, and perhaps in the future distutils2, for
-# the require_auto_deps() function.)
+# Note: please minimize imports in this file. In particular, do not import
+# any module from Tahoe-LAFS or its dependencies, and do not import any
+# modules at all at global level. That includes setuptools and pkg_resources.
+# It is ok to import modules from the Python Standard Library if they are
+# always available, or the import is protected by try...except ImportError.
 
hunk ./src/allmydata/_auto_deps.py 7
-install_requires=[
-                  # we require newer versions of setuptools (actually
-                  # zetuptoolz) to build, but can handle older versions to run
-                  "setuptools >= 0.6c6",
+install_requires = [
+    "zfec >= 1.1.0",
 
hunk ./src/allmydata/_auto_deps.py 10
-                  "zfec >= 1.1.0",
+    # Feisty has simplejson 1.4
+    "simplejson >= 1.4",
 
hunk ./src/allmydata/_auto_deps.py 13
-                  # Feisty has simplejson 1.4
-                  "simplejson >= 1.4",
+    "zope.interface",
 
hunk ./src/allmydata/_auto_deps.py 15
-                  "zope.interface",
-                  "Twisted >= 2.4.0",
+    "Twisted >= 2.4.0",
 
hunk ./src/allmydata/_auto_deps.py 17
-                  # foolscap < 0.5.1 had a performance bug which spent
-                  # O(N**2) CPU for transferring large mutable files
-                  # of size N.
-                  # foolscap < 0.6 is incompatible with Twisted 10.2.0.
-                  # foolscap 0.6.1 quiets a DeprecationWarning.
-                  "foolscap[secure_connections] >= 0.6.1",
-                  "Nevow >= 0.6.0",
+    # foolscap < 0.5.1 had a performance bug which spent
+    # O(N**2) CPU for transferring large mutable files
+    # of size N.
+    # foolscap < 0.6 is incompatible with Twisted 10.2.0.
+    # foolscap 0.6.1 quiets a DeprecationWarning.
+    "foolscap[secure_connections] >= 0.6.1",
 
hunk ./src/allmydata/_auto_deps.py 24
-                  # Needed for SFTP. pyasn1 is needed by twisted.conch in Twisted >= 9.0.
-                  # pycrypto 2.2 doesn't work due to https://bugs.launchpad.net/pycrypto/+bug/620253
-                  "pycrypto == 2.0.1, == 2.1, >= 2.3",
-                  "pyasn1 >= 0.0.8a",
+    "Nevow >= 0.6.0",
 
hunk ./src/allmydata/_auto_deps.py 26
-                  # http://www.voidspace.org.uk/python/mock/
-                  "mock",
+    # Needed for SFTP. pyasn1 is needed by twisted.conch in Twisted >= 9.0.
+    # pycrypto 2.2 doesn't work due to https://bugs.launchpad.net/pycrypto/+bug/620253
+    "pycrypto == 2.0.1, == 2.1.0, >= 2.3",
+    "pyasn1 >= 0.0.8a",
 
hunk ./src/allmydata/_auto_deps.py 31
-                  # Will be needed to test web apps, but not yet. See #1001.
-                  #"windmill >= 1.3",
-                  ]
+    # http://www.voidspace.org.uk/python/mock/
+    "mock",
 
hunk ./src/allmydata/_auto_deps.py 34
-import platform
-if platform.machine().lower() in ['i386', 'x86_64', 'amd64', 'x86', '']:
-    # pycryptopp v0.5.20 fixes bugs in SHA-256 and AES on x86 or amd64
-    # (from Crypto++ revisions 470, 471, 480, 492).  The '' is there
-    # in case platform.machine is broken and this is actually an x86
-    # or amd64 machine.
-    install_requires.append("pycryptopp >= 0.5.20")
-else:
-    # pycryptopp v0.5.13 had a new bundled version of Crypto++
-    # (v5.6.0) and a new bundled version of setuptools (although that
-    # shouldn't make any different to users of pycryptopp).
-    install_requires.append("pycryptopp >= 0.5.14")
+    # Will be needed to test web apps, but not yet. See #1001.
+    #"windmill >= 1.3",
+]
 
hunk ./src/allmydata/_auto_deps.py 38
+# Includes some indirect dependencies, but does not include allmydata.
+# These are in the order they should be listed by --version, etc.
+package_imports = [
+    # package name      module name
+    ('foolscap',        'foolscap'),
+    ('pycryptopp',      'pycryptopp'),
+    ('zfec',            'zfec'),
+    ('Twisted',         'twisted'),
+    ('Nevow',           'nevow'),
+    ('zope.interface',  'zope.interface'),
+    ('python',          None),
+    ('platform',        None),
+    ('pyOpenSSL',       'OpenSSL'),
+    ('simplejson',      'simplejson'),
+    ('pycrypto',        'Crypto'),
+    ('pyasn1',          'pyasn1'),
+    ('mock',            'mock'),
+]
 
hunk ./src/allmydata/_auto_deps.py 57
-# Sqlite comes built into Python >= 2.5, and is provided by the "pysqlite"
-# distribution for Python 2.4.
-import sys
-if sys.version_info < (2, 5):
-    # pysqlite v2.0.5 was shipped in Ubuntu 6.06 LTS "dapper" and Nexenta NCP 1.
-    install_requires.append("pysqlite >= 2.0.5")
+def require_more():
+    import platform, sys
 
hunk ./src/allmydata/_auto_deps.py 60
-if hasattr(sys, 'frozen'): # for py2exe
-    install_requires=[]
-del sys # clean up namespace
+    if platform.machine().lower() in ['i386', 'x86_64', 'amd64', 'x86', '']:
+        # pycryptopp v0.5.20 fixes bugs in SHA-256 and AES on x86 or amd64
+        # (from Crypto++ revisions 470, 471, 480, 492).  The '' is there
+        # in case platform.machine is broken and this is actually an x86
+        # or amd64 machine.
+        install_requires.append("pycryptopp >= 0.5.20")
+    else:
+        # pycryptopp v0.5.13 had a new bundled version of Crypto++
+        # (v5.6.0) and a new bundled version of setuptools (although that
+        # shouldn't make any difference to users of pycryptopp).
+        install_requires.append("pycryptopp >= 0.5.14")
 
hunk ./src/allmydata/_auto_deps.py 72
-def require_python_version():
-    import sys, platform
+    # Sqlite comes built into Python >= 2.5, and is provided by the "pysqlite"
+    # distribution for Python 2.4.
+    try:
+        import sqlite3
+        sqlite3 # hush pyflakes
+        package_imports.append(('sqlite3', 'sqlite3'))
+    except ImportError:
+        # pysqlite v2.0.5 was shipped in Ubuntu 6.06 LTS "dapper" and Nexenta NCP 1.
+        install_requires.append("pysqlite >= 2.0.5")
+        package_imports.append(('pysqlite', 'pysqlite.dbapi2'))
 
hunk ./src/allmydata/_auto_deps.py 83
-    # we require 2.4.4 on non-UCS-2, non-Redhat builds to avoid <http://www.python.org/news/security/PSF-2006-001/>
-    # we require 2.4.3 on non-UCS-2 Redhat, because 2.4.3 is common on Redhat-based distros and will have patched the above bug
-    # we require at least 2.4.2 in any case to avoid a bug in the base64 module: <http://bugs.python.org/issue1171487>
-    if sys.maxunicode == 65535:
-        if sys.version_info < (2, 4, 2) or sys.version_info[0] > 2:
-            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.2 or greater "
-                                      "for a UCS-2 build (but less than v3), not %r" %
-                                      (sys.version_info,))
-    elif platform.platform().lower().find('redhat') >= 0:
-        if sys.version_info < (2, 4, 3) or sys.version_info[0] > 2:
-            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.3 or greater "
-                                      "on Redhat-based distributions (but less than v3), not %r" %
-                                      (sys.version_info,))
-    else:
-        if sys.version_info < (2, 4, 4) or sys.version_info[0] > 2:
-            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.4 or greater "
-                                      "for a non-UCS-2 build (but less than v3), not %r" %
-                                      (sys.version_info,))
+    if not hasattr(sys, 'frozen'):
+        # we require newer versions of setuptools (actually
+        # zetuptoolz) to build, but can handle older versions to run
+        install_requires.append("setuptools >= 0.6c6")
+        package_imports.append(('setuptools', 'setuptools'))
+
+require_more()
 
hunk ./src/allmydata/_auto_deps.py 91
-def require_auto_deps():
-    """
-    The purpose of this function is to raise a pkg_resources exception if any of the
-    requirements can't be imported.  This is just to give earlier and more explicit error
-    messages, as opposed to waiting until the source code tries to import some module from one
-    of these packages and gets an ImportError.  This function gets called from
-    src/allmydata/__init__.py .
-    """
-    require_python_version()
+deprecation_messages = [
+    "the sha module is deprecated; use the hashlib module instead",
+    "object.__new__\(\) takes no parameters",
+    "The popen2 module is deprecated.  Use the subprocess module.",
+    "the md5 module is deprecated; use hashlib instead",
+    "twisted.web.error.NoResource is deprecated since Twisted 9.0.  See twisted.web.resource.NoResource.",
+    "the sets module is deprecated",
+]
 
hunk ./src/allmydata/_auto_deps.py 100
-    import pkg_resources
-    for requirement in install_requires:
-        try:
-            pkg_resources.require(requirement)
-        except pkg_resources.DistributionNotFound:
-            # there is no .egg-info present for this requirement, which
-            # either means that it isn't installed, or it is installed in a
-            # way that pkg_resources can't find it (but regular python
-            # might).  There are several older Linux distributions which
-            # provide our dependencies just fine, but they don't ship
-            # .egg-info files. Note that if there *is* an .egg-info file,
-            # but it shows a too-old version, then we'll get a
-            # VersionConflict error instead of DistributionNotFound.
-            pass
+deprecation_imports = [
+    'nevow',
+    'twisted.persisted.sob',
+    'twisted.python.filepath',
+    'Crypto.Hash.SHA',
+]
addfile ./src/allmydata/test/test_version.py
hunk ./src/allmydata/test/test_version.py 1
+
+from twisted.trial import unittest
+
+from allmydata import check_requirement, PackagingError
+from allmydata.util.verlib import NormalizedVersion as V, \
+                                  IrrationalVersionError, \
+                                  suggest_normalized_version as suggest
+
+
+class CheckRequirement(unittest.TestCase):
+    def test_check_requirement(self):
+        check_requirement("setuptools >= 0.6c6", {"setuptools": ("0.6", "")})
+        check_requirement("pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.1.0", "")})
+        check_requirement("pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.4.0", "")})
+
+        check_requirement("zope.interface", {"zope.interface": ("unknown", "")})
+        check_requirement("mock", {"mock": ("0.6.0", "")})
+        check_requirement("foo >= 1.0", {"foo": ("1.0", ""), "bar": ("2.0", "")})
+
+        check_requirement("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.7.0", "")})
+
+        self.failUnlessRaises(PackagingError, check_requirement,
+                              "foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.5.1", "")})
+        self.failUnlessRaises(PackagingError, check_requirement,
+                              "pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.2.0", "")})
+        self.failUnlessRaises(PackagingError, check_requirement,
+                              "foo >= 1.0", {})
+
+
+# based on https://bitbucket.org/tarek/distutilsversion/src/17df9a7d96ef/test_verlib.py
+
+class VersionTestCase(unittest.TestCase):
+    versions = ((V('1.0'), '1.0'),
+                (V('1.1'), '1.1'),
+                (V('1.2.3'), '1.2.3'),
+                (V('1.2'), '1.2'),
+                (V('1.2.3a4'), '1.2.3a4'),
+                (V('1.2c4'), '1.2c4'),
+                (V('1.2.3.4'), '1.2.3.4'),
+                (V('1.2.3.4.0b3'), '1.2.3.4b3'),
+                (V('1.2.0.0.0'), '1.2'),
+                (V('1.0.dev345'), '1.0.dev345'),
+                (V('1.0.post456.dev623'), '1.0.post456.dev623'))
+
+    def test_basic_versions(self):
+        for v, s in self.versions:
+            self.failUnlessEqual(str(v), s)
+
+    def test_from_parts(self):
+        for v, s in self.versions:
+            parts = v.parts
+            v2 = V.from_parts(*parts)
+            self.failUnlessEqual(v, v2)
+            self.failUnlessEqual(str(v), str(v2))
+
+    def test_irrational_versions(self):
+        irrational = ('1', '1.2a', '1.2.3b', '1.02', '1.2a03',
+                      '1.2a3.04', '1.2.dev.2', '1.2dev', '1.2.dev',
+                      '1.2.dev2.post2', '1.2.post2.dev3.post4')
+
+        for s in irrational:
+            self.failUnlessRaises(IrrationalVersionError, V, s)
+
+    def test_comparison(self):
+        self.failUnlessRaises(TypeError, lambda: V('1.2.0') == '1.2')
+
+        self.failUnlessEqual(V('1.2.0'), V('1.2'))
+        self.failIfEqual(V('1.2.0'), V('1.2.3'))
+        self.failUnless(V('1.2.0') < V('1.2.3'))
+        self.failUnless(V('1.0') > V('1.0b2'))
+        self.failUnless(V('1.0') > V('1.0c2') > V('1.0c1') > V('1.0b2') > V('1.0b1')
+                        > V('1.0a2') > V('1.0a1'))
+        self.failUnless(V('1.0.0') > V('1.0.0c2') > V('1.0.0c1') > V('1.0.0b2') > V('1.0.0b1')
+                        > V('1.0.0a2') > V('1.0.0a1'))
+
+        self.failUnless(V('1.0') < V('1.0.post456.dev623'))
+        self.failUnless(V('1.0.post456.dev623') < V('1.0.post456')  < V('1.0.post1234'))
+
+        self.failUnless(V('1.0a1')
+                        < V('1.0a2.dev456')
+                        < V('1.0a2')
+                        < V('1.0a2.1.dev456')  # e.g. need to do a quick post release on 1.0a2
+                        < V('1.0a2.1')
+                        < V('1.0b1.dev456')
+                        < V('1.0b2')
+                        < V('1.0c1')
+                        < V('1.0c2.dev456')
+                        < V('1.0c2')
+                        < V('1.0.dev7')
+                        < V('1.0.dev18')
+                        < V('1.0.dev456')
+                        < V('1.0.dev1234')
+                        < V('1.0')
+                        < V('1.0.post456.dev623')  # development version of a post release
+                        < V('1.0.post456'))
+
+    def test_suggest_normalized_version(self):
+        self.failUnlessEqual(suggest('1.0'), '1.0')
+        self.failUnlessEqual(suggest('1.0-alpha1'), '1.0a1')
+        self.failUnlessEqual(suggest('1.0c2'), '1.0c2')
+        self.failUnlessEqual(suggest('walla walla washington'), None)
+        self.failUnlessEqual(suggest('2.4c1'), '2.4c1')
+
+        # from setuptools
+        self.failUnlessEqual(suggest('0.4a1.r10'), '0.4a1.post10')
+        self.failUnlessEqual(suggest('0.7a1dev-r66608'), '0.7a1.dev66608')
+        self.failUnlessEqual(suggest('0.6a9.dev-r41475'), '0.6a9.dev41475')
+        self.failUnlessEqual(suggest('2.4preview1'), '2.4c1')
+        self.failUnlessEqual(suggest('2.4pre1') , '2.4c1')
+        self.failUnlessEqual(suggest('2.1-rc2'), '2.1c2')
+
+        # from pypi
+        self.failUnlessEqual(suggest('0.1dev'), '0.1.dev0')
+        self.failUnlessEqual(suggest('0.1.dev'), '0.1.dev0')
+
+        # we want to be able to parse Twisted
+        # development versions are like post releases in Twisted
+        self.failUnlessEqual(suggest('9.0.0+r2363'), '9.0.0.post2363')
+
+        # pre-releases are using markers like "pre1"
+        self.failUnlessEqual(suggest('9.0.0pre1'), '9.0.0c1')
+
+        # we want to be able to parse Tcl-TK
+        # they us "p1" "p2" for post releases
+        self.failUnlessEqual(suggest('1.4p1'), '1.4.post1')
+
+        # from darcsver
+        self.failUnlessEqual(suggest('1.8.1-r4956'), '1.8.1.post4956')
+
+        # zetuptoolz
+        self.failUnlessEqual(suggest('0.6c16dev3'), '0.6c16.dev3')
}

Context:

[src/allmydata/util/iputil.py: loosen regexps and ensure that 'LANG=en_US.UTF-8' is set in the environment, to minimize problems with localized output of IP-address-finding tools. refs #1274
david-sarah@jacaranda.org**20110120084827
 Ignore-this: da04b1d780915ecfe492b671fdc2727e
] 
[Eliminate dependencies on pywin32, even via Twisted. refs #1274
david-sarah@jacaranda.org**20110120043238
 Ignore-this: 96a2c30ea71a897472d704e905d3cb13
] 
[Makefile: consistently use TAHOE macro to run bin/tahoe. Use '$(TAHOE) debug repl' instead of $(RUNPP) -p. refs #1296
david-sarah@jacaranda.org**20110119234429
 Ignore-this: 1c339126c6cdb6cd7d60a95a2f0db0a2
] 
[Makefile: consistently use 'tahoe debug trial' to run tests. refs #1296
david-sarah@jacaranda.org**20110119233737
 Ignore-this: 4b6b5a13fcf767c23e5f983f92f2c053
] 
[setup.py: add descriptions for some of the setup commands. ref #1306
david-sarah@jacaranda.org**20110119233305
 Ignore-this: 8759eb5c3ee4b717bba5580622d76c6b
] 
[setup.py: create bin/tahoe.pyscript on Unix as well as Windows for consistency, and to reduce conditional code. ref #1306
david-sarah@jacaranda.org**20110119233145
 Ignore-this: d1a7e66b3a2244fb4523ab3ef4057e5f
] 
[src/allmydata/test/test_runner.py: add test_import_from_repl, which checks that we are running the right code in a bin/tahoe subprocess. refs #1258
david-sarah@jacaranda.org**20110119082145
 Ignore-this: c53a76827b47446df9e7b0128a2cb2c5
] 
[docs/frontends/CLI.rst, src/allmydata/test/trialtest.py: add trailing newlines. refs #1296
david-sarah@jacaranda.org**20110119081955
 Ignore-this: 1d19fad753ff17febf9b99bb2f5b7df7
] 
[Eliminate direct dependencies of Tahoe-LAFS on pywin32 (rebased to trunk). refs #1274
david-sarah@jacaranda.org**20110119075911
 Ignore-this: 8f31d1188daa382ec694908a68a19194
] 
[trivial: add comment in scripts/debug.py about trial option parsing. refs #1296
david-sarah@jacaranda.org**20110119060808
 Ignore-this: 3cda9b574d1fbc1cac683ed31c826051
] 
[Update foolscap requirement to >= 0.6.1. fixes #1329
david-sarah@jacaranda.org**20110119060639
 Ignore-this: 47908e13d1c79e74b9ebb9df934b3cf1
] 
[Add support to bin/tahoe for invoking a runner command prefixed with @, with the Tahoe libraries on the PYTHONPATH. This is documented in 'tahoe debug --help'.
david-sarah@jacaranda.org**20110119051137
 Ignore-this: 65fd13a23670aea3825a706f45a7019f
] 
[bin/tahoe-script.template, src/windows/fixups.py: simplify the method of stripping initial arguments in sys.argv on Windows. This helps with bb-freeze and running tahoe via 'coverage'. Also includes some wording changes and minor refactoring of bin/tahoe-script.template. refs #585, #1303
david-sarah@jacaranda.org**20110119045324
 Ignore-this: 756e83c5eae7dabac31290b98a0e5a99
] 
[Change misc/build_helpers/test-with-fake-pkg to use 'setup.py trial'. refs #1296
david-sarah@jacaranda.org**20110119042401
 Ignore-this: e1518b6f43becf47d5a956bb710a9dcb
] 
[Makefile: update 'make clean' to delete the setuptools_trial egg(s).
david-sarah@jacaranda.org**20110119025053
 Ignore-this: ec373228f3a169c7070633e3b89ec1d
] 
[Change 'setup.py trial' and 'setup.py test' to use 'bin/tahoe debug trial'. refs #1296
david-sarah@jacaranda.org**20110119024532
 Ignore-this: 43df1a50435c794cfa60ecca71a46b10
] 
[src/allmydata/test/test_cli.py: add test for 'tahoe debug trial' options help. refs #1296
david-sarah@jacaranda.org**20110119024224
 Ignore-this: e9f7a67724b60c11a34efbce9a83a5cb
] 
[Makefile: update 'make clean' to avoid deleting the setuptools_darcs egg.
david-sarah@jacaranda.org**20110119021958
 Ignore-this: 908673ddd30ab88db5af8c8d80a74eb1
] 
[Add src/allmydata/test/trialtest.py needed by tests for 'tahoe debug trial'. refs #1296
david-sarah@jacaranda.org**20110119020239
 Ignore-this: 58d468dbd869c2e6c85552710ed47ffe
] 
[Tests for 'tahoe debug trial' (rebased and fixed to work with Twisted 10.2). refs #1296
david-sarah@jacaranda.org**20110119013859
 Ignore-this: bb2ea70e5c3c841713ae38744b80980f
] 
[Documentation for 'tahoe debug trial' (rebased for trunk). refs #1296
david-sarah@jacaranda.org**20110118205729
 Ignore-this: 3a4a4c2d23864851cb24c32a5b7962b4
] 
[Make 'mock' a run-time rather than setup-time dependency. This is necessary in order for 'tahoe debug trial' to work. refs #1296
david-sarah@jacaranda.org**20110118205114
 Ignore-this: 256c4fcd259eda02dd86ed163afc6497
] 
[src/allmydata/scripts/debug.py: add 'tahoe debug trial' command (rebased for trunk). refs #1296
david-sarah@jacaranda.org**20110118204659
 Ignore-this: 19e5f96d15c14625d5969ca4ae10a3cc
] 
[Remove setuptools_trial egg.
david-sarah@jacaranda.org**20110110063306
 Ignore-this: 329f5062db0c7914464c547a3957c596
] 
[src/allmydata/webish.py: clean-ups and correction to a comment. Also change an open and write to use fileutil.write. See ref #1286 comment 13.
david-sarah@jacaranda.org**20110117233152
 Ignore-this: c4aa2f4286ad8a9fba9827d428f7fbe5
] 
[setup: load the setuptools_darcs-1.2.12.egg that is bundled in the root of the source tree at setup.py time, and setup_require it. This is in order to make sure that its 'find all package data' plugin works to inform setuptools of all files which are under revision control, so that setuptools can include them in a distribution. By the way, this is ugly and horrible. refs #1054
david-sarah@jacaranda.org**20110118065445
 Ignore-this: b4b9d3798a9beb9c44943daf2722a51
] 
[setup: bundle a copy of setuptools_darcs-1.2.12
zooko@zooko.com**20110118062521
 Ignore-this: 47e240417e0ff57a66d2f02f416a78fe
 This is to work-around https://bitbucket.org/tarek/distribute/issue/55/revision-control-plugin-automatically-installed-as-a-build-dependency-is-not-present-when-another-build-dependency-is-being . refs #1054.
] 
[NEWS: default reserved_space for new storage nodes is 1 GiB. refs #1208
david-sarah@jacaranda.org**20110117235930
 Ignore-this: 81c898890f51400b7229b4b6de69eb30
] 
['tahoe debug catalog-shares': sort SIs and shnums
Brian Warner <warner@lothar.com>**20110117095932
 Ignore-this: f2c60da422178dfba6d03ff4957cf80c
 
 Without this, SIs or shnums could be emitted in random order, depending upon
 what the filesystem happens to return.
] 
[CLI: tests for ref #1305 (v2, remove spurious extra arg to create-alias in test)
david-sarah@jacaranda.org**20110114040327
 Ignore-this: 770b7117e66b04ced293b7b740b4a27f
] 
[CLI: make 'tahoe create-alias' and 'tahoe add-alias' accept a trailing colon on the new alias name (v2, minor change not to rely on implicit Unicode conversion). Includes doc changes and news; tests in a separate patch. fixes #1305
david-sarah@jacaranda.org**20110114034414
 Ignore-this: 97e8e88d8b0f7c628b77db3adb67fa1b
] 
[Improve 'tahoe ln' help text. Patch by David-Sarah. Closes #1230.
Brian Warner <warner@lothar.com>**20110117081421
 Ignore-this: ae0ab1525fd39c95500535d6d015e706
] 
[Tolerate Twisted-10.2's endpoints, patch by David-Sarah. Closes #1286.
Brian Warner <warner@lothar.com>**20110117074751
 Ignore-this: 8875749e4cab0e444a8452e290647bb6
 
 The service generated by strports.service() changed in 10.2, and the ugly
 private-attribute-reading hack we used to glean a kernel-allocated port
 number (e.g. when using "tcp:0", especially during unit tests) broke, causing
 Tahoe to be completely unusable with Twisted-10.2 . The new ugly
 private-attribute-reading hack starts by figuring out what sort of service
 was generated, then reads different attributes accordingly.
 
 This also hushes a warning when using schemeless strports strings like "0" or
 "3456", by quietly prepending a "tcp:" scheme, since 10.2 complains about
 those. It also adds getURL() and getPortnum() accessors to the "webish"
 service, rather than having unit tests dig through _url and _portnum and such
 to find out what they are.
] 
[debian/control: add python-twisted-conch to dependencies. Closes #1095.
Brian Warner <warner@lothar.com>**20110117071206
 Ignore-this: 74714eeb8bd324d6124824f119468ab5
] 
[Test changes to take account of ref #1311.
david-sarah@jacaranda.org**20110117060540
 Ignore-this: d787405b00a05d98abb34e5133a88b36
] 
[create_node.py: add comments to default tahoe.cfg to clarify the meaning of each section. fixes #1311
david-sarah@jacaranda.org**20110117052419
 Ignore-this: a2b0bba6b347bb0b0247782ee9ea9419
] 
[Undo the temporary hack to check the foolscap version. refs #1246
david-sarah@jacaranda.org**20110117052042
 Ignore-this: c58a8a5b91355a15d02b60c20a44bbd9
] 
[misc/build_helpers/run_trial.py: fix pyflakes warning.
david-sarah@jacaranda.org**20110115080456
 Ignore-this: 95760a442fc397526a5d921510ec3843
] 
[Set "reserved_space=1G" in newly-created storage nodes. Closes #1208.
Brian Warner <warner@lothar.com>**20110116205822
 Ignore-this: 2aac3dbb46e181ce7ae5e0af07bbb3bb
] 
[Temporary hack to investigate whether we are getting the right version of foolscap on trunk. refs #1258
david-sarah@jacaranda.org**20110116044959
 Ignore-this: 4760970f9235dde07472ca980c24f75b
] 
[Makefile: allow tarball upload when either BB_BRANCH=='trunk' or BB_BRANCH==''.
david-sarah@jacaranda.org**20110115212211
 Ignore-this: 358822b25e69bfe9651a561ec387ca7a
] 
[misc/build_helpers/test-with-fake-dists.py: clean up directories and files only if they exist.
david-sarah@jacaranda.org**20110115053011
 Ignore-this: 7aa8fec370e12c62d9b56afcd55d17f
] 
[misc/build_helpers/test-with-fake-dists.py: wrong arguments in comment.
david-sarah@jacaranda.org**20110115045325
 Ignore-this: 89322306ed4fb478af4988675fd4c968
] 
[Attempt to fix test-with-fake-dist build step.
david-sarah@jacaranda.org**20110115022651
 Ignore-this: 9d7195dca59b79f93a5f527b1ae9e79e
] 
[bin/tahoe-script.template: improve the error message if we end up running under Python 3. refs #1302
david-sarah@jacaranda.org**20110112211628
 Ignore-this: ee78f8e4bbd197e620cb0cc6b995ac46
] 
[Makefile: Fix uploading of tarballs on trunk builds.
david-sarah@jacaranda.org**20110109065851
 Ignore-this: 864b06e39103f46dbb6ccb74e1e333d3
] 
[docs/frontends/CLI.rst: fix the rst syntax to be as actually intended :-)
david-sarah@jacaranda.org**20110109014057
 Ignore-this: c11331670ba89d8601ba3782ffc4f32c
] 
[docs/frontends/CLI.rst: really fix rst syntax error this time.
david-sarah@jacaranda.org**20110109013914
 Ignore-this: 59550154c9ab41488ddfdee8938d7bda
] 
[docs/frontends/CLI.rst: fix rst syntax error.
david-sarah@jacaranda.org**20110109010943
 Ignore-this: 427444f5572115059c75fa1bd8371d51
] 
[docs/frontends/CLI.rst: discuss commandline/output quoting issues and wildcards. refs #1135
david-sarah@jacaranda.org**20110109010119
 Ignore-this: 533938d89be878b404a8540aebdf68ad
] 
[setup.py: add Python 2.7 trove classifier.
david-sarah@jacaranda.org**20110108211212
 Ignore-this: b479c0a1adf9b7a2d1fdc54abc6582e6
] 
[docs/FTP-and-SFTP.rst: document issue in ref #1297. Remove known issue #1045 which is fixed. Also some cosmetic changes.
david-sarah@jacaranda.org**20110108061038
 Ignore-this: 8d9aa2e33f1054545f7bed47bf0e647d
] 
[misc/build_helpers/show-tool-versions.py: remove attempts to show stdout.encoding and stderr.encoding that always printed None due to redirection. Also remove code to show os.path.supports_unicode_filenames which is not useful. refs #1251
david-sarah@jacaranda.org**20110103015144
 Ignore-this: 45e11431f7e2e0cebcb58e1841485cf8
] 
[NEWS: 'top' for node processes, WUI formatting, removal of GUI apps, documentation updates, foolscap dependency. refs #174, #1219, #1225
david-sarah@jacaranda.org**20110106005727
 Ignore-this: f61ac58b4d10e635feb6f7391b1b48fe
] 
[Makefile: update 'clean' target for files in bin/
david-sarah@jacaranda.org**20110103052738
 Ignore-this: 2bdbc4a50e13e508b66d0f65718c79b2
] 
[docs: update performance.rst to describe the difference between already-uploaded and not-already-uploaded, to parameterize segment size, and to use "~A" to mean "approximately A"
zooko@zooko.com**20110104065455
 Ignore-this: 8df0d79a062ee19854c0211bd202f606
] 
[bin/tahoe-script.template: On non-Windows, invoke support/bin/tahoe directly as a script (rather than via python), so that 'top' for example will show it as 'tahoe'. On Windows, simplify some code that set argv[0], which is never used. fixes #174
david-sarah@jacaranda.org**20101127232650
 Ignore-this: 42a86f3eecfdc1ea7b76a7cc68626898
] 
[test_runner: avoid unnecessary use of non-ASCII.
david-sarah@jacaranda.org**20110101100101
 Ignore-this: e2ff40dce6bb3b021306f2913d4e75df
] 
[docs/quickstart.html: fix redundant, badly nested tag. refs #1284
david-sarah@jacaranda.org**20110102175159
 Ignore-this: 2ae9cc0b47d2e87b9eb64a0f517c4eef
] 
[docs/quickstart.html: information about 'troublesome dependencies' and 'verified systems' de-emphasized by smaller italic font. Re-wrap so that the HTML source is readable (just about) as text. Minor wording tweaks. Improve organization by adding 'Windows Caveats' subsection. fixes #1284
david-sarah@jacaranda.org**20110102174212
 Ignore-this: e9dc57983974478200856651c5318fee
] 
[NEWS: update entry for removal of Mac and Windows apps. refs #1282
david-sarah@jacaranda.org**20101226042245
 Ignore-this: c8099bc6e8235718d042c9a13c1e2425
] 
[Move dependency imports from windows/depends.py (which has gone away) into src/allmydata/windows/tahoesvc.py. Also fix a pyflakes warning, and change the service display name from 'Allmydata Tahoe Node' to 'Tahoe-LAFS node'. refs #1282
david-sarah@jacaranda.org**20101226042100
 Ignore-this: ee45f324934e1251380206dbee6346d0
] 
[Remove unmaintained Windows GUI app, except for windows/tahoesvc.py which is moved to src/allmydata/windows. refs #1282
david-sarah@jacaranda.org**20101226040237
 Ignore-this: cae37b6622a7dd5940acc7d3e6a98b90
] 
[Remove the Makefile targets relating to the Mac GUI app. refs #1282
david-sarah@jacaranda.org**20101226025859
 Ignore-this: 75303be783974b41138744ec62b07965
] 
[NEWS: remove unmaintained Mac GUI app. refs #1282
david-sarah@jacaranda.org**20101226020858
 Ignore-this: 40474a07f4a550b48563d35350be7ab5
] 
[Remove unmaintained Mac GUI app. fixes #1282
david-sarah@jacaranda.org**20101226020508
 Ignore-this: b3613bf1abfd284d542bf7c753ec557a
] 
[Remove src/allmydata/util/find_exe.py which is no longer used. fixes #1150
david-sarah@jacaranda.org**20101226023206
 Ignore-this: 7436c9b53bf210aed34a1a973cd9cace
] 
[status_web_pages_review.darcs.patch 
freestorm77@gmail.com**20110102034214
 Ignore-this: 29f1ecb36177f10f3f846b3d56b313b2
 
 I make some changes on status web pages
 
 status.xhtml:
 - Delete unused webform_css link
 - Align tables on the left
 
 tahoe-css:
 - Do some minor changes on code synthax
 - changes table.status-download-events style to look like other tables
 
 status.py:
 - Align table on the left
 - Changes table header
 - Add heading tags
 - Modify google api graph: add image border, calculate height to feet data
 
 signed-off-by: zooko@zooko.com
 fixes #1219
] 
[test_storage.py: fix a pyflakes unused import warning.
david-sarah@jacaranda.org**20101231220756
 Ignore-this: df08231540cb7dff9d2b038e47ab30ee
] 
[test_storage.py: leave at least 512 MiB free when running test_large_share. refs #1195
david-sarah@jacaranda.org**20101231203215
 Ignore-this: b2144c0341c3452b5d4ba219e284ea0e
] 
[storage: use fileutil's version of get_disk_stats() and get_available_space(), use mockery/fakery in tests, enable large share test on platforms with sparse files and if > 4 GiB of disk space is currently available
zooko@zooko.com**20100910173629
 Ignore-this: 1304f1164c661de6d5304f993eb9b27b
] 
[fileutil: copy in the get_disk_stats() and get_available_space() functions from storage/server.py
zooko@zooko.com**20100910173520
 Ignore-this: 8b15569715f710f4fc5092f7ca109253
] 
[Update foolscap version requirement to 0.6.0, to address http://foolscap.lothar.com/trac/ticket/167
david-sarah@jacaranda.org**20101231060039
 Ignore-this: 98d2b8086a1a500b9f4565bca5a3810
] 
[docs/webapi.rst: typos.
david-sarah@jacaranda.org**20101230034422
 Ignore-this: d1f5166d72cc711f7e0d9981eac9105e
] 
[docs/webapi.rst: capitalization, formatting of section on URL character encoding, and a correction about Internet Explorer.
david-sarah@jacaranda.org**20101230034049
 Ignore-this: b3b9819d2fb264b4cdc5c8afd4e8c48d
] 
[docs: corrections and clarifications.
david-sarah@jacaranda.org**20101227051056
 Ignore-this: e33202858c7644c58f3f924b164294b6
] 
[docs: more formatting cleanups and corrections. Spell webapi and wapi as web-API.
david-sarah@jacaranda.org**20101227050533
 Ignore-this: 18b23cbfb780df585d8a722a1ec63e94
] 
[docs/debian.rst: bring description of building dependencies from source up-to-date, and change hostname from allmydata.com to tahoe-lafs.org.
david-sarah@jacaranda.org**20101212222912
 Ignore-this: f38462afc88b4475195610385a28391c
] 
[docs/architecture.rst: correct rst syntax.
david-sarah@jacaranda.org**20101212202003
 Ignore-this: 3fbe12feb28bec6f1c63aedbc79aad21
] 
[docs/architecture.rst: formatting.
david-sarah@jacaranda.org**20101212201719
 Ignore-this: 305fa5dfc2939355eaf6d0d2161eb1ff
] 
[docs: linkification, wording improvements.
david-sarah@jacaranda.org**20101212201234
 Ignore-this: 4e67287f527a8bc728cfbd93255d2aae
] 
[docs: formatting.
david-sarah@jacaranda.org**20101212201115
 Ignore-this: 2e0ed394ac7726651d3a4f2c4b0d3798
] 
[docs/configuration.rst: more formatting tweaks; which -> that.
david-sarah@jacaranda.org**20101212195522
 Ignore-this: a7becb7021854ca5a90edd892b36fdd7
] 
[docs/configuration.rst: more changes to formatting.
david-sarah@jacaranda.org**20101212194511
 Ignore-this: 491aac33e5f5268d224359f1447d10be
] 
[docs/configuration.rst: changes to formatting (mainly putting commands and filenames in monospace).
david-sarah@jacaranda.org**20101212181828
 Ignore-this: 8a1480e2d5f43bee678476424615b50f
] 
[scripts/backupdb.py: more accurate comment about path field.
david-sarah@jacaranda.org**20101212170320
 Ignore-this: 50e47a2228a85207bbcd188a78a0d4e6
] 
[scripts/cli.py: fix missing 'put' in usage example for 'tahoe put'.
david-sarah@jacaranda.org**20101212170207
 Ignore-this: 2cbadf066fff611fc03d3c0ff97ce6ec
] 
[docs/frontends/CLI.rst: changes to formatting (mainly putting commands and filenames in monospace), and to command syntax to reflect that DIRCAP/... is accepted. Clarify the syntax of 'tahoe put' and other minor corrections. Tahoe -> Tahoe-LAFS.
david-sarah@jacaranda.org**20101212165800
 Ignore-this: a123ef6b564aa8624d1e79c97068ea12
] 
[docs/frontends/CLI.rst: Unicode arguments to 'tahoe' work on Windows as of v1.7.1.
david-sarah@jacaranda.org**20101212063740
 Ignore-this: 3977a99dfa86ac33a44171deaf43aaab
] 
[docs/known_issues.rst: fix title and linkify another URL. refs #1225
david-sarah@jacaranda.org**20101212062817
 Ignore-this: cc91287f7fb51c23440b3d2fe79c449c
] 
[docs/known_issues.rst: fix an external link. refs #1225
david-sarah@jacaranda.org**20101212062435
 Ignore-this: b8cbf12f353131756c358965c48060ec
] 
[Fix a link from uri.rst to dirnodes.rst. refs #1225
david-sarah@jacaranda.org**20101212054502
 Ignore-this: af6205299f5c9a33229cab259c00f9d5
] 
[Fix a link from webapi.rst to FTP-and-SFTP.rst. refs #1225
david-sarah@jacaranda.org**20101212053435
 Ignore-this: 2b9f88678c3447ea860d6b61e8799858
] 
[More specific hyperlink to architecture.rst from helper.rst. refs #1225
david-sarah@jacaranda.org**20101212052607
 Ignore-this: 50424c768fca481252fabf58424852dc
] 
[Update hyperlinks between docs, and linkify some external references. refs #1225
david-sarah@jacaranda.org**20101212051459
 Ignore-this: cd43a4c3d3de1f832abfa88d5fc4ace1
] 
[docs/specifications/dirnodes.rst: fix references to mutable.rst. refs #1225
david-sarah@jacaranda.org**20101212012720
 Ignore-this: 6819b4b4e06e947ee48b365e840db37d
] 
[docs/specifications/mutable.rst: correct the magic string for v1 mutable containers. refs #1225
david-sarah@jacaranda.org**20101212011400
 Ignore-this: 99a5fcdd40cef83dbb08f323f6cdaaca
] 
[Move .txt files in docs/frontends and docs/specifications to .rst. refs #1225
david-sarah@jacaranda.org**20101212010251
 Ignore-this: 8796d35d928370f7dc6ad2dafdc1c0fe
] 
[Convert docs/frontends and docs/specifications to reStructuredText format (not including file moves).
david-sarah@jacaranda.org**20101212004632
 Ignore-this: e3ceb2d832d73875abe48624ddbb5622
] 
[scripts/cli.py: remove the disclaimer in the help for 'tahoe cp' that it does not handle non-ASCII filenames well. (At least, we intend to handle them.)
david-sarah@jacaranda.org**20101130002145
 Ignore-this: 94c003efaa20b9eb4a83503d79844ca
] 
[relnotes.txt: fifth -> sixth labor-of-love release
zooko@zooko.com**20101129045647
 Ignore-this: 21c245015268b38916e3a138d256c09d
] 
[Makefile: BB_BRANCH is set to the empty string for trunk, not the string 'trunk'.
david-sarah@jacaranda.org**20101128233512
 Ignore-this: 5a7ef8eb10475636d21b91e25b56c369
] 
[relnotes.txt: eleventh -> twelfth release.
david-sarah@jacaranda.org**20101128223321
 Ignore-this: 1e26410156a665271c1170803dea2c0d
] 
[relnotes.tst: point to known_issues.rst, not known_issues.txt.
david-sarah@jacaranda.org**20101128222918
 Ignore-this: 60194eb4544cac446fe4f60b3e34b887
] 
[quickstart.html: fix link to point to allmydata-tahoe-1.8.1.zip.
david-sarah@jacaranda.org**20101128221728
 Ignore-this: 7b3ee86f8256aa12f5d862f689f3ee29
] 
[TAG allmydata-tahoe-1.8.1
david-sarah@jacaranda.org**20101128212336
 Ignore-this: 9c18bdeaef4822f590d2a0d879e00621
] 
Patch bundle hash:
2a5436643847f4294061f1182d078ec52424df11
