[Distutils] Initial auto-installation support
Phillip J. Eby
pje at telecommunity.com
Mon May 30 23:54:54 CEST 2005
At 04:10 PM 5/30/2005 -0500, Ian Bicking wrote:
>I've added some very initial support for automatic installation of
>packages in Paste, using easy_install
>(http://peak.telecommunity.com/DevCenter/EasyInstall). In a
>configuration file you can put:
>
> use_package(package_name, pkg_download_url=None)
>
>And a couple other options, but we'll ignore those. It will look for
>the named package, and if not found will install it (generally in
>app-packages).
FYI, just so you know, your implementation won't handle nested
dependencies, nor allow specifying optional features of requested packages.
I'd suggest that in a later version, you take a look at subclassing
pkg_resources.AvailableDistributions, and overriding the 'obtain()' method
to do the search and installation. In this way, your 'obtain()' method
will get called for any dependencies that the originally-requested package
requires.
To see what I mean, take a look at the source of pkg_resources.require(),
which looks like this:
requirements = parse_requirements(requirements)
for dist in AvailableDistributions().resolve(requirements):
dist.install_on(sys.path)
So, if you subclass AvailableDistributions to define an 'obtain()' method,
and then write a similar loop using that subclass, you'll be able to
cleanly integrate the auto-download in a forward-compatible way for
packages that declare dependencies in their PackageName.egg-info.
>There's another aspect to Paste installation, where some packages
>(plugins) need to write things into Paste. I'm not sure quite how that
>will work -- maybe use_package() will see if there's a paste_install
>module in the package somewhere, and call that somehow.
That might be a good candidate for egg metadata; if a package is a Paste
plugin, you could require a 'paste-install' file in the package's
EGG-INFO. Note that the AvailableDistributions().resolve() method returns
a list of Distribution objects, and distribution objects have a 'metadata'
attribute that implements 'IMetadataProvider'. So,
'aDistribution.metdata.has_metadata("paste-install")' will tell you if that
distribution has a "paste-install" file in its EGG-INFO, and using the
get_metadata() method will give it to you as a string. Thus, you can do
something like:
for dist in MyDownloadDistributions().resolve(requirements):
dist.install_on(sys.path)
if dist.metadata.has_metadata('paste-install'):
doSomething(dist.metadata.get_metadata('paste-install'))
If you use this algorithm, it will work for all egg varieties: compressed,
uncompressed, and "development" eggs. You will, however, need to keep
track of which paste-install scripts you've already processed, because
'resolve()' can yield distributions that are already present on
sys.path. Also, you may want to create and cache a single instance of your
MyDownloadDistributions class, because creating one does a lot of
filesystem stats and listdirs and such.
Of course, if you have people doing TheirPackage.egg-info/paste-install,
they can also create TheirPackage.egg-info/depends.txt, and list all their
dependencies there, with no need to use 'use_package'. It won't help with
download URLs, though. But we could perhaps define an
EGG-INFO/download_urls.txt as a stopgap, that lists known download urls...
Anyway, as you can see, eggs were definitely designed with plugin systems
like this in mind. :)
> But besides
>that, this should work now for any packages with a distutils install, so
>long as those packages are reasonably well behaved. Hrm... except
>setuptools 0.3a2 doesn't have SourceForge download support, but 0.3a3
>does and I think PJE will release that soon.
Hopefully within the next 24 hours or so. It will also include sandboxing
support (automatically aborts the install if the package tries to write to
the filesystem outside the build directory), and lots of workarounds to
support various packages out there that have quirky install_data subclasses.
Those items are already done, but items still on my to-do list include:
* help message to explain how to use require() for multi-version/instdir
installs
* a --build-dir/-b option to set the build directory, that will leave the
downloaded package and its extracted contents in place after the
installation is complete. (So you can read docs, install scripts, or debug
a failed installation.)
And I'd like to do something about scripts, but I think that's going to get
left to an 0.4a1 release, assuming there are no further bug fix releases
needed in the 0.3 line.
More information about the Distutils-SIG
mailing list