mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-16 00:03:12 -04:00
added first draft of geoserver tools nviz is back in grass tools
This commit is contained in:
parent
a4e4999e57
commit
983535fa58
2
.gitignore
vendored
2
.gitignore
vendored
@ -46,3 +46,5 @@ i18n/*.qm
|
|||||||
.project
|
.project
|
||||||
.pydevproject
|
.pydevproject
|
||||||
.idea
|
.idea
|
||||||
|
/python/plugins/sextante/resources_rc.py
|
||||||
|
/python/plugins/sextante/about/ui_aboutdialogbase.py
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
"""
|
"""
|
||||||
|
from sextante.servertools.GeoServerToolsAlgorithmProvider import GeoServerToolsAlgorithmProvider
|
||||||
|
|
||||||
|
|
||||||
__author__ = 'Victor Olaya'
|
__author__ = 'Victor Olaya'
|
||||||
@ -130,6 +131,7 @@ class Sextante:
|
|||||||
Sextante.addProvider(GrassAlgorithmProvider())
|
Sextante.addProvider(GrassAlgorithmProvider())
|
||||||
Sextante.addProvider(ScriptAlgorithmProvider())
|
Sextante.addProvider(ScriptAlgorithmProvider())
|
||||||
Sextante.addProvider(TauDEMAlgorithmProvider())
|
Sextante.addProvider(TauDEMAlgorithmProvider())
|
||||||
|
Sextante.addProvider(GeoServerToolsAlgorithmProvider())
|
||||||
Sextante.modeler.initializeSettings();
|
Sextante.modeler.initializeSettings();
|
||||||
#and initialize
|
#and initialize
|
||||||
SextanteLog.startLogging()
|
SextanteLog.startLogging()
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
DatabaseToolProvider.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
from sextante.core.AlgorithmProvider import AlgorithmProvider
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
import os
|
||||||
|
|
||||||
|
class DatabaseToolsAlgorithmProvider(AlgorithmProvider):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
AlgorithmProvider.__init__(self)
|
||||||
|
self.alglist = []#PostGISSQL(), ImportIntoPostGIS(), CreateTable()]
|
||||||
|
|
||||||
|
def initializeSettings(self):
|
||||||
|
AlgorithmProvider.initializeSettings(self)
|
||||||
|
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
AlgorithmProvider.unload(self)
|
||||||
|
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
return "database"
|
||||||
|
|
||||||
|
def getDescription(self):
|
||||||
|
return "Database tools"
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/postgis.png")
|
||||||
|
|
||||||
|
def _loadAlgorithms(self):
|
||||||
|
self.algs = self.alglist
|
||||||
|
|
||||||
|
def supportsNonFileBasedOutput(self):
|
||||||
|
return True
|
0
python/plugins/sextante/database/__init__.py
Normal file
0
python/plugins/sextante/database/__init__.py
Normal file
@ -16,6 +16,7 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
"""
|
"""
|
||||||
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
|
||||||
__author__ = 'Victor Olaya'
|
__author__ = 'Victor Olaya'
|
||||||
__date__ = 'August 2012'
|
__date__ = 'August 2012'
|
||||||
@ -34,6 +35,7 @@ class translate(GeoAlgorithm):
|
|||||||
|
|
||||||
INPUT = "INPUT"
|
INPUT = "INPUT"
|
||||||
OUTPUT = "OUTPUT"
|
OUTPUT = "OUTPUT"
|
||||||
|
EXTRA = "EXTRA"
|
||||||
|
|
||||||
def getIcon(self):
|
def getIcon(self):
|
||||||
filepath = os.path.dirname(__file__) + "/icons/translate.png"
|
filepath = os.path.dirname(__file__) + "/icons/translate.png"
|
||||||
@ -43,14 +45,18 @@ class translate(GeoAlgorithm):
|
|||||||
self.name = "translate"
|
self.name = "translate"
|
||||||
self.group = "Conversion"
|
self.group = "Conversion"
|
||||||
self.addParameter(ParameterRaster(translate.INPUT, "Input layer", False))
|
self.addParameter(ParameterRaster(translate.INPUT, "Input layer", False))
|
||||||
|
self.addParameter(ParameterString(translate.EXTRA, "Additional creation parameters"))
|
||||||
self.addOutput(OutputRaster(translate.OUTPUT, "Output layer"))
|
self.addOutput(OutputRaster(translate.OUTPUT, "Output layer"))
|
||||||
|
|
||||||
def processAlgorithm(self, progress):
|
def processAlgorithm(self, progress):
|
||||||
commands = ["gdal_translate"]
|
commands = ["gdal_translate"]
|
||||||
commands.append("-of")
|
commands.append("-of")
|
||||||
out = self.getOutputValue(translate.OUTPUT)
|
out = self.getOutputValue(translate.OUTPUT)
|
||||||
|
extra = self.getOutputValue(translate.EXTRA)
|
||||||
commands.append(GdalUtils.getFormatShortNameFromFilename(out))
|
commands.append(GdalUtils.getFormatShortNameFromFilename(out))
|
||||||
|
commands.append(extra)
|
||||||
commands.append(self.getParameterValue(translate.INPUT))
|
commands.append(self.getParameterValue(translate.INPUT))
|
||||||
commands.append(out)
|
commands.append(out)
|
||||||
|
|
||||||
|
|
||||||
GdalUtils.runGdal(commands, progress)
|
GdalUtils.runGdal(commands, progress)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
"""
|
"""
|
||||||
|
from sextante.grass.nviz import nviz
|
||||||
|
|
||||||
__author__ = 'Victor Olaya'
|
__author__ = 'Victor Olaya'
|
||||||
__date__ = 'August 2012'
|
__date__ = 'August 2012'
|
||||||
@ -37,10 +38,6 @@ class GrassAlgorithmProvider(AlgorithmProvider):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
AlgorithmProvider.__init__(self)
|
AlgorithmProvider.__init__(self)
|
||||||
#=======================================================================
|
|
||||||
# self.actions.append(DefineGrassRegionAction())
|
|
||||||
# self.actions.append(DefineGrassRegionFromLayerAction())
|
|
||||||
#=======================================================================
|
|
||||||
self.createAlgsList() #preloading algorithms to speed up
|
self.createAlgsList() #preloading algorithms to speed up
|
||||||
|
|
||||||
def initializeSettings(self):
|
def initializeSettings(self):
|
||||||
@ -76,7 +73,7 @@ class GrassAlgorithmProvider(AlgorithmProvider):
|
|||||||
SextanteLog.addToLog(SextanteLog.LOG_ERROR, "Could not open GRASS algorithm: " + descriptionFile)
|
SextanteLog.addToLog(SextanteLog.LOG_ERROR, "Could not open GRASS algorithm: " + descriptionFile)
|
||||||
except Exception,e:
|
except Exception,e:
|
||||||
SextanteLog.addToLog(SextanteLog.LOG_ERROR, "Could not open GRASS algorithm: " + descriptionFile)
|
SextanteLog.addToLog(SextanteLog.LOG_ERROR, "Could not open GRASS algorithm: " + descriptionFile)
|
||||||
#self.preloadedAlgs.append(nviz())
|
self.preloadedAlgs.append(nviz())
|
||||||
|
|
||||||
def _loadAlgorithms(self):
|
def _loadAlgorithms(self):
|
||||||
self.algs = self.preloadedAlgs
|
self.algs = self.preloadedAlgs
|
||||||
|
@ -54,7 +54,6 @@ from sextante.outputs.OutputHTML import OutputHTML
|
|||||||
from sextante.outputs.OutputRaster import OutputRaster
|
from sextante.outputs.OutputRaster import OutputRaster
|
||||||
from sextante.outputs.OutputTable import OutputTable
|
from sextante.outputs.OutputTable import OutputTable
|
||||||
from sextante.outputs.OutputVector import OutputVector
|
from sextante.outputs.OutputVector import OutputVector
|
||||||
from sextante.outputs.OutputNumber import OutputNumber
|
|
||||||
from sextante.parameters.ParameterString import ParameterString
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
|
||||||
class ParametersPanel(QtGui.QWidget):
|
class ParametersPanel(QtGui.QWidget):
|
||||||
|
BIN
python/plugins/sextante/images/geoserver.png
Normal file
BIN
python/plugins/sextante/images/geoserver.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 744 B |
@ -16,6 +16,7 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
"""
|
"""
|
||||||
|
from sextante.outputs.OutputString import OutputString
|
||||||
|
|
||||||
__author__ = 'Victor Olaya'
|
__author__ = 'Victor Olaya'
|
||||||
__date__ = 'August 2012'
|
__date__ = 'August 2012'
|
||||||
@ -436,6 +437,8 @@ class ModelerAlgorithm(GeoAlgorithm):
|
|||||||
return "output html"
|
return "output html"
|
||||||
elif isinstance(out, OutputNumber):
|
elif isinstance(out, OutputNumber):
|
||||||
return "output number"
|
return "output number"
|
||||||
|
elif isinstance(out, OutputString):
|
||||||
|
return "output string"
|
||||||
|
|
||||||
|
|
||||||
def getAsPythonCode(self):
|
def getAsPythonCode(self):
|
||||||
|
@ -64,10 +64,14 @@ class ModelerArrowItem(QtGui.QGraphicsLineItem):
|
|||||||
return self.myEndItem
|
return self.myEndItem
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
extra = (self.pen().width() + 20) / 2.0
|
#this is a quick fix to avoid arrows not being drawn
|
||||||
p1 = self.line().p1()
|
return QtCore.QRectF(0, 0, 4000,4000)
|
||||||
p2 = self.line().p2()
|
#=======================================================================
|
||||||
return QtCore.QRectF(p1, QtCore.QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted(-extra, -extra, extra, extra)
|
# extra = (self.pen().width() + 20) / 2.0
|
||||||
|
# p1 = self.line().p1()
|
||||||
|
# p2 = self.line().p2()
|
||||||
|
# return QtCore.QRectF(p1, QtCore.QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted(-extra, -extra, extra, extra)
|
||||||
|
#=======================================================================
|
||||||
|
|
||||||
def shape(self):
|
def shape(self):
|
||||||
path = super(ModelerArrowItem, self).shape()
|
path = super(ModelerArrowItem, self).shape()
|
||||||
@ -123,3 +127,4 @@ class ModelerArrowItem(QtGui.QGraphicsLineItem):
|
|||||||
|
|
||||||
painter.drawLine(line)
|
painter.drawLine(line)
|
||||||
painter.drawPolygon(self.arrowHead)
|
painter.drawPolygon(self.arrowHead)
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
***************************************************************************
|
***************************************************************************
|
||||||
"""
|
"""
|
||||||
from sextante.parameters.ParameterCrs import ParameterCrs
|
from sextante.parameters.ParameterCrs import ParameterCrs
|
||||||
|
from sextante.outputs.OutputString import OutputString
|
||||||
|
|
||||||
__author__ = 'Victor Olaya'
|
__author__ = 'Victor Olaya'
|
||||||
__date__ = 'August 2012'
|
__date__ = 'August 2012'
|
||||||
@ -317,6 +318,20 @@ class ModelerParametersDialog(QtGui.QDialog):
|
|||||||
for param in params:
|
for param in params:
|
||||||
if isinstance(param, ParameterString):
|
if isinstance(param, ParameterString):
|
||||||
strings.append(AlgorithmAndParameter(AlgorithmAndParameter.PARENT_MODEL_ALGORITHM, param.name, "", param.description))
|
strings.append(AlgorithmAndParameter(AlgorithmAndParameter.PARENT_MODEL_ALGORITHM, param.name, "", param.description))
|
||||||
|
|
||||||
|
if self.algIndex is None:
|
||||||
|
dependent = []
|
||||||
|
else:
|
||||||
|
dependent = self.model.getDependentAlgorithms(self.algIndex)
|
||||||
|
dependent.append(self.algIndex)
|
||||||
|
|
||||||
|
i=0
|
||||||
|
for alg in self.model.algs:
|
||||||
|
if i not in dependent:
|
||||||
|
for out in alg.outputs:
|
||||||
|
if isinstance(out, OutputString):
|
||||||
|
strings.append(AlgorithmAndParameter(i, out.name, alg.name, out.description))
|
||||||
|
i+=1
|
||||||
return strings
|
return strings
|
||||||
|
|
||||||
def getTableFields(self):
|
def getTableFields(self):
|
||||||
|
@ -37,6 +37,7 @@ class ModelerScene(QtGui.QGraphicsScene):
|
|||||||
super(ModelerScene, self).__init__(parent)
|
super(ModelerScene, self).__init__(parent)
|
||||||
self.paramItems = []
|
self.paramItems = []
|
||||||
self.algItems = []
|
self.algItems = []
|
||||||
|
self.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex);
|
||||||
|
|
||||||
def getParameterPositions(self):
|
def getParameterPositions(self):
|
||||||
pos = []
|
pos = []
|
||||||
@ -118,7 +119,6 @@ class ModelerScene(QtGui.QGraphicsScene):
|
|||||||
self.addItem(arrow)
|
self.addItem(arrow)
|
||||||
iAlg+=1
|
iAlg+=1
|
||||||
|
|
||||||
|
|
||||||
def mousePressEvent(self, mouseEvent):
|
def mousePressEvent(self, mouseEvent):
|
||||||
if (mouseEvent.button() != QtCore.Qt.LeftButton):
|
if (mouseEvent.button() != QtCore.Qt.LeftButton):
|
||||||
return
|
return
|
||||||
|
@ -24,7 +24,6 @@ __copyright__ = '(C) 2012, Victor Olaya'
|
|||||||
__revision__ = '$Format:%H$'
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from sextante.core.SextanteUtils import SextanteUtils
|
|
||||||
from sextante.core.SextanteUtils import mkdir
|
from sextante.core.SextanteUtils import mkdir
|
||||||
from sextante.core.SextanteConfig import SextanteConfig
|
from sextante.core.SextanteConfig import SextanteConfig
|
||||||
|
|
||||||
@ -37,8 +36,7 @@ class ModelerUtils:
|
|||||||
def modelsFolder():
|
def modelsFolder():
|
||||||
folder = SextanteConfig.getSetting(ModelerUtils.MODELS_FOLDER)
|
folder = SextanteConfig.getSetting(ModelerUtils.MODELS_FOLDER)
|
||||||
if folder == None:
|
if folder == None:
|
||||||
#folder = os.path.join(os.path.dirname(__file__), "models")
|
folder = os.path.join(os.path.dirname(__file__), "models")
|
||||||
folder = SextanteUtils.userFolder() + os.sep + "models"
|
|
||||||
mkdir(folder)
|
mkdir(folder)
|
||||||
|
|
||||||
return folder
|
return folder
|
||||||
|
75
python/plugins/sextante/modeler/models/watersheds.model
Normal file
75
python/plugins/sextante/modeler/models/watersheds.model
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
NAME:Watersheds from DEM
|
||||||
|
GROUP:[Sample models]
|
||||||
|
PARAMETER:ParameterRaster|RASTERLAYER_DEM|DEM|False
|
||||||
|
458.0,50.0
|
||||||
|
PARAMETER:ParameterNumber|NUMBER_INITIATIONTHRESHOLD|Initiation Threshold|None|None|10000000.0
|
||||||
|
257.0,403.0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_INIT_VALUE_1===10000000
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_SPLIT_3===0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_Method_0===0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_INIT_METHOD_1===2
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_CALC_METHOD_4===0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_CLASS_ID_3===0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_STEP_0===1
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_MINLEN_1===10
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_DOLINEAR _0===True
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_MINSIZE_2===0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_CLASS_ALL_3===1
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_LINEARTHRS_0===500.0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_CONVERGENCE_0===1.0
|
||||||
|
VALUE:HARDCODEDPARAMVALUE_DIV_CELLS_1===10
|
||||||
|
ALGORITHM:saga:catchmentarea(parallel)
|
||||||
|
260.0,172.0
|
||||||
|
-1|RASTERLAYER_DEM
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
-1|HARDCODEDPARAMVALUE_STEP_0
|
||||||
|
-1|HARDCODEDPARAMVALUE_Method_0
|
||||||
|
-1|HARDCODEDPARAMVALUE_DOLINEAR _0
|
||||||
|
-1|HARDCODEDPARAMVALUE_LINEARTHRS_0
|
||||||
|
None
|
||||||
|
None
|
||||||
|
-1|HARDCODEDPARAMVALUE_CONVERGENCE_0
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
ALGORITHM:saga:channelnetwork
|
||||||
|
447.0,291.0
|
||||||
|
-1|RASTERLAYER_DEM
|
||||||
|
None
|
||||||
|
0|CAREA
|
||||||
|
-1|HARDCODEDPARAMVALUE_INIT_METHOD_1
|
||||||
|
-1|NUMBER_INITIATIONTHRESHOLD
|
||||||
|
None
|
||||||
|
-1|HARDCODEDPARAMVALUE_DIV_CELLS_1
|
||||||
|
None
|
||||||
|
-1|HARDCODEDPARAMVALUE_MINLEN_1
|
||||||
|
None
|
||||||
|
None
|
||||||
|
None
|
||||||
|
ALGORITHM:saga:watershedbasins
|
||||||
|
730.0,182.0
|
||||||
|
-1|RASTERLAYER_DEM
|
||||||
|
1|CHNLNTWRK
|
||||||
|
None
|
||||||
|
-1|HARDCODEDPARAMVALUE_MINSIZE_2
|
||||||
|
None
|
||||||
|
ALGORITHM:saga:vectorisinggridclasses
|
||||||
|
864.0,330.0
|
||||||
|
2|BASINS
|
||||||
|
-1|HARDCODEDPARAMVALUE_CLASS_ALL_3
|
||||||
|
-1|HARDCODEDPARAMVALUE_CLASS_ID_3
|
||||||
|
-1|HARDCODEDPARAMVALUE_SPLIT_3
|
||||||
|
None
|
||||||
|
ALGORITHM:ftools:export/addgeometrycolumns
|
||||||
|
655.0,442.0
|
||||||
|
3|POLYGONS
|
||||||
|
-1|HARDCODEDPARAMVALUE_CALC_METHOD_4
|
||||||
|
Watersheds
|
@ -16,7 +16,6 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = 'Victor Olaya'
|
__author__ = 'Victor Olaya'
|
||||||
__date__ = 'August 2012'
|
__date__ = 'August 2012'
|
||||||
__copyright__ = '(C) 2012, Victor Olaya'
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
@ -29,12 +28,13 @@ from sextante.outputs.OutputTable import OutputTable
|
|||||||
from sextante.outputs.OutputVector import OutputVector
|
from sextante.outputs.OutputVector import OutputVector
|
||||||
from sextante.outputs.OutputNumber import OutputNumber
|
from sextante.outputs.OutputNumber import OutputNumber
|
||||||
from sextante.outputs.OutputFile import OutputFile
|
from sextante.outputs.OutputFile import OutputFile
|
||||||
|
from sextante.outputs.OutputString import OutputString
|
||||||
|
|
||||||
class OutputFactory():
|
class OutputFactory():
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getFromString(s):
|
def getFromString(s):
|
||||||
classes = [OutputRaster, OutputVector, OutputTable, OutputHTML, OutputNumber, OutputFile]
|
classes = [OutputRaster, OutputVector, OutputTable, OutputHTML, OutputNumber, OutputFile, OutputString]
|
||||||
for clazz in classes:
|
for clazz in classes:
|
||||||
if s.startswith(clazz().outputTypeName()):
|
if s.startswith(clazz().outputTypeName()):
|
||||||
tokens = s[len(clazz().outputTypeName())+1:].split("|")
|
tokens = s[len(clazz().outputTypeName())+1:].split("|")
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
__init__.py
|
OutputString.py
|
||||||
---------------------
|
---------------------
|
||||||
Date : August 2012
|
Date : October 2012
|
||||||
Copyright : (C) 2012 by Tim Sutton
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
Email : tim at linfiniti dot com
|
Email : volayaf at gmail dot com
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
@ -17,22 +17,18 @@
|
|||||||
***************************************************************************
|
***************************************************************************
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = 'Tim Sutton'
|
__author__ = 'Victor Olaya'
|
||||||
__date__ = 'August 2012'
|
__date__ = 'August 2012'
|
||||||
__copyright__ = '(C) 2012, Tim Sutton'
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
# This will get replaced with a git SHA1 when you do a git archive
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
__revision__ = '$Format:%H$'
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
def name():
|
from sextante.outputs.Output import Output
|
||||||
return "SEXTANTE example provider"
|
|
||||||
def description():
|
class OutputString(Output):
|
||||||
return "An example plugin that adds algorithms to SEXTANTE. Mainly created to guide developers in the process of creating plugins that add new capabilities to SEXTANTE"
|
|
||||||
def version():
|
def __init__(self, name="", description=""):
|
||||||
return "Version 1.0"
|
self.name = name
|
||||||
def icon():
|
self.description = description
|
||||||
return "icon.png"
|
self.value = None
|
||||||
def qgisMinimumVersion():
|
self.hidden = True
|
||||||
return "1.0"
|
|
||||||
def classFactory(iface):
|
|
||||||
from sextanteexampleprovider.SextanteExampleProviderPlugin import SextanteExampleProviderPlugin
|
|
||||||
return SextanteExampleProviderPlugin()
|
|
@ -36,7 +36,7 @@ class PymorphAlgorithmProvider(AlgorithmProvider):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
AlgorithmProvider.__init__(self)
|
AlgorithmProvider.__init__(self)
|
||||||
#self.readAlgNames()
|
self.activate = False
|
||||||
self.createAlgsList()
|
self.createAlgsList()
|
||||||
|
|
||||||
def scriptsFolder(self):
|
def scriptsFolder(self):
|
||||||
|
@ -91,6 +91,8 @@ class EditRScriptDialog(QtGui.QDialog):
|
|||||||
self.filename = QtGui.QFileDialog.getSaveFileName(self, "Save Script", RUtils.RScriptsFolder(), "SEXTANTE R script (*.rsx)")
|
self.filename = QtGui.QFileDialog.getSaveFileName(self, "Save Script", RUtils.RScriptsFolder(), "SEXTANTE R script (*.rsx)")
|
||||||
|
|
||||||
if self.filename:
|
if self.filename:
|
||||||
|
if not self.filename.endswith(".rsx"):
|
||||||
|
self.filename += ".rsx"
|
||||||
text = str(self.text.toPlainText())
|
text = str(self.text.toPlainText())
|
||||||
if self.alg is not None:
|
if self.alg is not None:
|
||||||
self.alg.script = text
|
self.alg.script = text
|
||||||
|
@ -91,6 +91,8 @@ class EditScriptDialog(QtGui.QDialog):
|
|||||||
self.filename = QtGui.QFileDialog.getSaveFileName(self, "Save Script", ScriptUtils.scriptsFolder(), "Python scripts (*.py)")
|
self.filename = QtGui.QFileDialog.getSaveFileName(self, "Save Script", ScriptUtils.scriptsFolder(), "Python scripts (*.py)")
|
||||||
|
|
||||||
if self.filename:
|
if self.filename:
|
||||||
|
if not self.filename.endswith(".py"):
|
||||||
|
self.filename += ".py"
|
||||||
text = str(self.text.toPlainText())
|
text = str(self.text.toPlainText())
|
||||||
if self.alg is not None:
|
if self.alg is not None:
|
||||||
self.alg.script = text
|
self.alg.script = text
|
||||||
|
61
python/plugins/sextante/servertools/CreateMosaicDatastore.py
Normal file
61
python/plugins/sextante/servertools/CreateMosaicDatastore.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#===============================================================================
|
||||||
|
# # -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# """
|
||||||
|
# ***************************************************************************
|
||||||
|
# CreateMosaicDatastore.py
|
||||||
|
# ---------------------
|
||||||
|
# Date : October 2012
|
||||||
|
# Copyright : (C) 2012 by Victor Olaya
|
||||||
|
# Email : volayaf at gmail dot com
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * 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 2 of the License, or *
|
||||||
|
# * (at your option) any later version. *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
# """
|
||||||
|
# from sextante.core.LayerExporter import LayerExporter
|
||||||
|
# from sextante.parameters.ParameterString import ParameterString
|
||||||
|
# from sextante.servertools.GeoServerToolsAlgorithm import GeoServerToolsAlgorithm
|
||||||
|
#
|
||||||
|
# __author__ = 'Victor Olaya'
|
||||||
|
# __date__ = 'October 2012'
|
||||||
|
# __copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# # This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
# __revision__ = '$Format:%H$'
|
||||||
|
#
|
||||||
|
# from qgis.core import *
|
||||||
|
# from sextante.parameters.ParameterVector import ParameterVector
|
||||||
|
# from sextante.core.QGisLayers import QGisLayers
|
||||||
|
# import os
|
||||||
|
#
|
||||||
|
# class CreateMosaicDatastore(GeoServerToolsAlgorithm):
|
||||||
|
#
|
||||||
|
# INPUT = "INPUT"
|
||||||
|
# WORKSPACE = "WORKSPACE"
|
||||||
|
#
|
||||||
|
# def processAlgorithm(self, progress):
|
||||||
|
# self.createCatalog()
|
||||||
|
# input = self.getParameterValue(self.INPUT)
|
||||||
|
# workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||||
|
# connection = {
|
||||||
|
# 'shp': basepathname + '.shp',
|
||||||
|
# 'shx': basepathname + '.shx',
|
||||||
|
# 'dbf': basepathname + '.dbf',
|
||||||
|
# 'prj': basepathname + '.prj'
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# workspace = self.catalog.get_workspace(workspaceName)
|
||||||
|
# self.catalog.create_featurestore(basefilename, connection, workspace)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def defineCharacteristics(self):
|
||||||
|
# self.addcaddBaseParameters()
|
||||||
|
# self.name = "Import into GeoServer"
|
||||||
|
# self.group = "GeoServer management tools"
|
||||||
|
# self.addParameter(ParameterVector(self.INPUT, "Layer to import", ParameterVector.VECTOR_TYPE_ANY))
|
||||||
|
# self.addParameter(ParameterString(self.WORKSPACE, "Workspace"))
|
||||||
|
#===============================================================================
|
56
python/plugins/sextante/servertools/CreateWorkspace.py
Normal file
56
python/plugins/sextante/servertools/CreateWorkspace.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
CreateWorkspace.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
from sextante.servertools.GeoServerToolsAlgorithm import GeoServerToolsAlgorithm
|
||||||
|
from sextante.outputs.OutputString import OutputString
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
import os
|
||||||
|
from qgis.core import *
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
|
||||||
|
class CreateWorkspace(GeoServerToolsAlgorithm):
|
||||||
|
|
||||||
|
WORKSPACE = "WORKSPACE"
|
||||||
|
WORKSPACEURI = "WORKSPACEURI"
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/geoserver.png")
|
||||||
|
|
||||||
|
def processAlgorithm(self, progress):
|
||||||
|
self.createCatalog()
|
||||||
|
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||||
|
workspaceUri = self.getParameterValue(self.WORKSPACEURI)
|
||||||
|
self.catalog.create_workspace(workspaceName, workspaceUri)
|
||||||
|
|
||||||
|
|
||||||
|
def defineCharacteristics(self):
|
||||||
|
self.addBaseParameters()
|
||||||
|
self.name = "Create workspace"
|
||||||
|
self.group = "GeoServer management tools"
|
||||||
|
self.addParameter(ParameterString(self.WORKSPACE, "Workspace"))
|
||||||
|
self.addParameter(ParameterString(self.WORKSPACEURI, "Workspace URI"))
|
||||||
|
self.addOutput(OutputString(self.WORKSPACE, "Workspace"))
|
||||||
|
|
||||||
|
|
56
python/plugins/sextante/servertools/DeleteDatastore.py
Normal file
56
python/plugins/sextante/servertools/DeleteDatastore.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
DeleteDatastore.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
from sextante.servertools.GeoServerToolsAlgorithm import GeoServerToolsAlgorithm
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
import os
|
||||||
|
from qgis.core import *
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
|
||||||
|
class DeleteDatastore(GeoServerToolsAlgorithm):
|
||||||
|
|
||||||
|
DATASTORE = "DATASTORE"
|
||||||
|
WORKSPACE = "WORKSPACE"
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/geoserver.png")
|
||||||
|
|
||||||
|
def processAlgorithm(self, progress):
|
||||||
|
self.createCatalog()
|
||||||
|
datastoreName = self.getParameterValue(self.DATASTORE)
|
||||||
|
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||||
|
ds = self.catalog.get_store(datastoreName, workspaceName)
|
||||||
|
self.catalog.delete(ds, recurse=True)
|
||||||
|
|
||||||
|
|
||||||
|
def defineCharacteristics(self):
|
||||||
|
self.addBaseParameters()
|
||||||
|
self.name = "Delete datastore"
|
||||||
|
self.group = "GeoServer management tools"
|
||||||
|
self.addParameter(ParameterString(self.DATASTORE, "Datastore name"))
|
||||||
|
self.addParameter(ParameterString(self.WORKSPACE, "Workspace"))
|
||||||
|
|
||||||
|
|
||||||
|
|
53
python/plugins/sextante/servertools/DeleteWorkspace.py
Normal file
53
python/plugins/sextante/servertools/DeleteWorkspace.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
DeleteWorkspace.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
from sextante.servertools.GeoServerToolsAlgorithm import GeoServerToolsAlgorithm
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
import os
|
||||||
|
from qgis.core import *
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
|
||||||
|
class DeleteWorkspace(GeoServerToolsAlgorithm):
|
||||||
|
|
||||||
|
WORKSPACE = "WORKSPACE"
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/geoserver.png")
|
||||||
|
|
||||||
|
def processAlgorithm(self, progress):
|
||||||
|
self.createCatalog()
|
||||||
|
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||||
|
ws = self.catalog.get_workspace(workspaceName)
|
||||||
|
self.catalog.delete(ws)
|
||||||
|
|
||||||
|
|
||||||
|
def defineCharacteristics(self):
|
||||||
|
self.addBaseParameters()
|
||||||
|
self.name = "Delete workspace"
|
||||||
|
self.group = "GeoServer management tools"
|
||||||
|
self.addParameter(ParameterString(self.WORKSPACE, "Workspace"))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
GeoserverToolsAlgorithm.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
from sextante.servertools.geoserver.catalog import Catalog
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
import os
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
from sextante.core.GeoAlgorithm import GeoAlgorithm
|
||||||
|
|
||||||
|
class GeoServerToolsAlgorithm(GeoAlgorithm):
|
||||||
|
|
||||||
|
URL = "URL"
|
||||||
|
USER = "USER"
|
||||||
|
PASSWORD = "PASSWORD"
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/geoserver.png")
|
||||||
|
|
||||||
|
def addBaseParameters(self):
|
||||||
|
self.addParameter(ParameterString(self.URL, "URL", "http://localhost:8080/geoserver/rest"))
|
||||||
|
self.addParameter(ParameterString(self.USER, "User", "admin"))
|
||||||
|
self.addParameter(ParameterString(self.PASSWORD, "Password", "geoserver"))
|
||||||
|
|
||||||
|
def createCatalog(self):
|
||||||
|
url = self.getParameterValue(self.URL)
|
||||||
|
user = self.getParameterValue(self.USER)
|
||||||
|
password = self.getParameterValue(self.PASSWORD)
|
||||||
|
self.catalog = Catalog(url, user, password)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
GeoServerToolsAlgorithmProvider.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
from sextante.servertools.CreateWorkspace import CreateWorkspace
|
||||||
|
from sextante.servertools.ImportVectorIntoGeoServer import ImportVectorIntoGeoServer
|
||||||
|
from sextante.servertools.ImportRasterIntoGeoServer import ImportRasterIntoGeoServer
|
||||||
|
from sextante.servertools.DeleteWorkspace import DeleteWorkspace
|
||||||
|
from sextante.servertools.DeleteDatastore import DeleteDatastore
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
from sextante.core.AlgorithmProvider import AlgorithmProvider
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
import os
|
||||||
|
|
||||||
|
class GeoServerToolsAlgorithmProvider(AlgorithmProvider):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
AlgorithmProvider.__init__(self)
|
||||||
|
self.alglist = [ImportVectorIntoGeoServer(), ImportRasterIntoGeoServer(),
|
||||||
|
CreateWorkspace(), DeleteWorkspace(), DeleteDatastore()]#, CreateMosaicGeoserver(), StyleGeoserverLayer(), TruncateSeedGWC()]
|
||||||
|
|
||||||
|
def initializeSettings(self):
|
||||||
|
AlgorithmProvider.initializeSettings(self)
|
||||||
|
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
AlgorithmProvider.unload(self)
|
||||||
|
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
return "geoserver"
|
||||||
|
|
||||||
|
def getDescription(self):
|
||||||
|
return "Geoserver management tools"
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/geoserver.png")
|
||||||
|
|
||||||
|
def _loadAlgorithms(self):
|
||||||
|
self.algs = self.alglist
|
||||||
|
|
||||||
|
def supportsNonFileBasedOutput(self):
|
||||||
|
return True
|
@ -0,0 +1,62 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
ImportVectorIntoGeoServer.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
from sextante.core.LayerExporter import LayerExporter
|
||||||
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
from sextante.servertools.GeoServerToolsAlgorithm import GeoServerToolsAlgorithm
|
||||||
|
from sextante.parameters.ParameterRaster import ParameterRaster
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
from qgis.core import *
|
||||||
|
|
||||||
|
class ImportRasterIntoGeoServer(GeoServerToolsAlgorithm):
|
||||||
|
|
||||||
|
INPUT = "INPUT"
|
||||||
|
WORKSPACE = "WORKSPACE"
|
||||||
|
NAME = "NAME"
|
||||||
|
|
||||||
|
|
||||||
|
def exportRasterLayer(self, inputFilename):
|
||||||
|
return inputFilename
|
||||||
|
|
||||||
|
|
||||||
|
def processAlgorithm(self, progress):
|
||||||
|
self.createCatalog()
|
||||||
|
inputFilename = self.getParameterValue(self.INPUT)
|
||||||
|
name = self.getParameterValue(self.NAME)
|
||||||
|
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||||
|
filename = self.exportRasterLayer(inputFilename)
|
||||||
|
workspace = self.catalog.get_workspace(workspaceName)
|
||||||
|
ds = self.catalog.create_coveragestore2(name, workspace)
|
||||||
|
ds.data_url = "file:" + filename;
|
||||||
|
self.catalog.save(ds)
|
||||||
|
|
||||||
|
|
||||||
|
def defineCharacteristics(self):
|
||||||
|
self.addBaseParameters()
|
||||||
|
self.name = "Import raster into GeoServer"
|
||||||
|
self.group = "GeoServer management tools"
|
||||||
|
self.addParameter(ParameterRaster(self.INPUT, "Layer to import"))
|
||||||
|
self.addParameter(ParameterString(self.WORKSPACE, "Workspace"))
|
||||||
|
self.addParameter(ParameterString(self.NAME, "Store name"))
|
||||||
|
|
@ -0,0 +1,64 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
ImportVectorIntoGeoServer.py
|
||||||
|
---------------------
|
||||||
|
Date : October 2012
|
||||||
|
Copyright : (C) 2012 by Victor Olaya
|
||||||
|
Email : volayaf at gmail dot com
|
||||||
|
***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
from sextante.core.LayerExporter import LayerExporter
|
||||||
|
from sextante.parameters.ParameterString import ParameterString
|
||||||
|
from sextante.servertools.GeoServerToolsAlgorithm import GeoServerToolsAlgorithm
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'October 2012'
|
||||||
|
__copyright__ = '(C) 2012, Victor Olaya'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
from qgis.core import *
|
||||||
|
from sextante.parameters.ParameterVector import ParameterVector
|
||||||
|
from sextante.core.QGisLayers import QGisLayers
|
||||||
|
import os
|
||||||
|
|
||||||
|
class ImportVectorIntoGeoServer(GeoServerToolsAlgorithm):
|
||||||
|
|
||||||
|
INPUT = "INPUT"
|
||||||
|
WORKSPACE = "WORKSPACE"
|
||||||
|
|
||||||
|
def processAlgorithm(self, progress):
|
||||||
|
self.createCatalog()
|
||||||
|
inputFilename = self.getParameterValue(self.INPUT)
|
||||||
|
layer = QGisLayers.getObjectFromUri(inputFilename)
|
||||||
|
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||||
|
filename = LayerExporter.exportVectorLayer(layer)
|
||||||
|
basefilename = os.path.basename(filename)
|
||||||
|
basepathname = os.path.dirname(filename) + os.sep + basefilename[:basefilename.find('.')]
|
||||||
|
connection = {
|
||||||
|
'shp': basepathname + '.shp',
|
||||||
|
'shx': basepathname + '.shx',
|
||||||
|
'dbf': basepathname + '.dbf',
|
||||||
|
'prj': basepathname + '.prj'
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace = self.catalog.get_workspace(workspaceName)
|
||||||
|
self.catalog.create_featurestore(basefilename, connection, workspace)
|
||||||
|
|
||||||
|
|
||||||
|
def defineCharacteristics(self):
|
||||||
|
self.addBaseParameters()
|
||||||
|
self.name = "Import vector into GeoServer"
|
||||||
|
self.group = "GeoServer management tools"
|
||||||
|
self.addParameter(ParameterVector(self.INPUT, "Layer to import", ParameterVector.VECTOR_TYPE_ANY))
|
||||||
|
self.addParameter(ParameterString(self.WORKSPACE, "Workspace"))
|
||||||
|
|
0
python/plugins/sextante/servertools/__init__.py
Normal file
0
python/plugins/sextante/servertools/__init__.py
Normal file
504
python/plugins/sextante/servertools/geoserver/catalog.py
Normal file
504
python/plugins/sextante/servertools/geoserver/catalog.py
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
import logging
|
||||||
|
from sextante.servertools.geoserver.layer import Layer
|
||||||
|
from sextante.servertools.geoserver.store import coveragestore_from_index, datastore_from_index, \
|
||||||
|
UnsavedDataStore, UnsavedCoverageStore
|
||||||
|
from sextante.servertools.geoserver.style import Style
|
||||||
|
from sextante.servertools.geoserver.support import prepare_upload_bundle, url
|
||||||
|
from sextante.servertools.geoserver.layergroup import LayerGroup, UnsavedLayerGroup
|
||||||
|
from sextante.servertools.geoserver.workspace import workspace_from_index, Workspace
|
||||||
|
from os import unlink
|
||||||
|
from xml.etree.ElementTree import XML
|
||||||
|
from xml.parsers.expat import ExpatError
|
||||||
|
from urlparse import urlparse
|
||||||
|
from sextante.servertools import httplib2
|
||||||
|
|
||||||
|
logger = logging.getLogger("gsconfig.catalog")
|
||||||
|
|
||||||
|
class UploadError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ConflictingDataError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AmbiguousRequestError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class FailedRequestError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _name(named):
|
||||||
|
"""Get the name out of an object. This varies based on the type of the input:
|
||||||
|
* the "name" of a string is itself
|
||||||
|
* the "name" of None is itself
|
||||||
|
* the "name" of an object with a property named name is that property -
|
||||||
|
as long as it's a string
|
||||||
|
* otherwise, we raise a ValueError
|
||||||
|
"""
|
||||||
|
if isinstance(named, basestring) or named is None:
|
||||||
|
return named
|
||||||
|
elif hasattr(named, 'name') and isinstance(named.name, basestring):
|
||||||
|
return named.name
|
||||||
|
else:
|
||||||
|
raise ValueError("Can't interpret %s as a name or a configuration object" % named)
|
||||||
|
|
||||||
|
class Catalog(object):
|
||||||
|
"""
|
||||||
|
The GeoServer catalog represents all of the information in the GeoServer
|
||||||
|
configuration. This includes:
|
||||||
|
- Stores of geospatial data
|
||||||
|
- Resources, or individual coherent datasets within stores
|
||||||
|
- Styles for resources
|
||||||
|
- Layers, which combine styles with resources to create a visible map layer
|
||||||
|
- LayerGroups, which alias one or more layers for convenience
|
||||||
|
- Workspaces, which provide logical grouping of Stores
|
||||||
|
- Maps, which provide a set of OWS services with a subset of the server's
|
||||||
|
Layers
|
||||||
|
- Namespaces, which provide unique identifiers for resources
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, service_url, username="admin", password="geoserver", disable_ssl_certificate_validation=False):
|
||||||
|
self.service_url = service_url
|
||||||
|
if self.service_url.endswith("/"):
|
||||||
|
self.service_url = self.service_url.strip("/")
|
||||||
|
self.http = httplib2.Http(
|
||||||
|
disable_ssl_certificate_validation=disable_ssl_certificate_validation)
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.http.add_credentials(self.username, self.password)
|
||||||
|
netloc = urlparse(service_url).netloc
|
||||||
|
self.http.authorizations.append(
|
||||||
|
httplib2.BasicAuthentication(
|
||||||
|
(username, password),
|
||||||
|
netloc,
|
||||||
|
service_url,
|
||||||
|
{},
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
self.http
|
||||||
|
))
|
||||||
|
self._cache = dict()
|
||||||
|
|
||||||
|
def delete(self, config_object, purge=False, recurse=False):
|
||||||
|
"""
|
||||||
|
send a delete request
|
||||||
|
XXX [more here]
|
||||||
|
"""
|
||||||
|
rest_url = config_object.href
|
||||||
|
|
||||||
|
#params aren't supported fully in httplib2 yet, so:
|
||||||
|
params = []
|
||||||
|
|
||||||
|
# purge deletes the SLD from disk when a style is deleted
|
||||||
|
if purge:
|
||||||
|
params.append("purge=true")
|
||||||
|
|
||||||
|
# recurse deletes the resource when a layer is deleted.
|
||||||
|
if recurse:
|
||||||
|
params.append("recurse=true")
|
||||||
|
|
||||||
|
if params:
|
||||||
|
rest_url = rest_url + "?" + "&".join(params)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-type": "application/xml",
|
||||||
|
"Accept": "application/xml"
|
||||||
|
}
|
||||||
|
response, content = self.http.request(rest_url, "DELETE", headers=headers)
|
||||||
|
self._cache.clear()
|
||||||
|
|
||||||
|
if response.status == 200:
|
||||||
|
return (response, content)
|
||||||
|
else:
|
||||||
|
raise FailedRequestError("Tried to make a DELETE request to %s but got a %d status code: \n%s" % (rest_url, response.status, content))
|
||||||
|
|
||||||
|
def get_xml(self, rest_url):
|
||||||
|
logger.debug("GET %s", rest_url)
|
||||||
|
|
||||||
|
cached_response = self._cache.get(rest_url)
|
||||||
|
|
||||||
|
def is_valid(cached_response):
|
||||||
|
return cached_response is not None and datetime.now() - cached_response[0] < timedelta(seconds=5)
|
||||||
|
|
||||||
|
def parse_or_raise(xml):
|
||||||
|
try:
|
||||||
|
return XML(xml)
|
||||||
|
except (ExpatError, SyntaxError), e:
|
||||||
|
msg = "GeoServer gave non-XML response for [GET %s]: %s"
|
||||||
|
msg = msg % (rest_url, xml)
|
||||||
|
raise Exception(msg, e)
|
||||||
|
|
||||||
|
if is_valid(cached_response):
|
||||||
|
raw_text = cached_response[1]
|
||||||
|
return parse_or_raise(raw_text)
|
||||||
|
else:
|
||||||
|
response, content = self.http.request(rest_url)
|
||||||
|
if response.status == 200:
|
||||||
|
self._cache[rest_url] = (datetime.now(), content)
|
||||||
|
return parse_or_raise(content)
|
||||||
|
else:
|
||||||
|
raise FailedRequestError("Tried to make a GET request to %s but got a %d status code: \n%s" % (url, response.status, content))
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
reload_url = url(self.service_url, ['reload'])
|
||||||
|
response = self.http.request(reload_url, "POST")
|
||||||
|
self._cache.clear()
|
||||||
|
return response
|
||||||
|
|
||||||
|
def save(self, obj):
|
||||||
|
"""
|
||||||
|
saves an object to the REST service
|
||||||
|
|
||||||
|
gets the object's REST location and the XML from the object,
|
||||||
|
then POSTS the request.
|
||||||
|
"""
|
||||||
|
rest_url = obj.href
|
||||||
|
message = obj.message()
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-type": "application/xml",
|
||||||
|
"Accept": "application/xml"
|
||||||
|
}
|
||||||
|
logger.debug("%s %s", obj.save_method, obj.href)
|
||||||
|
response = self.http.request(rest_url, obj.save_method, message, headers)
|
||||||
|
headers, body = response
|
||||||
|
self._cache.clear()
|
||||||
|
if 400 <= int(headers['status']) < 600:
|
||||||
|
raise FailedRequestError("Error code (%s) from GeoServer: %s" %
|
||||||
|
(headers['status'], body))
|
||||||
|
return response
|
||||||
|
|
||||||
|
def get_store(self, name, workspace=None):
|
||||||
|
#stores = [s for s in self.get_stores(workspace) if s.name == name]
|
||||||
|
if workspace is None:
|
||||||
|
store = None
|
||||||
|
for ws in self.get_workspaces():
|
||||||
|
found = None
|
||||||
|
try:
|
||||||
|
found = self.get_store(name, ws)
|
||||||
|
except:
|
||||||
|
# don't expect every workspace to contain the named store
|
||||||
|
pass
|
||||||
|
if found:
|
||||||
|
if store:
|
||||||
|
raise AmbiguousRequestError("Multiple stores found named: " + name)
|
||||||
|
else:
|
||||||
|
store = found
|
||||||
|
if not store:
|
||||||
|
raise FailedRequestError("No store found named: " + name)
|
||||||
|
return store
|
||||||
|
else: # workspace is not None
|
||||||
|
if isinstance(workspace, basestring):
|
||||||
|
workspace = self.get_workspace(workspace)
|
||||||
|
if workspace is None:
|
||||||
|
return None
|
||||||
|
logger.debug("datastore url is [%s]", workspace.datastore_url )
|
||||||
|
ds_list = self.get_xml(workspace.datastore_url)
|
||||||
|
cs_list = self.get_xml(workspace.coveragestore_url)
|
||||||
|
datastores = [n for n in ds_list.findall("dataStore") if n.find("name").text == name]
|
||||||
|
coveragestores = [n for n in cs_list.findall("coverageStore") if n.find("name").text == name]
|
||||||
|
ds_len, cs_len = len(datastores), len(coveragestores)
|
||||||
|
|
||||||
|
if ds_len == 1 and cs_len == 0:
|
||||||
|
return datastore_from_index(self, workspace, datastores[0])
|
||||||
|
elif ds_len == 0 and cs_len == 1:
|
||||||
|
return coveragestore_from_index(self, workspace, coveragestores[0])
|
||||||
|
elif ds_len == 0 and cs_len == 0:
|
||||||
|
raise FailedRequestError("No store found in " + str(workspace) + " named: " + name)
|
||||||
|
else:
|
||||||
|
raise AmbiguousRequestError(str(workspace) + " and name: " + name + " do not uniquely identify a layer")
|
||||||
|
|
||||||
|
def get_stores(self, workspace=None):
|
||||||
|
if workspace is not None:
|
||||||
|
if isinstance(workspace, basestring):
|
||||||
|
workspace = self.get_workspace(workspace)
|
||||||
|
ds_list = self.get_xml(workspace.datastore_url)
|
||||||
|
cs_list = self.get_xml(workspace.coveragestore_url)
|
||||||
|
datastores = [datastore_from_index(self, workspace, n) for n in ds_list.findall("dataStore")]
|
||||||
|
coveragestores = [coveragestore_from_index(self, workspace, n) for n in cs_list.findall("coverageStore")]
|
||||||
|
return datastores + coveragestores
|
||||||
|
else:
|
||||||
|
stores = []
|
||||||
|
for ws in self.get_workspaces():
|
||||||
|
a = self.get_stores(ws)
|
||||||
|
stores.extend(a)
|
||||||
|
return stores
|
||||||
|
|
||||||
|
def create_datastore(self, name, workspace=None):
|
||||||
|
if isinstance(workspace, basestring):
|
||||||
|
workspace = self.get_workspace(workspace)
|
||||||
|
elif workspace is None:
|
||||||
|
workspace = self.get_default_workspace()
|
||||||
|
return UnsavedDataStore(self, name, workspace)
|
||||||
|
|
||||||
|
def create_coveragestore2(self, name, workspace = None):
|
||||||
|
"""
|
||||||
|
Hm we already named the method that creates a coverage *resource*
|
||||||
|
create_coveragestore... time for an API break?
|
||||||
|
"""
|
||||||
|
if isinstance(workspace, basestring):
|
||||||
|
workspace = self.get_workspace(workspace)
|
||||||
|
elif workspace is None:
|
||||||
|
workspace = self.get_default_workspace()
|
||||||
|
return UnsavedCoverageStore(self, name, workspace)
|
||||||
|
|
||||||
|
def add_data_to_store(self, store, name, data, workspace=None, overwrite = False, charset = None):
|
||||||
|
if isinstance(store, basestring):
|
||||||
|
store = self.get_store(store, workspace=workspace)
|
||||||
|
if workspace is not None:
|
||||||
|
workspace = _name(workspace)
|
||||||
|
assert store.workspace.name == workspace, "Specified store (%s) is not in specified workspace (%s)!" % (store, workspace)
|
||||||
|
else:
|
||||||
|
workspace = store.workspace.name
|
||||||
|
store = store.name
|
||||||
|
|
||||||
|
if isinstance(data, dict):
|
||||||
|
bundle = prepare_upload_bundle(name, data)
|
||||||
|
else:
|
||||||
|
bundle = data
|
||||||
|
|
||||||
|
params = dict()
|
||||||
|
if overwrite:
|
||||||
|
params["update"] = "overwrite"
|
||||||
|
if charset is not None:
|
||||||
|
params["charset"] = charset
|
||||||
|
|
||||||
|
message = open(bundle)
|
||||||
|
headers = { 'Content-Type': 'application/zip', 'Accept': 'application/xml' }
|
||||||
|
upload_url = url(self.service_url,
|
||||||
|
["workspaces", workspace, "datastores", store, "file.shp"], params)
|
||||||
|
|
||||||
|
try:
|
||||||
|
headers, response = self.http.request(upload_url, "PUT", message, headers)
|
||||||
|
self._cache.clear()
|
||||||
|
if headers.status != 201:
|
||||||
|
raise UploadError(response)
|
||||||
|
finally:
|
||||||
|
unlink(bundle)
|
||||||
|
|
||||||
|
def create_featurestore(self, name, data, workspace=None, overwrite=False, charset=None):
|
||||||
|
if not overwrite:
|
||||||
|
try:
|
||||||
|
store = self.get_store(name, workspace)
|
||||||
|
msg = "There is already a store named " + name
|
||||||
|
if workspace:
|
||||||
|
msg += " in " + str(workspace)
|
||||||
|
raise ConflictingDataError(msg)
|
||||||
|
except FailedRequestError:
|
||||||
|
# we don't really expect that every layer name will be taken
|
||||||
|
pass
|
||||||
|
|
||||||
|
if workspace is None:
|
||||||
|
workspace = self.get_default_workspace()
|
||||||
|
workspace = _name(workspace)
|
||||||
|
params = dict()
|
||||||
|
if charset is not None:
|
||||||
|
params['charset'] = charset
|
||||||
|
ds_url = url(self.service_url,
|
||||||
|
["workspaces", workspace, "datastores", name, "file.shp"], params)
|
||||||
|
|
||||||
|
# PUT /workspaces/<ws>/datastores/<ds>/file.shp
|
||||||
|
headers = {
|
||||||
|
"Content-type": "application/zip",
|
||||||
|
"Accept": "application/xml"
|
||||||
|
}
|
||||||
|
if isinstance(data,dict):
|
||||||
|
logger.debug('Data is NOT a zipfile')
|
||||||
|
archive = prepare_upload_bundle(name, data)
|
||||||
|
else:
|
||||||
|
logger.debug('Data is a zipfile')
|
||||||
|
archive = data
|
||||||
|
message = open(archive)
|
||||||
|
try:
|
||||||
|
headers, response = self.http.request(ds_url, "PUT", message, headers)
|
||||||
|
self._cache.clear()
|
||||||
|
if headers.status != 201:
|
||||||
|
raise UploadError(response)
|
||||||
|
finally:
|
||||||
|
unlink(archive)
|
||||||
|
|
||||||
|
def create_coveragestore(self, name, data, workspace=None, overwrite=False):
|
||||||
|
if not overwrite:
|
||||||
|
try:
|
||||||
|
store = self.get_store(name, workspace)
|
||||||
|
msg = "There is already a store named " + name
|
||||||
|
if workspace:
|
||||||
|
msg += " in " + str(workspace)
|
||||||
|
raise ConflictingDataError(msg)
|
||||||
|
except FailedRequestError:
|
||||||
|
# we don't really expect that every layer name will be taken
|
||||||
|
pass
|
||||||
|
|
||||||
|
if workspace is None:
|
||||||
|
workspace = self.get_default_workspace()
|
||||||
|
headers = {
|
||||||
|
"Content-type": "image/tiff",
|
||||||
|
"Accept": "application/xml"
|
||||||
|
}
|
||||||
|
|
||||||
|
archive = None
|
||||||
|
ext = "geotiff"
|
||||||
|
|
||||||
|
if isinstance(data, dict):
|
||||||
|
archive = prepare_upload_bundle(name, data)
|
||||||
|
message = open(archive)
|
||||||
|
if "tfw" in data:
|
||||||
|
headers['Content-type'] = 'application/archive'
|
||||||
|
ext = "worldimage"
|
||||||
|
elif isinstance(data, basestring):
|
||||||
|
message = open(data)
|
||||||
|
else:
|
||||||
|
message = data
|
||||||
|
|
||||||
|
cs_url = url(self.service_url,
|
||||||
|
["workspaces", workspace.name, "coveragestores", name, "file." + ext])
|
||||||
|
|
||||||
|
try:
|
||||||
|
headers, response = self.http.request(cs_url, "PUT", message, headers)
|
||||||
|
self._cache.clear()
|
||||||
|
if headers.status != 201:
|
||||||
|
raise UploadError(response)
|
||||||
|
finally:
|
||||||
|
if archive is not None:
|
||||||
|
unlink(archive)
|
||||||
|
|
||||||
|
def get_resource(self, name, store=None, workspace=None):
|
||||||
|
if store is not None:
|
||||||
|
candidates = [s for s in self.get_resources(store) if s.name == name]
|
||||||
|
if len(candidates) == 0:
|
||||||
|
return None
|
||||||
|
elif len(candidates) > 1:
|
||||||
|
raise AmbiguousRequestError
|
||||||
|
else:
|
||||||
|
return candidates[0]
|
||||||
|
|
||||||
|
if workspace is not None:
|
||||||
|
for store in self.get_stores(workspace):
|
||||||
|
resource = self.get_resource(name, store)
|
||||||
|
if resource is not None:
|
||||||
|
return resource
|
||||||
|
return None
|
||||||
|
|
||||||
|
for ws in self.get_workspaces():
|
||||||
|
resource = self.get_resource(name, workspace=ws)
|
||||||
|
if resource is not None:
|
||||||
|
return resource
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_resources(self, store=None, workspace=None):
|
||||||
|
if isinstance(workspace, basestring):
|
||||||
|
workspace = self.get_workspace(workspace)
|
||||||
|
if isinstance(store, basestring):
|
||||||
|
store = self.get_store(store, workspace)
|
||||||
|
if store is not None:
|
||||||
|
return store.get_resources()
|
||||||
|
if workspace is not None:
|
||||||
|
resources = []
|
||||||
|
for store in self.get_stores(workspace):
|
||||||
|
resources.extend(self.get_resources(store))
|
||||||
|
return resources
|
||||||
|
resources = []
|
||||||
|
for ws in self.get_workspaces():
|
||||||
|
resources.extend(self.get_resources(workspace=ws))
|
||||||
|
return resources
|
||||||
|
|
||||||
|
def get_layer(self, name):
|
||||||
|
try:
|
||||||
|
lyr = Layer(self, name)
|
||||||
|
lyr.fetch()
|
||||||
|
return lyr
|
||||||
|
except FailedRequestError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_layers(self, resource=None):
|
||||||
|
if isinstance(resource, basestring):
|
||||||
|
resource = self.get_resource(resource)
|
||||||
|
layers_url = url(self.service_url, ["layers.xml"])
|
||||||
|
description = self.get_xml(layers_url)
|
||||||
|
lyrs = [Layer(self, l.find("name").text) for l in description.findall("layer")]
|
||||||
|
if resource is not None:
|
||||||
|
lyrs = [l for l in lyrs if l.resource.href == resource.href]
|
||||||
|
# TODO: Filter by style
|
||||||
|
return lyrs
|
||||||
|
|
||||||
|
def get_layergroup(self, name=None):
|
||||||
|
try:
|
||||||
|
group_url = url(self.service_url, ["layergroups", name + ".xml"])
|
||||||
|
group = self.get_xml(group_url)
|
||||||
|
return LayerGroup(self, group.find("name").text)
|
||||||
|
except FailedRequestError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_layergroups(self):
|
||||||
|
groups = self.get_xml("%s/layergroups.xml" % self.service_url)
|
||||||
|
return [LayerGroup(self, g.find("name").text) for g in groups.findall("layerGroup")]
|
||||||
|
|
||||||
|
def create_layergroup(self, name, layers = (), styles = (), bounds = None):
|
||||||
|
if any(g.name == name for g in self.get_layergroups()):
|
||||||
|
raise ConflictingDataError("LayerGroup named %s already exists!" % name)
|
||||||
|
else:
|
||||||
|
return UnsavedLayerGroup(self, name, layers, styles, bounds)
|
||||||
|
|
||||||
|
def get_style(self, name):
|
||||||
|
try:
|
||||||
|
style_url = url(self.service_url, ["styles", name + ".xml"])
|
||||||
|
dom = self.get_xml(style_url)
|
||||||
|
return Style(self, dom.find("name").text)
|
||||||
|
except FailedRequestError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_styles(self):
|
||||||
|
styles_url = url(self.service_url, ["styles.xml"])
|
||||||
|
description = self.get_xml(styles_url)
|
||||||
|
return [Style(self, s.find('name').text) for s in description.findall("style")]
|
||||||
|
|
||||||
|
def create_style(self, name, data, overwrite = False):
|
||||||
|
if overwrite == False and self.get_style(name) is not None:
|
||||||
|
raise ConflictingDataError("There is already a style named %s" % name)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-type": "application/vnd.ogc.sld+xml",
|
||||||
|
"Accept": "application/xml"
|
||||||
|
}
|
||||||
|
|
||||||
|
if overwrite:
|
||||||
|
style_url = url(self.service_url, ["styles", name + ".sld"])
|
||||||
|
headers, response = self.http.request(style_url, "PUT", data, headers)
|
||||||
|
else:
|
||||||
|
style_url = url(self.service_url, ["styles"], dict(name=name))
|
||||||
|
headers, response = self.http.request(style_url, "POST", data, headers)
|
||||||
|
|
||||||
|
self._cache.clear()
|
||||||
|
if headers.status < 200 or headers.status > 299: raise UploadError(response)
|
||||||
|
|
||||||
|
def create_workspace(self, name, uri):
|
||||||
|
xml = ("<namespace>"
|
||||||
|
"<prefix>{name}</prefix>"
|
||||||
|
"<uri>{uri}</uri>"
|
||||||
|
"</namespace>").format(name=name, uri=uri)
|
||||||
|
headers = { "Content-Type": "application/xml" }
|
||||||
|
workspace_url = self.service_url + "/namespaces/"
|
||||||
|
|
||||||
|
headers, response = self.http.request(workspace_url, "POST", xml, headers)
|
||||||
|
assert 200 <= headers.status < 300, "Tried to create workspace but got " + str(headers.status) + ": " + response
|
||||||
|
self._cache.clear()
|
||||||
|
return self.get_workspace(name)
|
||||||
|
|
||||||
|
def get_workspaces(self):
|
||||||
|
description = self.get_xml("%s/workspaces.xml" % self.service_url)
|
||||||
|
return [workspace_from_index(self, node) for node in description.findall("workspace")]
|
||||||
|
|
||||||
|
def get_workspace(self, name):
|
||||||
|
candidates = [w for w in self.get_workspaces() if w.name == name]
|
||||||
|
if len(candidates) == 0:
|
||||||
|
return None
|
||||||
|
elif len(candidates) > 1:
|
||||||
|
raise AmbiguousRequestError()
|
||||||
|
else:
|
||||||
|
return candidates[0]
|
||||||
|
|
||||||
|
def get_default_workspace(self):
|
||||||
|
return Workspace(self, "default")
|
||||||
|
|
||||||
|
def set_default_workspace(self):
|
||||||
|
raise NotImplementedError()
|
132
python/plugins/sextante/servertools/geoserver/layer.py
Normal file
132
python/plugins/sextante/servertools/geoserver/layer.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
from sextante.servertools.geoserver.support import ResourceInfo, xml_property, write_bool, url
|
||||||
|
from sextante.servertools.geoserver.style import Style
|
||||||
|
|
||||||
|
class _attribution(object):
|
||||||
|
def __init__(self, title, width, height):
|
||||||
|
self.title = title
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
|
||||||
|
def _read_attribution(node):
|
||||||
|
title = node.find("title")
|
||||||
|
width = node.find("logoWidth")
|
||||||
|
height = node.find("logoHeight")
|
||||||
|
|
||||||
|
if title is not None:
|
||||||
|
title = title.text
|
||||||
|
if width is not None:
|
||||||
|
width = width.text
|
||||||
|
if height is not None:
|
||||||
|
height = height.text
|
||||||
|
|
||||||
|
return _attribution(title, width, height)
|
||||||
|
|
||||||
|
def _write_attribution(builder, attr):
|
||||||
|
builder.start("attribution", dict())
|
||||||
|
if attr.title is not None:
|
||||||
|
builder.start("title", dict())
|
||||||
|
builder.data(attr.title)
|
||||||
|
builder.end("title")
|
||||||
|
if attr.width is not None:
|
||||||
|
builder.start("logoWidth", dict())
|
||||||
|
builder.data(attr.width)
|
||||||
|
builder.end("logoWidth")
|
||||||
|
if attr.height is not None:
|
||||||
|
builder.start("logoHeight", dict())
|
||||||
|
builder.data(attr.height)
|
||||||
|
builder.end("logoHeight")
|
||||||
|
builder.end("attribution")
|
||||||
|
|
||||||
|
def _write_default_style(builder, name):
|
||||||
|
builder.start("defaultStyle", dict())
|
||||||
|
if name is not None:
|
||||||
|
builder.start("name", dict())
|
||||||
|
builder.data(name)
|
||||||
|
builder.end("name")
|
||||||
|
builder.end("defaultStyle")
|
||||||
|
|
||||||
|
|
||||||
|
def _write_alternate_styles(builder, styles):
|
||||||
|
builder.start("styles", dict())
|
||||||
|
for s in styles:
|
||||||
|
builder.start("style", dict())
|
||||||
|
builder.start("name", dict())
|
||||||
|
builder.data(s.name)
|
||||||
|
builder.end("name")
|
||||||
|
builder.end("style")
|
||||||
|
builder.end("styles")
|
||||||
|
|
||||||
|
|
||||||
|
class Layer(ResourceInfo):
|
||||||
|
def __init__(self, catalog, name):
|
||||||
|
super(Layer, self).__init__()
|
||||||
|
self.catalog = catalog
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
resource_type = "layer"
|
||||||
|
save_method = "PUT"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url, ["layers", self.name + ".xml"])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def resource(self):
|
||||||
|
if self.dom is None:
|
||||||
|
self.fetch()
|
||||||
|
name = self.dom.find("resource/name").text
|
||||||
|
return self.catalog.get_resource(name)
|
||||||
|
|
||||||
|
def _get_default_style(self):
|
||||||
|
if 'default_style' in self.dirty:
|
||||||
|
return self.dirty['default_style']
|
||||||
|
if self.dom is None:
|
||||||
|
self.fetch()
|
||||||
|
name = self.dom.find("defaultStyle/name")
|
||||||
|
# aborted data uploads can result in no default style
|
||||||
|
if name is not None:
|
||||||
|
return self.catalog.get_style(name.text)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _set_default_style(self, style):
|
||||||
|
if isinstance(style, Style):
|
||||||
|
style = style.name
|
||||||
|
self.dirty["default_style"] = style
|
||||||
|
|
||||||
|
def _get_alternate_styles(self):
|
||||||
|
if "alternate_styles" in self.dirty:
|
||||||
|
return self.dirty["alternate_styles"]
|
||||||
|
if self.dom is None:
|
||||||
|
self.fetch()
|
||||||
|
styles = self.dom.findall("styles/style/name")
|
||||||
|
return [Style(self.catalog, s.text) for s in styles]
|
||||||
|
|
||||||
|
def _set_alternate_styles(self, styles):
|
||||||
|
self.dirty["alternate_styles"] = styles
|
||||||
|
|
||||||
|
default_style = property(_get_default_style, _set_default_style)
|
||||||
|
styles = property(_get_alternate_styles, _set_alternate_styles)
|
||||||
|
|
||||||
|
attribution_object = xml_property("attribution", _read_attribution)
|
||||||
|
enabled = xml_property("enabled", lambda x: x.text == "true")
|
||||||
|
|
||||||
|
def _get_attr_text(self):
|
||||||
|
return self.attribution_object.title
|
||||||
|
|
||||||
|
def _set_attr_text(self, text):
|
||||||
|
self.dirty["attribution"] = _attribution(
|
||||||
|
text,
|
||||||
|
self.attribution_object.width,
|
||||||
|
self.attribution_object.height
|
||||||
|
)
|
||||||
|
assert self.attribution_object.title == text
|
||||||
|
|
||||||
|
attribution = property(_get_attr_text, _set_attr_text)
|
||||||
|
|
||||||
|
writers = dict(
|
||||||
|
attribution = _write_attribution,
|
||||||
|
enabled = write_bool("enabled"),
|
||||||
|
default_style = _write_default_style,
|
||||||
|
alternate_styles = _write_alternate_styles
|
||||||
|
)
|
84
python/plugins/sextante/servertools/geoserver/layergroup.py
Normal file
84
python/plugins/sextante/servertools/geoserver/layergroup.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from sextante.servertools.geoserver.support import ResourceInfo, bbox, write_bbox, \
|
||||||
|
write_string, xml_property, url
|
||||||
|
|
||||||
|
def _maybe_text(n):
|
||||||
|
if n is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return n.text
|
||||||
|
|
||||||
|
def _layer_list(node):
|
||||||
|
if node is not None:
|
||||||
|
return [_maybe_text(n.find("name")) for n in node.findall("layer")]
|
||||||
|
|
||||||
|
def _style_list(node):
|
||||||
|
if node is not None:
|
||||||
|
return [_maybe_text(n.find("name")) for n in node.findall("style")]
|
||||||
|
|
||||||
|
def _write_layers(builder, layers):
|
||||||
|
builder.start("layers", dict())
|
||||||
|
for l in layers:
|
||||||
|
builder.start("layer", dict())
|
||||||
|
if l is not None:
|
||||||
|
builder.start("name", dict())
|
||||||
|
builder.data(l)
|
||||||
|
builder.end("name")
|
||||||
|
builder.end("layer")
|
||||||
|
builder.end("layers")
|
||||||
|
|
||||||
|
def _write_styles(builder, styles):
|
||||||
|
builder.start("styles", dict())
|
||||||
|
for s in styles:
|
||||||
|
builder.start("style", dict())
|
||||||
|
if s is not None:
|
||||||
|
builder.start("name", dict())
|
||||||
|
builder.data(s)
|
||||||
|
builder.end("name")
|
||||||
|
builder.end("style")
|
||||||
|
builder.end("styles")
|
||||||
|
|
||||||
|
class LayerGroup(ResourceInfo):
|
||||||
|
"""
|
||||||
|
Represents a layer group in geoserver
|
||||||
|
"""
|
||||||
|
|
||||||
|
resource_type = "layerGroup"
|
||||||
|
save_method = "PUT"
|
||||||
|
|
||||||
|
def __init__(self, catalog, name):
|
||||||
|
super(LayerGroup, self).__init__()
|
||||||
|
|
||||||
|
assert isinstance(name, basestring)
|
||||||
|
|
||||||
|
self.catalog = catalog
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url, ["layergroups", self.name + ".xml"])
|
||||||
|
|
||||||
|
styles = xml_property("styles", _style_list)
|
||||||
|
layers = xml_property("layers", _layer_list)
|
||||||
|
bounds = xml_property("bounds", bbox)
|
||||||
|
|
||||||
|
writers = dict(
|
||||||
|
name = write_string("name"),
|
||||||
|
styles = _write_styles,
|
||||||
|
layers = _write_layers,
|
||||||
|
bounds = write_bbox("bounds")
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<LayerGroup %s>" % self.name
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
|
class UnsavedLayerGroup(LayerGroup):
|
||||||
|
save_method = "POST"
|
||||||
|
def __init__(self, catalog, name, layers, styles, bounds):
|
||||||
|
super(UnsavedLayerGroup, self).__init__(catalog, name)
|
||||||
|
self.dirty.update(name = name, layers = layers, styles = styles, bounds = bounds)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return "%s/layergroups?name=%s" % (self.catalog.service_url, self.name)
|
176
python/plugins/sextante/servertools/geoserver/resource.py
Normal file
176
python/plugins/sextante/servertools/geoserver/resource.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
from sextante.servertools.geoserver.support import ResourceInfo, xml_property, write_string, bbox, \
|
||||||
|
write_bbox, string_list, write_string_list, attribute_list, write_bool, url
|
||||||
|
|
||||||
|
def md_link(node):
|
||||||
|
"""Extract a metadata link tuple from an xml node"""
|
||||||
|
mimetype = node.find("type")
|
||||||
|
mdtype = node.find("metadataType")
|
||||||
|
content = node.find("content")
|
||||||
|
if None in [mimetype, mdtype, content]:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return (mimetype.text, mdtype.text, content.text)
|
||||||
|
|
||||||
|
def metadata_link_list(node):
|
||||||
|
if node is not None:
|
||||||
|
return [md_link(n) for n in node.findall("metadataLink")]
|
||||||
|
|
||||||
|
def write_metadata_link_list(name):
|
||||||
|
def write(builder, md_links):
|
||||||
|
builder.start(name, dict())
|
||||||
|
for (mime, md_type, content_url) in md_links:
|
||||||
|
builder.start("metadataLink", dict())
|
||||||
|
builder.start("type", dict())
|
||||||
|
builder.data(mime)
|
||||||
|
builder.end("type")
|
||||||
|
builder.start("metadataType", dict())
|
||||||
|
builder.data(md_type)
|
||||||
|
builder.end("metadataType")
|
||||||
|
builder.start("content", dict())
|
||||||
|
builder.data(content_url)
|
||||||
|
builder.end("content")
|
||||||
|
builder.end("metadataLink")
|
||||||
|
builder.end("metadataLinks")
|
||||||
|
return write
|
||||||
|
|
||||||
|
def featuretype_from_index(catalog, workspace, store, node):
|
||||||
|
name = node.find("name")
|
||||||
|
return FeatureType(catalog, workspace, store, name.text)
|
||||||
|
|
||||||
|
def coverage_from_index(catalog, workspace, store, node):
|
||||||
|
name = node.find("name")
|
||||||
|
return Coverage(catalog, workspace, store, name.text)
|
||||||
|
|
||||||
|
class FeatureType(ResourceInfo):
|
||||||
|
resource_type = "featureType"
|
||||||
|
save_method = "PUT"
|
||||||
|
|
||||||
|
def __init__(self, catalog, workspace, store, name):
|
||||||
|
super(FeatureType, self).__init__()
|
||||||
|
|
||||||
|
assert isinstance(store, ResourceInfo)
|
||||||
|
assert isinstance(name, basestring)
|
||||||
|
|
||||||
|
self.catalog = catalog
|
||||||
|
self.workspace = workspace
|
||||||
|
self.store = store
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url,
|
||||||
|
["workspaces", self.workspace.name,
|
||||||
|
"datastores", self.store.name,
|
||||||
|
"featuretypes", self.name + ".xml"])
|
||||||
|
|
||||||
|
title = xml_property("title")
|
||||||
|
abstract = xml_property("abstract")
|
||||||
|
enabled = xml_property("enabled")
|
||||||
|
native_bbox = xml_property("nativeBoundingBox", bbox)
|
||||||
|
latlon_bbox = xml_property("latLonBoundingBox", bbox)
|
||||||
|
projection = xml_property("srs")
|
||||||
|
projection_policy = xml_property("projectionPolicy")
|
||||||
|
keywords = xml_property("keywords", string_list)
|
||||||
|
attributes = xml_property("attributes", attribute_list)
|
||||||
|
metadata_links = xml_property("metadataLinks", metadata_link_list)
|
||||||
|
|
||||||
|
writers = dict(
|
||||||
|
title = write_string("title"),
|
||||||
|
abstract = write_string("abstract"),
|
||||||
|
enabled = write_bool("enabled"),
|
||||||
|
nativeBoundingBox = write_bbox("nativeBoundingBox"),
|
||||||
|
latLonBoundingBox = write_bbox("latLonBoundingBox"),
|
||||||
|
srs = write_string("srs"),
|
||||||
|
projectionPolicy = write_string("projectionPolicy"),
|
||||||
|
keywords = write_string_list("keywords"),
|
||||||
|
metadataLinks = write_metadata_link_list("metadataLinks")
|
||||||
|
)
|
||||||
|
|
||||||
|
class CoverageDimension(object):
|
||||||
|
def __init__(self, name, description, dimension_range):
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.dimension_range = dimension_range
|
||||||
|
|
||||||
|
def coverage_dimension(node):
|
||||||
|
name = node.find("name")
|
||||||
|
name = name.text if name is not None else None
|
||||||
|
description = node.find("description")
|
||||||
|
description = description.text if description is not None else None
|
||||||
|
range_min = node.find("range/min")
|
||||||
|
range_max = node.find("range/max")
|
||||||
|
dimension_range = None
|
||||||
|
if None not in [min, max]:
|
||||||
|
dimension_range = float(range_min.text), float(range_max.text)
|
||||||
|
if None not in [name, description]:
|
||||||
|
return CoverageDimension(name, description, dimension_range)
|
||||||
|
else:
|
||||||
|
return None # should we bomb out more spectacularly here?
|
||||||
|
|
||||||
|
def coverage_dimension_xml(builder, dimension):
|
||||||
|
builder.start("coverageDimension", dict())
|
||||||
|
builder.start("name", dict())
|
||||||
|
builder.data(dimension.name)
|
||||||
|
builder.end("name")
|
||||||
|
|
||||||
|
builder.start("description", dict())
|
||||||
|
builder.data(dimension.description)
|
||||||
|
builder.end("description")
|
||||||
|
|
||||||
|
if dimension.range is not None:
|
||||||
|
builder.start("range", dict())
|
||||||
|
builder.start("min", dict())
|
||||||
|
builder.data(str(dimension.range[0]))
|
||||||
|
builder.end("min")
|
||||||
|
builder.start("max", dict())
|
||||||
|
builder.data(str(dimension.range[1]))
|
||||||
|
builder.end("max")
|
||||||
|
builder.end("range")
|
||||||
|
|
||||||
|
builder.end("coverageDimension")
|
||||||
|
|
||||||
|
class Coverage(ResourceInfo):
|
||||||
|
def __init__(self, catalog, workspace, store, name):
|
||||||
|
super(Coverage, self).__init__()
|
||||||
|
self.catalog = catalog
|
||||||
|
self.workspace = workspace
|
||||||
|
self.store = store
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url,
|
||||||
|
["workspaces", self.workspace.name,
|
||||||
|
"coveragestores", self.store.name,
|
||||||
|
"coverages", self.name + ".xml"])
|
||||||
|
|
||||||
|
resource_type = "coverage"
|
||||||
|
save_method = "PUT"
|
||||||
|
|
||||||
|
title = xml_property("title")
|
||||||
|
abstract = xml_property("abstract")
|
||||||
|
enabled = xml_property("enabled")
|
||||||
|
native_bbox = xml_property("nativeBoundingBox", bbox)
|
||||||
|
latlon_bbox = xml_property("latLonBoundingBox", bbox)
|
||||||
|
projection = xml_property("srs")
|
||||||
|
projection_policy = xml_property("projectionPolicy")
|
||||||
|
keywords = xml_property("keywords", string_list)
|
||||||
|
request_srs_list = xml_property("requestSRS", string_list)
|
||||||
|
response_srs_list = xml_property("responseSRS", string_list)
|
||||||
|
supported_formats = xml_property("supportedFormats", string_list)
|
||||||
|
metadata_links = xml_property("metadataLinks", metadata_link_list)
|
||||||
|
|
||||||
|
writers = dict(
|
||||||
|
title = write_string("title"),
|
||||||
|
abstract = write_string("abstract"),
|
||||||
|
enabled = write_bool("enabled"),
|
||||||
|
nativeBoundingBox = write_bbox("nativeBoundingBox"),
|
||||||
|
latLonBoundingBox = write_bbox("latLonBoundingBox"),
|
||||||
|
srs = write_string("srs"),
|
||||||
|
projection_policy = write_string("projectionPolicy"),
|
||||||
|
keywords = write_string_list("keywords"),
|
||||||
|
metadataLinks = write_metadata_link_list("metadataLinks"),
|
||||||
|
requestSRS = write_string_list("requestSRS"),
|
||||||
|
responseSRS = write_string_list("responseSRS"),
|
||||||
|
supportedFormats = write_string_list("supportedFormats")
|
||||||
|
)
|
117
python/plugins/sextante/servertools/geoserver/store.py
Normal file
117
python/plugins/sextante/servertools/geoserver/store.py
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import sextante.servertools.geoserver.workspace as ws
|
||||||
|
from sextante.servertools.geoserver.resource import featuretype_from_index, coverage_from_index
|
||||||
|
from sextante.servertools.geoserver.support import ResourceInfo, xml_property, key_value_pairs, \
|
||||||
|
write_bool, write_dict, write_string, url
|
||||||
|
|
||||||
|
def datastore_from_index(catalog, workspace, node):
|
||||||
|
name = node.find("name")
|
||||||
|
return DataStore(catalog, workspace, name.text)
|
||||||
|
|
||||||
|
def coveragestore_from_index(catalog, workspace, node):
|
||||||
|
name = node.find("name")
|
||||||
|
return CoverageStore(catalog, workspace, name.text)
|
||||||
|
|
||||||
|
class DataStore(ResourceInfo):
|
||||||
|
resource_type = "dataStore"
|
||||||
|
save_method = "PUT"
|
||||||
|
|
||||||
|
def __init__(self, catalog, workspace, name):
|
||||||
|
super(DataStore, self).__init__()
|
||||||
|
|
||||||
|
assert isinstance(workspace, ws.Workspace)
|
||||||
|
assert isinstance(name, basestring)
|
||||||
|
self.catalog = catalog
|
||||||
|
self.workspace = workspace
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url,
|
||||||
|
["workspaces", self.workspace.name, "datastores", self.name + ".xml"])
|
||||||
|
|
||||||
|
enabled = xml_property("enabled", lambda x: x.text == "true")
|
||||||
|
name = xml_property("name")
|
||||||
|
connection_parameters = xml_property("connectionParameters", key_value_pairs)
|
||||||
|
|
||||||
|
writers = dict(enabled = write_bool("enabled"),
|
||||||
|
name = write_string("name"),
|
||||||
|
connectionParameters = write_dict("connectionParameters"))
|
||||||
|
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
res_url = url(self.catalog.service_url,
|
||||||
|
["workspaces", self.workspace.name, "datastores", self.name, "featuretypes.xml"])
|
||||||
|
xml = self.catalog.get_xml(res_url)
|
||||||
|
def ft_from_node(node):
|
||||||
|
return featuretype_from_index(self.catalog, self.workspace, self, node)
|
||||||
|
|
||||||
|
return [ft_from_node(node) for node in xml.findall("featureType")]
|
||||||
|
|
||||||
|
class UnsavedDataStore(DataStore):
|
||||||
|
save_method = "POST"
|
||||||
|
|
||||||
|
def __init__(self, catalog, name, workspace):
|
||||||
|
super(UnsavedDataStore, self).__init__(catalog, workspace, name)
|
||||||
|
self.dirty.update(dict(
|
||||||
|
name=name, enabled=True, connectionParameters=dict()))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
path = [ "workspaces",
|
||||||
|
self.workspace.name, "datastores"]
|
||||||
|
query = dict(name=self.name)
|
||||||
|
return url(self.catalog.service_url, path, query)
|
||||||
|
|
||||||
|
class CoverageStore(ResourceInfo):
|
||||||
|
resource_type = 'coverageStore'
|
||||||
|
save_method = "PUT"
|
||||||
|
|
||||||
|
def __init__(self, catalog, workspace, name):
|
||||||
|
super(CoverageStore, self).__init__()
|
||||||
|
|
||||||
|
assert isinstance(workspace, ws.Workspace)
|
||||||
|
assert isinstance(name, basestring)
|
||||||
|
|
||||||
|
self.catalog = catalog
|
||||||
|
self.workspace = workspace
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url,
|
||||||
|
["workspaces", self.workspace.name, "coveragestores", self.name + ".xml"])
|
||||||
|
|
||||||
|
enabled = xml_property("enabled", lambda x: x.text == "true")
|
||||||
|
name = xml_property("name")
|
||||||
|
url = xml_property("url")
|
||||||
|
type = xml_property("type")
|
||||||
|
|
||||||
|
writers = dict(enabled = write_bool("enabled"),
|
||||||
|
name = write_string("name"),
|
||||||
|
url = write_string("url"),
|
||||||
|
type = write_string("type"))
|
||||||
|
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
res_url = url(self.catalog.service_url,
|
||||||
|
["workspaces", self.workspace.name, "coveragestores", self.name, "coverages.xml"])
|
||||||
|
|
||||||
|
xml = self.catalog.get_xml(res_url)
|
||||||
|
|
||||||
|
def cov_from_node(node):
|
||||||
|
return coverage_from_index(self.catalog, self.workspace, self, node)
|
||||||
|
|
||||||
|
return [cov_from_node(node) for node in xml.findall("coverage")]
|
||||||
|
|
||||||
|
class UnsavedCoverageStore(CoverageStore):
|
||||||
|
save_method = "POST"
|
||||||
|
|
||||||
|
def __init__(self, catalog, name, workspace):
|
||||||
|
super(UnsavedCoverageStore, self).__init__(catalog, workspace, name)
|
||||||
|
self.dirty.update(name=name, enabled = True, type="GeoTIFF",
|
||||||
|
url = "file:data/")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url,
|
||||||
|
["workspaces", self.workspace.name, "coveragestores"], dict(name=self.name))
|
46
python/plugins/sextante/servertools/geoserver/style.py
Normal file
46
python/plugins/sextante/servertools/geoserver/style.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
from sextante.servertools.geoserver.support import ResourceInfo, url, xml_property
|
||||||
|
|
||||||
|
class Style(ResourceInfo):
|
||||||
|
def __init__(self, catalog, name):
|
||||||
|
super(Style, self).__init__()
|
||||||
|
assert isinstance(name, basestring)
|
||||||
|
|
||||||
|
self.catalog = catalog
|
||||||
|
self.name = name
|
||||||
|
self._sld_dom = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url, ["styles", self.name + ".xml"])
|
||||||
|
|
||||||
|
def body_href(self):
|
||||||
|
return url(self.catalog.service_url, ["styles", self.name + ".sld"])
|
||||||
|
|
||||||
|
filename = xml_property("filename")
|
||||||
|
|
||||||
|
def _get_sld_dom(self):
|
||||||
|
if self._sld_dom is None:
|
||||||
|
self._sld_dom = self.catalog.get_xml(self.body_href())
|
||||||
|
return self._sld_dom
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sld_title(self):
|
||||||
|
user_style = self._get_sld_dom().find("{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle")
|
||||||
|
title_node = user_style.find("{http://www.opengis.net/sld}Title")
|
||||||
|
return title_node.text if title_node is not None else None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sld_name(self):
|
||||||
|
user_style = self._get_sld_dom().find("{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle")
|
||||||
|
name_node = user_style.find("{http://www.opengis.net/sld}Name")
|
||||||
|
return name_node.text if name_node is not None else None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sld_body(self):
|
||||||
|
content = self.catalog.http.request(self.body_href())[1]
|
||||||
|
return content
|
||||||
|
|
||||||
|
def update_body(self, body):
|
||||||
|
headers = { "Content-Type": "application/vnd.ogc.sld+xml" }
|
||||||
|
self.catalog.http.request(
|
||||||
|
self.body_href(), "PUT", body, headers)
|
218
python/plugins/sextante/servertools/geoserver/support.py
Normal file
218
python/plugins/sextante/servertools/geoserver/support.py
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
import logging
|
||||||
|
from xml.etree.ElementTree import TreeBuilder, tostring
|
||||||
|
import urllib
|
||||||
|
import urlparse
|
||||||
|
from zipfile import ZipFile
|
||||||
|
from sextante.core.SextanteUtils import SextanteUtils
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger("gsconfig.support")
|
||||||
|
|
||||||
|
FORCE_DECLARED = "FORCE_DECLARED"
|
||||||
|
## The projection handling policy for layers that should use coordinates
|
||||||
|
## directly while reporting the configured projection to clients. This should be
|
||||||
|
## used when projection information is missing from the underlying datastore.
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_NATIVE = "FORCE_NATIVE"
|
||||||
|
## The projection handling policy for layers that should use the projection
|
||||||
|
## information from the underlying storage mechanism directly, and ignore the
|
||||||
|
## projection setting.
|
||||||
|
|
||||||
|
REPROJECT = "REPROJECT"
|
||||||
|
## The projection handling policy for layers that should use the projection
|
||||||
|
## information from the underlying storage mechanism to reproject to the
|
||||||
|
## configured projection.
|
||||||
|
|
||||||
|
def url(base, seg, query=None):
|
||||||
|
"""
|
||||||
|
Create a URL from a list of path segments and an optional dict of query
|
||||||
|
parameters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
seg = (urllib.quote(s.strip('/')) for s in seg)
|
||||||
|
if query is None or len(query) == 0:
|
||||||
|
query_string = ''
|
||||||
|
else:
|
||||||
|
query_string = "?" + urllib.urlencode(query)
|
||||||
|
path = '/'.join(seg) + query_string
|
||||||
|
adjusted_base = base.rstrip('/') + '/'
|
||||||
|
return urlparse.urljoin(adjusted_base, path)
|
||||||
|
|
||||||
|
def xml_property(path, converter = lambda x: x.text):
|
||||||
|
def getter(self):
|
||||||
|
if path in self.dirty:
|
||||||
|
return self.dirty[path]
|
||||||
|
else:
|
||||||
|
if self.dom is None:
|
||||||
|
self.fetch()
|
||||||
|
node = self.dom.find(path)
|
||||||
|
return converter(self.dom.find(path)) if node is not None else None
|
||||||
|
|
||||||
|
def setter(self, value):
|
||||||
|
self.dirty[path] = value
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
self.dirty[path] = None
|
||||||
|
|
||||||
|
return property(getter, setter, delete)
|
||||||
|
|
||||||
|
def bbox(node):
|
||||||
|
if node is not None:
|
||||||
|
minx = node.find("minx")
|
||||||
|
maxx = node.find("maxx")
|
||||||
|
miny = node.find("miny")
|
||||||
|
maxy = node.find("maxy")
|
||||||
|
crs = node.find("crs")
|
||||||
|
crs = crs.text if crs is not None else None
|
||||||
|
|
||||||
|
if (None not in [minx, maxx, miny, maxy]):
|
||||||
|
return (minx.text, maxx.text, miny.text, maxy.text, crs)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def string_list(node):
|
||||||
|
if node is not None:
|
||||||
|
return [n.text for n in node.findall("string")]
|
||||||
|
|
||||||
|
def attribute_list(node):
|
||||||
|
if node is not None:
|
||||||
|
return [n.text for n in node.findall("attribute/name")]
|
||||||
|
|
||||||
|
def key_value_pairs(node):
|
||||||
|
if node is not None:
|
||||||
|
return dict((entry.attrib['key'], entry.text) for entry in node.findall("entry"))
|
||||||
|
|
||||||
|
def write_string(name):
|
||||||
|
def write(builder, value):
|
||||||
|
builder.start(name, dict())
|
||||||
|
if (value is not None):
|
||||||
|
builder.data(value)
|
||||||
|
builder.end(name)
|
||||||
|
return write
|
||||||
|
|
||||||
|
def write_bool(name):
|
||||||
|
def write(builder, b):
|
||||||
|
builder.start(name, dict())
|
||||||
|
builder.data("true" if b else "false")
|
||||||
|
builder.end(name)
|
||||||
|
return write
|
||||||
|
|
||||||
|
def write_bbox(name):
|
||||||
|
def write(builder, b):
|
||||||
|
builder.start(name, dict())
|
||||||
|
bbox_xml(builder, b)
|
||||||
|
builder.end(name)
|
||||||
|
return write
|
||||||
|
|
||||||
|
def write_string_list(name):
|
||||||
|
def write(builder, words):
|
||||||
|
builder.start(name, dict())
|
||||||
|
for w in words:
|
||||||
|
builder.start("string", dict())
|
||||||
|
builder.data(w)
|
||||||
|
builder.end("string")
|
||||||
|
builder.end(name)
|
||||||
|
return write
|
||||||
|
|
||||||
|
def write_dict(name):
|
||||||
|
def write(builder, pairs):
|
||||||
|
builder.start(name, dict())
|
||||||
|
for k, v in pairs.iteritems():
|
||||||
|
builder.start("entry", dict(key=k))
|
||||||
|
builder.data(v)
|
||||||
|
builder.end("entry")
|
||||||
|
builder.end(name)
|
||||||
|
return write
|
||||||
|
|
||||||
|
class ResourceInfo(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.dom = None
|
||||||
|
self.dirty = dict()
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
self.dom = self.catalog.get_xml(self.href)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.dirty = dict()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self.clear()
|
||||||
|
self.fetch()
|
||||||
|
|
||||||
|
def serialize(self, builder):
|
||||||
|
# GeoServer will disable the resource if we omit the <enabled> tag,
|
||||||
|
# so force it into the dirty dict before writing
|
||||||
|
if hasattr(self, "enabled"):
|
||||||
|
self.dirty['enabled'] = self.enabled
|
||||||
|
|
||||||
|
for k, writer in self.writers.items():
|
||||||
|
if k in self.dirty:
|
||||||
|
writer(builder, self.dirty[k])
|
||||||
|
|
||||||
|
def message(self):
|
||||||
|
builder = TreeBuilder()
|
||||||
|
builder.start(self.resource_type, dict())
|
||||||
|
self.serialize(builder)
|
||||||
|
builder.end(self.resource_type)
|
||||||
|
msg = tostring(builder.close())
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def prepare_upload_bundle(name, data):
|
||||||
|
"""GeoServer's REST API uses ZIP archives as containers for file formats such
|
||||||
|
as Shapefile and WorldImage which include several 'boxcar' files alongside
|
||||||
|
the main data. In such archives, GeoServer assumes that all of the relevant
|
||||||
|
files will have the same base name and appropriate extensions, and live in
|
||||||
|
the root of the ZIP archive. This method produces a zip file that matches
|
||||||
|
these expectations, based on a basename, and a dict of extensions to paths or
|
||||||
|
file-like objects. The client code is responsible for deleting the zip
|
||||||
|
archive when it's done."""
|
||||||
|
#we ut the zip file in the sextante temp dir, so it is deleted at the end.
|
||||||
|
f = SextanteUtils.getTempFilename('zip')
|
||||||
|
zip_file = ZipFile(f, 'w')
|
||||||
|
for ext, stream in data.iteritems():
|
||||||
|
fname = "%s.%s" % (name, ext)
|
||||||
|
if (isinstance(stream, basestring)):
|
||||||
|
zip_file.write(stream, fname)
|
||||||
|
else:
|
||||||
|
zip_file.writestr(fname, stream.read())
|
||||||
|
zip_file.close()
|
||||||
|
return f
|
||||||
|
|
||||||
|
def atom_link(node):
|
||||||
|
if 'href' in node.attrib:
|
||||||
|
return node.attrib['href']
|
||||||
|
else:
|
||||||
|
l = node.find("{http://www.w3.org/2005/Atom}link")
|
||||||
|
return l.get('href')
|
||||||
|
|
||||||
|
def atom_link_xml(builder, href):
|
||||||
|
builder.start("atom:link", {
|
||||||
|
'rel': 'alternate',
|
||||||
|
'href': href,
|
||||||
|
'type': 'application/xml',
|
||||||
|
'xmlns:atom': 'http://www.w3.org/2005/Atom'
|
||||||
|
})
|
||||||
|
builder.end("atom:link")
|
||||||
|
|
||||||
|
def bbox_xml(builder, box):
|
||||||
|
minx, maxx, miny, maxy, crs = box
|
||||||
|
builder.start("minx", dict())
|
||||||
|
builder.data(minx)
|
||||||
|
builder.end("minx")
|
||||||
|
builder.start("maxx", dict())
|
||||||
|
builder.data(maxx)
|
||||||
|
builder.end("maxx")
|
||||||
|
builder.start("miny", dict())
|
||||||
|
builder.data(miny)
|
||||||
|
builder.end("miny")
|
||||||
|
builder.start("maxy", dict())
|
||||||
|
builder.data(maxy)
|
||||||
|
builder.end("maxy")
|
||||||
|
if crs is not None:
|
||||||
|
builder.start("crs", {"class": "projected"})
|
||||||
|
builder.data(crs)
|
||||||
|
builder.end("crs")
|
||||||
|
|
5
python/plugins/sextante/servertools/geoserver/util.py
Normal file
5
python/plugins/sextante/servertools/geoserver/util.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# shapefile_and_friends = None
|
||||||
|
# shapefile_plus_sidecars = shapefile_and_friends("test/data/states")
|
||||||
|
|
||||||
|
def shapefile_and_friends(path):
|
||||||
|
return dict((ext, path + "." + ext) for ext in ['shx', 'shp', 'dbf', 'prj'])
|
33
python/plugins/sextante/servertools/geoserver/workspace.py
Normal file
33
python/plugins/sextante/servertools/geoserver/workspace.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from sextante.servertools.geoserver.support import xml_property, write_bool, ResourceInfo, url
|
||||||
|
|
||||||
|
def workspace_from_index(catalog, node):
|
||||||
|
name = node.find("name")
|
||||||
|
return Workspace(catalog, name.text)
|
||||||
|
|
||||||
|
class Workspace(ResourceInfo):
|
||||||
|
resource_type = "workspace"
|
||||||
|
|
||||||
|
def __init__(self, catalog, name):
|
||||||
|
super(Workspace, self).__init__()
|
||||||
|
self.catalog = catalog
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def href(self):
|
||||||
|
return url(self.catalog.service_url, ["workspaces", self.name + ".xml"])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coveragestore_url(self):
|
||||||
|
return url(self.catalog.service_url, ["workspaces", self.name, "coveragestores.xml"])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def datastore_url(self):
|
||||||
|
return url(self.catalog.service_url, ["workspaces", self.name, "datastores.xml"])
|
||||||
|
|
||||||
|
enabled = xml_property("enabled", lambda x: x.lower() == 'true')
|
||||||
|
writers = dict(
|
||||||
|
enabled = write_bool("enabled")
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s @ %s" % (self.name, self.href)
|
1675
python/plugins/sextante/servertools/httplib2/__init__.py
Normal file
1675
python/plugins/sextante/servertools/httplib2/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
110
python/plugins/sextante/servertools/httplib2/iri2uri.py
Normal file
110
python/plugins/sextante/servertools/httplib2/iri2uri.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
"""
|
||||||
|
iri2uri
|
||||||
|
|
||||||
|
Converts an IRI to a URI.
|
||||||
|
|
||||||
|
"""
|
||||||
|
__author__ = "Joe Gregorio (joe@bitworking.org)"
|
||||||
|
__copyright__ = "Copyright 2006, Joe Gregorio"
|
||||||
|
__contributors__ = []
|
||||||
|
__version__ = "1.0.0"
|
||||||
|
__license__ = "MIT"
|
||||||
|
__history__ = """
|
||||||
|
"""
|
||||||
|
|
||||||
|
import urlparse
|
||||||
|
|
||||||
|
|
||||||
|
# Convert an IRI to a URI following the rules in RFC 3987
|
||||||
|
#
|
||||||
|
# The characters we need to enocde and escape are defined in the spec:
|
||||||
|
#
|
||||||
|
# iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD
|
||||||
|
# ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
|
||||||
|
# / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
|
||||||
|
# / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
|
||||||
|
# / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
|
||||||
|
# / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
|
||||||
|
# / %xD0000-DFFFD / %xE1000-EFFFD
|
||||||
|
|
||||||
|
escape_range = [
|
||||||
|
(0xA0, 0xD7FF ),
|
||||||
|
(0xE000, 0xF8FF ),
|
||||||
|
(0xF900, 0xFDCF ),
|
||||||
|
(0xFDF0, 0xFFEF),
|
||||||
|
(0x10000, 0x1FFFD ),
|
||||||
|
(0x20000, 0x2FFFD ),
|
||||||
|
(0x30000, 0x3FFFD),
|
||||||
|
(0x40000, 0x4FFFD ),
|
||||||
|
(0x50000, 0x5FFFD ),
|
||||||
|
(0x60000, 0x6FFFD),
|
||||||
|
(0x70000, 0x7FFFD ),
|
||||||
|
(0x80000, 0x8FFFD ),
|
||||||
|
(0x90000, 0x9FFFD),
|
||||||
|
(0xA0000, 0xAFFFD ),
|
||||||
|
(0xB0000, 0xBFFFD ),
|
||||||
|
(0xC0000, 0xCFFFD),
|
||||||
|
(0xD0000, 0xDFFFD ),
|
||||||
|
(0xE1000, 0xEFFFD),
|
||||||
|
(0xF0000, 0xFFFFD ),
|
||||||
|
(0x100000, 0x10FFFD)
|
||||||
|
]
|
||||||
|
|
||||||
|
def encode(c):
|
||||||
|
retval = c
|
||||||
|
i = ord(c)
|
||||||
|
for low, high in escape_range:
|
||||||
|
if i < low:
|
||||||
|
break
|
||||||
|
if i >= low and i <= high:
|
||||||
|
retval = "".join(["%%%2X" % ord(o) for o in c.encode('utf-8')])
|
||||||
|
break
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
def iri2uri(uri):
|
||||||
|
"""Convert an IRI to a URI. Note that IRIs must be
|
||||||
|
passed in a unicode strings. That is, do not utf-8 encode
|
||||||
|
the IRI before passing it into the function."""
|
||||||
|
if isinstance(uri ,unicode):
|
||||||
|
(scheme, authority, path, query, fragment) = urlparse.urlsplit(uri)
|
||||||
|
authority = authority.encode('idna')
|
||||||
|
# For each character in 'ucschar' or 'iprivate'
|
||||||
|
# 1. encode as utf-8
|
||||||
|
# 2. then %-encode each octet of that utf-8
|
||||||
|
uri = urlparse.urlunsplit((scheme, authority, path, query, fragment))
|
||||||
|
uri = "".join([encode(c) for c in uri])
|
||||||
|
return uri
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_uris(self):
|
||||||
|
"""Test that URIs are invariant under the transformation."""
|
||||||
|
invariant = [
|
||||||
|
u"ftp://ftp.is.co.za/rfc/rfc1808.txt",
|
||||||
|
u"http://www.ietf.org/rfc/rfc2396.txt",
|
||||||
|
u"ldap://[2001:db8::7]/c=GB?objectClass?one",
|
||||||
|
u"mailto:John.Doe@example.com",
|
||||||
|
u"news:comp.infosystems.www.servers.unix",
|
||||||
|
u"tel:+1-816-555-1212",
|
||||||
|
u"telnet://192.0.2.16:80/",
|
||||||
|
u"urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ]
|
||||||
|
for uri in invariant:
|
||||||
|
self.assertEqual(uri, iri2uri(uri))
|
||||||
|
|
||||||
|
def test_iri(self):
|
||||||
|
""" Test that the right type of escaping is done for each part of the URI."""
|
||||||
|
self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri(u"http://\N{COMET}.com/\N{COMET}"))
|
||||||
|
self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri(u"http://bitworking.org/?fred=\N{COMET}"))
|
||||||
|
self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri(u"http://bitworking.org/#\N{COMET}"))
|
||||||
|
self.assertEqual("#%E2%98%84", iri2uri(u"#\N{COMET}"))
|
||||||
|
self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))
|
||||||
|
self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")))
|
||||||
|
self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8')))
|
||||||
|
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
|
438
python/plugins/sextante/servertools/httplib2/socks.py
Normal file
438
python/plugins/sextante/servertools/httplib2/socks.py
Normal file
@ -0,0 +1,438 @@
|
|||||||
|
"""SocksiPy - Python SOCKS module.
|
||||||
|
Version 1.00
|
||||||
|
|
||||||
|
Copyright 2006 Dan-Haim. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
3. Neither the name of Dan Haim nor the names of his contributors may be used
|
||||||
|
to endorse or promote products derived from this software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||||
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
|
||||||
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
|
||||||
|
|
||||||
|
|
||||||
|
This module provides a standard socket-like interface for Python
|
||||||
|
for tunneling connections through SOCKS proxies.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
|
||||||
|
for use in PyLoris (http://pyloris.sourceforge.net/)
|
||||||
|
|
||||||
|
Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
|
||||||
|
mainly to merge bug fixes found in Sourceforge
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if getattr(socket, 'socket', None) is None:
|
||||||
|
raise ImportError('socket.socket missing, proxy support unusable')
|
||||||
|
|
||||||
|
PROXY_TYPE_SOCKS4 = 1
|
||||||
|
PROXY_TYPE_SOCKS5 = 2
|
||||||
|
PROXY_TYPE_HTTP = 3
|
||||||
|
PROXY_TYPE_HTTP_NO_TUNNEL = 4
|
||||||
|
|
||||||
|
_defaultproxy = None
|
||||||
|
_orgsocket = socket.socket
|
||||||
|
|
||||||
|
class ProxyError(Exception): pass
|
||||||
|
class GeneralProxyError(ProxyError): pass
|
||||||
|
class Socks5AuthError(ProxyError): pass
|
||||||
|
class Socks5Error(ProxyError): pass
|
||||||
|
class Socks4Error(ProxyError): pass
|
||||||
|
class HTTPError(ProxyError): pass
|
||||||
|
|
||||||
|
_generalerrors = ("success",
|
||||||
|
"invalid data",
|
||||||
|
"not connected",
|
||||||
|
"not available",
|
||||||
|
"bad proxy type",
|
||||||
|
"bad input")
|
||||||
|
|
||||||
|
_socks5errors = ("succeeded",
|
||||||
|
"general SOCKS server failure",
|
||||||
|
"connection not allowed by ruleset",
|
||||||
|
"Network unreachable",
|
||||||
|
"Host unreachable",
|
||||||
|
"Connection refused",
|
||||||
|
"TTL expired",
|
||||||
|
"Command not supported",
|
||||||
|
"Address type not supported",
|
||||||
|
"Unknown error")
|
||||||
|
|
||||||
|
_socks5autherrors = ("succeeded",
|
||||||
|
"authentication is required",
|
||||||
|
"all offered authentication methods were rejected",
|
||||||
|
"unknown username or invalid password",
|
||||||
|
"unknown error")
|
||||||
|
|
||||||
|
_socks4errors = ("request granted",
|
||||||
|
"request rejected or failed",
|
||||||
|
"request rejected because SOCKS server cannot connect to identd on the client",
|
||||||
|
"request rejected because the client program and identd report different user-ids",
|
||||||
|
"unknown error")
|
||||||
|
|
||||||
|
def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
|
||||||
|
"""setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
|
||||||
|
Sets a default proxy which all further socksocket objects will use,
|
||||||
|
unless explicitly changed.
|
||||||
|
"""
|
||||||
|
global _defaultproxy
|
||||||
|
_defaultproxy = (proxytype, addr, port, rdns, username, password)
|
||||||
|
|
||||||
|
def wrapmodule(module):
|
||||||
|
"""wrapmodule(module)
|
||||||
|
Attempts to replace a module's socket library with a SOCKS socket. Must set
|
||||||
|
a default proxy using setdefaultproxy(...) first.
|
||||||
|
This will only work on modules that import socket directly into the namespace;
|
||||||
|
most of the Python Standard Library falls into this category.
|
||||||
|
"""
|
||||||
|
if _defaultproxy != None:
|
||||||
|
module.socket.socket = socksocket
|
||||||
|
else:
|
||||||
|
raise GeneralProxyError((4, "no proxy specified"))
|
||||||
|
|
||||||
|
class socksocket(socket.socket):
|
||||||
|
"""socksocket([family[, type[, proto]]]) -> socket object
|
||||||
|
Open a SOCKS enabled socket. The parameters are the same as
|
||||||
|
those of the standard socket init. In order for SOCKS to work,
|
||||||
|
you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
|
||||||
|
_orgsocket.__init__(self, family, type, proto, _sock)
|
||||||
|
if _defaultproxy != None:
|
||||||
|
self.__proxy = _defaultproxy
|
||||||
|
else:
|
||||||
|
self.__proxy = (None, None, None, None, None, None)
|
||||||
|
self.__proxysockname = None
|
||||||
|
self.__proxypeername = None
|
||||||
|
self.__httptunnel = True
|
||||||
|
|
||||||
|
def __recvall(self, count):
|
||||||
|
"""__recvall(count) -> data
|
||||||
|
Receive EXACTLY the number of bytes requested from the socket.
|
||||||
|
Blocks until the required number of bytes have been received.
|
||||||
|
"""
|
||||||
|
data = self.recv(count)
|
||||||
|
while len(data) < count:
|
||||||
|
d = self.recv(count-len(data))
|
||||||
|
if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
|
||||||
|
data = data + d
|
||||||
|
return data
|
||||||
|
|
||||||
|
def sendall(self, content, *args):
|
||||||
|
""" override socket.socket.sendall method to rewrite the header
|
||||||
|
for non-tunneling proxies if needed
|
||||||
|
"""
|
||||||
|
if not self.__httptunnel:
|
||||||
|
content = self.__rewriteproxy(content)
|
||||||
|
return super(socksocket, self).sendall(content, *args)
|
||||||
|
|
||||||
|
def __rewriteproxy(self, header):
|
||||||
|
""" rewrite HTTP request headers to support non-tunneling proxies
|
||||||
|
(i.e. those which do not support the CONNECT method).
|
||||||
|
This only works for HTTP (not HTTPS) since HTTPS requires tunneling.
|
||||||
|
"""
|
||||||
|
host, endpt = None, None
|
||||||
|
hdrs = header.split("\r\n")
|
||||||
|
for hdr in hdrs:
|
||||||
|
if hdr.lower().startswith("host:"):
|
||||||
|
host = hdr
|
||||||
|
elif hdr.lower().startswith("get") or hdr.lower().startswith("post"):
|
||||||
|
endpt = hdr
|
||||||
|
if host and endpt:
|
||||||
|
hdrs.remove(host)
|
||||||
|
hdrs.remove(endpt)
|
||||||
|
host = host.split(" ")[1]
|
||||||
|
endpt = endpt.split(" ")
|
||||||
|
if (self.__proxy[4] != None and self.__proxy[5] != None):
|
||||||
|
hdrs.insert(0, self.__getauthheader())
|
||||||
|
hdrs.insert(0, "Host: %s" % host)
|
||||||
|
hdrs.insert(0, "%s http://%s%s %s" % (endpt[0], host, endpt[1], endpt[2]))
|
||||||
|
return "\r\n".join(hdrs)
|
||||||
|
|
||||||
|
def __getauthheader(self):
|
||||||
|
auth = self.__proxy[4] + ":" + self.__proxy[5]
|
||||||
|
return "Proxy-Authorization: Basic " + base64.b64encode(auth)
|
||||||
|
|
||||||
|
def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
|
||||||
|
"""setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
|
||||||
|
Sets the proxy to be used.
|
||||||
|
proxytype - The type of the proxy to be used. Three types
|
||||||
|
are supported: PROXY_TYPE_SOCKS4 (including socks4a),
|
||||||
|
PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
|
||||||
|
addr - The address of the server (IP or DNS).
|
||||||
|
port - The port of the server. Defaults to 1080 for SOCKS
|
||||||
|
servers and 8080 for HTTP proxy servers.
|
||||||
|
rdns - Should DNS queries be preformed on the remote side
|
||||||
|
(rather than the local side). The default is True.
|
||||||
|
Note: This has no effect with SOCKS4 servers.
|
||||||
|
username - Username to authenticate with to the server.
|
||||||
|
The default is no authentication.
|
||||||
|
password - Password to authenticate with to the server.
|
||||||
|
Only relevant when username is also provided.
|
||||||
|
"""
|
||||||
|
self.__proxy = (proxytype, addr, port, rdns, username, password)
|
||||||
|
|
||||||
|
def __negotiatesocks5(self, destaddr, destport):
|
||||||
|
"""__negotiatesocks5(self,destaddr,destport)
|
||||||
|
Negotiates a connection through a SOCKS5 server.
|
||||||
|
"""
|
||||||
|
# First we'll send the authentication packages we support.
|
||||||
|
if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
|
||||||
|
# The username/password details were supplied to the
|
||||||
|
# setproxy method so we support the USERNAME/PASSWORD
|
||||||
|
# authentication (in addition to the standard none).
|
||||||
|
self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
|
||||||
|
else:
|
||||||
|
# No username/password were entered, therefore we
|
||||||
|
# only support connections with no authentication.
|
||||||
|
self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
|
||||||
|
# We'll receive the server's response to determine which
|
||||||
|
# method was selected
|
||||||
|
chosenauth = self.__recvall(2)
|
||||||
|
if chosenauth[0:1] != chr(0x05).encode():
|
||||||
|
self.close()
|
||||||
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
|
# Check the chosen authentication method
|
||||||
|
if chosenauth[1:2] == chr(0x00).encode():
|
||||||
|
# No authentication is required
|
||||||
|
pass
|
||||||
|
elif chosenauth[1:2] == chr(0x02).encode():
|
||||||
|
# Okay, we need to perform a basic username/password
|
||||||
|
# authentication.
|
||||||
|
self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
|
||||||
|
authstat = self.__recvall(2)
|
||||||
|
if authstat[0:1] != chr(0x01).encode():
|
||||||
|
# Bad response
|
||||||
|
self.close()
|
||||||
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
|
if authstat[1:2] != chr(0x00).encode():
|
||||||
|
# Authentication failed
|
||||||
|
self.close()
|
||||||
|
raise Socks5AuthError((3, _socks5autherrors[3]))
|
||||||
|
# Authentication succeeded
|
||||||
|
else:
|
||||||
|
# Reaching here is always bad
|
||||||
|
self.close()
|
||||||
|
if chosenauth[1] == chr(0xFF).encode():
|
||||||
|
raise Socks5AuthError((2, _socks5autherrors[2]))
|
||||||
|
else:
|
||||||
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
|
# Now we can request the actual connection
|
||||||
|
req = struct.pack('BBB', 0x05, 0x01, 0x00)
|
||||||
|
# If the given destination address is an IP address, we'll
|
||||||
|
# use the IPv4 address request even if remote resolving was specified.
|
||||||
|
try:
|
||||||
|
ipaddr = socket.inet_aton(destaddr)
|
||||||
|
req = req + chr(0x01).encode() + ipaddr
|
||||||
|
except socket.error:
|
||||||
|
# Well it's not an IP number, so it's probably a DNS name.
|
||||||
|
if self.__proxy[3]:
|
||||||
|
# Resolve remotely
|
||||||
|
ipaddr = None
|
||||||
|
req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr
|
||||||
|
else:
|
||||||
|
# Resolve locally
|
||||||
|
ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
|
||||||
|
req = req + chr(0x01).encode() + ipaddr
|
||||||
|
req = req + struct.pack(">H", destport)
|
||||||
|
self.sendall(req)
|
||||||
|
# Get the response
|
||||||
|
resp = self.__recvall(4)
|
||||||
|
if resp[0:1] != chr(0x05).encode():
|
||||||
|
self.close()
|
||||||
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
|
elif resp[1:2] != chr(0x00).encode():
|
||||||
|
# Connection failed
|
||||||
|
self.close()
|
||||||
|
if ord(resp[1:2])<=8:
|
||||||
|
raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
|
||||||
|
else:
|
||||||
|
raise Socks5Error((9, _socks5errors[9]))
|
||||||
|
# Get the bound address/port
|
||||||
|
elif resp[3:4] == chr(0x01).encode():
|
||||||
|
boundaddr = self.__recvall(4)
|
||||||
|
elif resp[3:4] == chr(0x03).encode():
|
||||||
|
resp = resp + self.recv(1)
|
||||||
|
boundaddr = self.__recvall(ord(resp[4:5]))
|
||||||
|
else:
|
||||||
|
self.close()
|
||||||
|
raise GeneralProxyError((1,_generalerrors[1]))
|
||||||
|
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
||||||
|
self.__proxysockname = (boundaddr, boundport)
|
||||||
|
if ipaddr != None:
|
||||||
|
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
||||||
|
else:
|
||||||
|
self.__proxypeername = (destaddr, destport)
|
||||||
|
|
||||||
|
def getproxysockname(self):
|
||||||
|
"""getsockname() -> address info
|
||||||
|
Returns the bound IP address and port number at the proxy.
|
||||||
|
"""
|
||||||
|
return self.__proxysockname
|
||||||
|
|
||||||
|
def getproxypeername(self):
|
||||||
|
"""getproxypeername() -> address info
|
||||||
|
Returns the IP and port number of the proxy.
|
||||||
|
"""
|
||||||
|
return _orgsocket.getpeername(self)
|
||||||
|
|
||||||
|
def getpeername(self):
|
||||||
|
"""getpeername() -> address info
|
||||||
|
Returns the IP address and port number of the destination
|
||||||
|
machine (note: getproxypeername returns the proxy)
|
||||||
|
"""
|
||||||
|
return self.__proxypeername
|
||||||
|
|
||||||
|
def __negotiatesocks4(self,destaddr,destport):
|
||||||
|
"""__negotiatesocks4(self,destaddr,destport)
|
||||||
|
Negotiates a connection through a SOCKS4 server.
|
||||||
|
"""
|
||||||
|
# Check if the destination address provided is an IP address
|
||||||
|
rmtrslv = False
|
||||||
|
try:
|
||||||
|
ipaddr = socket.inet_aton(destaddr)
|
||||||
|
except socket.error:
|
||||||
|
# It's a DNS name. Check where it should be resolved.
|
||||||
|
if self.__proxy[3]:
|
||||||
|
ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
|
||||||
|
rmtrslv = True
|
||||||
|
else:
|
||||||
|
ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
|
||||||
|
# Construct the request packet
|
||||||
|
req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
|
||||||
|
# The username parameter is considered userid for SOCKS4
|
||||||
|
if self.__proxy[4] != None:
|
||||||
|
req = req + self.__proxy[4]
|
||||||
|
req = req + chr(0x00).encode()
|
||||||
|
# DNS name if remote resolving is required
|
||||||
|
# NOTE: This is actually an extension to the SOCKS4 protocol
|
||||||
|
# called SOCKS4A and may not be supported in all cases.
|
||||||
|
if rmtrslv:
|
||||||
|
req = req + destaddr + chr(0x00).encode()
|
||||||
|
self.sendall(req)
|
||||||
|
# Get the response from the server
|
||||||
|
resp = self.__recvall(8)
|
||||||
|
if resp[0:1] != chr(0x00).encode():
|
||||||
|
# Bad data
|
||||||
|
self.close()
|
||||||
|
raise GeneralProxyError((1,_generalerrors[1]))
|
||||||
|
if resp[1:2] != chr(0x5A).encode():
|
||||||
|
# Server returned an error
|
||||||
|
self.close()
|
||||||
|
if ord(resp[1:2]) in (91, 92, 93):
|
||||||
|
self.close()
|
||||||
|
raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
|
||||||
|
else:
|
||||||
|
raise Socks4Error((94, _socks4errors[4]))
|
||||||
|
# Get the bound address/port
|
||||||
|
self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
|
||||||
|
if rmtrslv != None:
|
||||||
|
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
||||||
|
else:
|
||||||
|
self.__proxypeername = (destaddr, destport)
|
||||||
|
|
||||||
|
def __negotiatehttp(self, destaddr, destport):
|
||||||
|
"""__negotiatehttp(self,destaddr,destport)
|
||||||
|
Negotiates a connection through an HTTP server.
|
||||||
|
"""
|
||||||
|
# If we need to resolve locally, we do this now
|
||||||
|
if not self.__proxy[3]:
|
||||||
|
addr = socket.gethostbyname(destaddr)
|
||||||
|
else:
|
||||||
|
addr = destaddr
|
||||||
|
headers = ["CONNECT ", addr, ":", str(destport), " HTTP/1.1\r\n"]
|
||||||
|
headers += ["Host: ", destaddr, "\r\n"]
|
||||||
|
if (self.__proxy[4] != None and self.__proxy[5] != None):
|
||||||
|
headers += [self.__getauthheader(), "\r\n"]
|
||||||
|
headers.append("\r\n")
|
||||||
|
self.sendall("".join(headers).encode())
|
||||||
|
# We read the response until we get the string "\r\n\r\n"
|
||||||
|
resp = self.recv(1)
|
||||||
|
while resp.find("\r\n\r\n".encode()) == -1:
|
||||||
|
resp = resp + self.recv(1)
|
||||||
|
# We just need the first line to check if the connection
|
||||||
|
# was successful
|
||||||
|
statusline = resp.splitlines()[0].split(" ".encode(), 2)
|
||||||
|
if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
|
||||||
|
self.close()
|
||||||
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
|
try:
|
||||||
|
statuscode = int(statusline[1])
|
||||||
|
except ValueError:
|
||||||
|
self.close()
|
||||||
|
raise GeneralProxyError((1, _generalerrors[1]))
|
||||||
|
if statuscode != 200:
|
||||||
|
self.close()
|
||||||
|
raise HTTPError((statuscode, statusline[2]))
|
||||||
|
self.__proxysockname = ("0.0.0.0", 0)
|
||||||
|
self.__proxypeername = (addr, destport)
|
||||||
|
|
||||||
|
def connect(self, destpair):
|
||||||
|
"""connect(self, despair)
|
||||||
|
Connects to the specified destination through a proxy.
|
||||||
|
destpar - A tuple of the IP/DNS address and the port number.
|
||||||
|
(identical to socket's connect).
|
||||||
|
To select the proxy server use setproxy().
|
||||||
|
"""
|
||||||
|
# Do a minimal input check first
|
||||||
|
if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (not isinstance(destpair[0], basestring)) or (type(destpair[1]) != int):
|
||||||
|
raise GeneralProxyError((5, _generalerrors[5]))
|
||||||
|
if self.__proxy[0] == PROXY_TYPE_SOCKS5:
|
||||||
|
if self.__proxy[2] != None:
|
||||||
|
portnum = self.__proxy[2]
|
||||||
|
else:
|
||||||
|
portnum = 1080
|
||||||
|
_orgsocket.connect(self, (self.__proxy[1], portnum))
|
||||||
|
self.__negotiatesocks5(destpair[0], destpair[1])
|
||||||
|
elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
|
||||||
|
if self.__proxy[2] != None:
|
||||||
|
portnum = self.__proxy[2]
|
||||||
|
else:
|
||||||
|
portnum = 1080
|
||||||
|
_orgsocket.connect(self,(self.__proxy[1], portnum))
|
||||||
|
self.__negotiatesocks4(destpair[0], destpair[1])
|
||||||
|
elif self.__proxy[0] == PROXY_TYPE_HTTP:
|
||||||
|
if self.__proxy[2] != None:
|
||||||
|
portnum = self.__proxy[2]
|
||||||
|
else:
|
||||||
|
portnum = 8080
|
||||||
|
_orgsocket.connect(self,(self.__proxy[1], portnum))
|
||||||
|
self.__negotiatehttp(destpair[0], destpair[1])
|
||||||
|
elif self.__proxy[0] == PROXY_TYPE_HTTP_NO_TUNNEL:
|
||||||
|
if self.__proxy[2] != None:
|
||||||
|
portnum = self.__proxy[2]
|
||||||
|
else:
|
||||||
|
portnum = 8080
|
||||||
|
_orgsocket.connect(self,(self.__proxy[1],portnum))
|
||||||
|
if destpair[1] == 443:
|
||||||
|
self.__negotiatehttp(destpair[0],destpair[1])
|
||||||
|
else:
|
||||||
|
self.__httptunnel = False
|
||||||
|
elif self.__proxy[0] == None:
|
||||||
|
_orgsocket.connect(self, (destpair[0], destpair[1]))
|
||||||
|
else:
|
||||||
|
raise GeneralProxyError((4, _generalerrors[4]))
|
@ -1,104 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
***************************************************************************
|
|
||||||
ExampleAlgorithm.py
|
|
||||||
---------------------
|
|
||||||
Date : August 2012
|
|
||||||
Copyright : (C) 2012 by Tim Sutton
|
|
||||||
Email : tim at linfiniti dot com
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
"""
|
|
||||||
|
|
||||||
__author__ = 'Tim Sutton'
|
|
||||||
__date__ = 'August 2012'
|
|
||||||
__copyright__ = '(C) 2012, Tim Sutton'
|
|
||||||
# This will get replaced with a git SHA1 when you do a git archive
|
|
||||||
__revision__ = '$Format:%H$'
|
|
||||||
|
|
||||||
from sextante.core.GeoAlgorithm import GeoAlgorithm
|
|
||||||
from sextante.outputs.OutputVector import OutputVector
|
|
||||||
from sextante.parameters.ParameterVector import ParameterVector
|
|
||||||
from sextante.core.Sextante import Sextante
|
|
||||||
from qgis.core import *
|
|
||||||
from PyQt4.QtCore import *
|
|
||||||
from PyQt4.QtGui import *
|
|
||||||
from sextante.parameters.ParameterExtent import ParameterExtent
|
|
||||||
from sextante.parameters.ParameterCrs import ParameterCrs
|
|
||||||
|
|
||||||
|
|
||||||
class ExampleAlgorithm(GeoAlgorithm):
|
|
||||||
'''This is an example algorithm that takes a vector layer and creates
|
|
||||||
a new one just with just those features of the input layer that are
|
|
||||||
selected.
|
|
||||||
It is meant to be used as an example of how to create your own SEXTANTE
|
|
||||||
algorithms and explain methods and variables used to do it.
|
|
||||||
An algorithm like this will be available in all SEXTANTE elements, and
|
|
||||||
there is not need for additional work.
|
|
||||||
|
|
||||||
All SEXTANTE algorithms should extend the GeoAlgorithm class'''
|
|
||||||
|
|
||||||
#constants used to refer to parameters and outputs.
|
|
||||||
#They will be used when calling the algorithm from another algorithm,
|
|
||||||
#or when calling SEXTANTE from the QGIS console.
|
|
||||||
OUTPUT_LAYER = "OUTPUT_LAYER"
|
|
||||||
INPUT_LAYER = "INPUT_LAYER"
|
|
||||||
|
|
||||||
def defineCharacteristics(self):
|
|
||||||
'''Here we define the inputs and output of the algorithm, along
|
|
||||||
with some other properties'''
|
|
||||||
|
|
||||||
#the name that the user will see in the toolbox
|
|
||||||
self.name = "Create new layer with selected features"
|
|
||||||
|
|
||||||
#the branch of the toolbox under which the algorithm will appear
|
|
||||||
self.group = "Algorithms for vector layers"
|
|
||||||
|
|
||||||
#we add the input vector layer. It can have any kind of geometry
|
|
||||||
#It is a mandatory (not optional) one, hence the False argument
|
|
||||||
self.addParameter(ParameterVector(self.INPUT_LAYER, "Input layer", ParameterVector.VECTOR_TYPE_ANY, False))
|
|
||||||
self.addParameter(ParameterExtent("EXTENT","EXTENT"))
|
|
||||||
self.addParameter(ParameterCrs("CRS", "CRS"))
|
|
||||||
# we add a vector layer as output
|
|
||||||
self.addOutput(OutputVector(self.OUTPUT_LAYER, "Output layer with selected features"))
|
|
||||||
|
|
||||||
|
|
||||||
def processAlgorithm(self, progress):
|
|
||||||
'''Here is where the processing itself takes place'''
|
|
||||||
|
|
||||||
#the first thing to do is retrieve the values of the parameters
|
|
||||||
#entered by the user
|
|
||||||
inputFilename = self.getParameterValue(self.INPUT_LAYER)
|
|
||||||
output = self.getOutputValue(self.OUTPUT_LAYER)
|
|
||||||
|
|
||||||
#input layers values are always a string with its location.
|
|
||||||
#That string can be converted into a QGIS object (a QgsVectorLayer in this case))
|
|
||||||
#using the Sextante.getObject() method
|
|
||||||
vectorLayer = Sextante.getObject(inputFilename)
|
|
||||||
|
|
||||||
#And now we can process
|
|
||||||
|
|
||||||
#First we create the output layer.
|
|
||||||
#The output value entered by the user is a string containing a filename,
|
|
||||||
#so we can use it directly
|
|
||||||
settings = QSettings()
|
|
||||||
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
|
|
||||||
provider = vectorLayer.dataProvider()
|
|
||||||
writer = QgsVectorFileWriter( output, systemEncoding, provider.fields(), provider.geometryType(), provider.crs() )
|
|
||||||
|
|
||||||
#Now we take the selected features and add them to the output layer
|
|
||||||
selection = vectorLayer.selectedFeatures()
|
|
||||||
for feat in selection:
|
|
||||||
writer.addFeature(feat)
|
|
||||||
del writer
|
|
||||||
|
|
||||||
#There is nothing more to do here. We do not have to open the layer that we have created.
|
|
||||||
#SEXTANTE will take care of that, or will handle it if this algorithm is executed within
|
|
||||||
#a complex model
|
|
@ -1,78 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
***************************************************************************
|
|
||||||
ExampleAlgorithmProvider.py
|
|
||||||
---------------------
|
|
||||||
Date : August 2012
|
|
||||||
Copyright : (C) 2012 by Tim Sutton
|
|
||||||
Email : tim at linfiniti dot com
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
"""
|
|
||||||
|
|
||||||
__author__ = 'Tim Sutton'
|
|
||||||
__date__ = 'August 2012'
|
|
||||||
__copyright__ = '(C) 2012, Tim Sutton'
|
|
||||||
# This will get replaced with a git SHA1 when you do a git archive
|
|
||||||
__revision__ = '$Format:%H$'
|
|
||||||
|
|
||||||
from sextante.core.AlgorithmProvider import AlgorithmProvider
|
|
||||||
from sextanteexampleprovider.ExampleAlgorithm import ExampleAlgorithm
|
|
||||||
from sextante.core.SextanteConfig import Setting, SextanteConfig
|
|
||||||
|
|
||||||
class ExampleAlgorithmProvider(AlgorithmProvider):
|
|
||||||
|
|
||||||
MY_DUMMY_SETTING = "MY_DUMMY_SETTING"
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
AlgorithmProvider.__init__(self)
|
|
||||||
self.alglist = [ExampleAlgorithm()]
|
|
||||||
|
|
||||||
def initializeSettings(self):
|
|
||||||
'''In this method we add settings needed to configure our provider.
|
|
||||||
Do not forget to call the parent method, since it takes care or
|
|
||||||
automatically adding a setting for activating or deactivating the
|
|
||||||
algorithms in the provider'''
|
|
||||||
AlgorithmProvider.initializeSettings(self)
|
|
||||||
SextanteConfig.addSetting(Setting("Example algorithms", ExampleAlgorithmProvider.MY_DUMMY_SETTING, "Example setting", "Default value"))
|
|
||||||
'''To get the parameter of a setting parameter, use SextanteConfig.getSetting(name_of_parameter)'''
|
|
||||||
|
|
||||||
def unload(self):
|
|
||||||
'''Setting should be removed here, so they do not appear anymore
|
|
||||||
when the plugin is unloaded'''
|
|
||||||
AlgorithmProvider.unload(self)
|
|
||||||
SextanteConfig.removeSetting( ExampleAlgorithmProvider.MY_DUMMY_SETTING)
|
|
||||||
|
|
||||||
|
|
||||||
def getName(self):
|
|
||||||
'''This name is used to create the command line name of all the algorithms
|
|
||||||
from this provider'''
|
|
||||||
return "exampleprovider"
|
|
||||||
|
|
||||||
def getDescription(self):
|
|
||||||
'''This is the name that will appear on the toolbox group.'''
|
|
||||||
return "Example algorithms"
|
|
||||||
|
|
||||||
def getIcon(self):
|
|
||||||
'''We return the default icon'''
|
|
||||||
return AlgorithmProvider.getIcon(self)
|
|
||||||
|
|
||||||
|
|
||||||
def _loadAlgorithms(self):
|
|
||||||
'''Here we fill the list of algorithms in self.algs.
|
|
||||||
This method is called whenever the list of algorithms should be updated.
|
|
||||||
If the list of algorithms can change while executing SEXTANTE for QGIS
|
|
||||||
(for instance, if it contains algorithms from user-defined scripts and
|
|
||||||
a new script might have been added), you should create the list again
|
|
||||||
here.
|
|
||||||
In this case, since the list is always the same, we assign from the pre-made list.
|
|
||||||
This assignment has to be done in this method even if the list does not change,
|
|
||||||
since the self.algs list is cleared before calling this method'''
|
|
||||||
self.algs = self.alglist
|
|
@ -1,46 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
***************************************************************************
|
|
||||||
SextanteExampleProviderPlugin.py
|
|
||||||
---------------------
|
|
||||||
Date : August 2012
|
|
||||||
Copyright : (C) 2012 by Tim Sutton
|
|
||||||
Email : tim at linfiniti dot com
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* 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 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
"""
|
|
||||||
|
|
||||||
__author__ = 'Tim Sutton'
|
|
||||||
__date__ = 'August 2012'
|
|
||||||
__copyright__ = '(C) 2012, Tim Sutton'
|
|
||||||
# This will get replaced with a git SHA1 when you do a git archive
|
|
||||||
__revision__ = '$Format:%H$'
|
|
||||||
|
|
||||||
from qgis.core import *
|
|
||||||
import os, sys
|
|
||||||
import inspect
|
|
||||||
from sextante.core.Sextante import Sextante
|
|
||||||
from sextanteexampleprovider.ExampleAlgorithmProvider import ExampleAlgorithmProvider
|
|
||||||
|
|
||||||
|
|
||||||
cmd_folder = os.path.split(inspect.getfile( inspect.currentframe() ))[0]
|
|
||||||
if cmd_folder not in sys.path:
|
|
||||||
sys.path.insert(0, cmd_folder)
|
|
||||||
|
|
||||||
class SextanteExampleProviderPlugin:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.provider = ExampleAlgorithmProvider()
|
|
||||||
def initGui(self):
|
|
||||||
Sextante.addProvider(self.provider)
|
|
||||||
|
|
||||||
def unload(self):
|
|
||||||
Sextante.removeProvider(self.provider)
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
[general]
|
|
||||||
name=SEXTANTE Example Provider
|
|
||||||
description=An example plugin that adds algorithms to SEXTANTE. Mainly created to guide developers in the process of creating plugins that add new capabilities to SEXTANTE
|
|
||||||
version=1.0
|
|
||||||
qgisMinimumVersion=1.0
|
|
||||||
|
|
||||||
name=Victor Olaya
|
|
||||||
email=volayaf@gmail.com
|
|
||||||
website=www.sextantegis.com
|
|
||||||
|
|
||||||
class_name=SextanteExampleProviderPlugin
|
|
Loading…
x
Reference in New Issue
Block a user