# # $HeadURL: https://www.stsci.edu/svn/ssb/stsci_python/stsci_python/trunk/pytools/lib/stsci_distutils_hack.py $ # $Rev: 7093 $ # # Implements setup.py code common to many of our packages. # # The new standard stsci module setup.py is just # # import pytools.stsci_distutils_hack # pytools.stsci_distutils_hack.run( pytools_version = "XX" ) # # where XX is the version of pytools you expect for the install to work # ######## ######## ######## ######## ######## ######## ######## ######## # # actually perform the install # # NOTE: This is not used to install pytools itself! import sys def run( pytools_version = None ) : if not hasattr(sys, 'version_info') or sys.version_info < (2,3,0,'alpha',0): raise SystemExit, "Python 2.3 or later required." if pytools_version : # Only try to import pytools if we are asked to check for a version. # # ( We may have been extracted from pytools and bundled with a package. # In that case, we do not want to risk finding some _other_ pytools # and comparing that version. ) import pytools # bug: should use distutils version comparator to perform ">" comparisons if ( pytools.__version__ != pytools_version ) : print "wrong version of pytools!" print "have ",pytools.__version__ print "want ",pytools_version sys.exit(1) from distutils.core import setup from defsetup import setupargs, pkg # collect our subversion information __set_svn_version__() # save the date when we last ran setup.py __set_setup_date__() if "version" in sys.argv : sys.exit(0) # If they have multiple packages, we have to allow them to give a list. # That is the unusual case, so we let them give a string if they have a single # package. if isinstance(pkg,str) : pkg = [ pkg ] # If they have multiple packages, they have to specify package_dir. Otherwise, # we can create one for them. if not 'package_dir' in setupargs : setupargs['package_dir'] = { pkg[0] : 'lib' } setup( name = pkg[0], packages = pkg, **setupargs ) ######## ######## ######## ######## ######## ######## ######## ######## # # This part fixes install_data to put data files in the same directory # with the python library files, which is where our packages want # them. # # This is essentially "smart_install_data" as used in the old # setup.py files, except that it also understands wildcards # and os-specific paths. This means the module author can # ask for data files with # "data/generic/*" # instead of # glob.glob(os.path.join('data', 'generic', '*')) import os import glob import distutils.util import distutils.command.install_data o = distutils.command.install_data.install_data # same trick as smart_install_data used: save the old run() method and # insert our own run method ahead of it o.old_run = o.run def new_run ( self ) : # We want our data files in the directory with the library files install_cmd = self.get_finalized_command('install') self.install_dir = getattr(install_cmd, 'install_lib') # self.data_files is a list of # ( destination_directory, [ source_file, source_file, source_file ] ) # # We want to do wildcard expansion on all the file names. # l = [ ] for f in self.data_files : ( dest_dir, files ) = f fl = [ ] for ff in files : ff = distutils.util.convert_path(ff) ff = glob.glob(ff) fl.extend(ff) dest_dir = distutils.util.convert_path(dest_dir) l.append( ( dest_dir, fl ) ) self.data_files = l # now use the original run() function to finish return distutils.command.install_data.install_data.old_run(self) o.run = new_run ######## ######## ######## ######## ######## ######## ######## ######## # # Implements "python setup.py install --place=dir" # # This replaces --local from earlier stsci_python releases. The # flag is different because it doesn't quite do the same thing. # # --place=$dir means that # scripts go into $dir/bin # python code goes into $dir/lib # # This is a less complicated structure than you get from --prefix and --home. import distutils.command.install # same trick as smart_install_data used: save the old run() method and # insert our own run method ahead of it o = distutils.command.install.install o.old_finalize_unix = o.finalize_unix o.old_finalize_other = o.finalize_other # INSTALL_SCHEMES are effectively a list of where to put different kinds # of files. It exists so you can have complex structures like what # --prefix does. We want a simpler one, so here it is. distutils.command.install.INSTALL_SCHEMES['unix_place'] = { 'purelib': '$base/lib', 'platlib': '$base/lib', 'headers': '$base/include', 'scripts': '$base/bin', 'data' : '$base/lib', } def new_finalize_unix(self) : # this is handled just like --home, but with a different scheme name # see finalize_unix() in distutils/command/install.py if self.place : self.install_base = self.install_platbase = self.place self.select_scheme("unix_place") return self.old_finalize_unix() def new_finalize_other(self) : # need to think about what to do for windows # (distutils says that macs come through here, but macs use finalize_unix) self.old_finalize_unix() o.finalize_unix = new_finalize_unix o.finalize_other = new_finalize_other # to make a new option "--foo", you need to create a variable named # "foo" in the object and add an entry to user_options[] o.place = None o.user_options.append( ( "place=", None, "Specify place to install" ) ) ######## ######## ######## ######## ######## ######## ######## ######## # # Function to collect svn version information - used to be stsci_python/version.py # with multiple copies in the system. # import os.path import re # # This is the entry point. All you need to do is call this function from your # setup.py according to the example above. It will create a file called # lib/svn_version.py ; After that, you can # # # find out what subversion information applies to yourpackage # import yourpackage.svn_version # print yourpackage.svn_version.__svn_version__ # print yourpackage.svn_version.__full_svn_info__ # def __set_svn_version__(path="./", fname='svn_version.py' ) : # # path is the package where the version information will be stored. Default # is "this package", but from a higher level package, you can specify a directory # of a package to process # # fname is the name of the file to store the version information in. Never change # this. # info = None rev = __get_svn_rev__(path) version_file = os.path.join(path,'lib',fname) # if we are unable to determine the revision, we default to leaving the # revision file unchanged. Otherwise, we fill it in with whatever # we have if rev is None: if os.path.exists(version_file) : return revision = 'Unable to determine SVN revision' else: if ( rev == 'exported' or rev == 'unknown' ) and os.path.exists(version_file) : return revision = str(rev) info = __get_full_info__(path) # now we can write the version information f = open(version_file,'w') f.write("__svn_version__ = %s\n" % repr(revision)) # info will be a multi-line string. We are not using repr(info) # for readability; the output of "svn info" can not contain ''' # unless you are doing something bad. f.write("\n__full_svn_info__ = '''\n%s'''\n\n" % info) f.close() def __get_svn_rev__(path): m = None try: # with popen3, stderr goes into a pipe where we ignore it, # This means the user does not see errors. cmd = 'svnversion '+path (sin, sout, serr) = os.popen3(cmd) # pick up the first line of output m=sout.read().strip() # if it looks like valid svnversion output, return it if m == 'exported' : return m if re.match('^[0-9][0-9:]*[A-Z]*$',m) : return m # if we get here, it was not valid - that probably means # an error of some kind. except: pass return None def __get_full_info__(path): info = None try: # with popen3, stderr goes into a pipe where we ignore it, # This means the user does not see errors. (sin, sout, serr) = os.popen3('svn info %s' % path) # pick up all the lines of output info = [l.strip() for l in sout.readlines()] # if no output, there was an error and we don't know anything if len(info) == 0 : return "unknown" # there was output, so join it all together return '\n'.join(info) except: pass return "unknown" ######## ######## ######## ######## ######## ######## ######## ######## # # note when we last ran setup.py -- what we really want is when the # software was installed, but we can use the time we ran setup.py as # a proxy for that. # def __set_setup_date__( path="./", fname='svn_version.py') : import datetime file = os.path.join(path,'lib',fname) d = datetime.datetime.now() l = [ ] try : # we don't expect this to fail ever, but it might f = open(file,"r") for line in f : if line.find("# setupdate") < 0 : l.append(line) f.close() except IOError : pass f=open(file,"w") for line in l : f.write(line) f.write("%s # setupdate\n" % "import datetime") f.write("%s # setupdate\n" % ("setupdate = "+repr(d))) f.close()