Skip to content

Instantly share code, notes, and snippets.

@wlupton
Last active October 6, 2016 13:37
Show Gist options
  • Save wlupton/e9f698cb39b73306e772 to your computer and use it in GitHub Desktop.
Save wlupton/e9f698cb39b73306e772 to your computer and use it in GitHub Desktop.
Update directory modification times based on modification times of non-directories in sub-tree
#!/usr/bin/env python3
"""Scan the files in a directory sub-tree and set directory modification times
to be the modification time of the newest non directory file within the
sub-tree. This is work around the Office 2016 practice of creating a temporary
file in the same directory as each file when opening that file (which of
course updates the directory modification time."""
import argparse, os, sys, time
loglevel = 1
def scan_directory(dirpath, mtimes={}, level=0):
"""Scan directory sub-tree...
dirpath: root of directory sub-tree
mtimes: dictionary...
level: indentation level (used only for reporting)"""
mtime0 = os.stat(dirpath).st_mtime
mtimes[dirpath] = {"mtime0": mtime0, "mtime": 0.0}
for direntry in os.scandir(dirpath):
name = direntry.name
path = direntry.path
is_file = direntry.is_file()
is_dir = direntry.is_dir()
is_symlink = direntry.is_symlink()
if loglevel > 2:
print("%s%s %s" % (level * " ", name,
time.ctime(direntry.stat().st_mtime)))
if not is_file and not is_dir:
continue
if is_dir and name == ".git":
continue
if not is_dir and name == ".DS_Store":
continue
if is_dir and not is_symlink:
mtime = scan_directory(path, level=level+1, mtimes=mtimes)
else:
mtime = direntry.stat().st_mtime
if mtime > mtimes[dirpath]["mtime"]:
mtimes[dirpath]["mtime"] = mtime
return mtimes[dirpath]["mtime"]
def main(argv=None):
"""Main program."""
if argv is None: argv = sys.argv
# XXX might be better to use positional argument for directory?
global loglevel
parser = argparse.ArgumentParser(
prog=argv[0], description="update directory modification time")
parser.add_argument("-d", "--directory",
help="root of directory sub-tree; default is current directory")
parser.add_argument("-l", "--loglevel", type=int,
help="logging level; default: %d" % loglevel)
parser.add_argument("-n", "--dryrun", action="store_true",
help="dry run; report what would have been done but don't do it")
args = parser.parse_args(argv[1:])
directory = args.directory if args.directory else os.getcwd()
dryrun = args.dryrun
if args.loglevel is not None: loglevel = args.loglevel
mtimes = {}
scan_directory(directory, mtimes)
for dirname in sorted(mtimes.keys()):
mtime0 = mtimes[dirname]["mtime0"]
mtime = mtimes[dirname]["mtime"]
if mtime > 0 and mtime < mtime0:
if loglevel > 0:
print("%s: %s -> %s" % (dirname, time.ctime(mtime0),
time.ctime(mtime)))
if dryrun or loglevel > 1:
print("os.utime(\"%s\", (%d, %d))" % (dirname, mtime, mtime))
if not dryrun:
os.utime(dirname, (mtime, mtime))
if __name__ == "__main__":
sys.exit(main())
@wlupton
Copy link
Author

wlupton commented Feb 11, 2016

I created this script in frustration at Word's habit of creating a temporary file in the same directory as the open document, which updates the directory modification time even though nothing has really changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment