-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from dave-shawley/add-dist-support
Remove distribution directories.
- Loading branch information
Showing
7 changed files
with
277 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
Changelog | ||
========= | ||
|
||
* Next Release | ||
* 0.0.1 | ||
|
||
- Create something amazing | ||
- Support removal of distribution directories. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
-r test-requirements.txt | ||
detox>=0.9,<1 | ||
flake8>=2.2,<3 | ||
pyflakes>=0.8,<1 | ||
sphinx>=1.2,<2 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,88 @@ | ||
version_info = (0, 0, 0) | ||
from distutils import log | ||
from distutils.command.clean import clean as _CleanCommand | ||
import shutil | ||
|
||
|
||
version_info = (0, 0, 1) | ||
__version__ = '.'.join(str(v) for v in version_info) | ||
|
||
|
||
class CleanCommand(_CleanCommand): | ||
""" | ||
Extend the clean command to do additional house keeping. | ||
The traditional distutils clean command removes the by-products of | ||
compiling extension code. This class extends it to remove the | ||
similar by-products generated by producing a Python distribution. | ||
Most notably, it will remove .egg/.egg-info directories, the | ||
generated distribution, those pesky *__pycache__* directories, | ||
and even the virtual environment that it is running in. | ||
The level of cleanliness is controlled by command-line options as | ||
you might expect. The targets that are removed are influenced by | ||
the commands that created them. For example, if you set a custom | ||
distribution directory using the ``--dist-dir`` option or the | ||
matching snippet in *setup.cfg*, then this extension will honor | ||
that setting. It even goes as far as to detect the virtual | ||
environment directory based on environment variables. | ||
This all sounds a little dangerous... there is little to worry | ||
about though. This command only removes what it is configured to | ||
remove which is nothing by default. It also honors the | ||
``--dry-run`` global option so that there should be no question | ||
what it is going to remove. | ||
""" | ||
|
||
# See _set_options for `user_options` | ||
|
||
def __init__(self, *args, **kwargs): | ||
_CleanCommand.__init__(self, *args, **kwargs) | ||
self.dist = None | ||
|
||
def initialize_options(self): | ||
_CleanCommand.initialize_options(self) | ||
self.dist = False | ||
|
||
def run(self): | ||
_CleanCommand.run(self) | ||
if not self.dist: | ||
return | ||
|
||
dist_dirs = set() | ||
for cmd_name in self.distribution.commands: | ||
if 'dist' in cmd_name: | ||
command = self.distribution.get_command_obj(cmd_name) | ||
command.ensure_finalized() | ||
if getattr(command, 'dist_dir', None): | ||
dist_dirs.add(command.dist_dir) | ||
|
||
for dir_name in dist_dirs: | ||
self.announce('removing {0}'.format(dir_name), level=log.DEBUG) | ||
shutil.rmtree(dir_name, ignore_errors=True) | ||
|
||
|
||
def _set_options(): | ||
""" | ||
Set the options for CleanCommand. | ||
There are a number of reasons that this has to be done in an | ||
external function instead of inline in the class. First of all, | ||
the setuptools machinery really wants the options to be defined | ||
in a class attribute - otherwise, the help command doesn't work | ||
so we need a class attribute. However, we are extending an | ||
existing command and do not want to "monkey patch" over it so | ||
we need to define a *new* class attribute with the same name | ||
that contains a copy of the base class value. This could be | ||
accomplished using some magic in ``__new__`` but I would much | ||
rather set the class attribute externally... it's just cleaner. | ||
""" | ||
CleanCommand.user_options = _CleanCommand.user_options[:] | ||
CleanCommand.user_options.extend([ | ||
('dist', 'd', 'remove distribution directory'), | ||
]) | ||
CleanCommand.boolean_options = _CleanCommand.boolean_options[:] | ||
CleanCommand.boolean_options.append('dist') | ||
|
||
_set_options() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
from distutils import core, dist | ||
from distutils.command import clean | ||
import atexit | ||
import os.path | ||
import shutil | ||
import sys | ||
import tempfile | ||
|
||
if sys.version_info >= (2, 7): | ||
import unittest | ||
else: # noinspection PyPackageRequirements,PyUnresolvedReferences | ||
import unittest2 as unittest | ||
|
||
from setupext import janitor | ||
|
||
|
||
def run_setup(*command_line): | ||
""" | ||
Run the setup command with `command_line`. | ||
:param command_line: the command line arguments to pass | ||
as the simulated command line | ||
This function runs :func:`distutils.core.setup` after it | ||
configures an environment that mimics passing the specified | ||
command line arguments. The ``distutils`` internals are | ||
replaced with a :class:`~distutils.dist.Distribution` | ||
instance that will only execute the clean command. Other | ||
commands can be passed freely to simulate command line usage | ||
patterns. | ||
""" | ||
class FakeDistribution(dist.Distribution): | ||
|
||
def __init__(self, *args, **kwargs): | ||
"""Enable verbose output to make tests easier to debug.""" | ||
dist.Distribution.__init__(self, *args, **kwargs) | ||
self.verbose = 3 | ||
|
||
def run_command(self, command): | ||
"""Only run the clean command.""" | ||
if command == 'clean': | ||
dist.Distribution.run_command(self, command) | ||
|
||
def parse_config_files(self, filenames=None): | ||
"""Skip processing of configuration files.""" | ||
pass | ||
|
||
core.setup( | ||
distclass=FakeDistribution, | ||
script_name='testsetup.py', | ||
script_args=command_line, | ||
cmdclass={'clean': janitor.CleanCommand}, | ||
) | ||
|
||
|
||
class CommandOptionTests(unittest.TestCase): | ||
|
||
def test_that_distutils_options_are_present(self): | ||
defined_options = set(t[0] for t in janitor.CleanCommand.user_options) | ||
superclass_options = set(t[0] for t in clean.clean.user_options) | ||
self.assertTrue(defined_options.issuperset(superclass_options)) | ||
|
||
def test_that_janitor_user_options_are_not_clean_options(self): | ||
self.assertIsNot( | ||
janitor.CleanCommand.user_options, clean.clean.user_options) | ||
|
||
def test_that_janitor_defines_dist_command(self): | ||
self.assertIn( | ||
('dist', 'd', 'remove distribution directory'), | ||
janitor.CleanCommand.user_options) | ||
|
||
|
||
class DirectoryCleanupTests(unittest.TestCase): | ||
temp_dir = tempfile.mkdtemp() | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
super(DirectoryCleanupTests, cls).setUpClass() | ||
atexit.register(shutil.rmtree, cls.temp_dir) | ||
|
||
@classmethod | ||
def create_directory(cls, dir_name): | ||
return tempfile.mkdtemp(dir=cls.temp_dir, prefix=dir_name) | ||
|
||
def assert_path_does_not_exist(self, full_path): | ||
if os.path.exists(full_path): | ||
raise AssertionError('{0} should not exist'.format(full_path)) | ||
|
||
def assert_path_exists(self, full_path): | ||
if not os.path.exists(full_path): | ||
raise AssertionError('{0} should exist'.format(full_path)) | ||
|
||
def test_that_dist_directory_is_removed_for_sdist(self): | ||
dist_dir = self.create_directory('dist-dir') | ||
run_setup( | ||
'sdist', '--dist-dir={0}'.format(dist_dir), | ||
'clean', '--dist', | ||
) | ||
self.assert_path_does_not_exist(dist_dir) | ||
|
||
def test_that_dist_directory_is_removed_for_bdist_dumb(self): | ||
dist_dir = self.create_directory('dist-dir') | ||
run_setup( | ||
'bdist_dumb', '--dist-dir={0}'.format(dist_dir), | ||
'clean', '--dist', | ||
) | ||
self.assert_path_does_not_exist(dist_dir) | ||
|
||
def test_that_multiple_dist_directories_with_be_removed(self): | ||
sdist_dir = self.create_directory('sdist-dir') | ||
bdist_dir = self.create_directory('bdist_dumb') | ||
run_setup( | ||
'sdist', '--dist-dir={0}'.format(sdist_dir), | ||
'bdist_dumb', '--dist-dir={0}'.format(bdist_dir), | ||
'clean', '--dist', | ||
) | ||
self.assert_path_does_not_exist(sdist_dir) | ||
self.assert_path_does_not_exist(bdist_dir) | ||
|
||
def test_that_directories_are_not_removed_without_parameter(self): | ||
sdist_dir = self.create_directory('sdist-dir') | ||
bdist_dir = self.create_directory('bdist_dumb') | ||
run_setup( | ||
'sdist', '--dist-dir={0}'.format(sdist_dir), | ||
'bdist_dumb', '--dist-dir={0}'.format(bdist_dir), | ||
'clean', | ||
) | ||
self.assert_path_exists(sdist_dir) | ||
self.assert_path_exists(bdist_dir) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,17 @@ | ||
[tox] | ||
envlist = py27,py33,py34 | ||
envlist = py26,py27,py33,py34,pypy3 | ||
toxworkdir = {toxinidir}/build/tox | ||
|
||
[testenv] | ||
deps = nose | ||
deps = -rtest-requirements.txt | ||
commands = {envbindir}/nosetests | ||
|
||
[testenv:py27] | ||
deps = | ||
{[testenv]deps} | ||
mock | ||
|
||
[testenv:py26] | ||
deps = | ||
{[testenv:py27]deps} | ||
unittest2 |