util.py revision 3ce77fd05ed00168f618b63401d770ccc4f04b09
12689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward"""distutils.util
22689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
32689e3ddce70e8acc5bc231a80221980d5bdfec3Greg WardGeneral-purpose utility functions used throughout the Distutils
42689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward(especially in command classes).  Mostly filesystem manipulation, but
52689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardnot limited to that.  The functions in this module generally raise
62689e3ddce70e8acc5bc231a80221980d5bdfec3Greg WardDistutilsFileError when they have problems with the filesystem, because
72689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardos.error in pre-1.5.2 Python only gives the error message and not the
82689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardfile causing it."""
92689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
102689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# created 1999/03/08, Greg Ward
112689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
123ce77fd05ed00168f618b63401d770ccc4f04b09Greg Ward__revision__ = "$Id$"
132689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
14585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Wardimport os, string
152689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardfrom distutils.errors import *
162689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
18ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward# cache for by mkpath() -- in addition to cheapening redundant calls,
19ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
20ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg WardPATH_CREATED = {}
21ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
222689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# I don't use os.makedirs because a) it's new to Python 1.5.2, and
232689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# b) it blows up if the directory already exists (I want to silently
242689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# succeed in that case).
25e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Warddef mkpath (name, mode=0777, verbose=0, dry_run=0):
262689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Create a directory and any missing ancestor directories.  If the
272689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directory already exists, return silently.  Raise
282689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       DistutilsFileError if unable to create some directory along the
292689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       way (eg. some sub-path exists, but is a file rather than a
302689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directory).  If 'verbose' is true, print a one-line summary of
312689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       each mkdir to stdout."""
322689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
33ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    global PATH_CREATED
34ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
352689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # XXX what's the better way to handle verbosity? print as we create
362689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # each directory in the path (the current behaviour), or only announce
37ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    # the creation of the whole path? (quite easy to do the latter since
38ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    # we're not using a recursive algorithm)
392689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
40f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward    name = os.path.normpath (name)
41f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward
422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if os.path.isdir (name):
432689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        return
44ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    if PATH_CREATED.get (name):
45ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward        return
462689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
472689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    (head, tail) = os.path.split (name)
482689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    tails = [tail]                      # stack of lone dirs to create
492689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
502689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    while head and tail and not os.path.isdir (head):
512689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        #print "splitting '%s': " % head,
522689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        (head, tail) = os.path.split (head)
532689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        #print "to ('%s','%s')" % (head, tail)
542689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        tails.insert (0, tail)          # push next higher dir onto stack
552689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
562689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    #print "stack of tails:", tails
572689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
58e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    # now 'head' contains the deepest directory that already exists
59e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    # (that is, the child of 'head' in 'name' is the highest directory
60e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    # that does *not* exist)
612689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    for d in tails:
622689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        #print "head = %s, d = %s: " % (head, d),
632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        head = os.path.join (head, d)
64cd1486fff14888437837298ada405b13ce965217Greg Ward        if PATH_CREATED.get (head):
65cd1486fff14888437837298ada405b13ce965217Greg Ward            continue
66cd1486fff14888437837298ada405b13ce965217Greg Ward
672689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if verbose:
682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            print "creating", head
69e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward
70e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward        if not dry_run:
71e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            try:
72e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                os.mkdir (head)
73e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            except os.error, (errno, errstr):
74e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                raise DistutilsFileError, "%s: %s" % (head, errstr)
752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
76ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward        PATH_CREATED[head] = 1
77ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
782689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# mkpath ()
792689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
802689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
81138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef newer (source, target):
82138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Return true if 'source' exists and is more recently modified than
83138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       'target', or if 'source' exists and 'target' doesn't.  Return
84138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       false if both exist and 'target' is the same age or younger than
85138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       'source'.  Raise DistutilsFileError if 'source' does not
86138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       exist."""
87138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
88138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not os.path.exists (source):
89138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, "file '%s' does not exist" % source
90138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not os.path.exists (target):
912689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        return 1
922689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
93138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    from stat import ST_MTIME
94138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    mtime1 = os.stat(source)[ST_MTIME]
95138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    mtime2 = os.stat(target)[ST_MTIME]
962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    return mtime1 > mtime2
982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# newer ()
1002689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1012689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
102138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef newer_pairwise (sources, targets):
103138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Walk two filename lists in parallel, testing if each 'target' is
104138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       up-to-date relative to its corresponding 'source'.  If so, both
105138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       are deleted from their respective lists.  Return a list of tuples
106138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       containing the deleted (source,target) pairs."""
107138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
108138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if len (sources) != len (targets):
109138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise ValueError, "'sources' and 'targets' must be same length"
110138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
111138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    goners = []
112138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    for i in range (len (sources)-1, -1, -1):
113138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if not newer (sources[i], targets[i]):
114138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            goners.append ((sources[i], targets[i]))
115138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            del sources[i]
116138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            del targets[i]
117138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    goners.reverse()
118138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    return goners
119138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
120138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# newer_pairwise ()
121138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
122138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
1237b7679eb79a7ad7766881b05fab0681850f79a6fGreg Warddef newer_group (sources, target, missing='error'):
124138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Return true if 'target' is out-of-date with respect to any
125138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       file listed in 'sources'.  In other words, if 'target' exists and
126138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       is newer than every file in 'sources', return false; otherwise
1277b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       return true.  'missing' controls what we do when a source file is
1287b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       missing; the default ("error") is to blow up with an OSError from
1297b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       inside 'stat()'; if it is "ignore", we silently drop any missing
1307b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       source files; if it is "newer", any missing source files make us
1317b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       assume that 'target' is out-of-date (this is handy in "dry-run"
1327b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       mode: it'll make you pretend to carry out commands that wouldn't
1337b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       work because inputs are missing, but that doesn't matter because
1347b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward       you're not actually going to run the commands)."""
135138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
136138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # If the target doesn't even exist, then it's definitely out-of-date.
137138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not os.path.exists (target):
138138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        return 1
139138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
140138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # Otherwise we have to find out the hard way: if *any* source file
141138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # is more recent than 'target', then 'target' is out-of-date and
142138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # we can immediately return true.  If we fall through to the end
143138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # of the loop, then 'target' is up-to-date and we return false.
144138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    from stat import ST_MTIME
145138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    target_mtime = os.stat (target)[ST_MTIME]
146138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    for source in sources:
1477b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward        if not os.path.exists (source):
1487b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward            if missing == 'error':      # blow up when we stat() the file
1497b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward                pass
1507b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward            elif missing == 'ignore':   # missing source dropped from
1517b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward                continue                #  target's dependency list
1527b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward            elif missing == 'newer':    # missing source means target is
1537b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward                return 1                #  out-of-date
1547b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward
155138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        source_mtime = os.stat(source)[ST_MTIME]
156138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if source_mtime > target_mtime:
157138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            return 1
158138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    else:
159138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        return 0
160138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
161138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# newer_group ()
162138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
163138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
164f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward# XXX this isn't used anywhere, and worse, it has the same name as a method
165f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward# in Command with subtly different semantics.  (This one just has one
166f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward# source -> one dest; that one has many sources -> one dest.)  Nuke it?
1672689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef make_file (src, dst, func, args,
1682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               verbose=0, update_message=None, noupdate_message=None):
1692689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Makes 'dst' from 'src' (both filenames) by calling 'func' with
1702689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'args', but only if it needs to: i.e. if 'dst' does not exist or
1712689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'src' is newer than 'dst'."""
1722689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1732689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if newer (src, dst):
1742689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if verbose and update_message:
1752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            print update_message
1762689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        apply (func, args)
1772689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    else:
1782689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if verbose and noupdate_message:
1792689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            print noupdate_message
1802689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1812689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# make_file ()
1822689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1832689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1842689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef _copy_file_contents (src, dst, buffer_size=16*1024):
1852689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Copy the file 'src' to 'dst'; both must be filenames.  Any error
1862689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       opening either file, reading from 'src', or writing to 'dst',
1872689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       raises DistutilsFileError.  Data is read/written in chunks of
1882689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'buffer_size' bytes (default 16k).  No attempt is made to handle
1892689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       anything apart from regular files."""
1902689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1912689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # Stolen from shutil module in the standard library, but with
1922689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # custom error-handling added.
1932689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1942689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    fsrc = None
1952689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    fdst = None
1962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    try:
1972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        try:
1982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fsrc = open(src, 'rb')
1992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        except os.error, (errno, errstr):
2002689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            raise DistutilsFileError, "could not open %s: %s" % (src, errstr)
2012689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2022689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        try:
2032689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fdst = open(dst, 'wb')
2042689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        except os.error, (errno, errstr):
2052689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            raise DistutilsFileError, "could not create %s: %s" % (dst, errstr)
2062689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2072689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        while 1:
2082689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            try:
2092689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                buf = fsrc.read (buffer_size)
2102689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            except os.error, (errno, errstr):
2112689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                raise DistutilsFileError, \
2122689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                      "could not read from %s: %s" % (src, errstr)
2132689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2142689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            if not buf:
2152689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                break
2162689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            try:
2182689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                fdst.write(buf)
2192689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            except os.error, (errno, errstr):
2202689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                raise DistutilsFileError, \
2212689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                      "could not write to %s: %s" % (dst, errstr)
2222689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2232689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    finally:
2242689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if fdst:
2252689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fdst.close()
2262689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if fsrc:
2272689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fsrc.close()
2282689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2292689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# _copy_file_contents()
2302689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2312689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2322689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef copy_file (src, dst,
2332689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_mode=1,
2342689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_times=1,
2352689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               update=0,
236e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               verbose=0,
237e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               dry_run=0):
2382689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2392689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Copy a file 'src' to 'dst'.  If 'dst' is a directory, then 'src'
2402689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       is copied there with the same name; otherwise, it must be a
2412689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       filename.  (If the file exists, it will be ruthlessly clobbered.)
2422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       If 'preserve_mode' is true (the default), the file's mode (type
2432689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       and permission bits, or whatever is analogous on the current
2442689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       platform) is copied.  If 'preserve_times' is true (the default),
2452689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       the last-modified and last-access times are copied as well.  If
2462689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'update' is true, 'src' will only be copied if 'dst' does not
2472689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       exist, or if 'dst' does exist but is older than 'src'.  If
2482689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'verbose' is true, then a one-line summary of the copy will be
249884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       printed to stdout.
250884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
251884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       Return true if the file was copied (or would have been copied),
252884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       false otherwise (ie. 'update' was true and the destination is
253884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       up-to-date)."""
2542689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2552689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # XXX doesn't copy Mac-specific metadata
2562689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2572689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    from stat import *
2582689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2592689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if not os.path.isfile (src):
2602689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        raise DistutilsFileError, \
261138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't copy %s: not a regular file" % src
2622689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if os.path.isdir (dst):
2642689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dir = dst
2652689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dst = os.path.join (dst, os.path.basename (src))
2662689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    else:
2672689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dir = os.path.dirname (dst)
2682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2692689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if update and not newer (src, dst):
270884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward        if verbose:
271884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward            print "not copying %s (output up-to-date)" % src
272884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward        return 0
2732689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2742689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if verbose:
2752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        print "copying %s -> %s" % (src, dir)
2762689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
277e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    if dry_run:
278884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward        return 1
279e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward
280e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    _copy_file_contents (src, dst)
2812689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if preserve_mode or preserve_times:
2822689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        st = os.stat (src)
2835116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward
2845116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward        # According to David Ascher <da@ski.org>, utime() should be done
2855116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward        # before chmod() (at least under NT).
2862689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if preserve_times:
2872689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            os.utime (dst, (st[ST_ATIME], st[ST_MTIME]))
2885116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward        if preserve_mode:
2895116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward            os.chmod (dst, S_IMODE (st[ST_MODE]))
2902689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
291884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward    return 1
292884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
2932689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# copy_file ()
2942689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2952689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef copy_tree (src, dst,
2972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_mode=1,
2982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_times=1,
2992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_symlinks=0,
3002689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               update=0,
301e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               verbose=0,
302e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               dry_run=0):
303e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward
3042689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
3052689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Copy an entire directory tree 'src' to a new location 'dst'.  Both
3062689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'src' and 'dst' must be directory names.  If 'src' is not a
3072689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directory, raise DistutilsFileError.  If 'dst' does not exist, it
308f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward       is created with 'mkpath()'.  The end result of the copy is that
3092689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       every file in 'src' is copied to 'dst', and directories under
310884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       'src' are recursively copied to 'dst'.  Return the list of files
311884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       copied (under their output names) -- note that if 'update' is true,
312884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       this might be less than the list of files considered.  Return
313884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       value is not affected by 'dry_run'.
3142689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
3152689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'preserve_mode' and 'preserve_times' are the same as for
3162689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'copy_file'; note that they only apply to regular files, not to
3172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directories.  If 'preserve_symlinks' is true, symlinks will be
3182689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       copied as symlinks (on platforms that support them!); otherwise
3192689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       (the default), the destination of the symlink will be copied.
3202689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'update' and 'verbose' are the same as for 'copy_file'."""
3212689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
322138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not dry_run and not os.path.isdir (src):
3232689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        raise DistutilsFileError, \
3242689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward              "cannot copy tree %s: not a directory" % src
3252689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    try:
3262689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        names = os.listdir (src)
3272689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    except os.error, (errno, errstr):
328138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if dry_run:
329138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            names = []
330138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        else:
331138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            raise DistutilsFileError, \
332138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  "error listing files in %s: %s" % (src, errstr)
3332689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
334e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    if not dry_run:
335e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward        mkpath (dst, verbose=verbose)
3362689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
337884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward    outputs = []
338884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
3392689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    for n in names:
3402689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        src_name = os.path.join (src, n)
3412689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dst_name = os.path.join (dst, n)
3422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
3432689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if preserve_symlinks and os.path.islink (src_name):
3442689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            link_dest = os.readlink (src_name)
345e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            if verbose:
346e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                print "linking %s -> %s" % (dst_name, link_dest)
347e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            if not dry_run:
348e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                os.symlink (link_dest, dst_name)
349884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward            outputs.append (dst_name)
350884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
3512689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        elif os.path.isdir (src_name):
352a002edc85b25160cfffe610df9ab7337efc8f0c0Greg Ward            outputs.extend (
353884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                copy_tree (src_name, dst_name,
354884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                           preserve_mode, preserve_times, preserve_symlinks,
355a002edc85b25160cfffe610df9ab7337efc8f0c0Greg Ward                           update, verbose, dry_run))
3562689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        else:
357884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward            if (copy_file (src_name, dst_name,
358884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                           preserve_mode, preserve_times,
359884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                           update, verbose, dry_run)):
360884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                outputs.append (dst_name)
361884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
362884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward    return outputs
3632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
3642689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# copy_tree ()
365138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
366138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
367138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# XXX I suspect this is Unix-specific -- need porting help!
368138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef move_file (src, dst,
369138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward               verbose=0,
370138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward               dry_run=0):
371138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
372138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Move a file 'src' to 'dst'.  If 'dst' is a directory, the file
373138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       will be moved into it with the same name; otherwise, 'src' is
374138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       just renamed to 'dst'.  Return the new full name of the file.
375138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
376138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       Handles cross-device moves on Unix using
377138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       'copy_file()'.  What about other systems???"""
378138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
379138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    from os.path import exists, isfile, isdir, basename, dirname
380138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
381138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if verbose:
382138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        print "moving %s -> %s" % (src, dst)
383138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
384138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if dry_run:
385138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        return dst
386138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
387138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not isfile (src):
388138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, \
389138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't move '%s': not a regular file" % src
390138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
391138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if isdir (dst):
392138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        dst = os.path.join (dst, basename (src))
393138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    elif exists (dst):
394138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, \
395138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't move '%s': destination '%s' already exists" % \
396138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              (src, dst)
397138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
398138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not isdir (dirname (dst)):
399138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, \
400138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't move '%s': destination '%s' not a valid path" % \
401138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              (src, dst)
402138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
403138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    copy_it = 0
404138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    try:
405138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        os.rename (src, dst)
406138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    except os.error, (num, msg):
407138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if num == errno.EXDEV:
408138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            copy_it = 1
409138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        else:
410138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            raise DistutilsFileError, \
411138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  "couldn't move '%s' to '%s': %s" % (src, dst, msg)
412138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
413138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if copy_it:
414138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        copy_file (src, dst)
415138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        try:
416138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            os.unlink (src)
417138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        except os.error, (num, msg):
418138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            try:
419138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                os.unlink (dst)
420138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            except os.error:
421138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                pass
422138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            raise DistutilsFileError, \
423138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  ("couldn't move '%s' to '%s' by copy/delete: " +
424138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                   "delete '%s' failed: %s") % \
425138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  (src, dst, src, msg)
426138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
427138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    return dst
428138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
429138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# move_file ()
430ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
431ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
432ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Warddef write_file (filename, contents):
433f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward    """Create a file with the specified name and write 'contents' (a
434ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward       sequence of strings without line terminators) to it."""
435ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
436ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    f = open (filename, "w")
437ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    for line in contents:
438ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward        f.write (line + "\n")
439ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    f.close ()
440585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward
441585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward
442585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Warddef get_platform ():
443585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward    """Return a string (suitable for tacking onto directory names) that
444585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward       identifies the current platform.  Under Unix, identifies both the OS
445585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward       and hardware architecture, e.g. "linux-i586", "solaris-sparc",
446585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward       "irix-mips".  For Windows and Mac OS, just returns 'sys.platform' --
447585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward       i.e. "???" or "???"."""
448585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward
449585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward    if os.name == 'posix':
450585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward        uname = os.uname()
451585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward        OS = uname[0]
452585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward        arch = uname[4]
453585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward        return "%s-%s" % (string.lower (OS), string.lower (arch))
454585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward    else:
455585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward        return sys.platform
456585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward
457585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward# get_platform()
458