Skip to content
Browse files
Added setuptools.file_finders entry point group to allow implemen…

revision control plugins.

branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4043428
  • Loading branch information
PJ Eby committed Mar 29, 2006
1 parent 529b06d commit 97d43ce576112fdda6d2fa1cecf4b46cc85b04c2
Showing with 79 additions and 12 deletions.
  1. +3 −3
  2. +3 −0 setuptools.egg-info/entry_points.txt
  3. +65 −1 setuptools.txt
  4. +8 −8 setuptools/command/
@@ -77,9 +77,9 @@ def get_description():
"easy_install-%s = setuptools.command.easy_install:main"
% sys.version[:3]

["svn_cvs = setuptools.command.sdist:_default_revctrl"]
classifiers = [f.strip() for f in """
Development Status :: 3 - Alpha
Intended Audience :: Developers
@@ -12,6 +12,9 @@ eager_resources = setuptools.dist:assert_string_list
zip_safe = setuptools.dist:assert_bool
tests_require = setuptools.dist:check_requirements

svn_cvs = setuptools.command.sdist:_default_revctrl

dependency_links.txt = setuptools.command.egg_info:overwrite_arg
requires.txt = setuptools.command.egg_info:write_requirements
@@ -635,7 +635,10 @@ e.g.::

This tells setuptools to install any data files it finds in your packages. The
data files must be under CVS or Subversion control, or else they must be
specified via the distutils' ```` file.
specified via the distutils' ```` file. (They can also be tracked
by another revision control system, using an appropriate plugin. See the
section below on `Adding Support for Other Revision Control Systems`_ for
information on how to write such plugins.)

If you want finer-grained control over what files are included (for example, if
you have documentation files in your package directories and want to exclude
@@ -1346,6 +1349,10 @@ revision control, don't create a a ```` file for your project.
(And, if you already have one, you might consider deleting it the next time
you would otherwise have to change it.)

(NOTE: other revision control systems besides CVS and Subversion can be
supported using plugins; see the section below on `Adding Support for Other
Revision Control Systems`_ for information on how to write such plugins.)

If you need to include automatically generated files, or files that are kept in
an unsupported revision control system, you'll need to create a ````
file to specify any files that the default file location algorithm doesn't
@@ -2328,6 +2335,60 @@ the ``cmd`` object's ``write_file()``, ``delete_file()``, and
those methods' docstrings for more details.

Adding Support for Other Revision Control Systems

If you would like to create a plugin for ``setuptools`` to find files in other
source control systems besides CVS and Subversion, you can do so by adding an
entry point to the ``setuptools.file_finders`` group. The entry point should
be a function accepting a single directory name, and should yield
all the filenames within that directory (and any subdirectories thereof) that
are under revision control.

For example, if you were going to create a plugin for a revision control system
called "foobar", you would write a function something like this::

def find_files_for_foobar(dirname):
# loop to yield paths that start with `dirname`

And you would register it in a setup script using something like this:

entry_points = {
"setuptools.file_finders": [
"foobar = my_foobar_module:find_files_for_foobar"

Then, anyone who wants to use your plugin can simply install it, and their
local setuptools installation will be able to find the necessary files.

It is not necessary to distribute source control plugins with projects that
simply use the other source control system, or to specify the plugins in
``setup_requires``. When you create a source distribution with the ``sdist``
command, setuptools automatically records what files were found in the
``SOURCES.txt`` file. That way, recipients of source distributions don't need
to have revision control at all. However, if someone is working on a package
by checking out with that system, they will need the same plugin(s) that the
original author is using.

A few important points for writing revision control file finders:

* Your finder function MUST return relative paths, created by appending to the
passed-in directory name. Absolute paths are NOT allowed, nor are relative
paths that reference a parent directory of the passed-in directory.

* Your finder function MUST accept an empty string as the directory name,
meaning the current directory. You MUST NOT convert this to a dot; just
yield relative paths. So, yielding a subdirectory named ``some/dir`` under
the current directory should NOT be rendered as ``./some/dir`` or
``/somewhere/some/dir``, but *always* as simply ``some/dir``

* Your finder function SHOULD NOT raise any errors, and SHOULD deal gracefully
with the absence of needed programs (i.e., ones belonging to the revision
control system itself. It *may*, however, use ``distutils.log.warn()`` to
inform the user of the missing program(s).

Subclassing ``Command``

@@ -2371,6 +2432,9 @@ Release Notes/Change History

* Added ``setuptools.file_finders`` entry point group to allow implementing
revision control plugins.

* Added ``--identity`` option to ``upload`` command.

* Added ``dependency_links`` to allow specifying URLs for ``--find-links``.
@@ -1,6 +1,6 @@
from distutils.command.sdist import sdist as _sdist
from distutils.util import convert_path
import os, re, sys
import os, re, sys, pkg_resources

entities = [
("&lt;","<"), ("&gt;", ">"), ("&quot;", '"'), ("&apos;", "'"),
@@ -39,21 +39,21 @@ def joinpath(prefix,suffix):

def walk_revctrl(dirname='', memo=None):
def walk_revctrl(dirname=''):
"""Find all files under revision control"""
if memo is None:
memo = {}
if dirname in memo:
# Don't rescan a scanned directory
for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
for item in ep.load()(dirname):
yield item

def _default_revctrl(dirname=''):
for path, finder in finders:
path = joinpath(dirname,path)
if os.path.isfile(path):
for path in finder(dirname,path):
if os.path.isfile(path):
yield path
elif os.path.isdir(path):
for item in walk_revctrl(path, memo):
for item in _default_revctrl(path):
yield item

def externals_finder(dirname, filename):

0 comments on commit 97d43ce

Please sign in to comment.