I submitted a patch to Greg against the latest Snapshot release. It is
too big to include it here, but a list of changes follows:
- new command build_scripts: copy all scripts in build/scripts. If the
first line of a script begins with "#!" and ends with "python",
write the path to the current Python interpreter in this line.
- bug fixed in dist.py: import sysconfig for win32 platforms.
- new function Command.create_tree which calls util.create_tree.
- install_misc is now the base class for all install commands
- install_data now creates leading directories of the files you supply
and copies the files in these directories.
So for example pixmaps/open.xpm gets installed in
On 22 May 2000, Bastian Kleineidam said:
- new command build_scripts: copy all scripts in build/scripts. If the first line of a script begins with "#!" and ends with "python", write the path to the current Python interpreter in this line.
A *possible* variation on this: if the line starts wuth #! and *contains* "python", rewrite it. Not really necessary since command-line options to the Python interpreter are quite rare. I think your way will do just fine unless somebody howls.
- bug fixed in dist.py: import sysconfig for win32 platforms.
Already fixed in CVS -- well, I'll probably ask you to "cvs up" and resubmit the patch, as I've been doing some heavy lifting in dist.py that will affect all of the commands (sigh). IOW, you get to deal with the conflict. ;-)
- new function Command.create_tree which calls util.create_tree.
Fine.
- install_misc is now the base class for all install commands
I'd like to know why this is necessary -- please explain your rationale. (I've only skimmed the patch, not read it closely.)
- install_data now creates leading directories of the files you supply and copies the files in these directories. So for example pixmaps/open.xpm gets installed in
/pixmaps/open.xpm and not in /open.xpm I think the last point is a convenient way to install data in different directories. Another way (like in automake) is to supply for each set of filenames a different directory in which the files are going to be installed, but I like my solution better.
Good that you brought this up, because I think I like the Automake way better. Your installation directories shouldn't be constrained by your source directories, and it sounds like your scheme does that. Granted it's more convenient, and probably easier to implement, but I think I'd opt for more flexibility here. Other opinions? Greg -- Greg Ward - Unix nerd gward@python.net http://starship.python.net/~gward/ Never put off till tomorrow what you can put off till the day after tomorrow.
Ok, the patch is against latest CVS (sourceforge).
command-line options to the Python interpreter are quite rare. Now optionally ending command-line options are preserved in the scripts.
- install_misc is now the base class for all install commands install_misc is now removed since install_scripts and install_data both changed. No need of a common base class any more
Good that you brought this up, because I think I like the Automake way better. Your installation directories shouldn't be constrained by your Ok, implemented a bit of Automake: the data_files elements can be filename strings (these files are copied in install_data) and tuples with a directory to install to and a filename list. Example: data_files = ['info.txt', ('man/man1', ['bubble.1', 'bobble.1'])] ... installs /usr/share/info.txt /usr/share/man/man1/{bubble.1 bobble.1}
Note: if you want to provide an absolute data path instead of man/man1, the --root install option will fail. Bastian
On 24 May 2000, Bastian Kleineidam said:
- install_misc is now the base class for all install commands install_misc is now removed since install_scripts and install_data both changed. No need of a common base class any more
Whoops, you may have gone too far! (Or maybe not: I haven't looked at
the patch yet, this is just an off-the-cuff reply.) One more "simple"
install command definitely needs to be added: "install_headers", which
would put C header files into <prefix>/python1.x/include/
Next try with the build_scripts patch. Again the changes: - build command additionally calls build_scripts - build_scripts builds your scripts in 'build/scripts' and adjusts the first line if it begins with "#!" and ends with "python", optionally ending with commandline options (like -O, -t ...). Adjusting means we write the current path to the Python interpreter in the first line. - install_misc class is commented out because its not needed any more - install_scripts copies the scripts to the install_scripts dir - install_data copies your data_files in install_data. You can supply individual directories for your data_files: data_files = ['doc/info.txt', # copy this file in install_scripts dir ('testdata', ['a.dat', 'b.dat']), # copy these files in # install_scripts/testdata ('/etc', ['packagerc']), # copy this in /etc. When --root is # given, copy this in rootdir/etc ] So you can use the --root option with absolute data paths. Bastian
On 24 May 2000, Bastian Kleineidam said:
Next try with the build_scripts patch. Again the changes:
OK, I've checked it in. A few minor comments (I'm checking these changes in too, so howl if you don't like 'em and "cvs up" if you do.)
- install_misc class is commented out because its not needed any more
You forgot to include this in the patch, but that's OK because that's not what I meant! I just wanted a comment next to "install_misc" to remind us that it's not (currently) used. I'll do it myself.
data_files = ['doc/info.txt', # copy this file in install_scripts dir ('testdata', ['a.dat', 'b.dat']), # copy these files in # install_scripts/testdata ('/etc', ['packagerc']), # copy this in /etc. When --root is # given, copy this in rootdir/etc ]
Perfect! (Assuming it works. ;-)
--- distutils.orig/distutils/command/__init__.py Sat May 13 03:48:15 2000 +++ distutils.patched/distutils/command/__init__.py Wed May 24 10:11:54 2000 [...] @@ -99,5 +104,8 @@ # into the build tree if self.distribution.has_ext_modules(): self.run_peer ('build_ext') + + if self.distribution.scripts: + self.run_peer ('build_scripts')
This should use the 'has_scripts()' method of Distribution -- fixed.
+# check if Python is called on the first line with this expression +first_line_re = re.compile(r"^#!.+python(\s-\w+)*")
I think we can get away with a looser regex: I've changed this to r'^#!.*python(\s+.*)?'. Reasons: * I seem to recall having seen "#!python" notation somewhere -- it's a reasonable way to say, "Hey, <installation tool of choice>! Fix this up for me at install time!" * Why assume/impose a particular syntax on Python's command line? let's just preserve any old args on the #! line.
+ def _copy_files(self): + """Copy all the scripts to the build dir""" [...]
+ def _adjust_files(self): + """If the first line begins with #! and ends with python + replace it with the current python interpreter""" [...]
This strikes me as a rather wasteful implementation: in the worst case, we copy every file twice. I've merged them into the following method; it works for me, please look it over and try it out (from CVS -- a few other tweaks to build_scripts.py were needed to make this work): def copy_scripts (self): """Copy each script listed in 'self.scripts'; if it's marked as a Python script in the Unix way (first line matches 'first_line_re', ie. starts with "\#!" and contains "python"), then adjust the first line to refer to the current Python intepreter as we copy. """ outfiles = [] self.mkpath(self.build_dir) for script in self.scripts: adjust = 0 outfile = os.path.join(self.build_dir, script) if not self.force and not newer(script, outfile): self.announce("not copying %s (output up-to-date)" % script) continue # Always open the file, but ignore failures in dry-run mode -- # that way, we'll get accurate feedback if we can read the # script. try: f = open(script, "r") except IOError: if not self.dry_run: raise f = None else: first_line = f.readline() if not first_line: self.warn("%s is an empty file (skipping)" % script) continue match = first_line_re.match(first_line) if match: adjust = 1 post_interp = match.group(1) if adjust: self.announce("copying and adjusting %s -> %s" % (script, self.build_dir)) if not self.dry_run: outf = open(outfile, "w") outf.write("#!%s%s\n" % (os.path.normpath(sys.executable), post_interp)) outf.writelines(f.readlines()) outf.close() if f: f.close() else: f.close() self.copy_file(script, outfile) # copy_scripts ()
--- distutils.orig/distutils/command/install_data.py Sat May 13 05:09:50 2000 +++ distutils.patched/distutils/command/install_data.py Wed May 24 10:41:51 2000 [...] def run (self): - self._copy_files(self.distribution.data_files) + self.mkpath(self.install_dir) + for f in self.data_files: + if type(f) == StringType: + # its a simple file, so copy it + self.copy_file(f, self.install_dir) + else: + # its a tuple with path to install to and a list of files + dir = f[0] + if not os.path.isabs(dir): + dir = os.path.join(self.install_dir, dir) + elif self.root: + dir = os.path.join(self.root, dir[1:]) + self.mkpath(dir) + for data in f[1]: + self.copy_file(data, dir)
This looks unportable, in particular the 'dir[1:]' business. Should use the 'distutils.util.change_root()' function, which handles non-Unix platforms by blowing up with "I don't know how to do this!" error. (Which is really a function of me not having sat down and carefully thought through what it means to "change the root" of an MS-DOS filename: the presence of drive letters complicates matters.) Greg -- Greg Ward - just another /P(erl|ython)/ hacker gward@python.net http://starship.python.net/~gward/ I'm a GENIUS! I want to dispute sentence structure with SUSAN SONTAG!!
participants (2)
-
Bastian Kleineidam
-
Greg Ward