Merge lp:~abentley/charmworld/remove-scan-ingest-job into lp:~juju-jitsu/charmworld/trunk

Proposed by Aaron Bentley
Status: Merged
Approved by: Curtis Hovey
Approved revision: 285
Merged at revision: 281
Proposed branch: lp:~abentley/charmworld/remove-scan-ingest-job
Merge into: lp:~juju-jitsu/charmworld/trunk
Prerequisite: lp:~abentley/charmworld/remove-bzr-ingest-job
Diff against target: 409 lines (+152/-150)
3 files modified
charmworld/jobs/ingest.py (+134/-134)
charmworld/jobs/tests/test_scan.py (+16/-14)
charmworld/testing/factory.py (+2/-2)
To merge this branch: bzr merge lp:~abentley/charmworld/remove-scan-ingest-job
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+171093@code.launchpad.net

Commit message

Remove ScanIngestJob

Description of the change

This branch removes ScanIngestJob, as part of the fix for 1190015: "ingest is really a set of functions that are run consecutively, but is structured as a list of jobs".

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you.

This is fine to land. The diff reminds me of the cruft I was concerned about in the DB. Now that we have a Charm model, I don't think we need short_url, i_provides, i_requires (and their d_ counterparts). I fixed a UI bug recently by changing the model to create the short_url if one is not in the db. I will report a bug about this so that we can discuss which data is not needed in the db.

review: Approve (code)
Revision history for this message
Aaron Bentley (abentley) wrote :

I believe the i_requires and i_provides fields were meant to make these easy to query for a search engine ("i" being short for "index"). We should probably wait until we've restructured the representation of "requires" and "provides" before we consider deleting the i_ variants.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmworld/jobs/ingest.py'
2--- charmworld/jobs/ingest.py 2013-06-21 19:38:25 +0000
3+++ charmworld/jobs/ingest.py 2013-06-24 14:42:35 +0000
4@@ -244,8 +244,7 @@
5 if not run_job(ChangelogIngestJob(), charm_data):
6 return False
7 update_date_created(charm_data, log)
8- if not run_job(ScanIngestJob(), charm_data, db=db):
9- return False
10+ scan_charm(charm_data, db=db)
11 except Exception as e:
12 err_msg = "%s error: %s" % (charm_data, str(e))
13 log.exception(err_msg)
14@@ -509,140 +508,141 @@
15 charm['proof'] = proof
16
17
18-class ScanIngestJob(FSIngestJob):
19-
20- name = 'scan'
21-
22- @staticmethod
23- def normalize_interfaces(interfaces):
24- # Transform the short defintion of relations into the
25- # long form. Quoted from
26- # https://juju.ubuntu.com/docs/charm.html#the-metadata-file :
27- #
28- # As a shortcut, if these properties are not defined, and
29- # instead a single string value is provided next to the
30- # relation name, the string is taken as the interface
31- # value, as seen in this example:
32- #
33- # requires:
34- # db: mysql
35- for relation_name, relation_data in interfaces.items():
36- if isinstance(relation_data, StringTypes):
37- interfaces[relation_name] = {'interface': relation_data}
38-
39- @classmethod
40- def process_charm(cls, charm):
41- # Enrich charm metadata for webapp.
42-
43- # Charm url
44- if charm["promulgated"]:
45- charm["short_url"] = "/charms/%s/%s" % (
46- charm["series"], charm["name"])
47- else:
48- charm["short_url"] = "/~%s/%s/%s" % (charm["owner"],
49- charm["series"],
50- charm["name"])
51-
52- # Charm label
53- if charm["promulgated"]:
54- charm["label"] = "%s/%s" % (charm["series"], charm["name"])
55- else:
56- charm["label"] = "~%s:%s/%s" % (charm["owner"],
57- charm["series"],
58- charm["name"])
59-
60- # Flatten the interfaces provided
61- i_provides = []
62- provides = charm.get("provides")
63- if provides:
64- cls.normalize_interfaces(provides)
65- for v in provides.values():
66- if not isinstance(v, dict):
67- continue
68- i = v.get("interface")
69- if not i:
70- continue
71- i_provides.append(i)
72- charm["i_provides"] = i_provides
73-
74- # Flatten the interfaces required
75- i_requires = []
76- requires = charm.get("requires")
77- if requires:
78- cls.normalize_interfaces(requires)
79- for v in requires.values():
80- i = v.get("interface")
81- if not i:
82- continue
83- i_requires.append(i)
84- charm["i_requires"] = i_requires
85- return charm
86-
87- def run(self, charm_data):
88- # Note: charm_data is modified in-place. IndexIngestJob requires
89- # these modifications.
90- files = charm_data['files']
91- # Some files have bad characters in them since they are used as mongo
92- # keys. Use their escaped forms instead.
93- metadata_file = quote_key('metadata.yaml')
94- config_file = quote_key('config.yaml')
95-
96- if metadata_file not in files:
97- self.log.info(
98- "Charm has no metadata: %s", charm_data["branch_spec"])
99- return
100- else:
101- cfile = CharmFileSet.get_by_id(
102- self.fs, files[metadata_file]['fileid'])
103- try:
104- metadata = quote_yaml(yaml.load(cfile.read()))
105- except Exception, exc:
106- raise IngestError(
107- 'Invalid charm metadata %s: %s' % (
108+def scan_charm(charm_data, db=None, fs=None):
109+ # Note: charm_data is modified in-place. IndexIngestJob requires
110+ # these modifications.
111+ job = FSIngestJob()
112+ job.setup(db, fs)
113+ db = job.db
114+ fs = job.fs
115+ log = job.log
116+ files = charm_data['files']
117+ # Some files have bad characters in them since they are used as mongo
118+ # keys. Use their escaped forms instead.
119+ metadata_file = quote_key('metadata.yaml')
120+ config_file = quote_key('config.yaml')
121+
122+ if metadata_file not in files:
123+ log.info(
124+ "Charm has no metadata: %s", charm_data["branch_spec"])
125+ return
126+ else:
127+ cfile = CharmFileSet.get_by_id(
128+ fs, files[metadata_file]['fileid'])
129+ try:
130+ metadata = quote_yaml(yaml.load(cfile.read()))
131+ except Exception, exc:
132+ raise IngestError(
133+ 'Invalid charm metadata %s: %s' % (
134+ charm_data['branch_spec'],
135+ exc)
136+ )
137+
138+ if config_file in files:
139+ cfile = CharmFileSet.get_by_id(
140+ fs, files[config_file]['fileid'])
141+ config_raw = cfile.read()
142+
143+ try:
144+ config = quote_yaml(yaml.load(config_raw))
145+ except Exception, exc:
146+ raise IngestError(
147+ 'Invalid charm config yaml. %s: %s' % (
148 charm_data['branch_spec'],
149 exc)
150- )
151-
152- if config_file in files:
153- cfile = CharmFileSet.get_by_id(
154- self.fs, files[config_file]['fileid'])
155- config_raw = cfile.read()
156-
157- try:
158- config = quote_yaml(yaml.load(config_raw))
159- except Exception, exc:
160- raise IngestError(
161- 'Invalid charm config yaml. %s: %s' % (
162- charm_data['branch_spec'],
163- exc)
164- )
165-
166- metadata["config"] = config
167- metadata["config_raw"] = config_raw
168-
169- if 'revision' in files:
170- cfile = CharmFileSet.get_by_id(
171- self.fs, files['revision']['fileid'])
172- rev_raw = cfile.read()
173- rev_id = int(rev_raw.strip())
174- metadata["revision"] = rev_id
175- elif not "revision" in metadata:
176- self.log.info("Invalid revision %s", charm_data["branch_spec"])
177- metadata["revision"] = 0
178-
179- hooks = []
180- for filedata in files.values():
181- if filedata['subdir'] == 'hooks':
182- hooks.append(filedata['filename'])
183- hooks.sort()
184- metadata["hooks"] = hooks
185-
186- # Stuff into the db
187- metadata.update(charm_data)
188- metadata = self.process_charm(metadata)
189- # Modify charm_data itself.
190- charm_data.clear()
191- charm_data.update(metadata)
192+ )
193+
194+ metadata["config"] = config
195+ metadata["config_raw"] = config_raw
196+
197+ if 'revision' in files:
198+ cfile = CharmFileSet.get_by_id(
199+ fs, files['revision']['fileid'])
200+ rev_raw = cfile.read()
201+ rev_id = int(rev_raw.strip())
202+ metadata["revision"] = rev_id
203+ elif not "revision" in metadata:
204+ log.info("Invalid revision %s", charm_data["branch_spec"])
205+ metadata["revision"] = 0
206+
207+ hooks = []
208+ for filedata in files.values():
209+ if filedata['subdir'] == 'hooks':
210+ hooks.append(filedata['filename'])
211+ hooks.sort()
212+ metadata["hooks"] = hooks
213+
214+ # Stuff into the db
215+ metadata.update(charm_data)
216+ metadata = process_charm(metadata)
217+ # Modify charm_data itself.
218+ charm_data.clear()
219+ charm_data.update(metadata)
220+
221+
222+def normalize_interfaces(interfaces):
223+ # Transform the short defintion of relations into the
224+ # long form. Quoted from
225+ # https://juju.ubuntu.com/docs/charm.html#the-metadata-file :
226+ #
227+ # As a shortcut, if these properties are not defined, and
228+ # instead a single string value is provided next to the
229+ # relation name, the string is taken as the interface
230+ # value, as seen in this example:
231+ #
232+ # requires:
233+ # db: mysql
234+ for relation_name, relation_data in interfaces.items():
235+ if isinstance(relation_data, StringTypes):
236+ interfaces[relation_name] = {'interface': relation_data}
237+
238+
239+def process_charm(charm):
240+ # Enrich charm metadata for webapp.
241+
242+ # Charm url
243+ if charm["promulgated"]:
244+ charm["short_url"] = "/charms/%s/%s" % (
245+ charm["series"], charm["name"])
246+ else:
247+ charm["short_url"] = "/~%s/%s/%s" % (charm["owner"],
248+ charm["series"],
249+ charm["name"])
250+
251+ # Charm label
252+ if charm["promulgated"]:
253+ charm["label"] = "%s/%s" % (charm["series"], charm["name"])
254+ else:
255+ charm["label"] = "~%s:%s/%s" % (charm["owner"],
256+ charm["series"],
257+ charm["name"])
258+
259+ # Flatten the interfaces provided
260+ i_provides = []
261+ provides = charm.get("provides")
262+ if provides:
263+ normalize_interfaces(provides)
264+ for v in provides.values():
265+ if not isinstance(v, dict):
266+ continue
267+ i = v.get("interface")
268+ if not i:
269+ continue
270+ i_provides.append(i)
271+ charm["i_provides"] = i_provides
272+
273+ # Flatten the interfaces required
274+ i_requires = []
275+ requires = charm.get("requires")
276+ if requires:
277+ normalize_interfaces(requires)
278+ for v in requires.values():
279+ i = v.get("interface")
280+ if not i:
281+ continue
282+ i_requires.append(i)
283+ charm["i_requires"] = i_requires
284+ return charm
285
286
287 def addresses(charm):
288
289=== modified file 'charmworld/jobs/tests/test_scan.py'
290--- charmworld/jobs/tests/test_scan.py 2013-06-21 19:53:57 +0000
291+++ charmworld/jobs/tests/test_scan.py 2013-06-24 14:42:35 +0000
292@@ -2,8 +2,10 @@
293 # GNU Affero General Public License version 3 (see the file LICENSE).
294
295 from charmworld.jobs.ingest import (
296+ FSIngestJob,
297 IngestError,
298- ScanIngestJob,
299+ process_charm,
300+ scan_charm,
301 store_branch_files,
302 )
303 from charmworld.testing import factory
304@@ -11,21 +13,21 @@
305 from charmworld.utils import quote_key
306
307
308-class TestScanJob(JobTestBase):
309+class TestScanCharm(JobTestBase):
310
311 def setUp(self):
312- super(TestScanJob, self).setUp()
313- self.scan_job = ScanIngestJob()
314- self.scan_job.setup(db=self.db)
315+ super(TestScanCharm, self).setUp()
316+ self.fs_job = FSIngestJob()
317+ self.fs_job.setup(db=self.db)
318 ignore, self.charm = factory.makeCharm(self.db, with_real_files=True)
319 self.charm['files'] = dict([
320 (quote_key(cfile.filename), dict(cfile)) for cfile in
321- store_branch_files(self.scan_job.fs, self.charm, self.scan_job.log)
322+ store_branch_files(self.fs_job.fs, self.charm, self.fs_job.log)
323 ])
324
325 def test_config_metadata_with_dotted_keys(self):
326 del self.charm['config']
327- self.scan_job.run(self.charm)
328+ scan_charm(self.charm, self.db, self.fs_job.fs)
329 # The key 'dotted.name' is replaced with 'dotted%2Ename', and
330 # 'foo.bar' is replaced with 'foo%2Ebar'.
331 self.assertFalse('dotted.name' in self.charm)
332@@ -42,11 +44,11 @@
333 # https://juju.ubuntu.com/docs/charm.html#the-metadata-file
334 # for more details.)
335 #
336- # ScanJob.normalize_interfaces() transforms the short form
337+ # normalize_interfaces() transforms the short form
338 # into the long form for further processing and for storage.
339 del self.charm['provides']
340 del self.charm['requires']
341- self.scan_job.run(self.charm)
342+ scan_charm(self.charm, self.db, self.fs_job.fs)
343 # The sample metadata file has entries for the short and long
344 # form of the interface specification in the "provides" and
345 # in the "requires" section. The short entries are converted
346@@ -70,7 +72,7 @@
347 'fileid': metadata_file._id
348 }
349 with self.assertRaises(IngestError) as ctx:
350- self.scan_job.run(self.charm)
351+ scan_charm(self.charm, self.db, self.fs_job.fs)
352 info = str(ctx.exception)
353 self.assertTrue(info.startswith(
354 'Invalid charm metadata ~charmers/charms/precise/sample'))
355@@ -83,7 +85,7 @@
356 'fileid': config_file._id
357 }
358 with self.assertRaises(IngestError) as ctx:
359- self.scan_job.run(self.charm)
360+ scan_charm(self.charm, self.db, self.fs_job.fs)
361 info = str(ctx.exception)
362 self.assertTrue(info.startswith(
363 'Invalid charm config yaml. ~charmers/charms/precise/sample'))
364@@ -97,7 +99,7 @@
365 'name': 'bar',
366 'promulgated': False,
367 }
368- self.scan_job.process_charm(charm)
369+ process_charm(charm)
370 self.assertEqual('/~foo/precise/bar', charm['short_url'])
371 # The label of unpromulgated charms starts with the owner name.
372 self.assertEqual('~foo:precise/bar', charm['label'])
373@@ -109,7 +111,7 @@
374 'name': 'bar',
375 'promulgated': True,
376 }
377- self.scan_job.process_charm(charm)
378+ process_charm(charm)
379 self.assertEqual('/charms/precise/bar', charm['short_url'])
380 self.assertEqual('precise/bar', charm['label'])
381 # This is also true if the charm is not owned by charmes.
382@@ -119,6 +121,6 @@
383 'name': 'bar',
384 'promulgated': True,
385 }
386- self.scan_job.process_charm(charm)
387+ process_charm(charm)
388 self.assertEqual('/charms/precise/bar', charm['short_url'])
389 self.assertEqual('precise/bar', charm['label'])
390
391=== modified file 'charmworld/testing/factory.py'
392--- charmworld/testing/factory.py 2013-06-17 15:02:59 +0000
393+++ charmworld/testing/factory.py 2013-06-24 14:42:35 +0000
394@@ -21,7 +21,7 @@
395 )
396 from charmworld.jobs.ingest import (
397 JENKINS_PROVIDERS,
398- ScanIngestJob,
399+ process_charm,
400 )
401 from charmworld.models import (
402 getfs,
403@@ -279,7 +279,7 @@
404 charm['name'], charm['branch_spec'], status, provider)
405 if subordinate:
406 charm['subordinate'] = True
407- ScanIngestJob.process_charm(charm)
408+ process_charm(charm)
409 return charm
410
411

Subscribers

People subscribed via source and target branches