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