feat: add downloader binary for client-side dependencies
Replace the curl-based Taskfile download task with a Go binary that concurrently fetches datastar.js, datastar.js.map, daisyui.mjs, and daisyui-theme.mjs. Update vendored libs to latest versions.
This commit is contained in:
100
cmd/downloader/main.go
Normal file
100
cmd/downloader/main.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Asset directories, relative to project root.
|
||||
const (
|
||||
jsDir = "assets/js"
|
||||
cssDir = "assets/css"
|
||||
)
|
||||
|
||||
// files maps download URLs to local destination paths.
|
||||
var files = map[string]string{
|
||||
"https://raw.githubusercontent.com/starfederation/datastar/main/bundles/datastar.js": jsDir + "/datastar.js",
|
||||
"https://raw.githubusercontent.com/starfederation/datastar/main/bundles/datastar.js.map": jsDir + "/datastar.js.map",
|
||||
"https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.mjs": cssDir + "/daisyui.mjs",
|
||||
"https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.mjs": cssDir + "/daisyui-theme.mjs",
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
slog.Error("failure", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
dirs := []string{jsDir, cssDir}
|
||||
|
||||
for _, dir := range dirs {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("create directory %s: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
return download(files)
|
||||
}
|
||||
|
||||
func download(files map[string]string) error {
|
||||
var wg sync.WaitGroup
|
||||
errCh := make(chan error, len(files))
|
||||
|
||||
for url, dest := range files {
|
||||
wg.Go(func() {
|
||||
base := filepath.Base(dest)
|
||||
slog.Info("downloading...", "file", base, "url", url)
|
||||
if err := downloadFile(url, dest); err != nil {
|
||||
errCh <- fmt.Errorf("download %s: %w", base, err)
|
||||
} else {
|
||||
slog.Info("finished", "file", base)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errCh)
|
||||
|
||||
var errs []error
|
||||
for err := range errCh {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func downloadFile(url, dest string) error {
|
||||
resp, err := http.Get(url) //nolint:gosec,noctx // static URLs, simple tool
|
||||
if err != nil {
|
||||
return fmt.Errorf("GET %s: %w", url, err)
|
||||
}
|
||||
defer resp.Body.Close() //nolint:errcheck
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("GET %s: status %s", url, resp.Status)
|
||||
}
|
||||
|
||||
out, err := os.Create(dest) //nolint:gosec // paths are hardcoded constants
|
||||
if err != nil {
|
||||
return fmt.Errorf("create %s: %w", dest, err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(out, resp.Body); err != nil {
|
||||
out.Close() //nolint:errcheck
|
||||
return fmt.Errorf("write %s: %w", dest, err)
|
||||
}
|
||||
|
||||
if err := out.Close(); err != nil {
|
||||
return fmt.Errorf("close %s: %w", dest, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user