From 20674dd05da909b42cbdd07a6682fdf1d980f011 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Wed, 9 Nov 2022 07:34:27 +0100 Subject: [PATCH 1/5] Add package registry quota limits (#21584) Related #20471 This PR adds global quota limits for the package registry. Settings for individual users/orgs can be added in a seperate PR using the settings table. Co-authored-by: Lauris BH Co-authored-by: Lunny Xiao --- cmd/migrate_storage_test.go | 5 +- custom/conf/app.example.ini | 29 ++++++ .../doc/advanced/config-cheat-sheet.en-us.md | 14 +++ models/packages/package_file.go | 10 ++ models/packages/package_version.go | 9 ++ modules/setting/packages.go | 50 +++++++++- modules/setting/packages_test.go | 31 ++++++ routers/api/packages/composer/composer.go | 14 ++- routers/api/packages/conan/conan.go | 14 ++- routers/api/packages/generic/generic.go | 14 ++- routers/api/packages/helm/helm.go | 10 +- routers/api/packages/maven/maven.go | 10 +- routers/api/packages/npm/npm.go | 14 ++- routers/api/packages/nuget/nuget.go | 28 ++++-- routers/api/packages/pub/pub.go | 14 ++- routers/api/packages/pypi/pypi.go | 14 ++- routers/api/packages/rubygems/rubygems.go | 14 ++- routers/api/packages/vagrant/vagrant.go | 14 ++- services/packages/packages.go | 97 ++++++++++++++++++- tests/integration/api_packages_test.go | 34 +++++++ 20 files changed, 378 insertions(+), 61 deletions(-) create mode 100644 modules/setting/packages_test.go diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go index 0d264ef5a1bd..7051591ad68e 100644 --- a/cmd/migrate_storage_test.go +++ b/cmd/migrate_storage_test.go @@ -44,8 +44,9 @@ func TestMigratePackages(t *testing.T) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: "a.go", }, - Data: buf, - IsLead: true, + Creator: creator, + Data: buf, + IsLead: true, }) assert.NoError(t, err) assert.NotNil(t, v) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b59ceee4f1db..b46dfc20a969 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2335,6 +2335,35 @@ ROUTER = console ;; ;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload` ;CHUNKED_UPLOAD_PATH = tmp/package-upload +;; +;; Maxmimum count of package versions a single owner can have (`-1` means no limits) +;LIMIT_TOTAL_OWNER_COUNT = -1 +;; Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_TOTAL_OWNER_SIZE = -1 +;; Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_COMPOSER = -1 +;; Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_CONAN = -1 +;; Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_CONTAINER = -1 +;; Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_GENERIC = -1 +;; Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_HELM = -1 +;; Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_MAVEN = -1 +;; Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_NPM = -1 +;; Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_NUGET = -1 +;; Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_PUB = -1 +;; Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_PYPI = -1 +;; Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_RUBYGEMS = -1 +;; Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;LIMIT_SIZE_VAGRANT = -1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index df1911934c88..28bcaf29afdc 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -1138,6 +1138,20 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `ENABLED`: **true**: Enable/Disable package registry capabilities - `CHUNKED_UPLOAD_PATH`: **tmp/package-upload**: Path for chunked uploads. Defaults to `APP_DATA_PATH` + `tmp/package-upload` +- `LIMIT_TOTAL_OWNER_COUNT`: **-1**: Maxmimum count of package versions a single owner can have (`-1` means no limits) +- `LIMIT_TOTAL_OWNER_SIZE`: **-1**: Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_COMPOSER`: **-1**: Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONAN`: **-1**: Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONTAINER`: **-1**: Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_GENERIC`: **-1**: Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_HELM`: **-1**: Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_MAVEN`: **-1**: Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NPM`: **-1**: Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NUGET`: **-1**: Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PUB`: **-1**: Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PYPI`: **-1**: Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_RUBYGEMS`: **-1**: Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_VAGRANT`: **-1**: Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ## Mirror (`mirror`) diff --git a/models/packages/package_file.go b/models/packages/package_file.go index 8f304ce8ac42..9f6284af0763 100644 --- a/models/packages/package_file.go +++ b/models/packages/package_file.go @@ -199,3 +199,13 @@ func SearchFiles(ctx context.Context, opts *PackageFileSearchOptions) ([]*Packag count, err := sess.FindAndCount(&pfs) return pfs, count, err } + +// CalculateBlobSize sums up all blob sizes matching the search options. +// It does NOT respect the deduplication of blobs. +func CalculateBlobSize(ctx context.Context, opts *PackageFileSearchOptions) (int64, error) { + return db.GetEngine(ctx). + Table("package_file"). + Where(opts.toConds()). + Join("INNER", "package_blob", "package_blob.id = package_file.blob_id"). + SumInt(new(PackageBlob), "size") +} diff --git a/models/packages/package_version.go b/models/packages/package_version.go index 782261c575dc..48c6aa7d607f 100644 --- a/models/packages/package_version.go +++ b/models/packages/package_version.go @@ -319,3 +319,12 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P count, err := sess.FindAndCount(&pvs) return pvs, count, err } + +// CountVersions counts all versions of packages matching the search options +func CountVersions(ctx context.Context, opts *PackageSearchOptions) (int64, error) { + return db.GetEngine(ctx). + Where(opts.toConds()). + Table("package_version"). + Join("INNER", "package", "package.id = package_version.package_id"). + Count(new(PackageVersion)) +} diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 5e0f2a3b03da..62201032c740 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -5,11 +5,15 @@ package setting import ( + "math" "net/url" "os" "path/filepath" "code.gitea.io/gitea/modules/log" + + "github.com/dustin/go-humanize" + ini "gopkg.in/ini.v1" ) // Package registry settings @@ -19,8 +23,24 @@ var ( Enabled bool ChunkedUploadPath string RegistryHost string + + LimitTotalOwnerCount int64 + LimitTotalOwnerSize int64 + LimitSizeComposer int64 + LimitSizeConan int64 + LimitSizeContainer int64 + LimitSizeGeneric int64 + LimitSizeHelm int64 + LimitSizeMaven int64 + LimitSizeNpm int64 + LimitSizeNuGet int64 + LimitSizePub int64 + LimitSizePyPI int64 + LimitSizeRubyGems int64 + LimitSizeVagrant int64 }{ - Enabled: true, + Enabled: true, + LimitTotalOwnerCount: -1, } ) @@ -43,4 +63,32 @@ func newPackages() { if err := os.MkdirAll(Packages.ChunkedUploadPath, os.ModePerm); err != nil { log.Error("Unable to create chunked upload directory: %s (%v)", Packages.ChunkedUploadPath, err) } + + Packages.LimitTotalOwnerSize = mustBytes(sec, "LIMIT_TOTAL_OWNER_SIZE") + Packages.LimitSizeComposer = mustBytes(sec, "LIMIT_SIZE_COMPOSER") + Packages.LimitSizeConan = mustBytes(sec, "LIMIT_SIZE_CONAN") + Packages.LimitSizeContainer = mustBytes(sec, "LIMIT_SIZE_CONTAINER") + Packages.LimitSizeGeneric = mustBytes(sec, "LIMIT_SIZE_GENERIC") + Packages.LimitSizeHelm = mustBytes(sec, "LIMIT_SIZE_HELM") + Packages.LimitSizeMaven = mustBytes(sec, "LIMIT_SIZE_MAVEN") + Packages.LimitSizeNpm = mustBytes(sec, "LIMIT_SIZE_NPM") + Packages.LimitSizeNuGet = mustBytes(sec, "LIMIT_SIZE_NUGET") + Packages.LimitSizePub = mustBytes(sec, "LIMIT_SIZE_PUB") + Packages.LimitSizePyPI = mustBytes(sec, "LIMIT_SIZE_PYPI") + Packages.LimitSizeRubyGems = mustBytes(sec, "LIMIT_SIZE_RUBYGEMS") + Packages.LimitSizeVagrant = mustBytes(sec, "LIMIT_SIZE_VAGRANT") +} + +func mustBytes(section *ini.Section, key string) int64 { + const noLimit = "-1" + + value := section.Key(key).MustString(noLimit) + if value == noLimit { + return -1 + } + bytes, err := humanize.ParseBytes(value) + if err != nil || bytes > math.MaxInt64 { + return -1 + } + return int64(bytes) } diff --git a/modules/setting/packages_test.go b/modules/setting/packages_test.go new file mode 100644 index 000000000000..059273dce4be --- /dev/null +++ b/modules/setting/packages_test.go @@ -0,0 +1,31 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package setting + +import ( + "testing" + + "github.com/stretchr/testify/assert" + ini "gopkg.in/ini.v1" +) + +func TestMustBytes(t *testing.T) { + test := func(value string) int64 { + sec, _ := ini.Empty().NewSection("test") + sec.NewKey("VALUE", value) + + return mustBytes(sec, "VALUE") + } + + assert.EqualValues(t, -1, test("")) + assert.EqualValues(t, -1, test("-1")) + assert.EqualValues(t, 0, test("0")) + assert.EqualValues(t, 1, test("1")) + assert.EqualValues(t, 10000, test("10000")) + assert.EqualValues(t, 1000000, test("1 mb")) + assert.EqualValues(t, 1048576, test("1mib")) + assert.EqualValues(t, 1782579, test("1.7mib")) + assert.EqualValues(t, -1, test("1 yib")) // too large +} diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index 86ef7cbd9af5..92e83dbe79d2 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -235,16 +235,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(fmt.Sprintf("%s.%s.zip", strings.ReplaceAll(cp.Name, "/", "-"), cp.Version)), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index dd078d6ad34d..c8c9dc3e384b 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -348,8 +348,9 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey Filename: strings.ToLower(filename), CompositeKey: fileKey, }, - Data: buf, - IsLead: isConanfileFile, + Creator: ctx.Doer, + Data: buf, + IsLead: isConanfileFile, Properties: map[string]string{ conan_module.PropertyRecipeUser: rref.User, conan_module.PropertyRecipeChannel: rref.Channel, @@ -416,11 +417,14 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey pfci, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index 81891bec2646..1bccc6764cf1 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -104,16 +104,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go index 9c85e0874fd4..662d9a5dda28 100644 --- a/routers/api/packages/helm/helm.go +++ b/routers/api/packages/helm/helm.go @@ -186,17 +186,21 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: createFilename(metadata), }, + Creator: ctx.Doer, Data: buf, IsLead: true, OverwriteExisting: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index bf00c199f563..de274b204609 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -266,6 +266,7 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: params.Filename, }, + Creator: ctx.Doer, Data: buf, IsLead: false, OverwriteExisting: params.IsMeta, @@ -312,11 +313,14 @@ func UploadPackageFile(ctx *context.Context) { pfci, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 82dae0cf435d..6d589bde3a54 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -180,16 +180,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: npmPackage.Filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index e84aef3160f0..442d94243ba3 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -374,16 +374,20 @@ func UploadPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(fmt.Sprintf("%s.%s.nupkg", np.ID, np.Version)), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } @@ -428,8 +432,9 @@ func UploadSymbolPackage(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(fmt.Sprintf("%s.%s.snupkg", np.ID, np.Version)), }, - Data: buf, - IsLead: false, + Creator: ctx.Doer, + Data: buf, + IsLead: false, }, ) if err != nil { @@ -438,6 +443,8 @@ func UploadSymbolPackage(ctx *context.Context) { apiError(ctx, http.StatusNotFound, err) case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) + case packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) default: apiError(ctx, http.StatusInternalServerError, err) } @@ -452,8 +459,9 @@ func UploadSymbolPackage(ctx *context.Context) { Filename: strings.ToLower(pdb.Name), CompositeKey: strings.ToLower(pdb.ID), }, - Data: pdb.Content, - IsLead: false, + Creator: ctx.Doer, + Data: pdb.Content, + IsLead: false, Properties: map[string]string{ nuget_module.PropertySymbolID: strings.ToLower(pdb.ID), }, @@ -463,6 +471,8 @@ func UploadSymbolPackage(ctx *context.Context) { switch err { case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) + case packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) default: apiError(ctx, http.StatusInternalServerError, err) } diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go index 9af0ceeb0e6b..635147b6d0c4 100644 --- a/routers/api/packages/pub/pub.go +++ b/routers/api/packages/pub/pub.go @@ -199,16 +199,20 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(pck.Version + ".tar.gz"), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index 4c8041c30cc4..4853e6658bdc 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -162,16 +162,20 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: fileHeader.Filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index 319c94b91fee..eeae21146cbe 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -242,16 +242,20 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: filename, }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { + switch err { + case packages_model.ErrDuplicatePackageVersion: apiError(ctx, http.StatusBadRequest, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/vagrant/vagrant.go b/routers/api/packages/vagrant/vagrant.go index 7750e5dc4b2b..31ac56a532c7 100644 --- a/routers/api/packages/vagrant/vagrant.go +++ b/routers/api/packages/vagrant/vagrant.go @@ -193,19 +193,23 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: strings.ToLower(boxProvider), }, - Data: buf, - IsLead: true, + Creator: ctx.Doer, + Data: buf, + IsLead: true, Properties: map[string]string{ vagrant_module.PropertyProvider: strings.TrimSuffix(boxProvider, ".box"), }, }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageFile { + switch err { + case packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusConflict, err) - return + case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: + apiError(ctx, http.StatusForbidden, err) + default: + apiError(ctx, http.StatusInternalServerError, err) } - apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/services/packages/packages.go b/services/packages/packages.go index 96132eac0980..443976e174b7 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -6,6 +6,7 @@ package packages import ( "context" + "errors" "fmt" "io" "strings" @@ -19,10 +20,17 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" packages_module "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" container_service "code.gitea.io/gitea/services/packages/container" ) +var ( + ErrQuotaTypeSize = errors.New("maximum allowed package type size exceeded") + ErrQuotaTotalSize = errors.New("maximum allowed package storage quota exceeded") + ErrQuotaTotalCount = errors.New("maximum allowed package count exceeded") +) + // PackageInfo describes a package type PackageInfo struct { Owner *user_model.User @@ -50,6 +58,7 @@ type PackageFileInfo struct { // PackageFileCreationInfo describes a package file to create type PackageFileCreationInfo struct { PackageFileInfo + Creator *user_model.User Data packages_module.HashedSizeReader IsLead bool Properties map[string]string @@ -78,7 +87,7 @@ func createPackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreatio return nil, nil, err } - pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, pfci) + pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, &pvci.PackageInfo, pfci) removeBlob := false defer func() { if blobCreated && removeBlob { @@ -164,6 +173,10 @@ func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, all } if versionCreated { + if err := checkCountQuotaExceeded(ctx, pvci.Creator, pvci.Owner); err != nil { + return nil, false, err + } + for name, value := range pvci.VersionProperties { if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, name, value); err != nil { log.Error("Error setting package version property: %v", err) @@ -188,7 +201,7 @@ func AddFileToExistingPackage(pvi *PackageInfo, pfci *PackageFileCreationInfo) ( return nil, nil, err } - pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, pfci) + pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, pvi, pfci) removeBlob := false defer func() { if removeBlob { @@ -224,9 +237,13 @@ func NewPackageBlob(hsr packages_module.HashedSizeReader) *packages_model.Packag } } -func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { +func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { log.Trace("Adding package file: %v, %s", pv.ID, pfci.Filename) + if err := checkSizeQuotaExceeded(ctx, pfci.Creator, pvi.Owner, pvi.PackageType, pfci.Data.Size()); err != nil { + return nil, nil, false, err + } + pb, exists, err := packages_model.GetOrInsertBlob(ctx, NewPackageBlob(pfci.Data)) if err != nil { log.Error("Error inserting package blob: %v", err) @@ -285,6 +302,80 @@ func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVers return pf, pb, !exists, nil } +func checkCountQuotaExceeded(ctx context.Context, doer, owner *user_model.User) error { + if doer.IsAdmin { + return nil + } + + if setting.Packages.LimitTotalOwnerCount > -1 { + totalCount, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{ + OwnerID: owner.ID, + IsInternal: util.OptionalBoolFalse, + }) + if err != nil { + log.Error("CountVersions failed: %v", err) + return err + } + if totalCount > setting.Packages.LimitTotalOwnerCount { + return ErrQuotaTotalCount + } + } + + return nil +} + +func checkSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, packageType packages_model.Type, uploadSize int64) error { + if doer.IsAdmin { + return nil + } + + var typeSpecificSize int64 + switch packageType { + case packages_model.TypeComposer: + typeSpecificSize = setting.Packages.LimitSizeComposer + case packages_model.TypeConan: + typeSpecificSize = setting.Packages.LimitSizeConan + case packages_model.TypeContainer: + typeSpecificSize = setting.Packages.LimitSizeContainer + case packages_model.TypeGeneric: + typeSpecificSize = setting.Packages.LimitSizeGeneric + case packages_model.TypeHelm: + typeSpecificSize = setting.Packages.LimitSizeHelm + case packages_model.TypeMaven: + typeSpecificSize = setting.Packages.LimitSizeMaven + case packages_model.TypeNpm: + typeSpecificSize = setting.Packages.LimitSizeNpm + case packages_model.TypeNuGet: + typeSpecificSize = setting.Packages.LimitSizeNuGet + case packages_model.TypePub: + typeSpecificSize = setting.Packages.LimitSizePub + case packages_model.TypePyPI: + typeSpecificSize = setting.Packages.LimitSizePyPI + case packages_model.TypeRubyGems: + typeSpecificSize = setting.Packages.LimitSizeRubyGems + case packages_model.TypeVagrant: + typeSpecificSize = setting.Packages.LimitSizeVagrant + } + if typeSpecificSize > -1 && typeSpecificSize < uploadSize { + return ErrQuotaTypeSize + } + + if setting.Packages.LimitTotalOwnerSize > -1 { + totalSize, err := packages_model.CalculateBlobSize(ctx, &packages_model.PackageFileSearchOptions{ + OwnerID: owner.ID, + }) + if err != nil { + log.Error("CalculateBlobSize failed: %v", err) + return err + } + if totalSize+uploadSize > setting.Packages.LimitTotalOwnerSize { + return ErrQuotaTotalSize + } + } + + return nil +} + // RemovePackageVersionByNameAndVersion deletes a package version and all associated files func RemovePackageVersionByNameAndVersion(doer *user_model.User, pvi *PackageInfo) error { pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version) diff --git a/tests/integration/api_packages_test.go b/tests/integration/api_packages_test.go index 25f5b3f2a12d..815685ea7996 100644 --- a/tests/integration/api_packages_test.go +++ b/tests/integration/api_packages_test.go @@ -16,6 +16,7 @@ import ( container_model "code.gitea.io/gitea/models/packages/container" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" packages_service "code.gitea.io/gitea/services/packages" "code.gitea.io/gitea/tests" @@ -166,6 +167,39 @@ func TestPackageAccess(t *testing.T) { uploadPackage(admin, user, http.StatusCreated) } +func TestPackageQuota(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + limitTotalOwnerCount, limitTotalOwnerSize, limitSizeGeneric := setting.Packages.LimitTotalOwnerCount, setting.Packages.LimitTotalOwnerSize, setting.Packages.LimitSizeGeneric + + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) + + uploadPackage := func(doer *user_model.User, version string, expectedStatus int) { + url := fmt.Sprintf("/api/packages/%s/generic/test-package/%s/file.bin", user.Name, version) + req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{1})) + AddBasicAuthHeader(req, doer.Name) + MakeRequest(t, req, expectedStatus) + } + + // Exceeded quota result in StatusForbidden for normal users but admins are always allowed to upload. + + setting.Packages.LimitTotalOwnerCount = 0 + uploadPackage(user, "1.0", http.StatusForbidden) + uploadPackage(admin, "1.0", http.StatusCreated) + setting.Packages.LimitTotalOwnerCount = limitTotalOwnerCount + + setting.Packages.LimitTotalOwnerSize = 0 + uploadPackage(user, "1.1", http.StatusForbidden) + uploadPackage(admin, "1.1", http.StatusCreated) + setting.Packages.LimitTotalOwnerSize = limitTotalOwnerSize + + setting.Packages.LimitSizeGeneric = 0 + uploadPackage(user, "1.2", http.StatusForbidden) + uploadPackage(admin, "1.2", http.StatusCreated) + setting.Packages.LimitSizeGeneric = limitSizeGeneric +} + func TestPackageCleanup(t *testing.T) { defer tests.PrepareTestEnv(t)() From 7e40ceee9e90bd2cab0339f4301c476040d7121b Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 9 Nov 2022 15:40:26 +0800 Subject: [PATCH 2/5] Fix UI language switching bug (#21597) Related: * https://github.com/go-gitea/gitea/pull/21596#issuecomment-1291450224 There was a bug when switching language by AJAX: the irrelevant POST requests were processed by the target page's handler. Now, use GET instead of POST. The GET requests should be harmless. Co-authored-by: delvh Co-authored-by: Jason Song Co-authored-by: Lunny Xiao --- web_src/js/features/common-global.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index a3aebc024625..b00b4aea9c07 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -37,7 +37,7 @@ export function initHeadNavbarContentToggle() { export function initFootLanguageMenu() { function linkLanguageAction() { const $this = $(this); - $.post($this.data('url')).always(() => { + $.get($this.data('url')).always(() => { window.location.reload(); }); } From dd7f1c0334dff5fb5eb93765dff3b951a9f6b3fc Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Wed, 9 Nov 2022 18:02:19 +0800 Subject: [PATCH 3/5] Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) fixes: https://github.com/go-gitea/gitea/issues/21733 Uncaught Error: Language id "vs.editor.nullLanguage" is not configured nor known Note that this monaco-editor worked fine on 0.33.0 and broke on 0.34.0. If upstream fixed, remove this code. Signed-off-by: Xinyu Zhou Co-authored-by: Lunny Xiao --- web_src/js/bootstrap.js | 3 --- web_src/js/features/codeeditor.js | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index b5db3985456e..54b7c628873e 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -26,9 +26,6 @@ function processWindowErrorEvent(e) { return; // ignore such nonsense error event } - // Wait for upstream fix: https://github.com/microsoft/monaco-editor/issues/2962 - if (e.message.includes('Language id "vs.editor.nullLanguage" is not configured nor known')) return; - showGlobalErrorMessage(`JavaScript error: ${e.message} (${e.filename} @ ${e.lineno}:${e.colno}). Open browser console to see more details.`); } diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js index 0366afc2c092..23a26ba2b0d8 100644 --- a/web_src/js/features/codeeditor.js +++ b/web_src/js/features/codeeditor.js @@ -99,6 +99,10 @@ export async function createMonaco(textarea, filename, editorOpts) { } }); + // Quick fix: https://github.com/microsoft/monaco-editor/issues/2962 + monaco.languages.register({id: 'vs.editor.nullLanguage'}); + monaco.languages.setLanguageConfiguration('vs.editor.nullLanguage', {}); + const editor = monaco.editor.create(container, { value: textarea.value, theme: 'gitea', From 5a6cba4cf43f9e5be3ca4a3ffd8bfa351c92acbd Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 10 Nov 2022 00:42:06 +0800 Subject: [PATCH 4/5] Set last login when activating account (#21731) Fix #21698. Set the last login time to the current time when activating the user successfully. Co-authored-by: Lunny Xiao --- routers/web/auth/auth.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 25d70d7c4781..0f8128946c94 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -783,6 +783,13 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) { return } + // Register last login + user.SetLastLogin() + if err := user_model.UpdateUserCols(ctx, user, "last_login_unix"); err != nil { + ctx.ServerError("UpdateUserCols", err) + return + } + ctx.Flash.Success(ctx.Tr("auth.account_activated")) ctx.Redirect(setting.AppSubURL + "/") } From 99688ef994af34724a7120e97d09464297a673fe Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 10 Nov 2022 01:22:31 +0000 Subject: [PATCH 5/5] Attempt clarify AppWorkPath etc. (#21656) Attempt clarify the AppWorkPath in the documentation by using different notation and adding a section to the start of the cheat sheet. Fix #21523 Signed-off-by: Andrew Thornton Signed-off-by: Andrew Thornton --- custom/conf/app.example.ini | 62 +++++++++++++---- .../doc/advanced/config-cheat-sheet.en-us.md | 68 ++++++++++++++----- docs/content/doc/help/faq.en-us.md | 30 ++++---- .../doc/installation/from-source.en-us.md | 16 ++--- modules/setting/setting.go | 4 +- 5 files changed, 126 insertions(+), 54 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b46dfc20a969..9f41fdb080fc 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -7,6 +7,38 @@ ;; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Default Configuration (non-`app.ini` configuration) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; These values are environment-dependent but form the basis of a lot of values. They will be +;; reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. +;; +;; - _`AppPath`_: This is the absolute path of the running gitea binary. +;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: +;; - The `--work-path` flag passed to the binary +;; - The environment variable `$GITEA_WORK_DIR` +;; - A built-in value set at build time (see building from source) +;; - Otherwise it defaults to the directory of the _`AppPath`_ +;; - If any of the above are relative paths then they are made absolute against the +;; the directory of the _`AppPath`_ +;; - _`CustomPath`_: This is the base directory for custom templates and other options. +;; It is determined by using the first set thing in the following hierarchy: +;; - The `--custom-path` flag passed to the binary +;; - The environment variable `$GITEA_CUSTOM` +;; - A built-in value set at build time (see building from source) +;; - Otherwise it defaults to _`AppWorkPath`_`/custom` +;; - If any of the above are relative paths then they are made absolute against the +;; the directory of the _`AppWorkPath`_ +;; - _`CustomConf`_: This is the path to the `app.ini` file. +;; - The `--config` flag passed to the binary +;; - A built-in value set at build time (see building from source) +;; - Otherwise it defaults to _`CustomPath`_`/conf/app.ini` +;; - If any of the above are relative paths then they are made absolute against the +;; the directory of the _`CustomPath`_ +;; +;; In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_ + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; General Settings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -26,7 +58,7 @@ RUN_MODE = ; prod ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. Defaults to 'http' +;; The protocol the server listens on. One of 'http', 'https', 'http+unix', 'fcgi' or 'fcgi+unix'. Defaults to 'http' ;PROTOCOL = http ;; ;; Expect PROXY protocol headers on connections @@ -51,6 +83,8 @@ RUN_MODE = ; prod ;STATIC_URL_PREFIX = ;; ;; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. +;; If PROTOCOL is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. +;; Relative paths will be made absolute against the _`AppWorkPath`_. ;HTTP_ADDR = 0.0.0.0 ;; ;; The port to listen on. Leave empty when using a unix socket. @@ -64,7 +98,7 @@ RUN_MODE = ; prod ;PORT_TO_REDIRECT = 80 ;; ;; expect PROXY protocol header on connections to https redirector. -;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL) +;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;; Minimum and maximum supported TLS versions ;SSL_MIN_VERSION=TLSv1.2 ;SSL_MAX_VERSION= @@ -91,7 +125,7 @@ RUN_MODE = ; prod ;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ ;; ;; When making local connections pass the PROXY protocol header. -;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL) +;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;; ;; Disable SSH feature when not available ;DISABLE_SSH = false @@ -145,7 +179,7 @@ RUN_MODE = ; prod ;; ;; For the built-in SSH server, choose the keypair to offer as the host key ;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub -;; relative paths are made absolute relative to the APP_DATA_PATH +;; relative paths are made absolute relative to the %(APP_DATA_PATH)s ;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa ;; ;; Directory to create temporary files in when testing public keys using ssh-keygen, @@ -241,10 +275,10 @@ RUN_MODE = ; prod ;; ;; Root directory containing templates and static files. ;; default is the path where Gitea is executed -;STATIC_ROOT_PATH = +;STATIC_ROOT_PATH = ; Will default to the built-in value _`StaticRootPath`_ ;; ;; Default path for App data -;APP_DATA_PATH = data +;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_ ;; ;; Enable gzip compression for runtime-generated content, static resources excluded ;ENABLE_GZIP = false @@ -255,7 +289,7 @@ RUN_MODE = ; prod ;ENABLE_PPROF = false ;; ;; PPROF_DATA_PATH, use an absolute path when you start gitea as service -;PPROF_DATA_PATH = data/tmp/pprof +;PPROF_DATA_PATH = data/tmp/pprof ; Path is relative to _`AppWorkPath`_ ;; ;; Landing page, can be "home", "explore", "organizations", "login", or any URL such as "/org/repo" or even "https://anotherwebsite.com" ;; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in. @@ -633,7 +667,7 @@ ROUTER = console ;PATH = ;; ;; The HOME directory for Git -;HOME_PATH = %(APP_DATA_PATH)/home +;HOME_PATH = %(APP_DATA_PATH)s/home ;; ;; Disables highlight of added and removed changes ;DISABLE_DIFF_HIGHLIGHT = false @@ -838,8 +872,8 @@ ROUTER = console ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[repository] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)/gitea-repositories. -;; A relative path is interpreted as %(GITEA_WORK_DIR)/%(ROOT) +;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)s/gitea-repositories. +;; A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s ;ROOT = ;; ;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. @@ -1296,7 +1330,7 @@ ROUTER = console ;ISSUE_INDEXER_TYPE = bleve ;; ;; Issue indexer storage path, available when ISSUE_INDEXER_TYPE is bleve -;ISSUE_INDEXER_PATH = indexers/issues.bleve +;ISSUE_INDEXER_PATH = indexers/issues.bleve ; Relative paths will be made absolute against _`AppWorkPath`_. ;; ;; Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch ;ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200 @@ -1314,7 +1348,7 @@ ROUTER = console ;; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the path where the queue will be saved. ;; This can be overridden by `ISSUE_INDEXER_QUEUE_CONN_STR`. ;; default is queues/common -;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`. +;ISSUE_INDEXER_QUEUE_DIR = queues/common; **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`. ;; ;; When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. ;; When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of @@ -1370,7 +1404,7 @@ ROUTER = console ;TYPE = persistable-channel ;; ;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared. -;DATADIR = queues/ +;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`. ;; ;; Default queue length before a channel queue will block ;LENGTH = 20 @@ -1672,7 +1706,7 @@ ROUTER = console ;; file: session file path, e.g. `data/sessions` ;; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 ;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table` -;PROVIDER_CONFIG = data/sessions +;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_. ;; ;; Session cookie name ;COOKIE_NAME = i_like_gitea diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 28bcaf29afdc..b0060e9afa43 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -27,23 +27,56 @@ accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/ (s/main/\). Any string in the format `%(X)s` is a feature powered by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively. +In the default values below, a value in the form `$XYZ` refers to an environment variable. (However, see `environment-to-ini`.) Values in the form _`XxYyZz`_ refer to values listed as part of the default configuration. These notation forms will not work in your own `app.ini` file and are only listed here as documentation. + Values containing `#` or `;` must be quoted using `` ` `` or `"""`. **Note:** A full restart is required for Gitea configuration changes to take effect. {{< toc >}} +## Default Configuration (non-`app.ini` configuration) + +These values are environment-dependent but form the basis of a lot of values. They will be +reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. + +- _`AppPath`_: This is the absolute path of the running gitea binary. +- _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: + - The `--work-path` flag passed to the binary + - The environment variable `$GITEA_WORK_DIR` + - A built-in value set at build time (see building from source) + - Otherwise it defaults to the directory of the _`AppPath`_ + - If any of the above are relative paths then they are made absolute against the +the directory of the _`AppPath`_ +- _`CustomPath`_: This is the base directory for custom templates and other options. +It is determined by using the first set thing in the following hierarchy: + - The `--custom-path` flag passed to the binary + - The environment variable `$GITEA_CUSTOM` + - A built-in value set at build time (see building from source) + - Otherwise it defaults to _`AppWorkPath`_`/custom` + - If any of the above are relative paths then they are made absolute against the +the directory of the _`AppWorkPath`_ +- _`CustomConf`_: This is the path to the `app.ini` file. + - The `--config` flag passed to the binary + - A built-in value set at build time (see building from source) + - Otherwise it defaults to _`CustomPath`_`/conf/app.ini` + - If any of the above are relative paths then they are made absolute against the +the directory of the _`CustomPath`_ + +In addition there is _`StaticRootPath`_ which can be set as a built-in at build time, but will otherwise default to _`AppWorkPath`_ + ## Overall (`DEFAULT`) - `APP_NAME`: **Gitea: Git with a cup of tea**: Application name, used in the page title. -- `RUN_USER`: **git**: The user Gitea will run as. This should be a dedicated system - (non-user) account. Setting this incorrectly will cause Gitea to not start. +- `RUN_USER`: **_current OS username_/`$USER`/`$USERNAME` e.g. git**: The user Gitea will run as. + This should be a dedicated system (non-user) account. Setting this incorrectly will cause Gitea + to not start. - `RUN_MODE`: **prod**: Application run mode, affects performance and debugging. Either "dev", "prod" or "test". ## Repository (`repository`) -- `ROOT`: **%(APP_DATA_PATH)/gitea-repositories**: Root path for storing all repository data. - A relative path is interpreted as **%(GITEA_WORK_DIR)/%(ROOT)**. +- `ROOT`: **%(APP_DATA_PATH)s/gitea-repositories**: Root path for storing all repository data. + A relative path is interpreted as **_`AppWorkPath`_/%(ROOT)s**. - `SCRIPT_TYPE`: **bash**: The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. - `DETECTED_CHARSETS_ORDER`: **UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr**: Tie-break order of detected charsets - if the detected charsets have equal confidence, charsets earlier in the list will be chosen in preference to those later. Adding `defaults` will place the unnamed charsets at that point. @@ -240,6 +273,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a ## Server (`server`) +- `APP_DATA_PATH`: **_`AppWorkPath`_/data**: This is the default root path for storing data. - `PROTOCOL`: **http**: \[http, https, fcgi, http+unix, fcgi+unix\] - `USE_PROXY_PROTOCOL`: **false**: Expect PROXY protocol headers on connections - `PROXY_PROTOCOL_TLS_BRIDGING`: **false**: When protocol is https, expect PROXY protocol headers after TLS negotiation. @@ -259,7 +293,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `HTTP_ADDR`: **0.0.0.0**: HTTP listen address. - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings. - - If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the AppWorkPath. + - If `PROTOCOL` is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use. Relative paths will be made absolute against the _`AppWorkPath`_. - `HTTP_PORT`: **3000**: HTTP listen port. - If `PROTOCOL` is set to `fcgi`, Gitea will listen for FastCGI requests on TCP socket defined by `HTTP_ADDR` and `HTTP_PORT` configuration settings. @@ -269,7 +303,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a most cases you do not need to change the default value. Alter it only if your SSH server node is not the same as HTTP node. Do not set this variable if `PROTOCOL` is set to `http+unix`. -- `LOCAL_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)**: When making local connections pass the PROXY protocol header. +- `LOCAL_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)s**: When making local connections pass the PROXY protocol header. This should be set to false if the local connection will go through the proxy. - `PER_WRITE_TIMEOUT`: **30s**: Timeout for any write to the connection. (Set to -1 to disable all timeouts.) @@ -279,7 +313,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `START_SSH_SERVER`: **false**: When enabled, use the built-in SSH server. - `SSH_SERVER_USE_PROXY_PROTOCOL`: **false**: Expect PROXY protocol header on connections to the built-in SSH Server. - `BUILTIN_SSH_SERVER_USER`: **%(RUN_USER)s**: Username to use for the built-in SSH Server. -- `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`. +- `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)s**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`. - `SSH_DOMAIN`: **%(DOMAIN)s**: Domain name of this server, used for displayed clone URL. - `SSH_PORT`: **22**: SSH port displayed in clone URL. - `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address for the built-in SSH server. @@ -308,22 +342,22 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures. - `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`. - `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`. -- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path. -- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data. +- `STATIC_ROOT_PATH`: **_`StaticRootPath`_**: Upper level of template and static files path. +- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data. Relative paths will be made absolute against _`AppWorkPath`_. - `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev". - `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded. - `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on `localhost:6060`. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)__` -- `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service +- `PPROF_DATA_PATH`: **_`AppWorkPath`_/data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service - `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even `https://anotherwebsite.com` - `LFS_START_SERVER`: **false**: Enables Git LFS support. -- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`. +- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)s/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`. - `LFS_JWT_SECRET`: **\**: LFS authentication secret, change this a unique string. - `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail. - `LFS_MAX_FILE_SIZE`: **0**: Maximum allowed LFS file size in bytes (Set to 0 for no limit). - `LFS_LOCKS_PAGING_NUM`: **50**: Maximum number of LFS Locks returned per page. - `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, allows redirecting http requests on `PORT_TO_REDIRECT` to the https port Gitea listens on. -- `REDIRECTOR_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)**: expect PROXY protocol header on connections to https redirector. +- `REDIRECTOR_USE_PROXY_PROTOCOL`: **%(USE_PROXY_PROTOCOL)s**: expect PROXY protocol header on connections to https redirector. - `PORT_TO_REDIRECT`: **80**: Port for the http redirection service to listen on. Used when `REDIRECT_OTHER_PORT` is true. - `SSL_MIN_VERSION`: **TLSv1.2**: Set the minimum version of ssl support. - `SSL_MAX_VERSION`: **\**: Set the maximum version of ssl support. @@ -413,10 +447,10 @@ relation to port exhaustion. - `ISSUE_INDEXER_TYPE`: **bleve**: Issue indexer type, currently supported: `bleve`, `db` or `elasticsearch`. - `ISSUE_INDEXER_CONN_STR`: ****: Issue indexer connection string, available when ISSUE_INDEXER_TYPE is elasticsearch. i.e. http://elastic:changeme@localhost:9200 - `ISSUE_INDEXER_NAME`: **gitea_issues**: Issue indexer name, available when ISSUE_INDEXER_TYPE is elasticsearch -- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. +- `ISSUE_INDEXER_PATH`: **indexers/issues.bleve**: Index file used for issue search; available when ISSUE_INDEXER_TYPE is bleve and elasticsearch. Relative paths will be made absolute against _`AppWorkPath`_. - The next 4 configuration values are deprecated and should be set in `queue.issue_indexer` however are kept for backwards compatibility: - `ISSUE_INDEXER_QUEUE_TYPE`: **levelqueue**: Issue indexer queue, currently supports:`channel`, `levelqueue`, `redis`. **DEPRECATED** use settings in `[queue.issue_indexer]`. -- `ISSUE_INDEXER_QUEUE_DIR`: **queues/common**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the path where the queue will be saved. **DEPRECATED** use settings in `[queue.issue_indexer]`. +- `ISSUE_INDEXER_QUEUE_DIR`: **queues/common**: When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this will be the path where the queue will be saved. **DEPRECATED** use settings in `[queue.issue_indexer]`. Relative paths will be made absolute against `%(APP_DATA_PATH)s`. - `ISSUE_INDEXER_QUEUE_CONN_STR`: **addrs=127.0.0.1:6379 db=0**: When `ISSUE_INDEXER_QUEUE_TYPE` is `redis`, this will store the redis connection string. When `ISSUE_INDEXER_QUEUE_TYPE` is `levelqueue`, this is a directory or additional options of the form `leveldb://path/to/db?option=value&....`, and overrides `ISSUE_INDEXER_QUEUE_DIR`. **DEPRECATED** use settings in `[queue.issue_indexer]`. - `ISSUE_INDEXER_QUEUE_BATCH_NUMBER`: **20**: Batch queue number. **DEPRECATED** use settings in `[queue.issue_indexer]`. @@ -438,7 +472,7 @@ relation to port exhaustion. Configuration at `[queue]` will set defaults for queues with overrides for individual queues at `[queue.*]`. (However see below.) - `TYPE`: **persistable-channel**: General queue type, currently support: `persistable-channel` (uses a LevelDB internally), `channel`, `level`, `redis`, `dummy` -- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`common`**. (Previously each queue would default to `DATADIR/`**`name`**.) +- `DATADIR`: **queues/**: Base DataDir for storing persistent and level queues. `DATADIR` for individual queues can be set in `queue.name` sections but will default to `DATADIR/`**`common`**. (Previously each queue would default to `DATADIR/`**`name`**.) Relative paths will be made absolute against `%(APP_DATA_PATH)s`. - `LENGTH`: **20**: Maximal queue size before channel queues block - `BATCH_LENGTH`: **20**: Batch data before passing to the handler - `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. Options can be set using query params. Similarly LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR` @@ -722,7 +756,7 @@ and ## Session (`session`) - `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]` -- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. +- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. Relative paths will be made absolute against _`AppWorkPath`_. - `COOKIE_SECURE`: **false**: Enable this to force using HTTPS for all session access. - `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID. - `GC_INTERVAL_TIME`: **86400**: GC interval in seconds. @@ -980,7 +1014,7 @@ Default templates for project boards: ## Git (`git`) - `PATH`: **""**: The path of Git executable. If empty, Gitea searches through the PATH environment. -- `HOME_PATH`: **%(APP_DATA_PATH)/home**: The HOME directory for Git. +- `HOME_PATH`: **%(APP_DATA_PATH)s/home**: The HOME directory for Git. This directory will be used to contain the `.gitconfig` and possible `.gnupg` directories that Gitea's git calls will use. If you can confirm Gitea is the only application running in this environment, you can set it to the normal home directory for Gitea user. - `DISABLE_DIFF_HIGHLIGHT`: **false**: Disables highlight of added and removed changes. - `MAX_GIT_DIFF_LINES`: **1000**: Max number of lines allowed of a single file in diff view. diff --git a/docs/content/doc/help/faq.en-us.md b/docs/content/doc/help/faq.en-us.md index a59abe833568..a92186334f38 100644 --- a/docs/content/doc/help/faq.en-us.md +++ b/docs/content/doc/help/faq.en-us.md @@ -58,29 +58,33 @@ https://github.com/loganinak/MigrateGitlabToGogs ## Where does Gitea store what file -- WorkPath - - Environment variable `GITEA_WORK_DIR` - - Else `--work-path` flag +- _`AppWorkPath`_ + - The `--work-path` flag + - Else Environment variable `GITEA_WORK_DIR` + - Else a built-in value set at build time - Else the directory that contains the Gitea binary -- AppDataPath (default for database, indexers, etc.) +- `%(APP_DATA_PATH)` (default for database, indexers, etc.) - `APP_DATA_PATH` from `app.ini` - - Else `%(WorkPath)/data` -- CustomPath (custom templates) - - Environment variable `GITEA_CUSTOM` - - Else `%(WorkPath)/custom` + - Else _`AppWorkPath`_`/data` +- _`CustomPath`_ (custom templates) + - The `--custom-path` flag + - Else Environment variable `GITEA_CUSTOM` + - Else a built-in value set at build time + - Else _`AppWorkPath`_`/custom` - HomeDir - Unix: Environment variable `HOME` - Windows: Environment variable `USERPROFILE`, else environment variables `HOMEDRIVE`+`HOMEPATH` - RepoRootPath - `ROOT` in the \[repository] section of `app.ini` if absolute - - Else `%(AppWorkPath)/ROOT` if `ROOT` in the \[repository] section of `app.ini` if relative - - Default `%(AppDataPath)/gitea-repositories` + - Else _`AppWorkPath`_`/ROOT` if `ROOT` in the \[repository] section of `app.ini` if relative + - Default `%(APP_DATA_PATH)/gitea-repositories` - INI (config file) - - `-c` flag - - Else `%(CustomPath)/conf/app.ini` + - `--config` flag + - A possible built-in value set a build time + - Else _`CustomPath`_`/conf/app.ini` - SQLite Database - `PATH` in `database` section of `app.ini` - - Else `%(AppDataPath)/gitea.db` + - Else `%(APP_DATA_PATH)/gitea.db` ## Not seeing a clone URL or the clone URL being incorrect diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md index 0be5673be479..a6493598be23 100644 --- a/docs/content/doc/installation/from-source.en-us.md +++ b/docs/content/doc/installation/from-source.en-us.md @@ -144,11 +144,11 @@ launched manually from command line, it can be killed by pressing `Ctrl + C`. ## Changing default paths -Gitea will search for a number of things from the `CustomPath`. By default this is +Gitea will search for a number of things from the _`CustomPath`_. By default this is the `custom/` directory in the current working directory when running Gitea. It will also -look for its configuration file `CustomConf` in `$CustomPath/conf/app.ini`, and will use the -current working directory as the relative base path `AppWorkPath` for a number configurable -values. Finally the static files will be served from `StaticRootPath` which defaults to the `AppWorkPath`. +look for its configuration file _`CustomConf`_ in _`CustomPath`_/conf/app.ini`, and will use the +current working directory as the relative base path _`AppWorkPath`_ for a number configurable +values. Finally the static files will be served from _`StaticRootPath`_ which defaults to the _`AppWorkPath`_. These values, although useful when developing, may conflict with downstream users preferences. @@ -156,10 +156,10 @@ One option is to use a script file to shadow the `gitea` binary and create an ap environment before running Gitea. However, when building you can change these defaults using the `LDFLAGS` environment variable for `make`. The appropriate settings are as follows -- To set the `CustomPath` use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""` -- For `CustomConf` you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"` -- For `AppWorkPath` you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"` -- For `StaticRootPath` you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"` +- To set the _`CustomPath`_ use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""` +- For _`CustomConf`_ you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"` +- For _`AppWorkPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"` +- For _`StaticRootPath`_ you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"` - To change the default PID file location use `-X \"code.gitea.io/gitea/modules/setting.PIDFile=/run/gitea.pid\"` Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build` diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 2e5bb17b6a86..12558da494b2 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -88,10 +88,10 @@ var ( // AppWorkPath is used as the base path for several other paths. AppWorkPath string // AppDataPath is the default path for storing data. - // It maps to ini:"APP_DATA_PATH" and defaults to AppWorkPath + "/data" + // It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data" AppDataPath string // LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix - // It maps to ini:"LOCAL_ROOT_URL" + // It maps to ini:"LOCAL_ROOT_URL" in [server] LocalURL string // AssetVersion holds a opaque value that is used for cache-busting assets AssetVersion string