2011-03-14 14:34:48 +01:00
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
from pprint import pprint
|
|
|
|
|
|
|
|
from ckan.lib.cli import CkanCommand
|
2011-03-14 16:19:58 +01:00
|
|
|
from ckan.model import repo
|
2011-04-05 12:53:39 +02:00
|
|
|
#from ckanext.harvest.model import HarvestSource, HarvestingJob, HarvestedDocument
|
|
|
|
#from ckanext.harvest.model import HarvestSource, HarvestJob, HarvestObject
|
|
|
|
from ckanext.harvest.lib import *
|
2011-03-18 16:44:40 +01:00
|
|
|
|
2011-03-14 14:34:48 +01:00
|
|
|
class Harvester(CkanCommand):
|
|
|
|
'''Harvests remotely mastered metadata
|
|
|
|
|
|
|
|
Usage:
|
2011-04-05 12:53:39 +02:00
|
|
|
harvester source {url} {type} [{active}] [{user-id}] [{publisher-id}]
|
2011-03-14 14:34:48 +01:00
|
|
|
- create new harvest source
|
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
harvester rmsource {id}
|
2011-03-14 14:34:48 +01:00
|
|
|
- remove a harvester source (and associated jobs)
|
|
|
|
|
|
|
|
harvester sources
|
|
|
|
- lists harvest sources
|
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
harvester job {source-id}
|
|
|
|
- create new harvest job
|
2011-03-14 14:34:48 +01:00
|
|
|
|
|
|
|
harvester rmjob {job-id}
|
2011-04-05 12:53:39 +02:00
|
|
|
- remove a harvest job
|
2011-03-14 14:34:48 +01:00
|
|
|
|
|
|
|
harvester jobs
|
2011-04-05 12:53:39 +02:00
|
|
|
- lists harvest jobs
|
2011-03-14 14:34:48 +01:00
|
|
|
|
|
|
|
harvester run
|
2011-04-05 12:53:39 +02:00
|
|
|
- runs harvest jobs
|
2011-03-18 16:48:08 +01:00
|
|
|
|
|
|
|
harvester extents
|
|
|
|
- creates or updates the extent geometry column for packages with
|
|
|
|
a bounding box defined in extras
|
|
|
|
|
2011-03-14 14:34:48 +01:00
|
|
|
The commands should be run from the ckanext-harvest directory and expect
|
|
|
|
a development.ini file to be present. Most of the time you will
|
|
|
|
specify the config explicitly though::
|
|
|
|
|
|
|
|
paster harvester sources --config=../ckan/development.ini
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
summary = __doc__.split('\n')[0]
|
|
|
|
usage = __doc__
|
2011-04-05 12:53:39 +02:00
|
|
|
max_args = 6
|
2011-03-14 14:34:48 +01:00
|
|
|
min_args = 0
|
|
|
|
|
|
|
|
def command(self):
|
|
|
|
self._load_config()
|
|
|
|
print ""
|
|
|
|
|
|
|
|
if len(self.args) == 0:
|
|
|
|
self.parser.print_usage()
|
|
|
|
sys.exit(1)
|
|
|
|
cmd = self.args[0]
|
|
|
|
if cmd == 'source':
|
2011-04-05 12:53:39 +02:00
|
|
|
self.create_harvest_source()
|
2011-03-14 14:34:48 +01:00
|
|
|
elif cmd == "rmsource":
|
2011-04-05 12:53:39 +02:00
|
|
|
self.remove_harvest_source()
|
2011-03-14 14:34:48 +01:00
|
|
|
elif cmd == 'sources':
|
|
|
|
self.list_harvest_sources()
|
|
|
|
elif cmd == 'job':
|
2011-04-05 12:53:39 +02:00
|
|
|
self.create_harvest_job()
|
2011-03-14 14:34:48 +01:00
|
|
|
elif cmd == "rmjob":
|
2011-04-05 12:53:39 +02:00
|
|
|
self.remove_harvest_job()
|
2011-03-14 14:34:48 +01:00
|
|
|
elif cmd == 'jobs':
|
2011-04-05 12:53:39 +02:00
|
|
|
self.list_harvest_jobs()
|
2011-03-14 14:34:48 +01:00
|
|
|
elif cmd == 'run':
|
|
|
|
self.run_harvester()
|
2011-03-18 16:44:40 +01:00
|
|
|
elif cmd == 'extents':
|
|
|
|
self.update_extents()
|
|
|
|
|
2011-03-14 14:34:48 +01:00
|
|
|
else:
|
|
|
|
print 'Command %s not recognized' % cmd
|
|
|
|
|
|
|
|
def _load_config(self):
|
|
|
|
super(Harvester, self)._load_config()
|
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
def create_harvest_source(self):
|
2011-03-29 18:23:49 +02:00
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
if len(self.args) >= 2:
|
|
|
|
url = unicode(self.args[1])
|
2011-03-29 18:23:49 +02:00
|
|
|
else:
|
2011-04-05 12:53:39 +02:00
|
|
|
print 'Please provide a source URL'
|
|
|
|
sys.exit(1)
|
|
|
|
if len(self.args) >= 3:
|
|
|
|
type = unicode(self.args[2])
|
|
|
|
else:
|
|
|
|
print 'Please provide a source type'
|
|
|
|
sys.exit(1)
|
|
|
|
if len(self.args) >= 4:
|
|
|
|
active = not(self.args[3].lower() == 'false' or \
|
|
|
|
self.args[3] == '0')
|
|
|
|
else:
|
|
|
|
active = True
|
|
|
|
if len(self.args) >= 5:
|
|
|
|
user_id = unicode(self.args[4])
|
|
|
|
else:
|
|
|
|
user_id = u''
|
|
|
|
if len(self.args) >= 6:
|
|
|
|
publisher_id = unicode(self.args[5])
|
|
|
|
else:
|
|
|
|
publisher_id = u''
|
|
|
|
|
|
|
|
source = create_harvest_source({
|
|
|
|
'url':url,
|
|
|
|
'type':type,
|
|
|
|
'active':active,
|
|
|
|
'user_id':user_id,
|
|
|
|
'publisher_id':publisher_id})
|
|
|
|
|
|
|
|
print 'Created new harvest source:'
|
|
|
|
self.print_harvest_source(source)
|
|
|
|
|
|
|
|
sources = get_harvest_sources()
|
|
|
|
self.print_there_are('harvest source', sources)
|
|
|
|
|
|
|
|
# Create a Harvest Job for the new Source
|
|
|
|
create_harvest_job(source.id)
|
|
|
|
print 'A new Harvest Job for this source has also been created'
|
|
|
|
|
|
|
|
def remove_harvest_source(self):
|
|
|
|
if len(self.args) >= 2:
|
|
|
|
source_id = unicode(self.args[1])
|
|
|
|
else:
|
|
|
|
print 'Please provide a source id'
|
|
|
|
sys.exit(1)
|
2011-03-18 16:44:40 +01:00
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
delete_harvest_source(source_id)
|
|
|
|
print 'Removed harvest source: %s' % source_id
|
|
|
|
|
|
|
|
def list_harvest_sources(self):
|
|
|
|
sources = get_harvest_sources()
|
|
|
|
self.print_harvest_sources(sources)
|
|
|
|
self.print_there_are(what="harvest source", sequence=sources)
|
|
|
|
|
|
|
|
def create_harvest_job(self):
|
|
|
|
if len(self.args) >= 2:
|
|
|
|
source_id = unicode(self.args[1])
|
|
|
|
else:
|
|
|
|
print 'Please provide a source id'
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
job = create_harvest_job(source_id)
|
2011-03-18 16:44:40 +01:00
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
self.print_harvest_job(job)
|
|
|
|
status = u'New'
|
|
|
|
jobs = get_harvest_jobs(status=status)
|
|
|
|
self.print_there_are('harvest jobs', jobs, condition=status)
|
|
|
|
|
|
|
|
def remove_harvest_job(self):
|
|
|
|
if len(self.args) >= 2:
|
|
|
|
job_id = unicode(self.args[1])
|
|
|
|
else:
|
|
|
|
print 'Please provide a job id'
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
delete_harvest_job(job_id)
|
|
|
|
print 'Removed harvest job: %s' % job_id
|
|
|
|
|
|
|
|
def list_harvest_jobs(self):
|
|
|
|
jobs = get_harvest_jobs()
|
|
|
|
self.print_harvest_jobs(jobs)
|
|
|
|
self.print_there_are(what='harvest job', sequence=jobs)
|
|
|
|
|
|
|
|
#TODO: Move to lib and implement the queue system
|
2011-03-14 14:34:48 +01:00
|
|
|
def run_harvester(self, *args, **kwds):
|
|
|
|
from pylons.i18n.translation import _get_translator
|
|
|
|
import pylons
|
|
|
|
pylons.translator._push_object(_get_translator(pylons.config.get('lang')))
|
|
|
|
|
2011-03-14 18:04:41 +01:00
|
|
|
from ckanext.harvest.controllers.harvesting import HarvestingJobController
|
2011-03-14 14:34:48 +01:00
|
|
|
from ckanext.csw.validation import Validator
|
|
|
|
|
|
|
|
jobs = HarvestingJob.filter(status=u"New").all()
|
|
|
|
jobs_len = len(jobs)
|
|
|
|
jobs_count = 0
|
|
|
|
if jobs_len:
|
|
|
|
print "Running %s harvesting jobs..." % jobs_len
|
|
|
|
profiles = [
|
|
|
|
x.strip() for x in
|
|
|
|
pylons.config.get(
|
|
|
|
"ckan.harvestor.validator.profiles",
|
|
|
|
"iso19139,gemini2",
|
|
|
|
).split(",")
|
|
|
|
]
|
|
|
|
validator = Validator(profiles=profiles)
|
|
|
|
print ""
|
|
|
|
for job in jobs:
|
|
|
|
jobs_count += 1
|
|
|
|
if job.source is None:
|
|
|
|
print 'ERRROR: no source associated with this job'
|
|
|
|
else:
|
|
|
|
print "Running job %s/%s: %s" % (jobs_count, jobs_len, job.id)
|
|
|
|
self.print_harvesting_job(job)
|
|
|
|
job_controller = HarvestingJobController(job, validator)
|
|
|
|
job_controller.harvest_documents()
|
|
|
|
pprint (job.report)
|
|
|
|
else:
|
|
|
|
print "There are no new harvesting jobs."
|
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
#TODO: move to ckanext-?? for geo stuff
|
|
|
|
def update_extents(self):
|
|
|
|
from ckan.model import PackageExtra, Package, Session
|
|
|
|
conn = Session.connection()
|
|
|
|
packages = [extra.package \
|
|
|
|
for extra in \
|
|
|
|
Session.query(PackageExtra).filter(PackageExtra.key == 'bbox-east-long').all()]
|
2011-03-14 14:34:48 +01:00
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
error = False
|
|
|
|
for package in packages:
|
|
|
|
try:
|
|
|
|
save_extent(package)
|
|
|
|
except:
|
|
|
|
errors = True
|
|
|
|
|
|
|
|
if error:
|
|
|
|
msg = "There was an error saving the package extent. Have you set up the package_extent table in the DB?"
|
|
|
|
else:
|
|
|
|
msg = "Done. Extents generated for %i packages" % len(packages)
|
2011-03-14 14:34:48 +01:00
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
print msg
|
2011-03-14 14:34:48 +01:00
|
|
|
|
|
|
|
def print_harvest_sources(self, sources):
|
|
|
|
if sources:
|
|
|
|
print ""
|
|
|
|
for source in sources:
|
|
|
|
self.print_harvest_source(source)
|
|
|
|
|
|
|
|
def print_harvest_source(self, source):
|
2011-04-05 12:53:39 +02:00
|
|
|
print 'Source id: %s' % source.id
|
|
|
|
print ' url: %s' % source.url
|
|
|
|
print ' type: %s' % source.type
|
|
|
|
print ' active: %s' % source.active
|
|
|
|
print ' user: %s' % source.user_id
|
|
|
|
print 'publisher: %s' % source.publisher_id
|
|
|
|
print ' objects: %s' % len(source.objects)
|
|
|
|
print ''
|
|
|
|
|
|
|
|
def print_harvest_jobs(self, jobs):
|
2011-03-14 14:34:48 +01:00
|
|
|
if jobs:
|
2011-04-05 12:53:39 +02:00
|
|
|
print ''
|
2011-03-14 14:34:48 +01:00
|
|
|
for job in jobs:
|
2011-04-05 12:53:39 +02:00
|
|
|
self.print_harvest_job(job)
|
|
|
|
|
|
|
|
def print_harvest_job(self, job):
|
|
|
|
print 'Job id: %s' % job.id
|
|
|
|
print 'status: %s' % job.status
|
|
|
|
print 'source: %s' % job.source.id
|
|
|
|
print ' url: %s' % job.source.url
|
2011-03-14 14:34:48 +01:00
|
|
|
#print "report: %s" % job.report
|
2011-04-05 12:53:39 +02:00
|
|
|
#TODO: print errors
|
|
|
|
'''
|
2011-03-14 14:34:48 +01:00
|
|
|
if job.report and job.report['added']:
|
|
|
|
for package_id in job.report['added']:
|
|
|
|
print " doc: %s" % package_id
|
|
|
|
if job.report and job.report['errors']:
|
|
|
|
for msg in job.report['errors']:
|
|
|
|
print " error: %s" % msg
|
2011-04-05 12:53:39 +02:00
|
|
|
'''
|
|
|
|
print ''
|
2011-03-14 14:34:48 +01:00
|
|
|
|
2011-04-05 12:53:39 +02:00
|
|
|
def print_there_are(self, what, sequence, condition=''):
|
2011-03-14 14:34:48 +01:00
|
|
|
is_singular = self.is_singular(sequence)
|
2011-04-05 12:53:39 +02:00
|
|
|
print 'There %s %s %s%s%s' % (
|
|
|
|
is_singular and 'is' or 'are',
|
2011-03-14 14:34:48 +01:00
|
|
|
len(sequence),
|
2011-04-05 12:53:39 +02:00
|
|
|
condition and ('%s ' % condition.lower()) or '',
|
2011-03-14 14:34:48 +01:00
|
|
|
what,
|
2011-04-05 12:53:39 +02:00
|
|
|
not is_singular and 's' or '',
|
2011-03-14 14:34:48 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
def is_singular(self, sequence):
|
|
|
|
return len(sequence) == 1
|
|
|
|
|