install_lib.py 6.02 KB
Newer Older
1 2
# created 1999/03/13, Greg Ward

3
__revision__ = "$Id$"
4

5
import sys, os, string
6
from distutils.core import Command
7
from distutils.dir_util import copy_tree
8

Greg Ward's avatar
Greg Ward committed
9
class install_lib (Command):
10

Greg Ward's avatar
Greg Ward committed
11
    description = "install all Python modules (extensions and pure Python)"
12

13 14 15
    user_options = [
        ('install-dir=', 'd', "directory to install to"),
        ('build-dir=','b', "build directory (where to install from)"),
16
        ('force', 'f', "force installation (overwrite existing files)"),
17 18
        ('compile', 'c', "compile .py to .pyc"),
        ('optimize', 'o', "compile .py to .pyo (optimized)"),
19
        ('skip-build', None, "skip the build steps"),
20
        ]
21
               
22 23
    boolean_options = ['force', 'compile', 'optimize', 'skip-build']

24

25
    def initialize_options (self):
26
        # let the 'install' command dictate our installation directory
27
        self.install_dir = None
28
        self.build_dir = None
29
        self.force = 0
30 31
        self.compile = 1
        self.optimize = 1
32
        self.skip_build = None
33

34
    def finalize_options (self):
35

36 37 38
        # 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.
Greg Ward's avatar
Greg Ward committed
39 40 41 42 43 44 45 46
        self.set_undefined_options('install',
                                   ('build_lib', 'build_dir'),
                                   ('install_lib', 'install_dir'),
                                   ('force', 'force'),
                                   ('compile_py', 'compile'),
                                   ('optimize_py', 'optimize'),
                                   ('skip_build', 'skip_build'),
                                  )
47 48 49

    def run (self):

50
        # Make sure we have built everything we need first
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
        self.build()
        
        # Install everything: simply dump the entire contents of the build
        # directory to the installation directory (that's the beauty of
        # having a build directory!)
        outfiles = self.install()

        # (Optionally) compile .py to .pyc
        self.bytecompile(outfiles)

    # run ()


    # -- Top-level worker functions ------------------------------------
    # (called from 'run()')

    def build (self):
68 69
        if not self.skip_build:
            if self.distribution.has_pure_modules():
Greg Ward's avatar
Greg Ward committed
70
                self.run_command('build_py')
71
            if self.distribution.has_ext_modules():
Greg Ward's avatar
Greg Ward committed
72
                self.run_command('build_ext')
73 74
        
    def install (self):
75
        if os.path.isdir(self.build_dir):
Greg Ward's avatar
Greg Ward committed
76
            outfiles = self.copy_tree(self.build_dir, self.install_dir)
77 78 79 80
        else:
            self.warn("'%s' does not exist -- no Python modules to install" %
                      self.build_dir)
            return
81
        return outfiles
82

83
    def bytecompile (self, files):
84 85 86 87 88 89
        # 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

90
            for f in files:
91 92
                # only compile the file if it is actually a .py file
                if f[-3:] == '.py':
93 94
                    out_fn = f + (__debug__ and "c" or "o")
                    compile_msg = "byte-compiling %s to %s" % \
Greg Ward's avatar
Greg Ward committed
95
                                  (f, os.path.basename(out_fn))
96
                    skip_msg = "skipping byte-compilation of %s" % f
Greg Ward's avatar
Greg Ward committed
97 98
                    self.make_file(f, out_fn, compile, (f,),
                                   compile_msg, skip_msg)
99

100

101 102
    # -- Utility methods -----------------------------------------------

103 104 105 106 107
    def _mutate_outputs (self, has_any, build_cmd, cmd_option, output_dir):

        if not has_any:
            return []

Greg Ward's avatar
Greg Ward committed
108
        build_cmd = self.get_finalized_command(build_cmd)
109
        build_files = build_cmd.get_outputs()
Greg Ward's avatar
Greg Ward committed
110
        build_dir = getattr(build_cmd, cmd_option)
111

Greg Ward's avatar
Greg Ward committed
112
        prefix_len = len(build_dir) + len(os.sep)
113 114
        outputs = []
        for file in build_files:
Greg Ward's avatar
Greg Ward committed
115
            outputs.append(os.path.join(output_dir, file[prefix_len:]))
116 117 118 119

        return outputs

    # _mutate_outputs ()
120 121 122 123 124 125 126 127

    def _bytecode_filenames (self, py_filenames):
        bytecode_files = []
        for py_file in py_filenames:
            bytecode = py_file + (__debug__ and "c" or "o")
            bytecode_files.append(bytecode)

        return bytecode_files
128
        
129 130 131 132

    # -- External interface --------------------------------------------
    # (called by outsiders)

133 134 135
    def get_outputs (self):
        """Return the list of files that would be installed if this command
        were actually run.  Not affected by the "dry-run" flag or whether
Greg Ward's avatar
Greg Ward committed
136 137
        modules have actually been built yet.
        """
138
        pure_outputs = \
Greg Ward's avatar
Greg Ward committed
139 140 141
            self._mutate_outputs(self.distribution.has_pure_modules(),
                                 'build_py', 'build_lib',
                                 self.install_dir)
142 143 144 145
        if self.compile:
            bytecode_outputs = self._bytecode_filenames(pure_outputs)
        else:
            bytecode_outputs = []
146 147

        ext_outputs = \
Greg Ward's avatar
Greg Ward committed
148 149 150
            self._mutate_outputs(self.distribution.has_ext_modules(),
                                 'build_ext', 'build_lib',
                                 self.install_dir)
151

152
        return pure_outputs + bytecode_outputs + ext_outputs
153 154 155

    # get_outputs ()

Greg Ward's avatar
Greg Ward committed
156 157 158 159
    def get_inputs (self):
        """Get the list of files that are input to this command, ie. the
        files that get installed as they are named in the build tree.
        The files in this list correspond one-to-one to the output
Greg Ward's avatar
Greg Ward committed
160 161
        filenames returned by 'get_outputs()'.
        """
Greg Ward's avatar
Greg Ward committed
162 163 164
        inputs = []
        
        if self.distribution.has_pure_modules():
Greg Ward's avatar
Greg Ward committed
165 166
            build_py = self.get_finalized_command('build_py')
            inputs.extend(build_py.get_outputs())
Greg Ward's avatar
Greg Ward committed
167 168

        if self.distribution.has_ext_modules():
Greg Ward's avatar
Greg Ward committed
169 170
            build_ext = self.get_finalized_command('build_ext')
            inputs.extend(build_ext.get_outputs())
Greg Ward's avatar
Greg Ward committed
171 172 173

        return inputs

174
# class install_lib