mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-20 04:42:33 +02:00
new simpler setup method, readme and doc update
This commit is contained in:
parent
109c2460fa
commit
79ae26f1b5
12 changed files with 231 additions and 113 deletions
|
@ -19,6 +19,9 @@ COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
|
||||||
COPY --from=builder /src/go-proxy /app/
|
COPY --from=builder /src/go-proxy /app/
|
||||||
COPY schema/ /app/schema
|
COPY schema/ /app/schema
|
||||||
|
|
||||||
|
# copy cert required for setup
|
||||||
|
COPY --from=builder /etc/ssl/certs /etc/ssl/certs
|
||||||
|
|
||||||
ENV DOCKER_HOST=unix:///var/run/docker.sock
|
ENV DOCKER_HOST=unix:///var/run/docker.sock
|
||||||
ENV GOPROXY_DEBUG=0
|
ENV GOPROXY_DEBUG=0
|
||||||
|
|
||||||
|
|
22
README.md
22
README.md
|
@ -32,11 +32,12 @@ A lightweight, easy-to-use, and [performant](docs/benchmark_result.md) reverse p
|
||||||
|
|
||||||
- Easy to use
|
- Easy to use
|
||||||
- Effortless configuration
|
- Effortless configuration
|
||||||
|
- Simple multi-node setup
|
||||||
- Error messages is clear and detailed, easy troubleshooting
|
- Error messages is clear and detailed, easy troubleshooting
|
||||||
- Auto certificate obtaining and renewal (See [Supported DNS Challenge Providers](docs/dns_providers.md))
|
- Auto certificate obtaining and renewal (See [Supported DNS Challenge Providers](docs/dns_providers.md))
|
||||||
- Auto configuration for docker containers
|
- Auto configuration for docker containers
|
||||||
- Auto hot-reload on container state / config file changes
|
- Auto hot-reload on container state / config file changes
|
||||||
- Stop containers on idle, wake it up on traffic _(optional, see [showcase](#idlesleeper))_
|
- **idlesleeper**: stop containers on idle, wake it up on traffic _(optional, see [showcase](#idlesleeper))_
|
||||||
- HTTP(s) reserve proxy
|
- HTTP(s) reserve proxy
|
||||||
- TCP and UDP port forwarding
|
- TCP and UDP port forwarding
|
||||||
- Web UI for configuration and monitoring (See [screenshots](https://github.com/yusing/go-proxy-frontend?tab=readme-ov-file#screenshots))
|
- Web UI for configuration and monitoring (See [screenshots](https://github.com/yusing/go-proxy-frontend?tab=readme-ov-file#screenshots))
|
||||||
|
@ -48,18 +49,23 @@ A lightweight, easy-to-use, and [performant](docs/benchmark_result.md) reverse p
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
1. Setup DNS Records, e.g.
|
1. Pull docker image `docker pull ghcr.io/yusing/go-proxy:latest`
|
||||||
|
|
||||||
|
2. Create new directory, `cd` into it, then run setup
|
||||||
|
|
||||||
|
`docker run --rm -v .:/setup ghcr.io/yusing/go-proxy /app/go-proxy setup`
|
||||||
|
|
||||||
|
3. Setup DNS Records point to machine which runs `go-proxy`, e.g.
|
||||||
|
|
||||||
- A Record: `*.y.z` -> `10.0.10.1`
|
- A Record: `*.y.z` -> `10.0.10.1`
|
||||||
- AAAA Record: `*.y.z` -> `::ffff:a00:a01`
|
- AAAA Record: `*.y.z` -> `::ffff:a00:a01`
|
||||||
|
|
||||||
2. Setup `go-proxy` [See here](docs/docker.md)
|
4. Setup `docker-socket-proxy` other docker nodes _(if any)_ (see [example](docs/docker_socket_proxy.md)) and then them inside `config.yml`
|
||||||
|
|
||||||
3. Setup `docker-socket-proxy` (see [example](docs/docker_socket_proxy.md) other machine that is running docker (if any)
|
5. Done. You may now do some extra configuration
|
||||||
|
- With text editor (e.g. Visual Studio Code)
|
||||||
4. Configure `go-proxy`
|
- With Web UI via `gp.y.z`
|
||||||
- with text editor (e.g. Visual Studio Code)
|
- For more info, [See docker.md](docs/docker.md)
|
||||||
- or with web config editor via `http://gp.y.z`
|
|
||||||
|
|
||||||
[🔼Back to top](#table-of-content)
|
[🔼Back to top](#table-of-content)
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
# options:
|
# options:
|
||||||
# - auth_token: c1234565789-abcdefghijklmnopqrst # your zone API token
|
# - auth_token: c1234565789-abcdefghijklmnopqrst # your zone API token
|
||||||
|
|
||||||
# 3. other providers, check readme for more
|
# 3. other providers, check docs/dns_providers.md for more
|
||||||
|
|
||||||
providers:
|
providers:
|
||||||
include:
|
# include:
|
||||||
- providers.yml # config/providers.yml
|
# - providers.yml # config/providers.yml
|
||||||
# add some more below if you want
|
# # add some more below if you want
|
||||||
# - file1.yml # config/file_1.yml
|
# - file1.yml # config/file_1.yml
|
||||||
# - file2.yml
|
# - file2.yml
|
||||||
docker:
|
docker:
|
||||||
|
@ -30,8 +30,7 @@ providers:
|
||||||
# add more docker providers if needed
|
# add more docker providers if needed
|
||||||
# remote-1: tcp://10.0.2.1:2375
|
# remote-1: tcp://10.0.2.1:2375
|
||||||
# remote-2: ssh://root:1234@10.0.2.2
|
# remote-2: ssh://root:1234@10.0.2.2
|
||||||
|
|
||||||
# Fixed options (optional, non hot-reloadable)
|
# Fixed options (optional, non hot-reloadable)
|
||||||
|
|
||||||
# timeout_shutdown: 5
|
# timeout_shutdown: 5
|
||||||
# redirect_to_https: false
|
# redirect_to_https: false # redirect http requests to https (if enabled)
|
||||||
|
|
|
@ -11,26 +11,54 @@
|
||||||
|
|
||||||
## Cloudflare
|
## Cloudflare
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
autocert:
|
||||||
|
provider: cloudflare
|
||||||
|
options:
|
||||||
|
auth_token:
|
||||||
|
```
|
||||||
|
|
||||||
`auth_token` your zone API token
|
`auth_token` your zone API token
|
||||||
|
|
||||||
Follow [this guide](https://cloudkul.com/blog/automcatic-renew-and-generate-ssl-on-your-website-using-lego-client/) to create a new token with `Zone.DNS` read and edit permissions
|
Follow [this guide](https://cloudkul.com/blog/automcatic-renew-and-generate-ssl-on-your-website-using-lego-client/) to create a new token with `Zone.DNS` read and edit permissions
|
||||||
|
|
||||||
## CloudDNS
|
## CloudDNS
|
||||||
|
|
||||||
- `client_id`
|
```yaml
|
||||||
|
autocert:
|
||||||
- `email`
|
provider: clouddns
|
||||||
|
options:
|
||||||
- `password`
|
client_id:
|
||||||
|
email:
|
||||||
|
password:
|
||||||
|
```
|
||||||
|
|
||||||
## DuckDNS
|
## DuckDNS
|
||||||
|
|
||||||
- `token`: DuckDNS Token
|
```yaml
|
||||||
|
autocert:
|
||||||
|
provider: duckdns
|
||||||
|
options:
|
||||||
|
token:
|
||||||
|
```
|
||||||
|
|
||||||
Tested by [earvingad](https://github.com/earvingad)
|
Tested by [earvingad](https://github.com/earvingad)
|
||||||
|
|
||||||
## OVHCloud
|
## OVHCloud
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
autocert:
|
||||||
|
provider: ovh
|
||||||
|
options:
|
||||||
|
api_endpoint:
|
||||||
|
application_key:
|
||||||
|
application_secret:
|
||||||
|
consumer_key:
|
||||||
|
oauth2_config:
|
||||||
|
client_id:
|
||||||
|
client_secret:
|
||||||
|
```
|
||||||
|
|
||||||
_Note, `application_key` and `oauth2_config` **CANNOT** be used together_
|
_Note, `application_key` and `oauth2_config` **CANNOT** be used together_
|
||||||
|
|
||||||
- `api_endpoint`: Endpoint URL, or one of
|
- `api_endpoint`: Endpoint URL, or one of
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
- [Docker compose guide](#docker-compose-guide)
|
- [Docker compose guide](#docker-compose-guide)
|
||||||
- [Table of content](#table-of-content)
|
- [Table of content](#table-of-content)
|
||||||
- [Setup](#setup)
|
- [Additional setup](#additional-setup)
|
||||||
- [Labels](#labels)
|
- [Labels](#labels)
|
||||||
- [Syntax](#syntax)
|
- [Syntax](#syntax)
|
||||||
- [Fields](#fields)
|
- [Fields](#fields)
|
||||||
|
@ -16,34 +16,11 @@
|
||||||
- [Docker compose examples](#docker-compose-examples)
|
- [Docker compose examples](#docker-compose-examples)
|
||||||
- [Services URLs for above examples](#services-urls-for-above-examples)
|
- [Services URLs for above examples](#services-urls-for-above-examples)
|
||||||
|
|
||||||
## Setup
|
## Additional setup
|
||||||
|
|
||||||
1. Install `wget` if not already
|
1. Enable HTTPs _(optional)_
|
||||||
|
|
||||||
- Ubuntu based: `sudo apt install -y wget`
|
Mount a folder to store obtained certs or to load existing cert
|
||||||
- Fedora based: `sudo yum install -y wget`
|
|
||||||
- Arch based: `sudo pacman -Sy wget`
|
|
||||||
|
|
||||||
2. Run setup script
|
|
||||||
|
|
||||||
`bash <(wget -qO- https://github.com/yusing/go-proxy/raw/main/setup-docker.sh)`
|
|
||||||
|
|
||||||
It will setup folder structure and required config files
|
|
||||||
|
|
||||||
3. Verify folder structure and then `cd go-proxy`
|
|
||||||
|
|
||||||
```plain
|
|
||||||
go-proxy
|
|
||||||
├── certs
|
|
||||||
├── compose.yml
|
|
||||||
└── config
|
|
||||||
├── config.yml
|
|
||||||
└── providers.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Enable HTTPs _(optional)_
|
|
||||||
|
|
||||||
Mount a folder (to store obtained certs) or (containing existing cert)
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
|
@ -69,15 +46,16 @@
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
autocert:
|
autocert:
|
||||||
|
provider: local
|
||||||
cert_path: /app/certs/cert.crt
|
cert_path: /app/certs/cert.crt
|
||||||
key_path: /app/certs/priv.key
|
key_path: /app/certs/priv.key
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Modify `compose.yml` to fit your needs
|
2. Modify `compose.yml` to fit your needs
|
||||||
|
|
||||||
6. Run `docker compose up -d` to start the container
|
3. Run `docker compose up -d` to start the container
|
||||||
|
|
||||||
7. Navigate to Web panel `http://gp.yourdomain.com` or use **Visual Studio Code (provides schema check)** to edit proxy config
|
4. Navigate to Web panel `http://gp.yourdomain.com` or use **Visual Studio Code (provides schema check)** to edit proxy config
|
||||||
|
|
||||||
[🔼Back to top](#table-of-content)
|
[🔼Back to top](#table-of-content)
|
||||||
|
|
||||||
|
@ -101,13 +79,13 @@
|
||||||
### Fields
|
### Fields
|
||||||
|
|
||||||
| Field | Description | Default | Allowed Values / Syntax |
|
| Field | Description | Default | Allowed Values / Syntax |
|
||||||
| --------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `scheme` | proxy protocol | <ul><li>`http` for numeric port</li><li>`tcp` for `x:y` port</li></ul> | `http`, `https`, `tcp`, `udp` |
|
| `scheme` | proxy protocol | <ul><li>`http` for numeric port</li><li>`tcp` for `x:y` port</li></ul> | `http`, `https`, `tcp`, `udp` |
|
||||||
| `host` | proxy host | <ul><li>Docker: docker client IP / hostname </li><li>File: `localhost`</li></ul> | IP address, hostname |
|
| `host` | proxy host | <ul><li>Docker: docker client IP / hostname </li><li>File: `localhost`</li></ul> | IP address, hostname |
|
||||||
| `port` | proxy port **(http/s)** | first port returned from docker | number in range of `1 - 65535` |
|
| `port` | proxy port **(http/s)** | first port returned from docker | number in range of `1 - 65535` |
|
||||||
| `port` **(required)** | proxy port **(tcp/udp)** | N/A | `x:y` <br><ul><li>**x**: port for `go-proxy` to listen on.<br>**x** can be 0, which means listen on a random port</li><li>**y**: port or [_service name_](../src/common/constants.go#L55) of target container</li></ul> |
|
| `port` | proxy port **(tcp/udp)** | `0:first_port` | `x:y` <br><ul><li>**x**: port for `go-proxy` to listen on.<br>**x** can be 0, which means listen on a random port</li><li>**y**: port or [_service name_](../src/common/constants.go#L55) of target container</li></ul> |
|
||||||
| `no_tls_verify` | whether skip tls verify **(https only)** | `false` | boolean |
|
| `no_tls_verify` | whether skip tls verify **(https only)** | `false` | boolean |
|
||||||
| `path_patterns` | proxy path patterns **(http/s only)**<br> only requests that matched a pattern will be proxied | empty **(proxy all requests)** | yaml style list[<sup>1</sup>](#list-example) of ([path patterns](https://pkg.go.dev/net/http#hdr-Patterns-ServeMux)) |
|
| `path_patterns` | proxy path patterns **(http/s only)**<br> only requests that matched a pattern will be proxied | `/` **(proxy all requests)** | yaml style list[<sup>1</sup>](#list-example) of ([path patterns](https://pkg.go.dev/net/http#hdr-Patterns-ServeMux)) |
|
||||||
| `set_headers` | header to set **(http/s only)** | empty | yaml style key-value mapping[<sup>2</sup>](#key-value-mapping-example) of header-value pairs |
|
| `set_headers` | header to set **(http/s only)** | empty | yaml style key-value mapping[<sup>2</sup>](#key-value-mapping-example) of header-value pairs |
|
||||||
| `hide_headers` | header to hide **(http/s only)** | empty | yaml style list[<sup>1</sup>](#list-example) of headers |
|
| `hide_headers` | header to hide **(http/s only)** | empty | yaml style list[<sup>1</sup>](#list-example) of headers |
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ docker-proxy:
|
||||||
ports:
|
ports:
|
||||||
- 2375:2375
|
- 2375:2375
|
||||||
# or more secure
|
# or more secure
|
||||||
- <machine_ip>:2375:2375
|
- <machine_private_ip>:2375:2375
|
||||||
```
|
```
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
if [ -z "$BRANCH" ]; then
|
|
||||||
BRANCH="v0.5"
|
|
||||||
fi
|
|
||||||
BASE_URL="https://github.com/yusing/go-proxy/raw/${BRANCH}"
|
|
||||||
mkdir -p go-proxy
|
|
||||||
cd go-proxy
|
|
||||||
mkdir -p config
|
|
||||||
mkdir -p certs
|
|
||||||
[ -f compose.yml ] || wget -cO - ${BASE_URL}/compose.example.yml > compose.yml
|
|
||||||
[ -f config/config.yml ] || wget -cO - ${BASE_URL}/config.example.yml > config/config.yml
|
|
||||||
[ -f config/providers.yml ] || touch config/providers.yml
|
|
|
@ -13,6 +13,7 @@ type Args struct {
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CommandStart = ""
|
CommandStart = ""
|
||||||
|
CommandSetup = "setup"
|
||||||
CommandValidate = "validate"
|
CommandValidate = "validate"
|
||||||
CommandListConfigs = "ls-config"
|
CommandListConfigs = "ls-config"
|
||||||
CommandListRoutes = "ls-routes"
|
CommandListRoutes = "ls-routes"
|
||||||
|
@ -23,6 +24,7 @@ const (
|
||||||
|
|
||||||
var ValidCommands = []string{
|
var ValidCommands = []string{
|
||||||
CommandStart,
|
CommandStart,
|
||||||
|
CommandSetup,
|
||||||
CommandValidate,
|
CommandValidate,
|
||||||
CommandListConfigs,
|
CommandListConfigs,
|
||||||
CommandListRoutes,
|
CommandListRoutes,
|
||||||
|
|
|
@ -10,29 +10,24 @@ const (
|
||||||
KeepAlive = 5 * time.Second
|
KeepAlive = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
ProviderKind_Docker = "docker"
|
|
||||||
ProviderKind_File = "file"
|
|
||||||
)
|
|
||||||
|
|
||||||
// file, folder structure
|
// file, folder structure
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ConfigBasePath = "config/"
|
ConfigBasePath = "config"
|
||||||
ConfigFileName = "config.yml"
|
ConfigFileName = "config.yml"
|
||||||
ConfigPath = ConfigBasePath + ConfigFileName
|
ConfigExampleFileName = "config.example.yml"
|
||||||
|
ConfigPath = ConfigBasePath + "/" + ConfigFileName
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TemplatesBasePath = "templates/"
|
SchemaBasePath = "schema"
|
||||||
PanelTemplatePath = TemplatesBasePath + "panel/index.html"
|
ConfigSchemaPath = SchemaBasePath + "/config.schema.json"
|
||||||
ConfigEditorTemplatePath = TemplatesBasePath + "config_editor/index.html"
|
FileProviderSchemaPath = SchemaBasePath + "/providers.schema.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SchemaBasePath = "schema/"
|
ComposeFileName = "compose.yml"
|
||||||
ConfigSchemaPath = SchemaBasePath + "config.schema.json"
|
ComposeExampleFileName = "compose.example.yml"
|
||||||
FileProviderSchemaPath = SchemaBasePath + "providers.schema.json"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const DockerHostFromEnv = "$DOCKER_HOST"
|
const DockerHostFromEnv = "$DOCKER_HOST"
|
||||||
|
|
|
@ -7,18 +7,18 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
NoSchemaValidation = getEnvBool("GOPROXY_NO_SCHEMA_VALIDATION")
|
NoSchemaValidation = GetEnvBool("GOPROXY_NO_SCHEMA_VALIDATION")
|
||||||
IsDebug = getEnvBool("GOPROXY_DEBUG")
|
IsDebug = GetEnvBool("GOPROXY_DEBUG")
|
||||||
ProxyHTTPAddr = getEnv("GOPROXY_HTTP_ADDR", ":80")
|
ProxyHTTPAddr = GetEnv("GOPROXY_HTTP_ADDR", ":80")
|
||||||
ProxyHTTPSAddr = getEnv("GOPROXY_HTTPS_ADDR", ":443")
|
ProxyHTTPSAddr = GetEnv("GOPROXY_HTTPS_ADDR", ":443")
|
||||||
APIHTTPAddr = getEnv("GOPROXY_API_ADDR", "127.0.0.1:8888")
|
APIHTTPAddr = GetEnv("GOPROXY_API_ADDR", "127.0.0.1:8888")
|
||||||
)
|
)
|
||||||
|
|
||||||
func getEnvBool(key string) bool {
|
func GetEnvBool(key string) bool {
|
||||||
return U.ParseBool(os.Getenv(key))
|
return U.ParseBool(os.Getenv(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEnv(key string, defaultValue string) string {
|
func GetEnv(key string, defaultValue string) string {
|
||||||
value, ok := os.LookupEnv(key)
|
value, ok := os.LookupEnv(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
value = defaultValue
|
value = defaultValue
|
||||||
|
|
|
@ -30,6 +30,12 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
args := common.GetArgs()
|
args := common.GetArgs()
|
||||||
|
|
||||||
|
if args.Command == common.CommandSetup {
|
||||||
|
Setup()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
l := logrus.WithField("module", "main")
|
l := logrus.WithField("module", "main")
|
||||||
onShutdown := F.NewSlice[func()]()
|
onShutdown := F.NewSlice[func()]()
|
||||||
|
|
||||||
|
|
115
src/setup.go
Normal file
115
src/setup.go
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
. "github.com/yusing/go-proxy/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var branch = GetEnv("GOPROXY_BRANCH", "v0.5")
|
||||||
|
var baseUrl = fmt.Sprintf("https://github.com/yusing/go-proxy/raw/%s", branch)
|
||||||
|
var requiredConfigs = []Config{
|
||||||
|
{ConfigBasePath, true, false, ""},
|
||||||
|
{ComposeFileName, false, true, ComposeExampleFileName},
|
||||||
|
{path.Join(ConfigBasePath, ConfigFileName), false, true, ConfigExampleFileName},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Pathname string
|
||||||
|
IsDir bool
|
||||||
|
NeedDownload bool
|
||||||
|
DownloadFileName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setup() {
|
||||||
|
log.Println("setting up go-proxy")
|
||||||
|
log.Println("branch:", branch)
|
||||||
|
|
||||||
|
os.Chdir("/setup")
|
||||||
|
|
||||||
|
for _, config := range requiredConfigs {
|
||||||
|
config.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("done")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) setup() {
|
||||||
|
if c.IsDir {
|
||||||
|
mkdir(c.Pathname)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !c.NeedDownload {
|
||||||
|
touch(c.Pathname)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(c.DownloadFileName, c.Pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasFileOrDir(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkdir(pathname string) {
|
||||||
|
_, err := os.Stat(pathname)
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
log.Printf("creating directory %q\n", pathname)
|
||||||
|
err := os.MkdirAll(pathname, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed: %s\n", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed: %s\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func touch(pathname string) {
|
||||||
|
if hasFileOrDir(pathname) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("creating file %q\n", pathname)
|
||||||
|
_, err := os.Create(pathname)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed: %s\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func fetch(remoteFilename string, outFileName string) {
|
||||||
|
if hasFileOrDir(outFileName) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("downloading %q\n", remoteFilename)
|
||||||
|
|
||||||
|
url, err := url.JoinPath(baseUrl, remoteFilename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("unexpected error: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("http request failed: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error reading response body: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(outFileName, body, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to write to file: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("downloaded %q\n", outFileName)
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue