[ckan-changes] commit/ckan-debs-public: davi... at okfn.org: Builders improved with JG.
Bitbucket
commits-noreply at bitbucket.org
Tue Jun 7 15:42:54 UTC 2011
1 new changeset in ckan-debs-public:
http://bitbucket.org/okfn/ckan-debs-public/changeset/877b300622dc/
changeset: 877b300622dc
branches:
user: davi... at okfn.org
date: 2011-06-07 17:42:42
summary: Builders improved with JG.
affected #: 8 files (6.4 KB)
--- a/builder.py Tue Jun 07 11:54:37 2011 +0100
+++ b/builder.py Tue Jun 07 16:42:42 2011 +0100
@@ -1,4 +1,5 @@
from optparse import OptionParser
+from subprocess import Popen, PIPE, STDOUT
from imp import find_module, load_module, acquire_lock, release_lock
import os
import sys
@@ -13,34 +14,62 @@
class BuilderError(Exception):
pass
+#def run(cmd, echo_stdout=False, echo_stderr=False, merge=True, cwd=None, no_return=False, **popen_args):
+# if merge:
+# stderr = STDOUT
+# else:
+# stderr = PIPE
+# if cwd is None:
+# process = Popen(cmd, stdout=PIPE, stderr=stderr, **popen_args)
+# else:
+# if not os.path.exists(cwd):
+# raise Exception('No such file or directory %r'%cwd)
+# process = Popen(cmd, stdout=PIPE, stderr=stderr, cwd=cwd, **popen_args)
+# stdout, stderr = process.communicate()
+# if echo_stdout:
+# print stdout
+# if echo_stderr:
+# print stderr
+# retval = process.wait()
+# if retval != 0:
+# raise Exception('Command %s failed with code %r. Output: %s, %s'%(' '.join(cmd), retval, stdout, stderr))
+# if not no_return:
+# if merge:
+# return retval, stdout
+# else:
+# return retval, stdout, stderr
+
class BaseBuilderConfig(object):
- def __init__(self, env):
- self.env = env
+ def __init__(self, builder):
+ self.builder = builder
def get_print_prefix(self):
return '\n### %s: ' % self.name
def print_title(self, msg):
prefix = self.get_print_prefix()
- print '%s %s' % (prefix, msg % self.env)
+ print '%s %s' % (prefix, msg)
- def run(self, msg, cmd, is_verbose=True, **extra_env):
+ def run(self, msg, cmd, cwd=None, **extra_env):
+ if cwd is None:
+ cwd = os.getcwd()
self.print_title(msg)
- env = self.env
if extra_env:
- env = self.env
- env.update(extra_env)
- cmd = (cmd % env) % env
+ if not isinstance(cmd, list):
+ cmd = (cmd % extra_env)
+ else:
+ raise Exception('The extra_env argument does not work when using lists')
print cmd
- if is_verbose:
- if os.system(cmd):
- raise BuilderError("Error while running command: %s" % (cmd))
+ if not isinstance(cmd, list):
+ process = Popen(cmd, cwd=cwd, shell=True, stdout=PIPE, stderr=STDOUT)
else:
- (status, output) = commands.getstatusoutput(cmd)
- if status:
- print output
- raise BuilderError("Error while running command: %s" % (cmd))
- return output
+ process = Popen(cmd, cwd=cwd, stdout=PIPE, stderr=STDOUT)
+ stdout, stderr = process.communicate()
+ status = process.wait()
+ if status:
+ print stdout, stderr
+ raise BuilderError("Error while running command: %s" % (cmd,))
+ return stdout
def clone(self, repo_url, destination_path, revision='default'):
'''Clones a repo, or if it is already there, updates it to the latest version.
@@ -51,8 +80,8 @@
'''
repo_name = repo_url.split('/')[-1]
- repo_dir = destination_path % self.env
- revision = revision % self.env
+ repo_dir = destination_path
+ revision = revision
hgrc_filepath = os.path.join(repo_dir, '.hg', 'hgrc')
msg = 'Get repo for "%s" source' % repo_name
if os.path.exists(repo_dir):
@@ -63,9 +92,8 @@
repo_dir=repo_dir,
revision=revision)
else:
- import pdb; pdb.set_trace()
self.run(msg,
- 'hg clone %(repo_url)s/%(revision)s %(repo_dir)s',
+ 'hg clone %(repo_url)s -r %(revision)s %(repo_dir)s',
repo_url=repo_url,
repo_dir=repo_dir,
revision=revision)
@@ -75,36 +103,59 @@
repo = hg.repository(ui.ui(), repo_path)
return len(repo.changelog)
- def build_deb(self, source_path, out_dir, version, deps):
+ def build_deb(self, source_path, source_name, out_dir, version, deps):
#'cd conflict; ~/pyenv-tools/bin/python -m buildkit.deb . ckan-deps 0.1~%(ckan_deps_build_number)s+lucid http://ckan.org'
HOMEPAGE = 'http://ckan.org'
- in_dir, package_name = os.path.split(os.path.abspath(source_path % self.env))
+ #in_dir, package_name = os.path.split(os.path.abspath(source_path))
self.print_title('Building deb for source %r' % source_path)
db = DebBuilder(
package_path=source_path,
- package=package_name,
+ package=source_name,
version=version,
homepage=HOMEPAGE,
deps=deps,
- base=os.path.join(out_dir % self.env, 'python-%s-%s' % (package_name, version), 'debian'),
- here=out_dir % self.env,
+ base=os.path.join(out_dir, 'python-%s-%s' % (source_name, version), 'debian'),
+ here=out_dir,
print_prefix=self.get_print_prefix(),
- )
+ )
db.handle_one()
+ def builder_build(self, builder_name, args, options):
+ self.builder.build(builder_name, args, options)
-class BasicBuilder(BaseBuilderConfig):
- name = ''
+class BuilderCmd(object):
+ def __init__(self):
+ self.builder_configs = self.find_builder_configs()
+ usage = "usage: %prog [options] command"
+ usage += '\n Commands:'
+ usage += '\n list - list builders'
+ usage += '\n build BUILDER - build a specified builder'
+ usage += '\n clean - clean build directory'
+ parser = OptionParser(usage=usage)
+ parser.add_option("-b", "--build-dir", dest="build_dir",
+ help="build directory to use", metavar="PATH",
+ default='./build')
-class Builder(object):
- def __init__(self, env):
- self.builder_configs = []
- self.basic_builder = BasicBuilder(env)
- self.find_builder_configs()
- self.env = env
- self.env['build_dir'] = os.path.abspath(os.path.expanduser(self.env['build_dir']))
+ options, args = parser.parse_args()
+
+ if len(args) < 1:
+ parser.error('Need to specify a command')
+ options = options.__dict__
+ options['build_dir'] = os.path.abspath(os.path.expanduser(options['build_dir']))
+ cmd = args[0]
+ if cmd == 'list':
+ self.list()
+ elif cmd == 'build':
+ if len(args) < 2:
+ parser.error('Need to specify a builder config')
+ self.build(args[1], args[2:], options)
+ elif cmd == 'clean':
+ self.clean(args[1:], options)
+ else:
+ parser.error('Did not understand command: %s' % cmd)
def find_builder_configs(self):
+ builder_configs = []
part = BUILDERS_CONFIG.replace('.py', '')
fh = None
try:
@@ -116,76 +167,38 @@
fh.close()
release_lock()
for name in dir(module):
- if name.startswith('Builder'):
+ if name.startswith('Builder') and name is not "BuilderError":
obj = getattr(module, name)
- if (isinstance(obj, (type, types.ClassType))):
- self.builder_configs.append(obj)
+ if isinstance(obj, (type, types.ClassType)):
+ builder_configs.append(obj)
+ return builder_configs
def list(self):
print 'Builder configs:'
for builder_config in self.builder_configs:
print builder_config.name
- def get_builder_config(self, builder_config_name):
+ def build(self, builder_config_name, args, options):
+ builder_config_class = None
for builder_config in self.builder_configs:
if builder_config_name == builder_config.name:
- return builder_config(self.env)
- else:
+ builder_config_class = builder_config
+ break
+ if builder_config_class is None:
raise Exception('Could not find builder named: %s' % builder_config_name)
-
- def build(self, builder_config_name):
- builder_config = self.get_builder_config(builder_config_name)
print 'Building %s' % builder_config.name
- if not os.path.exists(self.env['build_dir']):
- os.makedirs(self.env['build_dir'])
+ if not os.path.exists(options['build_dir']):
+ os.makedirs(options['build_dir'])
try:
- builder_config.build()
+ builder_config(self).build(args, options)
except BuilderError, e:
print e
sys.exit(1)
- def clean(self):
+ def clean(self, args, options):
# simple check first
- assert len(os.path.abspath(self.basic_builder.env['build_dir'])) > 15, self.basic_builder.env['build_dir']
- self.basic_builder.run('Emptying build folder',
- 'rm -rf %(build_dir)s')
-
-
-class BuilderCmd(object):
- def __init__(self):
- usage = "usage: %prog [options] command"
- usage += '\n Commands:'
- usage += '\n list - list builders'
- usage += '\n build BUILDER - build a specified builder'
- usage += '\n clean - clean build directory'
- parser = OptionParser(usage=usage)
- parser.add_option("-b", "--build-dir", dest="build_dir",
- help="build directory to use", metavar="PATH",
- default='./build')
-## parser.add_option("-q", "--quiet",
-## action="store_false", dest="verbose", default=True,
-## help="don't print status messages to stdout")
-
- self.options, self.args = parser.parse_args()
-
- if len(self.args) < 1:
- parser.error('Need to specify a command')
-
- env = self.options.__dict__
- builder = Builder(env)
- cmd = self.args[0]
- if cmd == 'list':
- builder.list()
- elif cmd == 'build':
- if len(self.args) < 2:
- parser.error('Need to specify a builder config')
- if len(self.args) > 2:
- parser.error('Too many arguments')
- builder.build(self.args[1])
- elif cmd == 'clean':
- builder.clean()
- else:
- parser.error('Did not understand command: %s' % cmd)
+ assert len(os.path.abspath(options['build_dir'])) > 15, options['build_dir']
+ os.system('rm -rf %(build_dir)s'%options)
if __name__ == '__main__':
BuilderCmd()
--- a/buildersconfig.py Tue Jun 07 11:54:37 2011 +0100
+++ b/buildersconfig.py Tue Jun 07 16:42:42 2011 +0100
@@ -1,33 +1,97 @@
import os
import sys
-from builder import BaseBuilderConfig
+from builder import BaseBuilderConfig, BuilderError
-class BuilderCkanConflict(BaseBuilderConfig):
- name = 'ckan-conflict'
+class BuilderCheckoutRequirementsRepos(BaseBuilderConfig):
+ name = 'checkout-requirements-repos'
- def build(self):
- self.run('Create',
- 'mkdir -p %(build_dir)s/conflict')
- self.clone('https://bitbucket.org/okfn/ckan-deps', '%(build_dir)s/conflict/ckan-deps')
-## self.run('Conflict - rename ckan_deps to ckan-deps',
-## 'mv %(build_dir)s/conflict/src/ckan_deps %(build_dir)s/conflict/src/ckan-deps')
- deps_dir = '%(build_dir)s/conflict/ckan-deps' % self.env
- self.env['ckan_deps_build_number'] = self.get_build_number(deps_dir)
- self.build_deb(deps_dir, '%(build_dir)s/conflict', '0.1~%(ckan_deps_build_number)s+lucid' % self.env, None)
+ def build(self, args, options):
+ self.run('Create', 'mkdir -p %(build_dir)s/requirements-repos', **options)
+ python_ckan_dir = '%(build_dir)s/requirements-repos' % options
+ #self.clone('https://bitbucket.org/okfn/ckan', python_ckan_dir+'/ckan')
+ #self.clone('https://bitbucket.org/okfn/ckanext-dgu', python_ckan_dir+'/ckanext-dgu')
+ self.clone('https://bitbucket.org/okfn/ckanext-std', python_ckan_dir+'/ckanext-std')
-## b.run('Create python-ckan-deps package',
-## 'cd conflict; ~/pyenv-tools/bin/python -m buildkit.deb . ckan-deps 0.1~%(ckan_deps_build_number)s+lucid http://ckan.org')
+class BuilderPackagesIfNecessary(BaseBuilderConfig):
+ name = 'packages-if-necessary'
-class BuilderPythonCkan(BaseBuilderConfig):
- name = 'python-ckan'
+ def build(self, args, options):
+ python_ckan_dir = '%(build_dir)s/requirements-repos' % options
+ changed = []
+ for repo in [
+ #'ckan',
+ #'ckanext-dgu',
+ 'ckanext-std',
+ ]:
+ stdout = self.run('Looking for changes', 'hg incoming -r default', cwd=python_ckan_dir+'/'+repo, echo_stdout=True)
+ if "no changes found" not in stdout:
+ changed.append(repo)
+ print '\n'.join(changed)
+ self.builder_build('hello', [1,2,3], {1:1, 'build_dir': options['build_dir']})
- def build(self):
- self.run('Create',
- 'mkdir -p %(build_dir)s/python-ckan')
- python_ckan_dir = '%(build_dir)s/python-ckan/ckan' % self.env
- self.clone('https://bitbucket.org/okfn/ckan', python_ckan_dir, '%(revision)s')
- deps = []
- self.build_deb(python_ckan_dir, '%(build_dir)s/conflict', '0.1~03+lucid', deps)
-
-# 'cd python-ckan; ~/pyenv-tools/bin/python -m buildkit.deb . ckan %(ckan_version)s~%(ckan_build_number)s+lucid http://ckan.org ' + ckan_deps)
+class BuilderPackageCkanextSpatial(BaseBuilderConfig):
+ name = 'package-python-ckanext-spatial'
+ # Needs args of:
+ # * timestamp
+ # * pip requirements
+
+ def build(self, args, options):
+ timestamp = args[0]
+ requirement = args[1]
+ print args, requirement
+ source_name = args[2]
+ revision = requirement.split('@')[1].split('#')[0]
+ self.run('Create a packages directory', 'mkdir -p %(build_dir)s/packages'%options)
+ self.run('Create a virtualenv', 'virtualenv %(build_dir)s/pyenv'%options)
+ self.run('Installing the requirement %s'%requirement, '%s/pyenv/bin/pip install --upgrade --ignore-installed -e %s'%(options['build_dir'], requirement))
+ self.build_deb(
+ '%s/pyenv/src/%s'%(options['build_dir'], source_name),
+ source_name,
+ out_dir = '%(build_dir)s/packages' % options,
+ version='%s+%s+lucid'%(timestamp, revision),
+ deps=[],
+ )
+
+class BuilderHello(BaseBuilderConfig):
+ name = 'hello'
+
+ def build(self, args, options):
+ print '+++++++++++++++++++++++++++++++', args, options
+
+
+#
+# Old
+#
+
+
+
+#
+#class BuilderCkanConflict(BaseBuilderConfig):
+# name = 'ckan-conflict'
+#
+# def build(self):
+# self.run('Create',
+# 'mkdir -p %(build_dir)s/conflict')
+# self.clone('https://bitbucket.org/okfn/ckan-deps', '%(build_dir)s/conflict/ckan-deps')
+### self.run('Conflict - rename ckan_deps to ckan-deps',
+### 'mv %(build_dir)s/conflict/src/ckan_deps %(build_dir)s/conflict/src/ckan-deps')
+# deps_dir = '%(build_dir)s/conflict/ckan-deps' % self.env
+# self.env['ckan_deps_build_number'] = self.get_build_number(deps_dir)
+# self.build_deb(deps_dir, '%(build_dir)s/conflict', '0.1~%(ckan_deps_build_number)s+lucid' % self.env, None)
+#
+### b.run('Create python-ckan-deps package',
+### 'cd conflict; ~/pyenv-tools/bin/python -m buildkit.deb . ckan-deps 0.1~%(ckan_deps_build_number)s+lucid http://ckan.org')
+#
+#class BuilderPythonCkan(BaseBuilderConfig):
+# name = 'python-ckan'
+#
+# def build(self):
+# self.run('Create',
+# 'mkdir -p %(build_dir)s/python-ckan')
+# python_ckan_dir = '%(build_dir)s/python-ckan/ckan' % self.env
+# self.clone('https://bitbucket.org/okfn/ckan', python_ckan_dir, '%(revision)s')
+# deps = []
+# self.build_deb(python_ckan_dir, '%(build_dir)s/conflict', '0.1~03+lucid', deps)
+#
+## 'cd python-ckan; ~/pyenv-tools/bin/python -m buildkit.deb . ckan %(ckan_version)s~%(ckan_build_number)s+lucid http://ckan.org ' + ckan_deps)
--- a/ckan-common/usr/lib/ckan/common.sh Tue Jun 07 11:54:37 2011 +0100
+++ b/ckan-common/usr/lib/ckan/common.sh Tue Jun 07 16:42:42 2011 +0100
@@ -5,27 +5,40 @@
}
#_echo="echo"
-maintenance_on () {
- local instance
- instance=$1
- $_echo a2dissite ${instance} &> /dev/null
- $_echo a2ensite ${instance}.maint &> /dev/null
+ckan_maintenance_on () {
+ local INSTANCE
+ INSTANCE=$1
+ $_echo a2dissite ${INSTANCE} &> /dev/null
+ $_echo a2ensite ${INSTANCE}.maint &> /dev/null
$_echo service apache2 reload &> /dev/null
}
-maintenance_off () {
- local instance
- instance=$1
- $_echo a2dissite ${instance}.maint &> /dev/null
- $_echo a2ensite ${instance} &> /dev/null
+ckan_maintenance_off () {
+ local INSTANCE
+ INSTANCE=$1
+ $_echo a2dissite ${INSTANCE}.maint &> /dev/null
+ $_echo a2ensite ${INSTANCE} &> /dev/null
$_echo service apache2 reload &> /dev/null
}
-ensure_users_and_groups () {
+ckan_set_log_file_permissions () {
+ local INSTANCE
+ INSTANCE=$1
+ touch /var/log/ckan/${INSTANCE}/${INSTANCE}.log
+ touch /var/log/ckan/${INSTANCE}/${INSTANCE}[1-9].log
+ chmod g+w /var/log/ckan/${INSTANCE}/${INSTANCE}.log
+ chmod g+w /var/log/ckan/${INSTANCE}/${INSTANCE}[1-9].log
+ chown www-data:ckan${INSTANCE} /var/log/ckan/${INSTANCE}/${INSTANCE}.log
+ chown www-data:ckan${INSTANCE} /var/log/ckan/${INSTANCE}/${INSTANCE}[1-9].log
+}
+
+ckan_ensure_users_and_groups () {
+ local INSTANCE
+ INSTANCE=$1
local user group ckan_users
- user="ckan"
- group="${user}"
- ckan_users="www-data okfn"
+ user="ckan${INSTANCE}"
+ group="ckan"
+ ckan_users="ckan www-data okfn"
COMMAND_OUTPUT=`cat /etc/group | grep "ckan"`
if ! [[ "$COMMAND_OUTPUT" =~ ckan ]] ; then
sudo groupadd --system ${group}
@@ -35,131 +48,131 @@
done
COMMAND_OUTPUT=`cat /etc/passwd | grep "ckan"`
if ! [[ "$COMMAND_OUTPUT" =~ ckan ]] ; then
- sudo useradd --system --gid ${group} --home /var/lib/ckan -M --shell /usr/sbin/nologin ${user}
+ sudo useradd --system --gid ${group} --home /var/lib/ckan/${INSTANCE} -M --shell /usr/sbin/nologin ${user}
fi
}
-make_ckan_directories () {
- local instance
+ckan_make_ckan_directories () {
+ local INSTANCE
if [ "X$1" = "X" ] ; then
- echo "ERROR: call the function make_ckan_directories with an instance name, e.g."
+ echo "ERROR: call the function make_ckan_directories with an INSTANCE name, e.g."
echo " dgu"
exit 1
else
- instance=$1
- mkdir -p -m 0755 /etc/ckan/${instance}
- mkdir -p -m 2750 /var/lib/ckan/${instance}{,/static}
- mkdir -p -m 2770 /var/{backup,log}/ckan/${instance} /var/lib/ckan/${instance}/{data,sstore,static/dump}
- chgrp -R ckan /var/lib/ckan/
- chgrp -R ckan /var/backup/ckan/
- chgrp -R ckan /var/log/ckan/
+ INSTANCE=$1
+ mkdir -p -m 0755 /etc/ckan/${INSTANCE}
+ mkdir -p -m 2750 /var/lib/ckan/${INSTANCE}{,/static}
+ mkdir -p -m 2770 /var/{backup,log}/ckan/${INSTANCE} /var/lib/ckan/${INSTANCE}/{data,sstore,static/dump}
+ chgrp ckan /var/lib/ckan/
+ chgrp ckan /var/backup/ckan/
+ chgrp ckan /var/log/ckan/
fi
}
-create_who_ini () {
- local instance
+ckan_create_who_ini () {
+ local INSTANCE
if [ "X$1" = "X" ] ; then
- echo "ERROR: call the function create_who_ini function with an instance name, e.g."
+ echo "ERROR: call the function create_who_ini function with an INSTANCE name, e.g."
echo " dgu"
exit 1
else
- instance=$1
+ INSTANCE=$1
if ! [ -f /etc/ckan/$0/who.ini ] ; then
- cp -n /usr/share/pyshared/ckan/config/who.ini /etc/ckan/${instance}/who.ini
- sed -e "s,%(here)s,/var/lib/ckan/${instance}," \
- -i /etc/ckan/${instance}/who.ini
+ cp -n /usr/share/pyshared/ckan/config/who.ini /etc/ckan/${INSTANCE}/who.ini
+ sed -e "s,%(here)s,/var/lib/ckan/${INSTANCE}," \
+ -i /etc/ckan/${INSTANCE}/who.ini
fi
fi
}
-create_config_file () {
- local instance password
+ckan_create_config_file () {
+ local INSTANCE password
if [ "X$1" = "X" ] || [ "X$2" = "X" ] ; then
- echo "ERROR: call the function create_who_ini function with an instance name, and a password for postgresql e.g."
+ echo "ERROR: call the function create_who_ini function with an INSTANCE name, and a password for postgresql e.g."
echo " dgu 1U923hjkh8"
echo " You can generate a password like this: "
echo " < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c10"
exit 1
else
- instance=$1
+ INSTANCE=$1
password=$2
- if ! [ -f /etc/ckan/${instance}/${instance}.ini ] ; then
- paster make-config ckan /etc/ckan/${instance}/${instance}.ini
+ if ! [ -f /etc/ckan/${INSTANCE}/${INSTANCE}.ini ] ; then
+ paster make-config ckan /etc/ckan/${INSTANCE}/${INSTANCE}.ini
sed -e "s,^\(email_to\)[ =].*,\1 = root," \
- -e "s,^\(error_email_from\)[ =].*,\1 = ckan-${instance}@`hostname`," \
- -e "s,^\(cache_dir\)[ =].*,\1 = /var/lib/ckan/${instance}/data," \
- -e "s,^\(who.config_file\)[ =].*,\1 = /etc/ckan/${instance}/who.ini," \
- -e "s,%(here)s,/var/lib/ckan/${instance}," \
- -e "s,^\(sqlalchemy.url\)[ =].*,\1 = postgresql://${instance}:${password}@localhost/${instance}," \
- -i /etc/ckan/${instance}/${instance}.ini
+ -e "s,^\(error_email_from\)[ =].*,\1 = ckan-${INSTANCE}@`hostname`," \
+ -e "s,^\(cache_dir\)[ =].*,\1 = /var/lib/ckan/${INSTANCE}/data," \
+ -e "s,^\(who.config_file\)[ =].*,\1 = /etc/ckan/${INSTANCE}/who.ini," \
+ -e "s,%(here)s,/var/lib/ckan/${INSTANCE}," \
+ -e "s,^\(sqlalchemy.url\)[ =].*,\1 = postgresql://${INSTANCE}:${password}@localhost/${INSTANCE}," \
+ -i /etc/ckan/${INSTANCE}/${INSTANCE}.ini
fi
fi
}
-add_or_replace_database_user () {
- local instance password
+ckan_add_or_replace_database_user () {
+ local INSTANCE password
if [ "X$1" = "X" ] || [ "X$2" = "X" ] ; then
- echo "ERROR: call the function create_who_ini function with an instance name, and a password for postgresql e.g."
+ echo "ERROR: call the function create_who_ini function with an INSTANCE name, and a password for postgresql e.g."
echo " dgu 1U923hjkh8"
echo " You can generate a password like this: "
echo " < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c10"
exit 1
else
- instance=$1
+ INSTANCE=$1
password=$2
- COMMAND_OUTPUT=`sudo -u postgres psql -c "SELECT 'True' FROM pg_user WHERE usename='${instance}'" 2> /dev/null`
+ COMMAND_OUTPUT=`sudo -u postgres psql -c "SELECT 'True' FROM pg_user WHERE usename='${INSTANCE}'" 2> /dev/null`
if ! [[ "$COMMAND_OUTPUT" =~ True ]] ; then
- sudo -u postgres -c "psql -c \"CREATE USER \"${instance}\" WITH PASSWORD '${password}'\""
+ sudo -u postgres -c "psql -c \"CREATE USER \"${INSTANCE}\" WITH PASSWORD '${password}'\""
else
- sudo -u postgres -c "psql -c \"ALTER USER \"${instance}\" WITH PASSWORD '${password}'\""
+ sudo -u postgres -c "psql -c \"ALTER USER \"${INSTANCE}\" WITH PASSWORD '${password}'\""
fi
fi
}
-ensure_db_exists () {
- local instance
+ckan_ensure_db_exists () {
+ local INSTANCE
if [ "X$1" = "X" ] ; then
- echo "ERROR: call the function create_who_ini function with an instance name, e.g."
+ echo "ERROR: call the function create_who_ini function with an INSTANCE name, e.g."
echo " dgu"
exit 1
else
- instance=$1
+ INSTANCE=$1
COMMAND_OUTPUT=`sudo -u postgres psql -l 2> /dev/null`
- if ! [[ "$COMMAND_OUTPUT" =~ ${instance} ]] ; then
+ if ! [[ "$COMMAND_OUTPUT" =~ ${INSTANCE} ]] ; then
echo "Creating the database ..."
- su postgres -c "createdb -O ${instance} ${instance}"
+ su postgres -c "createdb -O ${INSTANCE} ${INSTANCE}"
fi
fi
}
-create_wsgi_handler () {
- local instance
+ckan_create_wsgi_handler () {
+ local INSTANCE
if [ "X$1" = "X" ] ; then
- echo "ERROR: call the function create_wsgi_handler function with an instance name, e.g."
+ echo "ERROR: call the function create_wsgi_handler function with an INSTANCE name, e.g."
echo " dgu"
exit 1
else
- instance=$1
+ INSTANCE=$1
wsgi_path="`python -c 'import ckan; print ckan.__path__[0]'`/wsgi.py"
- if ! [ -f /etc/ckan/${instance}/${instance}.py ] ; then
- echo "Found Apache script in ${wsgi_path}, creating symlink from /etc/ckan/${instance}/${instance}.py"
- ln -s ${wsgi_path} /etc/ckan/${instance}/${instance}.py
+ if ! [ -f /etc/ckan/${INSTANCE}/${INSTANCE}.py ] ; then
+ echo "Found Apache script in ${wsgi_path}, creating symlink from /etc/ckan/${INSTANCE}/${INSTANCE}.py"
+ ln -s ${wsgi_path} /etc/ckan/${INSTANCE}/${INSTANCE}.py
fi
fi
}
-overwrite_apache_config () {
- local instance ServerName ServerAlias
+ckan_overwrite_apache_config () {
+ local INSTANCE ServerName ServerAlias
if [ "X$1" = "X" ] ; then
- echo "ERROR: call the function overwrite_apache_config function with an instance name, the server name and a server aliase e.g."
+ echo "ERROR: call the function overwrite_apache_config function with an INSTANCE name, the server name and a server aliase e.g."
echo " dgu catalogue.data.gov.uk dgu-live.okfn.org"
exit 1
else
- instance=$1
+ INSTANCE=$1
ServerName=$2
ServerAlias=$3
- rm /etc/apache2/sites-available/${instance}.common
- cat <<EOF > /etc/apache2/sites-available/${instance}.common
+ rm /etc/apache2/sites-available/${INSTANCE}.common
+ cat <<EOF > /etc/apache2/sites-available/${INSTANCE}.common
# WARNING: Do not manually edit this file, it is desgined to be
# overwritten at any time by the postinst script of
@@ -167,7 +180,7 @@
# These are common settings used for both the normal and maintence modes
- DocumentRoot /var/lib/ckan/${instance}/static
+ DocumentRoot /var/lib/ckan/${INSTANCE}/static
ServerName ${ServerName}
ServerAlias ${ServerAlias}
@@ -175,15 +188,15 @@
deny from all
</Directory>
- <Directory /etc/ckan/${instance}/>
+ <Directory /etc/ckan/${INSTANCE}/>
allow from all
</Directory>
- <Directory /var/lib/ckan/${instance}/static>
+ <Directory /var/lib/ckan/${INSTANCE}/static>
allow from all
</Directory>
- Alias /dump /var/lib/ckan/${instance}/static/dump
+ Alias /dump /var/lib/ckan/${INSTANCE}/static/dump
# Disable the mod_python handler for static files
<Location /dump>
@@ -192,30 +205,30 @@
</Location>
# this is our app
- WSGIScriptAlias / /etc/ckan/${instance}/${instance}.py
+ WSGIScriptAlias / /etc/ckan/${INSTANCE}/${INSTANCE}.py
# pass authorization info on (needed for rest api)
WSGIPassAuthorization On
- ErrorLog /var/log/apache2/${instance}.error.log
- CustomLog /var/log/apache2/${instance}.custom.log combined
+ ErrorLog /var/log/apache2/${INSTANCE}.error.log
+ CustomLog /var/log/apache2/${INSTANCE}.custom.log combined
EOF
- rm /etc/apache2/sites-available/${instance}
- cat <<EOF > /etc/apache2/sites-available/${instance}
+ rm /etc/apache2/sites-available/${INSTANCE}
+ cat <<EOF > /etc/apache2/sites-available/${INSTANCE}
<VirtualHost *:80>
# WARNING: Do not manually edit this file, it is desgined to be
# overwritten at any time by the postinst script of
# dependent packages
- Include /etc/apache2/sites-available/${instance}.common
+ Include /etc/apache2/sites-available/${INSTANCE}.common
</VirtualHost>
EOF
- rm /etc/apache2/sites-available/${instance}.maint
- cat <<EOF > /etc/apache2/sites-available/${instance}.maint
+ rm /etc/apache2/sites-available/${INSTANCE}.maint
+ cat <<EOF > /etc/apache2/sites-available/${INSTANCE}.maint
<VirtualHost *:80>
# WARNING: Do not manually edit this file, it is desgined to be
# overwritten at any time by the postinst script of
# dependent packages
- Include /etc/apache2/sites-available/${instance}.common
+ Include /etc/apache2/sites-available/${INSTANCE}.common
# Maintenance mode
RewriteEngine On
--- a/ckan-dgu/DEBIAN/control Tue Jun 07 11:54:37 2011 +0100
+++ b/ckan-dgu/DEBIAN/control Tue Jun 07 16:42:42 2011 +0100
@@ -3,9 +3,45 @@
Architecture: all
Maintainer: James Gardner <james.gardner at okfn.org>
Installed-Size: 0
-Depends: python-ckan (>= 1.4), apache2, libapache2-mod-wsgi, python-apachemiddleware, python-ckanext-dgu, python-ckanext-harvest, python-ckanext-csw, python-swiss, python-dateutil, rabbitmq-server, postgresql-8.4-postgis, python-carrot, python-ckanext-spatial, python-ckanext-inspire, python-ckanext-qa, python-ckanext-
+Depends:
+
+ apache2, libapache2-mod-wsgi, rabbitmq-server, postgresql-8.4-postgis,
+ ckan-common, python-ckan-conflict
+ # Python deps (with their exact version) PRESENT
+ python-dateutil, python-carrot etc
+ # Python deps (with their exact version) MISSING
+ python-ckanext-spatial_0.1~06+lucid-1_amd64.deb
+ python-ckanext-stats_0.1~06+lucid-1_amd64.deb
+ python-ckanext-csw_0.3~12+lucid-1_amd64.deb
+ python-swiss_0.3~01-1_amd64.deb
+ python-ckanext-dgu_0.2~12+lucid-1_amd64.deb
+ python-ckanext-inspire_0.1~04+lucid-1_amd64.deb
+ python-pyutilib.component.core_4.1-1_amd64.deb
+ python-ckanext-dgutheme_0.1~01+lucid-1_amd64.deb
+ python-vdm_0.9-1_amd64.deb
+ python-ckanext-qa_0.1~19-1_amd64.deb
+ python-licenses_0.6-1_amd64.deb
+ python-ckanext-importlib_0.1~01-1_amd64.deb
+ python-apachemiddleware_0.1.0-1_amd64.deb
+ python-solrpy_0.9.3-1_amd64.deb
+ python-ckan_1.3.4~02-1_amd64.deb
+ python-markupsafe_0.9.2-1_amd64.deb
+ python-ckanext-harvest_0.1~16+lucid-1_amd64.deb
+ python-formalchemy_1.3.6-1_amd64.deb
+ python-owslib_0.3.2beta~04-1_amd64.deb
+ python-ckanclient_0.6-1_amd64.deb
+
+
+Depends: python-ckan (== 1.4~03+1029381023810+lucid), apache2, libapache2-mod-wsgi, python-apachemiddleware, python-ckanext-dgu, python-ckanext-harvest, python-ckanext-csw, python-swiss, python-dateutil, rabbitmq-server, postgresql-8.4-postgis, python-carrot, python-ckanext-spatial, python-ckanext-inspire, python-ckanext-qa, python-ckanext-
Section: main/web
Priority: extra
Homepage: http://ckan.org
Description: ckan-dgu
Extensions for CKAN to run the data.gov.uk site
+
+
+
+ckan-common_1.3.4~03_amd64.deb
+ckan-dgu_0.2~15_amd64.deb
+
+python-ckan-deps_1.3.4-1_amd64.deb
--- a/ckan-dgu/DEBIAN/postinst Tue Jun 07 11:54:37 2011 +0100
+++ b/ckan-dgu/DEBIAN/postinst Tue Jun 07 16:42:42 2011 +0100
@@ -5,10 +5,9 @@
# use them here
# Things that could be done in a future version of this script
-# * Have all common CKAN functions start with cc_
# * Have a separate config for drupal password and Apache names
# * Have dgu users, groups and directories, rather than CKAN ones so that
-# potentially lots of different instances can be installed on the same
+# potentially lots of different INSTANCEs can be installed on the same
# machine
# Exit immediately if there is ever a command that returns a non-zero value
@@ -22,68 +21,64 @@
exit 1
fi
-instance="dgu"
+INSTANCE="dgu"
# Disable any existing crontabs during the upgrade, we don't want
# scripts running when things are still changing
-echo "Disabling the crontab for the ckan user ..."
-PACKAGED_CRONJOB="/tmp/${instance}-cronjob"
+echo "Disabling the crontab for the ckan${INSTANCE} user ..."
+PACKAGED_CRONJOB="/tmp/${INSTANCE}-cronjob"
cat <<EOF > ${PACKAGED_CRONJOB}
# m h dom mon dow command
EOF
-crontab -u ckan ${PACKAGED_CRONJOB}
+crontab -u ckan${INSTANCE} ${PACKAGED_CRONJOB}
# Try to put CKAN into maintenance mode, if it is installed
-if ! [ -f /etc/apache2/sites-available/${instance}.maint ] ; then
+if ! [ -f /etc/apache2/sites-available/${INSTANCE}.maint ] ; then
# We have a maintence mode available
echo "Putting CKAN into maintenance mode ..."
- maintenance_on ${instance}
+ ckan_maintenance_on ${INSTANCE}
fi
echo "Ensuring users and groups are set up correctly ..."
-ensure_users_and_groups
+ckan_ensure_users_and_groups ${INSTANCE}
-echo "Ensuring directories exist for ${instance} CKAN instance ..."
+echo "Ensuring directories exist for ${INSTANCE} CKAN INSTANCE ..."
# Ensure the standard directories exist
-make_ckan_directories ${instance}
+ckan_make_ckan_directories ${INSTANCE}
# Then create the extra ones DGU need and set permissions
-sudo chmod a+x /var/lib/ckan/${instance}/
-sudo mkdir -p -m 0700 /var/lib/ckan/${instance}/pid
-sudo chmod a+x /var/lib/ckan/${instance}/pid
-sudo mkdir -p -m 0700 /var/lib/ckan/${instance}/qa/download
-sudo chmod a+x /var/lib/ckan/${instance}/qa/download
+sudo chmod a+x /var/lib/ckan/${INSTANCE}/
+sudo mkdir -p -m 0700 /var/lib/ckan/${INSTANCE}/pid
+sudo chmod a+x /var/lib/ckan/${INSTANCE}/pid
+sudo mkdir -p -m 0700 /var/lib/ckan/${INSTANCE}/qa/download
+sudo chmod a+x /var/lib/ckan/${INSTANCE}/qa/download
+sudo chown -R ckan${INSTANCE}:ckan${INSTANCE} /var/lib/ckan/${INSTANCE}/qa/download
echo "Setting log file permissions so that both Apache and cron jobs can log to the same place ..."
-sudo touch /var/log/ckan/${instance}/${instance}.log
-sudo touch /var/log/ckan/${instance}/${instance}[1-9].log
-sudo chmod g+w /var/log/ckan/${instance}/${instance}.log
-sudo chmod g+w /var/log/ckan/${instance}/${instance}[1-9].log
-sudo chown www-data:ckan /var/log/ckan/${instance}/${instance}.log
-sudo chown www-data:ckan /var/log/ckan/${instance}/${instance}[1-9].log
+ckan_set_log_file_permissions ${INSTANCE}
-echo "Ensuring who.ini file exists for data.gov.uk CKAN instance ..."
-create_who_ini ${instance}
+echo "Ensuring who.ini file exists for data.gov.uk CKAN INSTANCE ..."
+ckan_create_who_ini ${INSTANCE}
-echo "Ensuring ${instance}.py file exists for data.gov.uk CKAN instance ..."
-create_wsgi_handler ${instance}
+echo "Ensuring ${INSTANCE}.py file exists for data.gov.uk CKAN INSTANCE ..."
+ckan_create_wsgi_handler ${INSTANCE}
-echo "Ensuring the ${instance} database exists ..."
-ensure_db_exists ${instance}
+echo "Ensuring the ${INSTANCE} database exists ..."
+ckan_ensure_db_exists ${INSTANCE}
-echo "Ensuring ${instance}.ini file exists for data.gov.uk CKAN instance ..."
-if ! [ -f /etc/ckan/${instance}/${instance}.ini ] ; then
+echo "Ensuring ${INSTANCE}.ini file exists for data.gov.uk CKAN INSTANCE ..."
+if ! [ -f /etc/ckan/${INSTANCE}/${INSTANCE}.ini ] ; then
# Create a password
password=`< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c10`
# Replace any existing user with a new one with this password
- echo "Setting the password of the ${instance} user in PostgreSQL"
- add_or_replace_database_user ${instance} ${password}
+ echo "Setting the password of the ${INSTANCE} user in PostgreSQL"
+ ckan_add_or_replace_database_user ${INSTANCE} ${password}
# Create the config file
echo "Creating a data.gov.uk config for CKAN with the same password as the DGU user"
# We use the actual password in PostgreSQL in case any non-sense has gone on
- create_config_file ${instance} ${password}
+ ckan_create_config_file ${INSTANCE} ${password}
# Now that the file exists, make some customisations
- cat <<EOF >> /etc/ckan/${instance}/${instance}.ini
-ckan.qa_downloads = /var/lib/ckan/${instance}/qa/download
+ cat <<EOF >> /etc/ckan/${INSTANCE}/${INSTANCE}.ini
+ckan.qa_downloads = /var/lib/ckan/${INSTANCE}/qa/download
dgu.xmlrpc_username = CKAN_API
#------------------------------------- XXX setup Drupal here -------------
# dgu.xmlrpc_password = XXX
@@ -102,53 +97,53 @@
-e "s,^\(package_form\)[ =].*,\1 = package_gov3," \
-e "s,^\(email_to\)[ =].*,\1 = ckan-sysadmin at okfn.org," \
-e "s,^\(error_email_from\)[ =].*,\1 = ckan-sysadmin at okfn.org," \
- -i /etc/ckan/${instance}/${instance}.ini
- echo "CAUTION: Make sure you edit '/etc/ckan/${instance}/${instance}.ini' to set the Drupal password."
+ -i /etc/ckan/${INSTANCE}/${INSTANCE}.ini
+ echo "CAUTION: Make sure you edit '/etc/ckan/${INSTANCE}/${INSTANCE}.ini' to set the Drupal password."
fi
# Install the harvesting init scripts
-if ! [ -f /etc/rc2.d/S25${instance}_harvest_gather ] ; then
+if ! [ -f /etc/rc2.d/S25${INSTANCE}_harvest_gather ] ; then
echo "Creating the harvester gather consumers ..."
- sudo touch /var/lib/ckan/${instance}/pid/gather.pid
- sudo chown ckan:ckan /var/lib/ckan/${instance}/pid/gather.pid
- sudo update-rc.d -f ${instance}_harvest_gather defaults 25 &> /dev/null
- sudo /etc/init.d/${instance}_harvest_gather start &> /dev/null
+ sudo touch /var/lib/ckan/${INSTANCE}/pid/gather.pid
+ sudo chown ckan${INSTANCE}:ckan${INSTANCE} /var/lib/ckan/${INSTANCE}/pid/gather.pid
+ sudo update-rc.d -f ${INSTANCE}_harvest_gather defaults 25 &> /dev/null
+ sudo /etc/init.d/${INSTANCE}_harvest_gather start &> /dev/null
fi
-if ! [ -f /etc/rc2.d/S25${instance}_harvest_fetch ] ; then
+if ! [ -f /etc/rc2.d/S25${INSTANCE}_harvest_fetch ] ; then
echo "Creating the harvester fetch consumers ..."
- sudo touch /var/lib/ckan/${instance}/pid/fetch.pid
- sudo chown ckan:ckan /var/lib/ckan/${instance}/pid/fetch.pid
- sudo update-rc.d -f ${instance}_harvest_fetch defaults 25 &> /dev/null
- sudo /etc/init.d/${instance}_harvest_fetch start &> /dev/null
+ sudo touch /var/lib/ckan/${INSTANCE}/pid/fetch.pid
+ sudo chown ckan${INSTANCE}:ckan${INSTANCE} /var/lib/ckan/${INSTANCE}/pid/fetch.pid
+ sudo update-rc.d -f ${INSTANCE}_harvest_fetch defaults 25 &> /dev/null
+ sudo /etc/init.d/${INSTANCE}_harvest_fetch start &> /dev/null
fi
# Install the harvesting extension tables if they aren't there already
-COMMAND_OUTPUT=`sudo -u postgres psql -d ${instance} -c "SELECT 'True' AS harvest_source_exists from pg_tables where schemaname='public' and tablename='harvest_source';" 2> /dev/null`
+COMMAND_OUTPUT=`sudo -u postgres psql -d ${INSTANCE} -c "SELECT 'True' AS harvest_source_exists from pg_tables where schemaname='public' and tablename='harvest_source';" 2> /dev/null`
if [[ "$COMMAND_OUTPUT" =~ True ]] ; then
echo "Harvester tables present"
else
echo "Setting up the harvester tables ..."
- paster --plugin=ckanext-harvest harvester initdb --config=/etc/ckan/${instance}/${instance}.ini &> /dev/null
+ paster --plugin=ckanext-harvest harvester initdb --config=/etc/ckan/${INSTANCE}/${INSTANCE}.ini &> /dev/null
fi
# Install the geospatial search tables if they aren't there already
-COMMAND_OUTPUT=`sudo -u postgres psql -d ${instance} -c "SELECT count(*) from pg_proc where proname = 'postgis_full_version'" 2> /dev/null`
+COMMAND_OUTPUT=`sudo -u postgres psql -d ${INSTANCE} -c "SELECT count(*) from pg_proc where proname = 'postgis_full_version'" 2> /dev/null`
if [[ "$COMMAND_OUTPUT" =~ 0 ]] ; then
- echo "Adding the plpgsql langauge to the ${instance} database ..."
- sudo -u postgres createlang plpgsql ${instance} &> /dev/null
+ echo "Adding the plpgsql langauge to the ${INSTANCE} database ..."
+ sudo -u postgres createlang plpgsql ${INSTANCE} &> /dev/null
echo "Installing PostGIS extensions ..."
- sudo -u postgres psql -d ${instance} -f /usr/share/postgresql/8.4/contrib/postgis.sql &> /dev/null
- sudo -u postgres psql -d ${instance} -f /usr/share/postgresql/8.4/contrib/spatial_ref_sys.sql &> /dev/null
+ sudo -u postgres psql -d ${INSTANCE} -f /usr/share/postgresql/8.4/contrib/postgis.sql &> /dev/null
+ sudo -u postgres psql -d ${INSTANCE} -f /usr/share/postgresql/8.4/contrib/spatial_ref_sys.sql &> /dev/null
echo "Setting PostGIS permissions for CKAN and initialising tables ..."
- sudo -u postgres psql -d ${instance} -c "ALTER TABLE geometry_columns OWNER TO ${instance}" &> /dev/null
- sudo -u postgres psql -d ${instance} -c "ALTER TABLE spatial_ref_sys OWNER TO ${instance}" &> /dev/null
- sudo paster --plugin=ckanext-spatial spatial initdb --config=/etc/ckan/${instance}/${instance}.ini &> /dev/null
+ sudo -u postgres psql -d ${INSTANCE} -c "ALTER TABLE geometry_columns OWNER TO ${INSTANCE}" &> /dev/null
+ sudo -u postgres psql -d ${INSTANCE} -c "ALTER TABLE spatial_ref_sys OWNER TO ${INSTANCE}" &> /dev/null
+ sudo paster --plugin=ckanext-spatial spatial initdb --config=/etc/ckan/${INSTANCE}/${INSTANCE}.ini &> /dev/null
fi
# Set any plugins needed
echo "Ensuring the latest plugins are configured ..."
sed -e "s,^\(ckan.plugins\)[ =].*,\1 = dgu_form_api cswserver harvest gemini_harvester gemini_doc_harvester gemini_waf_harvester inspire_api wms_preview spatial_query dgu_theme_embedded qa dgu_auth_api," \
- -i /etc/ckan/${instance}/${instance}.ini
+ -i /etc/ckan/${INSTANCE}/${INSTANCE}.ini
# Overwrite the existing Apache config
if [ -f /etc/apache2/sites-enabled/default ] ; then
@@ -157,7 +152,7 @@
fi
echo "Overwriting the existing Apache config ..."
-overwrite_apache_config ${instance} catalog.data.gov.uk dgu-live.okfn.org
+ckan_overwrite_apache_config ${INSTANCE} catalog.data.gov.uk dgu-live.okfn.org
# Make sure mod_rewrite is enabled
if ! [ -f /etc/apache2/mods-enabled/rewrite.load ] ; then
@@ -168,11 +163,11 @@
# Standard paster db upgrade
echo "Performing any database upgrades ..."
-paster --plugin=ckan db upgrade --config=/etc/ckan/${instance}/${instance}.ini &> /dev/null
+paster --plugin=ckan db upgrade --config=/etc/ckan/${INSTANCE}/${INSTANCE}.ini &> /dev/null
-# Make sure our instance is enabled
-echo "Bringing the ${instance} instance out of maintenance mode ..."
-maintenance_off ${instance}
+# Make sure our INSTANCE is enabled
+echo "Bringing the ${INSTANCE} INSTANCE out of maintenance mode ..."
+ckan_maintenance_off ${INSTANCE}
# Restart Apache so it is aware of any changes
echo "Restarting apache ..."
@@ -180,11 +175,11 @@
#&> /dev/null
# Install the new crontab
-echo "Enabling crontab for the ckan user ..."
-PACKAGED_CRONJOB="/tmp/${instance}-cronjob"
+echo "Enabling crontab for the ckan${INSTANCE} user ..."
+PACKAGED_CRONJOB="/tmp/${INSTANCE}-cronjob"
cat <<EOF > ${PACKAGED_CRONJOB}
# WARNING: Do not edit these cron tabs, they will be overwritten any time
-# the ckan-dgu package is upgraded
+# the ckan INSTANCE package is upgraded
# QUESTION: Should email reports be sent to root?
# Gov Daily
# 31 23 * * * python /usr/lib/pymodules/python2.6/ckanext/dgu/bin/gov_daily.py /etc/ckan/dgu/dgu.ini
@@ -194,6 +189,7 @@
# Then run the harvester 1 minute after any fetch or gather restart
# 1,11,21,31,41,51 * * * * paster --plugin=ckanext-harvest harvester run --config=/etc/ckan/dgu/dgu.ini
# Update the package 5 star scores once a month
-# 0 0 1 * * paster --plugin=ckanext-qa update-scores update --config=/etc/ckan/dgu/dgu.ini
+# 0 0 1 * * paster --plugin=ckanext-qa package-scores update --config=/etc/ckan/dgu/dgu.ini
EOF
-crontab -u ckan ${PACKAGED_CRONJOB}
+crontab -u ckan${INSTANCE} ${PACKAGED_CRONJOB}
+
Repository URL: https://bitbucket.org/okfn/ckan-debs-public/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the ckan-changes
mailing list