-
Notifications
You must be signed in to change notification settings - Fork 1
Spiked a core-engine with example predicate and action #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| from abc import ABC, abstractmethod | ||
|
|
||
|
|
||
| class Action(ABC): | ||
| """Abstract class for all actioner to implement""" | ||
|
|
||
| @abstractmethod | ||
| def process(self): | ||
| """Process the file. Should return the file back for chaining.""" | ||
| pass | ||
|
|
||
|
|
||
| class MoveAction(Action): | ||
| def __init__(self, destination): | ||
| self.destination = destination | ||
|
|
||
| def process(self, file): | ||
| # TODO: Implement | ||
| print("Pretending to move '{}' to '{}'".format(file, self.destination)) | ||
| return file | ||
|
|
||
|
|
||
| class RenameAction(Action): | ||
| def __init__(self, regex): | ||
| self.regex = regex | ||
|
|
||
| def process(self, file): | ||
| # TODO: Implement | ||
| print("Pretending to rename '{}' to '{}'".format(file, self.regex)) | ||
| return file |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,56 +4,54 @@ | |
|
|
||
| from os import walk, path, listdir | ||
|
|
||
| from predicates.predicate import * | ||
| from actions.action import * | ||
|
|
||
|
|
||
| class Rule(object): | ||
| src = None | ||
| dst = None | ||
| reg = None | ||
| predicates = None | ||
| actions = None | ||
|
|
||
|
|
||
| def parse_config_file(fd): | ||
| """Parses the file descriptor line by line. Skips comments. This also | ||
| validates all the configurations, therefore the return value should be safe | ||
| and usable. | ||
| """ | ||
|
|
||
| rules = [] | ||
|
|
||
| for num, line in enumerate(fd): | ||
| line = line.strip() | ||
|
|
||
| # Skip comments | ||
| if line.startswith('#'): | ||
| if line.startswith('#') or not len(line) > 1: | ||
| continue | ||
|
|
||
| # Format of the line is src:dst:regexpression | ||
| # See resource/filedrc for example format | ||
| parts = line.split(':') | ||
| if len(parts) != 3: | ||
| logging.warning("{}:{}: Error reading line".format(filename, num)) | ||
| logging.warning("{}:{}: Error reading line".format(line, num)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| continue | ||
|
|
||
| # Validate the parts of the config | ||
| r = Rule() | ||
| r.src = path.expanduser(parts[0]) | ||
| r.dst = path.expanduser(parts[1]) | ||
| r.reg = parts[2] | ||
|
|
||
| if not path.isdir(r.src): | ||
| logging.warning( | ||
| "{}:{}: {} is not a directory" | ||
| .format(filename, num, r.src)) | ||
| try: | ||
| # TODO: Bad things will happen if pipe symbol inside the function | ||
| # TODO: Avoid using eval() | ||
| r.predicates = list(map(eval, parts[1].split('|'))) | ||
| r.actions = list(map(eval, parts[2].split('|'))) | ||
| except RuntimeError: | ||
| # TODO: Doing proper exceptions. | ||
| logging.warning("Something went wrong") | ||
| continue | ||
|
|
||
| if not path.isdir(r.dst): | ||
| if not path.isdir(r.src): | ||
| logging.warning( | ||
| "{}:{}: {} is not a directory" | ||
| .format(filename, num, r.dst)) | ||
|
|
||
| try: | ||
| re.compile(r.reg) | ||
| except Exception as e: | ||
| logging.warning( | ||
| "{}:{}: error parsing regex: {}" | ||
| .format(filename, num, str(e))) | ||
| .format(line, num, r.src)) | ||
|
|
||
| rules.append(r) | ||
|
|
||
|
|
@@ -82,7 +80,7 @@ def load_config_file(filename): | |
|
|
||
| def main(): | ||
| config_files = [ | ||
| '~/.filedrc' | ||
| path.join(path.dirname(__file__), 'resource/filedrc') | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we'll be getting a user's config from the "resource/filedrc" file? Good for testing but maybe we need to allow a certain file/folder for all user's configs. Okay for now, just something that would need to be discussed.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh. I should have mentioned that was just to wire up the example configure file. We still need to figure out how we want to lay out the confit file.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, sounds good :) |
||
| ] | ||
|
|
||
| rules = {} | ||
|
|
@@ -92,20 +90,16 @@ def main(): | |
| # Monitor folder for changes | ||
| for filename, rules in rules.items(): | ||
| for rule in rules: | ||
| matches = matcher(rule.src, rule.reg) | ||
| print(matches) | ||
| files = listdir(path.expanduser(rule.src)) | ||
|
|
||
| # TODO: Move the file if changes | ||
| for predicate in rule.predicates: | ||
| files = filter(predicate.match, files) | ||
|
|
||
| for action in rule.actions: | ||
| files = map(action.process, files) | ||
|
|
||
| # Returns the file path that match any of the rules | ||
| def matcher(source, rule): | ||
| f = [] | ||
| for filename in listdir(path.expanduser(source)): | ||
| if re.match(rule, filename): | ||
| f.append(path.join(source, filename)) | ||
| # TODO: Future subtrees - for (dirpath, dirnames, filenames) in walk(path.expanduser(s)): | ||
| return f | ||
| # Because map and filters are lazy function. This is needed to execute map and filters | ||
| list(files) | ||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import re | ||
|
|
||
| from abc import ABC, abstractmethod | ||
|
|
||
|
|
||
| class Predicate(ABC): | ||
| @abstractmethod | ||
| def match(self): | ||
| """ Returns true if file satisfies predicate. False otherwise. """ | ||
| pass | ||
|
|
||
|
|
||
| class RegexPredicate(Predicate): | ||
| def __init__(self, regex_str): | ||
| self.regex = re.compile(regex_str) | ||
|
|
||
| def match(self, path): | ||
| return bool(self.regex.match(path)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # Filed example config | ||
| # src:predicates:actions | ||
| # predicates = predicate1() | predicate2() | ... | ||
| # actions = action1() | action2() | ... | ||
|
|
||
| # Moves all *.pdf files into ~/documents | ||
| ~/downloads/:RegexPredicate(".*\.pdf"):MoveAction("~/documents/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe that condition could be rewritten?
len(line) == 0orlen(line) <= 0There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can I do just 'len(line)' is python? Like with truthy falsy values?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah,
not len(line)works too. Not sure which is better.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also do
not linebecause""is considered falseyThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!