Skip to content

Commit 10795f3

Browse files
committed
Project refactoring
1 parent d4583f8 commit 10795f3

File tree

18 files changed

+866
-425
lines changed

18 files changed

+866
-425
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
# Ignore Mac DS_Store files
22
.DS_Store
3+
4+
# Goland and VSCode
5+
.vscode
6+
.idea

Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM golang:1.18
2+
3+
WORKDIR /code
4+
5+
# Pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them
6+
# in subsequent builds if they change.
7+
COPY go.mod go.sum* .
8+
RUN go mod download && go mod verify
9+
10+
CMD tail -f /dev/null

LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2017 Łukasz Mikołajczak
3+
Copyright (c) 2022 Łukasz Mikołajczak
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -14,7 +14,7 @@ copies or substantial portions of the Software.
1414

1515
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

README.md

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,72 @@
1-
[![Go Report Card](https://goreportcard.com/badge/github.com/Luqqk/wms-tiles-downloader)](https://goreportcard.com/report/github.com/Luqqk/wms-tiles-downloader)
2-
31
## 🌐 wms-tiles-downloader
42

5-
Command line application for downloading wms-tiles from given URL with specified bbox and zoom parameters.
3+
Command line application for downloading map tiles from given WMS server.
64

75
### Installation
86

9-
If you have go installed locally:
10-
11-
```bash
12-
go get -u github.com/Luqqk/wms-tiles-downloader...
137
```
14-
Or you can use already compiled binaries available here:
8+
go get github.com/lmikolajczak/wms-tiles-downloader@latest
9+
```
1510

16-
[binaries](https://github.com/Luqqk/wms-tiles-downloader/releases)
11+
Go will automatically install it in your $GOPATH/bin directory which should be in your $PATH.
1712

1813
### Command Line Usage
1914

2015
```
21-
Usage:
22-
23-
wms-get [OPTIONS]
24-
25-
Download tiles from specific source and save them on hard drive.
26-
27-
Options:
28-
29-
--url WMS server url. REQUIRED
30-
--layer Layer name. REQUIRED
31-
--zooms Comma-separated list of zooms to download. REQUIRED
32-
--bbox Comma-separated list of bbox coordinates. REQUIRED
33-
--format Tiles format. DEFAULT: image/png
34-
--width Tile width. DEFAULT: 256
35-
--height Tiles hight. DEFAULT: 256
36-
--service Service type. DEFAULT: WMS
37-
--version WMS version. DEFAULT: 1.1.1
38-
--styles WMS styles. DEFAULT: ""
39-
--concurrency Limit concurrent requests to the WMS server. DEFAULT: 32
40-
Change only if you know what you're doing.
41-
42-
Help Options:
16+
Download tiles from WMS server based on provided options.
4317
44-
--help Help. Prints usage in the stdout.
18+
Usage:
19+
wms-tiles-downloader get [flags]
20+
21+
Flags:
22+
-b, --bbox float64Slice comma-separated list of bbox coords (default [])
23+
--concurrency int limit of concurrent requests to the WMS server (default 16)
24+
--format string tile format (default "image/png")
25+
--height int tile height (default 256)
26+
-h, --help help for get
27+
-l, --layer string layer name
28+
-s, --style string layer style
29+
-u, --url string WMS server url
30+
--version string WMS server version (default "1.3.0")
31+
--width int lile width (default 256)
32+
-z, --zoom ints comma-separated list of zooms
4533
```
4634

4735
### Examples
4836

49-
Get tiles from `http://129.206.228.72/cached/osm` server for specified `layer`, `zoom levels` and `bbox`.
50-
51-
```bash
52-
$ wms-get --url http://129.206.228.72/cached/osm --layer osm_auto:all --zooms 14,15 --bbox 16.80,52.05,16.83,52.06
53-
```
54-
55-
Command above will produce following output (tree of folders with files in z/x/y format):
37+
![demo](https://user-images.githubusercontent.com/10035716/182269225-80194102-a59e-4fe3-bf78-0b5d1ea457d4.gif)
5638

57-
![tiles_tree.png](docs/tiles_tree.png)
39+
Command above will produce following output - tree of folders with files in Z/X/Y format:
5840

59-
### Release history
60-
61-
Current binaries for different versions or platforms and changelog can be found here:
62-
63-
* [v2.0.0](https://github.com/Luqqk/wms-tiles-downloader/releases/tag/v2.0.0)
64-
* [v1.0.0](https://github.com/Luqqk/wms-tiles-downloader/releases/tag/v1.0.0)
41+
```
42+
root@df62f3f34fef:/tiles# tree
43+
.
44+
|-- 10
45+
| |-- 524
46+
| | |-- 336.png
47+
| | `-- 337.png
48+
| |-- 525
49+
| | |-- 336.png
50+
| | `-- 337.png
51+
| `-- 526
52+
| |-- 336.png
53+
| `-- 337.png
54+
|-- 11
55+
| |-- 1049
56+
| | |-- 672.png
57+
| | |-- 673.png
58+
| | `-- 674.png
59+
| |-- 1050
60+
| | |-- 672.png
61+
| | |-- 673.png
62+
| | `-- 674.png
63+
| |-- 1051
64+
| | |-- 672.png
65+
| | |-- 673.png
66+
| | `-- 674.png
67+
| `-- 1052
68+
| |-- 672.png
69+
| |-- 673.png
70+
| `-- 674.png
71+
...more directories...
72+
```

cmd/get.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/lmikolajczak/wms-tiles-downloader/mercantile"
7+
"github.com/lmikolajczak/wms-tiles-downloader/wms"
8+
"github.com/schollz/progressbar/v3"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var getCmd = &cobra.Command{
13+
Use: "get",
14+
Short: "Download tiles",
15+
Long: "Download tiles from WMS server based on provided options.",
16+
Run: func(cmd *cobra.Command, args []string) {
17+
ctx := context.Background()
18+
// Get IDs of tiles that are intersecting given bbox on provided zoom levels.
19+
bbox, err := cmd.Flags().GetFloat64Slice("bbox")
20+
if err != nil {
21+
fmt.Printf("ERR: %s\n", err)
22+
}
23+
zoom, err := cmd.Flags().GetIntSlice("zoom")
24+
if err != nil {
25+
fmt.Printf("ERR: %s\n", err)
26+
}
27+
tileIDs := mercantile.Tiles(bbox[0], bbox[1], bbox[2], bbox[3], zoom)
28+
bar := progressbar.Default(int64(len(tileIDs)))
29+
30+
// Initialize new WMS client
31+
url, err := cmd.Flags().GetString("url")
32+
if err != nil {
33+
fmt.Printf("ERR: %s\n", err)
34+
}
35+
version, err := cmd.Flags().GetString("version")
36+
if err != nil {
37+
fmt.Printf("ERR: %s\n", err)
38+
}
39+
WMSClient := wms.NewClient(wms.WithBaseURL(url), wms.WithVersion(version))
40+
41+
// Use semaphore pattern to limit concurrency. We don't want to flood WMS
42+
// server with too many requests.
43+
concurrency, err := cmd.Flags().GetInt("concurrency")
44+
if err != nil {
45+
fmt.Printf("ERR: %s\n", err)
46+
}
47+
sem := make(chan bool, concurrency)
48+
49+
// Download tiles from WMS server and save them on a hard drive.
50+
layer, err := cmd.Flags().GetString("layer")
51+
if err != nil {
52+
fmt.Printf("ERR: %s\n", err)
53+
}
54+
style, err := cmd.Flags().GetString("style")
55+
if err != nil {
56+
fmt.Printf("ERR: %s\n", err)
57+
}
58+
width, err := cmd.Flags().GetInt("width")
59+
if err != nil {
60+
fmt.Printf("ERR: %s\n", err)
61+
}
62+
height, err := cmd.Flags().GetInt("height")
63+
if err != nil {
64+
fmt.Printf("ERR: %s\n", err)
65+
}
66+
format, err := cmd.Flags().GetString("format")
67+
if err != nil {
68+
fmt.Printf("ERR: %s\n", err)
69+
}
70+
for _, tileID := range tileIDs {
71+
sem <- true
72+
go func(tileID mercantile.TileID) {
73+
defer func() { bar.Add(1); <-sem }()
74+
75+
tile, err := WMSClient.GetTile(
76+
ctx,
77+
tileID,
78+
wms.WithLayers(layer),
79+
wms.WithStyles(style),
80+
wms.WithWidth(width),
81+
wms.WithHeight(height),
82+
wms.WithFormat(format),
83+
)
84+
if err != nil {
85+
fmt.Printf("ERR: %s\n", err)
86+
return
87+
}
88+
err = WMSClient.SaveTile(tile)
89+
if err != nil {
90+
fmt.Printf("ERR: %s\n", err)
91+
}
92+
}(tileID)
93+
}
94+
// Make sure we wait for all goroutines to finish, attempt to fill the
95+
// semaphore back up to its capacity.
96+
for i := 0; i < cap(sem); i++ {
97+
sem <- true
98+
}
99+
},
100+
}
101+
102+
func init() {
103+
rootCmd.AddCommand(getCmd)
104+
105+
// Required args/flags
106+
getCmd.Flags().StringP(
107+
"url", "u", "", "WMS server url",
108+
)
109+
getCmd.MarkFlagRequired("url")
110+
getCmd.Flags().StringP(
111+
"layer", "l", "", "Layer name",
112+
)
113+
getCmd.MarkFlagRequired("layer")
114+
getCmd.Flags().IntSliceP(
115+
"zoom", "z", nil, "Comma-separated list of zooms",
116+
)
117+
getCmd.MarkFlagRequired("zoom")
118+
getCmd.Flags().Float64SliceP(
119+
"bbox", "b", nil, "Comma-separated list of bbox coords",
120+
)
121+
getCmd.MarkFlagRequired("bbox")
122+
123+
// Optional args/flags
124+
getCmd.Flags().StringP(
125+
"style", "s", "", "Layer style",
126+
)
127+
getCmd.Flags().Int(
128+
"width", 256, "Tile width",
129+
)
130+
getCmd.Flags().Int(
131+
"height", 256, "Tile height",
132+
)
133+
getCmd.Flags().String(
134+
"format", "image/png", "Tile format",
135+
)
136+
getCmd.Flags().String(
137+
"version", "1.3.0", "WMS server version",
138+
)
139+
getCmd.Flags().Int(
140+
"concurrency", 16, "Limit of concurrent requests to the WMS server",
141+
)
142+
}

cmd/root.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package cmd
2+
3+
import (
4+
"os"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
// rootCmd represents the base command when called without any subcommands
10+
var rootCmd = &cobra.Command{
11+
Use: "wms-tiles-downloader",
12+
Short: "Download tiles from WMS server",
13+
Long: `This is a simple CLI library for Go that allows to download
14+
WMS tiles from the server and save them on local hard drive`,
15+
}
16+
17+
// Execute adds all child commands to the root command and sets flags appropriately.
18+
// This is called by main.main(). It only needs to happen once to the rootCmd.
19+
func Execute() {
20+
err := rootCmd.Execute()
21+
if err != nil {
22+
os.Exit(1)
23+
}
24+
}

0 commit comments

Comments
 (0)