diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 505ace1a..c7b29d82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,13 +17,13 @@ jobs: if: github.repository == 'saltbo/zpan' defaults: run: - working-directory: downloader + working-directory: cmd steps: - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: - go-version-file: downloader/go.mod - cache-dependency-path: downloader/go.sum + go-version-file: cmd/go.mod + cache-dependency-path: cmd/go.sum - name: Check formatting run: | files="$(gofmt -l .)" @@ -51,8 +51,8 @@ jobs: cache: pnpm - uses: actions/setup-go@v6 with: - go-version-file: downloader/go.mod - cache-dependency-path: downloader/go.sum + go-version-file: cmd/go.mod + cache-dependency-path: cmd/go.sum - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm typecheck diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7064b866..13e7eaf5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,8 +20,8 @@ jobs: cache: pnpm - uses: actions/setup-go@v6 with: - go-version-file: downloader/go.mod - cache-dependency-path: downloader/go.sum + go-version-file: cmd/go.mod + cache-dependency-path: cmd/go.sum - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm typecheck diff --git a/Dockerfile b/Dockerfile index 597699e8..f5323b66 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,12 +15,12 @@ COPY . . RUN pnpm build:node \ && pnpm prune --prod -FROM golang:1.25 AS downloader-builder -WORKDIR /app/downloader -COPY downloader/go.mod downloader/go.sum ./ +FROM golang:1.25 AS cli-builder +WORKDIR /app/cmd +COPY cmd/go.mod cmd/go.sum ./ RUN go mod download -COPY downloader ./ -RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/zpan ./cmd/zpan +COPY cmd ./ +RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/zpan ./zpan FROM debian:bookworm-slim AS cli RUN apt-get update \ @@ -28,7 +28,7 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* \ && addgroup --system zpan \ && adduser --system --ingroup zpan --home /home/zpan zpan -COPY --from=downloader-builder /out/zpan /usr/local/bin/zpan +COPY --from=cli-builder /out/zpan /usr/local/bin/zpan RUN mkdir -p /home/zpan/.config/zpan /home/zpan/.local/state/zpan/downloader /downloads \ && chown -R zpan:zpan /home/zpan /downloads USER zpan @@ -52,7 +52,7 @@ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/migrations ./migrations COPY --from=builder /app/scripts/docker-entrypoint.sh /app/scripts/docker-entrypoint.sh -COPY --from=downloader-builder /out/zpan /usr/local/bin/zpan +COPY --from=cli-builder /out/zpan /usr/local/bin/zpan RUN mkdir -p /data /home/zpan/.config/zpan /home/zpan/.local/state/zpan/downloader \ && chown -R zpan:zpan /data /home/zpan diff --git a/downloader/go.mod b/cmd/go.mod similarity index 97% rename from downloader/go.mod rename to cmd/go.mod index 62fd975c..637d3434 100644 --- a/downloader/go.mod +++ b/cmd/go.mod @@ -1,4 +1,4 @@ -module github.com/saltbo/zpan/downloader +module github.com/saltbo/zpan/cmd go 1.25.0 diff --git a/downloader/go.sum b/cmd/go.sum similarity index 100% rename from downloader/go.sum rename to cmd/go.sum diff --git a/downloader/internal/client/client.go b/cmd/internal/client/client.go similarity index 99% rename from downloader/internal/client/client.go rename to cmd/internal/client/client.go index 6e523654..919ca659 100644 --- a/downloader/internal/client/client.go +++ b/cmd/internal/client/client.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/saltbo/zpan/downloader/internal/openapi" + "github.com/saltbo/zpan/cmd/internal/openapi" ) type Client struct { diff --git a/downloader/internal/client/client_test.go b/cmd/internal/client/client_test.go similarity index 100% rename from downloader/internal/client/client_test.go rename to cmd/internal/client/client_test.go diff --git a/downloader/internal/config/config.go b/cmd/internal/config/config.go similarity index 100% rename from downloader/internal/config/config.go rename to cmd/internal/config/config.go diff --git a/downloader/internal/config/config_test.go b/cmd/internal/config/config_test.go similarity index 100% rename from downloader/internal/config/config_test.go rename to cmd/internal/config/config_test.go diff --git a/downloader/internal/engine/aria2.go b/cmd/internal/engine/aria2.go similarity index 99% rename from downloader/internal/engine/aria2.go rename to cmd/internal/engine/aria2.go index 36615fb6..809be1e7 100644 --- a/downloader/internal/engine/aria2.go +++ b/cmd/internal/engine/aria2.go @@ -18,7 +18,7 @@ import ( "github.com/Braurbeki/arigo" "github.com/cenkalti/rpc2" - "github.com/saltbo/zpan/downloader/internal/client" + "github.com/saltbo/zpan/cmd/internal/client" ) type Aria2 struct { diff --git a/downloader/internal/engine/engine.go b/cmd/internal/engine/engine.go similarity index 99% rename from downloader/internal/engine/engine.go rename to cmd/internal/engine/engine.go index f9997b1f..cac1eed3 100644 --- a/downloader/internal/engine/engine.go +++ b/cmd/internal/engine/engine.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/saltbo/zpan/downloader/internal/client" + "github.com/saltbo/zpan/cmd/internal/client" ) type Result struct { diff --git a/downloader/internal/engine/engine_test.go b/cmd/internal/engine/engine_test.go similarity index 99% rename from downloader/internal/engine/engine_test.go rename to cmd/internal/engine/engine_test.go index 76253aa2..1d9aa754 100644 --- a/downloader/internal/engine/engine_test.go +++ b/cmd/internal/engine/engine_test.go @@ -14,7 +14,7 @@ import ( "github.com/Braurbeki/arigo" qbittorrent "github.com/autobrr/go-qbittorrent" "github.com/cenkalti/rpc2" - "github.com/saltbo/zpan/downloader/internal/client" + "github.com/saltbo/zpan/cmd/internal/client" ) func downloadTask(id, sourceType, sourceURI string) client.DownloadTask { diff --git a/downloader/internal/engine/http.go b/cmd/internal/engine/http.go similarity index 98% rename from downloader/internal/engine/http.go rename to cmd/internal/engine/http.go index 602dd3d9..6fb025f7 100644 --- a/downloader/internal/engine/http.go +++ b/cmd/internal/engine/http.go @@ -12,7 +12,7 @@ import ( "strconv" "time" - "github.com/saltbo/zpan/downloader/internal/client" + "github.com/saltbo/zpan/cmd/internal/client" ) type HTTP struct { diff --git a/downloader/internal/engine/live_download_test.go b/cmd/internal/engine/live_download_test.go similarity index 99% rename from downloader/internal/engine/live_download_test.go rename to cmd/internal/engine/live_download_test.go index 84d49857..9f3d3463 100644 --- a/downloader/internal/engine/live_download_test.go +++ b/cmd/internal/engine/live_download_test.go @@ -18,7 +18,7 @@ import ( "testing" "time" - "github.com/saltbo/zpan/downloader/internal/client" + "github.com/saltbo/zpan/cmd/internal/client" ) func liveTask(id, sourceType, sourceURI, name string) client.DownloadTask { diff --git a/downloader/internal/engine/process.go b/cmd/internal/engine/process.go similarity index 100% rename from downloader/internal/engine/process.go rename to cmd/internal/engine/process.go diff --git a/downloader/internal/engine/process_unix.go b/cmd/internal/engine/process_unix.go similarity index 100% rename from downloader/internal/engine/process_unix.go rename to cmd/internal/engine/process_unix.go diff --git a/downloader/internal/engine/process_windows.go b/cmd/internal/engine/process_windows.go similarity index 100% rename from downloader/internal/engine/process_windows.go rename to cmd/internal/engine/process_windows.go diff --git a/downloader/internal/engine/qbittorrent.go b/cmd/internal/engine/qbittorrent.go similarity index 99% rename from downloader/internal/engine/qbittorrent.go rename to cmd/internal/engine/qbittorrent.go index f6bc26b4..a3538fe9 100644 --- a/downloader/internal/engine/qbittorrent.go +++ b/cmd/internal/engine/qbittorrent.go @@ -13,7 +13,7 @@ import ( "time" qbittorrent "github.com/autobrr/go-qbittorrent" - "github.com/saltbo/zpan/downloader/internal/client" + "github.com/saltbo/zpan/cmd/internal/client" ) type QBittorrent struct { diff --git a/downloader/internal/openapi/client.gen.go b/cmd/internal/openapi/client.gen.go similarity index 100% rename from downloader/internal/openapi/client.gen.go rename to cmd/internal/openapi/client.gen.go diff --git a/downloader/internal/worker/api.go b/cmd/internal/worker/api.go similarity index 98% rename from downloader/internal/worker/api.go rename to cmd/internal/worker/api.go index 472f02ff..2b3e41dd 100644 --- a/downloader/internal/worker/api.go +++ b/cmd/internal/worker/api.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/saltbo/zpan/downloader/internal/client" + "github.com/saltbo/zpan/cmd/internal/client" ) const apiRetryAttempts = 3 diff --git a/downloader/internal/worker/api_test.go b/cmd/internal/worker/api_test.go similarity index 94% rename from downloader/internal/worker/api_test.go rename to cmd/internal/worker/api_test.go index ecf720cf..e03524c3 100644 --- a/downloader/internal/worker/api_test.go +++ b/cmd/internal/worker/api_test.go @@ -5,7 +5,7 @@ import ( "errors" "testing" - "github.com/saltbo/zpan/downloader/internal/config" + "github.com/saltbo/zpan/cmd/internal/config" ) func TestCallAPIRetriesTransientErrors(t *testing.T) { diff --git a/downloader/internal/worker/attempt_ledger.go b/cmd/internal/worker/attempt_ledger.go similarity index 100% rename from downloader/internal/worker/attempt_ledger.go rename to cmd/internal/worker/attempt_ledger.go diff --git a/downloader/internal/worker/engines.go b/cmd/internal/worker/engines.go similarity index 98% rename from downloader/internal/worker/engines.go rename to cmd/internal/worker/engines.go index 52930fa5..bb70b5c9 100644 --- a/downloader/internal/worker/engines.go +++ b/cmd/internal/worker/engines.go @@ -6,8 +6,8 @@ import ( "strings" "time" - "github.com/saltbo/zpan/downloader/internal/config" - "github.com/saltbo/zpan/downloader/internal/engine" + "github.com/saltbo/zpan/cmd/internal/config" + "github.com/saltbo/zpan/cmd/internal/engine" ) func (w *Worker) resolveEngine(ctx context.Context) error { diff --git a/downloader/internal/worker/seed_ledger.go b/cmd/internal/worker/seed_ledger.go similarity index 100% rename from downloader/internal/worker/seed_ledger.go rename to cmd/internal/worker/seed_ledger.go diff --git a/downloader/internal/worker/seeds.go b/cmd/internal/worker/seeds.go similarity index 98% rename from downloader/internal/worker/seeds.go rename to cmd/internal/worker/seeds.go index cb72d134..6e8b9d10 100644 --- a/downloader/internal/worker/seeds.go +++ b/cmd/internal/worker/seeds.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/saltbo/zpan/downloader/internal/client" - "github.com/saltbo/zpan/downloader/internal/engine" + "github.com/saltbo/zpan/cmd/internal/client" + "github.com/saltbo/zpan/cmd/internal/engine" ) const retainedSeedReportInterval = 5 * time.Second diff --git a/downloader/internal/worker/uploader.go b/cmd/internal/worker/uploader.go similarity index 98% rename from downloader/internal/worker/uploader.go rename to cmd/internal/worker/uploader.go index c08afbb6..e6a93fe4 100644 --- a/downloader/internal/worker/uploader.go +++ b/cmd/internal/worker/uploader.go @@ -11,8 +11,8 @@ import ( "strings" "time" - "github.com/saltbo/zpan/downloader/internal/client" - "github.com/saltbo/zpan/downloader/internal/engine" + "github.com/saltbo/zpan/cmd/internal/client" + "github.com/saltbo/zpan/cmd/internal/engine" ) const maxSingleUploadSize = 5 * 1024 * 1024 * 1024 diff --git a/downloader/internal/worker/worker.go b/cmd/internal/worker/worker.go similarity index 99% rename from downloader/internal/worker/worker.go rename to cmd/internal/worker/worker.go index 03c46221..c8708a85 100644 --- a/downloader/internal/worker/worker.go +++ b/cmd/internal/worker/worker.go @@ -15,9 +15,9 @@ import ( "sync" "time" - "github.com/saltbo/zpan/downloader/internal/client" - "github.com/saltbo/zpan/downloader/internal/config" - "github.com/saltbo/zpan/downloader/internal/engine" + "github.com/saltbo/zpan/cmd/internal/client" + "github.com/saltbo/zpan/cmd/internal/config" + "github.com/saltbo/zpan/cmd/internal/engine" ) const Version = "0.1.0" diff --git a/downloader/internal/worker/worker_test.go b/cmd/internal/worker/worker_test.go similarity index 99% rename from downloader/internal/worker/worker_test.go rename to cmd/internal/worker/worker_test.go index 13446b67..c8b6e5be 100644 --- a/downloader/internal/worker/worker_test.go +++ b/cmd/internal/worker/worker_test.go @@ -14,9 +14,9 @@ import ( "testing" "time" - "github.com/saltbo/zpan/downloader/internal/client" - "github.com/saltbo/zpan/downloader/internal/config" - "github.com/saltbo/zpan/downloader/internal/engine" + "github.com/saltbo/zpan/cmd/internal/client" + "github.com/saltbo/zpan/cmd/internal/config" + "github.com/saltbo/zpan/cmd/internal/engine" ) func TestResolveEngineRejectsUnknownConfiguredEngine(t *testing.T) { diff --git a/downloader/oapi-codegen.yaml b/cmd/oapi-codegen.yaml similarity index 100% rename from downloader/oapi-codegen.yaml rename to cmd/oapi-codegen.yaml diff --git a/downloader/cmd/zpan/main.go b/cmd/zpan/main.go similarity index 95% rename from downloader/cmd/zpan/main.go rename to cmd/zpan/main.go index 4ab13a7a..05cab5c1 100644 --- a/downloader/cmd/zpan/main.go +++ b/cmd/zpan/main.go @@ -12,9 +12,9 @@ import ( "syscall" "time" - "github.com/saltbo/zpan/downloader/internal/client" - "github.com/saltbo/zpan/downloader/internal/config" - "github.com/saltbo/zpan/downloader/internal/worker" + "github.com/saltbo/zpan/cmd/internal/client" + "github.com/saltbo/zpan/cmd/internal/config" + "github.com/saltbo/zpan/cmd/internal/worker" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -43,6 +43,7 @@ func rootCommand() *cobra.Command { v.SetConfigFile(cfgFile) } + root.AddCommand(configCommand(v, &cfgFile)) root.AddCommand(downloaderCommand(v, &cfgFile)) return root } @@ -53,7 +54,6 @@ func downloaderCommand(v *viper.Viper, cfgFile *string) *cobra.Command { Short: "Manage the ZPan remote downloader", } cmd.AddCommand(upCommand(v, cfgFile)) - cmd.AddCommand(downloaderConfigCommand(v, cfgFile)) return cmd } @@ -116,10 +116,10 @@ func upCommand(v *viper.Viper, cfgFile *string) *cobra.Command { } } -func downloaderConfigCommand(v *viper.Viper, cfgFile *string) *cobra.Command { +func configCommand(v *viper.Viper, cfgFile *string) *cobra.Command { cmd := &cobra.Command{ Use: "config", - Short: "Manage downloader configuration", + Short: "Manage CLI configuration", } cmd.AddCommand(&cobra.Command{ Use: "init", diff --git a/downloader/cmd/zpan/main_test.go b/cmd/zpan/main_test.go similarity index 78% rename from downloader/cmd/zpan/main_test.go rename to cmd/zpan/main_test.go index 1539eb81..107bb0a6 100644 --- a/downloader/cmd/zpan/main_test.go +++ b/cmd/zpan/main_test.go @@ -3,7 +3,7 @@ package main import ( "testing" - "github.com/saltbo/zpan/downloader/internal/config" + "github.com/saltbo/zpan/cmd/internal/config" ) func TestRegistrationHeartbeatNormalizesAutoEngine(t *testing.T) { @@ -49,4 +49,14 @@ func TestRootCommandExposesDownloaderSubcommands(t *testing.T) { if downloader.Name() != "up" { t.Fatalf("expected downloader up command, got %q", downloader.Name()) } + config, _, err := root.Find([]string{"config", "init"}) + if err != nil { + t.Fatal(err) + } + if config.Name() != "init" { + t.Fatalf("expected root config init command, got %q", config.Name()) + } + if command, _, err := root.Find([]string{"downloader", "config"}); err == nil && command.Name() == "config" { + t.Fatal("downloader config command should not be exposed") + } } diff --git a/package.json b/package.json index 961b704d..8ec1ef89 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "e2e:archive": "node scripts/run-cloud-e2e.mjs --local --with-s3-mock --spec archive.spec.ts", "e2e:archive:cf": "node scripts/run-cloud-e2e.mjs --runtime cf --local --with-s3-mock --spec archive.spec.ts", "openapi:downloader": "tsx scripts/generate-downloader-openapi.ts", - "openapi:downloader:go": "pnpm openapi:downloader && cd downloader && go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.7.0 -config oapi-codegen.yaml ../docs/openapi/downloader.json", + "openapi:downloader:go": "pnpm openapi:downloader && cd cmd && go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.7.0 -config oapi-codegen.yaml ../docs/openapi/downloader.json", "openapi:downloader:check": "tsx scripts/check-downloader-openapi.ts", "openapi:downloader:all": "pnpm openapi:downloader:go" }, diff --git a/scripts/check-downloader-openapi.ts b/scripts/check-downloader-openapi.ts index 93e33d26..fe0aaba1 100644 --- a/scripts/check-downloader-openapi.ts +++ b/scripts/check-downloader-openapi.ts @@ -52,7 +52,7 @@ async function main() { 'Downloader OpenAPI document is stale.', ) await assertSame( - 'downloader/internal/openapi/client.gen.go', + 'cmd/internal/openapi/client.gen.go', generatedClientPath, 'Downloader Go OpenAPI client is stale.', )