~usb-creator-hackers/usb-creator/trunk

« back to all changes in this revision

Viewing changes to tools/pypack/libpypack/application.py

  • Committer: Evan Dandrea
  • Date: 2009-07-23 13:58:53 UTC
  • mto: This revision was merged to the branch mainline in revision 133.
  • Revision ID: evan.dandrea@canonical.com-20090723135853-zjeg9r22xyuk1kz8
Support for building a Windows executable.  Run make build_windows or make test_windows.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#
 
3
# Copyright (c) 2007, 2008 Agostino Russo
 
4
#
 
5
# Written by Agostino Russo <agostino.russo@gmail.com>
 
6
#
 
7
# pack.py is free software; you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as
 
9
# published by the Free Software Foundation; either version 2 of
 
10
# the License, or (at your option) any later version.
 
11
#
 
12
# pack.py is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
#
 
20
 
 
21
import sys
 
22
import os
 
23
import shutil
 
24
from modulegraph.find_modules import find_modules
 
25
from modulegraph.modulegraph import SourceModule, Package, Script, Extension
 
26
from os.path import abspath, join, basename, dirname, exists
 
27
import py_compile
 
28
from optparse import OptionParser
 
29
import logging
 
30
from version import *
 
31
 
 
32
log = logging.getLogger(__name__)
 
33
 
 
34
class Application(object):
 
35
    def __init__(self, root_dir):
 
36
        self.root_dir = os.path.abspath(root_dir)
 
37
 
 
38
    def run(self):
 
39
        self.localize()
 
40
        self.parse_commandline_arguments()
 
41
        self.set_logger()
 
42
        self.create_dirs()
 
43
        self.add_dependencies(self.main_script)
 
44
        self.add_extras()
 
45
 
 
46
    def localize(self):
 
47
        try:
 
48
            import gettext
 
49
            gettext.install(APPLICATION_NAME)
 
50
        except ImportError:
 
51
            import __builtin__
 
52
            def dummytrans (text):
 
53
                """A _ function for systems without gettext. Effectively a NOOP"""
 
54
                return text
 
55
            __builtin__.__dict__['_'] = dummytrans
 
56
 
 
57
    def print_readme(self):
 
58
        readme = ajoin(self.root_dir, 'README')
 
59
        readme = open(readme, 'r')
 
60
        content = readme.read()
 
61
        readme.close()
 
62
        print content
 
63
 
 
64
    def parse_commandline_arguments(self):
 
65
        usage = "%prog [options] main_script [extra extra extra]"
 
66
        version = version="%s-rev%s" % (APPLICATION_VERSION, APPLICATION_REVISION)
 
67
        description='Pypack packages a script into a directory containing all needed depencies suitable for "folder deployment". Run `python pypack --readme` for more information.'
 
68
        parser = OptionParser(usage=usage, description = description, version = version)
 
69
        parser.add_option("--readme", action="store_true", dest="readme", help="show more information")
 
70
        parser.add_option("--verbose", action="store_true", dest="verbose", help="run in verbose mode, all messages are displayed")
 
71
        parser.add_option("--debug", action="store_true", dest="debug", help="print debug messages to stdout")
 
72
        parser.add_option("--print", action="store_true", dest="print_dependencies", help="print dependencies and exit")
 
73
        parser.add_option("--outputdir", dest="out_dir", default="./build", help="directory where the files will be built, if non existent, it will be created")
 
74
        parser.add_option("--bytecompile", action="store_true", dest="bytecompile", help="bytecompile the python files")
 
75
        options, args = parser.parse_args()
 
76
        self.options, args = parser.parse_args()
 
77
        if options.readme:
 
78
            print self.print_readme()
 
79
            sys.exit(0)
 
80
        if not len(args):
 
81
            parser.print_help()
 
82
            sys.exit(1)
 
83
        self.main_script = args[0]
 
84
        self.extras = args[1:]
 
85
        if self.options.debug:
 
86
            self.options.verbose = True
 
87
        if self.options.print_dependencies:
 
88
            self.print_dependencies()
 
89
            sys.exit(0)
 
90
 
 
91
    def create_dirs(self):
 
92
        self.out_dir = self.options.out_dir
 
93
        self.out_dir = ajoin(self.out_dir)
 
94
        if os.path.exists(self.out_dir):
 
95
            print 'ERROR: the build directory "%s" already exists.\nRemove that before running %s again.' % (self.out_dir, APPLICATION_NAME)
 
96
            sys.exit(1)
 
97
        self.lib_dir = ajoin(self.out_dir, 'lib')
 
98
        os.makedirs(self.lib_dir)
 
99
 
 
100
    def set_logger(self):
 
101
        '''
 
102
        Adjust the application root logger settings
 
103
        '''
 
104
        root_logger = logging.getLogger()
 
105
        if root_logger.handlers:
 
106
            handler = root_logger.handlers[0]
 
107
        else:
 
108
            handler = logging.StreamHandler()
 
109
            root_logger.addHandler(handler)
 
110
        formatter = logging.Formatter('%(message)s', datefmt='%m-%d %H:%M')
 
111
        handler.setFormatter(formatter)
 
112
        root_logger.setLevel(logging.DEBUG)
 
113
        if self.options.verbose:
 
114
            handler.setLevel(logging.DEBUG)
 
115
        else:
 
116
            handler.setLevel(logging.ERROR)
 
117
 
 
118
    def print_dependencies(self):
 
119
        scripts = [self.main_script]
 
120
        scripts += [f for f in self.extras if f[:-3] == '.py']
 
121
        modules = []
 
122
        for script in scripts:
 
123
            for m in get_modules(script):
 
124
                modules.append(m)
 
125
        for m in modules:
 
126
            print m
 
127
 
 
128
    def add_dependencies(self, script):
 
129
        '''
 
130
        Adds all dependencies to lib_dir
 
131
        '''
 
132
        modules = get_modules(script)
 
133
        lib_dir = self.lib_dir
 
134
        for module in modules:
 
135
            if not module.filename:
 
136
                continue
 
137
            if isinstance(module, SourceModule):
 
138
                target = module2path(lib_dir, module.identifier)
 
139
                target +=  '.py'
 
140
                self.compile(module.filename, target)
 
141
            elif isinstance(module, Package):
 
142
                target = module2path(lib_dir, module.identifier)
 
143
                target = ajoin(target, '__init__.py')
 
144
                self.compile(module.filename, target)
 
145
            elif isinstance(module, Script):
 
146
                log.debug("Script %s", script)
 
147
                if module.identifier[0] != "_":
 
148
                    script_name = basename(script)
 
149
                    target = ajoin(self.out_dir, script_name)
 
150
                    self.compile(module.filename, target)
 
151
            elif isinstance(module, Extension):
 
152
                target = module2path(lib_dir, module.identifier)
 
153
                target = dirname(target)
 
154
                makedirs(target)
 
155
                log.debug("copying %s -> %s" % (module.filename, target))
 
156
                shutil.copy(module.filename, target)
 
157
            else:
 
158
                log.error("Unkown module %s", module)
 
159
 
 
160
    def compile(self, source, target):
 
161
        log.debug("copying %s -> %s", source, target)
 
162
        makedirs(dirname(target))
 
163
        shutil.copy(source, target)
 
164
        if self.options.bytecompile:
 
165
            log.debug("compiling %s", target)
 
166
            dfile = target
 
167
            if target.startswith(self.out_dir):
 
168
                dfile = target[len(self.out_dir):]
 
169
            py_compile.compile(target, dfile=dfile, doraise=True)
 
170
            os.unlink(target)
 
171
 
 
172
    def add_extras(self):
 
173
        '''
 
174
        Add extra files, modules, pacakges or directories
 
175
        '''
 
176
        for extra in self.extras:
 
177
            if os.path.isfile(extra):
 
178
                if extra.endswith('.py'):
 
179
                    self.add_dependencies(extra)
 
180
                    target = os.path.basename(extra)
 
181
                    target = ajoin(self.lib_dir, target)
 
182
                    self.compile(extra, target)
 
183
                else:
 
184
                    target = os.path.basename(extra)
 
185
                    target = ajoin(self.out_dir, target)
 
186
                    log.debug("copying %s -> %s", extra, target)
 
187
                    shutil.copy(extra, target)
 
188
            elif os.path.isdir(extra):
 
189
                target = os.path.basename(extra)
 
190
                target = ajoin(self.out_dir, target)
 
191
                log.debug("copying %s -> %s", extra, target)
 
192
                shutil.copytree(extra, target, symlinks=False)
 
193
            else:
 
194
                print 'ERROR: The extra argument "%s" cannot be found' % extra
 
195
                sys.exit(1)
 
196
 
 
197
 
 
198
def ajoin(*args):
 
199
    return os.path.abspath(os.path.join(*args))
 
200
 
 
201
def makedirs(target_path):
 
202
    try:
 
203
        os.makedirs(target_path)
 
204
    except:
 
205
        pass
 
206
 
 
207
def module2path(root_dir, module_name):
 
208
    path = module_name.split('.')
 
209
    path = ajoin(root_dir, *path)
 
210
    return path
 
211
 
 
212
def get_modules(script_path):
 
213
    sys.path.insert(0, os.path.dirname(script_path))
 
214
    mf = find_modules((script_path,))
 
215
    del sys.path[0]
 
216
    modules = mf.flatten()
 
217
    return modules