25 Commits

Author SHA1 Message Date
e497d41030 chore: run make update-license fmt 2025-01-18 19:30:02 +03:00
d46414a67c Merge branch 'master' into chore/linting 2025-01-18 19:22:18 +03:00
29e2f85eeb Исправление ссылки на скрипт установки 2025-01-18 18:30:26 +03:00
c9c872abbc Merge remote-tracking branch 'gitea/master' 2025-01-18 18:29:50 +03:00
fb93864d09 Revert "Исправление ссылки на скрипт установки"
This reverts commit 9fcd618a83.
2025-01-18 18:29:42 +03:00
9fcd618a83 Исправление ссылки на скрипт установки 2025-01-18 18:29:17 +03:00
1fb9c6b574 Merge pull request 'refactor(db, config, repos): migrate from functions to struct' (#9) from Maks1mS/ALR:refactor/db into master
Reviewed-on: #9
2025-01-18 15:27:10 +00:00
fb5c875713 Merge pull request 'fix: add auto_req and auto_prov' (#7) from Maks1mS/ALR:fix/make-findprovides-findrequires-optional into master
Reviewed-on: #7
2025-01-18 15:24:07 +00:00
3f428ab7b5 chore: add golangci-lint 2025-01-14 15:45:29 +03:00
5b7af1f6b5 chore: refactor license update script 2025-01-14 15:28:54 +03:00
3224d7c6e4 chore: add license update script 2025-01-14 15:24:24 +03:00
e1829c4824 refactor: migrate repos find to struct 2025-01-14 13:18:51 +03:00
12d83f2015 test: fix decoder and handlers tests 2025-01-14 13:04:10 +03:00
6bc6bfdcd9 refactor: migrate dlcache to struct 2025-01-14 12:59:00 +03:00
eeb25c239b refactor: move defaultConfig from config_legacy to config 2025-01-14 11:54:00 +03:00
91937a1fc5 refactor: migrate repo to struct 2025-01-14 11:49:42 +03:00
e827fb8049 refactor: use context logger 2025-01-14 10:41:38 +03:00
a13acc5ed0 refactor: migrate list command to struct API 2025-01-14 10:35:23 +03:00
52d3ab7791 refactor: migrate db and config packages to use struct-based API
Removed global variables in favor of instance variables. This makes the code more maintainable and making it easier to write unit tests without relying on global state.

Marked the old functions with global state as obsolete, redirecting them to use a new API based on struct in order to rewrite the code using these functions gradually.
2025-01-14 10:11:17 +03:00
a345a24b95 fix: add auto_req and auto_prov 2024-12-27 21:15:37 +03:00
5d1d3d7c45 Merge pull request 'feat: add find-provides and find-requires (rpm only)' (#5) from Maks1mS/ALR:feat/auto-provides-requires into master
Reviewed-on: #5
2024-12-26 08:07:15 +00:00
a711edbcc0 fix: ignore empty dependencies 2024-12-23 21:12:08 +03:00
d5636e8094 feat: add find-provides and find-requires (rpm only) 2024-12-19 19:21:41 +03:00
5d17875813 Merge pull request 'Исправление file exists при распаковке архива' (#2) from Maks1mS/ALR:fix/unpack-file-exists-error into master
Reviewed-on: xpamych/ALR#2
2024-11-17 18:25:29 +00:00
41eec2fc98 fix: use MkdirAll instead Mkdir to ignore existing dirs 2024-11-17 21:11:54 +03:00
82 changed files with 2775 additions and 1692 deletions

46
.golangci.yml Normal file
View File

@@ -0,0 +1,46 @@
# 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 <http://www.gnu.org/licenses/>.
run:
timeout: 5m
linters-settings:
goimports:
local-prefixes: "plemya-x.ru/alr"
gofmt:
simplify: true
gofumpt:
extra-rules: true
linters:
enable:
- gofmt
- gofumpt
- goimports
- gocritic
- govet
- staticcheck
- unused
- errcheck
- typecheck
# - forbidigo
issues:
fix: true
exclude-rules:
- path: _test\.go
linters:
- errcheck

View File

@@ -1,3 +1,22 @@
# This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
# It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
#
# 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 <http://www.gnu.org/licenses/>.
before: before:
hooks: hooks:
- go mod tidy - go mod tidy

View File

@@ -1,3 +1,22 @@
# This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
# It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
#
# 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 <http://www.gnu.org/licenses/>.
platform: linux/amd64 platform: linux/amd64
pipeline: pipeline:
release: release:

View File

@@ -11,6 +11,9 @@ ZSH_COMPLETION := $(COMPLETIONS_DIR)/zsh
INSTALLED_BASH_COMPLETION := $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(NAME) INSTALLED_BASH_COMPLETION := $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(NAME)
INSTALLED_ZSH_COMPLETION := $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(NAME) INSTALLED_ZSH_COMPLETION := $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(NAME)
ADD_LICENSE_BIN := go run github.com/google/addlicense@4caba19b7ed7818bb86bc4cd20411a246aa4a524
GOLANGCI_LINT_BIN := go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
.PHONY: build install clean clear uninstall check-no-root .PHONY: build install clean clear uninstall check-no-root
build: check-no-root $(BIN) build: check-no-root $(BIN)
@@ -48,3 +51,12 @@ uninstall:
clean clear: clean clear:
rm -f $(BIN) rm -f $(BIN)
OLD_FILES=$$(< old-files)
IGNORE_OLD_FILES := $(foreach file,$(shell cat old-files),-ignore $(file))
update-license:
$(ADD_LICENSE_BIN) -v -f license-header-old-files.tmpl $(OLD_FILES)
$(ADD_LICENSE_BIN) -v -f license-header.tmpl $(IGNORE_OLD_FILES) .
fmt:
$(GOLANGCI_LINT_BIN) run --fix

View File

@@ -21,7 +21,7 @@ ALR написан на чистом Go и после сборки не имее
curl -fsSL plemya-x.ru/alr/install.sh | bash curl -fsSL plemya-x.ru/alr/install.sh | bash
``` ```
**ВАЖНО**: При этом скрипт будет загружен и запущен с <https://gitea.plemya-x.ru/xpamych/ALR/install>. Пожалуйста, просматривайте любые скрипты, которые вы скачиваете из Интернета (включая этот), прежде чем запускать их. **ВАЖНО**: При этом скрипт будет загружен и запущен с <https://gitea.plemya-x.ru/Plemya-x/ALR/src/branch/master/scripts/install.sh>. Пожалуйста, просматривайте любые скрипты, которые вы скачиваете из Интернета (включая этот), прежде чем запускать их.
### Сборка из исходного кода ### Сборка из исходного кода

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -23,6 +24,7 @@ import (
"path/filepath" "path/filepath"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/osutils" "plemya-x.ru/alr/internal/osutils"
"plemya-x.ru/alr/internal/types" "plemya-x.ru/alr/internal/types"

36
fix.go
View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -22,6 +23,7 @@ import (
"os" "os"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"

20
gen.go
View File

@@ -1,9 +1,29 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package main package main
import ( import (
"os" "os"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"plemya-x.ru/alr/pkg/gen" "plemya-x.ru/alr/pkg/gen"
) )

View File

@@ -1,3 +1,22 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package main package main
import ( import (
@@ -6,12 +25,13 @@ import (
"strings" "strings"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp"
"plemya-x.ru/alr/internal/cpu" "plemya-x.ru/alr/internal/cpu"
"plemya-x.ru/alr/internal/shutils/helpers" "plemya-x.ru/alr/internal/shutils/helpers"
"plemya-x.ru/alr/pkg/distro" "plemya-x.ru/alr/pkg/distro"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
"mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp"
) )
var helperCmd = &cli.Command{ var helperCmd = &cli.Command{

38
info.go
View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -23,13 +24,14 @@ import (
"os" "os"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"gopkg.in/yaml.v3"
"plemya-x.ru/alr/internal/cliutils" "plemya-x.ru/alr/internal/cliutils"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/overrides" "plemya-x.ru/alr/internal/overrides"
"plemya-x.ru/alr/pkg/distro" "plemya-x.ru/alr/pkg/distro"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
"plemya-x.ru/alr/pkg/repos" "plemya-x.ru/alr/pkg/repos"
"gopkg.in/yaml.v3"
) )
var infoCmd = &cli.Command{ var infoCmd = &cli.Command{

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -22,6 +23,7 @@ import (
"fmt" "fmt"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"plemya-x.ru/alr/internal/cliutils" "plemya-x.ru/alr/internal/cliutils"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package cliutils package cliutils
@@ -24,6 +25,7 @@ import (
"strings" "strings"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/pager" "plemya-x.ru/alr/internal/pager"

View File

@@ -1,33 +1,44 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package config package config
import ( import (
"context" "context"
"os" "os"
"path/filepath"
"sync" "sync"
"github.com/pelletier/go-toml/v2" "github.com/pelletier/go-toml/v2"
"plemya-x.ru/alr/internal/types" "plemya-x.ru/alr/internal/types"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
) )
type ALRConfig struct {
cfg *types.Config
paths *Paths
cfgOnce sync.Once
pathsOnce sync.Once
}
var defaultConfig = &types.Config{ var defaultConfig = &types.Config{
RootCmd: "sudo", RootCmd: "sudo",
PagerStyle: "native", PagerStyle: "native",
@@ -40,40 +51,107 @@ var defaultConfig = &types.Config{
}, },
} }
var ( func New() *ALRConfig {
configMtx sync.Mutex return &ALRConfig{}
config *types.Config }
)
// Config returns a ALR configuration struct. func (c *ALRConfig) Load(ctx context.Context) {
// The first time it's called, it'll load the config from a file.
// Subsequent calls will just return the same value.
func Config(ctx context.Context) *types.Config {
configMtx.Lock()
defer configMtx.Unlock()
log := loggerctx.From(ctx) log := loggerctx.From(ctx)
cfgFl, err := os.Open(c.GetPaths(ctx).ConfigPath)
if err != nil {
log.Warn("Error opening config file, using defaults").Err(err).Send()
c.cfg = defaultConfig
return
}
defer cfgFl.Close()
if config == nil { // Copy the default configuration into config
cfgFl, err := os.Open(GetPaths(ctx).ConfigPath) defCopy := *defaultConfig
if err != nil { config := &defCopy
log.Warn("Error opening config file, using defaults").Err(err).Send() config.Repos = nil
return defaultConfig
}
defer cfgFl.Close()
// Copy the default configuration into config err = toml.NewDecoder(cfgFl).Decode(config)
defCopy := *defaultConfig if err != nil {
config = &defCopy log.Warn("Error decoding config file, using defaults").Err(err).Send()
config.Repos = nil c.cfg = defaultConfig
return
}
c.cfg = config
}
err = toml.NewDecoder(cfgFl).Decode(config) func (c *ALRConfig) initPaths(ctx context.Context) {
if err != nil { log := loggerctx.From(ctx)
log.Warn("Error decoding config file, using defaults").Err(err).Send() paths := &Paths{}
// Set config back to nil so that we try again next time
config = nil cfgDir, err := os.UserConfigDir()
return defaultConfig if err != nil {
} log.Fatal("Unable to detect user config directory").Err(err).Send()
} }
return config paths.ConfigDir = filepath.Join(cfgDir, "alr")
err = os.MkdirAll(paths.ConfigDir, 0o755)
if err != nil {
log.Fatal("Unable to create ALR config directory").Err(err).Send()
}
paths.ConfigPath = filepath.Join(paths.ConfigDir, "alr.toml")
if _, err := os.Stat(paths.ConfigPath); err != nil {
cfgFl, err := os.Create(paths.ConfigPath)
if err != nil {
log.Fatal("Unable to create ALR config file").Err(err).Send()
}
err = toml.NewEncoder(cfgFl).Encode(&defaultConfig)
if err != nil {
log.Fatal("Error encoding default configuration").Err(err).Send()
}
cfgFl.Close()
}
cacheDir, err := os.UserCacheDir()
if err != nil {
log.Fatal("Unable to detect cache directory").Err(err).Send()
}
paths.CacheDir = filepath.Join(cacheDir, "alr")
paths.RepoDir = filepath.Join(paths.CacheDir, "repo")
paths.PkgsDir = filepath.Join(paths.CacheDir, "pkgs")
err = os.MkdirAll(paths.RepoDir, 0o755)
if err != nil {
log.Fatal("Unable to create repo cache directory").Err(err).Send()
}
err = os.MkdirAll(paths.PkgsDir, 0o755)
if err != nil {
log.Fatal("Unable to create package cache directory").Err(err).Send()
}
paths.DBPath = filepath.Join(paths.CacheDir, "db")
c.paths = paths
}
func (c *ALRConfig) GetPaths(ctx context.Context) *Paths {
c.pathsOnce.Do(func() {
c.initPaths(ctx)
})
return c.paths
}
func (c *ALRConfig) Repos(ctx context.Context) []types.Repo {
c.cfgOnce.Do(func() {
c.Load(ctx)
})
return c.cfg.Repos
}
func (c *ALRConfig) IgnorePkgUpdates(ctx context.Context) []string {
c.cfgOnce.Do(func() {
c.Load(ctx)
})
return c.cfg.IgnorePkgUpdates
} }

View File

@@ -0,0 +1,52 @@
// 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 <http://www.gnu.org/licenses/>.
package config
import (
"context"
"sync"
"plemya-x.ru/alr/internal/types"
)
// Config returns a ALR configuration struct.
// The first time it's called, it'll load the config from a file.
// Subsequent calls will just return the same value.
//
// Deprecated: use struct method
func Config(ctx context.Context) *types.Config {
return GetInstance(ctx).cfg
}
// =======================
// FOR LEGACY ONLY
// =======================
var (
alrConfig *ALRConfig
alrConfigOnce sync.Once
)
// Deprecated: For legacy only
func GetInstance(ctx context.Context) *ALRConfig {
alrConfigOnce.Do(func() {
alrConfig = New()
alrConfig.Load(ctx)
})
return alrConfig
}

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package config package config
@@ -24,8 +25,9 @@ import (
"strings" "strings"
"sync" "sync"
"plemya-x.ru/alr/pkg/loggerctx"
"golang.org/x/text/language" "golang.org/x/text/language"
"plemya-x.ru/alr/pkg/loggerctx"
) )
var ( var (

View File

@@ -1,31 +1,26 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package config package config
import ( import (
"context" "context"
"os"
"path/filepath"
"sync"
"github.com/pelletier/go-toml/v2"
"plemya-x.ru/alr/pkg/loggerctx"
) )
// Paths contains various paths used by ALR // Paths contains various paths used by ALR
@@ -38,71 +33,13 @@ type Paths struct {
DBPath string DBPath string
} }
var (
pathsMtx sync.Mutex
paths *Paths
)
// GetPaths returns a Paths struct. // GetPaths returns a Paths struct.
// The first time it's called, it'll generate the struct // The first time it's called, it'll generate the struct
// using information from the system. // using information from the system.
// Subsequent calls will return the same value. // Subsequent calls will return the same value.
//
// Depreacted: use struct API
func GetPaths(ctx context.Context) *Paths { func GetPaths(ctx context.Context) *Paths {
pathsMtx.Lock() alrConfig := GetInstance(ctx)
defer pathsMtx.Unlock() return alrConfig.GetPaths(ctx)
log := loggerctx.From(ctx)
if paths == nil {
paths = &Paths{}
cfgDir, err := os.UserConfigDir()
if err != nil {
log.Fatal("Unable to detect user config directory").Err(err).Send()
}
paths.ConfigDir = filepath.Join(cfgDir, "alr")
err = os.MkdirAll(paths.ConfigDir, 0o755)
if err != nil {
log.Fatal("Unable to create ALR config directory").Err(err).Send()
}
paths.ConfigPath = filepath.Join(paths.ConfigDir, "alr.toml")
if _, err := os.Stat(paths.ConfigPath); err != nil {
cfgFl, err := os.Create(paths.ConfigPath)
if err != nil {
log.Fatal("Unable to create ALR config file").Err(err).Send()
}
err = toml.NewEncoder(cfgFl).Encode(&defaultConfig)
if err != nil {
log.Fatal("Error encoding default configuration").Err(err).Send()
}
cfgFl.Close()
}
cacheDir, err := os.UserCacheDir()
if err != nil {
log.Fatal("Unable to detect cache directory").Err(err).Send()
}
paths.CacheDir = filepath.Join(cacheDir, "alr")
paths.RepoDir = filepath.Join(paths.CacheDir, "repo")
paths.PkgsDir = filepath.Join(paths.CacheDir, "pkgs")
err = os.MkdirAll(paths.RepoDir, 0o755)
if err != nil {
log.Fatal("Unable to create repo cache directory").Err(err).Send()
}
err = os.MkdirAll(paths.PkgsDir, 0o755)
if err != nil {
log.Fatal("Unable to create package cache directory").Err(err).Send()
}
paths.DBPath = filepath.Join(paths.CacheDir, "db")
}
return paths
} }

View File

@@ -1,3 +1,22 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package config package config
// Version contains the version of ALR. If the version // Version contains the version of ALR. If the version

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package cpu package cpu

View File

@@ -1,47 +1,37 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package db package db
import ( import (
"context" "context"
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"sync"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
"golang.org/x/exp/slices"
"modernc.org/sqlite"
) )
// CurrentVersion is the current version of the database. // CurrentVersion is the current version of the database.
// The database is reset if its version doesn't match this. // The database is reset if its version doesn't match this.
const CurrentVersion = 2 const CurrentVersion = 2
func init() {
sqlite.MustRegisterScalarFunction("json_array_contains", 2, jsonArrayContains)
}
// Package is a ALR package's database representation // Package is a ALR package's database representation
type Package struct { type Package struct {
Name string `sh:"name,required" db:"name"` Name string `sh:"name,required" db:"name"`
@@ -66,66 +56,47 @@ type version struct {
Version int `db:"version"` Version int `db:"version"`
} }
var ( type Config interface {
mu sync.Mutex GetPaths(ctx context.Context) *config.Paths
}
type Database struct {
conn *sqlx.DB conn *sqlx.DB
closed = true config Config
) }
// DB returns the ALR database. func New(config Config) *Database {
// The first time it's called, it opens the SQLite database file. return &Database{
// Subsequent calls return the same connection. config: config,
func DB(ctx context.Context) *sqlx.DB {
log := loggerctx.From(ctx)
if conn != nil && !closed {
return getConn()
} }
_, err := open(ctx, config.GetPaths(ctx).DBPath) }
func (d *Database) Init(ctx context.Context) error {
err := d.Connect(ctx)
if err != nil { if err != nil {
log.Fatal("Error opening database").Err(err).Send() return err
} }
return getConn() return d.initDB(ctx)
} }
func getConn() *sqlx.DB { func (d *Database) Connect(ctx context.Context) error {
mu.Lock() dsn := d.config.GetPaths(ctx).DBPath
defer mu.Unlock()
return conn
}
func open(ctx context.Context, dsn string) (*sqlx.DB, error) {
db, err := sqlx.Open("sqlite", dsn) db, err := sqlx.Open("sqlite", dsn)
if err != nil { if err != nil {
return nil, err return err
} }
d.conn = db
mu.Lock() return nil
conn = db
closed = false
mu.Unlock()
err = initDB(ctx, dsn)
if err != nil {
return nil, err
}
return db, nil
} }
// Close closes the database func (d *Database) GetConn() *sqlx.DB {
func Close() error { return d.conn
closed = true
if conn != nil {
return conn.Close()
} else {
return nil
}
} }
// initDB initializes the database func (d *Database) initDB(ctx context.Context) error {
func initDB(ctx context.Context, dsn string) error {
log := loggerctx.From(ctx) log := loggerctx.From(ctx)
conn = conn.Unsafe() d.conn = d.conn.Unsafe()
conn := d.conn
_, err := conn.ExecContext(ctx, ` _, err := conn.ExecContext(ctx, `
CREATE TABLE IF NOT EXISTS pkgs ( CREATE TABLE IF NOT EXISTS pkgs (
name TEXT NOT NULL, name TEXT NOT NULL,
@@ -155,58 +126,72 @@ func initDB(ctx context.Context, dsn string) error {
return err return err
} }
ver, ok := GetVersion(ctx) ver, ok := d.GetVersion(ctx)
if ok && ver != CurrentVersion { if ok && ver != CurrentVersion {
log.Warn("Database version mismatch; resetting").Int("version", ver).Int("expected", CurrentVersion).Send() log.Warn("Database version mismatch; resetting").Int("version", ver).Int("expected", CurrentVersion).Send()
reset(ctx) d.reset(ctx)
return initDB(ctx, dsn) return d.initDB(ctx)
} else if !ok { } else if !ok {
log.Warn("Database version does not exist. Run alr fix if something isn't working.").Send() log.Warn("Database version does not exist. Run alr fix if something isn't working.").Send()
return addVersion(ctx, CurrentVersion) return d.addVersion(ctx, CurrentVersion)
} }
return nil return nil
} }
// reset drops all the database tables func (d *Database) GetVersion(ctx context.Context) (int, bool) {
func reset(ctx context.Context) error {
_, err := DB(ctx).ExecContext(ctx, "DROP TABLE IF EXISTS pkgs;")
if err != nil {
return err
}
_, err = DB(ctx).ExecContext(ctx, "DROP TABLE IF EXISTS alr_db_version;")
return err
}
// IsEmpty returns true if the database has no packages in it, otherwise it returns false.
func IsEmpty(ctx context.Context) bool {
var count int
err := DB(ctx).GetContext(ctx, &count, "SELECT count(1) FROM pkgs;")
if err != nil {
return true
}
return count == 0
}
// GetVersion returns the database version and a boolean indicating
// whether the database contained a version number
func GetVersion(ctx context.Context) (int, bool) {
var ver version var ver version
err := DB(ctx).GetContext(ctx, &ver, "SELECT * FROM alr_db_version LIMIT 1;") err := d.conn.GetContext(ctx, &ver, "SELECT * FROM alr_db_version LIMIT 1;")
if err != nil { if err != nil {
return 0, false return 0, false
} }
return ver.Version, true return ver.Version, true
} }
func addVersion(ctx context.Context, ver int) error { func (d *Database) addVersion(ctx context.Context, ver int) error {
_, err := DB(ctx).ExecContext(ctx, `INSERT INTO alr_db_version(version) VALUES (?);`, ver) _, err := d.conn.ExecContext(ctx, `INSERT INTO alr_db_version(version) VALUES (?);`, ver)
return err return err
} }
// InsertPackage adds a package to the database func (d *Database) reset(ctx context.Context) error {
func InsertPackage(ctx context.Context, pkg Package) error { _, err := d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS pkgs;")
_, err := DB(ctx).NamedExecContext(ctx, ` if err != nil {
return err
}
_, err = d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS alr_db_version;")
return err
}
func (d *Database) GetPkgs(ctx context.Context, where string, args ...any) (*sqlx.Rows, error) {
stream, err := d.conn.QueryxContext(ctx, "SELECT * FROM pkgs WHERE "+where, args...)
if err != nil {
return nil, err
}
return stream, nil
}
func (d *Database) GetPkg(ctx context.Context, where string, args ...any) (*Package, error) {
out := &Package{}
err := d.conn.GetContext(ctx, out, "SELECT * FROM pkgs WHERE "+where+" LIMIT 1", args...)
return out, err
}
func (d *Database) DeletePkgs(ctx context.Context, where string, args ...any) error {
_, err := d.conn.ExecContext(ctx, "DELETE FROM pkgs WHERE "+where, args...)
return err
}
func (d *Database) IsEmpty(ctx context.Context) bool {
var count int
err := d.conn.GetContext(ctx, &count, "SELECT count(1) FROM pkgs;")
if err != nil {
return true
}
return count == 0
}
func (d *Database) InsertPackage(ctx context.Context, pkg Package) error {
_, err := d.conn.NamedExecContext(ctx, `
INSERT OR REPLACE INTO pkgs ( INSERT OR REPLACE INTO pkgs (
name, name,
repository, repository,
@@ -246,101 +231,10 @@ func InsertPackage(ctx context.Context, pkg Package) error {
return err return err
} }
// GetPkgs returns a result containing packages that match the where conditions func (d *Database) Close() error {
func GetPkgs(ctx context.Context, where string, args ...any) (*sqlx.Rows, error) { if d.conn != nil {
stream, err := DB(ctx).QueryxContext(ctx, "SELECT * FROM pkgs WHERE "+where, args...) return d.conn.Close()
if err != nil { } else {
return nil, err
}
return stream, nil
}
// GetPkg returns a single package that matches the where conditions
func GetPkg(ctx context.Context, where string, args ...any) (*Package, error) {
out := &Package{}
err := DB(ctx).GetContext(ctx, out, "SELECT * FROM pkgs WHERE "+where+" LIMIT 1", args...)
return out, err
}
// DeletePkgs deletes all packages matching the where conditions
func DeletePkgs(ctx context.Context, where string, args ...any) error {
_, err := DB(ctx).ExecContext(ctx, "DELETE FROM pkgs WHERE "+where, args...)
return err
}
// jsonArrayContains is an SQLite function that checks if a JSON array
// in the database contains a given value
func jsonArrayContains(ctx *sqlite.FunctionContext, args []driver.Value) (driver.Value, error) {
value, ok := args[0].(string)
if !ok {
return nil, errors.New("both arguments to json_array_contains must be strings")
}
item, ok := args[1].(string)
if !ok {
return nil, errors.New("both arguments to json_array_contains must be strings")
}
var array []string
err := json.Unmarshal([]byte(value), &array)
if err != nil {
return nil, err
}
return slices.Contains(array, item), nil
}
// JSON represents a JSON value in the database
type JSON[T any] struct {
Val T
}
// NewJSON creates a new database JSON value
func NewJSON[T any](v T) JSON[T] {
return JSON[T]{Val: v}
}
func (s *JSON[T]) Scan(val any) error {
if val == nil {
return nil return nil
} }
switch val := val.(type) {
case string:
err := json.Unmarshal([]byte(val), &s.Val)
if err != nil {
return err
}
case sql.NullString:
if val.Valid {
err := json.Unmarshal([]byte(val.String), &s.Val)
if err != nil {
return err
}
}
default:
return errors.New("sqlite json types must be strings")
}
return nil
}
func (s JSON[T]) Value() (driver.Value, error) {
data, err := json.Marshal(s.Val)
if err != nil {
return nil, err
}
return string(data), nil
}
func (s JSON[T]) MarshalYAML() (any, error) {
return s.Val, nil
}
func (s JSON[T]) String() string {
return fmt.Sprint(s.Val)
}
func (s JSON[T]) GoString() string {
return fmt.Sprintf("%#v", s.Val)
} }

104
internal/db/db_legacy.go Normal file
View File

@@ -0,0 +1,104 @@
// 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 <http://www.gnu.org/licenses/>.
package db
import (
"context"
"sync"
"github.com/jmoiron/sqlx"
"plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/pkg/loggerctx"
)
// DB returns the ALR database.
// The first time it's called, it opens the SQLite database file.
// Subsequent calls return the same connection.
//
// Deprecated: use struct method
func DB(ctx context.Context) *sqlx.DB {
return GetInstance(ctx).GetConn()
}
// Close closes the database
//
// Deprecated: use struct method
func Close() error {
if database != nil {
return database.Close()
}
return nil
}
// IsEmpty returns true if the database has no packages in it, otherwise it returns false.
//
// Deprecated: use struct method
func IsEmpty(ctx context.Context) bool {
return GetInstance(ctx).IsEmpty(ctx)
}
// InsertPackage adds a package to the database
//
// Deprecated: use struct method
func InsertPackage(ctx context.Context, pkg Package) error {
return GetInstance(ctx).InsertPackage(ctx, pkg)
}
// GetPkgs returns a result containing packages that match the where conditions
//
// Deprecated: use struct method
func GetPkgs(ctx context.Context, where string, args ...any) (*sqlx.Rows, error) {
return GetInstance(ctx).GetPkgs(ctx, where, args...)
}
// GetPkg returns a single package that matches the where conditions
//
// Deprecated: use struct method
func GetPkg(ctx context.Context, where string, args ...any) (*Package, error) {
return GetInstance(ctx).GetPkg(ctx, where, args...)
}
// DeletePkgs deletes all packages matching the where conditions
//
// Deprecated: use struct method
func DeletePkgs(ctx context.Context, where string, args ...any) error {
return GetInstance(ctx).DeletePkgs(ctx, where, args...)
}
// =======================
// FOR LEGACY ONLY
// =======================
var (
dbOnce sync.Once
database *Database
)
// Deprecated: For legacy only
func GetInstance(ctx context.Context) *Database {
dbOnce.Do(func() {
log := loggerctx.From(ctx)
cfg := config.GetInstance(ctx)
database = New(cfg)
err := database.Init(ctx)
if err != nil {
log.Fatal("Error opening database").Err(err).Send()
}
})
return database
}

View File

@@ -1,32 +1,50 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package db_test package db_test
import ( import (
"context"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
) )
type TestALRConfig struct{}
func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
return &config.Paths{
DBPath: ":memory:",
}
}
func prepareDb() *db.Database {
database := db.New(&TestALRConfig{})
database.Init(context.Background())
return database
}
var testPkg = db.Package{ var testPkg = db.Package{
Name: "test", Name: "test",
Version: "0.0.1", Version: "0.0.1",
@@ -59,18 +77,11 @@ var testPkg = db.Package{
} }
func TestInit(t *testing.T) { func TestInit(t *testing.T) {
_, err := db.Open(":memory:") ctx := context.Background()
if err != nil { database := prepareDb()
t.Fatalf("Expected no error, got %s", err) defer database.Close()
}
defer db.Close()
_, err = db.DB().Exec("SELECT * FROM pkgs") ver, ok := database.GetVersion(ctx)
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
ver, ok := db.GetVersion()
if !ok { if !ok {
t.Errorf("Expected version to be present") t.Errorf("Expected version to be present")
} else if ver != db.CurrentVersion { } else if ver != db.CurrentVersion {
@@ -79,19 +90,17 @@ func TestInit(t *testing.T) {
} }
func TestInsertPackage(t *testing.T) { func TestInsertPackage(t *testing.T) {
_, err := db.Open(":memory:") ctx := context.Background()
if err != nil { database := prepareDb()
t.Fatalf("Expected no error, got %s", err) defer database.Close()
}
defer db.Close()
err = db.InsertPackage(testPkg) err := database.InsertPackage(ctx, testPkg)
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
dbPkg := db.Package{} dbPkg := db.Package{}
err = sqlx.Get(db.DB(), &dbPkg, "SELECT * FROM pkgs WHERE name = 'test' AND repository = 'default'") err = sqlx.Get(database.GetConn(), &dbPkg, "SELECT * FROM pkgs WHERE name = 'test' AND repository = 'default'")
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
@@ -102,28 +111,26 @@ func TestInsertPackage(t *testing.T) {
} }
func TestGetPkgs(t *testing.T) { func TestGetPkgs(t *testing.T) {
_, err := db.Open(":memory:") ctx := context.Background()
if err != nil { database := prepareDb()
t.Fatalf("Expected no error, got %s", err) defer database.Close()
}
defer db.Close()
x1 := testPkg x1 := testPkg
x1.Name = "x1" x1.Name = "x1"
x2 := testPkg x2 := testPkg
x2.Name = "x2" x2.Name = "x2"
err = db.InsertPackage(x1) err := database.InsertPackage(ctx, x1)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
err = db.InsertPackage(x2) err = database.InsertPackage(ctx, x2)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
result, err := db.GetPkgs("name LIKE 'x%'") result, err := database.GetPkgs(ctx, "name LIKE 'x%'")
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
@@ -142,28 +149,26 @@ func TestGetPkgs(t *testing.T) {
} }
func TestGetPkg(t *testing.T) { func TestGetPkg(t *testing.T) {
_, err := db.Open(":memory:") ctx := context.Background()
if err != nil { database := prepareDb()
t.Fatalf("Expected no error, got %s", err) defer database.Close()
}
defer db.Close()
x1 := testPkg x1 := testPkg
x1.Name = "x1" x1.Name = "x1"
x2 := testPkg x2 := testPkg
x2.Name = "x2" x2.Name = "x2"
err = db.InsertPackage(x1) err := database.InsertPackage(ctx, x1)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
err = db.InsertPackage(x2) err = database.InsertPackage(ctx, x2)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
pkg, err := db.GetPkg("name LIKE 'x%' ORDER BY name") pkg, err := database.GetPkg(ctx, "name LIKE 'x%' ORDER BY name")
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
@@ -178,34 +183,32 @@ func TestGetPkg(t *testing.T) {
} }
func TestDeletePkgs(t *testing.T) { func TestDeletePkgs(t *testing.T) {
_, err := db.Open(":memory:") ctx := context.Background()
if err != nil { database := prepareDb()
t.Fatalf("Expected no error, got %s", err) defer database.Close()
}
defer db.Close()
x1 := testPkg x1 := testPkg
x1.Name = "x1" x1.Name = "x1"
x2 := testPkg x2 := testPkg
x2.Name = "x2" x2.Name = "x2"
err = db.InsertPackage(x1) err := database.InsertPackage(ctx, x1)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
err = db.InsertPackage(x2) err = database.InsertPackage(ctx, x2)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
err = db.DeletePkgs("name = 'x1'") err = database.DeletePkgs(ctx, "name = 'x1'")
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
var dbPkg db.Package var dbPkg db.Package
err = db.DB().Get(&dbPkg, "SELECT * FROM pkgs WHERE name LIKE 'x%' ORDER BY name LIMIT 1;") err = database.GetConn().Get(&dbPkg, "SELECT * FROM pkgs WHERE name LIKE 'x%' ORDER BY name LIMIT 1;")
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
@@ -216,11 +219,9 @@ func TestDeletePkgs(t *testing.T) {
} }
func TestJsonArrayContains(t *testing.T) { func TestJsonArrayContains(t *testing.T) {
_, err := db.Open(":memory:") ctx := context.Background()
if err != nil { database := prepareDb()
t.Fatalf("Expected no error, got %s", err) defer database.Close()
}
defer db.Close()
x1 := testPkg x1 := testPkg
x1.Name = "x1" x1.Name = "x1"
@@ -228,18 +229,18 @@ func TestJsonArrayContains(t *testing.T) {
x2.Name = "x2" x2.Name = "x2"
x2.Provides.Val = append(x2.Provides.Val, "x") x2.Provides.Val = append(x2.Provides.Val, "x")
err = db.InsertPackage(x1) err := database.InsertPackage(ctx, x1)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
err = db.InsertPackage(x2) err = database.InsertPackage(ctx, x2)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
var dbPkg db.Package var dbPkg db.Package
err = db.DB().Get(&dbPkg, "SELECT * FROM pkgs WHERE json_array_contains(provides, 'x');") err = database.GetConn().Get(&dbPkg, "SELECT * FROM pkgs WHERE json_array_contains(provides, 'x');")
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }

80
internal/db/json.go Normal file
View File

@@ -0,0 +1,80 @@
// 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 <http://www.gnu.org/licenses/>.
package db
import (
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
)
// JSON represents a JSON value in the database
type JSON[T any] struct {
Val T
}
// NewJSON creates a new database JSON value
func NewJSON[T any](v T) JSON[T] {
return JSON[T]{Val: v}
}
func (s *JSON[T]) Scan(val any) error {
if val == nil {
return nil
}
switch val := val.(type) {
case string:
err := json.Unmarshal([]byte(val), &s.Val)
if err != nil {
return err
}
case sql.NullString:
if val.Valid {
err := json.Unmarshal([]byte(val.String), &s.Val)
if err != nil {
return err
}
}
default:
return errors.New("sqlite json types must be strings")
}
return nil
}
func (s JSON[T]) Value() (driver.Value, error) {
data, err := json.Marshal(s.Val)
if err != nil {
return nil, err
}
return string(data), nil
}
func (s JSON[T]) MarshalYAML() (any, error) {
return s.Val, nil
}
func (s JSON[T]) String() string {
return fmt.Sprint(s.Val)
}
func (s JSON[T]) GoString() string {
return fmt.Sprintf("%#v", s.Val)
}

52
internal/db/utils.go Normal file
View File

@@ -0,0 +1,52 @@
// 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 <http://www.gnu.org/licenses/>.
package db
import (
"database/sql/driver"
"encoding/json"
"errors"
"golang.org/x/exp/slices"
"modernc.org/sqlite"
)
func init() {
sqlite.MustRegisterScalarFunction("json_array_contains", 2, jsonArrayContains)
}
// jsonArrayContains is an SQLite function that checks if a JSON array
// in the database contains a given value
func jsonArrayContains(ctx *sqlite.FunctionContext, args []driver.Value) (driver.Value, error) {
value, ok := args[0].(string)
if !ok {
return nil, errors.New("both arguments to json_array_contains must be strings")
}
item, ok := args[1].(string)
if !ok {
return nil, errors.New("both arguments to json_array_contains must be strings")
}
var array []string
err := json.Unmarshal([]byte(value), &array)
if err != nil {
return nil, err
}
return slices.Contains(array, item), nil
}

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Пакет dl содержит абстракции для загрузки файлов и каталогов // Пакет dl содержит абстракции для загрузки файлов и каталогов
// из различных источников. // из различных источников.
@@ -39,6 +40,8 @@ import (
"golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2b"
"golang.org/x/crypto/blake2s" "golang.org/x/crypto/blake2s"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/dlcache" "plemya-x.ru/alr/internal/dlcache"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
) )
@@ -142,6 +145,9 @@ type UpdatingDownloader interface {
// Функция Download загружает файл или каталог с использованием указанных параметров // Функция Download загружает файл или каталог с использованием указанных параметров
func Download(ctx context.Context, opts Options) (err error) { func Download(ctx context.Context, opts Options) (err error) {
log := loggerctx.From(ctx) log := loggerctx.From(ctx)
cfg := config.GetInstance(ctx)
dc := dlcache.New(cfg)
normalized, err := normalizeURL(opts.URL) normalized, err := normalizeURL(opts.URL)
if err != nil { if err != nil {
return err return err
@@ -156,7 +162,7 @@ func Download(ctx context.Context, opts Options) (err error) {
} }
var t Type var t Type
cacheDir, ok := dlcache.Get(ctx, opts.URL) cacheDir, ok := dc.Get(ctx, opts.URL)
if ok { if ok {
var updated bool var updated bool
if d, ok := d.(UpdatingDownloader); ok { if d, ok := d.(UpdatingDownloader); ok {
@@ -203,7 +209,7 @@ func Download(ctx context.Context, opts Options) (err error) {
log.Info("Downloading source").Str("source", opts.Name).Str("downloader", d.Name()).Send() log.Info("Downloading source").Str("source", opts.Name).Str("downloader", d.Name()).Send()
cacheDir, err = dlcache.New(ctx, opts.URL) cacheDir, err = dc.New(ctx, opts.URL)
if err != nil { if err != nil {
return err return err
} }
@@ -299,8 +305,6 @@ func linkDir(src, dest string) error {
return nil return nil
} }
rel, err := filepath.Rel(src, path) rel, err := filepath.Rel(src, path)
if err != nil { if err != nil {
return err return err

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dl package dl
@@ -33,6 +34,7 @@ import (
"github.com/mholt/archiver/v4" "github.com/mholt/archiver/v4"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
"plemya-x.ru/alr/internal/shutils/handlers" "plemya-x.ru/alr/internal/shutils/handlers"
) )
@@ -222,7 +224,7 @@ func extractFile(r io.Reader, format archiver.Format, name string, opts Options)
} }
if f.IsDir() { if f.IsDir() {
err = os.Mkdir(path, 0o755) err = os.MkdirAll(path, 0o755)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dl package dl

View File

@@ -1,3 +1,22 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package dl package dl
import ( import (

View File

@@ -1,48 +1,61 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dlcache package dlcache
import ( import (
"context" "context"
"crypto/sha1"
"encoding/hex"
"io"
"os" "os"
"path/filepath" "path/filepath"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
) )
// BasePath returns the base path of the download cache type Config interface {
func BasePath(ctx context.Context) string { GetPaths(ctx context.Context) *config.Paths
return filepath.Join(config.GetPaths(ctx).CacheDir, "dl") }
type DownloadCache struct {
cfg Config
}
func New(cfg Config) *DownloadCache {
return &DownloadCache{
cfg,
}
}
func (dc *DownloadCache) BasePath(ctx context.Context) string {
return filepath.Join(
dc.cfg.GetPaths(ctx).CacheDir, "dl",
)
} }
// New creates a new directory with the given ID in the cache. // New creates a new directory with the given ID in the cache.
// If a directory with the same ID already exists, // If a directory with the same ID already exists,
// it will be deleted before creating a new one. // it will be deleted before creating a new one.
func New(ctx context.Context, id string) (string, error) { func (dc *DownloadCache) New(ctx context.Context, id string) (string, error) {
h, err := hashID(id) h, err := hashID(id)
if err != nil { if err != nil {
return "", err return "", err
} }
itemPath := filepath.Join(BasePath(ctx), h) itemPath := filepath.Join(dc.BasePath(ctx), h)
fi, err := os.Stat(itemPath) fi, err := os.Stat(itemPath)
if err == nil || (fi != nil && !fi.IsDir()) { if err == nil || (fi != nil && !fi.IsDir()) {
@@ -65,12 +78,12 @@ func New(ctx context.Context, id string) (string, error) {
// returns the directory and true. If it // returns the directory and true. If it
// does not exist, it returns an empty string // does not exist, it returns an empty string
// and false. // and false.
func Get(ctx context.Context, id string) (string, bool) { func (dc *DownloadCache) Get(ctx context.Context, id string) (string, bool) {
h, err := hashID(id) h, err := hashID(id)
if err != nil { if err != nil {
return "", false return "", false
} }
itemPath := filepath.Join(BasePath(ctx), h) itemPath := filepath.Join(dc.BasePath(ctx), h)
_, err = os.Stat(itemPath) _, err = os.Stat(itemPath)
if err != nil { if err != nil {
@@ -79,15 +92,3 @@ func Get(ctx context.Context, id string) (string, bool) {
return itemPath, true return itemPath, true
} }
// hashID hashes the input ID with SHA1
// and returns the hex string of the hashed
// ID.
func hashID(id string) (string, error) {
h := sha1.New()
_, err := io.WriteString(h, id)
if err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dlcache_test package dlcache_test
@@ -39,14 +40,49 @@ func init() {
config.GetPaths(context.Background()).RepoDir = dir config.GetPaths(context.Background()).RepoDir = dir
} }
type TestALRConfig struct {
CacheDir string
}
func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
return &config.Paths{
CacheDir: c.CacheDir,
}
}
func prepare(t *testing.T) *TestALRConfig {
t.Helper()
dir, err := os.MkdirTemp("/tmp", "alr-dlcache-test.*")
if err != nil {
panic(err)
}
return &TestALRConfig{
CacheDir: dir,
}
}
func cleanup(t *testing.T, cfg *TestALRConfig) {
t.Helper()
os.Remove(cfg.CacheDir)
}
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
cfg := prepare(t)
defer cleanup(t, cfg)
dc := dlcache.New(cfg)
ctx := context.Background()
const id = "https://example.com" const id = "https://example.com"
dir, err := dlcache.New(id) dir, err := dc.New(ctx, id)
if err != nil { if err != nil {
t.Errorf("Expected no error, got %s", err) t.Errorf("Expected no error, got %s", err)
} }
exp := filepath.Join(dlcache.BasePath(), sha1sum(id)) exp := filepath.Join(dc.BasePath(ctx), sha1sum(id))
if dir != exp { if dir != exp {
t.Errorf("Expected %s, got %s", exp, dir) t.Errorf("Expected %s, got %s", exp, dir)
} }
@@ -60,7 +96,7 @@ func TestNew(t *testing.T) {
t.Errorf("Expected cache item to be a directory") t.Errorf("Expected cache item to be a directory")
} }
dir2, ok := dlcache.Get(id) dir2, ok := dc.Get(ctx, id)
if !ok { if !ok {
t.Errorf("Expected Get() to return valid value") t.Errorf("Expected Get() to return valid value")
} }

32
internal/dlcache/utils.go Normal file
View File

@@ -0,0 +1,32 @@
// 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 <http://www.gnu.org/licenses/>.
package dlcache
import (
"crypto/sha1"
"encoding/hex"
"io"
)
func hashID(id string) (string, error) {
h := sha1.New()
_, err := io.WriteString(h, id)
if err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package osutils package osutils

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package overrides package overrides
@@ -22,11 +23,12 @@ import (
"reflect" "reflect"
"strings" "strings"
"golang.org/x/exp/slices"
"golang.org/x/text/language"
"plemya-x.ru/alr/internal/cpu" "plemya-x.ru/alr/internal/cpu"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/pkg/distro" "plemya-x.ru/alr/pkg/distro"
"golang.org/x/exp/slices"
"golang.org/x/text/language"
) )
type Opts struct { type Opts struct {

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package overrides_test package overrides_test
@@ -23,9 +24,10 @@ import (
"reflect" "reflect"
"testing" "testing"
"golang.org/x/text/language"
"plemya-x.ru/alr/internal/overrides" "plemya-x.ru/alr/internal/overrides"
"plemya-x.ru/alr/pkg/distro" "plemya-x.ru/alr/pkg/distro"
"golang.org/x/text/language"
) )
var info = &distro.OSRelease{ var info = &distro.OSRelease{

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pager package pager

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pager package pager

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package decoder package decoder
@@ -25,12 +26,13 @@ import (
"strings" "strings"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"plemya-x.ru/alr/internal/overrides"
"plemya-x.ru/alr/pkg/distro"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"mvdan.cc/sh/v3/expand" "mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"plemya-x.ru/alr/internal/overrides"
"plemya-x.ru/alr/pkg/distro"
) )
var ErrNotPointerToStruct = errors.New("val must be a pointer to a struct") var ErrNotPointerToStruct = errors.New("val must be a pointer to a struct")
@@ -221,3 +223,8 @@ func (d *Decoder) getVar(name string) *expand.Variable {
} }
return nil return nil
} }
func IsTruthy(value string) bool {
value = strings.ToLower(strings.TrimSpace(value))
return value == "true" || value == "yes" || value == "1"
}

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package decoder_test package decoder_test
@@ -27,10 +28,11 @@ import (
"strings" "strings"
"testing" "testing"
"plemya-x.ru/alr/internal/shutils/decoder"
"plemya-x.ru/alr/pkg/distro"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"plemya-x.ru/alr/internal/shutils/decoder"
"plemya-x.ru/alr/pkg/distro"
) )
type BuildVars struct { type BuildVars struct {
@@ -56,7 +58,7 @@ const testScript = `
release=1 release=1
epoch=2 epoch=2
desc="Test package" desc="Test package"
homepage='//https://gitea.plemya-x.ru/xpamych/ALR' homepage='https://gitea.plemya-x.ru/xpamych/ALR'
maintainer='Евгений Храмов <xpamych@yandex.ru>' maintainer='Евгений Храмов <xpamych@yandex.ru>'
architectures=('arm64' 'amd64') architectures=('arm64' 'amd64')
license=('GPL-3.0-or-later') license=('GPL-3.0-or-later')

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package handlers package handlers

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package handlers_test package handlers_test
@@ -23,11 +24,12 @@ import (
"strings" "strings"
"testing" "testing"
"plemya-x.ru/alr/internal/shutils/handlers"
"plemya-x.ru/alr/internal/shutils/decoder"
"plemya-x.ru/alr/pkg/distro"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"plemya-x.ru/alr/internal/shutils/decoder"
"plemya-x.ru/alr/internal/shutils/handlers"
"plemya-x.ru/alr/pkg/distro"
) )
const testScript = ` const testScript = `
@@ -89,7 +91,7 @@ func TestExecFuncs(t *testing.T) {
t.Fatalf("Expected test() function to exist") t.Fatalf("Expected test() function to exist")
} }
eh := shutils.ExecFuncs{ eh := handlers.ExecFuncs{
"test-cmd": func(hc interp.HandlerContext, name string, args []string) error { "test-cmd": func(hc interp.HandlerContext, name string, args []string) error {
if name != "test-cmd" { if name != "test-cmd" {
t.Errorf("Expected name to be 'test-cmd', got '%s'", name) t.Errorf("Expected name to be 'test-cmd', got '%s'", name)

View File

@@ -1,3 +1,22 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package handlers package handlers
import ( import (
@@ -10,9 +29,9 @@ import (
"syscall" "syscall"
"time" "time"
"plemya-x.ru/fakeroot"
"mvdan.cc/sh/v3/expand" "mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"plemya-x.ru/fakeroot"
) )
// FakerootExecHandler was extracted from github.com/mvdan/sh/interp/handler.go // FakerootExecHandler was extracted from github.com/mvdan/sh/interp/handler.go

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package handlers package handlers

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package handlers_test package handlers_test
@@ -25,9 +26,10 @@ import (
"strings" "strings"
"testing" "testing"
"plemya-x.ru/alr/internal/shutils/handlers"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"plemya-x.ru/alr/internal/shutils/handlers"
) )
func TestNopExec(t *testing.T) { func TestNopExec(t *testing.T) {

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package handlers package handlers

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package helpers package helpers
@@ -31,8 +32,9 @@ import (
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/object"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"plemya-x.ru/alr/internal/shutils/handlers"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"plemya-x.ru/alr/internal/shutils/handlers"
) )
var ( var (

View File

@@ -1,3 +1,22 @@
# This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
# It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
#
# 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 <http://www.gnu.org/licenses/>.
[[translation]] [[translation]]
id = 1228660974 id = 1228660974
value = 'Pulling repository' value = 'Pulling repository'

View File

@@ -1,3 +1,22 @@
# This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
# It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
#
# 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 <http://www.gnu.org/licenses/>.
[[translation]] [[translation]]
id = 1228660974 id = 1228660974
value = 'Скачивание репозитория' value = 'Скачивание репозитория'

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package translations package translations
@@ -24,9 +25,10 @@ import (
"sync" "sync"
"go.elara.ws/logger" "go.elara.ws/logger"
"plemya-x.ru/alr/pkg/loggerctx"
"go.elara.ws/translate" "go.elara.ws/translate"
"golang.org/x/text/language" "golang.org/x/text/language"
"plemya-x.ru/alr/pkg/loggerctx"
) )
//go:embed files //go:embed files

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package types package types
@@ -49,6 +50,8 @@ type BuildVars struct {
Checksums []string `sh:"checksums"` Checksums []string `sh:"checksums"`
Backup []string `sh:"backup"` Backup []string `sh:"backup"`
Scripts Scripts `sh:"scripts"` Scripts Scripts `sh:"scripts"`
AutoReq []string `sh:"auto_req"`
AutoProv []string `sh:"auto_prov"`
} }
type Scripts struct { type Scripts struct {

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package types package types

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package types package types

View File

@@ -0,0 +1,18 @@
This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
ALR - Any Linux Repository
Copyright (C) {{ .Year }} Евгений Храмов
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 <http://www.gnu.org/licenses/>.

15
license-header.tmpl Normal file
View File

@@ -0,0 +1,15 @@
ALR - Any Linux Repository
Copyright (C) {{ .Year }} Евгений Храмов
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 <http://www.gnu.org/licenses/>.

54
list.go
View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -22,12 +23,13 @@ import (
"fmt" "fmt"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/slices"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" database "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
"plemya-x.ru/alr/pkg/manager" "plemya-x.ru/alr/pkg/manager"
"plemya-x.ru/alr/pkg/repos" "plemya-x.ru/alr/pkg/repos"
"golang.org/x/exp/slices"
) )
var listCmd = &cli.Command{ var listCmd = &cli.Command{
@@ -43,8 +45,14 @@ var listCmd = &cli.Command{
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
ctx := c.Context ctx := c.Context
log := loggerctx.From(ctx) log := loggerctx.From(ctx)
cfg := config.New()
err := repos.Pull(ctx, config.Config(ctx).Repos) db := database.New(cfg)
err := db.Init(ctx)
if err != nil {
log.Fatal("Error initialization database").Err(err).Send()
}
rs := repos.New(cfg, db)
err = rs.Pull(ctx, cfg.Repos(ctx))
if err != nil { if err != nil {
log.Fatal("Error pulling repositories").Err(err).Send() log.Fatal("Error pulling repositories").Err(err).Send()
} }
@@ -76,13 +84,13 @@ var listCmd = &cli.Command{
} }
for result.Next() { for result.Next() {
var pkg db.Package var pkg database.Package
err := result.StructScan(&pkg) err := result.StructScan(&pkg)
if err != nil { if err != nil {
return err return err
} }
if slices.Contains(config.Config(ctx).IgnorePkgUpdates, pkg.Name) { if slices.Contains(cfg.IgnorePkgUpdates(ctx), pkg.Name) {
continue continue
} }

36
main.go
View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -28,6 +29,7 @@ import (
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"go.elara.ws/logger" "go.elara.ws/logger"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/translations" "plemya-x.ru/alr/internal/translations"

83
old-files Normal file
View File

@@ -0,0 +1,83 @@
./.github/FUNDING.yml
./.gitignore
./.goreleaser.yaml
./.woodpecker.yml
./LICENSE
./Makefile
./README.md
./assets/logo.png
./build.go
./docs/README.md
./docs/configuration.md
./docs/packages/README.md
./docs/packages/adding-packages.md
./docs/packages/build-scripts.md
./docs/packages/conventions.md
./docs/usage.md
./fix.go
./gen.go
./go.mod
./go.sum
./helper.go
./info.go
./install.go
./internal/cliutils/prompt.go
./internal/config/config.go
./internal/config/lang.go
./internal/config/paths.go
./internal/config/version.go
./internal/cpu/cpu.go
./internal/db/db.go
./internal/db/db_test.go
./internal/dl/dl.go
./internal/dl/file.go
./internal/dl/git.go
./internal/dl/torrent.go
./internal/dlcache/dlcache.go
./internal/dlcache/dlcache_test.go
./internal/osutils/move.go
./internal/overrides/overrides.go
./internal/overrides/overrides_test.go
./internal/pager/highlighting.go
./internal/pager/pager.go
./internal/shutils/decoder/decoder.go
./internal/shutils/decoder/decoder_test.go
./internal/shutils/handlers/exec.go
./internal/shutils/handlers/exec_test.go
./internal/shutils/handlers/fakeroot.go
./internal/shutils/handlers/nop.go
./internal/shutils/handlers/nop_test.go
./internal/shutils/handlers/restricted.go
./internal/shutils/helpers/helpers.go
./internal/translations/files/lure.en.toml
./internal/translations/files/lure.ru.toml
./internal/translations/translations.go
./internal/types/build.go
./internal/types/config.go
./internal/types/repo.go
./list.go
./main.go
./pkg/build/build.go
./pkg/build/install.go
./pkg/distro/osrelease.go
./pkg/gen/funcs.go
./pkg/gen/pip.go
./pkg/gen/tmpls/pip.tmpl.sh
./pkg/loggerctx/log.go
./pkg/manager/apk.go
./pkg/manager/apt.go
./pkg/manager/dnf.go
./pkg/manager/managers.go
./pkg/manager/pacman.go
./pkg/manager/yum.go
./pkg/manager/zypper.go
./pkg/repos/find.go
./pkg/repos/find_test.go
./pkg/repos/pull.go
./pkg/repos/pull_test.go
./pkg/search/search.go
./repo.go
./scripts/completion/bash
./scripts/completion/zsh
./scripts/install.sh
./upgrade.go

View File

@@ -1,29 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* Это программное обеспечение свободно: вы можете распространять его и/или изменять // the Free Software Foundation, either version 3 of the License, or
* на условиях GNU General Public License, опубликованной Free Software Foundation, // (at your option) any later version.
* либо версии 3 лицензии, либо (на ваш выбор) любой более поздней версии. //
* // This program is distributed in the hope that it will be useful,
* This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details.
* 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 <http://www.gnu.org/licenses/>.
* КОММЕРЧЕСКОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. См.
* GNU General Public License для более подробной информации.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Вы должны были получить копию GNU General Public License
* вместе с этой программой. Если нет, см. <http://www.gnu.org/licenses/>.
*/
package build package build
@@ -41,17 +33,19 @@ import (
"strings" "strings"
"time" "time"
// Импортируем пакеты для поддержки различных форматов пакетов (APK, DEB, RPM и ARCH). // Импортируем пакеты для поддержки различных форматов пакетов (APK, DEB, RPM и ARCH).
_ "github.com/goreleaser/nfpm/v2/apk" _ "github.com/goreleaser/nfpm/v2/apk"
_ "github.com/goreleaser/nfpm/v2/arch" _ "github.com/goreleaser/nfpm/v2/arch"
_ "github.com/goreleaser/nfpm/v2/deb" _ "github.com/goreleaser/nfpm/v2/deb"
_ "github.com/goreleaser/nfpm/v2/rpm" _ "github.com/goreleaser/nfpm/v2/rpm"
"go.elara.ws/logger/log"
"mvdan.cc/sh/v3/expand" "mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"github.com/goreleaser/nfpm/v2" "github.com/goreleaser/nfpm/v2"
"github.com/goreleaser/nfpm/v2/files" "github.com/goreleaser/nfpm/v2/files"
"plemya-x.ru/alr/internal/cliutils" "plemya-x.ru/alr/internal/cliutils"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/cpu" "plemya-x.ru/alr/internal/cpu"
@@ -82,8 +76,8 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
return nil, nil, err return nil, nil, err
} }
// Первый проход предназначен для получения значений переменных и выполняется // Первый проход предназначен для получения значений переменных и выполняется
// до отображения скрипта, чтобы предотвратить выполнение вредоносного кода. // до отображения скрипта, чтобы предотвратить выполнение вредоносного кода.
vars, err := executeFirstPass(ctx, info, fl, opts.Script) vars, err := executeFirstPass(ctx, info, fl, opts.Script)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -91,8 +85,8 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
dirs := getDirs(ctx, vars, opts.Script) dirs := getDirs(ctx, vars, opts.Script)
// Если флаг opts.Clean не установлен, и пакет уже собран, // Если флаг opts.Clean не установлен, и пакет уже собран,
// возвращаем его, а не собираем заново. // возвращаем его, а не собираем заново.
if !opts.Clean { if !opts.Clean {
builtPkgPath, ok, err := checkForBuiltPackage(opts.Manager, vars, getPkgFormat(opts.Manager), dirs.BaseDir) builtPkgPath, ok, err := checkForBuiltPackage(opts.Manager, vars, getPkgFormat(opts.Manager), dirs.BaseDir)
if err != nil { if err != nil {
@@ -104,7 +98,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
} }
} }
// Спрашиваем у пользователя, хочет ли он увидеть скрипт сборки. // Спрашиваем у пользователя, хочет ли он увидеть скрипт сборки.
err = cliutils.PromptViewScript(ctx, opts.Script, vars.Name, config.Config(ctx).PagerStyle, opts.Interactive) err = cliutils.PromptViewScript(ctx, opts.Script, vars.Name, config.Config(ctx).PagerStyle, opts.Interactive)
if err != nil { if err != nil {
log.Fatal("Failed to prompt user to view build script").Err(err).Send() log.Fatal("Failed to prompt user to view build script").Err(err).Send()
@@ -112,9 +106,9 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send() log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
// Второй проход будет использоваться для выполнения реального кода, // Второй проход будет использоваться для выполнения реального кода,
// поэтому он не ограничен. Скрипт уже был показан // поэтому он не ограничен. Скрипт уже был показан
// пользователю к этому моменту, так что это должно быть безопасно. // пользователю к этому моменту, так что это должно быть безопасно.
dec, err := executeSecondPass(ctx, info, fl, dirs) dec, err := executeSecondPass(ctx, info, fl, dirs)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -133,7 +127,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
os.Exit(1) // Если проверки не пройдены, выходим из программы os.Exit(1) // Если проверки не пройдены, выходим из программы
} }
// Подготавливаем директории для сборки // Подготавливаем директории для сборки
err = prepareDirs(dirs) err = prepareDirs(dirs)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -170,7 +164,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
pkgFormat := getPkgFormat(opts.Manager) // Получаем формат пакета pkgFormat := getPkgFormat(opts.Manager) // Получаем формат пакета
pkgInfo, err := buildPkgMetadata(vars, dirs, pkgFormat, info, append(repoDeps, builtNames...)) // Собираем метаданные пакета pkgInfo, err := buildPkgMetadata(ctx, vars, dirs, pkgFormat, info, append(repoDeps, builtNames...)) // Собираем метаданные пакета
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -181,7 +175,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
} }
pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета
pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету
pkgFile, err := os.Create(pkgPath) // Создаём файл пакета pkgFile, err := os.Create(pkgPath) // Создаём файл пакета
if err != nil { if err != nil {
@@ -200,14 +194,14 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
return nil, nil, err return nil, nil, err
} }
// Добавляем путь и имя только что собранного пакета в // Добавляем путь и имя только что собранного пакета в
// соответствующие срезы // соответствующие срезы
pkgPaths := append(builtPaths, pkgPath) pkgPaths := append(builtPaths, pkgPath)
pkgNames := append(builtNames, vars.Name) pkgNames := append(builtNames, vars.Name)
// Удаляем дубликаты из pkgPaths и pkgNames. // Удаляем дубликаты из pkgPaths и pkgNames.
// Дубликаты могут появиться, если несколько зависимостей // Дубликаты могут появиться, если несколько зависимостей
// зависят от одних и тех же пакетов. // зависят от одних и тех же пакетов.
pkgPaths = removeDuplicates(pkgPaths) pkgPaths = removeDuplicates(pkgPaths)
pkgNames = removeDuplicates(pkgNames) pkgNames = removeDuplicates(pkgNames)
@@ -233,16 +227,16 @@ func parseScript(info *distro.OSRelease, script string) (*syntax.File, error) {
// Функция executeFirstPass выполняет парсированный скрипт в ограниченной среде, // Функция executeFirstPass выполняет парсированный скрипт в ограниченной среде,
// чтобы извлечь переменные сборки без выполнения реального кода. // чтобы извлечь переменные сборки без выполнения реального кода.
func executeFirstPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, script string) (*types.BuildVars, error) { func executeFirstPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, script string) (*types.BuildVars, error) {
scriptDir := filepath.Dir(script) // Получаем директорию скрипта scriptDir := filepath.Dir(script) // Получаем директорию скрипта
env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir}) // Создаём переменные окружения для сборки env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir}) // Создаём переменные окружения для сборки
runner, err := interp.New( runner, err := interp.New(
interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)), // Ограничиваем выполнение interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)), // Ограничиваем выполнение
interp.ReadDirHandler(handlers.RestrictedReadDir(scriptDir)), // Ограничиваем чтение директорий interp.ReadDirHandler(handlers.RestrictedReadDir(scriptDir)), // Ограничиваем чтение директорий
interp.StatHandler(handlers.RestrictedStat(scriptDir)), // Ограничиваем доступ к статистике файлов interp.StatHandler(handlers.RestrictedStat(scriptDir)), // Ограничиваем доступ к статистике файлов
interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), // Ограничиваем открытие файлов interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), // Ограничиваем открытие файлов
) )
if err != nil { if err != nil {
return nil, err return nil, err
@@ -282,8 +276,8 @@ func executeSecondPass(ctx context.Context, info *distro.OSRelease, fl *syntax.F
fakeroot := handlers.FakerootExecHandler(2 * time.Second) // Настраиваем "fakeroot" для выполнения fakeroot := handlers.FakerootExecHandler(2 * time.Second) // Настраиваем "fakeroot" для выполнения
runner, err := interp.New( runner, err := interp.New(
interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
interp.ExecHandler(helpers.Helpers.ExecHandler(fakeroot)), // Обрабатываем выполнение через fakeroot interp.ExecHandler(helpers.Helpers.ExecHandler(fakeroot)), // Обрабатываем выполнение через fakeroot
) )
if err != nil { if err != nil {
@@ -396,30 +390,30 @@ func buildALRDeps(ctx context.Context, opts types.BuildOpts, vars *types.BuildVa
} }
repoDeps = notFound repoDeps = notFound
// Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез // Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез
pkgs := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive) pkgs := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive)
scripts := GetScriptPaths(ctx, pkgs) scripts := GetScriptPaths(ctx, pkgs)
for _, script := range scripts { for _, script := range scripts {
newOpts := opts newOpts := opts
newOpts.Script = script newOpts.Script = script
// Собираем зависимости // Собираем зависимости
pkgPaths, pkgNames, err := BuildPackage(ctx, newOpts) pkgPaths, pkgNames, err := BuildPackage(ctx, newOpts)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
// Добавляем пути всех собранных пакетов в builtPaths // Добавляем пути всех собранных пакетов в builtPaths
builtPaths = append(builtPaths, pkgPaths...) builtPaths = append(builtPaths, pkgPaths...)
// Добавляем пути всех собранных пакетов в builtPaths // Добавляем пути всех собранных пакетов в builtPaths
builtNames = append(builtNames, pkgNames...) builtNames = append(builtNames, pkgNames...)
// Добавляем имя текущего пакета в builtNames // Добавляем имя текущего пакета в builtNames
builtNames = append(builtNames, filepath.Base(filepath.Dir(script))) builtNames = append(builtNames, filepath.Base(filepath.Dir(script)))
} }
} }
// Удаляем возможные дубликаты, которые могут быть введены, если // Удаляем возможные дубликаты, которые могут быть введены, если
// несколько зависимостей зависят от одних и тех же пакетов. // несколько зависимостей зависят от одних и тех же пакетов.
repoDeps = removeDuplicates(repoDeps) repoDeps = removeDuplicates(repoDeps)
builtPaths = removeDuplicates(builtPaths) builtPaths = removeDuplicates(builtPaths)
builtNames = removeDuplicates(builtNames) builtNames = removeDuplicates(builtNames)
@@ -474,35 +468,35 @@ func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Dire
} }
} }
// Выполнение всех функций, начинающихся с package_ // Выполнение всех функций, начинающихся с package_
for { for {
packageFn, ok := dec.GetFunc("package") packageFn, ok := dec.GetFunc("package")
if ok { if ok {
log.Info("Executing package()").Send() log.Info("Executing package()").Send()
err = packageFn(ctx, interp.Dir(dirs.SrcDir)) err = packageFn(ctx, interp.Dir(dirs.SrcDir))
if err != nil { if err != nil {
return err return err
} }
} }
// Проверка на наличие дополнительных функций package_* // Проверка на наличие дополнительных функций package_*
packageFuncName := "package_" packageFuncName := "package_"
if packageFunc, ok := dec.GetFunc(packageFuncName); ok { if packageFunc, ok := dec.GetFunc(packageFuncName); ok {
log.Info("Executing " + packageFuncName).Send() log.Info("Executing " + packageFuncName).Send()
err = packageFunc(ctx, interp.Dir(dirs.SrcDir)) err = packageFunc(ctx, interp.Dir(dirs.SrcDir))
if err != nil { if err != nil {
return err return err
} }
} else { } else {
break // Если больше нет функций package_*, выходим из цикла break // Если больше нет функций package_*, выходим из цикла
} }
} }
return nil return nil
} }
// Функция buildPkgMetadata создает метаданные для пакета, который будет собран. // Функция buildPkgMetadata создает метаданные для пакета, который будет собран.
func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat string, info *distro.OSRelease, deps []string) (*nfpm.Info, error) { func buildPkgMetadata(ctx context.Context, vars *types.BuildVars, dirs types.Directories, pkgFormat string, info *distro.OSRelease, deps []string) (*nfpm.Info, error) {
pkgInfo := getBasePkgInfo(vars) pkgInfo := getBasePkgInfo(vars)
pkgInfo.Description = vars.Description pkgInfo.Description = vars.Description
pkgInfo.Platform = "linux" pkgInfo.Platform = "linux"
@@ -517,7 +511,7 @@ func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat s
} }
if pkgFormat == "apk" { if pkgFormat == "apk" {
// Alpine отказывается устанавливать пакеты, которые предоставляют сами себя, поэтому удаляем такие элементы // Alpine отказывается устанавливать пакеты, которые предоставляют сами себя, поэтому удаляем такие элементы
pkgInfo.Overridables.Provides = slices.DeleteFunc(pkgInfo.Overridables.Provides, func(s string) bool { pkgInfo.Overridables.Provides = slices.DeleteFunc(pkgInfo.Overridables.Provides, func(s string) bool {
return s == pkgInfo.Name return s == pkgInfo.Name
}) })
@@ -543,6 +537,28 @@ func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat s
} }
pkgInfo.Overridables.Contents = contents pkgInfo.Overridables.Contents = contents
if len(vars.AutoProv) == 1 && decoder.IsTruthy(vars.AutoProv[0]) {
if pkgFormat == "rpm" {
err = rpmFindProvides(ctx, pkgInfo, dirs)
if err != nil {
return nil, err
}
} else {
log.Info("AutoProv is not implemented for this package format, so it's skiped").Send()
}
}
if len(vars.AutoReq) == 1 && decoder.IsTruthy(vars.AutoReq[0]) {
if pkgFormat == "rpm" {
err = rpmFindRequires(ctx, pkgInfo, dirs)
if err != nil {
return nil, err
}
} else {
log.Info("AutoReq is not implemented for this package format, so it's skiped").Send()
}
}
return pkgInfo, nil return pkgInfo, nil
} }
@@ -559,7 +575,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
return err return err
} }
// Если директория пустая, пропускаем её // Если директория пустая, пропускаем её
_, err = f.Readdirnames(1) _, err = f.Readdirnames(1)
if err != io.EOF { if err != io.EOF {
return nil return nil
@@ -576,13 +592,13 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
return f.Close() return f.Close()
} }
// Если файл является символической ссылкой, прорабатываем это // Если файл является символической ссылкой, прорабатываем это
if fi.Mode()&os.ModeSymlink != 0 { if fi.Mode()&os.ModeSymlink != 0 {
link, err := os.Readlink(path) link, err := os.Readlink(path)
if err != nil { if err != nil {
return err return err
} }
// Удаляем pkgdir из пути символической ссылки // Удаляем pkgdir из пути символической ссылки
link = strings.TrimPrefix(link, dirs.PkgDir) link = strings.TrimPrefix(link, dirs.PkgDir)
contents = append(contents, &files.Content{ contents = append(contents, &files.Content{
@@ -597,7 +613,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
return nil return nil
} }
// Обрабатываем обычные файлы // Обрабатываем обычные файлы
fileContent := &files.Content{ fileContent := &files.Content{
Source: path, Source: path,
Destination: trimmed, Destination: trimmed,
@@ -608,7 +624,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
}, },
} }
// Если файл должен быть сохранен, установите его тип как config|noreplace // Если файл должен быть сохранен, установите его тип как config|noreplace
if slices.Contains(vars.Backup, trimmed) { if slices.Contains(vars.Backup, trimmed) {
fileContent.Type = "config|noreplace" fileContent.Type = "config|noreplace"
} }
@@ -744,9 +760,9 @@ func getSources(ctx context.Context, dirs types.Directories, bv *types.BuildVars
} }
if !strings.EqualFold(bv.Checksums[i], "SKIP") { if !strings.EqualFold(bv.Checksums[i], "SKIP") {
// Если контрольная сумма содержит двоеточие, используйте часть до двоеточия // Если контрольная сумма содержит двоеточие, используйте часть до двоеточия
// как алгоритм, а часть после как фактическую контрольную сумму. // как алгоритм, а часть после как фактическую контрольную сумму.
// В противном случае используйте sha256 по умолчанию с целой строкой как контрольной суммой. // В противном случае используйте sha256 по умолчанию с целой строкой как контрольной суммой.
algo, hashData, ok := strings.Cut(bv.Checksums[i], ":") algo, hashData, ok := strings.Cut(bv.Checksums[i], ":")
if ok { if ok {
checksum, err := hex.DecodeString(hashData) checksum, err := hex.DecodeString(hashData)

97
pkg/build/findDeps.go Normal file
View File

@@ -0,0 +1,97 @@
// 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 <http://www.gnu.org/licenses/>.
package build
import (
"bytes"
"context"
"os/exec"
"path"
"strings"
"github.com/goreleaser/nfpm/v2"
"plemya-x.ru/alr/internal/types"
"plemya-x.ru/alr/pkg/loggerctx"
)
func rpmFindDependencies(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, command string, updateFunc func(string)) error {
log := loggerctx.From(ctx)
if _, err := exec.LookPath(command); err != nil {
log.Info("Command not found on the system").Str("command", command).Send()
return nil
}
var paths []string
for _, content := range pkgInfo.Contents {
if content.Type != "dir" {
paths = append(paths,
path.Join(dirs.PkgDir, content.Destination),
)
}
}
if len(paths) == 0 {
return nil
}
cmd := exec.Command(command)
cmd.Stdin = bytes.NewBufferString(strings.Join(paths, "\n"))
cmd.Env = append(cmd.Env,
"RPM_BUILD_ROOT="+dirs.PkgDir,
"RPM_FINDPROV_METHOD=",
"RPM_FINDREQ_METHOD=",
"RPM_DATADIR=",
"RPM_SUBPACKAGE_NAME=",
)
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
log.Error(stderr.String()).Send()
return err
}
dependencies := strings.Split(strings.TrimSpace(out.String()), "\n")
for _, dep := range dependencies {
if dep != "" {
updateFunc(dep)
}
}
return nil
}
func rpmFindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories) error {
log := loggerctx.From(ctx)
return rpmFindDependencies(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-provides", func(dep string) {
log.Info("Provided dependency found").Str("dep", dep).Send()
pkgInfo.Overridables.Provides = append(pkgInfo.Overridables.Provides, dep)
})
}
func rpmFindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories) error {
log := loggerctx.From(ctx)
return rpmFindDependencies(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-requires", func(dep string) {
log.Info("Required dependency found").Str("dep", dep).Send()
pkgInfo.Overridables.Depends = append(pkgInfo.Overridables.Depends, dep)
})
}

View File

@@ -1,31 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* ALR - Любой Linux Репозиторий //
* Copyright (C) 2024 Евгений Храмов // ALR - Any Linux Repository
* // Copyright (C) 2025 Евгений Храмов
* This program is free software: you can redistribute it and/or modify //
* Это программное обеспечение является свободным: вы можете распространять его и/или изменять // 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 // it under the terms of the GNU General Public License as published by
* на условиях GNU General Public License, опубликованной // the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or // (at your option) any later version.
* Free Software Foundation, либо версии 3 лицензии, либо //
* (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
* This program is distributed in the hope that it will be useful, // GNU General Public License for more details.
* Это программное обеспечение распространяется в надежде, что оно будет полезным, //
* but WITHOUT ANY WARRANTY; without even the implied warranty of // You should have received a copy of the GNU General Public License
* но БЕЗ КАКОЙ-ЛИБО ГАРАНТИИ; даже без подразумеваемой гарантии // along with this program. If not, see <http://www.gnu.org/licenses/>.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* КОММЕРЧЕСКОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ.
* GNU General Public License for more details.
* Подробности смотрите в GNU General Public License.
*
* You should have received a copy of the GNU General Public License
* Вы должны были получить копию GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* вместе с этой программой. Если нет, посмотрите <http://www.gnu.org/licenses/>.
*/
package build package build
@@ -46,15 +36,15 @@ func InstallPkgs(ctx context.Context, alrPkgs []db.Package, nativePkgs []string,
if len(nativePkgs) > 0 { if len(nativePkgs) > 0 {
err := opts.Manager.Install(nil, nativePkgs...) err := opts.Manager.Install(nil, nativePkgs...)
// Если есть нативные пакеты, выполняем их установку // Если есть нативные пакеты, выполняем их установку
if err != nil { if err != nil {
log.Fatal("Error installing native packages").Err(err).Send() log.Fatal("Error installing native packages").Err(err).Send()
// Логируем и завершаем выполнение при ошибке // Логируем и завершаем выполнение при ошибке
} }
} }
InstallScripts(ctx, GetScriptPaths(ctx, alrPkgs), opts) InstallScripts(ctx, GetScriptPaths(ctx, alrPkgs), opts)
// Устанавливаем скрипты сборки через функцию InstallScripts // Устанавливаем скрипты сборки через функцию InstallScripts
} }
// GetScriptPaths возвращает срез путей к скриптам, соответствующий // GetScriptPaths возвращает срез путей к скриптам, соответствующий
@@ -62,7 +52,7 @@ func InstallPkgs(ctx context.Context, alrPkgs []db.Package, nativePkgs []string,
func GetScriptPaths(ctx context.Context, pkgs []db.Package) []string { func GetScriptPaths(ctx context.Context, pkgs []db.Package) []string {
var scripts []string var scripts []string
for _, pkg := range pkgs { for _, pkg := range pkgs {
// Для каждого пакета создаем путь к скрипту сборки // Для каждого пакета создаем путь к скрипту сборки
scriptPath := filepath.Join(config.GetPaths(ctx).RepoDir, pkg.Repository, pkg.Name, "alr.sh") scriptPath := filepath.Join(config.GetPaths(ctx).RepoDir, pkg.Repository, pkg.Name, "alr.sh")
scripts = append(scripts, scriptPath) scripts = append(scripts, scriptPath)
} }
@@ -75,17 +65,17 @@ func InstallScripts(ctx context.Context, scripts []string, opts types.BuildOpts)
for _, script := range scripts { for _, script := range scripts {
opts.Script = script // Устанавливаем текущий скрипт в опции opts.Script = script // Устанавливаем текущий скрипт в опции
builtPkgs, _, err := BuildPackage(ctx, opts) builtPkgs, _, err := BuildPackage(ctx, opts)
// Выполняем сборку пакета // Выполняем сборку пакета
if err != nil { if err != nil {
log.Fatal("Error building package").Err(err).Send() log.Fatal("Error building package").Err(err).Send()
// Логируем и завершаем выполнение при ошибке сборки // Логируем и завершаем выполнение при ошибке сборки
} }
err = opts.Manager.InstallLocal(nil, builtPkgs...) err = opts.Manager.InstallLocal(nil, builtPkgs...)
// Устанавливаем локально собранные пакеты // Устанавливаем локально собранные пакеты
if err != nil { if err != nil {
log.Fatal("Error installing package").Err(err).Send() log.Fatal("Error installing package").Err(err).Send()
// Логируем и завершаем выполнение при ошибке установки // Логируем и завершаем выполнение при ошибке установки
} }
} }
} }

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package distro package distro
@@ -23,10 +24,11 @@ import (
"os" "os"
"strings" "strings"
"plemya-x.ru/alr/internal/shutils/handlers"
"mvdan.cc/sh/v3/expand" "mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"plemya-x.ru/alr/internal/shutils/handlers"
) )
// OSRelease contains information from an os-release file // OSRelease contains information from an os-release file

View File

@@ -1,20 +1,39 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package gen package gen
import ( import (
"strings" "strings"
"text/template" "text/template"
) )
// Определяем переменную funcs типа template.FuncMap, которая будет использоваться для // Определяем переменную funcs типа template.FuncMap, которая будет использоваться для
// предоставления пользовательских функций в шаблонах // предоставления пользовательских функций в шаблонах
var funcs = template.FuncMap{ var funcs = template.FuncMap{
// Функция "tolower" использует strings.ToLower // Функция "tolower" использует strings.ToLower
// для преобразования строки в нижний регистр // для преобразования строки в нижний регистр
"tolower": strings.ToLower, "tolower": strings.ToLower,
// Функция "firstchar" — это лямбда-функция, которая берет строку // Функция "firstchar" — это лямбда-функция, которая берет строку
// и возвращает её первый символ // и возвращает её первый символ
"firstchar": func(s string) string { "firstchar": func(s string) string {
return s[:1] return s[:1]
}, },
} }

View File

@@ -1,98 +1,118 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package gen package gen
import ( import (
_ "embed" // Пакет для встраивания содержимого файлов в бинарники Go, использовав откладку //go:embed _ "embed" // Пакет для встраивания содержимого файлов в бинарники Go, использовав откладку //go:embed
"encoding/json" // Пакет для работы с JSON: декодирование и кодирование "encoding/json" // Пакет для работы с JSON: декодирование и кодирование
"errors" // Пакет для создания и обработки ошибок "errors" // Пакет для создания и обработки ошибок
"fmt" // Пакет для форматированного ввода и вывода "fmt" // Пакет для форматированного ввода и вывода
"io" // Пакет для интерфейсов ввода и вывода "io" // Пакет для интерфейсов ввода и вывода
"net/http" // Пакет для HTTP-клиентов и серверов "net/http" // Пакет для HTTP-клиентов и серверов
"text/template" // Пакет для обработки текстовых шаблонов "text/template" // Пакет для обработки текстовых шаблонов
) )
// Используем директиву //go:embed для встраивания содержимого файла шаблона в строку pipTmpl // Используем директиву //go:embed для встраивания содержимого файла шаблона в строку pipTmpl
// Встраивание файла tmpls/pip.tmpl.sh // Встраивание файла tmpls/pip.tmpl.sh
//
//go:embed tmpls/pip.tmpl.sh //go:embed tmpls/pip.tmpl.sh
var pipTmpl string var pipTmpl string
// PipOptions содержит параметры, которые будут переданы в шаблон // PipOptions содержит параметры, которые будут переданы в шаблон
type PipOptions struct { type PipOptions struct {
Name string // Имя пакета Name string // Имя пакета
Version string // Версия пакета Version string // Версия пакета
Description string // Описание пакета Description string // Описание пакета
} }
// pypiAPIResponse представляет структуру ответа от API PyPI // pypiAPIResponse представляет структуру ответа от API PyPI
type pypiAPIResponse struct { type pypiAPIResponse struct {
Info pypiInfo `json:"info"` // Информация о пакете Info pypiInfo `json:"info"` // Информация о пакете
URLs []pypiURL `json:"urls"` // Список URL-адресов для загрузки пакета URLs []pypiURL `json:"urls"` // Список URL-адресов для загрузки пакета
} }
// Метод SourceURL ищет и возвращает URL исходного distribution для пакета, если он существует // Метод SourceURL ищет и возвращает URL исходного distribution для пакета, если он существует
func (res pypiAPIResponse) SourceURL() (pypiURL, error) { func (res pypiAPIResponse) SourceURL() (pypiURL, error) {
for _, url := range res.URLs { for _, url := range res.URLs {
if url.PackageType == "sdist" { if url.PackageType == "sdist" {
return url, nil return url, nil
} }
} }
return pypiURL{}, errors.New("package doesn't have a source distribution") return pypiURL{}, errors.New("package doesn't have a source distribution")
} }
// pypiInfo содержит основную информацию о пакете, такую как имя, версия и пр. // pypiInfo содержит основную информацию о пакете, такую как имя, версия и пр.
type pypiInfo struct { type pypiInfo struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
Summary string `json:"summary"` Summary string `json:"summary"`
Homepage string `json:"home_page"` Homepage string `json:"home_page"`
License string `json:"license"` License string `json:"license"`
} }
// pypiURL представляет информацию об одном из доступных для загрузки URL // pypiURL представляет информацию об одном из доступных для загрузки URL
type pypiURL struct { type pypiURL struct {
Digests map[string]string `json:"digests"` // Контрольные суммы для файлов Digests map[string]string `json:"digests"` // Контрольные суммы для файлов
Filename string `json:"filename"` // Имя файла Filename string `json:"filename"` // Имя файла
PackageType string `json:"packagetype"` // Тип пакета (например sdist) PackageType string `json:"packagetype"` // Тип пакета (например sdist)
} }
// Функция Pip загружает информацию о пакете из PyPI и использует шаблон для вывода информации // Функция Pip загружает информацию о пакете из PyPI и использует шаблон для вывода информации
func Pip(w io.Writer, opts PipOptions) error { func Pip(w io.Writer, opts PipOptions) error {
// Создаем новый шаблон с добавлением функций из FuncMap // Создаем новый шаблон с добавлением функций из FuncMap
tmpl, err := template.New("pip"). tmpl, err := template.New("pip").
Funcs(funcs). Funcs(funcs).
Parse(pipTmpl) Parse(pipTmpl)
if err != nil { if err != nil {
return err return err
} }
// Формируем URL для запроса к PyPI на основании имени и версии пакета // Формируем URL для запроса к PyPI на основании имени и версии пакета
url := fmt.Sprintf( url := fmt.Sprintf(
"https://pypi.org/pypi/%s/%s/json", "https://pypi.org/pypi/%s/%s/json",
opts.Name, opts.Name,
opts.Version, opts.Version,
) )
// Выполняем HTTP GET запрос к PyPI // Выполняем HTTP GET запрос к PyPI
res, err := http.Get(url) res, err := http.Get(url)
if err != nil { if err != nil {
return err return err
} }
defer res.Body.Close() // Закрываем тело ответа после завершения работы defer res.Body.Close() // Закрываем тело ответа после завершения работы
if res.StatusCode != 200 { if res.StatusCode != 200 {
return fmt.Errorf("pypi: %s", res.Status) return fmt.Errorf("pypi: %s", res.Status)
} }
// Раскодируем ответ JSON от PyPI в структуру pypiAPIResponse // Раскодируем ответ JSON от PyPI в структуру pypiAPIResponse
var resp pypiAPIResponse var resp pypiAPIResponse
err = json.NewDecoder(res.Body).Decode(&resp) err = json.NewDecoder(res.Body).Decode(&resp)
if err != nil { if err != nil {
return err return err
} }
// Если в opts указано описание, используем его вместо описания из PyPI // Если в opts указано описание, используем его вместо описания из PyPI
if opts.Description != "" { if opts.Description != "" {
resp.Info.Summary = opts.Description resp.Info.Summary = opts.Description
} }
// Выполняем шаблон с использованием данных из resp и записываем результат в w // Выполняем шаблон с использованием данных из resp и записываем результат в w
return tmpl.Execute(w, resp) return tmpl.Execute(w, resp)
} }

View File

@@ -1,3 +1,22 @@
# This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
# It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
#
# 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 <http://www.gnu.org/licenses/>.
name='{{.Info.Name | tolower}}' name='{{.Info.Name | tolower}}'
version='{{.Info.Version}}' version='{{.Info.Version}}'
release='1' release='1'

View File

@@ -1,3 +1,22 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package loggerctx package loggerctx
import ( import (

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package manager package manager

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package manager package manager

View File

@@ -1,20 +1,18 @@
/* // ALR - Any Linux Repository
* ALR - Any Linux Repository // Copyright (C) 2025 Евгений Храмов
* Copyright (C) 2024 Евгений Храмов //
* // This program is free software: you can redistribute it and/or modify
* 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
* it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or // (at your option) any later version.
* (at your option) any later version. //
* // This program is distributed in the hope that it will be useful,
* This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details.
* GNU General Public License for more details. //
* // You should have received a copy of the GNU General Public License
* You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package manager package manager
@@ -107,6 +105,7 @@ func (a *APTRpm) UpgradeAll(opts *Opts) error {
} }
return nil return nil
} }
func (y *APTRpm) ListInstalled(opts *Opts) (map[string]string, error) { func (y *APTRpm) ListInstalled(opts *Opts) (map[string]string, error) {
out := map[string]string{} out := map[string]string{}
cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n") cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")

View File

@@ -19,154 +19,154 @@
package manager package manager
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"os/exec" "os/exec"
"strings" "strings"
) )
// DNF представляет менеджер пакетов DNF // DNF представляет менеджер пакетов DNF
type DNF struct { type DNF struct {
rootCmd string // rootCmd хранит команду, используемую для выполнения команд с правами root rootCmd string // rootCmd хранит команду, используемую для выполнения команд с правами root
} }
// Exists проверяет, доступен ли DNF в системе, возвращает true если да // Exists проверяет, доступен ли DNF в системе, возвращает true если да
func (*DNF) Exists() bool { func (*DNF) Exists() bool {
_, err := exec.LookPath("dnf") _, err := exec.LookPath("dnf")
return err == nil return err == nil
} }
// Name возвращает имя менеджера пакетов, в данном случае "dnf" // Name возвращает имя менеджера пакетов, в данном случае "dnf"
func (*DNF) Name() string { func (*DNF) Name() string {
return "dnf" return "dnf"
} }
// Format возвращает формат пакетов "rpm", используемый DNF // Format возвращает формат пакетов "rpm", используемый DNF
func (*DNF) Format() string { func (*DNF) Format() string {
return "rpm" return "rpm"
} }
// SetRootCmd устанавливает команду, используемую для выполнения операций с правами root // SetRootCmd устанавливает команду, используемую для выполнения операций с правами root
func (d *DNF) SetRootCmd(s string) { func (d *DNF) SetRootCmd(s string) {
d.rootCmd = s d.rootCmd = s
} }
// Sync выполняет upgrade всех установленных пакетов, обновляя их до более новых версий // Sync выполняет upgrade всех установленных пакетов, обновляя их до более новых версий
func (d *DNF) Sync(opts *Opts) error { func (d *DNF) Sync(opts *Opts) error {
opts = ensureOpts(opts) // Гарантирует, что opts не равен nil и содержит допустимые значения opts = ensureOpts(opts) // Гарантирует, что opts не равен nil и содержит допустимые значения
cmd := d.getCmd(opts, "dnf", "upgrade") cmd := d.getCmd(opts, "dnf", "upgrade")
setCmdEnv(cmd) // Устанавливает переменные окружения для команды setCmdEnv(cmd) // Устанавливает переменные окружения для команды
err := cmd.Run() // Выполняет команду err := cmd.Run() // Выполняет команду
if err != nil { if err != nil {
return fmt.Errorf("dnf: sync: %w", err) return fmt.Errorf("dnf: sync: %w", err)
} }
return nil return nil
} }
// Install устанавливает указанные пакеты с помощью DNF // Install устанавливает указанные пакеты с помощью DNF
func (d *DNF) Install(opts *Opts, pkgs ...string) error { func (d *DNF) Install(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts) opts = ensureOpts(opts)
cmd := d.getCmd(opts, "dnf", "install", "--allowerasing") cmd := d.getCmd(opts, "dnf", "install", "--allowerasing")
cmd.Args = append(cmd.Args, pkgs...) // Добавляем названия пакетов к команде cmd.Args = append(cmd.Args, pkgs...) // Добавляем названия пакетов к команде
setCmdEnv(cmd) setCmdEnv(cmd)
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("dnf: install: %w", err) return fmt.Errorf("dnf: install: %w", err)
} }
return nil return nil
} }
// InstallLocal расширяет метод Install для установки пакетов, расположенных локально // InstallLocal расширяет метод Install для установки пакетов, расположенных локально
func (d *DNF) InstallLocal(opts *Opts, pkgs ...string) error { func (d *DNF) InstallLocal(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts) opts = ensureOpts(opts)
return d.Install(opts, pkgs...) return d.Install(opts, pkgs...)
} }
// Remove удаляет указанные пакеты с помощью DNF // Remove удаляет указанные пакеты с помощью DNF
func (d *DNF) Remove(opts *Opts, pkgs ...string) error { func (d *DNF) Remove(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts) opts = ensureOpts(opts)
cmd := d.getCmd(opts, "dnf", "remove") cmd := d.getCmd(opts, "dnf", "remove")
cmd.Args = append(cmd.Args, pkgs...) cmd.Args = append(cmd.Args, pkgs...)
setCmdEnv(cmd) setCmdEnv(cmd)
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("dnf: remove: %w", err) return fmt.Errorf("dnf: remove: %w", err)
} }
return nil return nil
} }
// Upgrade обновляет указанные пакеты до более новых версий // Upgrade обновляет указанные пакеты до более новых версий
func (d *DNF) Upgrade(opts *Opts, pkgs ...string) error { func (d *DNF) Upgrade(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts) opts = ensureOpts(opts)
cmd := d.getCmd(opts, "dnf", "upgrade") cmd := d.getCmd(opts, "dnf", "upgrade")
cmd.Args = append(cmd.Args, pkgs...) cmd.Args = append(cmd.Args, pkgs...)
setCmdEnv(cmd) setCmdEnv(cmd)
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("dnf: upgrade: %w", err) return fmt.Errorf("dnf: upgrade: %w", err)
} }
return nil return nil
} }
// UpgradeAll обновляет все установленные пакеты // UpgradeAll обновляет все установленные пакеты
func (d *DNF) UpgradeAll(opts *Opts) error { func (d *DNF) UpgradeAll(opts *Opts) error {
opts = ensureOpts(opts) opts = ensureOpts(opts)
cmd := d.getCmd(opts, "dnf", "upgrade") cmd := d.getCmd(opts, "dnf", "upgrade")
setCmdEnv(cmd) setCmdEnv(cmd)
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("dnf: upgradeall: %w", err) return fmt.Errorf("dnf: upgradeall: %w", err)
} }
return nil return nil
} }
// ListInstalled возвращает список установленных пакетов и их версий // ListInstalled возвращает список установленных пакетов и их версий
func (d *DNF) ListInstalled(opts *Opts) (map[string]string, error) { func (d *DNF) ListInstalled(opts *Opts) (map[string]string, error) {
out := map[string]string{} out := map[string]string{}
cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n") cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
stdout, err := cmd.StdoutPipe() stdout, err := cmd.StdoutPipe()
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = cmd.Start() err = cmd.Start()
if err != nil { if err != nil {
return nil, err return nil, err
} }
scanner := bufio.NewScanner(stdout) scanner := bufio.NewScanner(stdout)
for scanner.Scan() { for scanner.Scan() {
name, version, ok := strings.Cut(scanner.Text(), "\u200b") name, version, ok := strings.Cut(scanner.Text(), "\u200b")
if !ok { if !ok {
continue continue
} }
version = strings.TrimPrefix(version, "0:") version = strings.TrimPrefix(version, "0:")
out[name] = version out[name] = version
} }
err = scanner.Err() err = scanner.Err()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
// getCmd создает и возвращает команду exec.Cmd для менеджера пакетов DNF // getCmd создает и возвращает команду exec.Cmd для менеджера пакетов DNF
func (d *DNF) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd { func (d *DNF) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
var cmd *exec.Cmd var cmd *exec.Cmd
if opts.AsRoot { if opts.AsRoot {
cmd = exec.Command(getRootCmd(d.rootCmd), mgrCmd) cmd = exec.Command(getRootCmd(d.rootCmd), mgrCmd)
cmd.Args = append(cmd.Args, opts.Args...) cmd.Args = append(cmd.Args, opts.Args...)
cmd.Args = append(cmd.Args, args...) cmd.Args = append(cmd.Args, args...)
} else { } else {
cmd = exec.Command(mgrCmd, args...) cmd = exec.Command(mgrCmd, args...)
} }
if opts.NoConfirm { if opts.NoConfirm {
cmd.Args = append(cmd.Args, "-y") // Добавляет параметр автоматического подтверждения (-y) cmd.Args = append(cmd.Args, "-y") // Добавляет параметр автоматического подтверждения (-y)
} }
return cmd return cmd
} }

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package manager package manager

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package manager package manager

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package manager package manager

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package manager package manager

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repos package repos
@@ -24,10 +25,7 @@ import (
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
) )
// FindPkgs looks for packages matching the inputs inside the database. func (rs *Repos) FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) {
// It returns a map that maps the package name input to any packages found for it.
// It also returns a slice that contains the names of all packages that were not found.
func FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) {
found := map[string][]db.Package{} found := map[string][]db.Package{}
notFound := []string(nil) notFound := []string(nil)
@@ -36,7 +34,7 @@ func FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []st
continue continue
} }
result, err := db.GetPkgs(ctx, "json_array_contains(provides, ?)", pkgName) result, err := rs.db.GetPkgs(ctx, "json_array_contains(provides, ?)", pkgName)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -55,7 +53,7 @@ func FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []st
result.Close() result.Close()
if added == 0 { if added == 0 {
result, err := db.GetPkgs(ctx, "name LIKE ?", pkgName) result, err := rs.db.GetPkgs(ctx, "name LIKE ?", pkgName)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -1,25 +1,25 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repos_test package repos_test
import ( import (
"context"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
@@ -30,18 +30,15 @@ import (
) )
func TestFindPkgs(t *testing.T) { func TestFindPkgs(t *testing.T) {
_, err := db.Open(":memory:") e := prepare(t)
if err != nil { defer cleanup(t, e)
t.Fatalf("Expected no error, got %s", err)
}
defer db.Close()
setCfgDirs(t) rs := repos.New(
defer removeCacheDir(t) e.Cfg,
e.Db,
)
ctx := context.Background() err := rs.Pull(e.Ctx, []types.Repo{
err = repos.Pull(ctx, []types.Repo{
{ {
Name: "default", Name: "default",
URL: "https://gitea.plemya-x.ru/xpamych/xpamych-alr-repo.git", URL: "https://gitea.plemya-x.ru/xpamych/xpamych-alr-repo.git",
@@ -51,7 +48,10 @@ func TestFindPkgs(t *testing.T) {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
found, notFound, err := repos.FindPkgs([]string{"itd", "nonexistentpackage1", "nonexistentpackage2"}) found, notFound, err := rs.FindPkgs(
e.Ctx,
[]string{"alr", "nonexistentpackage1", "nonexistentpackage2"},
)
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
@@ -64,33 +64,32 @@ func TestFindPkgs(t *testing.T) {
t.Errorf("Expected 1 package found, got %d", len(found)) t.Errorf("Expected 1 package found, got %d", len(found))
} }
itdPkgs, ok := found["itd"] alrPkgs, ok := found["alr"]
if !ok { if !ok {
t.Fatalf("Expected 'itd' packages to be found") t.Fatalf("Expected 'alr' packages to be found")
} }
if len(itdPkgs) < 2 { if len(alrPkgs) < 2 {
t.Errorf("Expected two 'itd' packages to be found") t.Errorf("Expected two 'alr' packages to be found")
} }
for i, pkg := range itdPkgs { for i, pkg := range alrPkgs {
if !strings.HasPrefix(pkg.Name, "itd") { if !strings.HasPrefix(pkg.Name, "alr") {
t.Errorf("Expected package name of all found packages to start with 'itd', got %s on element %d", pkg.Name, i) t.Errorf("Expected package name of all found packages to start with 'alr', got %s on element %d", pkg.Name, i)
} }
} }
} }
func TestFindPkgsEmpty(t *testing.T) { func TestFindPkgsEmpty(t *testing.T) {
_, err := db.Open(":memory:") e := prepare(t)
if err != nil { defer cleanup(t, e)
t.Fatalf("Expected no error, got %s", err)
}
defer db.Close()
setCfgDirs(t) rs := repos.New(
defer removeCacheDir(t) e.Cfg,
e.Db,
)
err = db.InsertPackage(db.Package{ err := e.Db.InsertPackage(e.Ctx, db.Package{
Name: "test1", Name: "test1",
Repository: "default", Repository: "default",
Version: "0.0.1", Version: "0.0.1",
@@ -105,7 +104,7 @@ func TestFindPkgsEmpty(t *testing.T) {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
err = db.InsertPackage(db.Package{ err = e.Db.InsertPackage(e.Ctx, db.Package{
Name: "test2", Name: "test2",
Repository: "default", Repository: "default",
Version: "0.0.1", Version: "0.0.1",
@@ -120,7 +119,7 @@ func TestFindPkgsEmpty(t *testing.T) {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
found, notFound, err := repos.FindPkgs([]string{"test", ""}) found, notFound, err := rs.FindPkgs(e.Ctx, []string{"test", ""})
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }

View File

@@ -1,61 +1,70 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repos package repos
import ( import (
"context" "context"
"errors" "errors"
"io"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"strings" "strings"
"github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/osfs" "github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/format/diff"
"github.com/pelletier/go-toml/v2" "github.com/pelletier/go-toml/v2"
"go.elara.ws/vercmp" "go.elara.ws/vercmp"
"plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/shutils/decoder"
"plemya-x.ru/alr/internal/shutils/handlers"
"plemya-x.ru/alr/internal/types"
"plemya-x.ru/alr/pkg/distro"
"plemya-x.ru/alr/pkg/loggerctx"
"mvdan.cc/sh/v3/expand" "mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp" "mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax" "mvdan.cc/sh/v3/syntax"
"plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/shutils/handlers"
"plemya-x.ru/alr/internal/types"
"plemya-x.ru/alr/pkg/loggerctx"
) )
type actionType uint8
const (
actionDelete actionType = iota
actionUpdate
)
type action struct {
Type actionType
File string
}
// Pull pulls the provided repositories. If a repo doesn't exist, it will be cloned // Pull pulls the provided repositories. If a repo doesn't exist, it will be cloned
// and its packages will be written to the DB. If it does exist, it will be pulled. // and its packages will be written to the DB. If it does exist, it will be pulled.
// In this case, only changed packages will be processed if possible. // In this case, only changed packages will be processed if possible.
// If repos is set to nil, the repos in the ALR config will be used. // If repos is set to nil, the repos in the ALR config will be used.
func Pull(ctx context.Context, repos []types.Repo) error { func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error {
log := loggerctx.From(ctx) log := loggerctx.From(ctx)
if repos == nil { if repos == nil {
repos = config.Config(ctx).Repos repos = rs.cfg.Repos(ctx)
} }
for _, repo := range repos { for _, repo := range repos {
@@ -95,7 +104,7 @@ func Pull(ctx context.Context, repos []types.Repo) error {
repoFS = w.Filesystem repoFS = w.Filesystem
// Make sure the DB is created even if the repo is up to date // Make sure the DB is created even if the repo is up to date
if !errors.Is(err, git.NoErrAlreadyUpToDate) || db.IsEmpty(ctx) { if !errors.Is(err, git.NoErrAlreadyUpToDate) || rs.db.IsEmpty(ctx) {
new, err := r.Head() new, err := r.Head()
if err != nil { if err != nil {
return err return err
@@ -104,13 +113,13 @@ func Pull(ctx context.Context, repos []types.Repo) error {
// If the DB was not present at startup, that means it's // If the DB was not present at startup, that means it's
// empty. In this case, we need to update the DB fully // empty. In this case, we need to update the DB fully
// rather than just incrementally. // rather than just incrementally.
if db.IsEmpty(ctx) { if rs.db.IsEmpty(ctx) {
err = processRepoFull(ctx, repo, repoDir) err = rs.processRepoFull(ctx, repo, repoDir)
if err != nil { if err != nil {
return err return err
} }
} else { } else {
err = processRepoChanges(ctx, repo, r, w, old, new) err = rs.processRepoChanges(ctx, repo, r, w, old, new)
if err != nil { if err != nil {
return err return err
} }
@@ -135,7 +144,7 @@ func Pull(ctx context.Context, repos []types.Repo) error {
return err return err
} }
err = processRepoFull(ctx, repo, repoDir) err = rs.processRepoFull(ctx, repo, repoDir)
if err != nil { if err != nil {
return err return err
} }
@@ -169,19 +178,7 @@ func Pull(ctx context.Context, repos []types.Repo) error {
return nil return nil
} }
type actionType uint8 func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository, w *git.Worktree, old, new *plumbing.Reference) error {
const (
actionDelete actionType = iota
actionUpdate
)
type action struct {
Type actionType
File string
}
func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository, w *git.Worktree, old, new *plumbing.Reference) error {
oldCommit, err := r.CommitObject(old.Hash()) oldCommit, err := r.CommitObject(old.Hash())
if err != nil { if err != nil {
return err return err
@@ -275,7 +272,7 @@ func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository,
return err return err
} }
err = db.DeletePkgs(ctx, "name = ? AND repository = ?", pkg.Name, repo.Name) err = rs.db.DeletePkgs(ctx, "name = ? AND repository = ?", pkg.Name, repo.Name)
if err != nil { if err != nil {
return err return err
} }
@@ -310,7 +307,7 @@ func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository,
resolveOverrides(runner, &pkg) resolveOverrides(runner, &pkg)
err = db.InsertPackage(ctx, pkg) err = rs.db.InsertPackage(ctx, pkg)
if err != nil { if err != nil {
return err return err
} }
@@ -320,23 +317,7 @@ func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository,
return nil return nil
} }
// isValid makes sure the path of the file being updated is valid. func (rs *Repos) processRepoFull(ctx context.Context, repo types.Repo, repoDir string) error {
// It checks to make sure the file is not within a nested directory
// and that it is called alr.sh.
func isValid(from, to diff.File) bool {
var path string
if from != nil {
path = from.Path()
}
if to != nil {
path = to.Path()
}
match, _ := filepath.Match("*/*.sh", path)
return match
}
func processRepoFull(ctx context.Context, repo types.Repo, repoDir string) error {
glob := filepath.Join(repoDir, "/*/alr.sh") glob := filepath.Join(repoDir, "/*/alr.sh")
matches, err := filepath.Glob(glob) matches, err := filepath.Glob(glob)
if err != nil { if err != nil {
@@ -380,7 +361,7 @@ func processRepoFull(ctx context.Context, repo types.Repo, repoDir string) error
resolveOverrides(runner, &pkg) resolveOverrides(runner, &pkg)
err = db.InsertPackage(ctx, pkg) err = rs.db.InsertPackage(ctx, pkg)
if err != nil { if err != nil {
return err return err
} }
@@ -388,54 +369,3 @@ func processRepoFull(ctx context.Context, repo types.Repo, repoDir string) error
return nil return nil
} }
func parseScript(ctx context.Context, parser *syntax.Parser, runner *interp.Runner, r io.ReadCloser, pkg *db.Package) error {
defer r.Close()
fl, err := parser.Parse(r, "alr.sh")
if err != nil {
return err
}
runner.Reset()
err = runner.Run(ctx, fl)
if err != nil {
return err
}
d := decoder.New(&distro.OSRelease{}, runner)
d.Overrides = false
d.LikeDistros = false
return d.DecodeVars(pkg)
}
var overridable = map[string]string{
"deps": "Depends",
"build_deps": "BuildDepends",
"desc": "Description",
"homepage": "Homepage",
"maintainer": "Maintainer",
}
func resolveOverrides(runner *interp.Runner, pkg *db.Package) {
pkgVal := reflect.ValueOf(pkg).Elem()
for name, val := range runner.Vars {
for prefix, field := range overridable {
if strings.HasPrefix(name, prefix) {
override := strings.TrimPrefix(name, prefix)
override = strings.TrimPrefix(override, "_")
field := pkgVal.FieldByName(field)
varVal := field.FieldByName("Val")
varType := varVal.Type()
switch varType.Elem().String() {
case "[]string":
varVal.SetMapIndex(reflect.ValueOf(override), reflect.ValueOf(val.List))
case "string":
varVal.SetMapIndex(reflect.ValueOf(override), reflect.ValueOf(val.Str))
}
break
}
}
}
}

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* alr - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repos_test package repos_test
@@ -26,69 +27,104 @@ import (
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
database "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/types" "plemya-x.ru/alr/internal/types"
"plemya-x.ru/alr/pkg/repos" "plemya-x.ru/alr/pkg/repos"
) )
func setCfgDirs(t *testing.T) { type TestEnv struct {
t.Helper() Ctx context.Context
Cfg *TestALRConfig
paths := config.GetPaths() Db *db.Database
var err error
paths.CacheDir, err = os.MkdirTemp("/tmp", "alr-pull-test.*")
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
paths.RepoDir = filepath.Join(paths.CacheDir, "repo")
paths.PkgsDir = filepath.Join(paths.CacheDir, "pkgs")
err = os.MkdirAll(paths.RepoDir, 0o755)
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
err = os.MkdirAll(paths.PkgsDir, 0o755)
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
paths.DBPath = filepath.Join(paths.CacheDir, "db")
} }
func removeCacheDir(t *testing.T) { type TestALRConfig struct {
t.Helper() CacheDir string
RepoDir string
PkgsDir string
}
err := os.RemoveAll(config.GetPaths().CacheDir) func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
if err != nil { return &config.Paths{
t.Fatalf("Expected no error, got %s", err) DBPath: ":memory:",
CacheDir: c.CacheDir,
RepoDir: c.RepoDir,
PkgsDir: c.PkgsDir,
} }
} }
func TestPull(t *testing.T) { func (c *TestALRConfig) Repos(ctx context.Context) []types.Repo {
_, err := db.Open(":memory:") return []types.Repo{}
}
func prepare(t *testing.T) *TestEnv {
t.Helper()
cacheDir, err := os.MkdirTemp("/tmp", "alr-pull-test.*")
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
defer db.Close()
setCfgDirs(t) repoDir := filepath.Join(cacheDir, "repo")
defer removeCacheDir(t) err = os.MkdirAll(repoDir, 0o755)
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
pkgsDir := filepath.Join(cacheDir, "pkgs")
err = os.MkdirAll(pkgsDir, 0o755)
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
cfg := &TestALRConfig{
CacheDir: cacheDir,
RepoDir: repoDir,
PkgsDir: pkgsDir,
}
ctx := context.Background() ctx := context.Background()
err = repos.Pull(ctx, []types.Repo{ db := database.New(cfg)
db.Init(ctx)
return &TestEnv{
Cfg: cfg,
Db: db,
Ctx: ctx,
}
}
func cleanup(t *testing.T, e *TestEnv) {
t.Helper()
err := os.RemoveAll(e.Cfg.CacheDir)
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
e.Db.Close()
}
func TestPull(t *testing.T) {
e := prepare(t)
defer cleanup(t, e)
rs := repos.New(
e.Cfg,
e.Db,
)
err := rs.Pull(e.Ctx, []types.Repo{
{ {
Name: "default", Name: "default",
URL: "https://gitea.plemya-x.ru/xpamych/ALR.git", URL: "https://gitea.plemya-x.ru/Plemya-x/xpamych-alr-repo.git",
}, },
}) })
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
result, err := db.GetPkgs("name LIKE 'itd%'") result, err := e.Db.GetPkgs(e.Ctx, "true")
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %s", err) t.Fatalf("Expected no error, got %s", err)
} }
@@ -103,7 +139,7 @@ func TestPull(t *testing.T) {
pkgAmt++ pkgAmt++
} }
if pkgAmt < 2 { if pkgAmt == 0 {
t.Errorf("Expected 2 packages to match, got %d", pkgAmt) t.Errorf("Expected at least 1 matching package, but got %d", pkgAmt)
} }
} }

45
pkg/repos/repos.go Normal file
View File

@@ -0,0 +1,45 @@
// 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 <http://www.gnu.org/licenses/>.
package repos
import (
"context"
"plemya-x.ru/alr/internal/config"
database "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/types"
)
type Config interface {
GetPaths(ctx context.Context) *config.Paths
Repos(ctx context.Context) []types.Repo
}
type Repos struct {
cfg Config
db *database.Database
}
func New(
cfg Config,
db *database.Database,
) *Repos {
return &Repos{
cfg,
db,
}
}

70
pkg/repos/repos_legacy.go Normal file
View File

@@ -0,0 +1,70 @@
// 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 <http://www.gnu.org/licenses/>.
package repos
import (
"context"
"sync"
"plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db"
database "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/types"
)
// Pull pulls the provided repositories. If a repo doesn't exist, it will be cloned
// and its packages will be written to the DB. If it does exist, it will be pulled.
// In this case, only changed packages will be processed if possible.
// If repos is set to nil, the repos in the ALR config will be used.
//
// Deprecated: use struct method
func Pull(ctx context.Context, repos []types.Repo) error {
return GetInstance(ctx).Pull(ctx, repos)
}
// FindPkgs looks for packages matching the inputs inside the database.
// It returns a map that maps the package name input to any packages found for it.
// It also returns a slice that contains the names of all packages that were not found.
//
// Deprecated: use struct method
func FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.Package, []string, error) {
return GetInstance(ctx).FindPkgs(ctx, pkgs)
}
// =======================
// FOR LEGACY ONLY
// =======================
var (
reposInstance *Repos
alrConfigOnce sync.Once
)
// Deprecated: For legacy only
func GetInstance(ctx context.Context) *Repos {
alrConfigOnce.Do(func() {
cfg := config.GetInstance(ctx)
db := database.GetInstance(ctx)
reposInstance = New(
cfg,
db,
)
})
return reposInstance
}

100
pkg/repos/utils.go Normal file
View File

@@ -0,0 +1,100 @@
// 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 <http://www.gnu.org/licenses/>.
package repos
import (
"context"
"io"
"path/filepath"
"reflect"
"strings"
"github.com/go-git/go-git/v5/plumbing/format/diff"
"mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/syntax"
"plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/shutils/decoder"
"plemya-x.ru/alr/pkg/distro"
)
// isValid makes sure the path of the file being updated is valid.
// It checks to make sure the file is not within a nested directory
// and that it is called alr.sh.
func isValid(from, to diff.File) bool {
var path string
if from != nil {
path = from.Path()
}
if to != nil {
path = to.Path()
}
match, _ := filepath.Match("*/*.sh", path)
return match
}
func parseScript(ctx context.Context, parser *syntax.Parser, runner *interp.Runner, r io.ReadCloser, pkg *db.Package) error {
defer r.Close()
fl, err := parser.Parse(r, "alr.sh")
if err != nil {
return err
}
runner.Reset()
err = runner.Run(ctx, fl)
if err != nil {
return err
}
d := decoder.New(&distro.OSRelease{}, runner)
d.Overrides = false
d.LikeDistros = false
return d.DecodeVars(pkg)
}
var overridable = map[string]string{
"deps": "Depends",
"build_deps": "BuildDepends",
"desc": "Description",
"homepage": "Homepage",
"maintainer": "Maintainer",
}
func resolveOverrides(runner *interp.Runner, pkg *db.Package) {
pkgVal := reflect.ValueOf(pkg).Elem()
for name, val := range runner.Vars {
for prefix, field := range overridable {
if strings.HasPrefix(name, prefix) {
override := strings.TrimPrefix(name, prefix)
override = strings.TrimPrefix(override, "_")
field := pkgVal.FieldByName(field)
varVal := field.FieldByName("Val")
varType := varVal.Type()
switch varType.Elem().String() {
case "[]string":
varVal.SetMapIndex(reflect.ValueOf(override), reflect.ValueOf(val.List))
case "string":
varVal.SetMapIndex(reflect.ValueOf(override), reflect.ValueOf(val.Str))
}
break
}
}
}
}

View File

@@ -1,3 +1,22 @@
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
//
// 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 <http://www.gnu.org/licenses/>.
package search package search
import ( import (

38
repo.go
View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -24,12 +25,13 @@ import (
"github.com/pelletier/go-toml/v2" "github.com/pelletier/go-toml/v2"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/slices"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/types" "plemya-x.ru/alr/internal/types"
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
"plemya-x.ru/alr/pkg/repos" "plemya-x.ru/alr/pkg/repos"
"golang.org/x/exp/slices"
) )
var addrepoCmd = &cli.Command{ var addrepoCmd = &cli.Command{

View File

@@ -1,3 +1,22 @@
# This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
# It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
#
# 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 <http://www.gnu.org/licenses/>.
info() { info() {
echo $'\x1b[32m[ИНФО]\x1b[0m' $@ echo $'\x1b[32m[ИНФО]\x1b[0m' $@
} }

View File

@@ -1,20 +1,21 @@
/* // This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
* ALR - Any Linux Repository // It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
* Copyright (C) 2024 Евгений Храмов //
* // ALR - Any Linux Repository
* This program is free software: you can redistribute it and/or modify // Copyright (C) 2025 Евгений Храмов
* it under the terms of the GNU General Public License as published by //
* the Free Software Foundation, either version 3 of the License, or // This program is free software: you can redistribute it and/or modify
* (at your option) any later version. // it under the terms of the GNU General Public License as published by
* // the Free Software Foundation, either version 3 of the License, or
* This program is distributed in the hope that it will be useful, // (at your option) any later version.
* but WITHOUT ANY WARRANTY; without even the implied warranty of //
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // This program is distributed in the hope that it will be useful,
* GNU General Public License for more details. // but WITHOUT ANY WARRANTY; without even the implied warranty of
* // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* You should have received a copy of the GNU General Public License // GNU General Public License for more details.
* along with this program. If not, see <http://www.gnu.org/licenses/>. //
*/ // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
@@ -23,6 +24,10 @@ import (
"fmt" "fmt"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"go.elara.ws/vercmp"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"plemya-x.ru/alr/internal/config" "plemya-x.ru/alr/internal/config"
"plemya-x.ru/alr/internal/db" "plemya-x.ru/alr/internal/db"
"plemya-x.ru/alr/internal/types" "plemya-x.ru/alr/internal/types"
@@ -31,9 +36,6 @@ import (
"plemya-x.ru/alr/pkg/loggerctx" "plemya-x.ru/alr/pkg/loggerctx"
"plemya-x.ru/alr/pkg/manager" "plemya-x.ru/alr/pkg/manager"
"plemya-x.ru/alr/pkg/repos" "plemya-x.ru/alr/pkg/repos"
"go.elara.ws/vercmp"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
) )
var upgradeCmd = &cli.Command{ var upgradeCmd = &cli.Command{