package config import ( "encoding/json" "errors" "flag" "fmt" "log" "os" "time" ) type Config struct { CacheDir string `json:"cachedir"` DiffDir string `json:"diffdir"` Connection string `json:"connection"` MappingFile string `json:"mapping"` LimitTo string `json:"limitto"` LimitToCacheBuffer float64 `json:"limitto_cache_buffer"` Srid int `json:"srid"` Schemas Schemas `json:"schemas"` ExpireTilesDir string `json:"expiretiles_dir"` ExpireTilesZoom int `json:"expiretiles_zoom"` ReplicationUrl string `json:"replication_url"` ReplicationInterval MinutesInterval `json:"replication_interval"` DiffStateBefore MinutesInterval `json:"diff_state_before"` } type Schemas struct { Import string `json:"import"` Production string `json:"production"` Backup string `json:"backup"` } const defaultSrid = 3857 const defaultCacheDir = "/tmp/imposm3" const defaultSchemaImport = "import" const defaultSchemaProduction = "public" const defaultSchemaBackup = "backup" type Base struct { Connection string CacheDir string DiffDir string MappingFile string Srid int LimitTo string LimitToCacheBuffer float64 ConfigFile string Httpprofile string Quiet bool Schemas Schemas ExpireTilesDir string ExpireTilesZoom int ReplicationUrl string ReplicationInterval time.Duration DiffStateBefore time.Duration } func (o *Base) updateFromConfig() error { conf := &Config{ CacheDir: defaultCacheDir, Srid: defaultSrid, } if o.ConfigFile != "" { f, err := os.Open(o.ConfigFile) if err != nil { return err } decoder := json.NewDecoder(f) err = decoder.Decode(&conf) if err != nil { return err } } if conf.Schemas.Import != "" && o.Schemas.Import == defaultSchemaImport { o.Schemas.Import = conf.Schemas.Import } if conf.Schemas.Production != "" && o.Schemas.Production == defaultSchemaProduction { o.Schemas.Production = conf.Schemas.Production } if conf.Schemas.Backup != "" && o.Schemas.Backup == defaultSchemaBackup { o.Schemas.Backup = conf.Schemas.Backup } if o.Connection == "" { o.Connection = conf.Connection } if conf.Srid == 0 { conf.Srid = defaultSrid } if o.Srid == defaultSrid { o.Srid = conf.Srid } if o.MappingFile == "" { o.MappingFile = conf.MappingFile } if o.LimitTo == "" { o.LimitTo = conf.LimitTo } if o.LimitTo == "NONE" { // allow overwrite from cmd line o.LimitTo = "" } if o.LimitToCacheBuffer == 0.0 { o.LimitToCacheBuffer = conf.LimitToCacheBuffer } if o.CacheDir == defaultCacheDir { o.CacheDir = conf.CacheDir } if o.ExpireTilesDir == "" { o.ExpireTilesDir = conf.ExpireTilesDir } if o.ExpireTilesZoom == 0 { o.ExpireTilesZoom = conf.ExpireTilesZoom } if o.ExpireTilesZoom < 6 || o.ExpireTilesZoom > 18 { o.ExpireTilesZoom = 14 } if conf.ReplicationInterval.Duration != 0 && o.ReplicationInterval == time.Minute { o.ReplicationInterval = conf.ReplicationInterval.Duration } if o.ReplicationInterval < time.Minute { o.ReplicationInterval = time.Minute } o.ReplicationUrl = conf.ReplicationUrl if o.DiffDir == "" { if conf.DiffDir == "" { // use CacheDir for backwards compatibility o.DiffDir = o.CacheDir } else { o.DiffDir = conf.DiffDir } } if conf.DiffStateBefore.Duration != 0 && o.DiffStateBefore == 0 { o.DiffStateBefore = conf.DiffStateBefore.Duration } return nil } func (o *Base) check() []error { errs := []error{} if o.Srid != 3857 && o.Srid != 4326 { errs = append(errs, errors.New("only -srid=3857 or -srid=4326 are supported")) } if o.MappingFile == "" { errs = append(errs, errors.New("missing mapping")) } return errs } type Import struct { Base Base Overwritecache bool Appendcache bool Read string Write bool Optimize bool Diff bool DeployProduction bool RevertDeploy bool RemoveBackup bool } func addBaseFlags(opts *Base, flags *flag.FlagSet) { flags.StringVar(&opts.Connection, "connection", "", "connection parameters") flags.StringVar(&opts.CacheDir, "cachedir", defaultCacheDir, "cache directory") flags.StringVar(&opts.DiffDir, "diffdir", "", "diff directory for last.state.txt") flags.StringVar(&opts.MappingFile, "mapping", "", "mapping file") flags.IntVar(&opts.Srid, "srid", defaultSrid, "srs id") flags.StringVar(&opts.LimitTo, "limitto", "", "limit to geometries") flags.Float64Var(&opts.LimitToCacheBuffer, "limittocachebuffer", 0.0, "limit to buffer for cache") flags.StringVar(&opts.ConfigFile, "config", "", "config (json)") flags.StringVar(&opts.Httpprofile, "httpprofile", "", "bind address for profile server") flags.BoolVar(&opts.Quiet, "quiet", false, "quiet log output") flags.StringVar(&opts.Schemas.Import, "dbschema-import", defaultSchemaImport, "db schema for imports") flags.StringVar(&opts.Schemas.Production, "dbschema-production", defaultSchemaProduction, "db schema for production") flags.StringVar(&opts.Schemas.Backup, "dbschema-backup", defaultSchemaBackup, "db schema for backups") } func ParseImport(args []string) Import { flags := flag.NewFlagSet("import", flag.ExitOnError) opts := Import{} addBaseFlags(&opts.Base, flags) flags.BoolVar(&opts.Overwritecache, "overwritecache", false, "overwritecache") flags.BoolVar(&opts.Appendcache, "appendcache", false, "append cache") flags.StringVar(&opts.Read, "read", "", "read") flags.BoolVar(&opts.Write, "write", false, "write") flags.BoolVar(&opts.Optimize, "optimize", false, "optimize") flags.BoolVar(&opts.Diff, "diff", false, "enable diff support") flags.BoolVar(&opts.DeployProduction, "deployproduction", false, "deploy production") flags.BoolVar(&opts.RevertDeploy, "revertdeploy", false, "revert deploy to production") flags.BoolVar(&opts.RemoveBackup, "removebackup", false, "remove backups from deploy") flags.DurationVar(&opts.Base.DiffStateBefore, "diff-state-before", 0, "set initial diff sequence before") flags.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s %s [args]\n\n", os.Args[0], os.Args[1]) flags.PrintDefaults() os.Exit(2) } if len(args) == 0 { flags.Usage() } err := flags.Parse(args) if err != nil { log.Fatal(err) } err = opts.Base.updateFromConfig() if err != nil { log.Fatal(err) } errs := opts.Base.check() if len(errs) != 0 { reportErrors(errs) flags.Usage() } return opts } func ParseDiffImport(args []string) (Base, []string) { flags := flag.NewFlagSet("diff", flag.ExitOnError) opts := Base{} addBaseFlags(&opts, flags) flags.StringVar(&opts.ExpireTilesDir, "expiretiles-dir", "", "write expire tiles into dir") flags.IntVar(&opts.ExpireTilesZoom, "expiretiles-zoom", 14, "write expire tiles in this zoom level") flags.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s %s [args] [.osc.gz, ...]\n\n", os.Args[0], os.Args[1]) flags.PrintDefaults() os.Exit(2) } if len(args) == 0 { flags.Usage() } err := flags.Parse(args) if err != nil { log.Fatal(err) } err = opts.updateFromConfig() if err != nil { log.Fatal(err) } errs := opts.check() if len(errs) != 0 { reportErrors(errs) flags.Usage() } return opts, flags.Args() } func ParseRunImport(args []string) Base { flags := flag.NewFlagSet("run", flag.ExitOnError) opts := Base{} addBaseFlags(&opts, flags) flags.StringVar(&opts.ExpireTilesDir, "expiretiles-dir", "", "write expire tiles into dir") flags.IntVar(&opts.ExpireTilesZoom, "expiretiles-zoom", 14, "write expire tiles in this zoom level") flags.DurationVar(&opts.ReplicationInterval, "replication-interval", time.Minute, "replication interval as duration (1m, 1h, 24h)") flags.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s %s [args] [.osc.gz, ...]\n\n", os.Args[0], os.Args[1]) flags.PrintDefaults() os.Exit(2) } if len(args) == 0 { flags.Usage() } err := flags.Parse(args) if err != nil { log.Fatal(err) } err = opts.updateFromConfig() if err != nil { log.Fatal(err) } errs := opts.check() if len(errs) != 0 { reportErrors(errs) flags.Usage() } return opts } func reportErrors(errs []error) { fmt.Println("errors in config/options:") for _, err := range errs { fmt.Printf("\t%s\n", err) } os.Exit(1) } type MinutesInterval struct { time.Duration } func (d *MinutesInterval) UnmarshalJSON(b []byte) (err error) { if b[0] == '"' { sd := string(b[1 : len(b)-1]) d.Duration, err = time.ParseDuration(sd) return } var id int64 id, err = json.Number(string(b)).Int64() d.Duration = time.Duration(id) * time.Minute return }