22 import itertools |
22 import itertools |
23 from os.path import join, splitext |
23 from os.path import join, splitext |
24 from datetime import datetime, timedelta |
24 from datetime import datetime, timedelta |
25 from logging import getLogger |
25 from logging import getLogger |
26 |
26 |
27 from cubicweb import set_log_methods, server |
27 from logilab.common import configuration |
|
28 |
|
29 from yams.schema import role_name |
|
30 |
|
31 from cubicweb import ValidationError, set_log_methods, server |
28 from cubicweb.schema import VIRTUAL_RTYPES |
32 from cubicweb.schema import VIRTUAL_RTYPES |
29 from cubicweb.server.sqlutils import SQL_PREFIX |
33 from cubicweb.server.sqlutils import SQL_PREFIX |
30 from cubicweb.server.ssplanner import EditedEntity |
34 from cubicweb.server.ssplanner import EditedEntity |
31 |
35 |
32 |
36 |
101 cross_relations = () |
105 cross_relations = () |
102 |
106 |
103 # force deactivation (configuration error for instance) |
107 # force deactivation (configuration error for instance) |
104 disabled = False |
108 disabled = False |
105 |
109 |
106 def __init__(self, repo, source_config, *args, **kwargs): |
110 # source configuration options |
|
111 options = () |
|
112 |
|
113 def __init__(self, repo, source_config, eid=None): |
107 self.repo = repo |
114 self.repo = repo |
108 self.uri = source_config['uri'] |
|
109 set_log_methods(self, getLogger('cubicweb.sources.'+self.uri)) |
|
110 self.set_schema(repo.schema) |
115 self.set_schema(repo.schema) |
111 self.support_relations['identity'] = False |
116 self.support_relations['identity'] = False |
112 self.eid = None |
117 self.eid = eid |
113 self.public_config = source_config.copy() |
118 self.public_config = source_config.copy() |
114 self.remove_sensitive_information(self.public_config) |
119 self.remove_sensitive_information(self.public_config) |
|
120 self.uri = source_config.pop('uri') |
|
121 set_log_methods(self, getLogger('cubicweb.sources.'+self.uri)) |
|
122 source_config.pop('type') |
115 |
123 |
116 def __repr__(self): |
124 def __repr__(self): |
117 return '<%s source %s @%#x>' % (self.uri, self.eid, id(self)) |
125 return '<%s source %s @%#x>' % (self.uri, self.eid, id(self)) |
118 |
126 |
119 def __cmp__(self, other): |
127 def __cmp__(self, other): |
132 """method called to create a backup of source's data""" |
140 """method called to create a backup of source's data""" |
133 pass |
141 pass |
134 |
142 |
135 def restore(self, backupfile, confirm, drop): |
143 def restore(self, backupfile, confirm, drop): |
136 """method called to restore a backup of source's data""" |
144 """method called to restore a backup of source's data""" |
|
145 pass |
|
146 |
|
147 @classmethod |
|
148 def check_conf_dict(cls, eid, confdict, _=unicode, fail_if_unknown=True): |
|
149 """check configuration of source entity. Return config dict properly |
|
150 typed with defaults set. |
|
151 """ |
|
152 processed = {} |
|
153 for optname, optdict in cls.options: |
|
154 value = confdict.pop(optname, optdict.get('default')) |
|
155 if value is configuration.REQUIRED: |
|
156 if not fail_if_unknown: |
|
157 continue |
|
158 msg = _('specifying %s is mandatory' % optname) |
|
159 raise ValidationError(eid, {role_name('config', 'subject'): msg}) |
|
160 elif value is not None: |
|
161 # type check |
|
162 try: |
|
163 value = configuration.convert(value, optdict, optname) |
|
164 except Exception, ex: |
|
165 msg = unicode(ex) # XXX internationalization |
|
166 raise ValidationError(eid, {role_name('config', 'subject'): msg}) |
|
167 processed[optname] = value |
|
168 # cw < 3.10 bw compat |
|
169 try: |
|
170 processed['adapter'] = confdict['adapter'] |
|
171 except: |
|
172 pass |
|
173 # check for unknown options |
|
174 if confdict and not confdict.keys() == ['adapter']: |
|
175 if fail_if_unknown: |
|
176 msg = _('unknown options %s') % ', '.join(confdict) |
|
177 raise ValidationError(eid, {role_name('config', 'subject'): msg}) |
|
178 else: |
|
179 logger = getLogger('cubicweb.sources') |
|
180 logger.warning('unknown options %s', ', '.join(confdict)) |
|
181 # add options to processed, they may be necessary during migration |
|
182 processed.update(confdict) |
|
183 return processed |
|
184 |
|
185 @classmethod |
|
186 def check_config(cls, source_entity): |
|
187 """check configuration of source entity""" |
|
188 return cls.check_conf_dict(source_entity.eid, source_entity.host_config, |
|
189 _=source_entity._cw._) |
|
190 |
|
191 def update_config(self, source_entity, typedconfig): |
|
192 """update configuration from source entity. `typedconfig` is config |
|
193 properly typed with defaults set |
|
194 """ |
137 pass |
195 pass |
138 |
196 |
139 # source initialization / finalization ##################################### |
197 # source initialization / finalization ##################################### |
140 |
198 |
141 def set_schema(self, schema): |
199 def set_schema(self, schema): |
501 try: |
559 try: |
502 return SOURCE_TYPES[source_type] |
560 return SOURCE_TYPES[source_type] |
503 except KeyError: |
561 except KeyError: |
504 raise RuntimeError('Unknown source type %r' % source_type) |
562 raise RuntimeError('Unknown source type %r' % source_type) |
505 |
563 |
506 def get_source(type, source_config, repo): |
564 def get_source(type, source_config, repo, eid): |
507 """return a source adapter according to the adapter field in the |
565 """return a source adapter according to the adapter field in the source's |
508 source's configuration |
566 configuration |
509 """ |
567 """ |
510 return source_adapter(type)(repo, source_config) |
568 return source_adapter(type)(repo, source_config, eid) |