Skip to content

Commit

Permalink
Break some various code out of the plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
dcramer committed Jul 26, 2013
1 parent 27ee702 commit 68884cd
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 119 deletions.
69 changes: 69 additions & 0 deletions quickunit/filechecker.py
@@ -0,0 +1,69 @@
import os.path
import re

from quickunit.utils import clean_bytecode_extension


class FileChecker(dict):
def __init__(self, rules, root=None):
self.rules = rules
self.changed_files = set()
self.root = root
self.compiled = False
dict.__init__(self)

def __missing__(self, filepath):
self[filepath] = self.check(filepath)
return self[filepath]

def compile(self):
self.compiled = True

if self.root is None:
try:
filepath = self.changed_files.pop()
except IndexError:
self.root = ''
else:
self.changed_files.add(filepath)
self.root = os.path.abspath(filepath)[:-len(filepath)]

rules = []
for filepath in self.changed_files:
try:
path, filename = filepath.rsplit('/', 1)
except ValueError:
path, filename = '', filepath

basename = filename.rsplit('.', 1)[0]

params = {
'path': path,
'filename': filename,
'basename': basename,
}
for rule in self.rules:
rules.append(re.compile(rule.format(**params)))
self.rules = rules

def add(self, filepath):
if self.compiled:
raise Exception('The rules for this FileChecker are already compiled and files can no longer be added')
self.changed_files.add(filepath)

def check(self, filepath):
filepath = clean_bytecode_extension(filepath)

# check if this test was modified (e.g. added/changed)
if self.root and filepath.startswith(self.root):
filepath = filepath[len(self.root):]

# if the filepath is actually the changed file
if filepath in self.changed_files:
return None

for rule in self.rules:
if rule.search(filepath):
return None

return False
127 changes: 9 additions & 118 deletions quickunit/plugin.py
Expand Up @@ -9,84 +9,13 @@
from __future__ import absolute_import

import inspect
import logging
import os
import re
import sys

from collections import namedtuple
from nose.plugins.base import Plugin
from subprocess import Popen, PIPE, STDOUT

from quickunit.diff import DiffParser
from quickunit.utils import is_py_script, clean_bytecode_extension


ChangedFile = namedtuple('ChangedFile', ['filename', 'is_new'])

class FileChecker(dict):
def __init__(self, rules, root=None):
self.rules = rules
self.changed_files = set()
self.root = root
self.compiled = False
dict.__init__(self)

def __missing__(self, filepath):
self[filepath] = self.check(filepath)
return self[filepath]

def compile(self):
self.compiled = True

if self.root is None:
try:
filepath = self.changed_files.pop()
except IndexError:
self.root = ''
else:
self.changed_files.add(filepath)
self.root = os.path.abspath(filepath)[:-len(filepath)]

rules = []
for filepath in self.changed_files:
try:
path, filename = filepath.rsplit('/', 1)
except ValueError:
path, filename = '', filepath

basename = filename.rsplit('.', 1)[0]

params = {
'path': path,
'filename': filename,
'basename': basename,
}
for rule in self.rules:
rules.append(re.compile(rule.format(**params)))
self.rules = rules

def add(self, filepath):
if self.compiled:
raise Exception('The rules for this FileChecker are already compiled and files can no longer be added')
self.changed_files.add(filepath)

def check(self, filepath):
filepath = clean_bytecode_extension(filepath)

# check if this test was modified (e.g. added/changed)
if self.root and filepath.startswith(self.root):
filepath = filepath[len(self.root):]

# if the filepath is actually the changed file
if filepath in self.changed_files:
return None

for rule in self.rules:
if rule.search(filepath):
return None

return False
from quickunit.filechecker import FileChecker
from quickunit.utils import is_py_script
from quickunit.vcs import git


class QuickUnitPlugin(Plugin):
Expand All @@ -112,8 +41,8 @@ def _get_name_from_test(self, test):
# proper coverage
test_ = getattr(sys.modules[test.__module__], test.__class__.__name__)

test_name = '%s:%s.%s' % (test_.__module__, test_.__name__,
test_method_name)
test_name = '%s:%s.%s' % (
test_.__module__, test_.__name__, test_method_name)

return test_name

Expand All @@ -137,61 +66,23 @@ def configure(self, options, config):

root = options.quickunit_root

self.logger = logging.getLogger(__name__)
self.verbosity = options.verbosity
self.parent_branch = options.quickunit_parent_branch
# files which were changed as part of the diff
self.changed_files = set()
# store a list of filenames that should be accepted
self.file_checker = FileChecker(rules, root)

def parse_git_commit(self):
parent_branch = self.parent_branch or 'master'
proc = Popen(['git', 'merge-base', 'HEAD', parent_branch], stdout=PIPE, stderr=STDOUT)

parent_revision = proc.stdout.read().strip()

if self.verbosity > 1:
self.logger.info("Parent commit identified as %s", parent_revision)

# pull in our diff
# git diff `git merge-base HEAD master`
proc = Popen(['git', 'diff', parent_revision], stdout=PIPE, stderr=STDOUT)
diff = proc.stdout.read().strip()

parser = DiffParser(diff)

files = []
for file in parser.parse():
if file['is_header']:
continue

# file was removed
if file['new_filename'] == '/dev/null':
continue

filename = file['new_filename'][2:]
def begin(self):
file_list = git.parse_commit(parent=self.parent_branch)

for c_file in file_list:
# Ignore non python files
if not is_py_script(filename):
if not is_py_script(c_file.filename):
continue

is_new = (file['old_filename'] == '/dev/null')

files.append(ChangedFile(filename, is_new))

return files

def begin(self):
file_list = self.parse_git_commit()

for c_file in file_list:
self.file_checker.add(c_file.filename)
self.file_checker.compile()

if self.verbosity > 1:
self.logger.info("Found %d changed file(s)", file_list)

def wantMethod(self, method):
# only works with unittest compatible functions currently
method = getattr(sys.modules[method.im_class.__module__], method.im_class.__name__)
Expand Down
Empty file added quickunit/vcs/__init__.py
Empty file.
4 changes: 4 additions & 0 deletions quickunit/vcs/base.py
@@ -0,0 +1,4 @@
from collections import namedtuple

ChangedFile = namedtuple('ChangedFile', ['filename', 'is_new'])

37 changes: 37 additions & 0 deletions quickunit/vcs/git.py
@@ -0,0 +1,37 @@
from subprocess import Popen, PIPE, STDOUT

from quickunit.diff import DiffParser
from quickunit.vcs.base import ChangedFile


def parse_commit(parent=None):
if parent is None:
parent = 'master'

proc = Popen(['git', 'merge-base', 'HEAD', parent], stdout=PIPE, stderr=STDOUT)

parent_revision = proc.stdout.read().strip()

# pull in our diff
# git diff `git merge-base HEAD master`
proc = Popen(['git', 'diff', parent_revision], stdout=PIPE, stderr=STDOUT)
diff = proc.stdout.read().strip()

parser = DiffParser(diff)

files = []
for file in parser.parse():
if file['is_header']:
continue

# file was removed
if file['new_filename'] == '/dev/null':
continue

filename = file['new_filename'][2:]

is_new = (file['old_filename'] == '/dev/null')

files.append(ChangedFile(filename, is_new))

return files
4 changes: 3 additions & 1 deletion setup.py
Expand Up @@ -26,7 +26,9 @@
},
license='Apache License 2.0',
tests_require=tests_require,
extras_require={'tests': tests_require},
extras_require={
'tests': tests_require,
},
include_package_data=True,
classifiers=[
'Intended Audience :: Developers',
Expand Down

0 comments on commit 68884cd

Please sign in to comment.