diff --git a/coverage-badge.svg b/coverage-badge.svg index 9b2fae3..82fd6fa 100644 --- a/coverage-badge.svg +++ b/coverage-badge.svg @@ -11,7 +11,7 @@ coverage coverage - 14.4% - 14.4% + 18.2% + 18.2% diff --git a/internal/dl/dl.go b/internal/dl/dl.go index 3415e25..4a91fcb 100644 --- a/internal/dl/dl.go +++ b/internal/dl/dl.go @@ -42,9 +42,6 @@ import ( "golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2s" "golang.org/x/exp/slices" - - "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" - "gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache" ) // Константа для имени файла манифеста кэша @@ -83,6 +80,11 @@ func (t Type) String() string { return "" } +type DlCache interface { + Get(context.Context, string) (string, bool) + New(context.Context, string) (string, error) +} + // Структура Options содержит параметры для загрузки файлов и каталогов type Options struct { Hash []byte @@ -94,6 +96,7 @@ type Options struct { PostprocDisabled bool Progress io.Writer LocalDir string + DlCache DlCache } // Метод для создания нового хеша на основе указанного алгоритма хеширования @@ -145,9 +148,6 @@ type UpdatingDownloader interface { // Функция Download загружает файл или каталог с использованием указанных параметров func Download(ctx context.Context, opts Options) (err error) { - cfg := config.GetInstance(ctx) - dc := dlcache.New(cfg) - normalized, err := normalizeURL(opts.URL) if err != nil { return err @@ -162,7 +162,7 @@ func Download(ctx context.Context, opts Options) (err error) { } var t Type - cacheDir, ok := dc.Get(ctx, opts.URL) + cacheDir, ok := opts.DlCache.Get(ctx, opts.URL) if ok { var updated bool if d, ok := d.(UpdatingDownloader); ok { @@ -221,7 +221,7 @@ func Download(ctx context.Context, opts Options) (err error) { slog.Info(gotext.Get("Downloading source"), "source", opts.Name, "downloader", d.Name()) - cacheDir, err = dc.New(ctx, opts.URL) + cacheDir, err = opts.DlCache.New(ctx, opts.URL) if err != nil { return err } diff --git a/internal/dl/dl_test.go b/internal/dl/dl_test.go new file mode 100644 index 0000000..b5f425a --- /dev/null +++ b/internal/dl/dl_test.go @@ -0,0 +1,139 @@ +// ALR - Any Linux Repository +// Copyright (C) 2025 Евгений Храмов +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package dl_test + +import ( + "context" + "net/http" + "net/http/httptest" + "os" + "path" + "testing" + + "github.com/stretchr/testify/assert" + + "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" + "gitea.plemya-x.ru/Plemya-x/ALR/internal/dl" + "gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache" +) + +func TestDownloadFileWithoutCache(t *testing.T) { + type testCase struct { + name string + expectedErr error + } + + for _, tc := range []testCase{ + { + name: "simple download", + expectedErr: nil, + }, + } { + t.Run(tc.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.URL.Path == "/file": + w.WriteHeader(http.StatusOK) + w.Write([]byte("Hello, World!")) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + defer server.Close() + + tmpdir, err := os.MkdirTemp("", "test-download") + assert.NoError(t, err) + defer os.RemoveAll(tmpdir) + + opts := dl.Options{ + CacheDisabled: true, + URL: server.URL + "/file", + Destination: tmpdir, + } + + err = dl.Download(context.Background(), opts) + assert.ErrorIs(t, err, tc.expectedErr) + _, err = os.Stat(path.Join(tmpdir, "file")) + assert.NoError(t, err) + }) + } +} + +type TestALRConfig struct{} + +func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths { + return &config.Paths{ + CacheDir: "/tmp", + } +} + +func TestDownloadFileWithCache(t *testing.T) { + type testCase struct { + name string + expectedErr error + } + + for _, tc := range []testCase{ + { + name: "simple download", + expectedErr: nil, + }, + } { + t.Run(tc.name, func(t *testing.T) { + called := 0 + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.URL.Path == "/file": + called += 1 + w.WriteHeader(http.StatusOK) + w.Write([]byte("Hello, World!")) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + defer server.Close() + + tmpdir, err := os.MkdirTemp("", "test-download") + assert.NoError(t, err) + defer os.RemoveAll(tmpdir) + + cfg := &TestALRConfig{} + + opts := dl.Options{ + CacheDisabled: false, + URL: server.URL + "/file", + Destination: tmpdir, + DlCache: dlcache.New(cfg), + } + + outputFile := path.Join(tmpdir, "file") + + err = dl.Download(context.Background(), opts) + assert.ErrorIs(t, err, tc.expectedErr) + _, err = os.Stat(outputFile) + assert.NoError(t, err) + + err = os.Remove(outputFile) + assert.NoError(t, err) + + err = dl.Download(context.Background(), opts) + assert.NoError(t, err) + assert.Equal(t, 1, called) + }) + } +} diff --git a/internal/dl/file.go b/internal/dl/file.go index 56405dd..521ca50 100644 --- a/internal/dl/file.go +++ b/internal/dl/file.go @@ -143,7 +143,7 @@ func (FileDownloader) Download(ctx context.Context, opts Options) (Type, string, return 0, "", err } r.Close() - out.Close() + // out.Close() // Проверка контрольной суммы if opts.Hash != nil { diff --git a/internal/translations/default.pot b/internal/translations/default.pot index 28de0ef..b0cc59f 100644 --- a/internal/translations/default.pot +++ b/internal/translations/default.pot @@ -293,81 +293,81 @@ msgstr "" msgid "Error while running app" msgstr "" -#: pkg/build/build.go:107 +#: pkg/build/build.go:108 msgid "Failed to prompt user to view build script" msgstr "" -#: pkg/build/build.go:111 +#: pkg/build/build.go:112 msgid "Building package" msgstr "" -#: pkg/build/build.go:155 +#: pkg/build/build.go:156 msgid "Downloading sources" msgstr "" -#: pkg/build/build.go:167 +#: pkg/build/build.go:168 msgid "Building package metadata" msgstr "" -#: pkg/build/build.go:189 +#: pkg/build/build.go:190 msgid "Compressing package" msgstr "" -#: pkg/build/build.go:315 +#: pkg/build/build.go:316 msgid "" "Your system's CPU architecture doesn't match this package. Do you want to " "build anyway?" msgstr "" -#: pkg/build/build.go:326 +#: pkg/build/build.go:327 msgid "This package is already installed" msgstr "" -#: pkg/build/build.go:354 +#: pkg/build/build.go:355 msgid "Installing build dependencies" msgstr "" -#: pkg/build/build.go:396 +#: pkg/build/build.go:397 msgid "Installing dependencies" msgstr "" -#: pkg/build/build.go:442 +#: pkg/build/build.go:443 msgid "Executing version()" msgstr "" -#: pkg/build/build.go:462 +#: pkg/build/build.go:463 msgid "Updating version" msgstr "" -#: pkg/build/build.go:467 +#: pkg/build/build.go:468 msgid "Executing prepare()" msgstr "" -#: pkg/build/build.go:477 +#: pkg/build/build.go:478 msgid "Executing build()" msgstr "" -#: pkg/build/build.go:487 +#: pkg/build/build.go:488 msgid "Executing package()" msgstr "" -#: pkg/build/build.go:509 +#: pkg/build/build.go:510 msgid "Executing files()" msgstr "" -#: pkg/build/build.go:587 +#: pkg/build/build.go:588 msgid "AutoProv is not implemented for this package format, so it's skipped" msgstr "" -#: pkg/build/build.go:598 +#: pkg/build/build.go:599 msgid "AutoReq is not implemented for this package format, so it's skipped" msgstr "" -#: pkg/build/build.go:705 +#: pkg/build/build.go:706 msgid "Would you like to remove the build dependencies?" msgstr "" -#: pkg/build/build.go:811 +#: pkg/build/build.go:812 msgid "The checksums array must be the same length as sources" msgstr "" diff --git a/internal/translations/po/ru/default.po b/internal/translations/po/ru/default.po index fde74bf..3d5e548 100644 --- a/internal/translations/po/ru/default.po +++ b/internal/translations/po/ru/default.po @@ -307,27 +307,27 @@ msgstr "" msgid "Error while running app" msgstr "Ошибка при запуске приложения" -#: pkg/build/build.go:107 +#: pkg/build/build.go:108 msgid "Failed to prompt user to view build script" msgstr "Не удалось предложить пользователю просмотреть скрипт сборки" -#: pkg/build/build.go:111 +#: pkg/build/build.go:112 msgid "Building package" msgstr "Сборка пакета" -#: pkg/build/build.go:155 +#: pkg/build/build.go:156 msgid "Downloading sources" msgstr "Скачивание источников" -#: pkg/build/build.go:167 +#: pkg/build/build.go:168 msgid "Building package metadata" msgstr "Сборка метаданных пакета" -#: pkg/build/build.go:189 +#: pkg/build/build.go:190 msgid "Compressing package" msgstr "Сжатие пакета" -#: pkg/build/build.go:315 +#: pkg/build/build.go:316 msgid "" "Your system's CPU architecture doesn't match this package. Do you want to " "build anyway?" @@ -335,57 +335,57 @@ msgstr "" "Архитектура процессора вашей системы не соответствует этому пакету. Вы все " "равно хотите выполнить сборку?" -#: pkg/build/build.go:326 +#: pkg/build/build.go:327 msgid "This package is already installed" msgstr "Этот пакет уже установлен" -#: pkg/build/build.go:354 +#: pkg/build/build.go:355 msgid "Installing build dependencies" msgstr "Установка зависимостей сборки" -#: pkg/build/build.go:396 +#: pkg/build/build.go:397 msgid "Installing dependencies" msgstr "Установка зависимостей" -#: pkg/build/build.go:442 +#: pkg/build/build.go:443 msgid "Executing version()" msgstr "Исполнение версия()" -#: pkg/build/build.go:462 +#: pkg/build/build.go:463 msgid "Updating version" msgstr "Обновление версии" -#: pkg/build/build.go:467 +#: pkg/build/build.go:468 msgid "Executing prepare()" msgstr "Исполнение prepare()" -#: pkg/build/build.go:477 +#: pkg/build/build.go:478 msgid "Executing build()" msgstr "Исполнение build()" -#: pkg/build/build.go:487 +#: pkg/build/build.go:488 msgid "Executing package()" msgstr "Исполнение package()" -#: pkg/build/build.go:509 +#: pkg/build/build.go:510 msgid "Executing files()" msgstr "Исполнение files()" -#: pkg/build/build.go:587 +#: pkg/build/build.go:588 msgid "AutoProv is not implemented for this package format, so it's skipped" msgstr "" "AutoProv не реализовано для этого формата пакета, поэтому будет пропущено" -#: pkg/build/build.go:598 +#: pkg/build/build.go:599 msgid "AutoReq is not implemented for this package format, so it's skipped" msgstr "" "AutoReq не реализовано для этого формата пакета, поэтому будет пропущено" -#: pkg/build/build.go:705 +#: pkg/build/build.go:706 msgid "Would you like to remove the build dependencies?" msgstr "Хотели бы вы удалить зависимости сборки?" -#: pkg/build/build.go:811 +#: pkg/build/build.go:812 msgid "The checksums array must be the same length as sources" msgstr "Массив контрольных сумм должен быть той же длины, что и источники" diff --git a/pkg/build/build.go b/pkg/build/build.go index 9a30e1a..62be0a0 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -54,6 +54,7 @@ import ( "gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" "gitea.plemya-x.ru/Plemya-x/ALR/internal/dl" + "gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache" "gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" "gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" "gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers" @@ -842,6 +843,9 @@ func getSources(ctx context.Context, dirs types.Directories, bv *types.BuildVars } } + cfg := config.GetInstance(ctx) + opts.DlCache = dlcache.New(cfg) + err := dl.Download(ctx, opts) if err != nil { return err