| 1 | """my_install_data.py |
| 2 | |
| 3 | Provides a more sophisticated facility to install data files |
| 4 | than distutils' install_data does. |
| 5 | You can specify your files as a template like in MANIFEST.in |
| 6 | and you have more control over the copy process. |
| 7 | |
| 8 | """ |
| 9 | |
| 10 | # created 2000/08/01, Rene Liebscher <R.Liebscher@gmx.de> |
| 11 | |
| 12 | ########################################################################### |
| 13 | # import some modules we need |
| 14 | |
| 15 | import os,sys,string |
| 16 | from types import StringType,TupleType,ListType |
| 17 | from distutils.util import change_root |
| 18 | from distutils.filelist import FileList |
| 19 | from distutils.command.install_data import install_data |
| 20 | |
| 21 | ########################################################################### |
| 22 | # a container class for our more sophisticated install mechanism |
| 23 | |
| 24 | class Data_Files: |
| 25 | """ container for list of data files. |
| 26 | supports alternate base_dirs e.g. 'install_lib','install_header',... |
| 27 | supports a directory where to copy files |
| 28 | supports templates as in MANIFEST.in |
| 29 | supports preserving of paths in filenames |
| 30 | eg. foo/xyz is copied to base_dir/foo/xyz |
| 31 | supports stripping of leading dirs of source paths |
| 32 | eg. foo/bar1/xyz, foo/bar2/abc can be copied to bar1/xyz, bar2/abc |
| 33 | """ |
| 34 | |
| 35 | def __init__(self,base_dir=None,files=None,copy_to=None,template=None,preserve_path=0,strip_dirs=0): |
| 36 | self.base_dir = base_dir |
| 37 | self.files = files |
| 38 | self.copy_to = copy_to |
| 39 | self.template = template |
| 40 | self.preserve_path = preserve_path |
| 41 | self.strip_dirs = strip_dirs |
| 42 | self.finalized = 0 |
| 43 | |
| 44 | def warn (self, msg): |
| 45 | sys.stderr.write ("warning: %s: %s\n" % |
| 46 | ("install_data", msg)) |
| 47 | |
| 48 | def debug_print (self, msg): |
| 49 | """Print 'msg' to stdout if the global DEBUG (taken from the |
| 50 | DISTUTILS_DEBUG environment variable) flag is true. |
| 51 | """ |
| 52 | from distutils.core import DEBUG |
| 53 | if DEBUG: |
| 54 | print msg |
| 55 | |
| 56 | |
| 57 | def finalize(self): |
| 58 | """ complete the files list by processing the given template """ |
| 59 | if self.finalized: |
| 60 | return |
| 61 | if self.files == None: |
| 62 | self.files = [] |
| 63 | if self.template != None: |
| 64 | if type(self.template) == StringType: |
| 65 | self.template = string.split(self.template,";") |
| 66 | filelist = FileList(self.warn,self.debug_print) |
| 67 | for line in self.template: |
| 68 | filelist.process_template_line(string.strip(line)) |
| 69 | filelist.sort() |
| 70 | filelist.remove_duplicates() |
| 71 | self.files.extend(filelist.files) |
| 72 | self.finalized = 1 |
| 73 | |
| 74 | # end class Data_Files |
| 75 | |
| 76 | ########################################################################### |
| 77 | # a more sophisticated install routine than distutils install_data |
| 78 | |
| 79 | class my_install_data (install_data): |
| 80 | |
| 81 | def check_data(self,d): |
| 82 | """ check if data are in new format, if not create a suitable object. |
| 83 | returns finalized data object |
| 84 | """ |
| 85 | if not isinstance(d, Data_Files): |
| 86 | self.warn(("old-style data files list found " |
| 87 | "-- please convert to Data_Files instance")) |
| 88 | if type(d) is TupleType: |
| 89 | if len(d) != 2 or not (type(d[1]) is ListType): |
| 90 | raise DistutilsSetupError, \ |
| 91 | ("each element of 'data_files' option must be an " |
| 92 | "Data File instance, a string or 2-tuple (string,[strings])") |
| 93 | d = Data_Files(copy_to=d[0],files=d[1]) |
| 94 | else: |
| 95 | if not (type(d) is StringType): |
| 96 | raise DistutilsSetupError, \ |
| 97 | ("each element of 'data_files' option must be an " |
| 98 | "Data File instance, a string or 2-tuple (string,[strings])") |
| 99 | d = Data_Files(files=[d]) |
| 100 | d.finalize() |
| 101 | return d |
| 102 | |
| 103 | def run(self): |
| 104 | self.outfiles = [] |
| 105 | install_cmd = self.get_finalized_command('install') |
| 106 | |
| 107 | for d in self.data_files: |
| 108 | d = self.check_data(d) |
| 109 | |
| 110 | install_dir = self.install_dir |
| 111 | # alternative base dir given => overwrite install_dir |
| 112 | if d.base_dir != None: |
| 113 | install_dir = getattr(install_cmd,d.base_dir) |
| 114 | |
| 115 | # copy to an other directory |
| 116 | if d.copy_to != None: |
| 117 | if not os.path.isabs(d.copy_to): |
| 118 | # relatiev path to install_dir |
| 119 | dir = os.path.join(install_dir, d.copy_to) |
| 120 | elif install_cmd.root: |
| 121 | # absolute path and alternative root set |
| 122 | dir = change_root(self.root,d.copy_to) |
| 123 | else: |
| 124 | # absolute path |
| 125 | dir = d.copy_to |
| 126 | else: |
| 127 | # simply copy to install_dir |
| 128 | dir = install_dir |
| 129 | # warn if necceassary |
| 130 | self.warn("setup script did not provide a directory to copy files to " |
| 131 | " -- installing right in '%s'" % install_dir) |
| 132 | |
| 133 | dir=os.path.normpath(dir) |
| 134 | # create path |
| 135 | self.mkpath(dir) |
| 136 | |
| 137 | # copy all files |
| 138 | for src in d.files: |
| 139 | if d.strip_dirs > 0: |
| 140 | dst = string.join(string.split(os.path.normcase(src),os.sep)[d.strip_dirs:],os.sep) |
| 141 | else: |
| 142 | dst = src |
| 143 | if d.preserve_path: |
| 144 | # preserve path in filename |
| 145 | self.mkpath(os.path.dirname(os.path.join(dir,dst))) |
| 146 | out = self.copy_file(src, os.path.join(dir,dst)) |
| 147 | else: |
| 148 | out = self.copy_file(src, dir) |
| 149 | if type(out) is TupleType: |
| 150 | out = out[0] |
| 151 | self.outfiles.append(out) |
| 152 | |
| 153 | return self.outfiles |
| 154 | |
| 155 | def get_inputs (self): |
| 156 | inputs = [] |
| 157 | for d in self.data_files: |
| 158 | d = self.check_data(d) |
| 159 | inputs.append(d.files) |
| 160 | return inputs |
| 161 | |
| 162 | def get_outputs (self): |
| 163 | return self.outfiles |
| 164 | |
| 165 | |
| 166 | ########################################################################### |
| 167 | |