Patch for util.py (was: Re: [Distutils] bdist broken under Windows)
Greg Ward
gward@python.net
Tue, 30 May 2000 22:17:33 -0400
On 30 May 2000, Thomas Heller said:
> What would the user do with such an archive when his python-site-packages
> are to be installed into "/usr/local/lib/python1.5/site-packages" ?
There's a reason these are called "dumb" built distributions. They're
dumb! Stupid, moronic, clue-challenged -- call 'em what you will
they're *dumb*.
However, 'change_root()' is definitely needed to support "bdist_rpm",
and may well be useful for other Unix build distributions. In Unix,
/usr is always /usr, and /usr/local is always /usr/local -- and yes,
Python is not necessarily installed in either one of them. However,
prefix is not necessarily always exec-prefix, so if we want to put the
whole dumb built distribution in one tarball, either we assume prefix ==
exec-prefix, or we start at the root. Neither one is good enough, which
is why I don't expect dumb build distributions to catch on in a big way.
> Converting this into the windows world:
>
> Normally python1.5 is installed into
> "C:\Program Files\Python".
> So the bdist-created archive would contain filenames like
> "C:\Program Files\Python\distutils\..."
>
> On a german windows installation Python would be installed
> (per default) in
> "C:\Programme\Python"
> On the other hand, users would have been able to nstall it into
> "D:\Work\Python\1.5" or whatever they like.
>
> So to me it seems like a bad idea to create archives containing pathnames
> relative to the root directory.
Good point. Perhaps bdist_dumb should grow a *little* bit of
intelligence, and allow the packager to specify if the archive should be
relative to prefix or to the root. Yeah, I like that. Just added it to
the to-do list.
> Anyway, here is the relevant part of the implementation
> of change_root on windows:
> --------------------------------------
> elif os.name == 'nt':
> (root_drive, root_path) = os.path.splitdrive (new_root)
> (drive, path) = os.path.splitdrive (pathname)
> if path[0] == '\\':
> path = path[1:]
> return os.path.join (new_root, path)
Isn't splitdrive'ing new_root unnecessary here? (Oh wait, you just
inherited that from my aborted attempt...)
Apart from that, this looks right to me... but I just enumerated 20
distinct cases that 'change_root()' has to handle with MS-DOS pathnames,
so you can be sure I'll be testing this one carefully. ;-)
[...time passes...]
OK, I went ahead and wrote the test script. Good thing too: I found a
bug in the Unix case! Here's the output; first, the Unix cases:
ok: change_root(baz, foo) == baz/foo
ok: change_root(/baz, foo) == /baz/foo
ok: change_root(baz, /foo) == baz/foo
ok: change_root(/baz, /foo) == /baz/foo
and now the DOS/Windows cases:
ok: change_root(c:\baz, c:\foo) == c:\baz\foo
ok: change_root(\baz, c:\foo) == \baz\foo
ok: change_root(c:\baz, \foo) == c:\baz\foo
ok: change_root(\baz, \foo) == \baz\foo
not ok: change_root(c:\baz, c:foo) != c:\baz\foo (got c:\baz\c:foo)
not ok: change_root(\baz, c:foo) != c:\baz\foo (got \baz\c:foo)
ok: change_root(c:\baz, foo) == c:\baz\foo
ok: change_root(\baz, foo) == \baz\foo
ok: change_root(c:baz, c:\foo) == c:baz\foo
ok: change_root(baz, c:\foo) == baz\foo
ok: change_root(c:baz, \foo) == c:baz\foo
ok: change_root(baz, \foo) == baz\foo
not ok: change_root(c:baz, c:foo) != c:baz\foo (got c:baz\c:foo)
not ok: change_root(baz, c:foo) != baz\foo (got baz\c:foo)
ok: change_root(c:baz, foo) == c:baz\foo
ok: change_root(baz, foo) == baz\foo
ok: change_root(d:\baz, c:\foo) == d:\baz\foo
not ok: change_root(d:\baz, c:foo) != d:\baz\foo (got d:\baz\c:foo)
ok: change_root(d:baz, c:\foo) == d:baz\foo
not ok: change_root(d:baz, c:foo) != d:baz\foo (got d:baz\c:foo)
Hmmm, not quite there yet.
[...more time passes...]
OK, got it. Here's the revised 'change_root()'. Passes all those tests
for both POSIX and DOS/Windows paths. Anyone care to contribute a Mac
OS version (and tests!)?
def change_root (new_root, pathname):
"""Return 'pathname' with 'new_root' prepended. If 'pathname' is
relative, this is equivalent to "os.path.join(new_root,pathname)".
Otherwise, it requires making 'pathname' relative and then joining the
two, which is tricky on DOS/Windows and Mac OS.
"""
if os.name == 'posix':
if not os.path.isabs (pathname):
return os.path.join (new_root, pathname)
else:
return os.path.join (new_root, pathname[1:])
elif os.name == 'nt':
(drive, path) = os.path.splitdrive (pathname)
if path[0] == '\\':
path = path[1:]
return os.path.join (new_root, path)
elif os.name == 'mac':
raise RuntimeError, "no clue how to do this on Mac OS"
else:
raise DistutilsPlatformError, \
"nothing known about platform '%s'" % os.name
There, I've checked it in. And the test script too!
> Another minor nit:
> distutils\archive_util.py, function make_zipfile: The (nested) function
> visit
> should normpath() the generated path names, otherwise the created zipfile
> contains pathnames like ".\distutils\archive_util.py" (Not nice at least).
OK, thanks -- I've checked in your fix.
> Question:
> Zip-files created under windows contain backslashes as path-separators.
> Do we have to care about this?
Shouldn't that be done magically by os.path.join()?
> PS: As soon as the above problems have been cleared, I will prepare
> a first release of bdist_wininst.py as discussed before.
Hot dog!
Greg
--
Greg Ward - nerd gward@python.net
http://starship.python.net/~gward/
I don't understand the HUMOUR of the THREE STOOGES!!