Commits

Christophe-Marie Duquesne committed 6066c86

!fix #1

Comments (0)

Files changed (1)

 import os.path
 import sys
 
+class TasksTree():
+    """Tree for holding tasks"""
+
+    def __init__(self, title=None, task_id=None):
+        """init"""
+        self.title = title
+        self.task_id = task_id
+        self.subtasks = []
+
+    def get(self, task_id):
+        """Returns the task of given id"""
+        if self.task_id == task_id:
+            return self
+        else:
+            for subtask in self.subtasks:
+                if subtask.get(task_id) != None:
+                    return subtask.get(task_id)
+
+    def add_subtask(self, title, task_id = None, parent_id = None):
+        """Adds a subtask to the tree"""
+        if not parent_id:
+            self.subtasks.append(TasksTree(title, task_id))
+        else:
+            if not self.get(parent_id):
+                raise ValueError, "No element with suitable parent id"
+            self.get(parent_id).add_subtask(title, task_id)
+
+    def last(self, level):
+        """Returns the last task added at a given level of the tree"""
+        if level == 0:
+            return self
+        else:
+            res = None
+            for subtask in self.subtasks:
+                res = subtask.last(level - 1) or res
+            if res:
+                return res
+
+    def push(self, service, list_id, parent = None, root=True):
+        """Pushes the task tree to the given list"""
+        # We do not want to push the root node
+        if not root:
+            args = {'tasklist': list_id, 'body':{ 'title' : self.title } }
+            if parent:
+                args['parent'] = parent
+            res = service.tasks().insert(**args).execute()
+            self.task_id = res['id']
+        # the API head inserts, so we insert in reverse.
+        for subtask in reversed(self.subtasks):
+            subtask.push(service, list_id, parent=self.task_id, root=False)
+
+    def _lines(self, level):
+        """Returns the sequence of lines of the string representation"""
+        res = []
+        for subtask in self.subtasks:
+            indentations = '\t'.join(['' for i in range(level + 1)])
+            res.append(indentations + subtask.title)
+            subtasks_lines = subtask._lines(level + 1)
+            res += subtasks_lines
+        return res
+
+
+    def __str__(self):
+        """string representation of the tree"""
+        return '\n'.join(self._lines(0))
+
 def get_service():
     """
     Handle oauth's shit (copy-pasta from
     http = credentials.authorize(http)
     return build(serviceName='tasks', version='v1', http=http)
 
-def print_todolist():
+def print_todolist(list_id):
+    """Prints the todo list of given id"""
     service = get_service()
-    tasks = service.tasks().list(tasklist='@default').execute()
-    levels = {}
+    tasks = service.tasks().list(tasklist=list_id).execute()
+    tasks_tree = TasksTree()
+    tasklist = [t for t in tasks.get('items', [])]
+    fail_count = 0
+    while tasklist != [] and fail_count < 1000 :
+        t = tasklist.pop(0)
+        try:
+            tasks_tree.add_subtask(t['title'].encode('utf-8'), t['id'], t.get('parent'))
+        except ValueError:
+            fail_count += 1
+            tasklist.append(t)
+    print(tasks_tree)
+
+def erase_todolist(list_id):
+    """Erases the todo list of given id"""
+    service = get_service()
+    tasks = service.tasks().list(tasklist=list_id).execute()
     for task in tasks.get('items', []):
-        parent_id = task.get('parent')
-        if parent_id:
-            level = levels[parent_id] + 1
-        else:
-            level = 0
-        levels[task['id']] = level
-        title = task['title'].encode('utf-8')
-        print('\t'.join(['' for i in range(level + 1)]) + title)
-
-def wipe_todolist():
-    service = get_service()
-    tasks = service.tasks().list(tasklist='@default').execute()
-    for task in tasks.get('items', []):
-        service.tasks().delete(tasklist='@default',
+        service.tasks().delete(tasklist=list_id,
                 task=task['id']).execute()
 
-def push_todolist(path):
-    wipe_todolist()
-    service = get_service()
+def parse(path):
+    """Parses a todolist file and returns a tree"""
+    tasks_tree = TasksTree()
     with open(path) as f:
-        last_inserted = None
-        last_inserted_at_level = {}
-        for line in f:
+        curr_indent_lvl = 0
+        for n, line in enumerate(f):
+            # trim trailing '\n'
             if line[-1] == '\n':
                 line = line[:-1]
-            level = 0
+            # get the indent level
+            indent_lvl = 0
             while line[0] == '\t':
                 line = line[1:]
-                level += 1
-            args = {'tasklist':'@default', 'body':{ 'title' : line } }
-            if level:
-                args['parent'] = last_inserted_at_level[level - 1]
-            if args.get('parent') != last_inserted:
-                args['previous'] = last_inserted_at_level[level]
-            result = service.tasks().insert(**args).execute()
-            last_inserted = result['id']
-            last_inserted_at_level[level] = result['id']
+                indent_lvl += 1
+            assert indent_lvl <= curr_indent_lvl + 1, ("line %d: "
+                    "subtask has no parent task" % n)
+            curr_indent_lvl = indent_lvl
+            tasks_tree.last(indent_lvl).add_subtask(line)
+    return tasks_tree
+
+def push_todolist(path, list_id):
+    """Pushes the specified file to the specified todolist"""
+    tasks_tree = parse(path)
+    erase_todolist(list_id)
+    tasks_tree.push(get_service(), list_id)
 
 def main():
     if (len(sys.argv)) < 2:
         print(__doc__)
     elif sys.argv[1] == "pull":
-        print_todolist()
+        print_todolist('@default')
     elif sys.argv[1] == "push":
         if not len(sys.argv) == 3:
             print("'push' expects exactly 1 argument")
         if not os.path.exists(path):
             print("The file you want to push does not exist.")
             sys.exit(2)
-        push_todolist(path)
+        push_todolist(path, '@default')
     else:
         print(__doc__)
         sys.exit(2)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.