blob: 611767e7bc3277cd31d27a04cb927d8703bb19f1 [file] [log] [blame]
Greg Warda4efe652000-05-25 01:20:15 +00001"""distutils.command.build_scripts
2
3Implements the Distutils 'build_scripts' command."""
4
5# created 2000/05/23, Bastian Kleineidam
6
7__revision__ = "$Id$"
8
Greg Ward80fa55e2000-05-25 02:03:56 +00009import sys, os, re
Greg Warda4efe652000-05-25 01:20:15 +000010from distutils.core import Command
Greg Ward80fa55e2000-05-25 02:03:56 +000011from distutils.dep_util import newer
Just van Rossum8d8e7a32001-07-29 21:39:18 +000012from distutils.util import convert_path
Greg Warda4efe652000-05-25 01:20:15 +000013
Greg Ward7cf7e7e2001-07-25 20:20:11 +000014# check if Python is called on the first line with this expression
15first_line_re = re.compile(r'^#!.*python(\s+.*)?')
Greg Warda4efe652000-05-25 01:20:15 +000016
17class build_scripts (Command):
18
Greg Ward80fa55e2000-05-25 02:03:56 +000019 description = "\"build\" scripts (copy and fixup #! line)"
Greg Warda4efe652000-05-25 01:20:15 +000020
21 user_options = [
22 ('build-dir=', 'd', "directory to \"build\" (copy) to"),
23 ('force', 'f', "forcibly build everything (ignore file timestamps"),
24 ]
25
Greg Ward99b032e2000-09-25 01:41:15 +000026 boolean_options = ['force']
27
Greg Warda4efe652000-05-25 01:20:15 +000028
29 def initialize_options (self):
30 self.build_dir = None
31 self.scripts = None
32 self.force = None
33 self.outfiles = None
34
35 def finalize_options (self):
Greg Wardcb1f4c42000-09-30 18:27:54 +000036 self.set_undefined_options('build',
37 ('build_scripts', 'build_dir'),
38 ('force', 'force'))
Greg Warda4efe652000-05-25 01:20:15 +000039 self.scripts = self.distribution.scripts
40
41
42 def run (self):
43 if not self.scripts:
44 return
Greg Ward80fa55e2000-05-25 02:03:56 +000045 self.copy_scripts()
46
Fred Drake53a79062001-03-02 07:28:03 +000047
Greg Ward80fa55e2000-05-25 02:03:56 +000048 def copy_scripts (self):
49 """Copy each script listed in 'self.scripts'; if it's marked as a
50 Python script in the Unix way (first line matches 'first_line_re',
51 ie. starts with "\#!" and contains "python"), then adjust the first
Greg Ward612eb9f2000-07-27 02:13:20 +000052 line to refer to the current Python interpreter as we copy.
Greg Ward80fa55e2000-05-25 02:03:56 +000053 """
54 outfiles = []
Greg Warda4efe652000-05-25 01:20:15 +000055 self.mkpath(self.build_dir)
Greg Ward80fa55e2000-05-25 02:03:56 +000056 for script in self.scripts:
57 adjust = 0
Just van Rossum8d8e7a32001-07-29 21:39:18 +000058 script = convert_path(script)
Greg Wardfe55e862000-05-25 20:05:52 +000059 outfile = os.path.join(self.build_dir, os.path.basename(script))
Greg Ward80fa55e2000-05-25 02:03:56 +000060
61 if not self.force and not newer(script, outfile):
Fred Drake53a79062001-03-02 07:28:03 +000062 self.announce("not copying %s (up-to-date)" % script)
Greg Ward80fa55e2000-05-25 02:03:56 +000063 continue
64
65 # Always open the file, but ignore failures in dry-run mode --
66 # that way, we'll get accurate feedback if we can read the
67 # script.
68 try:
69 f = open(script, "r")
70 except IOError:
71 if not self.dry_run:
72 raise
73 f = None
74 else:
75 first_line = f.readline()
76 if not first_line:
77 self.warn("%s is an empty file (skipping)" % script)
Greg Warda4efe652000-05-25 01:20:15 +000078 continue
Greg Ward80fa55e2000-05-25 02:03:56 +000079
80 match = first_line_re.match(first_line)
81 if match:
82 adjust = 1
83 post_interp = match.group(1)
84
85 if adjust:
86 self.announce("copying and adjusting %s -> %s" %
87 (script, self.build_dir))
88 if not self.dry_run:
89 outf = open(outfile, "w")
90 outf.write("#!%s%s\n" %
91 (os.path.normpath(sys.executable), post_interp))
92 outf.writelines(f.readlines())
93 outf.close()
94 if f:
95 f.close()
96 else:
97 f.close()
98 self.copy_file(script, outfile)
99
100 # copy_scripts ()
101
102# class build_scripts