diff --git a/.circleci/populate-wheelhouse.sh b/.circleci/populate-wheelhouse.sh index 80b684eba..75afb6f6f 100755 --- a/.circleci/populate-wheelhouse.sh +++ b/.circleci/populate-wheelhouse.sh @@ -40,7 +40,7 @@ export PIP_FIND_LINKS="file://${WHEELHOUSE_PATH}" "${PIP}" \ wheel \ --wheel-dir "${WHEELHOUSE_PATH}" \ - "${PROJECT_ROOT}"[test,tor,i2p] \ + "${PROJECT_ROOT}"[test] \ ${BASIC_DEPS} \ ${TEST_DEPS} \ ${REPORTING_DEPS} diff --git a/docs/INSTALL.rst b/docs/INSTALL.rst index f85d5e124..5f9d72d1d 100644 --- a/docs/INSTALL.rst +++ b/docs/INSTALL.rst @@ -193,6 +193,17 @@ You can also install directly from the source tarball URL:: tahoe-lafs: 1.13.0 ... +Extras +------ + +Tahoe-LAFS provides some functionality only when explicitly requested at installation time. +It does this using the "extras" feature of setuptools. +You can request these extra features when running the ``pip install`` command like this:: + + % venv/bin/pip install tahoe-lafs[tor] + +This example enables support for listening and connecting using Tor. +The Tahoe-LAFS documentation for specific features which require an explicit install-time step will mention the "extra" that must be requested. Hacking On Tahoe-LAFS --------------------- diff --git a/newsfragments/3240.minor b/newsfragments/3240.minor new file mode 100644 index 000000000..e69de29bb diff --git a/setup.py b/setup.py index 357b9cd41..f3b837d1d 100644 --- a/setup.py +++ b/setup.py @@ -75,12 +75,21 @@ install_requires = [ # leftover timers) # * Twisted-16.4.0 introduces `python -m twisted.trial` which is needed # for coverage testing - # * Twisted 16.6.0 drops the undesirable gmpy dependency from the conch # extra, letting us use that extra instead of trying to duplicate its # dependencies here. Twisted[conch] >18.7 introduces a dependency on # bcrypt. It is nice to avoid that if the user ends up with an older # version of Twisted. That's hard to express except by using the extra. + # + # In a perfect world, Twisted[conch] would be a dependency of an "sftp" + # extra. However, pip fails to resolve the dependencies all + # dependencies when asked for Twisted[tls] *and* Twisted[conch]. + # Specifically, "Twisted[conch]" (as the later requirement) is ignored. + # If there were an Tahoe-LAFS sftp extra that dependended on + # Twisted[conch] and install_requires only included Twisted[tls] then + # `pip install tahoe-lafs[sftp]` would not install requirements + # specified by Twisted[conch]. Since this would be the *whole point* of + # an sftp extra in Tahoe-LAFS, there is no point in having one. "Twisted[tls,conch] >= 16.6.0", # We need Nevow >= 0.11.1 which can be installed using pip. @@ -108,6 +117,18 @@ setup_requires = [ 'setuptools >= 28.8.0', # for PEP-440 style versions ] +tor_requires = [ + # This is exactly what `foolscap[tor]` means but pip resolves the pair of + # dependencies "foolscap[i2p] foolscap[tor]" to "foolscap[i2p]" so we lose + # this if we don't declare it ourselves! + "txtorcon >= 0.17.0", +] + +i2p_requires = [ + # See the comment in tor_requires. + "txi2p >= 0.3.2", +] + if len(sys.argv) > 1 and sys.argv[1] == '--fakedependency': del sys.argv[1] install_requires += ["fakedependency >= 1.0.0"] @@ -330,10 +351,6 @@ setup(name="tahoe-lafs", # also set in __init__.py "coverage", "mock", "tox", - "foolscap[tor] >= 0.12.5", - "txtorcon >= 0.17.0", # in case pip's resolver doesn't work - "foolscap[i2p] >= 0.12.6", - "txi2p >= 0.3.2", # in case pip's resolver doesn't work "pytest", "pytest-twisted", "hypothesis >= 3.6.1", @@ -341,15 +358,9 @@ setup(name="tahoe-lafs", # also set in __init__.py "towncrier", "testtools", "fixtures", - ], - "tor": [ - "foolscap[tor] >= 0.12.5", - "txtorcon >= 0.17.0", # in case pip's resolver doesn't work - ], - "i2p": [ - "foolscap[i2p] >= 0.12.6", - "txi2p >= 0.3.2", # in case pip's resolver doesn't work - ], + ] + tor_requires + i2p_requires, + "tor": tor_requires, + "i2p": i2p_requires, }, package_data={"allmydata.web": ["*.xhtml", "static/*.js", "static/*.png", "static/*.css", diff --git a/src/allmydata/test/test_sftp.py b/src/allmydata/test/test_sftp.py index 06b6d1d7a..b6f1fbc8a 100644 --- a/src/allmydata/test/test_sftp.py +++ b/src/allmydata/test/test_sftp.py @@ -12,18 +12,15 @@ from allmydata.util import deferredutil conch_interfaces = None sftp = None sftpd = None -have_pycrypto = False -try: - from Crypto import Util - Util # hush pyflakes - have_pycrypto = True -except ImportError: - pass -if have_pycrypto: +try: from twisted.conch import interfaces as conch_interfaces from twisted.conch.ssh import filetransfer as sftp from allmydata.frontends import sftpd +except ImportError as e: + conch_unavailable_reason = e +else: + conch_unavailable_reason = None from allmydata.interfaces import IDirectoryNode, ExistingChildError, NoSuchChildError from allmydata.mutable.common import NotWriteableError @@ -38,8 +35,10 @@ from allmydata.test.common_util import ReallyEqualMixin class Handler(GridTestMixin, ShouldFailMixin, ReallyEqualMixin, unittest.TestCase): """This is a no-network unit test of the SFTPUserHandler and the abstractions it uses.""" - if not have_pycrypto: - skip = "SFTP support requires pycrypto, which is not installed" + if conch_unavailable_reason: + skip = "SFTP support requires Twisted Conch which is not available: {}".format( + conch_unavailable_reason, + ) def shouldFailWithSFTPError(self, expected_code, which, callable, *args, **kwargs): assert isinstance(expected_code, int), repr(expected_code)