]>
Commit | Line | Data |
---|---|---|
1 | """distutils.command.build_scripts | |
2 | ||
3 | Implements the Distutils 'build_scripts' command.""" | |
4 | ||
5 | # This module should be kept compatible with Python 1.5.2. | |
6 | ||
7 | __revision__ = "$Id$" | |
8 | ||
9 | import sys, os, re | |
10 | from stat import ST_MODE | |
11 | from distutils import sysconfig | |
12 | from distutils.core import Command | |
13 | from distutils.dep_util import newer | |
14 | from distutils.util import convert_path | |
15 | from distutils import log | |
16 | ||
17 | # check if Python is called on the first line with this expression | |
18 | first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$') | |
19 | ||
20 | class build_scripts (Command): | |
21 | ||
22 | description = "\"build\" scripts (copy and fixup #! line)" | |
23 | ||
24 | user_options = [ | |
25 | ('build-dir=', 'd', "directory to \"build\" (copy) to"), | |
26 | ('force', 'f', "forcibly build everything (ignore file timestamps"), | |
27 | ] | |
28 | ||
29 | boolean_options = ['force'] | |
30 | ||
31 | ||
32 | def initialize_options (self): | |
33 | self.build_dir = None | |
34 | self.scripts = None | |
35 | self.force = None | |
36 | self.outfiles = None | |
37 | ||
38 | def finalize_options (self): | |
39 | self.set_undefined_options('build', | |
40 | ('build_scripts', 'build_dir'), | |
41 | ('force', 'force')) | |
42 | self.scripts = self.distribution.scripts | |
43 | ||
44 | ||
45 | def run (self): | |
46 | if not self.scripts: | |
47 | return | |
48 | self.copy_scripts() | |
49 | ||
50 | ||
51 | def copy_scripts (self): | |
52 | """Copy each script listed in 'self.scripts'; if it's marked as a | |
53 | Python script in the Unix way (first line matches 'first_line_re', | |
54 | ie. starts with "\#!" and contains "python"), then adjust the first | |
55 | line to refer to the current Python interpreter as we copy. | |
56 | """ | |
57 | self.mkpath(self.build_dir) | |
58 | outfiles = [] | |
59 | for script in self.scripts: | |
60 | adjust = 0 | |
61 | script = convert_path(script) | |
62 | outfile = os.path.join(self.build_dir, os.path.basename(script)) | |
63 | outfiles.append(outfile) | |
64 | ||
65 | if not self.force and not newer(script, outfile): | |
66 | log.debug("not copying %s (up-to-date)", script) | |
67 | continue | |
68 | ||
69 | # Always open the file, but ignore failures in dry-run mode -- | |
70 | # that way, we'll get accurate feedback if we can read the | |
71 | # script. | |
72 | try: | |
73 | f = open(script, "r") | |
74 | except IOError: | |
75 | if not self.dry_run: | |
76 | raise | |
77 | f = None | |
78 | else: | |
79 | first_line = f.readline() | |
80 | if not first_line: | |
81 | self.warn("%s is an empty file (skipping)" % script) | |
82 | continue | |
83 | ||
84 | match = first_line_re.match(first_line) | |
85 | if match: | |
86 | adjust = 1 | |
87 | post_interp = match.group(1) or '' | |
88 | ||
89 | if adjust: | |
90 | log.info("copying and adjusting %s -> %s", script, | |
91 | self.build_dir) | |
92 | if not self.dry_run: | |
93 | outf = open(outfile, "w") | |
94 | if not sysconfig.python_build: | |
95 | outf.write("#!%s%s\n" % | |
96 | (os.path.normpath(sys.executable), | |
97 | post_interp)) | |
98 | else: | |
99 | outf.write("#!%s%s\n" % | |
100 | (os.path.join( | |
101 | sysconfig.get_config_var("BINDIR"), | |
102 | "python" + sysconfig.get_config_var("EXE")), | |
103 | post_interp)) | |
104 | outf.writelines(f.readlines()) | |
105 | outf.close() | |
106 | if f: | |
107 | f.close() | |
108 | else: | |
109 | f.close() | |
110 | self.copy_file(script, outfile) | |
111 | ||
112 | if os.name == 'posix': | |
113 | for file in outfiles: | |
114 | if self.dry_run: | |
115 | log.info("changing mode of %s", file) | |
116 | else: | |
117 | oldmode = os.stat(file)[ST_MODE] & 07777 | |
118 | newmode = (oldmode | 0555) & 07777 | |
119 | if newmode != oldmode: | |
120 | log.info("changing mode of %s from %o to %o", | |
121 | file, oldmode, newmode) | |
122 | os.chmod(file, newmode) | |
123 | ||
124 | # copy_scripts () | |
125 | ||
126 | # class build_scripts |