Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

share|improve this question
    
I don't think recursion is a good solution for this problem at all. You're initial solution is better. – James Khoury Jan 30 '14 at 1:22
    
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. – benjymous Jan 30 '14 at 9:13

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'))
share|improve this answer

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?

share|improve this answer
    
Yes, Windows I'm afraid! – benjymous Jan 29 '14 at 16:06
1  
I've updated your question accordingly. – Gareth Rees Jan 29 '14 at 16:08
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

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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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