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.

Gareth Rees
50.1k3 gold badges130 silver badges210 bronze badges
asked Jan 29, 2014 at 15:35
\$\endgroup\$
2
  • \$\begingroup\$ I don't think recursion is a good solution for this problem at all. You're initial solution is better. \$\endgroup\$ Commented Jan 30, 2014 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\$ Commented Jan 30, 2014 at 9:13

3 Answers 3

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'))
answered Jan 29, 2014 at 21:23
\$\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?

answered Jan 29, 2014 at 16:05
\$\endgroup\$
2
  • \$\begingroup\$ Yes, Windows I'm afraid! \$\endgroup\$ Commented Jan 29, 2014 at 16:06
  • 1
    \$\begingroup\$ I've updated your question accordingly. \$\endgroup\$ Commented Jan 29, 2014 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

answered Jan 29, 2014 at 18:04
\$\endgroup\$
2
  • \$\begingroup\$ Can you revise this to avoid the long line? \$\endgroup\$ Commented Jan 29, 2014 at 18:09
  • \$\begingroup\$ there its shorter lines ... still probably not quite pep-8 \$\endgroup\$ Commented Jan 29, 2014 at 18:12

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.