initialise repo
[debian/make-magic.git] / lib / loaders.py
1 #! /usr/bin/env python
2
3 '''Loader of item groups'''
4
5 import json
6
7 import core.marshal
8 import core.deptools
9 from core.bits import *
10
11 # FIXME: Need to implement predicate and requirement stuff and
12 #        all that implies!
13
14 class TaskFactory(object):
15         '''Factory to generate tasks'''
16         def __init__(self, classes, dependency_strategy=core.deptools.DigraphDependencyStrategy):
17                 self.classes = classes
18                 self.dependency_strategy = dependency_strategy
19
20         def task_from_requirements(self, requirements):
21                 '''This is to create a new task given a set of requirements
22                 '''
23                 # Instantiate items
24                 items = self.dependency_strategy.instantiate_items(self.classes)
25                 items = set(items.values())     # TODO: Fix instantiate_items return. this is unintuitive
26
27                 # Define a clear goal node that all existing goals depend on
28                 goal = TaskComplete(self.dependency_strategy.find_goal_nodes(items))
29                 items.add(goal)
30                 assert set(self.dependency_strategy.early_iter_all_items(goal)) == items
31
32                 # Filter out things that aren't for this task
33                 goal = self.dependency_strategy.filter_dependency_graph(requirements, goal)
34                 assert goal.name == 'TaskComplete'
35
36                 # Unroll groups
37                 items = set(self.dependency_strategy.early_iter_all_items(goal))
38                 items = self.dependency_strategy.make_group_dependencies_explicit_for_items(items)
39                 assert goal in items
40
41                 # Create task for great justice
42                 return Task(items, requirements, goal)
43
44 class ObjectItemLoader(object):
45         '''Load in items defined by python objects and make a TaskFactory from them'''
46
47         @classmethod
48         def taskfactory_from_objects(self, objects):
49                 ''''process class items represented by simple python objects and return a TaskFactory'''
50                 classes = []
51                 marsh = core.marshal.ItemConverter()
52                 for o in objects:
53                         self.check_sanity(o)
54                         classes.append(marsh.itemdict_to_item_class(o))
55
56                 # Have dependencies refer to the classes they depend on, not just the names
57                 # FIXME: This should probably be in the marshaller module
58                 class_dict = dict((cls.__name__, cls) for cls in classes)
59                 for cls in classes:
60                         # TODO: Warn more sanely about dependencies on non-existant items
61                         cls.depends = tuple(class_dict[c] for c in cls.depends)
62                         if issubclass(cls, Group):
63                                 cls.contains = tuple(class_dict[c] for c in cls.contains)
64
65                 return TaskFactory(classes)
66
67         @classmethod
68         def check_sanity(self, objdict):
69                 '''check that objdict is actually in the correct form
70                 if objdict isn't in the correct form for marshalling, raise
71                 a ValueError'''
72                 name,group = objdict.get('name'),objdict.get('group')
73                 if not name and not group: 
74                         raise ValueError('dict has neither name nor group keys',objdict)
75                 if name and group:
76                         raise ValueError('dict has both name and group keys')
77                 if group:
78                         contains = objdict.get('contains')
79                         if not contains:
80                                 raise ValueError('group dict has no contains key')
81                         if len(contains) == 0:
82                                 raise ValueError('group contains list is empty')
83                 return True
84
85 class JSONItemLoader(ObjectItemLoader):
86         '''Load in items defined by some json and make a TaskFactory from them'''
87
88         @classmethod
89         def load_item_classes_from_file(cls, f):
90                 ''''load json items from a file and return a TaskFactory'''
91                 return cls.taskfactory_from_objects(json.load(f))
92
93         @classmethod
94         def load_item_classes_from_string(cls, data):
95                 ''''load json items from a file and return a TaskFactory'''
96                 return cls.taskfactory_from_objects(json.loads(data))