mirror of
https://github.com/python/cpython.git
synced 2025-07-23 19:25:40 +00:00
Added 'newer_pairwise()' and 'newer_group()'.
Terminology change in 'newer()'. Made 'copy_tree' respect dry_run flag a little better. Added 'move_file()'.
This commit is contained in:
parent
9b17cb5819
commit
138ce653cc
1 changed files with 132 additions and 15 deletions
|
@ -62,26 +62,75 @@ def mkpath (name, mode=0777, verbose=0, dry_run=0):
|
||||||
# mkpath ()
|
# mkpath ()
|
||||||
|
|
||||||
|
|
||||||
def newer (file1, file2):
|
def newer (source, target):
|
||||||
"""Return true if file1 exists and is more recently modified than
|
"""Return true if 'source' exists and is more recently modified than
|
||||||
file2, or if file1 exists and file2 doesn't. Return false if both
|
'target', or if 'source' exists and 'target' doesn't. Return
|
||||||
exist and file2 is the same age or younger than file1. Raises
|
false if both exist and 'target' is the same age or younger than
|
||||||
DistutilsFileError if file1 does not exist."""
|
'source'. Raise DistutilsFileError if 'source' does not
|
||||||
|
exist."""
|
||||||
|
|
||||||
if not os.path.exists (file1):
|
if not os.path.exists (source):
|
||||||
raise DistutilsFileError, "file '%s' does not exist" % file1
|
raise DistutilsFileError, "file '%s' does not exist" % source
|
||||||
if not os.path.exists (file2):
|
if not os.path.exists (target):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
from stat import *
|
from stat import ST_MTIME
|
||||||
mtime1 = os.stat(file1)[ST_MTIME]
|
mtime1 = os.stat(source)[ST_MTIME]
|
||||||
mtime2 = os.stat(file2)[ST_MTIME]
|
mtime2 = os.stat(target)[ST_MTIME]
|
||||||
|
|
||||||
return mtime1 > mtime2
|
return mtime1 > mtime2
|
||||||
|
|
||||||
# newer ()
|
# newer ()
|
||||||
|
|
||||||
|
|
||||||
|
def newer_pairwise (sources, targets):
|
||||||
|
|
||||||
|
"""Walk two filename lists in parallel, testing if each 'target' is
|
||||||
|
up-to-date relative to its corresponding 'source'. If so, both
|
||||||
|
are deleted from their respective lists. Return a list of tuples
|
||||||
|
containing the deleted (source,target) pairs."""
|
||||||
|
|
||||||
|
if len (sources) != len (targets):
|
||||||
|
raise ValueError, "'sources' and 'targets' must be same length"
|
||||||
|
|
||||||
|
goners = []
|
||||||
|
for i in range (len (sources)-1, -1, -1):
|
||||||
|
if not newer (sources[i], targets[i]):
|
||||||
|
goners.append ((sources[i], targets[i]))
|
||||||
|
del sources[i]
|
||||||
|
del targets[i]
|
||||||
|
goners.reverse()
|
||||||
|
return goners
|
||||||
|
|
||||||
|
# newer_pairwise ()
|
||||||
|
|
||||||
|
|
||||||
|
def newer_group (sources, target):
|
||||||
|
"""Return true if 'target' is out-of-date with respect to any
|
||||||
|
file listed in 'sources'. In other words, if 'target' exists and
|
||||||
|
is newer than every file in 'sources', return false; otherwise
|
||||||
|
return true."""
|
||||||
|
|
||||||
|
# If the target doesn't even exist, then it's definitely out-of-date.
|
||||||
|
if not os.path.exists (target):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Otherwise we have to find out the hard way: if *any* source file
|
||||||
|
# is more recent than 'target', then 'target' is out-of-date and
|
||||||
|
# we can immediately return true. If we fall through to the end
|
||||||
|
# of the loop, then 'target' is up-to-date and we return false.
|
||||||
|
from stat import ST_MTIME
|
||||||
|
target_mtime = os.stat (target)[ST_MTIME]
|
||||||
|
for source in sources:
|
||||||
|
source_mtime = os.stat(source)[ST_MTIME]
|
||||||
|
if source_mtime > target_mtime:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# newer_group ()
|
||||||
|
|
||||||
|
|
||||||
def make_file (src, dst, func, args,
|
def make_file (src, dst, func, args,
|
||||||
verbose=0, update_message=None, noupdate_message=None):
|
verbose=0, update_message=None, noupdate_message=None):
|
||||||
"""Makes 'dst' from 'src' (both filenames) by calling 'func' with
|
"""Makes 'dst' from 'src' (both filenames) by calling 'func' with
|
||||||
|
@ -176,7 +225,7 @@ def copy_file (src, dst,
|
||||||
|
|
||||||
if not os.path.isfile (src):
|
if not os.path.isfile (src):
|
||||||
raise DistutilsFileError, \
|
raise DistutilsFileError, \
|
||||||
"can't copy %s:not a regular file" % src
|
"can't copy %s: not a regular file" % src
|
||||||
|
|
||||||
if os.path.isdir (dst):
|
if os.path.isdir (dst):
|
||||||
dir = dst
|
dir = dst
|
||||||
|
@ -237,14 +286,17 @@ def copy_tree (src, dst,
|
||||||
(the default), the destination of the symlink will be copied.
|
(the default), the destination of the symlink will be copied.
|
||||||
'update' and 'verbose' are the same as for 'copy_file'."""
|
'update' and 'verbose' are the same as for 'copy_file'."""
|
||||||
|
|
||||||
if not os.path.isdir (src):
|
if not dry_run and not os.path.isdir (src):
|
||||||
raise DistutilsFileError, \
|
raise DistutilsFileError, \
|
||||||
"cannot copy tree %s: not a directory" % src
|
"cannot copy tree %s: not a directory" % src
|
||||||
try:
|
try:
|
||||||
names = os.listdir (src)
|
names = os.listdir (src)
|
||||||
except os.error, (errno, errstr):
|
except os.error, (errno, errstr):
|
||||||
raise DistutilsFileError, \
|
if dry_run:
|
||||||
"error listing files in %s: %s" % (src, errstr)
|
names = []
|
||||||
|
else:
|
||||||
|
raise DistutilsFileError, \
|
||||||
|
"error listing files in %s: %s" % (src, errstr)
|
||||||
|
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
mkpath (dst, verbose=verbose)
|
mkpath (dst, verbose=verbose)
|
||||||
|
@ -277,3 +329,68 @@ def copy_tree (src, dst,
|
||||||
return outputs
|
return outputs
|
||||||
|
|
||||||
# copy_tree ()
|
# copy_tree ()
|
||||||
|
|
||||||
|
|
||||||
|
# XXX I suspect this is Unix-specific -- need porting help!
|
||||||
|
def move_file (src, dst,
|
||||||
|
verbose=0,
|
||||||
|
dry_run=0):
|
||||||
|
|
||||||
|
"""Move a file 'src' to 'dst'. If 'dst' is a directory, the file
|
||||||
|
will be moved into it with the same name; otherwise, 'src' is
|
||||||
|
just renamed to 'dst'. Return the new full name of the file.
|
||||||
|
|
||||||
|
Handles cross-device moves on Unix using
|
||||||
|
'copy_file()'. What about other systems???"""
|
||||||
|
|
||||||
|
from os.path import exists, isfile, isdir, basename, dirname
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print "moving %s -> %s" % (src, dst)
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
return dst
|
||||||
|
|
||||||
|
if not isfile (src):
|
||||||
|
raise DistutilsFileError, \
|
||||||
|
"can't move '%s': not a regular file" % src
|
||||||
|
|
||||||
|
if isdir (dst):
|
||||||
|
dst = os.path.join (dst, basename (src))
|
||||||
|
elif exists (dst):
|
||||||
|
raise DistutilsFileError, \
|
||||||
|
"can't move '%s': destination '%s' already exists" % \
|
||||||
|
(src, dst)
|
||||||
|
|
||||||
|
if not isdir (dirname (dst)):
|
||||||
|
raise DistutilsFileError, \
|
||||||
|
"can't move '%s': destination '%s' not a valid path" % \
|
||||||
|
(src, dst)
|
||||||
|
|
||||||
|
copy_it = 0
|
||||||
|
try:
|
||||||
|
os.rename (src, dst)
|
||||||
|
except os.error, (num, msg):
|
||||||
|
if num == errno.EXDEV:
|
||||||
|
copy_it = 1
|
||||||
|
else:
|
||||||
|
raise DistutilsFileError, \
|
||||||
|
"couldn't move '%s' to '%s': %s" % (src, dst, msg)
|
||||||
|
|
||||||
|
if copy_it:
|
||||||
|
copy_file (src, dst)
|
||||||
|
try:
|
||||||
|
os.unlink (src)
|
||||||
|
except os.error, (num, msg):
|
||||||
|
try:
|
||||||
|
os.unlink (dst)
|
||||||
|
except os.error:
|
||||||
|
pass
|
||||||
|
raise DistutilsFileError, \
|
||||||
|
("couldn't move '%s' to '%s' by copy/delete: " +
|
||||||
|
"delete '%s' failed: %s") % \
|
||||||
|
(src, dst, src, msg)
|
||||||
|
|
||||||
|
return dst
|
||||||
|
|
||||||
|
# move_file ()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue