Skip to content

Commit

Permalink
modifying how rules work a bit, adding WasChanged.
Browse files Browse the repository at this point in the history
  • Loading branch information
toumorokoshi committed Jan 17, 2016
1 parent e8ca736 commit 325dd87
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ python:
- "2.7"
- "3.3"
install: "pip install -r requirements.txt"
script: "uranium test"
script: "uranium test"
Empty file added tests/rules/__init__.py
Empty file.
45 changes: 24 additions & 21 deletions tests/decorators/test_rules.py → tests/rules/test_rules.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
from uranium import rule
from uranium.rules import rule, RuleBase


class AlwaysPass(RuleBase):

def before(self, build):
return True

def after(self, build):
pass


class AlwaysFail(RuleBase):

def before(self, build):
return False

def after(self, build):
pass


def test_rule_does_not_execute(build):

g = []

def rule_func(build):
return True

@rule(rule_func)
@rule(AlwaysPass())
def main(build):
g.append("main")

Expand All @@ -23,14 +38,8 @@ def test_all_true_multiple_rules(build):

g = []

def rule_func(build):
return True

def rule_func_2(build):
return True

@rule(rule_func)
@rule(rule_func_2)
@rule(AlwaysPass())
@rule(AlwaysPass())
def main(build):
g.append("main")

Expand All @@ -45,14 +54,8 @@ def test_one_false_multiple_rules(build):

g = []

def rule_func(build):
return True

def rule_func_2(build):
return False

@rule(rule_func)
@rule(rule_func_2)
@rule(AlwaysPass())
@rule(AlwaysFail())
def main(build):
g.append("main")

Expand Down
5 changes: 4 additions & 1 deletion uranium/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
import setuptools

from .remote import get_remote_script
from .decorators import task_requires, rule
from .decorators import task_requires
from .rules import rule

__all__ = ["get_remote_script", "task_requires", "rule"]
35 changes: 0 additions & 35 deletions uranium/decorators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import functools
from .experimental import experimental


def task_requires(func_or_func_name):
Expand All @@ -24,37 +23,3 @@ def func(build):
return func

return decorator


@experimental
def rule(rule_func):
"""
the rule decorator is used to add a rule function to the task.
the rule function should accept a build object, and should return
True in the case where a build is required.
multiple rules can be added to a task. If any of the rules return false,
the task will be re-executed.
"""
key = "_uranium_rules"

def decorator(f):

if hasattr(f, key):
getattr(f, key).append(rule_func)
return f

rules = [rule_func]

@functools.wraps(f)
def func(build):
if all((r(build) for r in rules)):
return 0
return f(build)

setattr(func, key, rules)

return func

return decorator
60 changes: 60 additions & 0 deletions uranium/rules/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import functools
from abc import ABCMeta, abstractmethod
from ..experimental import experimental


class RuleBase(object):
"""
an example of a rule.
* func gets set during the initialization process.
"""
func = None

__metaclass__ = ABCMeta

@abstractmethod
def before(self, build):
pass

@abstractmethod
def after(self, build):
pass


@experimental
def rule(rule_object):
"""
the rule decorator is used to add a rule function to the task.
the rule function should accept a build object, and should return
True in the case where a build is required.
multiple rules can be added to a task. If any of the rules return false,
the task will be re-executed.
"""
key = "_uranium_rules"

def decorator(f):
rule_object.func = f

if hasattr(f, key):
getattr(f, key).append(rule_object)
return f

rules = [rule_object]

@functools.wraps(f)
def func(build):
if all((r.before(build) for r in rules)):
return 0
return_value = f(build)
for r in rules:
r.after(build)
return return_value

setattr(func, key, rules)

return func

return decorator
45 changes: 45 additions & 0 deletions uranium/rules/was_changed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import os
import time
from . import RuleBase
KEY = "_uranium.rules.was_changed"


class WasChanged(RuleBase):

def __init__(self, path):
self._path = path

def before(self, build):
previous_timestamp = build.history.get(self.key)
if not previous_timestamp:
return False
current_timestamp = self._get_timestamp(self.path)
return current_timestamp > previous_timestamp

def after(self, build):
current_timestamp = self._get_timestamp(self.path)
build.history[self.key] = current_timestamp

@property
def key(self):
return "{}.{}.{}".format(
KEY, self._path, self.func.__name__
)

@classmethod
def _get_timestamp(cls, path):
""" return the timestamp as a UTC datetime object. """
if os.path.isdir(path):
return cls._get_dir_timestamp(path)
else:
return os.path.getmtime(path)

@classmethod
def _get_dir_timestamp(cls, path):
oldest_timestamp = time.time()
for root, _, filename in os.walk(path):
f_path = os.path.join(root, filename)
ts = os.path.getmtime(f_path)
if ts < oldest_timestamp:
oldest_timestamp = ts
return oldest_timestamp

0 comments on commit 325dd87

Please sign in to comment.