mirror of
https://github.com/Hopiu/linkchecker.git
synced 2026-04-16 04:11:01 +00:00
See ChangeLog
git-svn-id: https://linkchecker.svn.sourceforge.net/svnroot/linkchecker/trunk/linkchecker@31 e7d03fd6-7b0d-0410-9947-9c21f3af8025
This commit is contained in:
parent
cb5cf83d7f
commit
e971098902
21 changed files with 2361 additions and 67 deletions
|
|
@ -1,3 +1,7 @@
|
|||
20.3.2000
|
||||
* fix a bug in reporting download time
|
||||
* added the distutils package
|
||||
|
||||
19.3.2000
|
||||
* report the duration of checking a link (Check Time)
|
||||
* rename httplib.py to http11lib.py so it does not silently
|
||||
|
|
|
|||
55
INSTALL
55
INSTALL
|
|
@ -5,41 +5,27 @@ Requirements:
|
|||
You need Python >= 1.5.2
|
||||
You get Python from http://www.python.org
|
||||
|
||||
Unix Users:
|
||||
1. Edit the file linkchecker.
|
||||
Adjust the argument to sys.path.append to point to the distribution
|
||||
directory.
|
||||
2. HTTPS support (optional, you need SSLeay)
|
||||
See below
|
||||
3. Copy linkchecker to a location in your PATH (or make a symlink).
|
||||
4. Check links happily by typing `linkchecker`.
|
||||
Installation:
|
||||
Execute "python setup.py install --create-uninstall", optionally with your
|
||||
custom options (see below).
|
||||
Now check links with "linkchecker" (Unix users) resp. "linkchecker.bat"
|
||||
(Windows users).
|
||||
|
||||
Use the "build_ext" command to supply options for SSL compilation support.
|
||||
|
||||
Windows Users:
|
||||
1. Edit the file linkchecker.
|
||||
Adjust the argument to sys.path.append to point to the distribution
|
||||
directory.
|
||||
2. Edit the file linkchecker.bat.
|
||||
a) Adjust the PYTHON variable to point to python.exe.
|
||||
b) Adjust the LINKCHECKER variable to point to the distribution directory.
|
||||
3. HTTPS support (optional, you need SSLeay)
|
||||
See below
|
||||
4. Add the distribution directory to your PATH.
|
||||
5. Check links happily by typing `linkchecker.bat`.
|
||||
|
||||
|
||||
HTTPS support:
|
||||
Run "python setup.py build_ext" to compile the ssl library.
|
||||
Here is the overall usage guide for setup.py:
|
||||
Here is the usage guide for setup.py:
|
||||
Global options:
|
||||
--verbose (-v) run verbosely (default)
|
||||
--quiet (-q) run quietly (turns verbosity off)
|
||||
--dry-run (-n) don't actually do anything
|
||||
--force (-f) skip dependency checking between files
|
||||
--help (-h) show this help message
|
||||
--verbose (-v) run verbosely (default)
|
||||
--print-version (-V) print version
|
||||
--quiet (-q) run quietly (turns verbosity off)
|
||||
--dry-run (-n) don't actually do anything
|
||||
--force (-f) skip dependency checking between files
|
||||
--help (-h) show this help message
|
||||
|
||||
Options for 'build_ext' command:
|
||||
--build-dir (-d) directory for compiled extension modules
|
||||
--build-lib (-b) directory for compiled extension modules
|
||||
--build-temp (-t) directory for temporary files (build by-products)
|
||||
--inplace (-i) ignore build-lib and put compiled extensions into the
|
||||
--include-dirs (-I) list of directories to search for header files
|
||||
--define (-D) C preprocessor macros to define
|
||||
--undef (-U) C preprocessor macros to undefine
|
||||
|
|
@ -47,11 +33,12 @@ Options for 'build_ext' command:
|
|||
--library-dirs (-L) directories to search for external C libraries
|
||||
--rpath (-R) directories to search for shared C libraries at runtime
|
||||
--link-objects (-O) extra explicit link objects to include in the link
|
||||
--debug (-g) compile/link with debugging information
|
||||
|
||||
usage: ./setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
|
||||
or: ./setup.py --help
|
||||
or: ./setup.py --help-commands
|
||||
or: ./setup.py cmd --help
|
||||
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
|
||||
or: setup.py --help
|
||||
or: setup.py --help-commands
|
||||
or: setup.py cmd --help
|
||||
|
||||
For example your openssl headers are in /usr/local/include/openssl and
|
||||
the library is in /usr/local/lib:
|
||||
|
|
|
|||
9
Makefile
9
Makefile
|
|
@ -1,8 +1,8 @@
|
|||
VERSION=$(shell ./setup.py -q version)
|
||||
VERSION=$(shell ./setup.py -V)
|
||||
HOST=treasure.calvinsplayground.de
|
||||
PROXY=treasure.calvinsplayground.de:5050 -s
|
||||
PROXY=-P$(HOST):5050
|
||||
#HOST=fsinfo.cs.uni-sb.de
|
||||
#PROXY=www-proxy.uni-sb.de:3128
|
||||
#PROXY=-Pwww-proxy.uni-sb.de:3128
|
||||
PACKAGE = linkchecker
|
||||
DEBPACKAGE = $(PACKAGE)_$(VERSION)_i386.deb
|
||||
ALLPACKAGES = ../$(DEBPACKAGE)
|
||||
|
|
@ -19,7 +19,6 @@ clean:
|
|||
|
||||
install:
|
||||
./setup.py install --destdir=$(DESTDIR)
|
||||
install -c 755 linkchecker $(DESTDIR)/usr/bin
|
||||
install -c 644 linkcheckerrc $(DESTDIR)/etc
|
||||
|
||||
dist:
|
||||
|
|
@ -27,7 +26,7 @@ dist:
|
|||
fakeroot debian/rules binary
|
||||
|
||||
files:
|
||||
./$(PACKAGE) -Wtext -Whtml -Wgml -Wsql -R -t0 -v -P$(PROXY) -i$(HOST) http://$(HOST)/~calvin/
|
||||
./$(PACKAGE) -Wtext -Whtml -Wgml -Wsql -R -t0 -v $(PROXY) -i$(HOST) http://$(HOST)/~calvin/
|
||||
|
||||
homepage: files
|
||||
scp *-out.* shell1.sourceforge.net:/home/groups/linkchecker/htdocs/
|
||||
|
|
|
|||
12
README
12
README
|
|
@ -32,14 +32,12 @@ package release sequence number.
|
|||
So for example 1.1.5 is the fifth release of the 1.1 development package.
|
||||
|
||||
Included packages:
|
||||
http11lib from http://www.lyra.org/greg/python/
|
||||
httplib from http://www.lyra.org/greg/python/
|
||||
httpslib from http://home.att.net/~nvsoft1/ssl_wrapper.html
|
||||
PyLR parser generator from http://starship.python.net/crew/scott/PyLR.html
|
||||
DNS see README.dns
|
||||
distutils from http://www.python.org/sigs/distutils-sig/
|
||||
fcgi.py from ???
|
||||
sz_fcgi.py from ???
|
||||
fcgi.py and sz_fcgi.py from http://saarland.sz-sb.de/~ajung/sz_fcgi/
|
||||
|
||||
BEWARE: the PyLR and http11lib packages are modified by me!
|
||||
It seems that http11lib and distutils will be included in Python 1.6, but
|
||||
for now I provide them myself.
|
||||
Note that the following packages are modified by me:
|
||||
httplib.py (renamed to http11lib.py)
|
||||
distutils
|
||||
|
|
|
|||
11
TODO
11
TODO
|
|
@ -1,5 +1,8 @@
|
|||
Is there a way to cleanly stop arbitrary Thread objects
|
||||
(with exit handler)? Mail me solutions!
|
||||
(1) I want to be able to supply a "break" command even when multiple
|
||||
threads are running.
|
||||
So a thread has to check regularly if a break command was issued? No,
|
||||
I do not want this. The thread has to be interrupted from outside, but
|
||||
there is at the moment no way how to do this with Python threads. What I
|
||||
am doing is to call sys.exit(1). This kills the entire Python interpreter.
|
||||
|
||||
When Python offers this in the next release:
|
||||
Internationalization and Distutils
|
||||
(2) Internationalization
|
||||
|
|
|
|||
16
distutils/command/__init__.py
Normal file
16
distutils/command/__init__.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"""distutils.command
|
||||
|
||||
Package containing implementation of all the standard Distutils
|
||||
commands."""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
__all__ = ['build',
|
||||
'build_py',
|
||||
'build_ext',
|
||||
'install',
|
||||
'install_py',
|
||||
'install_ext',
|
||||
'clean',
|
||||
'sdist',
|
||||
]
|
||||
97
distutils/command/build.py
Normal file
97
distutils/command/build.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
"""distutils.command.build
|
||||
|
||||
Implements the Distutils 'build' command."""
|
||||
|
||||
# created 1999/03/08, Greg Ward
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys, os
|
||||
from distutils.core import Command
|
||||
from distutils.util import get_platform
|
||||
|
||||
class build (Command):
|
||||
|
||||
description = "build everything needed to install"
|
||||
|
||||
user_options = [
|
||||
('build-base=', 'b',
|
||||
"base directory for build library"),
|
||||
('build-purelib=', None,
|
||||
"build directory for platform-neutral distributions"),
|
||||
('build-platlib=', None,
|
||||
"build directory for platform-specific distributions"),
|
||||
('build-lib=', None,
|
||||
"build directory for all distribution (defaults to either " +
|
||||
"build-purelib or build-platlib"),
|
||||
('build-temp=', 't',
|
||||
"temporary build directory"),
|
||||
('debug', 'g',
|
||||
"compile extensions and libraries with debugging information"),
|
||||
]
|
||||
|
||||
def initialize_options (self):
|
||||
self.build_base = 'build'
|
||||
# these are decided only after 'build_base' has its final value
|
||||
# (unless overridden by the user or client)
|
||||
self.build_purelib = None
|
||||
self.build_platlib = None
|
||||
self.build_lib = None
|
||||
self.build_temp = None
|
||||
self.debug = None
|
||||
|
||||
def finalize_options (self):
|
||||
|
||||
# Need this to name platform-specific directories, but sys.platform
|
||||
# is not enough -- it only names the OS and version, not the
|
||||
# hardware architecture!
|
||||
self.plat = get_platform ()
|
||||
|
||||
# 'build_purelib' and 'build_platlib' just default to 'lib' and
|
||||
# 'lib.<plat>' under the base build directory. We only use one of
|
||||
# them for a given distribution, though --
|
||||
if self.build_purelib is None:
|
||||
self.build_purelib = os.path.join (self.build_base, 'lib')
|
||||
if self.build_platlib is None:
|
||||
self.build_platlib = os.path.join (self.build_base,
|
||||
'lib.' + self.plat)
|
||||
|
||||
# 'build_lib' is the actual directory that we will use for this
|
||||
# particular module distribution -- if user didn't supply it, pick
|
||||
# one of 'build_purelib' or 'build_platlib'.
|
||||
if self.build_lib is None:
|
||||
if self.distribution.ext_modules:
|
||||
self.build_lib = self.build_platlib
|
||||
else:
|
||||
self.build_lib = self.build_purelib
|
||||
|
||||
# 'build_temp' -- temporary directory for compiler turds,
|
||||
# "build/temp.<plat>"
|
||||
if self.build_temp is None:
|
||||
self.build_temp = os.path.join (self.build_base,
|
||||
'temp.' + self.plat)
|
||||
# finalize_options ()
|
||||
|
||||
|
||||
def run (self):
|
||||
|
||||
# For now, "build" means "build_py" then "build_ext". (Eventually
|
||||
# it should also build documentation.)
|
||||
|
||||
# Invoke the 'build_py' command to "build" pure Python modules
|
||||
# (ie. copy 'em into the build tree)
|
||||
if self.distribution.packages or self.distribution.py_modules:
|
||||
self.run_peer ('build_py')
|
||||
|
||||
# Build any standalone C libraries next -- they're most likely to
|
||||
# be needed by extension modules, so obviously have to be done
|
||||
# first!
|
||||
if self.distribution.libraries:
|
||||
self.run_peer ('build_clib')
|
||||
|
||||
# And now 'build_ext' -- compile extension modules and put them
|
||||
# into the build tree
|
||||
if self.distribution.ext_modules:
|
||||
self.run_peer ('build_ext')
|
||||
|
||||
# end class Build
|
||||
201
distutils/command/build_clib.py
Normal file
201
distutils/command/build_clib.py
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
"""distutils.command.build_clib
|
||||
|
||||
Implements the Distutils 'build_clib' command, to build a C/C++ library
|
||||
that is included in the module distribution and needed by an extension
|
||||
module."""
|
||||
|
||||
# created (an empty husk) 1999/12/18, Greg Ward
|
||||
# fleshed out 2000/02/03-04
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
|
||||
# XXX this module has *lots* of code ripped-off quite transparently from
|
||||
# build_ext.py -- not surprisingly really, as the work required to build
|
||||
# a static library from a collection of C source files is not really all
|
||||
# that different from what's required to build a shared object file from
|
||||
# a collection of C source files. Nevertheless, I haven't done the
|
||||
# necessary refactoring to account for the overlap in code between the
|
||||
# two modules, mainly because a number of subtle details changed in the
|
||||
# cut 'n paste. Sigh.
|
||||
|
||||
import os, string
|
||||
from types import *
|
||||
from distutils.core import Command
|
||||
from distutils.errors import *
|
||||
from distutils.ccompiler import new_compiler
|
||||
|
||||
|
||||
class build_clib (Command):
|
||||
|
||||
description = "build C/C++ libraries used by Python extensions"
|
||||
|
||||
user_options = [
|
||||
('build-clib', 'b',
|
||||
"directory to build C/C++ libraries to"),
|
||||
('build-temp', 't',
|
||||
"directory to put temporary build by-products"),
|
||||
('debug', 'g',
|
||||
"compile with debugging information"),
|
||||
]
|
||||
|
||||
def initialize_options (self):
|
||||
self.build_clib = None
|
||||
self.build_temp = None
|
||||
|
||||
# List of libraries to build
|
||||
self.libraries = None
|
||||
|
||||
# Compilation options for all libraries
|
||||
self.include_dirs = None
|
||||
self.define = None
|
||||
self.undef = None
|
||||
self.debug = None
|
||||
|
||||
# initialize_options()
|
||||
|
||||
|
||||
def finalize_options (self):
|
||||
|
||||
# This might be confusing: both build-clib and build-temp default
|
||||
# to build-temp as defined by the "build" command. This is because
|
||||
# I think that C libraries are really just temporary build
|
||||
# by-products, at least from the point of view of building Python
|
||||
# extensions -- but I want to keep my options open.
|
||||
self.set_undefined_options ('build',
|
||||
('build_temp', 'build_clib'),
|
||||
('build_temp', 'build_temp'),
|
||||
('debug', 'debug'))
|
||||
|
||||
self.libraries = self.distribution.libraries
|
||||
if self.libraries:
|
||||
self.check_library_list (self.libraries)
|
||||
|
||||
if self.include_dirs is None:
|
||||
self.include_dirs = self.distribution.include_dirs or []
|
||||
if type (self.include_dirs) is StringType:
|
||||
self.include_dirs = string.split (self.include_dirs,
|
||||
os.pathsep)
|
||||
|
||||
# XXX same as for build_ext -- what about 'self.define' and
|
||||
# 'self.undef' ?
|
||||
|
||||
# finalize_options()
|
||||
|
||||
|
||||
def run (self):
|
||||
|
||||
if not self.libraries:
|
||||
return
|
||||
|
||||
# Yech -- this is cut 'n pasted from build_ext.py!
|
||||
self.compiler = new_compiler (plat=os.environ.get ('PLAT'),
|
||||
verbose=self.verbose,
|
||||
dry_run=self.dry_run,
|
||||
force=self.force)
|
||||
if self.include_dirs is not None:
|
||||
self.compiler.set_include_dirs (self.include_dirs)
|
||||
if self.define is not None:
|
||||
# 'define' option is a list of (name,value) tuples
|
||||
for (name,value) in self.define:
|
||||
self.compiler.define_macro (name, value)
|
||||
if self.undef is not None:
|
||||
for macro in self.undef:
|
||||
self.compiler.undefine_macro (macro)
|
||||
|
||||
self.build_libraries (self.libraries)
|
||||
|
||||
# run()
|
||||
|
||||
|
||||
def check_library_list (self, libraries):
|
||||
"""Ensure that the list of libraries (presumably provided as a
|
||||
command option 'libraries') is valid, i.e. it is a list of
|
||||
2-tuples, where the tuples are (library_name, build_info_dict).
|
||||
Raise DistutilsValueError if the structure is invalid anywhere;
|
||||
just returns otherwise."""
|
||||
|
||||
# Yechh, blecch, ackk: this is ripped straight out of build_ext.py,
|
||||
# with only names changed to protect the innocent!
|
||||
|
||||
if type (libraries) is not ListType:
|
||||
raise DistutilsValueError, \
|
||||
"'libraries' option must be a list of tuples"
|
||||
|
||||
for lib in libraries:
|
||||
if type (lib) is not TupleType and len (lib) != 2:
|
||||
raise DistutilsValueError, \
|
||||
"each element of 'libraries' must a 2-tuple"
|
||||
|
||||
if type (lib[0]) is not StringType:
|
||||
raise DistutilsValueError, \
|
||||
"first element of each tuple in 'libraries' " + \
|
||||
"must be a string (the library name)"
|
||||
if '/' in lib[0] or (os.sep != '/' and os.sep in lib[0]):
|
||||
raise DistutilsValueError, \
|
||||
("bad library name '%s': " +
|
||||
"may not contain directory separators") % \
|
||||
lib[0]
|
||||
|
||||
if type (lib[1]) is not DictionaryType:
|
||||
raise DistutilsValueError, \
|
||||
"second element of each tuple in 'libraries' " + \
|
||||
"must be a dictionary (build info)"
|
||||
# for lib
|
||||
|
||||
# check_library_list ()
|
||||
|
||||
|
||||
def get_library_names (self):
|
||||
# Assume the library list is valid -- 'check_library_list()' is
|
||||
# called from 'finalize_options()', so it should be!
|
||||
|
||||
if not self.libraries:
|
||||
return None
|
||||
|
||||
lib_names = []
|
||||
for (lib_name, build_info) in self.libraries:
|
||||
lib_names.append (lib_name)
|
||||
return lib_names
|
||||
|
||||
# get_library_names ()
|
||||
|
||||
|
||||
def build_libraries (self, libraries):
|
||||
|
||||
compiler = self.compiler
|
||||
|
||||
for (lib_name, build_info) in libraries:
|
||||
sources = build_info.get ('sources')
|
||||
if sources is None or type (sources) not in (ListType, TupleType):
|
||||
raise DistutilsValueError, \
|
||||
("in 'libraries' option (library '%s'), " +
|
||||
"'sources' must be present and must be " +
|
||||
"a list of source filenames") % lib_name
|
||||
sources = list (sources)
|
||||
|
||||
self.announce ("building '%s' library" % lib_name)
|
||||
|
||||
# First, compile the source code to object files in the library
|
||||
# directory. (This should probably change to putting object
|
||||
# files in a temporary build directory.)
|
||||
macros = build_info.get ('macros')
|
||||
include_dirs = build_info.get ('include_dirs')
|
||||
objects = self.compiler.compile (sources,
|
||||
output_dir=self.build_temp,
|
||||
macros=macros,
|
||||
include_dirs=include_dirs,
|
||||
debug=self.debug)
|
||||
|
||||
# Now "link" the object files together into a static library.
|
||||
# (On Unix at least, this isn't really linking -- it just
|
||||
# builds an archive. Whatever.)
|
||||
self.compiler.create_static_lib (objects, lib_name,
|
||||
output_dir=self.build_clib,
|
||||
debug=self.debug)
|
||||
|
||||
# for libraries
|
||||
|
||||
# build_libraries ()
|
||||
|
||||
# class BuildLib
|
||||
320
distutils/command/build_ext.py
Normal file
320
distutils/command/build_ext.py
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
"""distutils.command.build_ext
|
||||
|
||||
Implements the Distutils 'build_ext' command, for building extension
|
||||
modules (currently limited to C extensions, should accomodate C++
|
||||
extensions ASAP)."""
|
||||
|
||||
# created 1999/08/09, Greg Ward
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys, os, string, re
|
||||
from types import *
|
||||
from distutils.core import Command
|
||||
from distutils.errors import *
|
||||
|
||||
|
||||
# An extension name is just a dot-separated list of Python NAMEs (ie.
|
||||
# the same as a fully-qualified module name).
|
||||
extension_name_re = re.compile \
|
||||
(r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$')
|
||||
|
||||
|
||||
class build_ext (Command):
|
||||
|
||||
description = "build C/C++ extensions (compile/link to build directory)"
|
||||
|
||||
# XXX thoughts on how to deal with complex command-line options like
|
||||
# these, i.e. how to make it so fancy_getopt can suck them off the
|
||||
# command line and make it look like setup.py defined the appropriate
|
||||
# lists of tuples of what-have-you.
|
||||
# - each command needs a callback to process its command-line options
|
||||
# - Command.__init__() needs access to its share of the whole
|
||||
# command line (must ultimately come from
|
||||
# Distribution.parse_command_line())
|
||||
# - it then calls the current command class' option-parsing
|
||||
# callback to deal with weird options like -D, which have to
|
||||
# parse the option text and churn out some custom data
|
||||
# structure
|
||||
# - that data structure (in this case, a list of 2-tuples)
|
||||
# will then be present in the command object by the time
|
||||
# we get to finalize_options() (i.e. the constructor
|
||||
# takes care of both command-line and client options
|
||||
# in between initialize_options() and finalize_options())
|
||||
|
||||
user_options = [
|
||||
('build-lib=', 'b',
|
||||
"directory for compiled extension modules"),
|
||||
('build-temp=', 't',
|
||||
"directory for temporary files (build by-products)"),
|
||||
('inplace', 'i',
|
||||
"ignore build-lib and put compiled extensions into the source" +
|
||||
"directory alongside your pure Python modules"),
|
||||
('include-dirs=', 'I',
|
||||
"list of directories to search for header files"),
|
||||
('define=', 'D',
|
||||
"C preprocessor macros to define"),
|
||||
('undef=', 'U',
|
||||
"C preprocessor macros to undefine"),
|
||||
('libs=', 'l',
|
||||
"external C libraries to link with"),
|
||||
('library-dirs=', 'L',
|
||||
"directories to search for external C libraries"),
|
||||
('rpath=', 'R',
|
||||
"directories to search for shared C libraries at runtime"),
|
||||
('link-objects=', 'O',
|
||||
"extra explicit link objects to include in the link"),
|
||||
('debug', 'g',
|
||||
"compile/link with debugging information"),
|
||||
]
|
||||
|
||||
|
||||
def initialize_options (self):
|
||||
self.extensions = None
|
||||
self.build_lib = None
|
||||
self.build_temp = None
|
||||
self.inplace = 0
|
||||
self.package = None
|
||||
|
||||
self.include_dirs = None
|
||||
self.define = None
|
||||
self.undef = None
|
||||
self.libs = None
|
||||
self.library_dirs = None
|
||||
self.rpath = None
|
||||
self.link_objects = None
|
||||
self.debug = None
|
||||
|
||||
|
||||
def finalize_options (self):
|
||||
from distutils import sysconfig
|
||||
|
||||
self.set_undefined_options ('build',
|
||||
('build_lib', 'build_lib'),
|
||||
('build_temp', 'build_temp'),
|
||||
('debug', 'debug'))
|
||||
|
||||
if self.package is None:
|
||||
self.package = self.distribution.ext_package
|
||||
|
||||
self.extensions = self.distribution.ext_modules
|
||||
|
||||
|
||||
# Make sure Python's include directories (for Python.h, config.h,
|
||||
# etc.) are in the include search path. We have to roll our own
|
||||
# "exec include dir", because the Makefile parsed by sysconfig
|
||||
# doesn't have it (sigh).
|
||||
py_include = sysconfig.INCLUDEPY # prefix + "include" + "python" + ver
|
||||
exec_py_include = os.path.join (sysconfig.exec_prefix, 'include',
|
||||
'python' + sys.version[0:3])
|
||||
if self.include_dirs is None:
|
||||
self.include_dirs = self.distribution.include_dirs or []
|
||||
if type (self.include_dirs) is StringType:
|
||||
self.include_dirs = string.split (self.include_dirs,
|
||||
os.pathsep)
|
||||
|
||||
self.include_dirs.insert (0, py_include)
|
||||
if exec_py_include != py_include:
|
||||
self.include_dirs.insert (0, exec_py_include)
|
||||
|
||||
if type (self.libs) is StringType:
|
||||
self.libs = [self.libs]
|
||||
|
||||
# XXX how the heck are 'self.define' and 'self.undef' supposed to
|
||||
# be set?
|
||||
|
||||
# finalize_options ()
|
||||
|
||||
|
||||
def run (self):
|
||||
|
||||
from distutils.ccompiler import new_compiler
|
||||
|
||||
# 'self.extensions', as supplied by setup.py, is a list of 2-tuples.
|
||||
# Each tuple is simple:
|
||||
# (ext_name, build_info)
|
||||
# build_info is a dictionary containing everything specific to
|
||||
# building this extension. (Info pertaining to all extensions
|
||||
# should be handled by general distutils options passed from
|
||||
# setup.py down to right here, but that's not taken care of yet.)
|
||||
|
||||
if not self.extensions:
|
||||
return
|
||||
|
||||
# First, sanity-check the 'self.extensions' list
|
||||
self.check_extensions_list (self.extensions)
|
||||
|
||||
# Setup the CCompiler object that we'll use to do all the
|
||||
# compiling and linking
|
||||
self.compiler = new_compiler (plat=os.environ.get ('PLAT'),
|
||||
verbose=self.verbose,
|
||||
dry_run=self.dry_run,
|
||||
force=self.force)
|
||||
if self.include_dirs is not None:
|
||||
self.compiler.set_include_dirs (self.include_dirs)
|
||||
if self.define is not None:
|
||||
# 'define' option is a list of (name,value) tuples
|
||||
for (name,value) in self.define:
|
||||
self.compiler.define_macro (name, value)
|
||||
if self.undef is not None:
|
||||
for macro in self.undef:
|
||||
self.compiler.undefine_macro (macro)
|
||||
if self.libs is not None:
|
||||
self.compiler.set_libraries (self.libs)
|
||||
if self.library_dirs is not None:
|
||||
self.compiler.set_library_dirs (self.library_dirs)
|
||||
if self.rpath is not None:
|
||||
self.compiler.set_runtime_library_dirs (self.rpath)
|
||||
if self.link_objects is not None:
|
||||
self.compiler.set_link_objects (self.link_objects)
|
||||
|
||||
if self.distribution.libraries:
|
||||
build_clib = self.find_peer ('build_clib')
|
||||
self.libraries = build_clib.get_library_names () or []
|
||||
self.library_dirs = [build_clib.build_clib]
|
||||
else:
|
||||
self.libraries = []
|
||||
self.library_dirs = []
|
||||
|
||||
# Now the real loop over extensions
|
||||
self.build_extensions (self.extensions)
|
||||
|
||||
|
||||
|
||||
def check_extensions_list (self, extensions):
|
||||
"""Ensure that the list of extensions (presumably provided as a
|
||||
command option 'extensions') is valid, i.e. it is a list of
|
||||
2-tuples, where the tuples are (extension_name, build_info_dict).
|
||||
Raise DistutilsValueError if the structure is invalid anywhere;
|
||||
just returns otherwise."""
|
||||
|
||||
if type (extensions) is not ListType:
|
||||
raise DistutilsValueError, \
|
||||
"'ext_modules' option must be a list of tuples"
|
||||
|
||||
for ext in extensions:
|
||||
if type (ext) is not TupleType and len (ext) != 2:
|
||||
raise DistutilsValueError, \
|
||||
"each element of 'ext_modules' option must be a 2-tuple"
|
||||
|
||||
if not (type (ext[0]) is StringType and
|
||||
extension_name_re.match (ext[0])):
|
||||
raise DistutilsValueError, \
|
||||
"first element of each tuple in 'ext_modules' " + \
|
||||
"must be the extension name (a string)"
|
||||
|
||||
if type (ext[1]) is not DictionaryType:
|
||||
raise DistutilsValueError, \
|
||||
"second element of each tuple in 'ext_modules' " + \
|
||||
"must be a dictionary (build info)"
|
||||
|
||||
# end sanity-check for
|
||||
|
||||
# check_extensions_list ()
|
||||
|
||||
|
||||
def get_source_files (self):
|
||||
|
||||
filenames = []
|
||||
|
||||
# Wouldn't it be neat if we knew the names of header files too...
|
||||
for (extension_name, build_info) in self.extensions:
|
||||
sources = build_info.get ('sources')
|
||||
if type (sources) in (ListType, TupleType):
|
||||
filenames.extend (sources)
|
||||
|
||||
return filenames
|
||||
|
||||
|
||||
def build_extensions (self, extensions):
|
||||
|
||||
for (extension_name, build_info) in extensions:
|
||||
sources = build_info.get ('sources')
|
||||
if sources is None or type (sources) not in (ListType, TupleType):
|
||||
raise DistutilsValueError, \
|
||||
("in 'ext_modules' option (extension '%s'), " +
|
||||
"'sources' must be present and must be " +
|
||||
"a list of source filenames") % extension_name
|
||||
sources = list (sources)
|
||||
|
||||
self.announce ("building '%s' extension" % extension_name)
|
||||
|
||||
# First step: compile the source code to object files. This
|
||||
# drops the object files in the current directory, regardless
|
||||
# of where the source is (may be a bad thing, but that's how a
|
||||
# Makefile.pre.in-based system does it, so at least there's a
|
||||
# precedent!)
|
||||
macros = build_info.get ('macros')
|
||||
include_dirs = build_info.get ('include_dirs')
|
||||
objects = self.compiler.compile (sources,
|
||||
output_dir=self.build_temp,
|
||||
macros=macros,
|
||||
include_dirs=include_dirs,
|
||||
debug=self.debug)
|
||||
|
||||
# Now link the object files together into a "shared object" --
|
||||
# of course, first we have to figure out all the other things
|
||||
# that go into the mix.
|
||||
extra_objects = build_info.get ('extra_objects')
|
||||
if extra_objects:
|
||||
objects.extend (extra_objects)
|
||||
libraries = (self.libraries +
|
||||
(build_info.get ('libraries') or []))
|
||||
library_dirs = (self.library_dirs +
|
||||
(build_info.get ('library_dirs') or []))
|
||||
extra_args = build_info.get ('extra_link_args') or []
|
||||
|
||||
if self.compiler.compiler_type == 'msvc':
|
||||
def_file = build_info.get ('def_file')
|
||||
if def_file is None:
|
||||
source_dir = os.path.dirname (sources[0])
|
||||
ext_base = (string.split (extension_name, '.'))[-1]
|
||||
def_file = os.path.join (source_dir, "%s.def" % ext_base)
|
||||
if not os.path.exists (def_file):
|
||||
def_file = None
|
||||
|
||||
if def_file is not None:
|
||||
extra_args.append ('/DEF:' + def_file)
|
||||
else:
|
||||
modname = string.split (extension_name, '.')[-1]
|
||||
extra_args.append('/export:init%s'%modname)
|
||||
# end if MSVC
|
||||
|
||||
fullname = self.get_ext_fullname (extension_name)
|
||||
if self.inplace:
|
||||
# ignore build-lib -- put the compiled extension into
|
||||
# the source tree along with pure Python modules
|
||||
|
||||
modpath = string.split (fullname, '.')
|
||||
package = string.join (modpath[0:-1], '.')
|
||||
base = modpath[-1]
|
||||
|
||||
build_py = self.find_peer ('build_py')
|
||||
package_dir = build_py.get_package_dir (package)
|
||||
ext_filename = os.path.join (package_dir,
|
||||
self.get_ext_filename(base))
|
||||
else:
|
||||
ext_filename = os.path.join (self.build_lib,
|
||||
self.get_ext_filename(fullname))
|
||||
|
||||
self.compiler.link_shared_object (objects, ext_filename,
|
||||
libraries=libraries,
|
||||
library_dirs=library_dirs,
|
||||
extra_postargs=extra_args,
|
||||
debug=self.debug)
|
||||
|
||||
# build_extensions ()
|
||||
|
||||
|
||||
def get_ext_fullname (self, ext_name):
|
||||
if self.package is None:
|
||||
return ext_name
|
||||
else:
|
||||
return self.package + '.' + ext_name
|
||||
|
||||
def get_ext_filename (self, ext_name):
|
||||
from distutils import sysconfig
|
||||
ext_path = string.split (ext_name, '.')
|
||||
return apply (os.path.join, ext_path) + sysconfig.SO
|
||||
|
||||
# class BuildExt
|
||||
309
distutils/command/build_py.py
Normal file
309
distutils/command/build_py.py
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
"""distutils.command.build_py
|
||||
|
||||
Implements the Distutils 'build_py' command."""
|
||||
|
||||
# created 1999/03/08, Greg Ward
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys, string, os
|
||||
from types import *
|
||||
from glob import glob
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils.errors import *
|
||||
|
||||
|
||||
class build_py (Command):
|
||||
|
||||
description = "\"build\" pure Python modules (copy to build directory)"
|
||||
|
||||
user_options = [
|
||||
('build-lib=', 'd', "directory to \"build\" (copy) to"),
|
||||
]
|
||||
|
||||
|
||||
def initialize_options (self):
|
||||
self.build_lib = None
|
||||
self.modules = None
|
||||
self.package = None
|
||||
self.package_dir = None
|
||||
|
||||
def finalize_options (self):
|
||||
self.set_undefined_options ('build',
|
||||
('build_lib', 'build_lib'))
|
||||
|
||||
# Get the distribution options that are aliases for build_py
|
||||
# options -- list of packages and list of modules.
|
||||
self.packages = self.distribution.packages
|
||||
self.modules = self.distribution.py_modules
|
||||
self.package_dir = self.distribution.package_dir
|
||||
|
||||
|
||||
def run (self):
|
||||
|
||||
# XXX copy_file by default preserves atime and mtime. IMHO this is
|
||||
# the right thing to do, but perhaps it should be an option -- in
|
||||
# particular, a site administrator might want installed files to
|
||||
# reflect the time of installation rather than the last
|
||||
# modification time before the installed release.
|
||||
|
||||
# XXX copy_file by default preserves mode, which appears to be the
|
||||
# wrong thing to do: if a file is read-only in the working
|
||||
# directory, we want it to be installed read/write so that the next
|
||||
# installation of the same module distribution can overwrite it
|
||||
# without problems. (This might be a Unix-specific issue.) Thus
|
||||
# we turn off 'preserve_mode' when copying to the build directory,
|
||||
# since the build directory is supposed to be exactly what the
|
||||
# installation will look like (ie. we preserve mode when
|
||||
# installing).
|
||||
|
||||
# XXX copy_file does *not* preserve MacOS-specific file metadata.
|
||||
# If this is a problem for building/installing Python modules, then
|
||||
# we'll have to fix copy_file. (And what about installing scripts,
|
||||
# when the time comes for that -- does MacOS use its special
|
||||
# metadata to know that a file is meant to be interpreted by
|
||||
# Python?)
|
||||
|
||||
infiles = []
|
||||
outfiles = []
|
||||
missing = []
|
||||
|
||||
# Two options control which modules will be installed: 'packages'
|
||||
# and 'modules'. The former lets us work with whole packages, not
|
||||
# specifying individual modules at all; the latter is for
|
||||
# specifying modules one-at-a-time. Currently they are mutually
|
||||
# exclusive: you can define one or the other (or neither), but not
|
||||
# both. It remains to be seen how limiting this is.
|
||||
|
||||
# Dispose of the two "unusual" cases first: no pure Python modules
|
||||
# at all (no problem, just return silently), and over-specified
|
||||
# 'packages' and 'modules' options.
|
||||
|
||||
if not self.modules and not self.packages:
|
||||
return
|
||||
if self.modules and self.packages:
|
||||
raise DistutilsOptionError, \
|
||||
"build_py: supplying both 'packages' and 'modules' " + \
|
||||
"options is not allowed"
|
||||
|
||||
# Now we're down to two cases: 'modules' only and 'packages' only.
|
||||
if self.modules:
|
||||
self.build_modules ()
|
||||
else:
|
||||
self.build_packages ()
|
||||
|
||||
# run ()
|
||||
|
||||
|
||||
def get_package_dir (self, package):
|
||||
"""Return the directory, relative to the top of the source
|
||||
distribution, where package 'package' should be found
|
||||
(at least according to the 'package_dir' option, if any)."""
|
||||
|
||||
if type (package) is StringType:
|
||||
path = string.split (package, '.')
|
||||
elif type (package) in (TupleType, ListType):
|
||||
path = list (package)
|
||||
else:
|
||||
raise TypeError, "'package' must be a string, list, or tuple"
|
||||
|
||||
if not self.package_dir:
|
||||
if path:
|
||||
return apply (os.path.join, path)
|
||||
else:
|
||||
return ''
|
||||
else:
|
||||
tail = []
|
||||
while path:
|
||||
try:
|
||||
pdir = self.package_dir[string.join (path, '.')]
|
||||
except KeyError:
|
||||
tail.insert (0, path[-1])
|
||||
del path[-1]
|
||||
else:
|
||||
tail.insert (0, pdir)
|
||||
return apply (os.path.join, tail)
|
||||
else:
|
||||
# arg! everything failed, we might as well have not even
|
||||
# looked in package_dir -- oh well
|
||||
if tail:
|
||||
return apply (os.path.join, tail)
|
||||
else:
|
||||
return ''
|
||||
|
||||
# get_package_dir ()
|
||||
|
||||
|
||||
def check_package (self, package, package_dir):
|
||||
|
||||
# Empty dir name means current directory, which we can probably
|
||||
# assume exists. Also, os.path.exists and isdir don't know about
|
||||
# my "empty string means current dir" convention, so we have to
|
||||
# circumvent them.
|
||||
if package_dir != "":
|
||||
if not os.path.exists (package_dir):
|
||||
raise DistutilsFileError, \
|
||||
"package directory '%s' does not exist" % package_dir
|
||||
if not os.path.isdir (package_dir):
|
||||
raise DistutilsFileError, \
|
||||
("supposed package directory '%s' exists, " +
|
||||
"but is not a directory") % package_dir
|
||||
|
||||
# Require __init__.py for all but the "root package"
|
||||
if package:
|
||||
init_py = os.path.join (package_dir, "__init__.py")
|
||||
if not os.path.isfile (init_py):
|
||||
self.warn (("package init file '%s' not found " +
|
||||
"(or not a regular file)") % init_py)
|
||||
# check_package ()
|
||||
|
||||
|
||||
def check_module (self, module, module_file):
|
||||
if not os.path.isfile (module_file):
|
||||
self.warn ("file %s (for module %s) not found" %
|
||||
(module_file, module))
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
# check_module ()
|
||||
|
||||
|
||||
def find_package_modules (self, package, package_dir):
|
||||
module_files = glob (os.path.join (package_dir, "*.py"))
|
||||
module_pairs = []
|
||||
setup_script = os.path.abspath (sys.argv[0])
|
||||
|
||||
for f in module_files:
|
||||
abs_f = os.path.abspath (f)
|
||||
if abs_f != setup_script:
|
||||
module = os.path.splitext (os.path.basename (f))[0]
|
||||
module_pairs.append ((module, f))
|
||||
return module_pairs
|
||||
|
||||
|
||||
def find_modules (self):
|
||||
# Map package names to tuples of useful info about the package:
|
||||
# (package_dir, checked)
|
||||
# package_dir - the directory where we'll find source files for
|
||||
# this package
|
||||
# checked - true if we have checked that the package directory
|
||||
# is valid (exists, contains __init__.py, ... ?)
|
||||
packages = {}
|
||||
|
||||
# List of (module, package, filename) tuples to return
|
||||
modules = []
|
||||
|
||||
# We treat modules-in-packages almost the same as toplevel modules,
|
||||
# just the "package" for a toplevel is empty (either an empty
|
||||
# string or empty list, depending on context). Differences:
|
||||
# - don't check for __init__.py in directory for empty package
|
||||
|
||||
for module in self.modules:
|
||||
path = string.split (module, '.')
|
||||
package = tuple (path[0:-1])
|
||||
module_base = path[-1]
|
||||
|
||||
try:
|
||||
(package_dir, checked) = packages[package]
|
||||
except KeyError:
|
||||
package_dir = self.get_package_dir (package)
|
||||
checked = 0
|
||||
|
||||
if not checked:
|
||||
self.check_package (package, package_dir)
|
||||
packages[package] = (package_dir, 1)
|
||||
|
||||
# XXX perhaps we should also check for just .pyc files
|
||||
# (so greedy closed-source bastards can distribute Python
|
||||
# modules too)
|
||||
module_file = os.path.join (package_dir, module_base + ".py")
|
||||
if not self.check_module (module, module_file):
|
||||
continue
|
||||
|
||||
modules.append ((module, package, module_file))
|
||||
|
||||
return modules
|
||||
|
||||
# find_modules ()
|
||||
|
||||
|
||||
def get_source_files (self):
|
||||
|
||||
if self.modules:
|
||||
modules = self.find_modules ()
|
||||
else:
|
||||
modules = []
|
||||
for package in self.packages:
|
||||
package_dir = self.get_package_dir (package)
|
||||
m = self.find_package_modules (package, package_dir)
|
||||
modules.extend (m)
|
||||
|
||||
# Both find_modules() and find_package_modules() return a list of
|
||||
# tuples where the last element of each tuple is the filename --
|
||||
# what a happy coincidence!
|
||||
filenames = []
|
||||
for module in modules:
|
||||
filenames.append (module[-1])
|
||||
|
||||
return filenames
|
||||
|
||||
|
||||
def build_module (self, module, module_file, package):
|
||||
|
||||
if type (package) is StringType:
|
||||
package = string.split (package, '.')
|
||||
elif type (package) not in (ListType, TupleType):
|
||||
raise TypeError, \
|
||||
"'package' must be a string (dot-separated), list, or tuple"
|
||||
|
||||
# Now put the module source file into the "build" area -- this is
|
||||
# easy, we just copy it somewhere under self.build_lib (the build
|
||||
# directory for Python source).
|
||||
outfile_path = list (package)
|
||||
outfile_path.append (module + ".py")
|
||||
outfile_path.insert (0, self.build_lib)
|
||||
outfile = apply (os.path.join, outfile_path)
|
||||
|
||||
dir = os.path.dirname (outfile)
|
||||
self.mkpath (dir)
|
||||
self.copy_file (module_file, outfile, preserve_mode=0)
|
||||
|
||||
|
||||
def build_modules (self):
|
||||
|
||||
modules = self.find_modules()
|
||||
for (module, package, module_file) in modules:
|
||||
|
||||
# Now "build" the module -- ie. copy the source file to
|
||||
# self.build_lib (the build directory for Python source).
|
||||
# (Actually, it gets copied to the directory for this package
|
||||
# under self.build_lib.)
|
||||
self.build_module (module, module_file, package)
|
||||
|
||||
# build_modules ()
|
||||
|
||||
|
||||
def build_packages (self):
|
||||
|
||||
for package in self.packages:
|
||||
package_dir = self.get_package_dir (package)
|
||||
self.check_package (package, package_dir)
|
||||
|
||||
# Get list of (module, module_file) tuples based on scanning
|
||||
# the package directory. Here, 'module' is the *unqualified*
|
||||
# module name (ie. no dots, no package -- we already know its
|
||||
# package!), and module_file is the path to the .py file,
|
||||
# relative to the current directory (ie. including
|
||||
# 'package_dir').
|
||||
modules = self.find_package_modules (package, package_dir)
|
||||
|
||||
# Now loop over the modules we found, "building" each one (just
|
||||
# copy it to self.build_lib).
|
||||
for (module, module_file) in modules:
|
||||
self.build_module (module, module_file, package)
|
||||
|
||||
# build_packages ()
|
||||
|
||||
# end class BuildPy
|
||||
64
distutils/command/clean.py
Normal file
64
distutils/command/clean.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
"""distutils.command.clean
|
||||
|
||||
Implements the Distutils 'clean' command."""
|
||||
|
||||
# contributed by Bastian Kleineidam <calvin@cs.uni-sb.de>, added 2000-03-18
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import os
|
||||
from distutils.core import Command
|
||||
from distutils.util import remove_tree
|
||||
|
||||
class clean (Command):
|
||||
|
||||
description = "clean up output of 'build' command"
|
||||
user_options = [
|
||||
('build-base=', 'b',
|
||||
"base build directory (default: 'build.build-base')"),
|
||||
('build-lib=', None,
|
||||
"build directory for all modules (default: 'build.build-lib')"),
|
||||
('build-temp=', 't',
|
||||
"temporary build directory (default: 'build.build-temp')"),
|
||||
('all', 'a',
|
||||
"remove all build output, not just temporary by-products")
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.build_base = None
|
||||
self.build_lib = None
|
||||
self.build_temp = None
|
||||
self.all = None
|
||||
|
||||
def finalize_options(self):
|
||||
if self.build_lib and not os.path.exists (self.build_lib):
|
||||
self.warn ("'%s' does not exist -- can't clean it" %
|
||||
self.build_lib)
|
||||
if self.build_temp and not os.path.exists (self.build_temp):
|
||||
self.warn ("'%s' does not exist -- can't clean it" %
|
||||
self.build_temp)
|
||||
|
||||
self.set_undefined_options('build',
|
||||
('build_base', 'build_base'),
|
||||
('build_lib', 'build_lib'),
|
||||
('build_temp', 'build_temp'))
|
||||
|
||||
def run(self):
|
||||
# remove the build/temp.<plat> directory (unless it's already
|
||||
# gone)
|
||||
if os.path.exists (self.build_temp):
|
||||
remove_tree (self.build_temp, self.verbose, self.dry_run)
|
||||
|
||||
if self.all:
|
||||
# remove the module build directory (unless already gone)
|
||||
if os.path.exists (self.build_lib):
|
||||
remove_tree (self.build_lib, self.verbose, self.dry_run)
|
||||
|
||||
# just for the heck of it, try to remove the base build directory:
|
||||
# we might have emptied it right now, but if not we don't care
|
||||
if not self.dry_run:
|
||||
try:
|
||||
os.rmdir (self.build_base)
|
||||
self.announce ("removing '%s'" % self.build_base)
|
||||
except OSError:
|
||||
pass
|
||||
351
distutils/command/install.py
Normal file
351
distutils/command/install.py
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
"""distutils.command.install
|
||||
|
||||
Implements the Distutils 'install' command."""
|
||||
|
||||
# created 1999/03/13, Greg Ward
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys, os, string
|
||||
from types import *
|
||||
from distutils.core import Command
|
||||
from distutils.util import write_file
|
||||
from distutils.errors import DistutilsOptionError
|
||||
|
||||
_uninstall_template = """#!/usr/bin/env python
|
||||
# this file is generated from the distutils 'install' command
|
||||
|
||||
filelist = %s
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os
|
||||
paths = filelist.keys()
|
||||
# sort to catch all files before removing directories
|
||||
paths.sort()
|
||||
paths.reverse()
|
||||
for f in paths:
|
||||
print "removing",f
|
||||
if os.path.exists(f) and not os.path.isdir(f):
|
||||
os.remove(f)
|
||||
elif os.path.isdir(f):
|
||||
if os.listdir(f):
|
||||
print "warning: directory "+f+" not empty so not removed"
|
||||
else:
|
||||
os.rmdir(f)
|
||||
else:
|
||||
raise AttributeError, "Unknown file type "+f
|
||||
"""
|
||||
|
||||
class install (Command):
|
||||
|
||||
description = "install everything from build directory"
|
||||
|
||||
user_options = [
|
||||
('destdir=', None, 'destination directory'),
|
||||
('prefix=', None, "installation prefix"),
|
||||
('exec-prefix=', None,
|
||||
"prefix for platform-specific files"),
|
||||
|
||||
# Installation directories: where to put modules and packages
|
||||
('install-lib=', None, "base Python library directory"),
|
||||
('install-platlib=', None,
|
||||
"platform-specific Python library directory"),
|
||||
('install-bin=', None,
|
||||
"directory for programs and scripts (default exec-prefix/bin)"),
|
||||
('install-path=', None,
|
||||
"extra intervening directories to put below install-lib"),
|
||||
('create-uninstall', None, 'create and install uninstall script'),
|
||||
|
||||
# Build directories: where to find the files to install
|
||||
('build-base=', None,
|
||||
"base build directory"),
|
||||
('build-lib=', None,
|
||||
"build directory for pure Python modules"),
|
||||
('build-platlib=', None,
|
||||
"build directory for extension modules"),
|
||||
|
||||
# Where to install documentation (eventually!)
|
||||
#('doc-format=', None, "format of documentation to generate"),
|
||||
#('install-man=', None, "directory for Unix man pages"),
|
||||
#('install-html=', None, "directory for HTML documentation"),
|
||||
#('install-info=', None, "directory for GNU info files"),
|
||||
|
||||
# Flags for 'build_py'
|
||||
#('compile-py', None, "compile .py to .pyc"),
|
||||
#('optimize-py', None, "compile .py to .pyo (optimized)"),
|
||||
]
|
||||
|
||||
|
||||
def initialize_options (self):
|
||||
|
||||
# Don't define 'prefix' or 'exec_prefix' so we can know when the
|
||||
# command is run whether the user supplied values
|
||||
self.prefix = None
|
||||
self.exec_prefix = None
|
||||
self.destdir = None
|
||||
|
||||
# The actual installation directories are determined only at
|
||||
# run-time, so the user can supply just prefix (and exec_prefix?)
|
||||
# as a base for everything else
|
||||
self.install_lib = None
|
||||
self.install_platlib = None
|
||||
self.install_path = None
|
||||
self.install_bin = None
|
||||
|
||||
self.build_base = None
|
||||
self.build_lib = None
|
||||
self.build_platlib = None
|
||||
|
||||
self.install_man = None
|
||||
self.install_html = None
|
||||
self.install_info = None
|
||||
self.create_uninstall = None
|
||||
|
||||
self.compile_py = 1
|
||||
self.optimize_py = 1
|
||||
|
||||
|
||||
def finalize_options (self):
|
||||
|
||||
# XXX this method is where the default installation directories
|
||||
# for modules and extension modules are determined. (Someday,
|
||||
# the default installation directories for scripts,
|
||||
# documentation, and whatever else the Distutils can build and
|
||||
# install will also be determined here.) Thus, this is a pretty
|
||||
# important place to fiddle with for anyone interested in
|
||||
# installation schemes for the Python library. Issues that
|
||||
# are not yet resolved to my satisfaction:
|
||||
# * how much platform dependence should be here, and
|
||||
# how much can be pushed off to sysconfig (or, better, the
|
||||
# Makefiles parsed by sysconfig)?
|
||||
# * how independent of Python version should this be -- ie.
|
||||
# should we have special cases to handle Python 1.5 and
|
||||
# older, and then do it "the right way" for 1.6? Or should
|
||||
# we install a site.py along with Distutils under pre-1.6
|
||||
# Python to take care of the current deficiencies in
|
||||
# Python's library installation scheme?
|
||||
#
|
||||
# Currently, this method has hacks to distinguish POSIX from
|
||||
# non-POSIX systems (for installation of site-local modules),
|
||||
# and assumes the Python 1.5 installation tree with no site.py
|
||||
# to fix things.
|
||||
|
||||
# Figure out actual installation directories; the basic principle
|
||||
# is: ...
|
||||
|
||||
if self.destdir is None:
|
||||
self.destdir = ""
|
||||
sys_prefix = os.path.normpath (sys.prefix)
|
||||
sys_exec_prefix = os.path.normpath (sys.exec_prefix)
|
||||
|
||||
if self.prefix is None:
|
||||
if self.exec_prefix is not None:
|
||||
raise DistutilsOptionError, \
|
||||
"you may not supply exec_prefix without prefix"
|
||||
self.prefix = sys_prefix
|
||||
else:
|
||||
# This is handy to guarantee that self.prefix is normalized --
|
||||
# but it could be construed as rude to go normalizing a
|
||||
# user-supplied path (they might like to see their "../" or
|
||||
# symlinks in the installation feedback).
|
||||
self.prefix = os.path.normpath (self.prefix)
|
||||
|
||||
if self.exec_prefix is None:
|
||||
if self.prefix == sys_prefix:
|
||||
self.exec_prefix = sys_exec_prefix
|
||||
else:
|
||||
self.exec_prefix = self.prefix
|
||||
else:
|
||||
# Same as above about handy versus rude to normalize user's
|
||||
# exec_prefix.
|
||||
self.exec_prefix = os.path.normpath (self.exec_prefix)
|
||||
|
||||
if self.distribution.ext_modules: # any extensions to install?
|
||||
effective_prefix = self.exec_prefix
|
||||
else:
|
||||
effective_prefix = self.prefix
|
||||
|
||||
if os.name == 'posix':
|
||||
if self.install_lib is None:
|
||||
if self.prefix == sys_prefix:
|
||||
self.install_lib = \
|
||||
os.path.join (effective_prefix,
|
||||
"lib",
|
||||
"python" + sys.version[:3],
|
||||
"site-packages")
|
||||
else:
|
||||
self.install_lib = \
|
||||
os.path.join (effective_prefix,
|
||||
"lib",
|
||||
"python") # + sys.version[:3] ???
|
||||
# end if self.install_lib ...
|
||||
|
||||
if self.install_platlib is None:
|
||||
if self.exec_prefix == sys_exec_prefix:
|
||||
self.install_platlib = \
|
||||
os.path.join (effective_prefix,
|
||||
"lib",
|
||||
"python" + sys.version[:3],
|
||||
"site-packages")
|
||||
else:
|
||||
self.install_platlib = \
|
||||
os.path.join (effective_prefix,
|
||||
"lib",
|
||||
"python") # + sys.version[:3] ???
|
||||
# end if self.install_platlib ...
|
||||
|
||||
else:
|
||||
raise DistutilsPlatformError, \
|
||||
"duh, I'm clueless (for now) about installing on %s" % os.name
|
||||
|
||||
# end if/else on os.name
|
||||
|
||||
if self.install_bin is None:
|
||||
self.install_bin = os.path.join(self.exec_prefix,"bin")
|
||||
|
||||
# 'path_file' and 'extra_dirs' are how we handle distributions that
|
||||
# want to be installed to their own directory, but aren't
|
||||
# package-ized yet. 'extra_dirs' is just a directory under
|
||||
# 'install_lib' or 'install_platlib' where top-level modules will
|
||||
# actually be installed; 'path_file' is the basename of a .pth file
|
||||
# to drop in 'install_lib' or 'install_platlib' (depending on the
|
||||
# distribution). Very often they will be the same, which is why we
|
||||
# allow them to be supplied as a string or 1-tuple as well as a
|
||||
# 2-element comma-separated string or a 2-tuple.
|
||||
|
||||
# XXX this will drop a .pth file in install_{lib,platlib} even if
|
||||
# they're not one of the site-packages directories: this is wrong!
|
||||
# we need to suppress path_file in those cases, and warn if
|
||||
# "install_lib/extra_dirs" is not in sys.path.
|
||||
|
||||
if self.install_path is None:
|
||||
self.install_path = self.distribution.install_path
|
||||
|
||||
if self.install_path is not None:
|
||||
if type (self.install_path) is StringType:
|
||||
self.install_path = string.split (self.install_path, ',')
|
||||
|
||||
if len (self.install_path) == 1:
|
||||
path_file = extra_dirs = self.install_path[0]
|
||||
elif len (self.install_path) == 2:
|
||||
(path_file, extra_dirs) = self.install_path
|
||||
else:
|
||||
raise DistutilsOptionError, \
|
||||
"'install_path' option must be a list, tuple, or " + \
|
||||
"comma-separated string with 1 or 2 elements"
|
||||
|
||||
# install path has slashes in it -- might need to convert to
|
||||
# local form
|
||||
if string.find (extra_dirs, '/') and os.name != "posix":
|
||||
extra_dirs = string.split (extra_dirs, '/')
|
||||
extra_dirs = apply (os.path.join, extra_dirs)
|
||||
else:
|
||||
path_file = None
|
||||
extra_dirs = ''
|
||||
|
||||
# XXX should we warn if path_file and not extra_dirs (in which case
|
||||
# the path file would be harmless but pointless)
|
||||
self.path_file = path_file
|
||||
self.extra_dirs = extra_dirs
|
||||
|
||||
|
||||
# Figure out the build directories, ie. where to install from
|
||||
self.set_peer_option ('build', 'build_base', self.build_base)
|
||||
self.set_undefined_options ('build',
|
||||
('build_base', 'build_base'),
|
||||
('build_lib', 'build_lib'),
|
||||
('build_platlib', 'build_platlib'))
|
||||
|
||||
# Punt on doc directories for now -- after all, we're punting on
|
||||
# documentation completely!
|
||||
|
||||
# finalize_options ()
|
||||
|
||||
|
||||
def run (self):
|
||||
|
||||
# Obviously have to build before we can install
|
||||
self.run_peer ('build')
|
||||
|
||||
# Install modules in two steps: "platform-shared" files (ie. pure
|
||||
# Python modules) and platform-specific files (compiled C
|
||||
# extensions). Note that 'install_py' is smart enough to install
|
||||
# pure Python modules in the "platlib" directory if we built any
|
||||
# extensions.
|
||||
if self.distribution.packages or self.distribution.py_modules:
|
||||
self.run_peer ('install_py')
|
||||
if self.distribution.ext_modules:
|
||||
self.run_peer ('install_ext')
|
||||
if self.distribution.scripts or self.distribution.programs:
|
||||
self.run_peer('install_bin')
|
||||
|
||||
if self.path_file:
|
||||
self.create_path_file ()
|
||||
if self.create_uninstall:
|
||||
self.create_uninstall_file()
|
||||
|
||||
# run ()
|
||||
|
||||
|
||||
def create_path_file (self):
|
||||
|
||||
if self.distribution.ext_modules:
|
||||
base = self.platbase
|
||||
else:
|
||||
base = self.base
|
||||
|
||||
filename = os.path.join (base, self.path_file + ".pth")
|
||||
self.execute (write_file,
|
||||
(filename, [self.extra_dirs]),
|
||||
"creating %s" % filename)
|
||||
|
||||
def create_uninstall_file(self):
|
||||
"""Create an uninstall file <distribution name>_uninstall.py.
|
||||
The distribution name must be given!
|
||||
If there is already an uninstall file, we add any new files we
|
||||
installed to it.
|
||||
To uninstall, simply execute the uninstall file with python.
|
||||
"""
|
||||
# check for distribution name
|
||||
if not self.distribution.name:
|
||||
raise DistutilsOptionError, "you must supply a distribution name"
|
||||
# construct the paths and filenames
|
||||
if self.distribution.ext_modules:
|
||||
base = self.install_platlib
|
||||
else:
|
||||
base = self.install_lib
|
||||
modulename = self.distribution.name+"_uninstall"
|
||||
filename = modulename+".py"
|
||||
import __builtin__
|
||||
cfilename = filename + (__builtin__.__debug__ and "c" or "o")
|
||||
# add the uninstall script itself to outfiles
|
||||
uninstall_script = os.path.join(base, filename)
|
||||
uninstall_script_c = os.path.join(base, cfilename)
|
||||
self.distribution.outfiles.append(uninstall_script)
|
||||
self.distribution.outfiles.append(uninstall_script_c)
|
||||
|
||||
if self.destdir:
|
||||
base = self.destdir + base
|
||||
path = os.path.join(base, filename)
|
||||
cpath = os.path.join(base, cfilename)
|
||||
if not os.path.exists(path):
|
||||
filelist = {}
|
||||
else:
|
||||
if base not in sys.path:
|
||||
sys.path.insert(0, base)
|
||||
exec "from %s import filelist" % modulename
|
||||
for f in self.distribution.outfiles:
|
||||
# to eliminate duplicates we use a dictionary
|
||||
filelist[f] = 1
|
||||
f = open(path, "w")
|
||||
f.write(_uninstall_template % filelist)
|
||||
f.close()
|
||||
# byte-compile the script
|
||||
from py_compile import compile
|
||||
self.make_file (path, cpath, compile, (path,),
|
||||
"byte-compiling %s" % path,
|
||||
"byte-compilation of %s skipped" % path)
|
||||
self.announce("to uninstall execute "+uninstall_script+" with python")
|
||||
|
||||
|
||||
# class Install
|
||||
88
distutils/command/install_bin.py
Normal file
88
distutils/command/install_bin.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
"""install_bin
|
||||
|
||||
Implement the Distutils "install_bin" command to install programs
|
||||
and scripts."""
|
||||
|
||||
from distutils.core import Command
|
||||
import os,types,string
|
||||
|
||||
class install_bin(Command):
|
||||
|
||||
description = "install programs and scripts"
|
||||
|
||||
user_options = [
|
||||
('install-dir=', 'd', "directory to install to"),
|
||||
('destdir', None, 'destination directory'),
|
||||
]
|
||||
|
||||
def initialize_options (self):
|
||||
# let the 'install' command dictate our installation directory
|
||||
self.install_dir = None
|
||||
self.create_uninstall = None
|
||||
self.destdir = None
|
||||
|
||||
def finalize_options (self):
|
||||
self.set_undefined_options ('install',
|
||||
('install_bin', 'install_dir'),
|
||||
('create_uninstall', 'create_uninstall'),
|
||||
('destdir', 'destdir'))
|
||||
self.programs = self.get_platform_bins(self.distribution.programs)
|
||||
self.scripts = self.get_platform_bins(self.distribution.scripts)
|
||||
|
||||
def get_platform_bins(self, bins):
|
||||
filtered = []
|
||||
if bins:
|
||||
for b in bins:
|
||||
if type(b)==types.TupleType:
|
||||
if len(b)==2 and os.name==b[1]:
|
||||
filtered.append(b[0])
|
||||
else:
|
||||
filtered.append(b)
|
||||
return filtered
|
||||
|
||||
def run (self):
|
||||
|
||||
if not self.programs and not self.scripts:
|
||||
return
|
||||
|
||||
# Copy specified programs and scripts to install_dir
|
||||
# Additionally replace in scripts some variables
|
||||
# (currently only @INSTALL_BIN@ with install_dir)
|
||||
real_install_dir = self.install_dir
|
||||
if self.destdir:
|
||||
self.install_dir = self.destdir+self.install_dir
|
||||
ddlen = len(self.destdir)
|
||||
# create the install directory
|
||||
outfiles = self.mkpath(self.install_dir)
|
||||
# copy the files
|
||||
if self.create_uninstall and not self.force:
|
||||
# turn on self.force to catch all previous installed files
|
||||
oldforce = self.force
|
||||
self.force = 1
|
||||
outfiles.extend(self.run_copy_files(real_install_dir))
|
||||
# restore previous options
|
||||
self.force = oldforce
|
||||
else:
|
||||
outfiles.extend(self.run_copy_files(real_install_dir))
|
||||
if self.destdir:
|
||||
# cut off destdir prefix
|
||||
outfiles = map(lambda s,l=ddlen: s[l:], outfiles)
|
||||
self.distribution.outfiles.extend(outfiles)
|
||||
|
||||
def run_copy_files(self, real_install_dir):
|
||||
outfiles = []
|
||||
for f in self.programs:
|
||||
if self.copy_file(f, self.install_dir):
|
||||
outfiles.append(os.path.join(real_install_dir, f))
|
||||
for f in self.scripts:
|
||||
if self.copy_file(f, self.install_dir):
|
||||
outfiles.append(os.path.join(real_install_dir, f))
|
||||
self.replace_vars(os.path.join(self.install_dir, f),
|
||||
real_install_dir)
|
||||
return outfiles
|
||||
|
||||
def replace_vars(self, file, directory):
|
||||
data = open(file).read()
|
||||
data = string.replace(data, "@INSTALL_BIN@", directory)
|
||||
open(file,"w").write(data)
|
||||
|
||||
62
distutils/command/install_ext.py
Normal file
62
distutils/command/install_ext.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
"""install_ext
|
||||
|
||||
Implement the Distutils "install_ext" command to install extension modules."""
|
||||
|
||||
# created 1999/09/12, Greg Ward
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils.util import copy_tree
|
||||
|
||||
class install_ext (Command):
|
||||
|
||||
description = "install C/C++ extension modules"
|
||||
|
||||
user_options = [
|
||||
('install-dir=', 'd', "directory to install to"),
|
||||
('build-dir=','b', "build directory (where to install from)"),
|
||||
('destdir', None, "destination directory")
|
||||
]
|
||||
|
||||
def initialize_options (self):
|
||||
# let the 'install' command dictate our installation directory
|
||||
self.install_dir = None
|
||||
self.build_dir = None
|
||||
self.create_uninstall = None
|
||||
self.destdir = None
|
||||
|
||||
def finalize_options (self):
|
||||
self.set_undefined_options ('install',
|
||||
('build_platlib', 'build_dir'),
|
||||
('install_platlib', 'install_dir'),
|
||||
('create_uninstall', 'create_uninstall'),
|
||||
('destdir', 'destdir'))
|
||||
|
||||
def run (self):
|
||||
|
||||
# Make sure we have built all extension modules first
|
||||
self.run_peer ('build_ext')
|
||||
|
||||
# Dump the entire "build/platlib" directory (or whatever it really
|
||||
# is; "build/platlib" is the default) to the installation target
|
||||
# (eg. "/usr/local/lib/python1.5/site-packages"). Note that
|
||||
# putting files in the right package dir is already done when we
|
||||
# build.
|
||||
if self.destdir:
|
||||
self.install_dir = self.destdir+self.install_dir
|
||||
ddlen = len(self.destdir)
|
||||
if self.create_uninstall and not self.force:
|
||||
# turn on self.force to catch all previous installed files
|
||||
oldforce = self.force
|
||||
self.force = 1
|
||||
outfiles = self.copy_tree (self.build_dir, self.install_dir)
|
||||
# restore previous options
|
||||
self.force = oldforce
|
||||
else:
|
||||
outfiles = self.copy_tree (self.build_dir, self.install_dir)
|
||||
if self.destdir:
|
||||
outfiles = map(lambda s,l=ddlen: s[l:], outfiles)
|
||||
self.distribution.outfiles = self.distribution.outfiles + outfiles
|
||||
|
||||
# class InstallExt
|
||||
95
distutils/command/install_py.py
Normal file
95
distutils/command/install_py.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# created 1999/03/13, Greg Ward
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys, string
|
||||
from distutils.core import Command
|
||||
from distutils.util import copy_tree
|
||||
|
||||
class install_py (Command):
|
||||
|
||||
description = "install pure Python modules"
|
||||
|
||||
user_options = [
|
||||
('install-dir=', 'd', "directory to install to"),
|
||||
('build-dir=','b', "build directory (where to install from)"),
|
||||
('compile', 'c', "compile .py to .pyc"),
|
||||
('optimize', 'o', "compile .py to .pyo (optimized)"),
|
||||
('destdir', None, 'destination directory'),
|
||||
]
|
||||
|
||||
|
||||
def initialize_options (self):
|
||||
# let the 'install' command dictate our installation directory
|
||||
self.install_dir = None
|
||||
self.build_dir = None
|
||||
self.compile = 1
|
||||
self.optimize = 1
|
||||
self.create_uninstall = None
|
||||
self.destdir = None
|
||||
|
||||
def finalize_options (self):
|
||||
|
||||
# Get all the information we need to install pure Python modules
|
||||
# from the umbrella 'install' command -- build (source) directory,
|
||||
# install (target) directory, and whether to compile .py files.
|
||||
self.set_undefined_options ('install',
|
||||
('build_lib', 'build_dir'),
|
||||
('install_lib', 'install_dir'),
|
||||
('create_uninstall', 'create_uninstall'),
|
||||
('compile_py', 'compile'),
|
||||
('optimize_py', 'optimize'),
|
||||
('destdir', 'destdir'))
|
||||
|
||||
|
||||
def run (self):
|
||||
|
||||
# Make sure we have "built" all pure Python modules first
|
||||
self.run_peer ('build_py')
|
||||
|
||||
# Install everything: simply dump the entire contents of the build
|
||||
# directory to the installation directory (that's the beauty of
|
||||
# having a build directory!)
|
||||
if self.destdir:
|
||||
self.install_dir = self.destdir+self.install_dir
|
||||
ddlen = len(self.destdir)
|
||||
if self.create_uninstall and not self.force:
|
||||
# turn on self.force to catch all previous installed files
|
||||
oldforce = self.force
|
||||
self.force = 1
|
||||
outfiles = self.copy_tree (self.build_dir, self.install_dir)
|
||||
self.force = oldforce
|
||||
else:
|
||||
outfiles = self.copy_tree (self.build_dir, self.install_dir)
|
||||
|
||||
# (Optionally) compile .py to .pyc
|
||||
# XXX hey! we can't control whether we optimize or not; that's up
|
||||
# to the invocation of the current Python interpreter (at least
|
||||
# according to the py_compile docs). That sucks.
|
||||
|
||||
if self.compile:
|
||||
from py_compile import compile
|
||||
import __builtin__
|
||||
|
||||
for f in outfiles:
|
||||
# XXX we can determine if we run python -O by looking
|
||||
# at __builtin__.__debug__, but we can not change it
|
||||
|
||||
# only compile the file if it is actually a .py file
|
||||
if f[-3:] == '.py':
|
||||
out_fn = f + (__builtin__.__debug__ and "c" or "o")
|
||||
outfiles.append(out_fn)
|
||||
self.make_file (f, out_fn, compile, (f,),
|
||||
"byte-compiling %s" % f,
|
||||
"byte-compilation of %s skipped" % f)
|
||||
|
||||
# XXX ignore self.optimize for now, since we don't really know if
|
||||
# we're compiling optimally or not, and couldn't pick what to do
|
||||
# even if we did know. ;-(
|
||||
if self.destdir:
|
||||
outfiles = map(lambda s,l=ddlen: s[l:], outfiles)
|
||||
self.distribution.outfiles = self.distribution.outfiles + outfiles
|
||||
|
||||
# run ()
|
||||
|
||||
# class InstallPy
|
||||
704
distutils/command/sdist.py
Normal file
704
distutils/command/sdist.py
Normal file
|
|
@ -0,0 +1,704 @@
|
|||
"""distutils.command.sdist
|
||||
|
||||
Implements the Distutils 'sdist' command (create a source distribution)."""
|
||||
|
||||
# created 1999/09/22, Greg Ward
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys, os, string, re
|
||||
import fnmatch
|
||||
from types import *
|
||||
from glob import glob
|
||||
from distutils.core import Command
|
||||
from distutils.util import newer, remove_tree
|
||||
from distutils.text_file import TextFile
|
||||
from distutils.errors import DistutilsExecError
|
||||
|
||||
|
||||
class sdist (Command):
|
||||
|
||||
description = "create a source distribution (tarball, zip file, etc.)"
|
||||
|
||||
user_options = [
|
||||
('template=', 't',
|
||||
"name of manifest template file [default: MANIFEST.in]"),
|
||||
('manifest=', 'm',
|
||||
"name of manifest file [default: MANIFEST]"),
|
||||
('use-defaults', None,
|
||||
"include the default file set in the manifest "
|
||||
"[default; disable with --no-defaults]"),
|
||||
('manifest-only', None,
|
||||
"just regenerate the manifest and then stop"),
|
||||
('force-manifest', None,
|
||||
"forcibly regenerate the manifest and carry on as usual"),
|
||||
|
||||
('formats=', None,
|
||||
"formats for source distribution (tar, ztar, gztar, or zip)"),
|
||||
('list-only', 'l',
|
||||
"just list files that would be distributed"),
|
||||
('keep-tree', 'k',
|
||||
"keep the distribution tree around after creating " +
|
||||
"archive file(s)"),
|
||||
]
|
||||
negative_opts = {'use-defaults': 'no-defaults'}
|
||||
|
||||
default_format = { 'posix': 'gztar',
|
||||
'nt': 'zip' }
|
||||
|
||||
exclude_re = re.compile (r'\s*!\s*(\S+)') # for manifest lines
|
||||
|
||||
|
||||
def initialize_options (self):
|
||||
# 'template' and 'manifest' are, respectively, the names of
|
||||
# the manifest template and manifest file.
|
||||
self.template = None
|
||||
self.manifest = None
|
||||
|
||||
# 'use_defaults': if true, we will include the default file set
|
||||
# in the manifest
|
||||
self.use_defaults = 1
|
||||
|
||||
self.manifest_only = 0
|
||||
self.force_manifest = 0
|
||||
|
||||
self.formats = None
|
||||
self.list_only = 0
|
||||
self.keep_tree = 0
|
||||
|
||||
|
||||
def finalize_options (self):
|
||||
if self.manifest is None:
|
||||
self.manifest = "MANIFEST"
|
||||
if self.template is None:
|
||||
self.template = "MANIFEST.in"
|
||||
|
||||
if self.formats is None:
|
||||
try:
|
||||
self.formats = [self.default_format[os.name]]
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError, \
|
||||
"don't know how to build source distributions on " + \
|
||||
"%s platform" % os.name
|
||||
elif type (self.formats) is StringType:
|
||||
self.formats = string.split (self.formats, ',')
|
||||
|
||||
|
||||
def run (self):
|
||||
|
||||
# 'files' is the list of files that will make up the manifest
|
||||
self.files = []
|
||||
|
||||
# Ensure that all required meta-data is given; warn if not (but
|
||||
# don't die, it's not *that* serious!)
|
||||
self.check_metadata ()
|
||||
|
||||
# Do whatever it takes to get the list of files to process
|
||||
# (process the manifest template, read an existing manifest,
|
||||
# whatever). File list is put into 'self.files'.
|
||||
self.get_file_list ()
|
||||
|
||||
# If user just wanted us to regenerate the manifest, stop now.
|
||||
if self.manifest_only:
|
||||
return
|
||||
|
||||
# Otherwise, go ahead and create the source distribution tarball,
|
||||
# or zipfile, or whatever.
|
||||
self.make_distribution ()
|
||||
|
||||
|
||||
def check_metadata (self):
|
||||
|
||||
dist = self.distribution
|
||||
|
||||
missing = []
|
||||
for attr in ('name', 'version', 'url'):
|
||||
if not (hasattr (dist, attr) and getattr (dist, attr)):
|
||||
missing.append (attr)
|
||||
|
||||
if missing:
|
||||
self.warn ("missing required meta-data: " +
|
||||
string.join (missing, ", "))
|
||||
|
||||
if dist.author:
|
||||
if not dist.author_email:
|
||||
self.warn ("missing meta-data: if 'author' supplied, " +
|
||||
"'author_email' must be supplied too")
|
||||
elif dist.maintainer:
|
||||
if not dist.maintainer_email:
|
||||
self.warn ("missing meta-data: if 'maintainer' supplied, " +
|
||||
"'maintainer_email' must be supplied too")
|
||||
else:
|
||||
self.warn ("missing meta-data: either (author and author_email) " +
|
||||
"or (maintainer and maintainer_email) " +
|
||||
"must be supplied")
|
||||
|
||||
# check_metadata ()
|
||||
|
||||
|
||||
def get_file_list (self):
|
||||
"""Figure out the list of files to include in the source
|
||||
distribution, and put it in 'self.files'. This might
|
||||
involve reading the manifest template (and writing the
|
||||
manifest), or just reading the manifest, or just using
|
||||
the default file set -- it all depends on the user's
|
||||
options and the state of the filesystem."""
|
||||
|
||||
|
||||
template_exists = os.path.isfile (self.template)
|
||||
if template_exists:
|
||||
template_newer = newer (self.template, self.manifest)
|
||||
|
||||
# Regenerate the manifest if necessary (or if explicitly told to)
|
||||
if ((template_exists and template_newer) or
|
||||
self.force_manifest or
|
||||
self.manifest_only):
|
||||
|
||||
if not template_exists:
|
||||
self.warn (("manifest template '%s' does not exist " +
|
||||
"(using default file list)") %
|
||||
self.template)
|
||||
|
||||
# Add default file set to 'files'
|
||||
if self.use_defaults:
|
||||
self.find_defaults ()
|
||||
|
||||
# Read manifest template if it exists
|
||||
if template_exists:
|
||||
self.read_template ()
|
||||
|
||||
# File list now complete -- sort it so that higher-level files
|
||||
# come first
|
||||
sortable_files = map (os.path.split, self.files)
|
||||
sortable_files.sort ()
|
||||
self.files = []
|
||||
for sort_tuple in sortable_files:
|
||||
self.files.append (apply (os.path.join, sort_tuple))
|
||||
|
||||
# Remove duplicates from the file list
|
||||
for i in range (len(self.files)-1, 0, -1):
|
||||
if self.files[i] == self.files[i-1]:
|
||||
del self.files[i]
|
||||
|
||||
# And write complete file list (including default file set) to
|
||||
# the manifest.
|
||||
self.write_manifest ()
|
||||
|
||||
# Don't regenerate the manifest, just read it in.
|
||||
else:
|
||||
self.read_manifest ()
|
||||
|
||||
# get_file_list ()
|
||||
|
||||
|
||||
def find_defaults (self):
|
||||
|
||||
standards = [('README', 'README.txt'), 'setup.py']
|
||||
for fn in standards:
|
||||
if type (fn) is TupleType:
|
||||
alts = fn
|
||||
got_it = 0
|
||||
for fn in alts:
|
||||
if os.path.exists (fn):
|
||||
got_it = 1
|
||||
self.files.append (fn)
|
||||
break
|
||||
|
||||
if not got_it:
|
||||
self.warn ("standard file not found: should have one of " +
|
||||
string.join (alts, ', '))
|
||||
else:
|
||||
if os.path.exists (fn):
|
||||
self.files.append (fn)
|
||||
else:
|
||||
self.warn ("standard file '%s' not found" % fn)
|
||||
|
||||
optional = ['test/test*.py']
|
||||
for pattern in optional:
|
||||
files = filter (os.path.isfile, glob (pattern))
|
||||
if files:
|
||||
self.files.extend (files)
|
||||
|
||||
if self.distribution.packages or self.distribution.py_modules:
|
||||
build_py = self.find_peer ('build_py')
|
||||
build_py.ensure_ready ()
|
||||
self.files.extend (build_py.get_source_files ())
|
||||
|
||||
if self.distribution.ext_modules:
|
||||
build_ext = self.find_peer ('build_ext')
|
||||
build_ext.ensure_ready ()
|
||||
self.files.extend (build_ext.get_source_files ())
|
||||
|
||||
|
||||
|
||||
def search_dir (self, dir, pattern=None):
|
||||
"""Recursively find files under 'dir' matching 'pattern' (a string
|
||||
containing a Unix-style glob pattern). If 'pattern' is None,
|
||||
find all files under 'dir'. Return the list of found
|
||||
filenames."""
|
||||
|
||||
allfiles = findall (dir)
|
||||
if pattern is None:
|
||||
return allfiles
|
||||
|
||||
pattern_re = translate_pattern (pattern)
|
||||
files = []
|
||||
for file in allfiles:
|
||||
if pattern_re.match (os.path.basename (file)):
|
||||
files.append (file)
|
||||
|
||||
return files
|
||||
|
||||
# search_dir ()
|
||||
|
||||
|
||||
def exclude_pattern (self, pattern):
|
||||
"""Remove filenames from 'self.files' that match 'pattern'."""
|
||||
print "exclude_pattern: pattern=%s" % pattern
|
||||
pattern_re = translate_pattern (pattern)
|
||||
for i in range (len (self.files)-1, -1, -1):
|
||||
if pattern_re.match (self.files[i]):
|
||||
print "removing %s" % self.files[i]
|
||||
del self.files[i]
|
||||
|
||||
|
||||
def recursive_exclude_pattern (self, dir, pattern=None):
|
||||
"""Remove filenames from 'self.files' that are under 'dir'
|
||||
and whose basenames match 'pattern'."""
|
||||
|
||||
print "recursive_exclude_pattern: dir=%s, pattern=%s" % (dir, pattern)
|
||||
if pattern is None:
|
||||
pattern_re = None
|
||||
else:
|
||||
pattern_re = translate_pattern (pattern)
|
||||
|
||||
for i in range (len (self.files)-1, -1, -1):
|
||||
(cur_dir, cur_base) = os.path.split (self.files[i])
|
||||
if (cur_dir == dir and
|
||||
(pattern_re is None or pattern_re.match (cur_base))):
|
||||
print "removing %s" % self.files[i]
|
||||
del self.files[i]
|
||||
|
||||
|
||||
def read_template (self):
|
||||
"""Read and parse the manifest template file named by
|
||||
'self.template' (usually "MANIFEST.in"). Process all file
|
||||
specifications (include and exclude) in the manifest template
|
||||
and add the resulting filenames to 'self.files'."""
|
||||
|
||||
assert self.files is not None and type (self.files) is ListType
|
||||
|
||||
template = TextFile (self.template,
|
||||
strip_comments=1,
|
||||
skip_blanks=1,
|
||||
join_lines=1,
|
||||
lstrip_ws=1,
|
||||
rstrip_ws=1,
|
||||
collapse_ws=1)
|
||||
|
||||
all_files = findall ()
|
||||
|
||||
while 1:
|
||||
|
||||
line = template.readline()
|
||||
if line is None: # end of file
|
||||
break
|
||||
|
||||
words = string.split (line)
|
||||
action = words[0]
|
||||
|
||||
# First, check that the right number of words are present
|
||||
# for the given action (which is the first word)
|
||||
if action in ('include','exclude',
|
||||
'global-include','global-exclude'):
|
||||
if len (words) != 2:
|
||||
template.warn \
|
||||
("invalid manifest template line: " +
|
||||
"'%s' expects a single <pattern>" %
|
||||
action)
|
||||
continue
|
||||
|
||||
pattern = words[1]
|
||||
|
||||
elif action in ('recursive-include','recursive-exclude'):
|
||||
if len (words) != 3:
|
||||
template.warn \
|
||||
("invalid manifest template line: " +
|
||||
"'%s' expects <dir> <pattern>" %
|
||||
action)
|
||||
continue
|
||||
|
||||
(dir, pattern) = words[1:3]
|
||||
|
||||
elif action in ('graft','prune'):
|
||||
if len (words) != 2:
|
||||
template.warn \
|
||||
("invalid manifest template line: " +
|
||||
"'%s' expects a single <dir_pattern>" %
|
||||
action)
|
||||
continue
|
||||
|
||||
dir_pattern = words[1]
|
||||
|
||||
else:
|
||||
template.warn ("invalid manifest template line: " +
|
||||
"unknown action '%s'" % action)
|
||||
continue
|
||||
|
||||
# OK, now we know that the action is valid and we have the
|
||||
# right number of words on the line for that action -- so we
|
||||
# can proceed with minimal error-checking. Also, we have
|
||||
# defined either 'patter', 'dir' and 'pattern', or
|
||||
# 'dir_pattern' -- so we don't have to spend any time digging
|
||||
# stuff up out of 'words'.
|
||||
|
||||
if action == 'include':
|
||||
print "include", pattern
|
||||
files = select_pattern (all_files, pattern, anchor=1)
|
||||
if not files:
|
||||
template.warn ("no files found matching '%s'" % pattern)
|
||||
else:
|
||||
self.files.extend (files)
|
||||
|
||||
elif action == 'exclude':
|
||||
print "exclude", pattern
|
||||
num = exclude_pattern (self.files, pattern, anchor=1)
|
||||
if num == 0:
|
||||
template.warn \
|
||||
("no previously-included files found matching '%s'" %
|
||||
pattern)
|
||||
|
||||
elif action == 'global-include':
|
||||
print "global-include", pattern
|
||||
files = select_pattern (all_files, pattern, anchor=0)
|
||||
if not files:
|
||||
template.warn (("no files found matching '%s' " +
|
||||
"anywhere in distribution") %
|
||||
pattern)
|
||||
else:
|
||||
self.files.extend (files)
|
||||
|
||||
elif action == 'global-exclude':
|
||||
print "global-exclude", pattern
|
||||
num = exclude_pattern (self.files, pattern, anchor=0)
|
||||
if num == 0:
|
||||
template.warn \
|
||||
(("no previously-included files matching '%s' " +
|
||||
"found anywhere in distribution") %
|
||||
pattern)
|
||||
|
||||
elif action == 'recursive-include':
|
||||
print "recursive-include", dir, pattern
|
||||
files = select_pattern (all_files, pattern, prefix=dir)
|
||||
if not files:
|
||||
template.warn (("no files found matching '%s' " +
|
||||
"under directory '%s'") %
|
||||
(pattern, dir))
|
||||
else:
|
||||
self.files.extend (files)
|
||||
|
||||
elif action == 'recursive-exclude':
|
||||
print "recursive-exclude", dir, pattern
|
||||
num = exclude_pattern (self.files, pattern, prefix=dir)
|
||||
if num == 0:
|
||||
template.warn \
|
||||
(("no previously-included files matching '%s' " +
|
||||
"found under directory '%s'") %
|
||||
(pattern, dir))
|
||||
|
||||
elif action == 'graft':
|
||||
print "graft", dir_pattern
|
||||
files = select_pattern (all_files, None, prefix=dir_pattern)
|
||||
if not files:
|
||||
template.warn ("no directories found matching '%s'" %
|
||||
dir_pattern)
|
||||
else:
|
||||
self.files.extend (files)
|
||||
|
||||
elif action == 'prune':
|
||||
print "prune", dir_pattern
|
||||
num = exclude_pattern (self.files, None, prefix=dir_pattern)
|
||||
if num == 0:
|
||||
template.warn \
|
||||
(("no previously-included directories found " +
|
||||
"matching '%s'") %
|
||||
dir_pattern)
|
||||
else:
|
||||
raise RuntimeError, \
|
||||
"this cannot happen: invalid action '%s'" % action
|
||||
|
||||
# while loop over lines of template file
|
||||
|
||||
# read_template ()
|
||||
|
||||
|
||||
def write_manifest (self):
|
||||
"""Write the file list in 'self.files' (presumably as filled in
|
||||
by 'find_defaults()' and 'read_template()') to the manifest file
|
||||
named by 'self.manifest'."""
|
||||
|
||||
manifest = open (self.manifest, "w")
|
||||
for fn in self.files:
|
||||
manifest.write (fn + '\n')
|
||||
manifest.close ()
|
||||
|
||||
# write_manifest ()
|
||||
|
||||
|
||||
def read_manifest (self):
|
||||
"""Read the manifest file (named by 'self.manifest') and use
|
||||
it to fill in 'self.files', the list of files to include
|
||||
in the source distribution."""
|
||||
|
||||
manifest = open (self.manifest)
|
||||
while 1:
|
||||
line = manifest.readline ()
|
||||
if line == '': # end of file
|
||||
break
|
||||
if line[-1] == '\n':
|
||||
line = line[0:-1]
|
||||
self.files.append (line)
|
||||
|
||||
# read_manifest ()
|
||||
|
||||
|
||||
|
||||
def make_release_tree (self, base_dir, files):
|
||||
|
||||
# First get the list of directories to create
|
||||
need_dir = {}
|
||||
for file in files:
|
||||
need_dir[os.path.join (base_dir, os.path.dirname (file))] = 1
|
||||
need_dirs = need_dir.keys()
|
||||
need_dirs.sort()
|
||||
|
||||
# Now create them
|
||||
for dir in need_dirs:
|
||||
self.mkpath (dir)
|
||||
|
||||
# And walk over the list of files, either making a hard link (if
|
||||
# os.link exists) to each one that doesn't already exist in its
|
||||
# corresponding location under 'base_dir', or copying each file
|
||||
# that's out-of-date in 'base_dir'. (Usually, all files will be
|
||||
# out-of-date, because by default we blow away 'base_dir' when
|
||||
# we're done making the distribution archives.)
|
||||
|
||||
try:
|
||||
link = os.link
|
||||
msg = "making hard links in %s..." % base_dir
|
||||
except AttributeError:
|
||||
link = 0
|
||||
msg = "copying files to %s..." % base_dir
|
||||
|
||||
self.announce (msg)
|
||||
for file in files:
|
||||
dest = os.path.join (base_dir, file)
|
||||
if link:
|
||||
if not os.path.exists (dest):
|
||||
self.execute (os.link, (file, dest),
|
||||
"linking %s -> %s" % (file, dest))
|
||||
else:
|
||||
self.copy_file (file, dest)
|
||||
|
||||
# make_release_tree ()
|
||||
|
||||
|
||||
def make_tarball (self, base_dir, compress="gzip"):
|
||||
|
||||
# XXX GNU tar 1.13 has a nifty option to add a prefix directory.
|
||||
# It's pretty new, though, so we certainly can't require it --
|
||||
# but it would be nice to take advantage of it to skip the
|
||||
# "create a tree of hardlinks" step! (Would also be nice to
|
||||
# detect GNU tar to use its 'z' option and save a step.)
|
||||
|
||||
if compress is not None and compress not in ('gzip', 'compress'):
|
||||
raise ValueError, \
|
||||
"if given, 'compress' must be 'gzip' or 'compress'"
|
||||
|
||||
archive_name = base_dir + ".tar"
|
||||
self.spawn (["tar", "-cf", archive_name, base_dir])
|
||||
|
||||
if compress:
|
||||
self.spawn ([compress, archive_name])
|
||||
|
||||
|
||||
def make_zipfile (self, base_dir):
|
||||
|
||||
# This initially assumed the Unix 'zip' utility -- but
|
||||
# apparently InfoZIP's zip.exe works the same under Windows, so
|
||||
# no changes needed!
|
||||
|
||||
try:
|
||||
self.spawn (["zip", "-r", base_dir + ".zip", base_dir])
|
||||
except DistutilsExecError:
|
||||
|
||||
# XXX really should distinguish between "couldn't find
|
||||
# external 'zip' command" and "zip failed" -- shouldn't try
|
||||
# again in the latter case. (I think fixing this will
|
||||
# require some cooperation from the spawn module -- perhaps
|
||||
# a utility function to search the path, so we can fallback
|
||||
# on zipfile.py without the failed spawn.)
|
||||
try:
|
||||
import zipfile
|
||||
except ImportError:
|
||||
raise DistutilsExecError, \
|
||||
("unable to create zip file '%s.zip': " +
|
||||
"could neither find a standalone zip utility nor " +
|
||||
"import the 'zipfile' module") % base_dir
|
||||
|
||||
z = zipfile.ZipFile (base_dir + ".zip", "wb",
|
||||
compression=zipfile.ZIP_DEFLATED)
|
||||
|
||||
def visit (z, dirname, names):
|
||||
for name in names:
|
||||
path = os.path.join (dirname, name)
|
||||
if os.path.isfile (path):
|
||||
z.write (path, path)
|
||||
|
||||
os.path.walk (base_dir, visit, z)
|
||||
z.close()
|
||||
|
||||
|
||||
def make_distribution (self):
|
||||
|
||||
# Don't warn about missing meta-data here -- should be done
|
||||
# elsewhere.
|
||||
name = self.distribution.name or "UNKNOWN"
|
||||
version = self.distribution.version
|
||||
|
||||
if version:
|
||||
base_dir = "%s-%s" % (name, version)
|
||||
else:
|
||||
base_dir = name
|
||||
|
||||
# Remove any files that match "base_dir" from the fileset -- we
|
||||
# don't want to go distributing the distribution inside itself!
|
||||
self.exclude_pattern (base_dir + "*")
|
||||
|
||||
self.make_release_tree (base_dir, self.files)
|
||||
for fmt in self.formats:
|
||||
if fmt == 'gztar':
|
||||
self.make_tarball (base_dir, compress='gzip')
|
||||
elif fmt == 'ztar':
|
||||
self.make_tarball (base_dir, compress='compress')
|
||||
elif fmt == 'tar':
|
||||
self.make_tarball (base_dir, compress=None)
|
||||
elif fmt == 'zip':
|
||||
self.make_zipfile (base_dir)
|
||||
|
||||
if not self.keep_tree:
|
||||
remove_tree (base_dir, self.verbose, self.dry_run)
|
||||
|
||||
# class Dist
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Utility functions
|
||||
|
||||
def findall (dir = os.curdir):
|
||||
"""Find all files under 'dir' and return the list of full
|
||||
filenames (relative to 'dir')."""
|
||||
|
||||
list = []
|
||||
stack = [dir]
|
||||
pop = stack.pop
|
||||
push = stack.append
|
||||
|
||||
while stack:
|
||||
dir = pop()
|
||||
names = os.listdir (dir)
|
||||
|
||||
for name in names:
|
||||
if dir != os.curdir: # avoid the dreaded "./" syndrome
|
||||
fullname = os.path.join (dir, name)
|
||||
else:
|
||||
fullname = name
|
||||
list.append (fullname)
|
||||
if os.path.isdir (fullname) and not os.path.islink(fullname):
|
||||
push (fullname)
|
||||
|
||||
return list
|
||||
|
||||
|
||||
def select_pattern (files, pattern, anchor=1, prefix=None):
|
||||
"""Select strings (presumably filenames) from 'files' that match
|
||||
'pattern', a Unix-style wildcard (glob) pattern. Patterns are not
|
||||
quite the same as implemented by the 'fnmatch' module: '*' and '?'
|
||||
match non-special characters, where "special" is platform-dependent:
|
||||
slash on Unix, colon, slash, and backslash on DOS/Windows, and colon
|
||||
on Mac OS.
|
||||
|
||||
If 'anchor' is true (the default), then the pattern match is more
|
||||
stringent: "*.py" will match "foo.py" but not "foo/bar.py". If
|
||||
'anchor' is false, both of these will match.
|
||||
|
||||
If 'prefix' is supplied, then only filenames starting with 'prefix'
|
||||
(itself a pattern) and ending with 'pattern', with anything in
|
||||
between them, will match. 'anchor' is ignored in this case.
|
||||
|
||||
Return the list of matching strings, possibly empty."""
|
||||
|
||||
matches = []
|
||||
pattern_re = translate_pattern (pattern, anchor, prefix)
|
||||
print "select_pattern: applying re %s" % pattern_re.pattern
|
||||
for name in files:
|
||||
if pattern_re.search (name):
|
||||
matches.append (name)
|
||||
print " adding", name
|
||||
|
||||
return matches
|
||||
|
||||
# select_pattern ()
|
||||
|
||||
|
||||
def exclude_pattern (files, pattern, anchor=1, prefix=None):
|
||||
|
||||
pattern_re = translate_pattern (pattern, anchor, prefix)
|
||||
print "exclude_pattern: applying re %s" % pattern_re.pattern
|
||||
for i in range (len(files)-1, -1, -1):
|
||||
if pattern_re.search (files[i]):
|
||||
print " removing", files[i]
|
||||
del files[i]
|
||||
|
||||
# exclude_pattern ()
|
||||
|
||||
|
||||
def glob_to_re (pattern):
|
||||
"""Translate a shell-like glob pattern to a regular expression;
|
||||
return a string containing the regex. Differs from
|
||||
'fnmatch.translate()' in that '*' does not match "special
|
||||
characters" (which are platform-specific)."""
|
||||
pattern_re = fnmatch.translate (pattern)
|
||||
|
||||
# '?' and '*' in the glob pattern become '.' and '.*' in the RE, which
|
||||
# IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix,
|
||||
# and by extension they shouldn't match such "special characters" under
|
||||
# any OS. So change all non-escaped dots in the RE to match any
|
||||
# character except the special characters.
|
||||
# XXX currently the "special characters" are just slash -- i.e. this is
|
||||
# Unix-only.
|
||||
pattern_re = re.sub (r'(^|[^\\])\.', r'\1[^/]', pattern_re)
|
||||
return pattern_re
|
||||
|
||||
# glob_to_re ()
|
||||
|
||||
|
||||
def translate_pattern (pattern, anchor=1, prefix=None):
|
||||
"""Translate a shell-like wildcard pattern to a compiled regular
|
||||
expression. Return the compiled regex."""
|
||||
|
||||
if pattern:
|
||||
pattern_re = glob_to_re (pattern)
|
||||
else:
|
||||
pattern_re = ''
|
||||
|
||||
if prefix is not None:
|
||||
prefix_re = (glob_to_re (prefix))[0:-1] # ditch trailing $
|
||||
pattern_re = "^" + os.path.join (prefix_re, ".*" + pattern_re)
|
||||
else: # no prefix -- respect anchor flag
|
||||
if anchor:
|
||||
pattern_re = "^" + pattern_re
|
||||
|
||||
return re.compile (pattern_re)
|
||||
|
||||
# translate_pattern ()
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import httplib,urlparse,sys,time
|
||||
import http11lib,urlparse,sys,time
|
||||
from UrlData import UrlData
|
||||
from RobotsTxt import RobotsTxt
|
||||
import Config,StringUtil
|
||||
|
|
@ -116,7 +116,7 @@ class HttpUrlData(UrlData):
|
|||
return self.urlConnection.getreply()
|
||||
|
||||
def _getHTTPObject(self, host):
|
||||
return httplib.HTTP(host)
|
||||
return http11lib.HTTP(host)
|
||||
|
||||
def getContent(self):
|
||||
self.closeConnection()
|
||||
|
|
@ -124,7 +124,7 @@ class HttpUrlData(UrlData):
|
|||
self._getHttpRequest("GET")
|
||||
self.urlConnection = self.urlConnection.getfile()
|
||||
data = StringUtil.stripHtmlComments(self.urlConnection.read())
|
||||
self.time = time.time() - t
|
||||
self.downloadtime = time.time() - t
|
||||
Config.debug(Config.DebugDelim+data+Config.DebugDelim)
|
||||
return data
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,8 @@ class StandardLogger:
|
|||
self.fd.write(" found.\n")
|
||||
self.stoptime = time.time()
|
||||
self.fd.write("Stopped checking at "+_strtime(self.stoptime)+
|
||||
(" (%.3f seconds)" % (self.stoptime - self.starttime)))
|
||||
(" (%.3f seconds)" % (self.stoptime - self.starttime))+
|
||||
"\n")
|
||||
self.fd.flush()
|
||||
self.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class UrlData:
|
|||
recursionLevel,
|
||||
parentName = None,
|
||||
baseRef = None,
|
||||
line = None, _time = None):
|
||||
line = None):
|
||||
self.urlName = urlName
|
||||
self.recursionLevel = recursionLevel
|
||||
self.parentName = parentName
|
||||
|
|
@ -30,7 +30,7 @@ class UrlData:
|
|||
self.valid = 1
|
||||
self.url = None
|
||||
self.line = line
|
||||
self.downloadtime = _time
|
||||
self.downloadtime = None
|
||||
self.checktime = None
|
||||
self.cached = 0
|
||||
self.urlConnection = None
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import getopt,sys,re,string
|
||||
import sys
|
||||
|
||||
if sys.version[:5] < "1.5.2":
|
||||
print "This program requires Python 1.5.2 or later."
|
||||
sys.exit(1)
|
||||
|
||||
# add the path to linkcheck module
|
||||
#sys.path.insert(0, "/home/calvin/projects/linkchecker")
|
||||
|
||||
import linkcheck
|
||||
# add the path to linkcheck module if you install it manually somewhere
|
||||
#sys.path.append("/home/calvin/projects/linkchecker")
|
||||
import getopt,re,string,linkcheck
|
||||
|
||||
Usage = """USAGE\tlinkchecker [options] file_or_url...
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
@echo off
|
||||
|
||||
rem === adjust vars below ===
|
||||
set PYTHON=c:\progra~1\python\python.exe
|
||||
set LINKCHECKER=c:\progra~1\linkchecker-1.1.2
|
||||
rem === end configure ===
|
||||
|
||||
%PYTHON% %LINKCHECKER%\linkchecker %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
rem Limited to 9 parameters? Is there a $* for Windows?
|
||||
python @INSTALL_BIN@\linkchecker %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
|
|
|
|||
Loading…
Reference in a new issue