mirror of
https://github.com/HaitiData/haitidata.git
synced 2026-10-26 17:35:17 +00:00
1169 lines
37 KiB
Python
1169 lines
37 KiB
Python
# -*- coding: utf-8 -*-
|
|
#########################################################################
|
|
#
|
|
# Copyright (C) 2018 OSGeo
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
#########################################################################
|
|
|
|
import django
|
|
import fileinput
|
|
import glob
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import signal
|
|
import sys
|
|
import time
|
|
import urllib
|
|
import urllib2
|
|
import zipfile
|
|
from urlparse import urlparse
|
|
|
|
import yaml
|
|
from paver.easy import (BuildFailure, call_task, cmdopts, info, needs, options,
|
|
path, sh, task)
|
|
from setuptools.command import easy_install
|
|
|
|
try:
|
|
from haitidata.local_settings import *
|
|
except ImportError:
|
|
from haitidata.settings import *
|
|
|
|
try:
|
|
from paver.path import pushd
|
|
except ImportError:
|
|
from paver.easy import pushd
|
|
|
|
from geonode.settings import (INSTALLED_APPS,
|
|
GEONODE_CORE_APPS,
|
|
GEONODE_INTERNAL_APPS,
|
|
GEONODE_APPS,
|
|
OGC_SERVER,
|
|
ASYNC_SIGNALS)
|
|
|
|
assert sys.version_info >= (2, 6), \
|
|
SystemError("GeoNode Build requires python 2.6 or better")
|
|
|
|
dev_config = None
|
|
with open("dev_config.yml", 'r') as f:
|
|
dev_config = yaml.load(f, Loader=yaml.Loader)
|
|
|
|
|
|
def grab(src, dest, name):
|
|
download = True
|
|
if not dest.exists():
|
|
print('Downloading %s' % name)
|
|
elif not zipfile.is_zipfile(dest):
|
|
print('Downloading %s (corrupt file)' % name)
|
|
else:
|
|
download = False
|
|
if download:
|
|
if str(src).startswith("file://"):
|
|
src2 = src[7:]
|
|
if not os.path.exists(src2):
|
|
print("Source location (%s) does not exist" % str(src2))
|
|
else:
|
|
print("Copying local file from %s" % str(src2))
|
|
shutil.copyfile(str(src2), str(dest))
|
|
else:
|
|
# urllib.urlretrieve(str(src), str(dest))
|
|
from tqdm import tqdm
|
|
import requests
|
|
import math
|
|
# Streaming, so we can iterate over the response.
|
|
r = requests.get(str(src), stream=True, timeout=10, verify=False)
|
|
# Total size in bytes.
|
|
total_size = int(r.headers.get('content-length', 0))
|
|
print("Requesting %s" % str(src))
|
|
block_size = 1024
|
|
wrote = 0
|
|
with open('output.bin', 'wb') as f:
|
|
for data in tqdm(r.iter_content(block_size), total=math.ceil(total_size//block_size) , unit='KB', unit_scale=False):
|
|
wrote = wrote + len(data)
|
|
f.write(data)
|
|
print(" total_size [%d] / wrote [%d] " % (total_size, wrote))
|
|
if total_size != 0 and wrote != total_size:
|
|
print("ERROR, something went wrong")
|
|
else:
|
|
shutil.move('output.bin', str(dest))
|
|
try:
|
|
# Cleaning up
|
|
os.remove('output.bin')
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
@task
|
|
@cmdopts([
|
|
('geoserver=', 'g', 'The location of the geoserver build (.war file).'),
|
|
('jetty=', 'j', 'The location of the Jetty Runner (.jar file).'),
|
|
])
|
|
def setup_geoserver(options):
|
|
"""Prepare a testing instance of GeoServer."""
|
|
# only start if using Geoserver backend
|
|
_backend = os.environ.get('BACKEND', OGC_SERVER['default']['BACKEND'])
|
|
if _backend == 'geonode.qgis_server' or 'geonode.geoserver' not in INSTALLED_APPS:
|
|
return
|
|
|
|
download_dir = path('downloaded')
|
|
if not download_dir.exists():
|
|
download_dir.makedirs()
|
|
|
|
geoserver_dir = path('geoserver')
|
|
|
|
geoserver_bin = download_dir / \
|
|
os.path.basename(dev_config['GEOSERVER_URL'])
|
|
jetty_runner = download_dir / \
|
|
os.path.basename(dev_config['JETTY_RUNNER_URL'])
|
|
|
|
grab(
|
|
options.get(
|
|
'geoserver',
|
|
dev_config['GEOSERVER_URL']),
|
|
geoserver_bin,
|
|
"geoserver binary")
|
|
grab(
|
|
options.get(
|
|
'jetty',
|
|
dev_config['JETTY_RUNNER_URL']),
|
|
jetty_runner,
|
|
"jetty runner")
|
|
|
|
if not geoserver_dir.exists():
|
|
geoserver_dir.makedirs()
|
|
|
|
webapp_dir = geoserver_dir / 'geoserver'
|
|
if not webapp_dir:
|
|
webapp_dir.makedirs()
|
|
|
|
print 'extracting geoserver'
|
|
z = zipfile.ZipFile(geoserver_bin, "r")
|
|
z.extractall(webapp_dir)
|
|
|
|
_install_data_dir()
|
|
|
|
|
|
@task
|
|
def setup_qgis_server(options):
|
|
"""Prepare a testing instance of QGIS Server."""
|
|
# only start if using QGIS Server backend
|
|
_backend = os.environ.get('BACKEND', OGC_SERVER['default']['BACKEND'])
|
|
if _backend == 'geonode.geoserver' or 'geonode.qgis_server' not in INSTALLED_APPS:
|
|
return
|
|
|
|
# QGIS Server testing instance run on top of docker
|
|
try:
|
|
sh('scripts/misc/docker_check.sh')
|
|
except Exception:
|
|
info("You need to have docker and docker-compose installed.")
|
|
return
|
|
|
|
info('Docker and docker-compose were installed.')
|
|
info('Proceeded to setup QGIS Server.')
|
|
info('Create QGIS Server related folder.')
|
|
|
|
try:
|
|
os.makedirs('geonode/qgis_layer')
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
os.makedirs('geonode/qgis_tiles')
|
|
except Exception:
|
|
pass
|
|
|
|
all_permission = 0o777
|
|
os.chmod('geonode/qgis_layer', all_permission)
|
|
stat = os.stat('geonode/qgis_layer')
|
|
info('Mode : %o' % stat.st_mode)
|
|
os.chmod('geonode/qgis_tiles', all_permission)
|
|
stat = os.stat('geonode/qgis_tiles')
|
|
info('Mode : %o' % stat.st_mode)
|
|
|
|
info('QGIS Server related folder successfully setup.')
|
|
|
|
|
|
def _robust_rmtree(path, logger=None, max_retries=5):
|
|
"""Try to delete paths robustly .
|
|
Retries several times (with increasing delays) if an OSError
|
|
occurs. If the final attempt fails, the Exception is propagated
|
|
to the caller. Taken from https://github.com/hashdist/hashdist/pull/116
|
|
"""
|
|
|
|
for i in range(max_retries):
|
|
try:
|
|
shutil.rmtree(path)
|
|
return
|
|
except OSError as e:
|
|
if logger:
|
|
info('Unable to remove path: %s' % path)
|
|
info('Retrying after %d seconds' % i)
|
|
time.sleep(i)
|
|
|
|
# Final attempt, pass any Exceptions up to caller.
|
|
shutil.rmtree(path)
|
|
|
|
|
|
def _install_data_dir():
|
|
target_data_dir = path('geoserver/data')
|
|
if target_data_dir.exists():
|
|
try:
|
|
target_data_dir.rmtree()
|
|
except OSError:
|
|
_robust_rmtree(target_data_dir, logger=True)
|
|
|
|
original_data_dir = path('geoserver/geoserver/data')
|
|
justcopy(original_data_dir, target_data_dir)
|
|
|
|
try:
|
|
config = path(
|
|
'geoserver/data/global.xml')
|
|
with open(config) as f:
|
|
xml = f.read()
|
|
m = re.search('proxyBaseUrl>([^<]+)', xml)
|
|
xml = xml[:m.start(1)] + \
|
|
"http://localhost:8080/geoserver" + xml[m.end(1):]
|
|
with open(config, 'w') as f:
|
|
f.write(xml)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
try:
|
|
config = path(
|
|
'geoserver/data/security/filter/geonode-oauth2/config.xml')
|
|
with open(config) as f:
|
|
xml = f.read()
|
|
m = re.search('accessTokenUri>([^<]+)', xml)
|
|
xml = xml[:m.start(1)] + \
|
|
"http://localhost:8000/o/token/" + xml[m.end(1):]
|
|
m = re.search('userAuthorizationUri>([^<]+)', xml)
|
|
xml = xml[:m.start(
|
|
1)] + "http://localhost:8000/o/authorize/" + xml[m.end(1):]
|
|
m = re.search('redirectUri>([^<]+)', xml)
|
|
xml = xml[:m.start(
|
|
1)] + "http://localhost:8080/geoserver/index.html" + xml[m.end(1):]
|
|
m = re.search('checkTokenEndpointUrl>([^<]+)', xml)
|
|
xml = xml[:m.start(
|
|
1)] + "http://localhost:8000/api/o/v4/tokeninfo/" + xml[m.end(1):]
|
|
m = re.search('logoutUri>([^<]+)', xml)
|
|
xml = xml[:m.start(
|
|
1)] + "http://localhost:8000/account/logout/" + xml[m.end(1):]
|
|
with open(config, 'w') as f:
|
|
f.write(xml)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
try:
|
|
config = path(
|
|
'geoserver/data/security/role/geonode REST role service/config.xml')
|
|
with open(config) as f:
|
|
xml = f.read()
|
|
m = re.search('baseUrl>([^<]+)', xml)
|
|
xml = xml[:m.start(1)] + "http://localhost:8000" + xml[m.end(1):]
|
|
with open(config, 'w') as f:
|
|
f.write(xml)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
|
|
@task
|
|
def static(options):
|
|
with pushd('geonode/static'):
|
|
sh('grunt production')
|
|
|
|
|
|
@task
|
|
@needs([
|
|
'setup_geoserver',
|
|
'setup_qgis_server',
|
|
])
|
|
def setup(options):
|
|
"""Get dependencies and prepare a GeoNode development environment."""
|
|
|
|
updategeoip(options)
|
|
info(('GeoNode development environment successfully set up.'
|
|
'If you have not set up an administrative account,'
|
|
' please do so now. Use "paver start" to start up the server.'))
|
|
|
|
|
|
def grab_winfiles(url, dest, packagename):
|
|
# Add headers
|
|
headers = {'User-Agent': 'Mozilla 5.10'}
|
|
request = urllib2.Request(url, None, headers)
|
|
response = urllib2.urlopen(request)
|
|
with open(dest, 'wb') as writefile:
|
|
writefile.write(response.read())
|
|
|
|
|
|
@task
|
|
def win_install_deps(options):
|
|
"""
|
|
Install all Windows Binary automatically
|
|
This can be removed as wheels become available for these packages
|
|
"""
|
|
download_dir = path('downloaded').abspath()
|
|
if not download_dir.exists():
|
|
download_dir.makedirs()
|
|
win_packages = {
|
|
# required by transifex-client
|
|
"Py2exe": dev_config['WINDOWS']['py2exe'],
|
|
"Nose": dev_config['WINDOWS']['nose'],
|
|
# the wheel 1.9.4 installs but pycsw wants 1.9.3, which fails to compile
|
|
# when pycsw bumps their pyproj to 1.9.4 this can be removed.
|
|
"PyProj": dev_config['WINDOWS']['pyproj'],
|
|
"lXML": dev_config['WINDOWS']['lxml']
|
|
}
|
|
failed = False
|
|
for package, url in win_packages.iteritems():
|
|
tempfile = download_dir / os.path.basename(url)
|
|
print "Installing file ... " + tempfile
|
|
grab_winfiles(url, tempfile, package)
|
|
try:
|
|
easy_install.main([tempfile])
|
|
except Exception as e:
|
|
failed = True
|
|
print "install failed with error: ", e
|
|
os.remove(tempfile)
|
|
if failed and sys.maxsize > 2**32:
|
|
print "64bit architecture is not currently supported"
|
|
print "try finding the 64 binaries for py2exe, nose, and pyproj"
|
|
elif failed:
|
|
print "install failed for py2exe, nose, and/or pyproj"
|
|
else:
|
|
print "Windows dependencies now complete. Run pip install -e geonode --use-mirrors"
|
|
|
|
|
|
@cmdopts([
|
|
('version=', 'v', 'Legacy GeoNode version of the existing database.')
|
|
])
|
|
@task
|
|
def upgradedb(options):
|
|
"""
|
|
Add 'fake' data migrations for existing tables from legacy GeoNode versions
|
|
"""
|
|
version = options.get('version')
|
|
if version in ['1.1', '1.2']:
|
|
sh("python -W ignore manage.py migrate maps 0001 --fake")
|
|
sh("python -W ignore manage.py migrate avatar 0001 --fake")
|
|
elif version is None:
|
|
print "Please specify your GeoNode version"
|
|
else:
|
|
print "Upgrades from version %s are not yet supported." % version
|
|
|
|
|
|
@task
|
|
def updategeoip(options):
|
|
"""
|
|
Update geoip db
|
|
"""
|
|
settings = options.get('settings', '')
|
|
if settings:
|
|
settings = 'DJANGO_SETTINGS_MODULE=%s' % settings
|
|
|
|
sh("%s python -W ignore manage.py updategeoip -o" % settings)
|
|
|
|
|
|
@task
|
|
@cmdopts([
|
|
('settings', 's', 'Specify custom DJANGO_SETTINGS_MODULE')
|
|
])
|
|
def sync(options):
|
|
"""
|
|
Run the migrate and migrate management commands to create and migrate a DB
|
|
"""
|
|
settings = options.get('settings', '')
|
|
if settings:
|
|
settings = 'DJANGO_SETTINGS_MODULE=%s' % settings
|
|
|
|
sh("%s python -W ignore manage.py makemigrations --noinput" % settings)
|
|
sh("%s python -W ignore manage.py migrate --noinput" % settings)
|
|
sh("%s python -W ignore manage.py loaddata fixtures/sample_admin.json" % settings)
|
|
sh("%s python -W ignore manage.py loaddata fixtures/default_oauth_apps.json" %
|
|
settings)
|
|
sh("%s python -W ignore manage.py loaddata fixtures/initial_data.json" % settings)
|
|
sh("%s python -W ignore manage.py set_all_layers_alternate" % settings)
|
|
|
|
|
|
@task
|
|
def package(options):
|
|
"""
|
|
Creates a tarball to use for building the system elsewhere
|
|
"""
|
|
import tarfile
|
|
import geonode
|
|
|
|
version = geonode.get_version()
|
|
# Use GeoNode's version for the package name.
|
|
pkgname = 'GeoNode-%s-all' % version
|
|
|
|
# Create the output directory.
|
|
out_pkg = path(pkgname)
|
|
out_pkg_tar = path("%s.tar.gz" % pkgname)
|
|
|
|
# Create a distribution in zip format for the geonode python package.
|
|
dist_dir = path('dist')
|
|
dist_dir.rmtree()
|
|
sh('python setup.py sdist --formats=zip')
|
|
|
|
with pushd('package'):
|
|
|
|
# Delete old tar files in that directory
|
|
for f in glob.glob('GeoNode*.tar.gz'):
|
|
old_package = path(f)
|
|
if old_package != out_pkg_tar:
|
|
old_package.remove()
|
|
|
|
if out_pkg_tar.exists():
|
|
info('There is already a package for version %s' % version)
|
|
return
|
|
|
|
# Clean anything that is in the oupout package tree.
|
|
out_pkg.rmtree()
|
|
out_pkg.makedirs()
|
|
|
|
support_folder = path('support')
|
|
install_file = path('install.sh')
|
|
|
|
# And copy the default files from the package folder.
|
|
justcopy(support_folder, out_pkg / 'support')
|
|
justcopy(install_file, out_pkg)
|
|
|
|
geonode_dist = path('..') / 'dist' / 'GeoNode-%s.zip' % version
|
|
justcopy(geonode_dist, out_pkg)
|
|
|
|
# Create a tar file with all files in the output package folder.
|
|
tar = tarfile.open(out_pkg_tar, "w:gz")
|
|
for file in out_pkg.walkfiles():
|
|
tar.add(file)
|
|
|
|
# Add the README with the license and important links to documentation.
|
|
tar.add('README', arcname=('%s/README.rst' % out_pkg))
|
|
tar.close()
|
|
|
|
# Remove all the files in the temporary output package directory.
|
|
out_pkg.rmtree()
|
|
|
|
# Report the info about the new package.
|
|
info("%s created" % out_pkg_tar.abspath())
|
|
|
|
|
|
@task
|
|
@needs(['start_geoserver',
|
|
'start_qgis_server',
|
|
'start_django'])
|
|
@cmdopts([
|
|
('bind=', 'b', 'Bind server to provided IP address and port number.'),
|
|
('java_path=', 'j', 'Full path to java install for Windows'),
|
|
('foreground', 'f', 'Do not run in background but in foreground'),
|
|
('settings', 's', 'Specify custom DJANGO_SETTINGS_MODULE')
|
|
], share_with=['start_django', 'start_geoserver'])
|
|
def start():
|
|
"""
|
|
Start GeoNode (Django, GeoServer & Client)
|
|
"""
|
|
sh('sleep 30')
|
|
info("GeoNode is now available.")
|
|
|
|
|
|
@task
|
|
def stop_django():
|
|
"""
|
|
Stop the GeoNode Django application
|
|
"""
|
|
kill('python', 'celery')
|
|
kill('python', 'runserver')
|
|
kill('python', 'runmessaging')
|
|
|
|
|
|
@task
|
|
def stop_geoserver():
|
|
"""
|
|
Stop GeoServer
|
|
"""
|
|
# only start if using Geoserver backend
|
|
_backend = os.environ.get('BACKEND', OGC_SERVER['default']['BACKEND'])
|
|
if _backend == 'geonode.qgis_server' or 'geonode.geoserver' not in INSTALLED_APPS:
|
|
return
|
|
kill('java', 'geoserver')
|
|
|
|
# Kill process.
|
|
try:
|
|
# proc = subprocess.Popen("ps -ef | grep -i -e '[j]ava\|geoserver' |
|
|
# awk '{print $2}'",
|
|
proc = subprocess.Popen(
|
|
"ps -ef | grep -i -e 'geoserver' | awk '{print $2}'",
|
|
shell=True,
|
|
stdout=subprocess.PIPE)
|
|
for pid in proc.stdout:
|
|
info('Stopping geoserver (process number %s)' % int(pid))
|
|
os.kill(int(pid), signal.SIGKILL)
|
|
os.kill(int(pid), 9)
|
|
sh('sleep 30')
|
|
# Check if the process that we killed is alive.
|
|
try:
|
|
os.kill(int(pid), 0)
|
|
# raise Exception("""wasn't able to kill the process\nHINT:use
|
|
# signal.SIGKILL or signal.SIGABORT""")
|
|
except OSError as ex:
|
|
continue
|
|
except Exception as e:
|
|
info(e)
|
|
|
|
|
|
@task
|
|
@cmdopts([
|
|
('qgis_server_port=', 'p', 'The port of the QGIS Server instance.')
|
|
])
|
|
def stop_qgis_server():
|
|
"""
|
|
Stop QGIS Server Backend.
|
|
"""
|
|
# only start if using QGIS Server backend
|
|
_backend = os.environ.get('BACKEND', OGC_SERVER['default']['BACKEND'])
|
|
if _backend == 'geonode.geoserver' or 'geonode.qgis_server' not in INSTALLED_APPS:
|
|
return
|
|
port = options.get('qgis_server_port', '9000')
|
|
|
|
sh(
|
|
'docker-compose -f docker-compose-qgis-server.yml down',
|
|
env={
|
|
'GEONODE_PROJECT_PATH': os.getcwd(),
|
|
'QGIS_SERVER_PORT': port
|
|
})
|
|
|
|
|
|
@task
|
|
@needs([
|
|
'stop_geoserver',
|
|
'stop_qgis_server'
|
|
])
|
|
def stop():
|
|
"""
|
|
Stop GeoNode
|
|
"""
|
|
# windows needs to stop the geoserver first b/c we can't tell which python
|
|
# is running, so we kill everything
|
|
info("Stopping GeoNode ...")
|
|
stop_django()
|
|
|
|
|
|
@cmdopts([
|
|
('bind=', 'b', 'Bind server to provided IP address and port number.')
|
|
])
|
|
@task
|
|
def start_django():
|
|
"""
|
|
Start the GeoNode Django application
|
|
"""
|
|
settings = options.get('settings', '')
|
|
if settings:
|
|
settings = 'DJANGO_SETTINGS_MODULE=%s' % settings
|
|
bind = options.get('bind', '0.0.0.0:8000')
|
|
foreground = '' if options.get('foreground', False) else '&'
|
|
sh('%s python -W ignore manage.py runserver %s %s' % (settings, bind, foreground))
|
|
|
|
celery_queues = [
|
|
"default",
|
|
"geonode",
|
|
"cleanup",
|
|
"update",
|
|
"email",
|
|
# Those queues are directly managed by messages.consumer
|
|
# "broadcast",
|
|
# "email.events",
|
|
# "all.geoserver",
|
|
# "geoserver.events",
|
|
# "geoserver.data",
|
|
# "geoserver.catalog",
|
|
# "notifications.events",
|
|
# "geonode.layer.viewer"
|
|
]
|
|
sh('%s celery -A geonode.celery_app:app worker -Q %s -B -E -l INFO %s' % (settings, ",".join(celery_queues),foreground))
|
|
|
|
if ASYNC_SIGNALS:
|
|
sh('%s python -W ignore manage.py runmessaging %s' % (settings, foreground))
|
|
|
|
|
|
def start_messaging():
|
|
"""
|
|
Start the GeoNode messaging server
|
|
"""
|
|
settings = options.get('settings', '')
|
|
if settings:
|
|
settings = 'DJANGO_SETTINGS_MODULE=%s' % settings
|
|
foreground = '' if options.get('foreground', False) else '&'
|
|
sh('%s python -W ignore manage.py runmessaging %s' % (settings, foreground))
|
|
|
|
|
|
@cmdopts([
|
|
('java_path=', 'j', 'Full path to java install for Windows')
|
|
])
|
|
@task
|
|
def start_geoserver(options):
|
|
"""
|
|
Start GeoServer with GeoNode extensions
|
|
"""
|
|
# only start if using Geoserver backend
|
|
_backend = os.environ.get('BACKEND', OGC_SERVER['default']['BACKEND'])
|
|
if _backend == 'geonode.qgis_server' or 'geonode.geoserver' not in INSTALLED_APPS:
|
|
return
|
|
|
|
GEOSERVER_BASE_URL = OGC_SERVER['default']['LOCATION']
|
|
url = GEOSERVER_BASE_URL
|
|
|
|
if urlparse(GEOSERVER_BASE_URL).hostname != 'localhost':
|
|
print "Warning: OGC_SERVER['default']['LOCATION'] hostname is not equal to 'localhost'"
|
|
|
|
if not GEOSERVER_BASE_URL.endswith('/'):
|
|
print "Error: OGC_SERVER['default']['LOCATION'] does not end with a '/'"
|
|
sys.exit(1)
|
|
|
|
download_dir = path('downloaded').abspath()
|
|
jetty_runner = download_dir / \
|
|
os.path.basename(dev_config['JETTY_RUNNER_URL'])
|
|
data_dir = path('geoserver/data').abspath()
|
|
geofence_dir = path('geoserver/data/geofence').abspath()
|
|
web_app = path('geoserver/geoserver').abspath()
|
|
log_file = path('geoserver/jetty.log').abspath()
|
|
config = path('scripts/misc/jetty-runner.xml').abspath()
|
|
jetty_port = urlparse(GEOSERVER_BASE_URL).port
|
|
|
|
import socket
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
socket_free = True
|
|
try:
|
|
s.bind(("127.0.0.1", jetty_port))
|
|
except socket.error as e:
|
|
socket_free = False
|
|
if e.errno == 98:
|
|
info('Port %s is already in use' % jetty_port)
|
|
else:
|
|
info(
|
|
'Something else raised the socket.error exception while checking port %s' %
|
|
jetty_port)
|
|
print(e)
|
|
finally:
|
|
s.close()
|
|
|
|
if socket_free:
|
|
# @todo - we should not have set workdir to the datadir but a bug in geoserver
|
|
# prevents geonode security from initializing correctly otherwise
|
|
with pushd(data_dir):
|
|
javapath = "java"
|
|
loggernullpath = os.devnull
|
|
|
|
# checking if our loggernullpath exists and if not, reset it to
|
|
# something manageable
|
|
if loggernullpath == "nul":
|
|
try:
|
|
open("../../downloaded/null.txt", 'w+').close()
|
|
except IOError as e:
|
|
print "Chances are that you have Geoserver currently running. You \
|
|
can either stop all servers with paver stop or start only \
|
|
the django application with paver start_django."
|
|
sys.exit(1)
|
|
loggernullpath = "../../downloaded/null.txt"
|
|
|
|
try:
|
|
sh(('java -version'))
|
|
except Exception:
|
|
print "Java was not found in your path. Trying some other options: "
|
|
javapath_opt = None
|
|
if os.environ.get('JAVA_HOME', None):
|
|
print "Using the JAVA_HOME environment variable"
|
|
javapath_opt = os.path.join(os.path.abspath(
|
|
os.environ['JAVA_HOME']), "bin", "java.exe")
|
|
elif options.get('java_path'):
|
|
javapath_opt = options.get('java_path')
|
|
else:
|
|
print "Paver cannot find java in the Windows Environment. \
|
|
Please provide the --java_path flag with your full path to \
|
|
java.exe e.g. --java_path=C:/path/to/java/bin/java.exe"
|
|
sys.exit(1)
|
|
# if there are spaces
|
|
javapath = 'START /B "" "' + javapath_opt + '"'
|
|
|
|
sh((
|
|
'%(javapath)s -Xms512m -Xmx2048m -server -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m'
|
|
' -DGEOSERVER_DATA_DIR=%(data_dir)s'
|
|
' -Dgeofence.dir=%(geofence_dir)s'
|
|
# ' -Dgeofence-ovr=geofence-datasource-ovr.properties'
|
|
# workaround for JAI sealed jar issue and jetty classloader
|
|
# ' -Dorg.eclipse.jetty.server.webapp.parentLoaderPriority=true'
|
|
' -jar %(jetty_runner)s'
|
|
' --port %(jetty_port)i'
|
|
' --log %(log_file)s'
|
|
' %(config)s'
|
|
' > %(loggernullpath)s &' % locals()
|
|
))
|
|
|
|
info('Starting GeoServer on %s' % url)
|
|
|
|
# wait for GeoServer to start
|
|
started = waitfor(url)
|
|
info('The logs are available at %s' % log_file)
|
|
|
|
if not started:
|
|
# If applications did not start in time we will give the user a chance
|
|
# to inspect them and stop them manually.
|
|
info(('GeoServer never started properly or timed out.'
|
|
'It may still be running in the background.'))
|
|
sys.exit(1)
|
|
|
|
|
|
@task
|
|
@cmdopts([
|
|
('qgis_server_port=', 'p', 'The port of the QGIS Server instance.')
|
|
])
|
|
def start_qgis_server():
|
|
"""Start QGIS Server instance with GeoNode related plugins."""
|
|
# only start if using QGIS Serrver backend
|
|
_backend = os.environ.get('BACKEND', OGC_SERVER['default']['BACKEND'])
|
|
if _backend == 'geonode.geoserver' or 'geonode.qgis_server' not in INSTALLED_APPS:
|
|
return
|
|
info('Starting up QGIS Server...')
|
|
|
|
port = options.get('qgis_server_port', '9000')
|
|
|
|
sh(
|
|
'docker-compose -f docker-compose-qgis-server.yml up -d qgis-server',
|
|
env={
|
|
'GEONODE_PROJECT_PATH': os.getcwd(),
|
|
'QGIS_SERVER_PORT': port
|
|
})
|
|
info('QGIS Server is up.')
|
|
|
|
|
|
@task
|
|
def test(options):
|
|
"""
|
|
Run GeoNode's Unit Test Suite
|
|
"""
|
|
sh("%s manage.py test %s.tests --noinput" % (options.get('prefix'),
|
|
'.tests '.join(GEONODE_APPS)))
|
|
|
|
|
|
@task
|
|
@cmdopts([
|
|
('local=', 'l', 'Set to True if running bdd tests locally')
|
|
])
|
|
def test_bdd():
|
|
"""
|
|
Run GeoNode's BDD Test Suite
|
|
"""
|
|
local = str2bool(options.get('local', 'false'))
|
|
if local:
|
|
call_task('reset_hard')
|
|
call_task('setup')
|
|
else:
|
|
call_task('reset')
|
|
call_task('setup')
|
|
call_task('sync')
|
|
sh('sleep 30')
|
|
info("GeoNode is now available, running the bdd tests now.")
|
|
|
|
sh('py.test')
|
|
|
|
if local:
|
|
call_task('reset_hard')
|
|
|
|
|
|
@task
|
|
def test_javascript(options):
|
|
with pushd('geonode/static/geonode'):
|
|
sh('./run-tests.sh')
|
|
|
|
|
|
@task
|
|
@cmdopts([
|
|
('name=', 'n', 'Run specific tests.'),
|
|
('settings', 's', 'Specify custom DJANGO_SETTINGS_MODULE')
|
|
])
|
|
def test_integration(options):
|
|
"""
|
|
Run GeoNode's Integration test suite against the external apps
|
|
"""
|
|
_backend = os.environ.get('BACKEND', OGC_SERVER['default']['BACKEND'])
|
|
if _backend == 'geonode.geoserver' or 'geonode.qgis_server' not in INSTALLED_APPS:
|
|
call_task('stop_geoserver')
|
|
_reset()
|
|
# Start GeoServer
|
|
call_task('start_geoserver')
|
|
else:
|
|
call_task('stop_qgis_server')
|
|
_reset()
|
|
# Start QGis Server
|
|
call_task('start_qgis_server')
|
|
|
|
sh('sleep 30')
|
|
|
|
name = options.get('name', 'geonode.tests.integration')
|
|
settings = options.get('settings', '')
|
|
if not settings and name == 'geonode.upload.tests.integration':
|
|
sh("cp geonode/upload/tests/test_settings.py geonode/")
|
|
settings = 'geonode.test_settings'
|
|
|
|
success = False
|
|
try:
|
|
if name == 'geonode.tests.csw':
|
|
call_task('sync', options={'settings': settings})
|
|
call_task('start', options={'settings': settings})
|
|
call_task('setup_data', options={'settings': settings})
|
|
|
|
settings = 'DJANGO_SETTINGS_MODULE=%s' % settings if settings else ''
|
|
|
|
if name == 'geonode.upload.tests.integration':
|
|
sh("%s python -W ignore manage.py makemigrations --noinput" % settings)
|
|
sh("%s python -W ignore manage.py migrate --noinput" % settings)
|
|
sh("%s python -W ignore manage.py loaddata sample_admin.json" % settings)
|
|
sh("%s python -W ignore manage.py loaddata geonode/base/fixtures/default_oauth_apps.json" %
|
|
settings)
|
|
sh("%s python -W ignore manage.py loaddata geonode/base/fixtures/initial_data.json" %
|
|
settings)
|
|
call_task('start_geoserver')
|
|
bind = options.get('bind', '0.0.0.0:8000')
|
|
foreground = '' if options.get('foreground', False) else '&'
|
|
sh('%s python -W ignore manage.py runmessaging %s' % (settings, foreground))
|
|
sh('%s python -W ignore manage.py runserver %s %s' %
|
|
(settings, bind, foreground))
|
|
sh('sleep 30')
|
|
settings = 'REUSE_DB=1 %s' % settings
|
|
|
|
live_server_option = ''
|
|
info("GeoNode is now available, running the tests now.")
|
|
sh(('%s python -W ignore manage.py test %s'
|
|
' %s --noinput %s' % (settings, name, _keepdb, live_server_option)))
|
|
|
|
except BuildFailure as e:
|
|
info('Tests failed! %s' % str(e))
|
|
else:
|
|
success = True
|
|
finally:
|
|
# don't use call task here - it won't run since it already has
|
|
stop()
|
|
|
|
call_task('stop_geoserver')
|
|
_reset()
|
|
if not success:
|
|
sys.exit(1)
|
|
|
|
|
|
@task
|
|
@needs(['start_geoserver',
|
|
'start_qgis_server'])
|
|
@cmdopts([
|
|
('coverage', 'c', 'use this flag to generate coverage during test runs'),
|
|
('local=', 'l', 'Set to True if running bdd tests locally')
|
|
])
|
|
def run_tests(options):
|
|
"""
|
|
Executes the entire test suite.
|
|
"""
|
|
if options.get('coverage'):
|
|
prefix = 'coverage run --branch --source=geonode \
|
|
--omit="*/management/*,*/test*,*/wsgi*,*/middleware*,*/context_processors*,geonode/qgis_server/*,geonode/contrib/*,geonode/upload/*"'
|
|
else:
|
|
prefix = 'python'
|
|
local = options.get('local', 'false') # travis uses default to false
|
|
sh('%s manage.py test geonode.tests.smoke' % prefix)
|
|
call_task('test', options={'prefix': prefix})
|
|
call_task('test_integration')
|
|
call_task('test_integration', options={'name': 'geonode.tests.csw'})
|
|
|
|
# only start if using Geoserver backend
|
|
if 'geonode.geoserver' in INSTALLED_APPS:
|
|
call_task('test_integration',
|
|
options={'name': 'geonode.upload.tests.integration',
|
|
'settings': 'geonode.upload.tests.test_settings'})
|
|
|
|
call_task('test_bdd', options={'local': local})
|
|
sh('flake8 geonode')
|
|
|
|
|
|
@task
|
|
@needs(['stop'])
|
|
def reset():
|
|
"""
|
|
Reset a development environment (Database, GeoServer & Catalogue)
|
|
"""
|
|
_reset()
|
|
|
|
|
|
def _reset():
|
|
from geonode import settings
|
|
sh("rm -rf {path}".format(
|
|
path=os.path.join(settings.PROJECT_ROOT, 'development.db')
|
|
)
|
|
)
|
|
sh("rm -rf haitidata/development.db")
|
|
sh("rm -rf haitidata/uploaded/*")
|
|
_install_data_dir()
|
|
|
|
|
|
@needs(['reset'])
|
|
def reset_hard():
|
|
"""
|
|
Reset a development environment (Database, GeoServer & Catalogue)
|
|
"""
|
|
sh("git clean -dxf")
|
|
|
|
|
|
@task
|
|
@cmdopts([
|
|
('type=', 't', 'Import specific data type ("vector", "raster", "time")'),
|
|
('settings', 's', 'Specify custom DJANGO_SETTINGS_MODULE')
|
|
])
|
|
def setup_data():
|
|
"""
|
|
Import sample data (from gisdata package) into GeoNode
|
|
"""
|
|
import gisdata
|
|
|
|
ctype = options.get('type', None)
|
|
|
|
data_dir = gisdata.GOOD_DATA
|
|
|
|
if ctype in ['vector', 'raster', 'time']:
|
|
data_dir = os.path.join(gisdata.GOOD_DATA, ctype)
|
|
|
|
settings = options.get('settings', '')
|
|
if settings:
|
|
settings = 'DJANGO_SETTINGS_MODULE=%s' % settings
|
|
|
|
sh("%s python -W ignore manage.py importlayers %s -v2" % (settings, data_dir))
|
|
|
|
|
|
@needs(['package'])
|
|
@cmdopts([
|
|
('key=', 'k', 'The GPG key to sign the package'),
|
|
('ppa=', 'p', 'PPA this package should be published to.'),
|
|
])
|
|
def deb(options):
|
|
"""
|
|
Creates debian packages.
|
|
|
|
Example uses:
|
|
paver deb
|
|
paver deb -k 12345
|
|
paver deb -k 12345 -p geonode/testing
|
|
"""
|
|
key = options.get('key', None)
|
|
ppa = options.get('ppa', None)
|
|
|
|
version, simple_version = versions()
|
|
|
|
info('Creating package for GeoNode version %s' % version)
|
|
|
|
# Get rid of any uncommitted changes to debian/changelog
|
|
info('Getting rid of any uncommitted changes in debian/changelog')
|
|
sh('git checkout package/debian/changelog')
|
|
|
|
# Workaround for git-dch bug
|
|
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=594580
|
|
sh('rm -rf %s/.git' % (os.path.realpath('package')))
|
|
sh('ln -s %s %s' % (os.path.realpath('.git'), os.path.realpath('package')))
|
|
|
|
with pushd('package'):
|
|
|
|
# Install requirements
|
|
# sh('sudo apt-get -y install debhelper devscripts git-buildpackage')
|
|
|
|
# sh(('git-dch --spawn-editor=snapshot --git-author --new-version=%s'
|
|
# ' --id-length=6 --ignore-branch --release' % (simple_version)))
|
|
# In case you publish from Ubuntu Xenial (git-dch is removed from upstream)
|
|
# use the following line instead:
|
|
# sh(('gbp dch --spawn-editor=snapshot --git-author --new-version=%s'
|
|
# ' --id-length=6 --ignore-branch --release' % (simple_version)))
|
|
distribution = "bionic"
|
|
# sh(('gbp dch --distribution=%s --force-distribution --spawn-editor=snapshot --git-author --new-version=%s'
|
|
# ' --id-length=6 --ignore-branch --release' % (distribution, simple_version)))
|
|
|
|
deb_changelog = path('debian') / 'changelog'
|
|
for idx, line in enumerate(fileinput.input([deb_changelog], inplace=True)):
|
|
if idx == 0:
|
|
print "geonode (%s) %s; urgency=high" % (simple_version, distribution),
|
|
else:
|
|
print line.replace("urgency=medium", "urgency=high"),
|
|
|
|
# Revert workaround for git-dhc bug
|
|
sh('rm -rf .git')
|
|
|
|
if key is None and ppa is None:
|
|
print("A local installable package")
|
|
sh('debuild -uc -us -A')
|
|
elif key is None and ppa is not None:
|
|
print("A sources package, signed by daemon")
|
|
sh('debuild -S')
|
|
elif key is not None and ppa is None:
|
|
print("A signed installable package")
|
|
sh('debuild -k%s -A' % key)
|
|
elif key is not None and ppa is not None:
|
|
print("A signed, source package")
|
|
sh('debuild -k%s -S' % key)
|
|
|
|
if ppa is not None:
|
|
sh('dput ppa:%s geonode_%s_source.changes' % (ppa, simple_version))
|
|
|
|
|
|
@task
|
|
def publish():
|
|
if 'GPG_KEY_GEONODE' in os.environ:
|
|
key = os.environ['GPG_KEY_GEONODE']
|
|
else:
|
|
print "You need to set the GPG_KEY_GEONODE environment variable"
|
|
return
|
|
|
|
if 'PPA_GEONODE' in os.environ:
|
|
ppa = os.environ['PPA_GEONODE']
|
|
else:
|
|
ppa = None
|
|
|
|
call_task('deb', options={
|
|
'key': key,
|
|
'ppa': ppa,
|
|
# 'ppa': 'geonode/testing',
|
|
# 'ppa': 'geonode/unstable',
|
|
})
|
|
|
|
version, simple_version = versions()
|
|
if ppa:
|
|
sh('git add package/debian/changelog')
|
|
sh('git commit -m "Updated changelog for version %s"' % version)
|
|
sh('git tag -f %s' % version)
|
|
sh('git push origin %s' % version)
|
|
sh('git tag -f debian/%s' % simple_version)
|
|
sh('git push origin debian/%s' % simple_version)
|
|
# sh('git push origin master')
|
|
sh('python setup.py sdist upload -r pypi')
|
|
|
|
|
|
def versions():
|
|
import geonode
|
|
from geonode.version import get_git_changeset
|
|
raw_version = geonode.__version__
|
|
version = geonode.get_version()
|
|
timestamp = get_git_changeset()
|
|
|
|
major, minor, revision, stage, edition = raw_version
|
|
|
|
branch = 'dev'
|
|
|
|
if stage == 'final':
|
|
stage = 'thefinal'
|
|
|
|
if stage == 'unstable':
|
|
tail = '%s%s' % (branch, timestamp)
|
|
else:
|
|
tail = '%s%s' % (stage, edition)
|
|
|
|
simple_version = '%s.%s.%s+%s' % (major, minor, revision, tail)
|
|
return version, simple_version
|
|
|
|
|
|
def kill(arg1, arg2):
|
|
"""Stops a proces that contains arg1 and is filtered by arg2
|
|
"""
|
|
from subprocess import Popen, PIPE
|
|
|
|
# Wait until ready
|
|
t0 = time.time()
|
|
# Wait no more than these many seconds
|
|
time_out = 30
|
|
running = True
|
|
|
|
while running and time.time() - t0 < time_out:
|
|
if os.name == 'nt':
|
|
p = Popen('tasklist | find "%s"' % arg1, shell=True,
|
|
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False)
|
|
else:
|
|
p = Popen('ps aux | grep %s' % arg1, shell=True,
|
|
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
|
|
|
|
lines = p.stdout.readlines()
|
|
|
|
running = False
|
|
for line in lines:
|
|
# this kills all java.exe and python including self in windows
|
|
if ('%s' %
|
|
arg2 in line) or (os.name == 'nt' and '%s' %
|
|
arg1 in line):
|
|
running = True
|
|
|
|
# Get pid
|
|
fields = line.strip().split()
|
|
|
|
info('Stopping %s (process number %s)' % (arg1, fields[1]))
|
|
if os.name == 'nt':
|
|
kill = 'taskkill /F /PID "%s"' % fields[1]
|
|
else:
|
|
kill = 'kill -9 %s 2> /dev/null' % fields[1]
|
|
os.system(kill)
|
|
|
|
# Give it a little more time
|
|
time.sleep(1)
|
|
else:
|
|
pass
|
|
|
|
if running:
|
|
raise Exception('Could not stop %s: '
|
|
'Running processes are\n%s'
|
|
% (arg1, '\n'.join([l.strip() for l in lines])))
|
|
|
|
|
|
def waitfor(url, timeout=300):
|
|
started = False
|
|
for a in xrange(timeout):
|
|
try:
|
|
resp = urllib.urlopen(url)
|
|
except IOError:
|
|
pass
|
|
else:
|
|
if resp.getcode() == 200:
|
|
started = True
|
|
break
|
|
time.sleep(1)
|
|
return started
|
|
|
|
|
|
def _copytree(src, dst, symlinks=False, ignore=None):
|
|
if not os.path.exists(dst):
|
|
os.makedirs(dst)
|
|
for item in os.listdir(src):
|
|
s = os.path.join(src, item)
|
|
d = os.path.join(dst, item)
|
|
if os.path.isdir(s):
|
|
shutil.copytree(s, d, symlinks, ignore)
|
|
elif os.path.isfile(s):
|
|
shutil.copy2(s, d)
|
|
|
|
|
|
def justcopy(origin, target):
|
|
if os.path.isdir(origin):
|
|
shutil.rmtree(target, ignore_errors=True)
|
|
_copytree(origin, target)
|
|
elif os.path.isfile(origin):
|
|
if not os.path.exists(target):
|
|
os.makedirs(target)
|
|
shutil.copy(origin, target)
|
|
|
|
|
|
def str2bool(v):
|
|
if v and len(v) > 0:
|
|
return v.lower() in ("yes", "true", "t", "1")
|
|
else:
|
|
return False
|