diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6bdf0fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +.DS_Store +*.[56789ao] +*.a[56789o] +*.so +*.pyc +._* +.nfs.* +[56789a].out +*~ +*.orig +*.rej +*.exe +.*.swp +core +*.cgo*.go +*.cgo*.c +_cgo_* +_obj +_test +_testmain.go + +/VERSION.cache +/bin/ +/build.out +/doc/articles/wiki/*.bin +/goinstall.log +/last-change +/misc/cgo/life/run.out +/misc/cgo/stdio/run.out +/misc/cgo/testso/main +/pkg/ +/src/*.*/ +/src/cmd/cgo/zdefaultcc.go +/src/cmd/dist/dist +/src/cmd/go/internal/cfg/zdefaultcc.go +/src/cmd/go/internal/cfg/zosarch.go +/src/cmd/internal/objabi/zbootstrap.go +/src/go/build/zcgo.go +/src/go/doc/headscan +/src/runtime/internal/sys/zversion.go +/src/unicode/maketables +/test.out +/test/garbage/*.out +/test/pass.out +/test/run.out +/test/times.out + +# This file includes artifacts of Go build that should not be checked in. +# For files created by specific development environment (e.g. editor), +# use alternative ways to exclude files from git. +# For example, set up .git/info/exclude or use a global .gitignore. + +loca_config.yaml \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bbf71c6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2018 Hisham Karam + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e095bcd --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# GisManager +Publish Your Gis Data to Postgis and Geoserver diff --git a/datastore.go b/datastore.go new file mode 100644 index 0000000..a887ab7 --- /dev/null +++ b/datastore.go @@ -0,0 +1,16 @@ +package gismanager + +import "fmt" + +type datastore struct { + Host string `yaml:"host"` + Port uint `yaml:"port"` + DBName string `yaml:"database"` + DBUser string `yaml:"username"` + DBPass string `yaml:"password"` + Name string `yaml:"name"` +} + +func (ds *datastore) BuildConnectionString() string { + return fmt.Sprintf("PG: host=%s port=%d dbname=%s user=%s password=%s", ds.Host, ds.Port, ds.DBName, ds.DBUser, ds.DBPass) +} diff --git a/example/config.yaml b/example/config.yaml new file mode 100644 index 0000000..4673f0c --- /dev/null +++ b/example/config.yaml @@ -0,0 +1,14 @@ +geoserver: + url: http://localhost/geoserver + username: admin + password: geoserver + workspace: 'sample_workspace' +datastore: + host: localhost + port: 5432 + database: gis_data + username: db_user + password: db_pass + name: geoserver_datastore +source: + path: /xx/xx/xx/x.gpkg \ No newline at end of file diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..99f82b4 --- /dev/null +++ b/example/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "errors" + "flag" + "os" + + "github.com/hishamkaram/gismanager" +) + +func main() { + logger := gismanager.GetLogger() + configFile := flag.String("config", "", "Config File") + flag.Parse() + if *configFile == "" { + panic(errors.New("config 'Parameter required'")) + } + if _, err := os.Stat(*configFile); os.IsNotExist(err) { + panic(errors.New("Config File Doesn't exist")) + } + manager, confErr := gismanager.FromConfig(*configFile) + if confErr != nil { + panic(confErr) + } + source, ok := manager.OpenSource(manager.Source.Path, 0) + targetSource, targetOK := manager.OpenSource(manager.Datastore.BuildConnectionString(), 1) + if ok && targetOK { + for index := 0; index < source.LayerCount(); index++ { + layer := source.LayerByIndex(index) + gLayer := gismanager.GdalLayer{ + Layer: &layer, + } + if newLayer := gLayer.LayerToPostgis(targetSource); newLayer.Layer != nil { + ok, pubErr := manager.PublishGeoserverLayer(newLayer) + if pubErr != nil { + logger.Error(pubErr) + } + if !ok { + logger.Error("Failed to Publish") + } else { + logger.Info("published") + } + } + + } + } +} diff --git a/layer.go b/layer.go new file mode 100644 index 0000000..ad18dfe --- /dev/null +++ b/layer.go @@ -0,0 +1,23 @@ +package gismanager + +import ( + "fmt" + + "github.com/lukeroth/gdal" +) + +//GdalLayer Layer +type GdalLayer struct { + *gdal.Layer +} + +//LayerToPostgis Layer to Postgis +func (layer *GdalLayer) LayerToPostgis(targetSource gdal.DataSource) (newLayer *GdalLayer) { + if layer.Layer != nil { + _layer := targetSource.CopyLayer(*layer.Layer, layer.Name(), []string{fmt.Sprintf("GEOMETRY_NAME=%s", layer.GeometryColumn())}) + newLayer = &GdalLayer{ + Layer: &_layer, + } + } + return +} diff --git a/log.go b/log.go new file mode 100644 index 0000000..3e0f9e8 --- /dev/null +++ b/log.go @@ -0,0 +1,13 @@ +package gismanager + +import "github.com/sirupsen/logrus" + +//GetLogger return logger +func GetLogger() (logger *logrus.Logger) { + logger = logrus.New() + Formatter := new(logrus.TextFormatter) + Formatter.TimestampFormat = "02-01-2006 15:04:05" + Formatter.FullTimestamp = true + logger.Formatter = Formatter + return +} diff --git a/manager.go b/manager.go new file mode 100644 index 0000000..850e701 --- /dev/null +++ b/manager.go @@ -0,0 +1,87 @@ +package gismanager + +import ( + "errors" + "path/filepath" + "strings" + + gsconfig "github.com/hishamkaram/geoserver" + "github.com/lukeroth/gdal" + "github.com/sirupsen/logrus" +) + +type geoserver struct { + WorkspaceName string `yaml:"workspace"` + ServerURL string `yaml:"url"` + Username string `yaml:"username"` + Password string `yaml:"password"` +} + +type source struct { + Path string `yaml:"path"` +} + +//ManagerConfig is the configuration Object +type ManagerConfig struct { + Geoserver geoserver `yaml:"geoserver"` + Datastore datastore `yaml:"datastore"` + Source source `yaml:"source"` + logger *logrus.Logger +} + +//GetGeoserverCatalog publish return geoserver Catalog +func (manager *ManagerConfig) GetGeoserverCatalog() *gsconfig.GeoServer { + gsCatalog := gsconfig.GetCatalog(manager.Geoserver.ServerURL, manager.Geoserver.Username, manager.Geoserver.Password) + return gsCatalog +} + +//PublishGeoserverLayer publish Layer to postgis +func (manager *ManagerConfig) PublishGeoserverLayer(layer *GdalLayer) (ok bool, err error) { + if layer != nil { + gsCatalog := manager.GetGeoserverCatalog() + exists, storeErr := gsCatalog.DatastoreExists(manager.Geoserver.WorkspaceName, manager.Datastore.Name, true) + if storeErr != nil { + err = storeErr + } + if exists { + ok, err = gsCatalog.PublishPostgisLayer(manager.Geoserver.WorkspaceName, manager.Datastore.Name, layer.Name(), layer.Name()) + } + } + return +} + +//OpenSource open Datasource +func (manager *ManagerConfig) OpenSource(path string, access int) (source gdal.DataSource, ok bool) { + driver, err := manager.GetDriver(path) + if err != nil { + panic(err) + } + source, ok = driver.Open(path, access) + return +} + +//GetDriver open Datasource +func (manager *ManagerConfig) GetDriver(path string) (driver gdal.OGRDriver, err error) { + if pgRegex.MatchString(path) { + driver = gdal.OGRDriverByName(postgreSQLDriver) + } else { + switch strings.ToLower(filepath.Ext(path)) { + case ".gpkg": + driver = gdal.OGRDriverByName(geopackageDriver) + break + case ".shp", ".zip": + driver = gdal.OGRDriverByName(shapeFileDriver) + break + case ".json": + driver = gdal.OGRDriverByName(geoJSONDriver) + break + case ".kml": + driver = gdal.OGRDriverByName(kmlDriver) + break + default: + err = errors.New("Can't Find the Proper Driver") + manager.logger.Error(err) + } + } + return +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..c7faa5b --- /dev/null +++ b/utils.go @@ -0,0 +1,25 @@ +package gismanager + +import ( + "io/ioutil" + + yaml "gopkg.in/yaml.v2" +) + +//FromConfig load geoserver config from yaml file +func FromConfig(configFile string) (config *ManagerConfig, err error) { + gpkgConfig := ManagerConfig{} + gpkgConfig.logger = GetLogger() + yamlFile, err := ioutil.ReadFile(configFile) + if err != nil { + gpkgConfig.logger.Errorf("yamlFile.Get err %v ", err) + return + } + err = yaml.Unmarshal(yamlFile, &gpkgConfig) + if err != nil { + gpkgConfig.logger.Errorf("Unmarshal: %v", err) + return + } + config = &gpkgConfig + return +} diff --git a/vars.go b/vars.go new file mode 100644 index 0000000..5031086 --- /dev/null +++ b/vars.go @@ -0,0 +1,15 @@ +package gismanager + +import "regexp" + +var pgRegex = regexp.MustCompile(`^\s?PG:\s?.*$`) + +const ( + geopackageDriver = "GPKG" + postgreSQLDriver = "PostgreSQL" + shapeFileDriver = "ESRI Shapefile" + geoJSONDriver = "GeoJSON" + kmlDriver = "KML" + openFileGDBDriver = "OpenFileGDB" + esriJSONDriver = "ESRIJSON" +)