[csw-devel] SF.net SVN: gar:[13107] csw/mgar/gar/v2
wahwah at users.sourceforge.net
wahwah at users.sourceforge.net
Sat Jan 29 16:48:42 CET 2011
Revision: 13107
http://gar.svn.sourceforge.net/gar/?rev=13107&view=rev
Author: wahwah
Date: 2011-01-29 15:48:41 +0000 (Sat, 29 Jan 2011)
Log Message:
-----------
catalog_notifier: Initial commit
Initial inquiry in the mailing list:
http://lists.opencsw.org/pipermail/maintainers/2011-January/013865.html
This is the first iteration of implementation of the notifier.
It needs to be used with caution, because of the potential of spamming
people.
Notes:
- It stores previous catalog state in a pickle file
- It does not store history, only the previous version
- It does not support locking
- Allows whitelisting for testing
- Default behavior is not to send e-mail, but only print to screen
Modified Paths:
--------------
csw/mgar/gar/v2/lib/python/catalog.py
csw/mgar/gar/v2/lib/python/catalog_test.py
csw/mgar/gar/v2/tests/run_tests.py
Added Paths:
-----------
csw/mgar/gar/v2/lib/python/catalog_notifier.py
csw/mgar/gar/v2/lib/python/catalog_notifier_test.py
Modified: csw/mgar/gar/v2/lib/python/catalog.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog.py 2011-01-29 15:48:01 UTC (rev 13106)
+++ csw/mgar/gar/v2/lib/python/catalog.py 2011-01-29 15:48:41 UTC (rev 13107)
@@ -174,8 +174,14 @@
def GetCatalogDiff(self, cat_a, cat_b):
"""Returns a difference between two catalogs."""
- bc_a = cat_a.GetDataByCatalogname()
- bc_b = cat_b.GetDataByCatalogname()
+ if type(cat_a) == dict:
+ bc_a = cat_a
+ else:
+ bc_a = cat_a.GetDataByCatalogname()
+ if type(cat_b) == dict:
+ bc_b = cat_b
+ else:
+ bc_b = cat_b.GetDataByCatalogname()
cn_a = set(bc_a)
cn_b = set(bc_b)
new_catalognames = cn_b.difference(cn_a)
Added: csw/mgar/gar/v2/lib/python/catalog_notifier.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog_notifier.py (rev 0)
+++ csw/mgar/gar/v2/lib/python/catalog_notifier.py 2011-01-29 15:48:41 UTC (rev 13107)
@@ -0,0 +1,274 @@
+#!/usr/bin/env python2.6
+
+"""Polls a designated catalog tree, and sends notifications about
+package updates."""
+
+import optparse
+import catalog
+import common_constants
+from Cheetah import Template
+import urllib2
+import logging
+import configuration
+import pprint
+import cPickle
+import json
+import os.path
+import smtplib
+from email.mime.text import MIMEText
+
+REPORT_TMPL = u"""Catalog update report for $email
+Catalog URL: $url
+#if "new_pkgs" in $pkg_data
+
+New packages:
+#for basename in $pkg_data["new_pkgs"]
+* $basename
+ In catalogs:
+#for catalog in $sorted($pkg_data["new_pkgs"][basename]["catalogs"])
+ - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "removed_pkgs" in $pkg_data
+
+Removed packages:
+#for basename in $pkg_data["removed_pkgs"]
+* $basename
+ From catalogs:
+#for catalog in $sorted($pkg_data["removed_pkgs"][basename]["catalogs"])
+ - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "upgraded_pkg" in $pkg_data
+
+Version change (probably upgrade):
+#for basename in $pkg_data["upgraded_pkg"]
+* $basename
+ In catalogs:
+#for catalog in $sorted($pkg_data["upgraded_pkg"][basename]["catalogs"])
+ - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "lost_pkg" in $pkg_data
+
+You no longer maintain packages:
+#for basename in $pkg_data["lost_pkg"]
+* $basename
+ In catalogs:
+#for catalog in $sorted($pkg_data["lost_pkg"][basename]["catalogs"])
+ - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "got_pkg" in $pkg_data
+
+You took over packages:
+#for basename in $pkg_data["got_pkg"]
+* $basename
+ In catalogs:
+#for catalog in $sorted($pkg_data["got_pkg"][basename]["catalogs"])
+ - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+"""
+
+class RestClient(object):
+
+ def GetPkgByMd5(self, md5_sum):
+ url = "http://buildfarm.opencsw.org/pkgdb/rest/srv4/%s/" % md5_sum
+ logging.debug("GetPkgByMd5(): calling %s", url)
+ data = urllib2.urlopen(url).read()
+ return json.loads(data)
+
+ def GetMaintainerByMd5(self, md5_sum):
+ pkg = self.GetPkgByMd5(md5_sum)
+ return {
+ "maintainer_email": pkg["maintainer_email"],
+ }
+
+
+class NotificationFormatter(object):
+
+ def _GetPkgsByMaintainer(self, catalogs, rest_client):
+ c = catalog.CatalogComparator()
+ pkgs_by_maintainer = {}
+ for catrel, arch, osrel, cat_a, cat_b in catalogs:
+ catalog_key = (catrel, arch, osrel)
+ new_pkgs, removed_pkgs, updated_pkgs = c.GetCatalogDiff(cat_a, cat_b)
+ labels_and_lists = (
+ ("new_pkgs", new_pkgs),
+ ("removed_pkgs", removed_pkgs),
+ )
+ for label, pkg_list in labels_and_lists:
+ for pkg in pkg_list:
+ maintainer = rest_client.GetMaintainerByMd5(pkg["md5sum"])
+ maintainer_email = maintainer["maintainer_email"]
+ pkgs_by_maintainer.setdefault(maintainer_email, {})
+ pkgs_by_maintainer[maintainer_email].setdefault(label, {})
+ labeled = pkgs_by_maintainer[maintainer_email][label]
+ basename = pkg["file_basename"]
+ labeled.setdefault(basename, {
+ "pkg": pkg,
+ "catalogs": [],
+ })
+ labeled[basename]["catalogs"].append(catalog_key)
+ for d in updated_pkgs:
+ from_pkg = d["from"]
+ to_pkg = d["to"]
+ maintainer_from = rest_client.GetMaintainerByMd5(from_pkg["md5sum"])
+ maintainer_to = rest_client.GetMaintainerByMd5(to_pkg["md5sum"])
+ from_email = maintainer_from["maintainer_email"]
+ to_email = maintainer_to["maintainer_email"]
+ if from_email == to_email:
+ # A normal upgrade, no takeover
+ label = "upgraded_pkg"
+ self._StorePkgUpdate(catalog_key,
+ label, pkgs_by_maintainer, from_email, from_pkg, to_pkg)
+ else:
+ # Package takeover
+ self._StorePkgUpdate(catalog_key,
+ "lost_pkg", pkgs_by_maintainer, from_email, from_pkg, to_pkg)
+ self._StorePkgUpdate(catalog_key,
+ "got_pkg", pkgs_by_maintainer, to_email, from_pkg, to_pkg)
+ return pkgs_by_maintainer
+
+ def _StorePkgUpdate(self,
+ catalog_key,
+ label, pkgs_by_maintainer, email, from_pkg, to_pkg):
+ pkgs_by_maintainer.setdefault(email, {})
+ pkgs_by_maintainer[email].setdefault(label, {})
+ labeled = pkgs_by_maintainer[email][label]
+ basename = to_pkg["file_basename"]
+ labeled.setdefault(basename, {
+ "to_pkg": to_pkg,
+ "from_pkg": {},
+ "catalogs": [],
+ })
+ labeled[basename]["from_pkg"][from_pkg["file_basename"]] = from_pkg
+ labeled[basename]["catalogs"].append(catalog_key)
+
+ def _RenderForMaintainer(self, pkg_data, email, url):
+ namespace = {
+ "pkg_data": pkg_data,
+ "email": email,
+ "url": url}
+ t = Template.Template(REPORT_TMPL, searchList=[namespace])
+ return unicode(t)
+
+ def FormatNotifications(self, url, catalogs, rest_client):
+ """Formats a notification from a series of catalogs.
+
+ Args:
+ url: Base URL for catalogs
+ catalogs: A list of triplets (catrel, arch, osrel, cat_a, cat_b)
+ rest_client: An interface to the outside world
+ """
+ pkgs_by_maintainer = self._GetPkgsByMaintainer(catalogs, rest_client)
+ rendered_notifications = {}
+ for email in pkgs_by_maintainer:
+ rendered_notifications[email] = self._RenderForMaintainer(
+ pkgs_by_maintainer[email], email, url)
+ return rendered_notifications
+
+
+class CatalogIndexDownloader(object):
+
+ def GetCatalogsByTriad(self, cat_tree_url):
+ catalogs_by_triad = {}
+ for catrel in common_constants.DEFAULT_CATALOG_RELEASES:
+ for arch in common_constants.PHYSICAL_ARCHITECTURES:
+ for osrel in common_constants.OS_RELS:
+ short_osrel = osrel.replace("SunOS", "")
+ catalog_file_url = (
+ "%s%s/%s/%s/catalog"
+ % (cat_tree_url, catrel, arch, short_osrel))
+ logging.info("Opening %s", repr(catalog_file_url))
+ try:
+ f = urllib2.urlopen(catalog_file_url)
+ key = (catrel, arch, osrel)
+ catalog_instance = catalog.OpencswCatalog(f)
+ catalogs_by_triad[key] = catalog_instance.GetDataByCatalogname()
+ except urllib2.URLError, e:
+ logging.warning(e)
+ return catalogs_by_triad
+
+
+def main():
+ DEFAULT_URL = "http://mirror.opencsw.org/opencsw/"
+ DEFAULT_URL = "http://ivy.home.blizinski.pl/~maciej/opencsw/"
+ parser = optparse.OptionParser()
+ parser.add_option("-u", "--url",
+ dest="url", help="Base URL of OpenCSW catalog",
+ default=DEFAULT_URL)
+ parser.add_option("-d", "--debug",
+ dest="debug", action="store_true",
+ default=False)
+ parser.add_option("-s", "--send-notifications",
+ dest="send_notifications", action="store_true",
+ default=False)
+ parser.add_option("-p", "--pickle-file",
+ dest="pickle_file", help="Pickle file",
+ default="/tmp/opencsw-notifier-data/example.pickle")
+ parser.add_option("-w", "--whitelist",
+ dest="whitelist",
+ help="E-mail address whitelist, comma separated",
+ default=None)
+ options, args = parser.parse_args()
+ logging.basicConfig(level=logging.DEBUG)
+ # Getting catalogs
+ cat_tree_url = options.url
+ downloader = CatalogIndexDownloader()
+ catalogs_by_triad = downloader.GetCatalogsByTriad(cat_tree_url)
+ pickle_path = options.pickle_file
+ previous_catalogs_by_triad = None
+ try:
+ with open(pickle_path, "rb") as fd:
+ previous_catalogs_by_triad = cPickle.load(fd)
+ except (IOError, EOFError), e:
+ logging.warning(e)
+ previous_catalogs_by_triad = {}
+ # Merge the two data structures here
+ catalogs = []
+ for key in catalogs_by_triad:
+ if key in previous_catalogs_by_triad:
+ catalogs.append(
+ # ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+ key + (previous_catalogs_by_triad[key], catalogs_by_triad[key])
+ )
+ else:
+ logging.debug("%s not found in previous_catalogs_by_triad", key)
+ formatter = NotificationFormatter()
+ rest_client = RestClient()
+ notifications = formatter.FormatNotifications(
+ cat_tree_url, catalogs, rest_client)
+ whitelist = frozenset()
+ if options.whitelist:
+ whitelist = frozenset(options.whitelist.split(","))
+ logging.debug("Email whitelist: %s", whitelist)
+ for email in notifications:
+ if options.send_notifications:
+ logging.debug("email: %s", repr(email))
+ if email not in whitelist: continue
+ logging.debug("Sending.")
+ msg = MIMEText(notifications[email])
+ msg["Subject"] = "OpenCSW catalog update report"
+ from_address = "Catalog update notifier <noreply at opencsw.org>"
+ msg['From'] = from_address
+ msg['To'] = email
+ s = smtplib.SMTP('localhost')
+ s.sendmail(from_address, [email], msg.as_string())
+ s.quit()
+ logging.debug("E-mail sent.")
+ else:
+ print notifications[email]
+ print "* * *"
+ with open(pickle_path, "wb") as fd:
+ cPickle.dump(catalogs_by_triad, fd)
+
+
+if __name__ == '__main__':
+ main()
Property changes on: csw/mgar/gar/v2/lib/python/catalog_notifier.py
___________________________________________________________________
Added: svn:executable
+ *
Added: csw/mgar/gar/v2/lib/python/catalog_notifier_test.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog_notifier_test.py (rev 0)
+++ csw/mgar/gar/v2/lib/python/catalog_notifier_test.py 2011-01-29 15:48:41 UTC (rev 13107)
@@ -0,0 +1,186 @@
+#!/usr/bin/env python2.6
+
+import unittest
+import mox
+import catalog_notifier
+import catalog
+import catalog_test
+import copy
+import pprint
+
+
+class NotificationFormatterTest(mox.MoxTestBase):
+
+ def disabled_testOne(self):
+ """This tested too much."""
+ f = catalog_notifier.NotificationFormatter()
+ rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+ url = "http://www.example.com/opencsw/"
+ cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+ cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+ catalogs = [
+ ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+ ]
+ maintainers = {
+ "cfe40c06e994f6e8d3b191396d0365cb": {"maintainer_email": "joe at example.com"},
+ }
+ cat_a.GetDataByCatalogname().AndReturn({})
+ cat_b.GetDataByCatalogname().AndReturn({"syslog_ng": catalog_test.PKG_STRUCT_1})
+ self.mox.ReplayAll()
+ self.assertEqual(
+ "report here",
+ f.FormatNotification(url, catalogs, rest_client_mock))
+
+ def test_GetPkgsByMaintainerNew(self):
+ f = catalog_notifier.NotificationFormatter()
+ rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+ cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+ cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+ catalogs = [
+ ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+ ]
+ rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+ {"maintainer_email": "joe at example.com"}
+ )
+ cat_a.GetDataByCatalogname().AndReturn({})
+ cat_b.GetDataByCatalogname().AndReturn({
+ "syslog_ng": catalog_test.PKG_STRUCT_1,
+ })
+ self.mox.ReplayAll()
+ expected = {'joe at example.com': {
+ 'new_pkgs': {
+ catalog_test.PKG_STRUCT_1["file_basename"]: {
+ "pkg": catalog_test.PKG_STRUCT_1,
+ "catalogs": [
+ ("fossil", "amd65", "SolarOS5.12"),
+ ],
+ },
+ }}
+ }
+ self.assertEqual(
+ expected,
+ f._GetPkgsByMaintainer(catalogs, rest_client_mock))
+ expected_text = u"""aa"""
+ # Uncomment to see rendered template
+ # print f._RenderForMaintainer(expected["joe at example.com"])
+
+ def test_GetPkgsByMaintainerRemoved(self):
+ f = catalog_notifier.NotificationFormatter()
+ rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+ cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+ cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+ catalogs = [
+ ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+ ]
+ rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+ {"maintainer_email": "joe at example.com"}
+ )
+ cat_a.GetDataByCatalogname().AndReturn({
+ "syslog_ng": catalog_test.PKG_STRUCT_1,
+ })
+ cat_b.GetDataByCatalogname().AndReturn({})
+ self.mox.ReplayAll()
+ expected = {'joe at example.com': {
+ 'removed_pkgs': {
+ catalog_test.PKG_STRUCT_1["file_basename"]: {
+ "pkg": catalog_test.PKG_STRUCT_1,
+ "catalogs": [
+ ("fossil", "amd65", "SolarOS5.12"),
+ ],
+ },
+ }}
+ }
+ self.assertEqual(
+ expected,
+ f._GetPkgsByMaintainer(catalogs, rest_client_mock))
+ expected_text = u"""aa"""
+ # Uncomment to see rendered template
+ # print f._RenderForMaintainer(expected["joe at example.com"])
+
+ def test_GetPkgsByMaintainerTakeover(self):
+ f = catalog_notifier.NotificationFormatter()
+ rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+ cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+ cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+ catalogs = [
+ ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+ ]
+ previous_pkg = copy.deepcopy(catalog_test.PKG_STRUCT_1)
+ previous_pkg["version"] = "previous_version"
+ previous_pkg["md5sum"] = "previous_md5"
+ cat_a.GetDataByCatalogname().AndReturn({
+ "syslog_ng": previous_pkg,
+ })
+ cat_b.GetDataByCatalogname().AndReturn({
+ "syslog_ng": catalog_test.PKG_STRUCT_1,
+ })
+ rest_client_mock.GetMaintainerByMd5('previous_md5').AndReturn(
+ {"maintainer_email": "jack at example.com"}
+ )
+ rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+ {"maintainer_email": "joe at example.com"}
+ )
+ self.mox.ReplayAll()
+ result = f._GetPkgsByMaintainer(catalogs, rest_client_mock)
+ self.assertTrue("jack at example.com" in result)
+ self.assertEqual({"lost_pkg": {
+ catalog_test.PKG_STRUCT_1["file_basename"]: {
+ "from_pkg": {previous_pkg["file_basename"]: previous_pkg},
+ "to_pkg": catalog_test.PKG_STRUCT_1,
+ "catalogs": [("fossil", "amd65", "SolarOS5.12")],
+ }}},
+ result["jack at example.com"])
+ self.assertEqual({"got_pkg": {
+ catalog_test.PKG_STRUCT_1["file_basename"]: {
+ "from_pkg": {previous_pkg["file_basename"]: previous_pkg},
+ "to_pkg": catalog_test.PKG_STRUCT_1,
+ "catalogs": [("fossil", "amd65", "SolarOS5.12")],
+ }}},
+ result["joe at example.com"])
+ # Uncomment to see rendered templates
+ # print f._RenderForMaintainer(
+ # result["jack at example.com"], "jack at example.com",
+ # "http://mirror.example.com")
+ # print f._RenderForMaintainer(
+ # result["joe at example.com"], "joe at example.com",
+ # "http://mirror.example.com")
+
+ def test_GetPkgsByMaintainerUpgrade(self):
+ f = catalog_notifier.NotificationFormatter()
+ rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+ cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+ cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+ catalogs = [
+ ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+ ]
+ previous_pkg = copy.deepcopy(catalog_test.PKG_STRUCT_1)
+ previous_pkg["version"] = "previous_version"
+ previous_pkg["md5sum"] = "previous_md5"
+ cat_a.GetDataByCatalogname().AndReturn({
+ "syslog_ng": previous_pkg,
+ })
+ cat_b.GetDataByCatalogname().AndReturn({
+ "syslog_ng": catalog_test.PKG_STRUCT_1,
+ })
+ rest_client_mock.GetMaintainerByMd5('previous_md5').AndReturn(
+ {"maintainer_email": "jack at example.com"}
+ )
+ rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+ {"maintainer_email": "jack at example.com"}
+ )
+ self.mox.ReplayAll()
+ result = f._GetPkgsByMaintainer(catalogs, rest_client_mock)
+ # pprint.pprint(result)
+ self.assertTrue("jack at example.com" in result)
+ # In this scenario, we group packages by the target package (after upgrade)
+ self.assertEqual({"upgraded_pkg": {
+ catalog_test.PKG_STRUCT_1["file_basename"]: {
+ "from_pkg": {previous_pkg["file_basename"]: previous_pkg},
+ "to_pkg": catalog_test.PKG_STRUCT_1,
+ "catalogs": [("fossil", "amd65", "SolarOS5.12")],
+ }}},
+ result["jack at example.com"])
+
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: csw/mgar/gar/v2/lib/python/catalog_notifier_test.py
___________________________________________________________________
Added: svn:executable
+ *
Modified: csw/mgar/gar/v2/lib/python/catalog_test.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog_test.py 2011-01-29 15:48:01 UTC (rev 13106)
+++ csw/mgar/gar/v2/lib/python/catalog_test.py 2011-01-29 15:48:41 UTC (rev 13107)
@@ -25,8 +25,21 @@
'145351cf6186fdcadcd169b66387f72f 214091 '
'CSWcommon|CSWlibevent none none\n')
+PKG_STRUCT_1 = {
+ 'category': 'none',
+ 'i_deps': (),
+ 'pkgname': 'CSWsyslogng',
+ 'md5sum': 'cfe40c06e994f6e8d3b191396d0365cb',
+ 'version': '3.0.4,REV=2009.08.30',
+ 'deps': ('CSWgcc4corert', 'CSWeventlog', 'CSWosslrt', 'CSWzlib',
+ 'CSWpcrert', 'CSWggettextrt', 'CSWglib2', 'CSWtcpwrap',
+ 'CSWcswclassutils', 'CSWcommon'),
+ 'file_basename': 'syslog_ng-3.0.4,REV=2009.08.30-SunOS5.8-i386-CSW.pkg.gz',
+ 'size': '137550',
+ 'catalogname': 'syslog_ng'}
+
class OpencswCatalogUnitTest(unittest.TestCase):
def test_ParseCatalogLine_1(self):
@@ -44,20 +57,9 @@
self.assertEquals(expected, parsed)
def testGetDataByCatalogname(self):
- expected = {'syslog_ng': {
- 'category': 'none',
- 'i_deps': (),
- 'pkgname': 'CSWsyslogng',
- 'md5sum': 'cfe40c06e994f6e8d3b191396d0365cb',
- 'version': '3.0.4,REV=2009.08.30',
- 'deps': ('CSWgcc4corert', 'CSWeventlog', 'CSWosslrt', 'CSWzlib',
- 'CSWpcrert', 'CSWggettextrt', 'CSWglib2', 'CSWtcpwrap',
- 'CSWcswclassutils', 'CSWcommon'),
- 'file_basename': 'syslog_ng-3.0.4,REV=2009.08.30-SunOS5.8-i386-CSW.pkg.gz',
- 'size': '137550',
- 'catalogname': 'syslog_ng'}}
fd = StringIO(CATALOG_LINE_1)
oc = catalog.OpencswCatalog(fd)
+ expected = {"syslog_ng": PKG_STRUCT_1}
self.assertEqual(expected, oc.GetDataByCatalogname())
Modified: csw/mgar/gar/v2/tests/run_tests.py
===================================================================
--- csw/mgar/gar/v2/tests/run_tests.py 2011-01-29 15:48:01 UTC (rev 13106)
+++ csw/mgar/gar/v2/tests/run_tests.py 2011-01-29 15:48:41 UTC (rev 13107)
@@ -12,6 +12,7 @@
# To add more test files, create <name>.py file and add a corresponding line
# here:
from catalog_test import *
+from catalog_notifier_test import *
from checkpkg_lib_test import *
from checkpkg_test import *
from dependency_checks_test import *
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the devel
mailing list