3
# Copyright (c) 2007, 2008 Agostino Russo
5
# Written by Agostino Russo <agostino.russo@gmail.com>
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.
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.
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/>.
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
28
from optparse import OptionParser
32
log = logging.getLogger(__name__)
34
class Application(object):
35
def __init__(self, root_dir):
36
self.root_dir = os.path.abspath(root_dir)
40
self.parse_commandline_arguments()
43
self.add_dependencies(self.main_script)
49
gettext.install(APPLICATION_NAME)
52
def dummytrans (text):
53
"""A _ function for systems without gettext. Effectively a NOOP"""
55
__builtin__.__dict__['_'] = dummytrans
57
def print_readme(self):
58
readme = ajoin(self.root_dir, 'README')
59
readme = open(readme, 'r')
60
content = readme.read()
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()
78
print self.print_readme()
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()
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)
97
self.lib_dir = ajoin(self.out_dir, 'lib')
98
os.makedirs(self.lib_dir)
100
def set_logger(self):
102
Adjust the application root logger settings
104
root_logger = logging.getLogger()
105
if root_logger.handlers:
106
handler = root_logger.handlers[0]
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)
116
handler.setLevel(logging.ERROR)
118
def print_dependencies(self):
119
scripts = [self.main_script]
120
scripts += [f for f in self.extras if f[:-3] == '.py']
122
for script in scripts:
123
for m in get_modules(script):
128
def add_dependencies(self, script):
130
Adds all dependencies to lib_dir
132
modules = get_modules(script)
133
lib_dir = self.lib_dir
134
for module in modules:
135
if not module.filename:
137
if isinstance(module, SourceModule):
138
target = module2path(lib_dir, module.identifier)
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)
155
log.debug("copying %s -> %s" % (module.filename, target))
156
shutil.copy(module.filename, target)
158
log.error("Unkown module %s", module)
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)
167
if target.startswith(self.out_dir):
168
dfile = target[len(self.out_dir):]
169
py_compile.compile(target, dfile=dfile, doraise=True)
172
def add_extras(self):
174
Add extra files, modules, pacakges or directories
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)
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)
194
print 'ERROR: The extra argument "%s" cannot be found' % extra
199
return os.path.abspath(os.path.join(*args))
201
def makedirs(target_path):
203
os.makedirs(target_path)
207
def module2path(root_dir, module_name):
208
path = module_name.split('.')
209
path = ajoin(root_dir, *path)
212
def get_modules(script_path):
213
sys.path.insert(0, os.path.dirname(script_path))
214
mf = find_modules((script_path,))
216
modules = mf.flatten()