3
\$\begingroup\$

The intent of this script is to hunt down all "*/testResults/*.xml" files and touch them, so that our build system doesn't issue errors that the files are too old (it's entirely intentional that tests are only re-run when the libraries they change have been modified)

import fnmatch
import os
import time

matches = []

# Find all xml files  (1)
for root, dirnames, filenames in os.walk('.'):
  for filename in fnmatch.filter(filenames, '*.xml'):
      matches.append(os.path.join(root, filename))

# filter to only the ones in a "/testResults/" folder  (2)
tests = [k for k in matches if "\\testResults\\" in k]

t = time.time()

# touch them
for test in tests:
    os.utime(test,(t,t))

Is there a simpler way to achieve this? Specifically to perform steps (1) and (2) in a single process, rather than having to filter the matches array? An alternative solution would be to just recursively find all folders called "/testResults/" and list the files within them.

Notes:

  • This script would also find "blah/testResults/blah2/result.xml" - I'm not worried about that, as the testResults folders will only contain test result xml files (but not all xml files are test results!)

  • This runs on Windows.

\$\endgroup\$
  • \$\begingroup\$ I don't think recursion is a good solution for this problem at all. You're initial solution is better. \$\endgroup\$ – James Khoury Jan 30 '14 at 1:22
  • \$\begingroup\$ I meant recursively in a filesystem sense (i.e. it could be /a/testResults/ or /a/b/testResults/ etc), not in a recursive function sense. \$\endgroup\$ – benjymous Jan 30 '14 at 9:13
4
\$\begingroup\$

For combining (1) and (2) you can reverse the sort by only trying if your are under a test directory

Also this is a great use for a generator / map combo to avoid extra loops

import os 
import re

is_xml = re.compile('xml', re.I)
is_test = re.compile('testResults', re.I)

def find_xml_tests(root):
    for current, dirnames, filenames in os.walk(root):
        if is_test.search(current):
            for filename in filter(lambda p: is_xml.search(p),  filenames):
                yield  os.path.normpath(os.path.join(current, filename))

def touch(filename ):
    os.utime(test,(time.time(),time.time()))

map(touch, find_xml_tests('path/to/files'))
\$\endgroup\$
3
\$\begingroup\$

Python seems like overkill here: this is surely a job for the shell? Depending on exactly which files you want to touch, then use this:

touch -- */testResults/*.xml

or this:

find . -path '*/testResults/*.xml' -exec touch -- {} \+

You indicated that you are using Windows. But even on Windows, surely a PowerShell script (using Get-ChildItem instead of find and Set-ItemProperty -Name LastWriteTime instead of touch) would be simplest?

\$\endgroup\$
  • \$\begingroup\$ Yes, Windows I'm afraid! \$\endgroup\$ – benjymous Jan 29 '14 at 16:06
  • 1
    \$\begingroup\$ I've updated your question accordingly. \$\endgroup\$ – Gareth Rees Jan 29 '14 at 16:08
0
\$\begingroup\$
import os,glob,time
t = time.time()
def touchy(fpath):
    os.utime(fpath,(t,t))
    return fpath

def findResults(directory = "/"):
    results = [] 
    search_path = os.path.join(directory,"testResults/*.xml")
    for d in filter(os.path.isdir,os.listdir(directory)):   
        results.extend( map(touchy,glob.glob(search_path)) if d == "testResults" else findResults(os.path.join(directory,d))
    return results

is probably about the best you can do if you want python

\$\endgroup\$
  • \$\begingroup\$ Can you revise this to avoid the long line? \$\endgroup\$ – Gareth Rees Jan 29 '14 at 18:09
  • \$\begingroup\$ there its shorter lines ... still probably not quite pep-8 \$\endgroup\$ – Joran Beasley Jan 29 '14 at 18:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.