Compare commits
1 Commits
v0.0.24
...
be7323abbc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be7323abbc |
@@ -1,57 +0,0 @@
|
|||||||
# ALR - Any Linux Repository
|
|
||||||
# Copyright (C) 2025 The ALR Authors
|
|
||||||
#
|
|
||||||
# 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: E2E
|
|
||||||
|
|
||||||
# on:
|
|
||||||
# push:
|
|
||||||
# branches: [ main ]
|
|
||||||
# pull_request:
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
tests:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
container:
|
|
||||||
image: altlinux.space/maks1ms/actions-container-runner:latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: https://github.com/actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: https://github.com/actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.24'
|
|
||||||
cache: false
|
|
||||||
|
|
||||||
# - name: Cache Podman images
|
|
||||||
# uses: actions/cache@v4
|
|
||||||
# with:
|
|
||||||
# path: |
|
|
||||||
# ~/.local/share/containers/storage
|
|
||||||
# /var/lib/containers/storage
|
|
||||||
# key: ${{ runner.os }}-primes
|
|
||||||
|
|
||||||
- name: Run E2E tests
|
|
||||||
env:
|
|
||||||
IGNORE_ROOT_CHECK: 1
|
|
||||||
run: |
|
|
||||||
make e2e-test
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
# ALR - Any Linux Repository
|
|
||||||
# Copyright (C) 2025 The ALR Authors
|
|
||||||
#
|
|
||||||
# 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: Pre-commit
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
pre-commit:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: https://github.com/actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: https://github.com/actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.24'
|
|
||||||
|
|
||||||
- name: Set up Python for pre-commit
|
|
||||||
uses: https://github.com/actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.12'
|
|
||||||
|
|
||||||
- name: Install deps
|
|
||||||
run: apt-get update && apt-get install -y gettext bc
|
|
||||||
|
|
||||||
- run: pip install pre-commit
|
|
||||||
- run: pre-commit install
|
|
||||||
- run: pre-commit run --all-files
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
# ALR - Any Linux Repository
|
|
||||||
# Copyright (C) 2025 The ALR Authors
|
|
||||||
#
|
|
||||||
# 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: Create Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
changelog:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout this repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.24'
|
|
||||||
|
|
||||||
- name: Get Changes between Tags
|
|
||||||
id: changes
|
|
||||||
uses: simbo/changes-between-tags-action@v1
|
|
||||||
|
|
||||||
- name: Set version
|
|
||||||
run: |
|
|
||||||
version=$(echo "${GITHUB_REF##*/}" | sed 's/^v//')
|
|
||||||
echo "Version - $version"
|
|
||||||
echo "VERSION=$version" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Prepare for install
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
|
|
||||||
- name: Build alr
|
|
||||||
env:
|
|
||||||
IGNORE_ROOT_CHECK: 1
|
|
||||||
run: |
|
|
||||||
make build
|
|
||||||
|
|
||||||
- name: Create tar.gz
|
|
||||||
run: |
|
|
||||||
mkdir -p ./out/completion
|
|
||||||
cp alr ./out
|
|
||||||
cp scripts/completion/bash ./out/completion/alr
|
|
||||||
cp scripts/completion/zsh ./out/completion/_alr
|
|
||||||
|
|
||||||
( cd out && tar -czvf ../alr-${{ env.VERSION }}-linux-x86_64.tar.gz * )
|
|
||||||
|
|
||||||
- name: Release
|
|
||||||
uses: akkuman/gitea-release-action@v1
|
|
||||||
with:
|
|
||||||
body: ${{ steps.changes.outputs.changes }}
|
|
||||||
files: |-
|
|
||||||
alr-${{ env.VERSION }}-linux-x86_64.tar.gz
|
|
||||||
|
|
||||||
- name: Checkout alr-default repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: Plemya-x/alr-default
|
|
||||||
token: ${{ secrets.GITEAPUBLIC }}
|
|
||||||
path: alr-default
|
|
||||||
|
|
||||||
- name: Calculate checksum
|
|
||||||
run: |
|
|
||||||
# Вычисляем SHA256 контрольную сумму архива
|
|
||||||
CHECKSUM=$(sha256sum alr-${{ env.VERSION }}-linux-x86_64.tar.gz | awk '{print $1}')
|
|
||||||
echo "Archive checksum: $CHECKSUM"
|
|
||||||
echo "CHECKSUM=$CHECKSUM" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Update version and checksum in alr-bin
|
|
||||||
run: |
|
|
||||||
# Обновляем версию
|
|
||||||
sed -i "s/version='[0-9]\+\.[0-9]\+\.[0-9]\+'/version='${{ env.VERSION }}'/g" alr-default/alr-bin/alr.sh
|
|
||||||
sed -i "s/release='[0-9]\+'/release='1'/g" alr-default/alr-bin/alr.sh
|
|
||||||
|
|
||||||
# Обновляем контрольную сумму
|
|
||||||
sed -i "s/checksums=('[^']*')/checksums=('${{ env.CHECKSUM }}')/g" alr-default/alr-bin/alr.sh
|
|
||||||
|
|
||||||
- name: Commit and push changes to alr-default
|
|
||||||
run: |
|
|
||||||
cd alr-default
|
|
||||||
git config user.name "gitea"
|
|
||||||
git config user.email "admin@plemya-x.ru"
|
|
||||||
git add alr-bin/alr.sh
|
|
||||||
git commit -m "Обновление alr-bin до версии ${{ env.VERSION }}"
|
|
||||||
git push
|
|
||||||
|
|
||||||
- name: Install alr
|
|
||||||
env:
|
|
||||||
CREATE_SYSTEM_RESOURCES: 0
|
|
||||||
run: |
|
|
||||||
make install
|
|
||||||
|
|
||||||
- name: Prepare directories for ALR
|
|
||||||
run: |
|
|
||||||
# Создаём необходимые директории для работы alr build
|
|
||||||
mkdir -p /tmp/alr/dl /tmp/alr/pkgs /var/cache/alr
|
|
||||||
chmod -R 777 /tmp/alr
|
|
||||||
chmod -R 755 /var/cache/alr
|
|
||||||
|
|
||||||
- name: Build packages
|
|
||||||
run: |
|
|
||||||
SCRIPT_PATH=alr-default/alr-bin/alr.sh
|
|
||||||
ALR_DISTRO=altlinux ALR_PKG_FORMAT=rpm alr build -s "$SCRIPT_PATH"
|
|
||||||
ALR_PKG_FORMAT=rpm alr build -s "$SCRIPT_PATH"
|
|
||||||
ALR_PKG_FORMAT=deb alr build -s "$SCRIPT_PATH"
|
|
||||||
ALR_PKG_FORMAT=archlinux alr build -s "$SCRIPT_PATH"
|
|
||||||
|
|
||||||
- name: Upload assets
|
|
||||||
uses: akkuman/gitea-release-action@v1
|
|
||||||
with:
|
|
||||||
body: ${{ steps.changes.outputs.changes }}
|
|
||||||
files: |-
|
|
||||||
alr-bin*.deb
|
|
||||||
alr-bin*.rpm
|
|
||||||
alr-bin*.pkg.tar.zst
|
|
||||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -3,12 +3,8 @@
|
|||||||
/cmd/alr-api-server/alr-api-server
|
/cmd/alr-api-server/alr-api-server
|
||||||
/dist/
|
/dist/
|
||||||
/internal/config/version.txt
|
/internal/config/version.txt
|
||||||
.fleet/
|
.fleet
|
||||||
.idea/
|
.idea
|
||||||
.gigaide/
|
.gigaide
|
||||||
|
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
e2e-tests/alr
|
|
||||||
CLAUDE.md
|
|
||||||
commit_msg.txt
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# ALR - Any Linux Repository
|
# ALR - Any Linux Repository
|
||||||
# Copyright (C) 2025 The ALR Authors
|
# 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
|
||||||
@@ -36,14 +36,11 @@ linters:
|
|||||||
- unused
|
- unused
|
||||||
- errcheck
|
- errcheck
|
||||||
- typecheck
|
- typecheck
|
||||||
- wrapcheck
|
# - forbidigo
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
fix: true
|
fix: true
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
- linters:
|
|
||||||
- wrapcheck
|
|
||||||
path-except: "internal/repos/find.go"
|
|
||||||
- path: _test\.go
|
- path: _test\.go
|
||||||
linters:
|
linters:
|
||||||
- errcheck
|
- errcheck
|
||||||
|
|||||||
118
.goreleaser.yaml
Normal file
118
.goreleaser.yaml
Normal file
@@ -0,0 +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/>.
|
||||||
|
|
||||||
|
before:
|
||||||
|
hooks:
|
||||||
|
- go mod tidy
|
||||||
|
builds:
|
||||||
|
- id: alr
|
||||||
|
env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
|
binary: alr
|
||||||
|
ldflags:
|
||||||
|
- -X gitea.plemya-x.ru/xpamych/ALR/src/branch/master/internal/config.Version={{.Version}}
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
goarch:
|
||||||
|
- amd64
|
||||||
|
- 386
|
||||||
|
- arm64
|
||||||
|
- arm
|
||||||
|
- riscv64
|
||||||
|
archives:
|
||||||
|
- name_template: >-
|
||||||
|
{{- .ProjectName}}-
|
||||||
|
{{- .Version}}-
|
||||||
|
{{- .Os}}-
|
||||||
|
{{- if .Arch | eq "amd64"}}x86_64
|
||||||
|
{{- else if .Arch | eq "386"}}i386
|
||||||
|
{{- else if .Arch | eq "arm64"}}aarch64
|
||||||
|
{{- else }}{{ .Arch }}{{ end -}}
|
||||||
|
files:
|
||||||
|
- scripts/completion/*
|
||||||
|
nfpms:
|
||||||
|
- id: alr
|
||||||
|
package_name: linux-user-repository
|
||||||
|
file_name_template: >-
|
||||||
|
{{- .PackageName}}-
|
||||||
|
{{- .Version}}-
|
||||||
|
{{- .Os}}-
|
||||||
|
{{- if .Arch | eq "amd64"}}x86_64
|
||||||
|
{{- else if .Arch | eq "386"}}i386
|
||||||
|
{{- else if .Arch | eq "arm64"}}aarch64
|
||||||
|
{{- else }}{{ .Arch }}{{ end -}}
|
||||||
|
description: "Any Linux Repository"
|
||||||
|
homepage: 'https://gitea.plemya-x.ru/xpamych/ALR'
|
||||||
|
maintainer: 'Евгений Храмов <xpamych@yandex.ru>'
|
||||||
|
license: GPLv3
|
||||||
|
formats:
|
||||||
|
- apk
|
||||||
|
- deb
|
||||||
|
- rpm
|
||||||
|
- archlinux
|
||||||
|
provides:
|
||||||
|
- linux-user-repository
|
||||||
|
conflicts:
|
||||||
|
- linux-user-repository
|
||||||
|
recommends:
|
||||||
|
- aria2
|
||||||
|
contents:
|
||||||
|
- src: scripts/completion/bash
|
||||||
|
dst: /usr/share/bash-completion/completions/alr
|
||||||
|
- src: scripts/completion/zsh
|
||||||
|
dst: /usr/share/zsh/site-functions/_alr
|
||||||
|
aurs:
|
||||||
|
- name: linux-user-repository-bin
|
||||||
|
homepage: 'https://gitea.plemya-x.ru/xpamych/ALR'
|
||||||
|
description: "Any Linux Repository"
|
||||||
|
maintainers:
|
||||||
|
- 'Евгений Храмов <xpamych@yandex.ru>'
|
||||||
|
license: GPLv3
|
||||||
|
private_key: '{{ .Env.AUR_KEY }}'
|
||||||
|
git_url: 'ssh://aur@aur.archlinux.org/linux-user-repository-bin.git'
|
||||||
|
provides:
|
||||||
|
- alr
|
||||||
|
conflicts:
|
||||||
|
- alr
|
||||||
|
depends:
|
||||||
|
- sudo
|
||||||
|
- pacman
|
||||||
|
optdepends:
|
||||||
|
- 'aria2: for downloading torrent sources'
|
||||||
|
package: |-
|
||||||
|
# binaries
|
||||||
|
install -Dm755 ./alr "${pkgdir}/usr/bin/alr"
|
||||||
|
|
||||||
|
# completions
|
||||||
|
install -Dm755 ./scripts/completion/bash ${pkgdir}/usr/share/bash-completion/completions/alr
|
||||||
|
install -Dm755 ./scripts/completion/zsh ${pkgdir}/usr/share/zsh/site-functions/_alr
|
||||||
|
release:
|
||||||
|
gitea:
|
||||||
|
owner: alr
|
||||||
|
name: alr
|
||||||
|
gitea_urls:
|
||||||
|
api: 'https://gitea.elara.ws/api/v1/'
|
||||||
|
download: 'https://gitea.elara.ws'
|
||||||
|
skip_tls_verify: false
|
||||||
|
checksum:
|
||||||
|
name_template: 'checksums.txt'
|
||||||
|
snapshot:
|
||||||
|
name_template: "{{ incpatch .Version }}-next"
|
||||||
|
changelog:
|
||||||
|
sort: asc
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# ALR - Any Linux Repository
|
# ALR - Any Linux Repository
|
||||||
# Copyright (C) 2025 The ALR Authors
|
# 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
|
||||||
@@ -19,13 +19,13 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: test-coverage
|
- id: test-coverage
|
||||||
name: Run test coverage
|
name: Run test coverage
|
||||||
entry: bash scripts/test-coverage-precommit.sh
|
entry: make test-coverage
|
||||||
language: system
|
language: system
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- id: fmt
|
- id: fmt
|
||||||
name: Format code
|
name: Format code
|
||||||
entry: bash scripts/fmt-precommit.sh
|
entry: make fmt
|
||||||
language: system
|
language: system
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
@@ -37,7 +37,6 @@ repos:
|
|||||||
|
|
||||||
- id: i18n
|
- id: i18n
|
||||||
name: Update i18n
|
name: Update i18n
|
||||||
entry: bash scripts/i18n-precommit.sh
|
entry: make i18n
|
||||||
language: system
|
language: system
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
always_run: true
|
|
||||||
28
.woodpecker.yml
Normal file
28
.woodpecker.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# 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
|
||||||
|
pipeline:
|
||||||
|
release:
|
||||||
|
image: goreleaser/goreleaser
|
||||||
|
commands:
|
||||||
|
- goreleaser release
|
||||||
|
secrets: [ gitea_token, aur_key ]
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
47
Makefile
47
Makefile
@@ -1,21 +1,16 @@
|
|||||||
NAME := alr
|
NAME := alr
|
||||||
GIT_VERSION ?= $(shell git describe --tags )
|
GIT_VERSION = $(shell git describe --tags )
|
||||||
IGNORE_ROOT_CHECK ?= 0
|
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
BIN := ./$(NAME)
|
BIN := ./$(NAME)
|
||||||
INSTALLED_BIN := $(DESTDIR)/$(PREFIX)/bin/$(NAME)
|
INSTALED_BIN := $(DESTDIR)/$(PREFIX)/bin/$(NAME)
|
||||||
COMPLETIONS_DIR := ./scripts/completion
|
COMPLETIONS_DIR := ./scripts/completion
|
||||||
BASH_COMPLETION := $(COMPLETIONS_DIR)/bash
|
BASH_COMPLETION := $(COMPLETIONS_DIR)/bash
|
||||||
ZSH_COMPLETION := $(COMPLETIONS_DIR)/zsh
|
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)
|
||||||
|
|
||||||
GENERATE ?= 1
|
|
||||||
|
|
||||||
CREATE_SYSTEM_RESOURCES ?= 1
|
|
||||||
ROOT_DIRS := /var/cache/alr /etc/alr
|
|
||||||
|
|
||||||
ADD_LICENSE_BIN := go run github.com/google/addlicense@4caba19b7ed7818bb86bc4cd20411a246aa4a524
|
ADD_LICENSE_BIN := go run github.com/google/addlicense@4caba19b7ed7818bb86bc4cd20411a246aa4a524
|
||||||
GOLANGCI_LINT_BIN := go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.63.4
|
GOLANGCI_LINT_BIN := go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.63.4
|
||||||
XGOTEXT_BIN := go run github.com/Tom5521/xgotext@v1.2.0
|
XGOTEXT_BIN := go run github.com/Tom5521/xgotext@v1.2.0
|
||||||
@@ -26,36 +21,22 @@ build: check-no-root $(BIN)
|
|||||||
|
|
||||||
export CGO_ENABLED := 0
|
export CGO_ENABLED := 0
|
||||||
$(BIN):
|
$(BIN):
|
||||||
ifeq ($(GENERATE),1)
|
|
||||||
go generate ./...
|
|
||||||
else
|
|
||||||
@echo "Skipping go generate (GENERATE=0)"
|
|
||||||
endif
|
|
||||||
go build -ldflags="-X 'gitea.plemya-x.ru/Plemya-x/ALR/internal/config.Version=$(GIT_VERSION)'" -o $@
|
go build -ldflags="-X 'gitea.plemya-x.ru/Plemya-x/ALR/internal/config.Version=$(GIT_VERSION)'" -o $@
|
||||||
|
|
||||||
check-no-root:
|
check-no-root:
|
||||||
@if [ "$$IGNORE_ROOT_CHECK" != "1" ] && [ "`whoami`" = "root" ]; then \
|
@if [[ "$$(whoami)" == 'root' ]]; then \
|
||||||
echo "This target shouldn't run as root" 1>&2; \
|
echo "This target shouldn't run as root" 1>&2; \
|
||||||
echo "Set IGNORE_ROOT_CHECK=1 to override" 1>&2; \
|
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install: \
|
install: \
|
||||||
$(INSTALLED_BIN) \
|
$(INSTALED_BIN) \
|
||||||
$(INSTALLED_BASH_COMPLETION) \
|
$(INSTALLED_BASH_COMPLETION) \
|
||||||
$(INSTALLED_ZSH_COMPLETION)
|
$(INSTALLED_ZSH_COMPLETION)
|
||||||
@echo "Installation done!"
|
@echo "Installation done!"
|
||||||
|
|
||||||
$(INSTALLED_BIN): $(BIN)
|
$(INSTALED_BIN): $(BIN)
|
||||||
install -Dm755 $< $@
|
install -Dm755 $< $@
|
||||||
ifeq ($(CREATE_SYSTEM_RESOURCES),1)
|
|
||||||
@for dir in $(ROOT_DIRS); do \
|
|
||||||
install -d -m 775 $$dir; \
|
|
||||||
chgrp wheel $$dir; \
|
|
||||||
done
|
|
||||||
else
|
|
||||||
@echo "Skipping root dir creation (CREATE_SYSTEM_RESOURCES=0)"
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(INSTALLED_BASH_COMPLETION): $(BASH_COMPLETION)
|
$(INSTALLED_BASH_COMPLETION): $(BASH_COMPLETION)
|
||||||
install -Dm755 $< $@
|
install -Dm755 $< $@
|
||||||
@@ -65,14 +46,14 @@ $(INSTALLED_ZSH_COMPLETION): $(ZSH_COMPLETION)
|
|||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f \
|
rm -f \
|
||||||
$(INSTALLED_BIN) \
|
$(INSTALED_BIN) \
|
||||||
$(INSTALLED_BASH_COMPLETION) \
|
$(INSTALLED_BASH_COMPLETION) \
|
||||||
$(INSTALLED_ZSH_COMPLETION)
|
$(INSTALLED_ZSH_COMPLETION)
|
||||||
|
|
||||||
clean clear:
|
clean clear:
|
||||||
rm -f $(BIN)
|
rm -f $(BIN)
|
||||||
|
|
||||||
OLD_FILES=$(shell cat old-files)
|
OLD_FILES=$$(< old-files)
|
||||||
IGNORE_OLD_FILES := $(foreach file,$(shell cat old-files),-ignore $(file))
|
IGNORE_OLD_FILES := $(foreach file,$(shell cat old-files),-ignore $(file))
|
||||||
update-license:
|
update-license:
|
||||||
$(ADD_LICENSE_BIN) -v -f license-header-old-files.tmpl $(OLD_FILES)
|
$(ADD_LICENSE_BIN) -v -f license-header-old-files.tmpl $(OLD_FILES)
|
||||||
@@ -88,15 +69,5 @@ i18n:
|
|||||||
bash scripts/i18n-badge.sh
|
bash scripts/i18n-badge.sh
|
||||||
|
|
||||||
test-coverage:
|
test-coverage:
|
||||||
go test -tags=test ./... -v -coverpkg=./... -coverprofile=coverage.out
|
go test ./... -v -coverpkg=./... -coverprofile=coverage.out
|
||||||
bash scripts/coverage-badge.sh
|
bash scripts/coverage-badge.sh
|
||||||
|
|
||||||
update-deps-cve:
|
|
||||||
bash scripts/update-deps-cve.sh
|
|
||||||
|
|
||||||
prepare-for-e2e-test: clean build
|
|
||||||
rm -f ./e2e-tests/alr
|
|
||||||
cp alr e2e-tests
|
|
||||||
|
|
||||||
e2e-test: prepare-for-e2e-test
|
|
||||||
go test -tags=e2e ./...
|
|
||||||
20
README.md
20
README.md
@@ -20,10 +20,10 @@ ALR написан на чистом Go и после сборки не имее
|
|||||||
Установочный скрипт автоматически загрузит и установит соответствующий пакет ALR в вашей системе. Чтобы использовать его, просто выполните следующую команду:
|
Установочный скрипт автоматически загрузит и установит соответствующий пакет ALR в вашей системе. Чтобы использовать его, просто выполните следующую команду:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://gitea.plemya-x.ru/Plemya-x/ALR/raw/branch/master/scripts/install.sh | bash
|
curl -fsSL plemya-x.ru/alr/install.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
**ВАЖНО**: При этом скрипт будет загружен и запущен [скрипт](https://gitea.plemya-x.ru/Plemya-x/ALR/src/branch/master/scripts/install.sh). Пожалуйста, просматривайте любые скрипты, которые вы скачиваете из Интернета (включая этот), прежде чем запускать их.
|
**ВАЖНО**: При этом скрипт будет загружен и запущен с <https://plemya-x.ru/alr/install.sh>. Пожалуйста, просматривайте любые скрипты, которые вы скачиваете из Интернета (включая этот), прежде чем запускать их.
|
||||||
|
|
||||||
### Сборка из исходного кода
|
### Сборка из исходного кода
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ ALR был создан потому, что упаковка программн
|
|||||||
|
|
||||||
## Документация
|
## Документация
|
||||||
|
|
||||||
Документация находится в [Wiki](https://alr.plemya-x.ru/wiki/ALR).
|
Документация находится в [Wiki](https://disc.plemya-x.ru/c/alr/wiki-alr).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -52,21 +52,15 @@ ALR был создан потому, что упаковка программн
|
|||||||
|
|
||||||
Репозитории alr - это git-хранилища, которые содержат каталог для каждого пакета с файлом `alr.sh` внутри. Файл `alr.sh` содержит все инструкции по сборке пакета и информацию о нем. Скрипты `alr.sh` аналогичны скриптам Aur PKGBUILD.
|
Репозитории alr - это git-хранилища, которые содержат каталог для каждого пакета с файлом `alr.sh` внутри. Файл `alr.sh` содержит все инструкции по сборке пакета и информацию о нем. Скрипты `alr.sh` аналогичны скриптам Aur PKGBUILD.
|
||||||
|
|
||||||
Например, репозиторий с ALR [alr-default](https://gitea.plemya-x.ru/Plemya-x/alr-default.git)
|
Например, репозиторий [Plemya-x/alr-repo](https://gitea.plemya-x.ru/Plemya-x/alr-repo.git) можно подключить так:
|
||||||
```
|
```
|
||||||
alr repo add alr-default https://gitea.plemya-x.ru/Plemya-x/alr-default.git
|
alr addrepo --name alr-repo --url https://gitea.plemya-x.ru/Plemya-x/alr-repo.git
|
||||||
```
|
|
||||||
Репозиторий пакетов [alr-repo](https://gitea.plemya-x.ru/Plemya-x/alr-repo.git) можно подключить так:
|
|
||||||
```
|
|
||||||
alr repo add alr-repo https://gitea.plemya-x.ru/Plemya-x/alr-repo.git
|
|
||||||
```
|
|
||||||
Репозиторий Linux-Gaming [alr-LG](https://gitea.plemya-x.ru/Plemya-x/alr-LG.git) можно подключить так:
|
|
||||||
```
|
|
||||||
alr repo add alr-LG https://git.linux-gaming.ru/Linux-Gaming/alr-LG.git
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
## Соцсети
|
## Соцсети
|
||||||
|
VK - https://vk.com/plemya_kh
|
||||||
|
|
||||||
Telegram - https://t.me/plemyakh
|
Telegram - https://t.me/plemyakh
|
||||||
|
|
||||||
## Спасибы
|
## Спасибы
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
||||||
<text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
|
<text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
|
||||||
<text x="33.5" y="14">coverage</text>
|
<text x="33.5" y="14">coverage</text>
|
||||||
<text x="86" y="15" fill="#010101" fill-opacity=".3">18.9%</text>
|
<text x="86" y="15" fill="#010101" fill-opacity=".3">19.8%</text>
|
||||||
<text x="86" y="14">18.9%</text>
|
<text x="86" y="14">19.8%</text>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 926 B |
189
build.go
189
build.go
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -23,16 +23,19 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/build"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||||
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/osutils"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/osutils"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/build"
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager"
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BuildCmd() *cli.Command {
|
func BuildCmd() *cli.Command {
|
||||||
@@ -63,147 +66,117 @@ func BuildCmd() *cli.Command {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
if err := utils.CheckUserPrivileges(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error getting working directory"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := c.Context
|
ctx := c.Context
|
||||||
|
cfg := config.New()
|
||||||
deps, err := appbuilder.
|
db := database.New(cfg)
|
||||||
New(ctx).
|
rs := repos.New(cfg, db)
|
||||||
WithConfig().
|
err := db.Init(ctx)
|
||||||
WithDB().
|
|
||||||
WithReposNoPull().
|
|
||||||
WithDistroInfo().
|
|
||||||
WithManager().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.Exit(err, 1)
|
slog.Error(gotext.Get("Error initialization database"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
var script string
|
var script string
|
||||||
var packages []string
|
var packages []string
|
||||||
|
repository := "default"
|
||||||
|
|
||||||
var res []*build.BuiltDep
|
repoDir := cfg.GetPaths(ctx).RepoDir
|
||||||
|
|
||||||
var scriptArgs *build.BuildPackageFromScriptArgs
|
|
||||||
var dbArgs *build.BuildPackageFromDbArgs
|
|
||||||
|
|
||||||
buildArgs := &build.BuildArgs{
|
|
||||||
Opts: &types.BuildOpts{
|
|
||||||
Clean: c.Bool("clean"),
|
|
||||||
Interactive: c.Bool("interactive"),
|
|
||||||
},
|
|
||||||
PkgFormat_: build.GetPkgFormat(deps.Manager),
|
|
||||||
Info: deps.Info,
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case c.IsSet("script"):
|
case c.IsSet("script"):
|
||||||
script, err = filepath.Abs(c.String("script"))
|
script = c.String("script")
|
||||||
if err != nil {
|
packages = append(packages, c.String("script-package"))
|
||||||
return cliutils.FormatCliExit(gotext.Get("Cannot get absolute script path"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
subpackage := c.String("subpackage")
|
|
||||||
|
|
||||||
if subpackage != "" {
|
|
||||||
packages = append(packages, subpackage)
|
|
||||||
}
|
|
||||||
|
|
||||||
scriptArgs = &build.BuildPackageFromScriptArgs{
|
|
||||||
Script: script,
|
|
||||||
Packages: packages,
|
|
||||||
BuildArgs: *buildArgs,
|
|
||||||
}
|
|
||||||
case c.IsSet("package"):
|
case c.IsSet("package"):
|
||||||
// TODO: handle multiple packages
|
// TODO: handle multiple packages
|
||||||
packageInput := c.String("package")
|
packageInput := c.String("package")
|
||||||
|
|
||||||
pkgs, _, err := deps.Repos.FindPkgs(ctx, []string{packageInput})
|
arr := strings.Split(packageInput, "/")
|
||||||
if err != nil {
|
var packageSearch string
|
||||||
return cliutils.FormatCliExit("failed to find pkgs", err)
|
if len(arr) == 2 {
|
||||||
|
packageSearch = arr[1]
|
||||||
|
} else {
|
||||||
|
packageSearch = arr[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg := cliutils.FlattenPkgs(ctx, pkgs, "build", c.Bool("interactive"))
|
pkgs, _, _ := rs.FindPkgs(ctx, []string{packageSearch})
|
||||||
|
pkg, ok := pkgs[packageSearch]
|
||||||
if len(pkg) < 1 {
|
if len(pkg) < 1 || !ok {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Package not found"), nil)
|
slog.Error(gotext.Get("Package not found"))
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repository = pkg[0].Repository
|
||||||
|
|
||||||
if pkg[0].BasePkgName != "" {
|
if pkg[0].BasePkgName != "" {
|
||||||
|
script = filepath.Join(repoDir, repository, pkg[0].BasePkgName, "alr.sh")
|
||||||
packages = append(packages, pkg[0].Name)
|
packages = append(packages, pkg[0].Name)
|
||||||
}
|
} else {
|
||||||
|
script = filepath.Join(repoDir, repository, pkg[0].Name, "alr.sh")
|
||||||
dbArgs = &build.BuildPackageFromDbArgs{
|
|
||||||
Package: &pkg[0],
|
|
||||||
Packages: packages,
|
|
||||||
BuildArgs: *buildArgs,
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return cliutils.FormatCliExit(gotext.Get("Nothing to build"), nil)
|
script = filepath.Join(repoDir, "alr.sh")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверка автоматического пулла репозиториев
|
||||||
|
if cfg.AutoPull(ctx) {
|
||||||
|
err := rs.Pull(ctx, cfg.Repos(ctx))
|
||||||
|
|
||||||
installer, installerClose, err := build.GetSafeInstaller()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error pulling repositories"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer installerClose()
|
|
||||||
|
|
||||||
|
// Обнаружение менеджера пакетов
|
||||||
|
mgr := manager.Detect()
|
||||||
|
if mgr == nil {
|
||||||
|
slog.Error(gotext.Get("Unable to detect a supported package manager on the system"))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := distro.ParseOSRelease(ctx)
|
||||||
scripter, scripterClose, err := build.GetSafeScriptExecutor()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error parsing os release"), "err", err)
|
||||||
}
|
os.Exit(1)
|
||||||
defer scripterClose()
|
|
||||||
|
|
||||||
builder, err := build.NewMainBuilder(
|
|
||||||
deps.Cfg,
|
|
||||||
deps.Manager,
|
|
||||||
deps.Repos,
|
|
||||||
scripter,
|
|
||||||
installer,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if scriptArgs != nil {
|
builder := build.NewBuilder(
|
||||||
res, err = builder.BuildPackageFromScript(
|
|
||||||
ctx,
|
ctx,
|
||||||
scriptArgs,
|
types.BuildOpts{
|
||||||
|
Packages: packages,
|
||||||
|
Repository: repository,
|
||||||
|
Script: script,
|
||||||
|
Manager: mgr,
|
||||||
|
Clean: c.Bool("clean"),
|
||||||
|
Interactive: c.Bool("interactive"),
|
||||||
|
},
|
||||||
|
rs,
|
||||||
|
info,
|
||||||
|
cfg,
|
||||||
)
|
)
|
||||||
} else if dbArgs != nil {
|
|
||||||
res, err = builder.BuildPackageFromDb(
|
|
||||||
ctx,
|
|
||||||
dbArgs,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Сборка пакета
|
||||||
|
pkgPaths, _, err := builder.BuildPackage(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error building package"), err)
|
slog.Error(gotext.Get("Error building package"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range res {
|
// Получение текущей рабочей директории
|
||||||
name := filepath.Base(pkg.Path)
|
wd, err := os.Getwd()
|
||||||
err = osutils.Move(pkg.Path, filepath.Join(wd, name))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error moving the package"), err)
|
slog.Error(gotext.Get("Error getting working directory"), "err", err)
|
||||||
}
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info(gotext.Get("Done"))
|
// Перемещение собранных пакетов в рабочую директорию
|
||||||
|
for _, pkgPath := range pkgPaths {
|
||||||
|
name := filepath.Base(pkgPath)
|
||||||
|
err = osutils.Move(pkgPath, filepath.Join(wd, name))
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Error moving the package"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
236
config.go
236
config.go
@@ -1,236 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
|
||||||
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ConfigCmd() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "config",
|
|
||||||
Usage: gotext.Get("Manage config"),
|
|
||||||
Subcommands: []*cli.Command{
|
|
||||||
ShowCmd(),
|
|
||||||
SetConfig(),
|
|
||||||
GetConfig(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ShowCmd() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "show",
|
|
||||||
Usage: gotext.Get("Show config"),
|
|
||||||
BashComplete: cliutils.BashCompleteWithError(func(c *cli.Context) error {
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
deps, err := appbuilder.
|
|
||||||
New(c.Context).
|
|
||||||
WithConfig().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
content, err := deps.Cfg.ToYAML()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println(content)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var configKeys = []string{
|
|
||||||
"rootCmd",
|
|
||||||
"useRootCmd",
|
|
||||||
"pagerStyle",
|
|
||||||
"autoPull",
|
|
||||||
"logLevel",
|
|
||||||
"ignorePkgUpdates",
|
|
||||||
"updateSystemOnUpgrade",
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetConfig() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "set",
|
|
||||||
Usage: gotext.Get("Set config value"),
|
|
||||||
ArgsUsage: gotext.Get("<key> <value>"),
|
|
||||||
BashComplete: cliutils.BashCompleteWithError(func(c *cli.Context) error {
|
|
||||||
if c.Args().Len() == 0 {
|
|
||||||
for _, key := range configKeys {
|
|
||||||
fmt.Println(key)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
Action: utils.RootNeededAction(func(c *cli.Context) error {
|
|
||||||
if c.Args().Len() < 2 {
|
|
||||||
return cliutils.FormatCliExit("missing args", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := c.Args().Get(0)
|
|
||||||
value := c.Args().Get(1)
|
|
||||||
|
|
||||||
deps, err := appbuilder.
|
|
||||||
New(c.Context).
|
|
||||||
WithConfig().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
switch key {
|
|
||||||
case "rootCmd":
|
|
||||||
deps.Cfg.System.SetRootCmd(value)
|
|
||||||
case "useRootCmd":
|
|
||||||
boolValue, err := strconv.ParseBool(value)
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("invalid boolean value for %s: %s", key, value), err)
|
|
||||||
}
|
|
||||||
deps.Cfg.System.SetUseRootCmd(boolValue)
|
|
||||||
case "pagerStyle":
|
|
||||||
deps.Cfg.System.SetPagerStyle(value)
|
|
||||||
case "autoPull":
|
|
||||||
boolValue, err := strconv.ParseBool(value)
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("invalid boolean value for %s: %s", key, value), err)
|
|
||||||
}
|
|
||||||
deps.Cfg.System.SetAutoPull(boolValue)
|
|
||||||
case "logLevel":
|
|
||||||
deps.Cfg.System.SetLogLevel(value)
|
|
||||||
case "ignorePkgUpdates":
|
|
||||||
var updates []string
|
|
||||||
if value != "" {
|
|
||||||
updates = strings.Split(value, ",")
|
|
||||||
for i, update := range updates {
|
|
||||||
updates[i] = strings.TrimSpace(update)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deps.Cfg.System.SetIgnorePkgUpdates(updates)
|
|
||||||
case "updateSystemOnUpgrade":
|
|
||||||
boolValue, err := strconv.ParseBool(value)
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("invalid boolean value for %s: %s", key, value), err)
|
|
||||||
}
|
|
||||||
deps.Cfg.System.SetUpdateSystemOnUpgrade(boolValue)
|
|
||||||
case "repo", "repos":
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("use 'repo add/remove' commands to manage repositories"), nil)
|
|
||||||
default:
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("unknown config key: %s", key), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := deps.Cfg.System.Save(); err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("failed to save config"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(gotext.Get("Successfully set %s = %s", key, value))
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfig() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "get",
|
|
||||||
Usage: gotext.Get("Get config value"),
|
|
||||||
ArgsUsage: gotext.Get("<key>"),
|
|
||||||
BashComplete: cliutils.BashCompleteWithError(func(c *cli.Context) error {
|
|
||||||
if c.Args().Len() == 0 {
|
|
||||||
for _, key := range configKeys {
|
|
||||||
fmt.Println(key)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
deps, err := appbuilder.
|
|
||||||
New(c.Context).
|
|
||||||
WithConfig().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
if c.Args().Len() == 0 {
|
|
||||||
content, err := deps.Cfg.ToYAML()
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit("failed to serialize config", err)
|
|
||||||
}
|
|
||||||
fmt.Print(content)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
key := c.Args().Get(0)
|
|
||||||
|
|
||||||
switch key {
|
|
||||||
case "rootCmd":
|
|
||||||
fmt.Println(deps.Cfg.RootCmd())
|
|
||||||
case "useRootCmd":
|
|
||||||
fmt.Println(deps.Cfg.UseRootCmd())
|
|
||||||
case "pagerStyle":
|
|
||||||
fmt.Println(deps.Cfg.PagerStyle())
|
|
||||||
case "autoPull":
|
|
||||||
fmt.Println(deps.Cfg.AutoPull())
|
|
||||||
case "logLevel":
|
|
||||||
fmt.Println(deps.Cfg.LogLevel())
|
|
||||||
case "ignorePkgUpdates":
|
|
||||||
updates := deps.Cfg.IgnorePkgUpdates()
|
|
||||||
if len(updates) == 0 {
|
|
||||||
fmt.Println("[]")
|
|
||||||
} else {
|
|
||||||
fmt.Println(strings.Join(updates, ", "))
|
|
||||||
}
|
|
||||||
case "updateSystemOnUpgrade":
|
|
||||||
fmt.Println(deps.Cfg.UpdateSystemOnUpgrade())
|
|
||||||
case "repo", "repos":
|
|
||||||
repos := deps.Cfg.Repos()
|
|
||||||
if len(repos) == 0 {
|
|
||||||
fmt.Println("[]")
|
|
||||||
} else {
|
|
||||||
repoData, err := yaml.Marshal(repos)
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit("failed to serialize repos", err)
|
|
||||||
}
|
|
||||||
fmt.Print(string(repoData))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("unknown config key: %s", key), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
- name: alr-repo
|
|
||||||
url: https://gitea.plemya-x.ru/Plemya-x/repo-for-tests
|
|
||||||
ref: main
|
|
||||||
mirrors:
|
|
||||||
- https://github.com/example/example.git
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
alr-repo/foo-pkg 1.0.0-1
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
alr-repo/bar-pkg 1.0.0-1
|
|
||||||
alr-repo/foo-pkg 1.0.0-1
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EAlrAddRepo(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"add-repo-remove-repo",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "addrepo", "--name", "alr-repo", "--url", "https://gitea.plemya-x.ru/Plemya-x/alr-repo.git")
|
|
||||||
execShouldNoError(t, r, "bash", "-c", "cat /etc/alr/alr.toml")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "removerepo", "--name", "alr-repo")
|
|
||||||
|
|
||||||
r.Command("bash", "-c", "cat /etc/alr/alr.toml").
|
|
||||||
ExpectStdoutContains("repo = []").
|
|
||||||
Run(t)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EBashCompletion(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"bash-completion",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
execShouldNoError(t, r, "alr", "install", "--generate-bash-completion")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
"go.alt-gnome.ru/capytest/providers/podman"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ALL_SYSTEMS []string = []string{
|
|
||||||
"ubuntu-24.04",
|
|
||||||
"alt-sisyphus",
|
|
||||||
"fedora-41",
|
|
||||||
// "archlinux",
|
|
||||||
// "alpine",
|
|
||||||
// "opensuse-leap",
|
|
||||||
// "redos-8",
|
|
||||||
}
|
|
||||||
|
|
||||||
var AUTOREQ_AUTOPROV_SYSTEMS []string = []string{
|
|
||||||
// "alt-sisyphus",
|
|
||||||
"fedora-41",
|
|
||||||
}
|
|
||||||
|
|
||||||
var RPM_SYSTEMS []string = []string{
|
|
||||||
"fedora-41",
|
|
||||||
}
|
|
||||||
|
|
||||||
var COMMON_SYSTEMS []string = []string{
|
|
||||||
"ubuntu-24.04",
|
|
||||||
}
|
|
||||||
|
|
||||||
func execShouldNoError(t *testing.T, r capytest.Runner, cmd string, args ...string) {
|
|
||||||
t.Helper()
|
|
||||||
r.Command(cmd, args...).ExpectSuccess().Run(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func execShouldError(t *testing.T, r capytest.Runner, cmd string, args ...string) {
|
|
||||||
t.Helper()
|
|
||||||
r.Command(cmd, args...).ExpectFailure().Run(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
const REPO_NAME_FOR_E2E_TESTS = "alr-repo"
|
|
||||||
const REPO_URL_FOR_E2E_TESTS = "https://gitea.plemya-x.ru/Plemya-x/repo-for-tests.git"
|
|
||||||
|
|
||||||
func defaultPrepare(t *testing.T, r capytest.Runner) {
|
|
||||||
execShouldNoError(t, r,
|
|
||||||
"sudo",
|
|
||||||
"alr",
|
|
||||||
"repo",
|
|
||||||
"add",
|
|
||||||
REPO_NAME_FOR_E2E_TESTS,
|
|
||||||
REPO_URL_FOR_E2E_TESTS,
|
|
||||||
)
|
|
||||||
|
|
||||||
execShouldNoError(t, r,
|
|
||||||
"sudo",
|
|
||||||
"alr",
|
|
||||||
"ref",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runMatrixSuite(t *testing.T, name string, images []string, test func(t *testing.T, r capytest.Runner)) {
|
|
||||||
t.Helper()
|
|
||||||
for _, image := range images {
|
|
||||||
ts := capytest.NewTestSuite(t, podman.Provider(
|
|
||||||
podman.WithImage(fmt.Sprintf("ghcr.io/maks1ms/alr-e2e-test-image-%s", image)),
|
|
||||||
podman.WithVolumes("./alr:/tmp/alr"),
|
|
||||||
podman.WithPrivileged(true),
|
|
||||||
))
|
|
||||||
ts.BeforeEach(func(t *testing.T, r capytest.Runner) {
|
|
||||||
execShouldNoError(t, r, "/bin/alr-test-setup", "alr-install")
|
|
||||||
execShouldNoError(t, r, "/bin/alr-test-setup", "passwordless-sudo-setup")
|
|
||||||
})
|
|
||||||
ts.Run(fmt.Sprintf("%s/%s", name, image), test)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EFirejailedPackage(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"firejailed-package",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "alr", "build", "-p", fmt.Sprintf("%s/firejailed-pkg", REPO_NAME_FOR_E2E_TESTS))
|
|
||||||
execShouldError(t, r, "alr", "build", "-p", fmt.Sprintf("%s/firejailed-pkg-incorrect", REPO_NAME_FOR_E2E_TESTS))
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "dpkg -c *.deb | grep -q '/usr/lib/alr/firejailed/_usr_bin_danger.sh'")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "dpkg -c *.deb | grep -q '/usr/lib/alr/firejailed/_usr_bin_danger.sh.profile'")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EAlrFix(t *testing.T) {
|
|
||||||
runMatrixSuite(t, "run-fix", COMMON_SYSTEMS, func(t *testing.T, r capytest.Runner) {
|
|
||||||
r.Command("alr", "fix").
|
|
||||||
ExpectStderrContains("--> Done").
|
|
||||||
ExpectSuccess().
|
|
||||||
Run(t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EGroupAndSummaryField(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"group-and-summary-field",
|
|
||||||
RPM_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr search --name test-group-and-summary --format \"{{.Group.Resolved}}\" | grep ^System/Base$")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr search --name test-group-and-summary --format \"{{.Summary.Resolved}}\" | grep \"^Custom summary$\"")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue129RepoTomlImportTest(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-129-repo-toml-import-test",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
|
|
||||||
r.Command("alr", "config", "get", "repos").
|
|
||||||
ExpectStdoutMatchesSnapshot().
|
|
||||||
Run(t)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue130Install(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"alr install {repo}/{package}",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
t.Parallel()
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
|
|
||||||
r.Command("sudo", "alr", "in", fmt.Sprintf("%s/foo-pkg", REPO_NAME_FOR_E2E_TESTS)).
|
|
||||||
ExpectSuccess().
|
|
||||||
Run(t)
|
|
||||||
|
|
||||||
r.Command("sudo", "alr", "in", fmt.Sprintf("%s/bar-pkg", "NOT_REPO_NAME_FOR_E2E_TESTS")).
|
|
||||||
ExpectFailure().
|
|
||||||
Run(t)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"alr install {package}+{repo}",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
t.Parallel()
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
|
|
||||||
r.Command("sudo", "alr", "in", fmt.Sprintf("foo-pkg+%s", REPO_NAME_FOR_E2E_TESTS)).
|
|
||||||
ExpectSuccess().
|
|
||||||
Run(t)
|
|
||||||
|
|
||||||
r.Command("sudo", "alr", "in", fmt.Sprintf("bar-pkg+%s", "NOT_REPO_NAME_FOR_E2E_TESTS")).
|
|
||||||
ExpectFailure().
|
|
||||||
Run(t)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue32Interactive(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-32-interactive",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
execShouldNoError(t, r, "alr", "--interactive=false", "remove", "ca-certificates")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "--interactive=false", "remove", "openssl")
|
|
||||||
execShouldNoError(t, r, "alr", "fix")
|
|
||||||
execShouldNoError(t, r, "sudo", "apt-get", "update")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "--interactive=false", "install", "ca-certificates")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue41AutoreqSkiplist(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-41-autoreq-skiplist",
|
|
||||||
AUTOREQ_AUTOPROV_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "alr", "build", "-p", "alr-repo/test-autoreq-autoprov")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "rpm -qp --requires *.rpm | grep \"^/bin/sh$\"")
|
|
||||||
execShouldError(t, r, "sh", "-c", "rpm -qp --requires *.rpm | grep \"^/bin/bash$\"")
|
|
||||||
execShouldError(t, r, "sh", "-c", "rpm -qp --requires *.rpm | grep \"^/bin/zsh$\"")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue50InstallMultiple(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-50-install-multiple",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "in", "foo-pkg", "bar-pkg")
|
|
||||||
execShouldNoError(t, r, "cat", "/opt/foo")
|
|
||||||
execShouldNoError(t, r, "cat", "/opt/bar")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue53LcAllCInfo(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-53-lc-all-c-info",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "bash", "-c", "LANG=C alr info foo-pkg")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue59RmCompletion(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-59-rm-completion",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "in", "foo-pkg", "bar-pkg")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr rm --generate-bash-completion | grep ^foo-pkg$")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr rm --generate-bash-completion | grep ^bar-pkg$")
|
|
||||||
execShouldError(t, r, "sh", "-c", "alr rm --generate-bash-completion | grep ^test-autoreq-autoprov$")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue62List(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-62-list",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-ref", "alr-repo", "bd26236cd7")
|
|
||||||
execShouldNoError(t, r, "alr", "ref")
|
|
||||||
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "in", "foo-pkg")
|
|
||||||
|
|
||||||
r.Command("alr", "list", "-I").
|
|
||||||
ExpectSuccess().
|
|
||||||
ExpectStdoutMatchesSnapshot().
|
|
||||||
Run(t)
|
|
||||||
|
|
||||||
r.Command("alr", "list").
|
|
||||||
ExpectSuccess().
|
|
||||||
ExpectStdoutMatchesSnapshot().
|
|
||||||
Run(t)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue72InstallWithDeps(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-72-install-with-deps",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "in", "test-app-with-lib")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue74Upgradable(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-74-upgradable",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-ref", "alr-repo", "bd26236cd7")
|
|
||||||
execShouldNoError(t, r, "alr", "ref")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "in", "bar-pkg")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "test $(alr list -U | wc -l) -eq 0 || exit 1")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-ref", "alr-repo", "d9a3541561")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "ref")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "test $(alr list -U | wc -l) -eq 1 || exit 1")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue75InstallWithDeps(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-75-ref-specify",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-ref", "alr-repo", "bd26236cd7")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "test $(alr list | wc -l) -eq 2 || exit 1")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test75SinglePackageRepo(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-76-single-package-repo",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
execShouldNoError(t, r,
|
|
||||||
"sudo",
|
|
||||||
"alr",
|
|
||||||
"repo",
|
|
||||||
"add",
|
|
||||||
REPO_NAME_FOR_E2E_TESTS,
|
|
||||||
"https://gitea.plemya-x.ru/Maks1mS/test-single-package-alr-repo.git",
|
|
||||||
)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "ref")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-ref", REPO_NAME_FOR_E2E_TESTS, "1075c918be")
|
|
||||||
execShouldNoError(t, r, "alr", "fix")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "in", "test-single-repo")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr list -U")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "test $(alr list -U | wc -l) -eq 0 || exit 1")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-ref", REPO_NAME_FOR_E2E_TESTS, "5e361c50d7")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "ref")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "test $(alr list -U | wc -l) -eq 1 || exit 1")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "up")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "test $(alr list -U | wc -l) -eq 0 || exit 1")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue78Mirrors(t *testing.T) {
|
|
||||||
runMatrixSuite(t, "issue-78-mirrors", COMMON_SYSTEMS, func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "add", REPO_NAME_FOR_E2E_TESTS, "https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-url", REPO_NAME_FOR_E2E_TESTS, "https://example.com")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "ref")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "clear", REPO_NAME_FOR_E2E_TESTS)
|
|
||||||
execShouldError(t, r, "sudo", "alr", "ref")
|
|
||||||
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "add", REPO_NAME_FOR_E2E_TESTS, "https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "rm", "--partial", REPO_NAME_FOR_E2E_TESTS, "gitea.plemya-x.ru/Maks1mS")
|
|
||||||
execShouldError(t, r, "sudo", "alr", "ref")
|
|
||||||
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "add", REPO_NAME_FOR_E2E_TESTS, "https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "rm", REPO_NAME_FOR_E2E_TESTS, "https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git")
|
|
||||||
execShouldError(t, r, "sudo", "alr", "ref")
|
|
||||||
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "add", REPO_NAME_FOR_E2E_TESTS, "https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "mirror", "rm", REPO_NAME_FOR_E2E_TESTS, "https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git")
|
|
||||||
execShouldError(t, r, "sudo", "alr", "ref")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue81MultiplePackages(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-81-multiple-packages",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "in", "first-package-with-dashes")
|
|
||||||
execShouldNoError(t, r, "cat", "/opt/first-package")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue91MultiplePackages(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-91-set-repo-ref",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldError(t, r, "sudo", "alr", "repo", "set-ref")
|
|
||||||
execShouldError(t, r, "sudo", "alr", "repo", "set-ref", "alr-repo")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "repo", "set-ref", "alr-repo", "bd26236cd7")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "test $(alr list | wc -l) -eq 2 || exit 1")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue94TwiceBuild(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-94-twice-build",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
|
|
||||||
r.Command("sudo", "alr", "in", "test-94-app").
|
|
||||||
WithCaptureStderr(&stderr).
|
|
||||||
ExpectSuccess().
|
|
||||||
Run(t)
|
|
||||||
|
|
||||||
assert.Equal(t, 1, strings.Count(stderr.String(), "Building package name=test-94-dep"))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EIssue95ConfigCommand(t *testing.T) {
|
|
||||||
runMatrixSuite(
|
|
||||||
t,
|
|
||||||
"issue-95-config-command",
|
|
||||||
COMMON_SYSTEMS,
|
|
||||||
func(t *testing.T, r capytest.Runner) {
|
|
||||||
defaultPrepare(t, r)
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr config show | grep \"autoPull: true\"")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr config get | grep \"autoPull: true\"")
|
|
||||||
execShouldError(t, r, "sh", "-c", "cat /etc/alr/alr.toml | grep \"autoPull\"")
|
|
||||||
execShouldNoError(t, r, "alr", "config", "get", "autoPull")
|
|
||||||
execShouldError(t, r, "alr", "config", "set", "autoPull")
|
|
||||||
execShouldNoError(t, r, "sudo", "alr", "config", "set", "autoPull", "false")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr config show | grep \"autoPull: false\"")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "alr config get | grep \"autoPull: false\"")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "cat /etc/alr/alr.toml | grep \"autoPull = false\"")
|
|
||||||
execShouldNoError(t, r, "alr", "config", "set", "autoPull", "true")
|
|
||||||
execShouldNoError(t, r, "sh", "-c", "cat /etc/alr/alr.toml | grep \"autoPull = true\"")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build e2e
|
|
||||||
|
|
||||||
package e2etests_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.alt-gnome.ru/capytest"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestE2EAlrVersion(t *testing.T) {
|
|
||||||
runMatrixSuite(t, "version", COMMON_SYSTEMS, func(t *testing.T, r capytest.Runner) {
|
|
||||||
r.Command("alr", "version").
|
|
||||||
ExpectStderrRegex(`^v\d+\.\d+\.\d+(?:-\d+-g[a-f0-9]+)?\n$`).
|
|
||||||
ExpectStdoutEmpty().
|
|
||||||
ExpectSuccess().
|
|
||||||
Run(t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
193
fix.go
193
fix.go
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -20,176 +20,55 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
|
database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils"
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos"
|
||||||
)
|
)
|
||||||
|
|
||||||
// execWithPrivileges выполняет команду напрямую если root или CI, иначе через sudo
|
|
||||||
func execWithPrivileges(name string, args ...string) *exec.Cmd {
|
|
||||||
isRoot := os.Geteuid() == 0
|
|
||||||
isCI := os.Getenv("CI") == "true"
|
|
||||||
|
|
||||||
if !isRoot && !isCI {
|
|
||||||
// Если не root и не в CI, используем sudo
|
|
||||||
allArgs := append([]string{name}, args...)
|
|
||||||
return exec.Command("sudo", allArgs...)
|
|
||||||
} else {
|
|
||||||
// Если root или в CI, запускаем напрямую
|
|
||||||
return exec.Command(name, args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FixCmd() *cli.Command {
|
func FixCmd() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "fix",
|
Name: "fix",
|
||||||
Usage: gotext.Get("Attempt to fix problems with ALR"),
|
Usage: gotext.Get("Attempt to fix problems with ALR"),
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
// Команда выполняется от текущего пользователя
|
|
||||||
// При необходимости будет запрошен sudo для удаления файлов root
|
|
||||||
|
|
||||||
ctx := c.Context
|
ctx := c.Context
|
||||||
|
cfg := config.New()
|
||||||
|
paths := cfg.GetPaths(ctx)
|
||||||
|
|
||||||
deps, err := appbuilder.
|
slog.Info(gotext.Get("Removing cache directory"))
|
||||||
New(ctx).
|
|
||||||
WithConfig().
|
err := os.RemoveAll(paths.CacheDir)
|
||||||
Build()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.Exit(err, 1)
|
slog.Error(gotext.Get("Unable to remove cache directory"), "err", err)
|
||||||
}
|
os.Exit(1)
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
cfg := deps.Cfg
|
|
||||||
|
|
||||||
paths := cfg.GetPaths()
|
|
||||||
|
|
||||||
slog.Info(gotext.Get("Clearing cache and temporary directories"))
|
|
||||||
|
|
||||||
// Проверяем, существует ли директория кэша
|
|
||||||
dir, err := os.Open(paths.CacheDir)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
// Директория не существует, просто создадим её позже
|
|
||||||
slog.Info(gotext.Get("Cache directory does not exist, will create it"))
|
|
||||||
} else {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Unable to open cache directory"), err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
defer dir.Close()
|
|
||||||
|
|
||||||
entries, err := dir.Readdirnames(-1)
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Unable to read cache directory contents"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, entry := range entries {
|
|
||||||
fullPath := filepath.Join(paths.CacheDir, entry)
|
|
||||||
|
|
||||||
// Пробуем сделать файлы доступными для записи
|
|
||||||
if err := makeWritableRecursive(fullPath); err != nil {
|
|
||||||
slog.Debug("Failed to make path writable", "path", fullPath, "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Пробуем удалить
|
|
||||||
err = os.RemoveAll(fullPath)
|
|
||||||
if err != nil {
|
|
||||||
// Если не получилось удалить, пробуем через sudo
|
|
||||||
slog.Warn(gotext.Get("Unable to remove cache item (%s) as current user, trying with sudo", entry))
|
|
||||||
|
|
||||||
sudoCmd := execWithPrivileges("rm", "-rf", fullPath)
|
|
||||||
if sudoErr := sudoCmd.Run(); sudoErr != nil {
|
|
||||||
// Если и через sudo не получилось, пропускаем с предупреждением
|
|
||||||
slog.Error(gotext.Get("Unable to remove cache item (%s)", entry), "error", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Очищаем временные директории
|
|
||||||
slog.Info(gotext.Get("Clearing temporary directory"))
|
|
||||||
tmpDir := "/tmp/alr"
|
|
||||||
if _, err := os.Stat(tmpDir); err == nil {
|
|
||||||
// Директория существует, пробуем очистить
|
|
||||||
err = os.RemoveAll(tmpDir)
|
|
||||||
if err != nil {
|
|
||||||
// Если не получилось удалить, пробуем через sudo
|
|
||||||
slog.Warn(gotext.Get("Unable to remove temporary directory as current user, trying with sudo"))
|
|
||||||
sudoCmd := execWithPrivileges("rm", "-rf", tmpDir)
|
|
||||||
if sudoErr := sudoCmd.Run(); sudoErr != nil {
|
|
||||||
slog.Error(gotext.Get("Unable to remove temporary directory"), "error", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Создаем базовый каталог /tmp/alr с владельцем root:wheel и правами 2775
|
|
||||||
err = utils.EnsureTempDirWithRootOwner(tmpDir, 0o2775)
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn(gotext.Get("Unable to create temporary directory"), "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Создаем каталог dl с правами для группы wheel
|
|
||||||
dlDir := filepath.Join(tmpDir, "dl")
|
|
||||||
err = utils.EnsureTempDirWithRootOwner(dlDir, 0o2775)
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn(gotext.Get("Unable to create download directory"), "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Создаем каталог pkgs с правами для группы wheel
|
|
||||||
pkgsDir := filepath.Join(tmpDir, "pkgs")
|
|
||||||
err = utils.EnsureTempDirWithRootOwner(pkgsDir, 0o2775)
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn(gotext.Get("Unable to create packages directory"), "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Исправляем права на все существующие файлы в /tmp/alr, если там что-то есть
|
|
||||||
if _, err := os.Stat(tmpDir); err == nil {
|
|
||||||
slog.Info(gotext.Get("Fixing permissions on temporary files"))
|
|
||||||
|
|
||||||
// Проверяем, есть ли файлы в директории
|
|
||||||
entries, err := os.ReadDir(tmpDir)
|
|
||||||
if err == nil && len(entries) > 0 {
|
|
||||||
group := utils.GetPrivilegedGroup()
|
|
||||||
fixCmd := execWithPrivileges("chown", "-R", "root:"+group, tmpDir)
|
|
||||||
if fixErr := fixCmd.Run(); fixErr != nil {
|
|
||||||
slog.Warn(gotext.Get("Unable to fix file ownership"), "error", fixErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fixCmd = execWithPrivileges("chmod", "-R", "2775", tmpDir)
|
|
||||||
if fixErr := fixCmd.Run(); fixErr != nil {
|
|
||||||
slog.Warn(gotext.Get("Unable to fix file permissions"), "error", fixErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info(gotext.Get("Rebuilding cache"))
|
slog.Info(gotext.Get("Rebuilding cache"))
|
||||||
|
|
||||||
// Создаем директорию кэша с правильными правами
|
err = os.MkdirAll(paths.CacheDir, 0o755)
|
||||||
slog.Info(gotext.Get("Creating cache directory"))
|
|
||||||
err = utils.EnsureTempDirWithRootOwner(paths.CacheDir, 0o2775)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Unable to create new cache directory"), err)
|
slog.Error(gotext.Get("Unable to create new cache directory"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
deps, err = appbuilder.
|
cfg = config.New()
|
||||||
New(ctx).
|
db := database.New(cfg)
|
||||||
WithConfig().
|
err = db.Init(ctx)
|
||||||
WithDB().
|
|
||||||
WithReposForcePull().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.Exit(err, 1)
|
slog.Error(gotext.Get("Error initialization database"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
rs := repos.New(cfg, db)
|
||||||
|
err = rs.Pull(ctx, cfg.Repos(ctx))
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Error pulling repos"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
slog.Info(gotext.Get("Done"))
|
slog.Info(gotext.Get("Done"))
|
||||||
|
|
||||||
@@ -197,23 +76,3 @@ func FixCmd() *cli.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeWritableRecursive(path string) error {
|
|
||||||
return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := d.Info()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newMode := info.Mode() | 0o200
|
|
||||||
if d.IsDir() {
|
|
||||||
newMode |= 0o100
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Chmod(path, newMode)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
29
gen.go
29
gen.go
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/gen"
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenCmd() *cli.Command {
|
func GenCmd() *cli.Command {
|
||||||
@@ -61,29 +61,6 @@ func GenCmd() *cli.Command {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "aur",
|
|
||||||
Usage: gotext.Get("Generate a ALR script for an AUR package"),
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "name",
|
|
||||||
Aliases: []string{"n"},
|
|
||||||
Required: true,
|
|
||||||
Usage: gotext.Get("Name of the AUR package"),
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "version",
|
|
||||||
Aliases: []string{"v"},
|
|
||||||
Usage: gotext.Get("Version of the package (optional, uses latest if not specified)"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
return gen.AUR(os.Stdout, gen.AUROptions{
|
|
||||||
Name: c.String("name"),
|
|
||||||
Version: c.String("version"),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,251 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/format"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resolvedStructGenerator(buf *bytes.Buffer, fields []*ast.Field) {
|
|
||||||
contentTemplate := template.Must(template.New("").Parse(`
|
|
||||||
type {{ .EntityNameLower }}Resolved struct {
|
|
||||||
{{ .StructFields }}
|
|
||||||
}
|
|
||||||
`))
|
|
||||||
|
|
||||||
var structFieldsBuilder strings.Builder
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
for _, name := range field.Names {
|
|
||||||
// Поле с типом
|
|
||||||
fieldTypeStr := exprToString(field.Type)
|
|
||||||
|
|
||||||
// Структура поля
|
|
||||||
var buf bytes.Buffer
|
|
||||||
buf.WriteString("\t")
|
|
||||||
buf.WriteString(name.Name)
|
|
||||||
buf.WriteString(" ")
|
|
||||||
buf.WriteString(fieldTypeStr)
|
|
||||||
|
|
||||||
// Обработка json-тега
|
|
||||||
jsonTag := ""
|
|
||||||
if field.Tag != nil {
|
|
||||||
raw := strings.Trim(field.Tag.Value, "`")
|
|
||||||
tag := reflect.StructTag(raw)
|
|
||||||
if val := tag.Get("json"); val != "" {
|
|
||||||
jsonTag = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if jsonTag == "" {
|
|
||||||
jsonTag = strings.ToLower(name.Name)
|
|
||||||
}
|
|
||||||
buf.WriteString(fmt.Sprintf(" `json:\"%s\"`", jsonTag))
|
|
||||||
buf.WriteString("\n")
|
|
||||||
structFieldsBuilder.Write(buf.Bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params := struct {
|
|
||||||
EntityNameLower string
|
|
||||||
StructFields string
|
|
||||||
}{
|
|
||||||
EntityNameLower: "package",
|
|
||||||
StructFields: structFieldsBuilder.String(),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := contentTemplate.Execute(buf, params)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("execute template: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toResolvedFuncGenerator(buf *bytes.Buffer, fields []*ast.Field) {
|
|
||||||
contentTemplate := template.Must(template.New("").Parse(`
|
|
||||||
func {{ .EntityName }}ToResolved(src *{{ .EntityName }}) {{ .EntityNameLower }}Resolved {
|
|
||||||
return {{ .EntityNameLower }}Resolved{
|
|
||||||
{{ .Assignments }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`))
|
|
||||||
|
|
||||||
var assignmentsBuilder strings.Builder
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
for _, name := range field.Names {
|
|
||||||
var assignBuf bytes.Buffer
|
|
||||||
assignBuf.WriteString("\t\t")
|
|
||||||
assignBuf.WriteString(name.Name)
|
|
||||||
assignBuf.WriteString(": ")
|
|
||||||
if isOverridableField(field.Type) {
|
|
||||||
assignBuf.WriteString(fmt.Sprintf("src.%s.Resolved()", name.Name))
|
|
||||||
} else {
|
|
||||||
assignBuf.WriteString(fmt.Sprintf("src.%s", name.Name))
|
|
||||||
}
|
|
||||||
assignBuf.WriteString(",\n")
|
|
||||||
assignmentsBuilder.Write(assignBuf.Bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params := struct {
|
|
||||||
EntityName string
|
|
||||||
EntityNameLower string
|
|
||||||
Assignments string
|
|
||||||
}{
|
|
||||||
EntityName: "Package",
|
|
||||||
EntityNameLower: "package",
|
|
||||||
Assignments: assignmentsBuilder.String(),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := contentTemplate.Execute(buf, params)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("execute template: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveFuncGenerator(buf *bytes.Buffer, fields []*ast.Field) {
|
|
||||||
contentTemplate := template.Must(template.New("").Parse(`
|
|
||||||
func Resolve{{ .EntityName }}(pkg *{{ .EntityName }}, overrides []string) {
|
|
||||||
{{.Code}}}
|
|
||||||
`))
|
|
||||||
|
|
||||||
var codeBuilder strings.Builder
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
for _, name := range field.Names {
|
|
||||||
if isOverridableField(field.Type) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
buf.WriteString(fmt.Sprintf("\t\tpkg.%s.Resolve(overrides)\n", name.Name))
|
|
||||||
codeBuilder.Write(buf.Bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params := struct {
|
|
||||||
EntityName string
|
|
||||||
Code string
|
|
||||||
}{
|
|
||||||
EntityName: "Package",
|
|
||||||
Code: codeBuilder.String(),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := contentTemplate.Execute(buf, params)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("execute template: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
path := os.Getenv("GOFILE")
|
|
||||||
if path == "" {
|
|
||||||
log.Fatal("GOFILE must be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
node, err := parser.ParseFile(fset, path, nil, parser.AllErrors)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("parsing file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
entityName := "Package" // имя структуры, которую анализируем
|
|
||||||
|
|
||||||
found := false
|
|
||||||
|
|
||||||
fields := make([]*ast.Field, 0)
|
|
||||||
|
|
||||||
// Ищем структуру с нужным именем
|
|
||||||
for _, decl := range node.Decls {
|
|
||||||
genDecl, ok := decl.(*ast.GenDecl)
|
|
||||||
if !ok || genDecl.Tok != token.TYPE {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, spec := range genDecl.Specs {
|
|
||||||
typeSpec := spec.(*ast.TypeSpec)
|
|
||||||
if typeSpec.Name.Name != entityName {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
structType, ok := typeSpec.Type.(*ast.StructType)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fields = structType.Fields.List
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
log.Fatalf("struct %s not found", entityName)
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
buf.WriteString("// DO NOT EDIT MANUALLY. This file is generated.\n")
|
|
||||||
buf.WriteString("package alrsh")
|
|
||||||
|
|
||||||
resolvedStructGenerator(&buf, fields)
|
|
||||||
toResolvedFuncGenerator(&buf, fields)
|
|
||||||
resolveFuncGenerator(&buf, fields)
|
|
||||||
|
|
||||||
// Форматируем вывод
|
|
||||||
formatted, err := format.Source(buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("formatting: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outPath := strings.TrimSuffix(path, ".go") + "_gen.go"
|
|
||||||
outFile, err := os.Create(outPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("create file: %v", err)
|
|
||||||
}
|
|
||||||
_, err = outFile.Write(formatted)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("writing output: %v", err)
|
|
||||||
}
|
|
||||||
outFile.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func exprToString(expr ast.Expr) string {
|
|
||||||
if t, ok := expr.(*ast.IndexExpr); ok {
|
|
||||||
if ident, ok := t.X.(*ast.Ident); ok && ident.Name == "OverridableField" {
|
|
||||||
return exprToString(t.Index) // T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := format.Node(&buf, token.NewFileSet(), expr); err != nil {
|
|
||||||
return "<invalid>"
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func isOverridableField(expr ast.Expr) bool {
|
|
||||||
indexExpr, ok := expr.(*ast.IndexExpr)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
ident, ok := indexExpr.X.(*ast.Ident)
|
|
||||||
return ok && ident.Name == "OverridableField"
|
|
||||||
}
|
|
||||||
@@ -1,416 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/format"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"golang.org/x/text/cases"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MethodInfo struct {
|
|
||||||
Name string
|
|
||||||
Params []ParamInfo
|
|
||||||
Results []ResultInfo
|
|
||||||
EntityName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParamInfo struct {
|
|
||||||
Name string
|
|
||||||
Type string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultInfo struct {
|
|
||||||
Name string
|
|
||||||
Type string
|
|
||||||
Index int
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractImports(node *ast.File) []string {
|
|
||||||
var imports []string
|
|
||||||
for _, imp := range node.Imports {
|
|
||||||
if imp.Path.Value != "" {
|
|
||||||
imports = append(imports, imp.Path.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return imports
|
|
||||||
}
|
|
||||||
|
|
||||||
func output(path string, buf bytes.Buffer) {
|
|
||||||
formatted, err := format.Source(buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("formatting: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outPath := strings.TrimSuffix(path, ".go") + "_gen.go"
|
|
||||||
outFile, err := os.Create(outPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("create file: %v", err)
|
|
||||||
}
|
|
||||||
_, err = outFile.Write(formatted)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("writing output: %v", err)
|
|
||||||
}
|
|
||||||
outFile.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
path := os.Getenv("GOFILE")
|
|
||||||
if path == "" {
|
|
||||||
log.Fatal("GOFILE must be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(os.Args) < 2 {
|
|
||||||
log.Fatal("At least one entity name must be provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
entityNames := os.Args[1:]
|
|
||||||
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
node, err := parser.ParseFile(fset, path, nil, parser.AllErrors)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("parsing file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
packageName := node.Name.Name
|
|
||||||
|
|
||||||
// Find all specified entities
|
|
||||||
entityData := make(map[string][]*ast.Field)
|
|
||||||
|
|
||||||
for _, decl := range node.Decls {
|
|
||||||
genDecl, ok := decl.(*ast.GenDecl)
|
|
||||||
if !ok || genDecl.Tok != token.TYPE {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, spec := range genDecl.Specs {
|
|
||||||
typeSpec := spec.(*ast.TypeSpec)
|
|
||||||
for _, entityName := range entityNames {
|
|
||||||
if typeSpec.Name.Name == entityName {
|
|
||||||
interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
|
|
||||||
if !ok {
|
|
||||||
log.Fatalf("entity %s is not an interface", entityName)
|
|
||||||
}
|
|
||||||
entityData[entityName] = interfaceType.Methods.List
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify all entities were found
|
|
||||||
for _, entityName := range entityNames {
|
|
||||||
if _, found := entityData[entityName]; !found {
|
|
||||||
log.Fatalf("interface %s not found", entityName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
buf.WriteString(`
|
|
||||||
// DO NOT EDIT MANUALLY. This file is generated.
|
|
||||||
|
|
||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
|
|
||||||
`)
|
|
||||||
|
|
||||||
buf.WriteString(fmt.Sprintf("package %s\n", packageName))
|
|
||||||
|
|
||||||
// Generate base structures for all entities
|
|
||||||
baseStructs(&buf, entityNames, extractImports(node))
|
|
||||||
|
|
||||||
// Generate method-specific code for each entity
|
|
||||||
for _, entityName := range entityNames {
|
|
||||||
methods := parseMethodsFromFields(entityName, entityData[entityName])
|
|
||||||
argsGen(&buf, methods)
|
|
||||||
}
|
|
||||||
|
|
||||||
output(path, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseMethodsFromFields(entityName string, fields []*ast.Field) []MethodInfo {
|
|
||||||
var methods []MethodInfo
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
if len(field.Names) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
methodName := field.Names[0].Name
|
|
||||||
funcType, ok := field.Type.(*ast.FuncType)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
method := MethodInfo{
|
|
||||||
Name: methodName,
|
|
||||||
EntityName: entityName,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parameters, excluding context.Context
|
|
||||||
if funcType.Params != nil {
|
|
||||||
for i, param := range funcType.Params.List {
|
|
||||||
paramType := typeToString(param.Type)
|
|
||||||
// Skip context.Context parameters
|
|
||||||
if paramType == "context.Context" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(param.Names) == 0 {
|
|
||||||
method.Params = append(method.Params, ParamInfo{
|
|
||||||
Name: fmt.Sprintf("Arg%d", i),
|
|
||||||
Type: paramType,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
for _, name := range param.Names {
|
|
||||||
method.Params = append(method.Params, ParamInfo{
|
|
||||||
Name: cases.Title(language.Und, cases.NoLower).String(name.Name),
|
|
||||||
Type: paramType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse results
|
|
||||||
if funcType.Results != nil {
|
|
||||||
resultIndex := 0
|
|
||||||
for _, result := range funcType.Results.List {
|
|
||||||
resultType := typeToString(result.Type)
|
|
||||||
if resultType == "error" {
|
|
||||||
continue // Skip error in response struct
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result.Names) == 0 {
|
|
||||||
method.Results = append(method.Results, ResultInfo{
|
|
||||||
Name: fmt.Sprintf("Result%d", resultIndex),
|
|
||||||
Type: resultType,
|
|
||||||
Index: resultIndex,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
for _, name := range result.Names {
|
|
||||||
method.Results = append(method.Results, ResultInfo{
|
|
||||||
Name: cases.Title(language.Und, cases.NoLower).String(name.Name),
|
|
||||||
Type: resultType,
|
|
||||||
Index: resultIndex,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resultIndex++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
methods = append(methods, method)
|
|
||||||
}
|
|
||||||
|
|
||||||
return methods
|
|
||||||
}
|
|
||||||
|
|
||||||
func argsGen(buf *bytes.Buffer, methods []MethodInfo) {
|
|
||||||
// Add template functions first
|
|
||||||
funcMap := template.FuncMap{
|
|
||||||
"lowerFirst": func(s string) string {
|
|
||||||
if len(s) == 0 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return strings.ToLower(s[:1]) + s[1:]
|
|
||||||
},
|
|
||||||
"zeroValue": func(typeName string) string {
|
|
||||||
typeName = strings.TrimSpace(typeName)
|
|
||||||
|
|
||||||
switch typeName {
|
|
||||||
case "string":
|
|
||||||
return "\"\""
|
|
||||||
case "int", "int8", "int16", "int32", "int64":
|
|
||||||
return "0"
|
|
||||||
case "uint", "uint8", "uint16", "uint32", "uint64":
|
|
||||||
return "0"
|
|
||||||
case "float32", "float64":
|
|
||||||
return "0.0"
|
|
||||||
case "bool":
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(typeName, "*") {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(typeName, "[]") ||
|
|
||||||
strings.HasPrefix(typeName, "map[") ||
|
|
||||||
strings.HasPrefix(typeName, "chan ") {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
|
|
||||||
if typeName == "interface{}" {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
|
|
||||||
// If external type: pkg.Type
|
|
||||||
if strings.Contains(typeName, ".") {
|
|
||||||
return typeName + "{}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// If starts with uppercase — likely struct
|
|
||||||
if len(typeName) > 0 && unicode.IsUpper(rune(typeName[0])) {
|
|
||||||
return typeName + "{}"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "nil"
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
argsTemplate := template.Must(template.New("args").Funcs(funcMap).Parse(`
|
|
||||||
{{range .}}
|
|
||||||
type {{.EntityName}}{{.Name}}Args struct {
|
|
||||||
{{range .Params}} {{.Name}} {{.Type}}
|
|
||||||
{{end}}}
|
|
||||||
|
|
||||||
type {{.EntityName}}{{.Name}}Resp struct {
|
|
||||||
{{range .Results}} {{.Name}} {{.Type}}
|
|
||||||
{{end}}}
|
|
||||||
|
|
||||||
func (s *{{.EntityName}}RPC) {{.Name}}(ctx context.Context, {{range $i, $p := .Params}}{{if $i}}, {{end}}{{lowerFirst $p.Name}} {{$p.Type}}{{end}}) ({{range $i, $r := .Results}}{{if $i}}, {{end}}{{$r.Type}}{{end}}{{if .Results}}, {{end}}error) {
|
|
||||||
var resp *{{.EntityName}}{{.Name}}Resp
|
|
||||||
err := s.client.Call("Plugin.{{.Name}}", &{{.EntityName}}{{.Name}}Args{
|
|
||||||
{{range .Params}} {{.Name}}: {{lowerFirst .Name}},
|
|
||||||
{{end}} }, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return {{range $i, $r := .Results}}{{if $i}}, {{end}}{{zeroValue $r.Type}}{{end}}{{if .Results}}, {{end}}err
|
|
||||||
}
|
|
||||||
return {{range $i, $r := .Results}}{{if $i}}, {{end}}resp.{{$r.Name}}{{end}}{{if .Results}}, {{end}}nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *{{.EntityName}}RPCServer) {{.Name}}(args *{{.EntityName}}{{.Name}}Args, resp *{{.EntityName}}{{.Name}}Resp) error {
|
|
||||||
{{if .Results}}{{range $i, $r := .Results}}{{if $i}}, {{end}}{{lowerFirst $r.Name}}{{end}}, err := {{else}}err := {{end}}s.Impl.{{.Name}}(context.Background(),{{range $i, $p := .Params}}{{if $i}}, {{end}}args.{{$p.Name}}{{end}})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
{{if .Results}}*resp = {{.EntityName}}{{.Name}}Resp{
|
|
||||||
{{range .Results}} {{.Name}}: {{lowerFirst .Name}},
|
|
||||||
{{end}} }
|
|
||||||
{{else}}*resp = {{.EntityName}}{{.Name}}Resp{}
|
|
||||||
{{end}}return nil
|
|
||||||
}
|
|
||||||
{{end}}
|
|
||||||
`))
|
|
||||||
|
|
||||||
err := argsTemplate.Execute(buf, methods)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("execute args template: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeToString(expr ast.Expr) string {
|
|
||||||
switch t := expr.(type) {
|
|
||||||
case *ast.Ident:
|
|
||||||
return t.Name
|
|
||||||
case *ast.StarExpr:
|
|
||||||
return "*" + typeToString(t.X)
|
|
||||||
case *ast.ArrayType:
|
|
||||||
return "[]" + typeToString(t.Elt)
|
|
||||||
case *ast.SelectorExpr:
|
|
||||||
xStr := typeToString(t.X)
|
|
||||||
if xStr == "context" && t.Sel.Name == "Context" {
|
|
||||||
return "context.Context"
|
|
||||||
}
|
|
||||||
return xStr + "." + t.Sel.Name
|
|
||||||
case *ast.InterfaceType:
|
|
||||||
return "interface{}"
|
|
||||||
default:
|
|
||||||
return "interface{}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func baseStructs(buf *bytes.Buffer, entityNames, imports []string) {
|
|
||||||
// Ensure "context" is included in imports
|
|
||||||
updatedImports := imports
|
|
||||||
hasContext := false
|
|
||||||
for _, imp := range imports {
|
|
||||||
if strings.Contains(imp, `"context"`) {
|
|
||||||
hasContext = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !hasContext {
|
|
||||||
updatedImports = append(updatedImports, `"context"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
contentTemplate := template.Must(template.New("").Parse(`
|
|
||||||
import (
|
|
||||||
"net/rpc"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-plugin"
|
|
||||||
{{range .Imports}} {{.}}
|
|
||||||
{{end}}
|
|
||||||
)
|
|
||||||
|
|
||||||
{{range .EntityNames}}
|
|
||||||
type {{ . }}Plugin struct {
|
|
||||||
Impl {{ . }}
|
|
||||||
}
|
|
||||||
|
|
||||||
type {{ . }}RPCServer struct {
|
|
||||||
Impl {{ . }}
|
|
||||||
}
|
|
||||||
|
|
||||||
type {{ . }}RPC struct {
|
|
||||||
client *rpc.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *{{ . }}Plugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
|
||||||
return &{{ . }}RPC{client: c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *{{ . }}Plugin) Server(*plugin.MuxBroker) (interface{}, error) {
|
|
||||||
return &{{ . }}RPCServer{Impl: p.Impl}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
{{end}}
|
|
||||||
`))
|
|
||||||
err := contentTemplate.Execute(buf, struct {
|
|
||||||
EntityNames []string
|
|
||||||
Imports []string
|
|
||||||
}{
|
|
||||||
EntityNames: entityNames,
|
|
||||||
Imports: updatedImports,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("execute template: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
87
go.mod
87
go.mod
@@ -1,49 +1,41 @@
|
|||||||
module gitea.plemya-x.ru/Plemya-x/ALR
|
module gitea.plemya-x.ru/Plemya-x/ALR
|
||||||
|
|
||||||
go 1.24.4
|
go 1.22
|
||||||
|
|
||||||
|
toolchain go1.23.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.2-0.20250408104831-427aaa7713c3
|
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.1
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||||
github.com/PuerkitoBio/purell v1.2.0
|
github.com/PuerkitoBio/purell v1.2.0
|
||||||
github.com/alecthomas/chroma/v2 v2.9.1
|
github.com/alecthomas/chroma/v2 v2.9.1
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1
|
|
||||||
github.com/charmbracelet/bubbles v0.20.0
|
github.com/charmbracelet/bubbles v0.20.0
|
||||||
github.com/charmbracelet/bubbletea v1.2.4
|
github.com/charmbracelet/bubbletea v1.2.4
|
||||||
github.com/charmbracelet/lipgloss v1.0.0
|
github.com/charmbracelet/lipgloss v1.0.0
|
||||||
github.com/charmbracelet/log v0.4.0
|
github.com/charmbracelet/log v0.4.0
|
||||||
github.com/go-git/go-billy/v5 v5.6.0
|
github.com/go-git/go-billy/v5 v5.5.0
|
||||||
github.com/go-git/go-git/v5 v5.13.0
|
github.com/go-git/go-git/v5 v5.12.0
|
||||||
github.com/goccy/go-yaml v1.18.0
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/goreleaser/nfpm/v2 v2.41.0
|
github.com/goreleaser/nfpm/v2 v2.41.0
|
||||||
github.com/hashicorp/go-hclog v0.14.1
|
|
||||||
github.com/hashicorp/go-plugin v1.6.3
|
|
||||||
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08
|
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08
|
||||||
github.com/knadh/koanf/parsers/toml/v2 v2.2.0
|
github.com/jmoiron/sqlx v1.3.5
|
||||||
github.com/knadh/koanf/providers/confmap v1.0.0
|
|
||||||
github.com/knadh/koanf/providers/env v1.1.0
|
|
||||||
github.com/knadh/koanf/providers/file v1.2.0
|
|
||||||
github.com/knadh/koanf/v2 v2.2.1
|
|
||||||
github.com/leonelquinteros/gotext v1.7.0
|
github.com/leonelquinteros/gotext v1.7.0
|
||||||
github.com/mattn/go-isatty v0.0.20
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8
|
github.com/mholt/archiver/v4 v4.0.0-alpha.8
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/muesli/reflow v0.3.0
|
github.com/muesli/reflow v0.3.0
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4
|
github.com/pelletier/go-toml/v2 v2.1.0
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/urfave/cli/v2 v2.25.7
|
github.com/urfave/cli/v2 v2.25.7
|
||||||
github.com/vmihailenco/msgpack/v5 v5.3.5
|
github.com/vmihailenco/msgpack/v5 v5.3.5
|
||||||
go.alt-gnome.ru/capytest v0.0.3-0.20250706082755-f20413e052f9
|
|
||||||
go.alt-gnome.ru/capytest/providers/podman v0.0.3-0.20250706082755-f20413e052f9
|
|
||||||
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4
|
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4
|
||||||
golang.org/x/crypto v0.36.0
|
golang.org/x/crypto v0.27.0
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb
|
||||||
golang.org/x/sys v0.33.0
|
golang.org/x/sys v0.29.0
|
||||||
golang.org/x/text v0.23.0
|
golang.org/x/text v0.21.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
modernc.org/sqlite v1.25.0
|
modernc.org/sqlite v1.25.0
|
||||||
mvdan.cc/sh/v3 v3.10.0
|
mvdan.cc/sh/v3 v3.10.0
|
||||||
xorm.io/xorm v1.3.9
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -53,7 +45,7 @@ require (
|
|||||||
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
github.com/ProtonMail/go-crypto v1.0.0 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
|
||||||
@@ -64,96 +56,68 @@ require (
|
|||||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
github.com/cloudflare/circl v1.6.1 // indirect
|
github.com/cloudflare/circl v1.3.8 // indirect
|
||||||
github.com/connesc/cipherio v0.2.1 // indirect
|
github.com/connesc/cipherio v0.2.1 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||||
github.com/creack/pty v1.1.24 // indirect
|
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||||
github.com/dsnet/compress v0.0.1 // indirect
|
github.com/dsnet/compress v0.0.1 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/fatih/color v1.7.0 // indirect
|
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
|
||||||
github.com/gkampitakis/ciinfo v0.3.2 // indirect
|
|
||||||
github.com/gkampitakis/go-diff v1.3.2 // indirect
|
|
||||||
github.com/gkampitakis/go-snaps v0.5.13 // indirect
|
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
|
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/goccy/go-json v0.8.1 // indirect
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a // indirect
|
github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.4.0 // indirect
|
||||||
github.com/goreleaser/chglog v0.6.1 // indirect
|
github.com/goreleaser/chglog v0.6.1 // indirect
|
||||||
github.com/goreleaser/fileglob v1.3.0 // indirect
|
github.com/goreleaser/fileglob v1.3.0 // indirect
|
||||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
|
||||||
github.com/huandu/xstrings v1.3.3 // indirect
|
github.com/huandu/xstrings v1.3.3 // indirect
|
||||||
github.com/imdario/mergo v0.3.16 // indirect
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/compress v1.17.11 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||||
github.com/knadh/koanf/maps v0.1.2 // indirect
|
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
|
||||||
github.com/kr/text v0.2.0 // indirect
|
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/maruel/natural v1.1.1 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/termenv v0.15.2 // indirect
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
||||||
github.com/oklog/run v1.0.0 // indirect
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
github.com/shopspring/decimal v1.2.0 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
github.com/skeema/knownhosts v1.2.2 // indirect
|
||||||
github.com/spf13/cast v1.7.1 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
|
||||||
github.com/therootcompany/xz v1.0.1 // indirect
|
github.com/therootcompany/xz v1.0.1 // indirect
|
||||||
github.com/tidwall/gjson v1.18.0 // indirect
|
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
|
||||||
github.com/tidwall/sjson v1.2.5 // indirect
|
|
||||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
|
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
|
||||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||||
golang.org/x/mod v0.19.0 // indirect
|
golang.org/x/mod v0.18.0 // indirect
|
||||||
golang.org/x/net v0.38.0 // indirect
|
golang.org/x/net v0.26.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
golang.org/x/term v0.30.0 // indirect
|
golang.org/x/term v0.28.0 // indirect
|
||||||
golang.org/x/tools v0.23.0 // indirect
|
golang.org/x/tools v0.22.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
|
||||||
google.golang.org/grpc v1.67.3 // indirect
|
|
||||||
google.golang.org/protobuf v1.36.1 // indirect
|
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
lukechampine.com/uint128 v1.2.0 // indirect
|
lukechampine.com/uint128 v1.2.0 // indirect
|
||||||
modernc.org/cc/v3 v3.40.0 // indirect
|
modernc.org/cc/v3 v3.40.0 // indirect
|
||||||
modernc.org/ccgo/v3 v3.16.13 // indirect
|
modernc.org/ccgo/v3 v3.16.13 // indirect
|
||||||
@@ -163,5 +127,4 @@ require (
|
|||||||
modernc.org/opt v0.1.3 // indirect
|
modernc.org/opt v0.1.3 // indirect
|
||||||
modernc.org/strutil v1.1.3 // indirect
|
modernc.org/strutil v1.1.3 // indirect
|
||||||
modernc.org/token v1.0.1 // indirect
|
modernc.org/token v1.0.1 // indirect
|
||||||
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
233
go.sum
233
go.sum
@@ -17,10 +17,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
|||||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.1 h1:c7F4OsyQbiVpSOrYGMrNsRL37BwoOfrgoKxAwULBKZo=
|
||||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.1/go.mod h1:iKQM6uttMJgE5CFrPw6SQqAV7TKtlJNICRAie/dTciw=
|
||||||
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.2-0.20250408104831-427aaa7713c3 h1:56BjRJJ2Sv50DfSvNUydUMJwwFuiBMWC1uYtH2GYjk8=
|
|
||||||
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.2-0.20250408104831-427aaa7713c3/go.mod h1:iKQM6uttMJgE5CFrPw6SQqAV7TKtlJNICRAie/dTciw=
|
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
|
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
|
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
|
||||||
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
||||||
@@ -41,8 +39,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
|
|||||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
||||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||||
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
|
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||||
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
|
github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
|
||||||
@@ -65,16 +63,13 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
|
|||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
|
||||||
github.com/bodgit/plumbing v1.2.0 h1:gg4haxoKphLjml+tgnecR4yLBV5zo4HAZGCtAh3xCzM=
|
github.com/bodgit/plumbing v1.2.0 h1:gg4haxoKphLjml+tgnecR4yLBV5zo4HAZGCtAh3xCzM=
|
||||||
github.com/bodgit/plumbing v1.2.0/go.mod h1:b9TeRi7Hvc6Y05rjm8VML3+47n4XTZPtQ/5ghqic2n8=
|
github.com/bodgit/plumbing v1.2.0/go.mod h1:b9TeRi7Hvc6Y05rjm8VML3+47n4XTZPtQ/5ghqic2n8=
|
||||||
github.com/bodgit/sevenzip v1.3.0 h1:1ljgELgtHqvgIp8W8kgeEGHIWP4ch3xGI8uOBZgLVKY=
|
github.com/bodgit/sevenzip v1.3.0 h1:1ljgELgtHqvgIp8W8kgeEGHIWP4ch3xGI8uOBZgLVKY=
|
||||||
github.com/bodgit/sevenzip v1.3.0/go.mod h1:omwNcgZTEooWM8gA/IJ2Nk/+ZQ94+GsytRzOJJ8FBlM=
|
github.com/bodgit/sevenzip v1.3.0/go.mod h1:omwNcgZTEooWM8gA/IJ2Nk/+ZQ94+GsytRzOJJ8FBlM=
|
||||||
github.com/bodgit/windows v1.0.0 h1:rLQ/XjsleZvx4fR1tB/UxQrK+SJ2OFHzfPjLWWOhDIA=
|
github.com/bodgit/windows v1.0.0 h1:rLQ/XjsleZvx4fR1tB/UxQrK+SJ2OFHzfPjLWWOhDIA=
|
||||||
github.com/bodgit/windows v1.0.0/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
github.com/bodgit/windows v1.0.0/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||||
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
|
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
|
|
||||||
github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8=
|
github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8=
|
||||||
github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk=
|
github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk=
|
||||||
github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM=
|
github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM=
|
||||||
@@ -98,18 +93,18 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
|||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
||||||
|
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||||
github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEycw=
|
github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEycw=
|
||||||
github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA=
|
github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
|
||||||
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
|
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -120,53 +115,36 @@ github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5Jflh
|
|||||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug=
|
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||||
github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
|
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
|
||||||
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
|
|
||||||
github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
|
|
||||||
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
|
|
||||||
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
|
|
||||||
github.com/gkampitakis/go-snaps v0.5.13 h1:Hhjmvv1WboSCxkR9iU2mj5PQ8tsz/y8ECGrIbjjPF8Q=
|
|
||||||
github.com/gkampitakis/go-snaps v0.5.13/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
|
|
||||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
|
||||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
|
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||||
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
|
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E=
|
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
||||||
github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw=
|
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||||
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
||||||
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
|
||||||
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/goccy/go-json v0.8.1 h1:4/Wjm0JIJaTDm8K1KcGrLHJoa8EsJ13YWeX+6Kfq6uI=
|
|
||||||
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
|
||||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
@@ -183,10 +161,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@@ -195,10 +169,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
|||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
@@ -211,8 +183,8 @@ github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a/go.mod h1:uqVAUVQ
|
|||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||||
@@ -225,22 +197,14 @@ github.com/goreleaser/nfpm/v2 v2.41.0 h1:JyMzS/EwqaWbFs+7Z9oZ4Hkk4or00gUTqwm9Dgr
|
|||||||
github.com/goreleaser/nfpm/v2 v2.41.0/go.mod h1:VPc5kF5OgfA+BosV/A2aB+Vg34honjWvp0Vt8ogsSi0=
|
github.com/goreleaser/nfpm/v2 v2.41.0/go.mod h1:VPc5kF5OgfA+BosV/A2aB+Vg34honjWvp0Vt8ogsSi0=
|
||||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
|
|
||||||
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg=
|
|
||||||
github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
|
||||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
||||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
@@ -251,10 +215,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
|
|||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 h1:wMeVzrPO3mfHIWLZtDcSaGAe2I4PW9B/P5nMkRSwCAc=
|
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 h1:wMeVzrPO3mfHIWLZtDcSaGAe2I4PW9B/P5nMkRSwCAc=
|
||||||
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
||||||
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
|
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||||
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
|
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
@@ -270,18 +232,6 @@ github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90
|
|||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
|
|
||||||
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
|
||||||
github.com/knadh/koanf/parsers/toml/v2 v2.2.0 h1:2nV7tHYJ5OZy2BynQ4mOJ6k5bDqbbCzRERLUKBytz3A=
|
|
||||||
github.com/knadh/koanf/parsers/toml/v2 v2.2.0/go.mod h1:JpjTeK1Ge1hVX0wbof5DMCuDBriR8bWgeQP98eeOZpI=
|
|
||||||
github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE=
|
|
||||||
github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
|
|
||||||
github.com/knadh/koanf/providers/env v1.1.0 h1:U2VXPY0f+CsNDkvdsG8GcsnK4ah85WwWyJgef9oQMSc=
|
|
||||||
github.com/knadh/koanf/providers/env v1.1.0/go.mod h1:QhHHHZ87h9JxJAn2czdEl6pdkNnDh/JS1Vtsyt65hTY=
|
|
||||||
github.com/knadh/koanf/providers/file v1.2.0 h1:hrUJ6Y9YOA49aNu/RSYzOTFlqzXSCpmYIDXI7OJU6+U=
|
|
||||||
github.com/knadh/koanf/providers/file v1.2.0/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
|
|
||||||
github.com/knadh/koanf/v2 v2.2.1 h1:jaleChtw85y3UdBnI0wCqcg1sj1gPoz6D3caGNHtrNE=
|
|
||||||
github.com/knadh/koanf/v2 v2.2.1/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
@@ -291,18 +241,16 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leonelquinteros/gotext v1.7.0 h1:jcJmF4AXqyamP7vuw2MMIKs+O3jAEmvrc5JQiI8Ht/8=
|
github.com/leonelquinteros/gotext v1.7.0 h1:jcJmF4AXqyamP7vuw2MMIKs+O3jAEmvrc5JQiI8Ht/8=
|
||||||
github.com/leonelquinteros/gotext v1.7.0/go.mod h1:qJdoQuERPpccw7L70uoU+K/BvTfRBHYsisCQyFLXyvw=
|
github.com/leonelquinteros/gotext v1.7.0/go.mod h1:qJdoQuERPpccw7L70uoU+K/BvTfRBHYsisCQyFLXyvw=
|
||||||
|
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||||
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
|
|
||||||
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
|
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
@@ -311,6 +259,7 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei
|
|||||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||||
@@ -325,11 +274,6 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
|||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
@@ -340,21 +284,14 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo
|
|||||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
|
||||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
|
||||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
||||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -368,7 +305,6 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
|||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
@@ -378,42 +314,32 @@ github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtC
|
|||||||
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
|
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
|
||||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
|
||||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||||
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
||||||
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
||||||
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
||||||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
|
||||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
|
||||||
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
||||||
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
|
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
|
||||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
|
||||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
|
||||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
|
||||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
|
||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
|
||||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
|
||||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
|
||||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
|
||||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
|
||||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
|
||||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
@@ -432,12 +358,6 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsr
|
|||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8=
|
gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8=
|
||||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
|
gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
|
||||||
go.alt-gnome.ru/capytest v0.0.2 h1:clmvIqmYS86hhA1rsvivSSPpfOFkJTpbn38EQP7I3E8=
|
|
||||||
go.alt-gnome.ru/capytest v0.0.2/go.mod h1:lvxPx3H6h+LPnStBFblgoT2wkjv0wbug3S14troykEg=
|
|
||||||
go.alt-gnome.ru/capytest v0.0.3-0.20250706082755-f20413e052f9 h1:NST+V5LV/eLgs0p6PsuvfHiZ4UrIWqftCdifO8zgg0g=
|
|
||||||
go.alt-gnome.ru/capytest v0.0.3-0.20250706082755-f20413e052f9/go.mod h1:qiM8LARP+JBZr5mrDoVylOoqjrN0MAzvZ21NR9qMc0Y=
|
|
||||||
go.alt-gnome.ru/capytest/providers/podman v0.0.3-0.20250706082755-f20413e052f9 h1:VZclgdJxARvhZ6PIWWW2hQ6Ge4XeE36pzUr/U/y62bE=
|
|
||||||
go.alt-gnome.ru/capytest/providers/podman v0.0.3-0.20250706082755-f20413e052f9/go.mod h1:Wpq1Ny3eMzADJpMJArA2TZGZbsviUBmawtEPcxnoerg=
|
|
||||||
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4 h1:Ep54XceQlKhcCHl9awG+wWP4kz4kIP3c3Lzw/Gc/zwY=
|
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4 h1:Ep54XceQlKhcCHl9awG+wWP4kz4kIP3c3Lzw/Gc/zwY=
|
||||||
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4/go.mod h1:/7PNW7nFnDR5W7UXZVc04gdVLR/wBNgkm33KgIz0OBk=
|
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4/go.mod h1:/7PNW7nFnDR5W7UXZVc04gdVLR/wBNgkm33KgIz0OBk=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
@@ -453,8 +373,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
|
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||||
|
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -463,8 +385,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE
|
|||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -483,11 +405,11 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||||
|
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
@@ -504,8 +426,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
|
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||||
|
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -518,10 +442,10 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -531,7 +455,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -547,14 +470,18 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
|
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||||
|
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -563,8 +490,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -592,8 +521,9 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
|||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||||
|
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -623,8 +553,6 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx
|
|||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
@@ -632,25 +560,14 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
|||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8=
|
|
||||||
google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
|
||||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
@@ -695,7 +612,3 @@ mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY=
|
|||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 h1:bvLlAPW1ZMTWA32LuZMBEGHAUOcATZjzHcotf3SWweM=
|
|
||||||
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
|
||||||
xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU=
|
|
||||||
xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=
|
|
||||||
|
|||||||
13
helper.go
13
helper.go
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -30,7 +30,6 @@ import (
|
|||||||
"mvdan.cc/sh/v3/expand"
|
"mvdan.cc/sh/v3/expand"
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/helpers"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/helpers"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
||||||
@@ -72,17 +71,19 @@ func HelperCmd() *cli.Command {
|
|||||||
helper, ok := helpers.Helpers[c.Args().First()]
|
helper, ok := helpers.Helpers[c.Args().First()]
|
||||||
if !ok {
|
if !ok {
|
||||||
slog.Error(gotext.Get("No such helper command"), "name", c.Args().First())
|
slog.Error(gotext.Get("No such helper command"), "name", c.Args().First())
|
||||||
return cli.Exit(gotext.Get("No such helper command"), 1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error getting working directory"), err)
|
slog.Error(gotext.Get("Error getting working directory"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := distro.ParseOSRelease(ctx)
|
info, err := distro.ParseOSRelease(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error parsing os-release file"), err)
|
slog.Error(gotext.Get("Error getting working directory"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
hc := interp.HandlerContext{
|
hc := interp.HandlerContext{
|
||||||
|
|||||||
119
info.go
119
info.go
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -21,18 +21,20 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
|
||||||
"github.com/jeandeaual/go-locale"
|
"github.com/jeandeaual/go-locale"
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
||||||
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
|
database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InfoCmd() *cli.Command {
|
func InfoCmd() *cli.Command {
|
||||||
@@ -46,60 +48,68 @@ func InfoCmd() *cli.Command {
|
|||||||
Usage: gotext.Get("Show all information, not just for the current distro"),
|
Usage: gotext.Get("Show all information, not just for the current distro"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
BashComplete: cliutils.BashCompleteWithError(func(c *cli.Context) error {
|
BashComplete: func(c *cli.Context) {
|
||||||
|
|
||||||
ctx := c.Context
|
ctx := c.Context
|
||||||
deps, err := appbuilder.
|
cfg := config.New()
|
||||||
New(ctx).
|
db := database.New(cfg)
|
||||||
WithConfig().
|
err := db.Init(ctx)
|
||||||
WithDB().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error initialization database"), "err", err)
|
||||||
}
|
os.Exit(1)
|
||||||
defer deps.Defer()
|
}
|
||||||
|
|
||||||
result, err := deps.DB.GetPkgs(c.Context, "true")
|
result, err := db.GetPkgs(c.Context, "true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error getting packages"), err)
|
slog.Error(gotext.Get("Error getting packages"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer result.Close()
|
||||||
|
|
||||||
|
for result.Next() {
|
||||||
|
var pkg database.Package
|
||||||
|
err = result.StructScan(&pkg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Error iterating over packages"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range result {
|
|
||||||
fmt.Println(pkg.Name)
|
fmt.Println(pkg.Name)
|
||||||
}
|
}
|
||||||
return nil
|
},
|
||||||
}),
|
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
// Запуск от текущего пользователя
|
ctx := c.Context
|
||||||
|
|
||||||
|
cfg := config.New()
|
||||||
|
db := database.New(cfg)
|
||||||
|
err := db.Init(ctx)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Error initialization database"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
rs := repos.New(cfg, db)
|
||||||
|
|
||||||
args := c.Args()
|
args := c.Args()
|
||||||
if args.Len() < 1 {
|
if args.Len() < 1 {
|
||||||
return cli.Exit(gotext.Get("Command info expected at least 1 argument, got %d", args.Len()), 1)
|
slog.Error(gotext.Get("Command info expected at least 1 argument, got %d", args.Len()))
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := c.Context
|
if cfg.AutoPull(ctx) {
|
||||||
|
err := rs.Pull(ctx, cfg.Repos(ctx))
|
||||||
deps, err := appbuilder.
|
|
||||||
New(ctx).
|
|
||||||
WithConfig().
|
|
||||||
WithDB().
|
|
||||||
WithDistroInfo().
|
|
||||||
WithRepos().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.Exit(err, 1)
|
slog.Error(gotext.Get("Error pulling repos"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
rs := deps.Repos
|
|
||||||
|
|
||||||
found, _, err := rs.FindPkgs(ctx, args.Slice())
|
found, _, err := rs.FindPkgs(ctx, args.Slice())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error finding packages"), err)
|
slog.Error(gotext.Get("Error finding packages"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(found) == 0 {
|
if len(found) == 0 {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Package not found"), err)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgs := cliutils.FlattenPkgs(ctx, found, "show", c.Bool("interactive"))
|
pkgs := cliutils.FlattenPkgs(ctx, found, "show", c.Bool("interactive"))
|
||||||
@@ -109,15 +119,15 @@ func InfoCmd() *cli.Command {
|
|||||||
|
|
||||||
systemLang, err := locale.GetLanguage()
|
systemLang, err := locale.GetLanguage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Can't detect system language"), err)
|
slog.Error("Can't detect system language", "err", err)
|
||||||
}
|
os.Exit(1)
|
||||||
if systemLang == "" {
|
|
||||||
systemLang = "en"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !all {
|
||||||
info, err := distro.ParseOSRelease(ctx)
|
info, err := distro.ParseOSRelease(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error parsing os-release file"), err)
|
slog.Error(gotext.Get("Error parsing os-release file"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
names, err = overrides.Resolve(
|
names, err = overrides.Resolve(
|
||||||
info,
|
info,
|
||||||
@@ -125,17 +135,26 @@ func InfoCmd() *cli.Command {
|
|||||||
WithLanguages([]string{systemLang}),
|
WithLanguages([]string{systemLang}),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error resolving overrides"), err)
|
slog.Error(gotext.Get("Error resolving overrides"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
alrsh.ResolvePackage(&pkg, names)
|
if !all {
|
||||||
view := alrsh.NewPackageView(pkg)
|
err = yaml.NewEncoder(os.Stdout).Encode(overrides.ResolvePackage(&pkg, names))
|
||||||
view.Resolved = !all
|
|
||||||
err = yaml.NewEncoder(os.Stdout, yaml.UseJSONMarshaler(), yaml.OmitEmpty()).Encode(view)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error encoding script variables"), err)
|
slog.Error(gotext.Get("Error encoding script variables"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
err = yaml.NewEncoder(os.Stdout).Encode(pkg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Error encoding script variables"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("---")
|
fmt.Println("---")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
218
install.go
218
install.go
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -21,16 +21,20 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/build"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
||||||
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/build"
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager"
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InstallCmd() *cli.Command {
|
func InstallCmd() *cli.Command {
|
||||||
@@ -45,94 +49,99 @@ func InstallCmd() *cli.Command {
|
|||||||
Usage: gotext.Get("Build package from scratch even if there's an already built package available"),
|
Usage: gotext.Get("Build package from scratch even if there's an already built package available"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: utils.RootNeededAction(func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
|
ctx := c.Context
|
||||||
|
|
||||||
args := c.Args()
|
args := c.Args()
|
||||||
if args.Len() < 1 {
|
if args.Len() < 1 {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Command install expected at least 1 argument, got %d", args.Len()), nil)
|
slog.Error(gotext.Get("Command install expected at least 1 argument, got %d", args.Len()))
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mgr := manager.Detect()
|
||||||
|
if mgr == nil {
|
||||||
|
slog.Error(gotext.Get("Unable to detect a supported package manager on the system"))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
installer, installerClose, err := build.GetSafeInstaller()
|
cfg := config.New()
|
||||||
|
db := database.New(cfg)
|
||||||
|
rs := repos.New(cfg, db)
|
||||||
|
err := db.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error initialization database"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer installerClose()
|
|
||||||
|
|
||||||
|
if cfg.AutoPull(ctx) {
|
||||||
scripter, scripterClose, err := build.GetSafeScriptExecutor()
|
err := rs.Pull(ctx, cfg.Repos(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error pulling repositories"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer scripterClose()
|
|
||||||
|
|
||||||
ctx := c.Context
|
found, notFound, err := rs.FindPkgs(ctx, args.Slice())
|
||||||
|
|
||||||
deps, err := appbuilder.
|
|
||||||
New(ctx).
|
|
||||||
WithConfig().
|
|
||||||
WithDB().
|
|
||||||
WithRepos().
|
|
||||||
WithDistroInfo().
|
|
||||||
WithManager().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error finding packages"), "err", err)
|
||||||
}
|
os.Exit(1)
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
builder, err := build.NewMainBuilder(
|
|
||||||
deps.Cfg,
|
|
||||||
deps.Manager,
|
|
||||||
deps.Repos,
|
|
||||||
scripter,
|
|
||||||
installer,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = builder.InstallPkgs(
|
pkgs := cliutils.FlattenPkgs(ctx, found, "install", c.Bool("interactive"))
|
||||||
ctx,
|
|
||||||
&build.BuildArgs{
|
opts := types.BuildOpts{
|
||||||
Opts: &types.BuildOpts{
|
Manager: mgr,
|
||||||
Clean: c.Bool("clean"),
|
Clean: c.Bool("clean"),
|
||||||
Interactive: c.Bool("interactive"),
|
Interactive: c.Bool("interactive"),
|
||||||
},
|
}
|
||||||
Info: deps.Info,
|
|
||||||
PkgFormat_: build.GetPkgFormat(deps.Manager),
|
info, err := distro.ParseOSRelease(ctx)
|
||||||
},
|
if err != nil {
|
||||||
args.Slice(),
|
slog.Error(gotext.Get("Error parsing os release"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := build.NewBuilder(
|
||||||
|
ctx,
|
||||||
|
opts,
|
||||||
|
rs,
|
||||||
|
info,
|
||||||
|
cfg,
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error when installing the package"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
builder.InstallPkgs(ctx, pkgs, notFound, types.BuildOpts{
|
||||||
|
Manager: mgr,
|
||||||
|
Clean: c.Bool("clean"),
|
||||||
|
Interactive: c.Bool("interactive"),
|
||||||
|
})
|
||||||
return nil
|
return nil
|
||||||
}),
|
},
|
||||||
BashComplete: cliutils.BashCompleteWithError(func(c *cli.Context) error {
|
BashComplete: func(c *cli.Context) {
|
||||||
|
cfg := config.New()
|
||||||
ctx := c.Context
|
db := database.New(cfg)
|
||||||
deps, err := appbuilder.
|
err := db.Init(c.Context)
|
||||||
New(ctx).
|
|
||||||
WithConfig().
|
|
||||||
WithDB().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error initialization database"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer deps.Defer()
|
result, err := db.GetPkgs(c.Context, "true")
|
||||||
|
|
||||||
result, err := deps.DB.GetPkgs(c.Context, "true")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error getting packages"), err)
|
slog.Error(gotext.Get("Error getting packages"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer result.Close()
|
||||||
|
|
||||||
|
for result.Next() {
|
||||||
|
var pkg database.Package
|
||||||
|
err = result.StructScan(&pkg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Error iterating over packages"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range result {
|
|
||||||
fmt.Println(pkg.Name)
|
fmt.Println(pkg.Name)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,71 +150,26 @@ func RemoveCmd() *cli.Command {
|
|||||||
Name: "remove",
|
Name: "remove",
|
||||||
Usage: gotext.Get("Remove an installed package"),
|
Usage: gotext.Get("Remove an installed package"),
|
||||||
Aliases: []string{"rm"},
|
Aliases: []string{"rm"},
|
||||||
BashComplete: cliutils.BashCompleteWithError(func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
ctx := c.Context
|
|
||||||
|
|
||||||
deps, err := appbuilder.
|
|
||||||
New(ctx).
|
|
||||||
WithConfig().
|
|
||||||
WithDB().
|
|
||||||
WithManager().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
|
||||||
return cli.Exit(err, 1)
|
|
||||||
}
|
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
installedAlrPackages := map[string]string{}
|
|
||||||
installed, err := deps.Manager.ListInstalled(&manager.Opts{})
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error listing installed packages"), err)
|
|
||||||
}
|
|
||||||
for pkgName, version := range installed {
|
|
||||||
matches := build.RegexpALRPackageName.FindStringSubmatch(pkgName)
|
|
||||||
if matches != nil {
|
|
||||||
packageName := matches[build.RegexpALRPackageName.SubexpIndex("package")]
|
|
||||||
repoName := matches[build.RegexpALRPackageName.SubexpIndex("repo")]
|
|
||||||
installedAlrPackages[fmt.Sprintf("%s/%s", repoName, packageName)] = version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := deps.DB.GetPkgs(c.Context, "true")
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error getting packages"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pkg := range result {
|
|
||||||
_, ok := installedAlrPackages[fmt.Sprintf("%s/%s", pkg.Repository, pkg.Name)]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Println(pkg.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
Action: utils.RootNeededAction(func(c *cli.Context) error {
|
|
||||||
args := c.Args()
|
args := c.Args()
|
||||||
if args.Len() < 1 {
|
if args.Len() < 1 {
|
||||||
return cliutils.FormatCliExit(gotext.Get("Command remove expected at least 1 argument, got %d", args.Len()), nil)
|
slog.Error(gotext.Get("Command remove expected at least 1 argument, got %d", args.Len()))
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
deps, err := appbuilder.
|
mgr := manager.Detect()
|
||||||
New(c.Context).
|
if mgr == nil {
|
||||||
WithManager().
|
slog.Error(gotext.Get("Unable to detect a supported package manager on the system"))
|
||||||
Build()
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mgr.Remove(nil, c.Args().Slice()...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
slog.Error(gotext.Get("Error removing packages"), "err", err)
|
||||||
}
|
os.Exit(1)
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
if err := deps.Manager.Remove(&manager.Opts{
|
|
||||||
NoConfirm: !c.Bool("interactive"),
|
|
||||||
}, c.Args().Slice()...); err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error removing packages"), err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}),
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
156
internal.go
156
internal.go
@@ -1,156 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
|
||||||
"github.com/hashicorp/go-plugin"
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/build"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
|
||||||
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func InternalBuildCmd() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "_internal-safe-script-executor",
|
|
||||||
HideHelp: true,
|
|
||||||
Hidden: true,
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
logger.SetupForGoPlugin()
|
|
||||||
|
|
||||||
slog.Debug("start _internal-safe-script-executor", "uid", syscall.Getuid(), "gid", syscall.Getgid())
|
|
||||||
|
|
||||||
|
|
||||||
cfg := config.New()
|
|
||||||
err := cfg.Load()
|
|
||||||
if err != nil {
|
|
||||||
return cliutils.FormatCliExit(gotext.Get("Error loading config"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := hclog.New(&hclog.LoggerOptions{
|
|
||||||
Name: "plugin",
|
|
||||||
Output: os.Stderr,
|
|
||||||
Level: hclog.Debug,
|
|
||||||
JSONFormat: false,
|
|
||||||
DisableTime: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
plugin.Serve(&plugin.ServeConfig{
|
|
||||||
HandshakeConfig: build.HandshakeConfig,
|
|
||||||
Plugins: map[string]plugin.Plugin{
|
|
||||||
"script-executor": &build.ScriptExecutorPlugin{
|
|
||||||
Impl: build.NewLocalScriptExecutor(cfg),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Logger: logger,
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func InternalReposCmd() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "_internal-repos",
|
|
||||||
HideHelp: true,
|
|
||||||
Hidden: true,
|
|
||||||
Action: utils.RootNeededAction(func(ctx *cli.Context) error {
|
|
||||||
logger.SetupForGoPlugin()
|
|
||||||
|
|
||||||
|
|
||||||
deps, err := appbuilder.
|
|
||||||
New(ctx.Context).
|
|
||||||
WithConfig().
|
|
||||||
WithDB().
|
|
||||||
WithReposNoPull().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
pluginCfg := build.GetPluginServeCommonConfig()
|
|
||||||
pluginCfg.Plugins = map[string]plugin.Plugin{
|
|
||||||
"repos": &build.ReposExecutorPlugin{
|
|
||||||
Impl: build.NewRepos(
|
|
||||||
deps.Repos,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
plugin.Serve(pluginCfg)
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func InternalInstallCmd() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "_internal-installer",
|
|
||||||
HideHelp: true,
|
|
||||||
Hidden: true,
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
logger.SetupForGoPlugin()
|
|
||||||
|
|
||||||
// Запуск от текущего пользователя, повышение прав будет через sudo при необходимости
|
|
||||||
|
|
||||||
deps, err := appbuilder.
|
|
||||||
New(c.Context).
|
|
||||||
WithConfig().
|
|
||||||
WithDB().
|
|
||||||
WithReposNoPull().
|
|
||||||
Build()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer deps.Defer()
|
|
||||||
|
|
||||||
logger := hclog.New(&hclog.LoggerOptions{
|
|
||||||
Name: "plugin",
|
|
||||||
Output: os.Stderr,
|
|
||||||
Level: hclog.Trace,
|
|
||||||
JSONFormat: true,
|
|
||||||
DisableTime: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
plugin.Serve(&plugin.ServeConfig{
|
|
||||||
HandshakeConfig: build.HandshakeConfig,
|
|
||||||
Plugins: map[string]plugin.Plugin{
|
|
||||||
"installer": &build.InstallerExecutorPlugin{
|
|
||||||
Impl: build.NewInstaller(
|
|
||||||
manager.Detect(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Logger: logger,
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,745 +0,0 @@
|
|||||||
// 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 the ALR Authors.
|
|
||||||
//
|
|
||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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"
|
|
||||||
"encoding/gob"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/stats"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BuildInput struct {
|
|
||||||
opts *types.BuildOpts
|
|
||||||
info *distro.OSRelease
|
|
||||||
pkgFormat string
|
|
||||||
script string
|
|
||||||
repository string
|
|
||||||
packages []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bi *BuildInput) GobEncode() ([]byte, error) {
|
|
||||||
w := new(bytes.Buffer)
|
|
||||||
encoder := gob.NewEncoder(w)
|
|
||||||
|
|
||||||
if err := encoder.Encode(bi.opts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := encoder.Encode(bi.info); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := encoder.Encode(bi.pkgFormat); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := encoder.Encode(bi.script); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := encoder.Encode(bi.repository); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := encoder.Encode(bi.packages); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bi *BuildInput) GobDecode(data []byte) error {
|
|
||||||
r := bytes.NewBuffer(data)
|
|
||||||
decoder := gob.NewDecoder(r)
|
|
||||||
|
|
||||||
if err := decoder.Decode(&bi.opts); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := decoder.Decode(&bi.info); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := decoder.Decode(&bi.pkgFormat); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := decoder.Decode(&bi.script); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := decoder.Decode(&bi.repository); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := decoder.Decode(&bi.packages); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BuildInput) Repository() string {
|
|
||||||
return b.repository
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BuildInput) BuildOpts() *types.BuildOpts {
|
|
||||||
return b.opts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BuildInput) OSRelease() *distro.OSRelease {
|
|
||||||
return b.info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BuildInput) PkgFormat() string {
|
|
||||||
return b.pkgFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
type BuildOptsProvider interface {
|
|
||||||
BuildOpts() *types.BuildOpts
|
|
||||||
}
|
|
||||||
|
|
||||||
type OsInfoProvider interface {
|
|
||||||
OSRelease() *distro.OSRelease
|
|
||||||
}
|
|
||||||
|
|
||||||
type PkgFormatProvider interface {
|
|
||||||
PkgFormat() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryProvider interface {
|
|
||||||
Repository() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================================================
|
|
||||||
|
|
||||||
type BuiltDep struct {
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Map[T, R any](items []T, f func(T) R) []R {
|
|
||||||
res := make([]R, len(items))
|
|
||||||
for i, item := range items {
|
|
||||||
res[i] = f(item)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBuiltPaths(deps []*BuiltDep) []string {
|
|
||||||
return Map(deps, func(dep *BuiltDep) string {
|
|
||||||
return dep.Path
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBuiltName(deps []*BuiltDep) []string {
|
|
||||||
return Map(deps, func(dep *BuiltDep) string {
|
|
||||||
return dep.Name
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type PackageFinder interface {
|
|
||||||
FindPkgs(ctx context.Context, pkgs []string) (map[string][]alrsh.Package, []string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config interface {
|
|
||||||
GetPaths() *config.Paths
|
|
||||||
PagerStyle() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type FunctionsOutput struct {
|
|
||||||
Contents *[]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXECUTORS
|
|
||||||
|
|
||||||
type ScriptResolverExecutor interface {
|
|
||||||
ResolveScript(ctx context.Context, pkg *alrsh.Package) *ScriptInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type CacheExecutor interface {
|
|
||||||
CheckForBuiltPackage(ctx context.Context, input *BuildInput, vars *alrsh.Package) (string, bool, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptViewerExecutor interface {
|
|
||||||
ViewScript(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile, basePkg string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type CheckerExecutor interface {
|
|
||||||
PerformChecks(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
vars *alrsh.Package,
|
|
||||||
) (bool, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type SourcesInput struct {
|
|
||||||
Sources []string
|
|
||||||
Checksums []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SourceDownloaderExecutor interface {
|
|
||||||
DownloadSources(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
basePkg string,
|
|
||||||
si SourcesInput,
|
|
||||||
) error
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
func NewBuilder(
|
|
||||||
scriptResolver ScriptResolverExecutor,
|
|
||||||
scriptExecutor ScriptExecutor,
|
|
||||||
cacheExecutor CacheExecutor,
|
|
||||||
scriptViewerExecutor ScriptViewerExecutor,
|
|
||||||
checkerExecutor CheckerExecutor,
|
|
||||||
installerExecutor InstallerExecutor,
|
|
||||||
sourceExecutor SourceDownloaderExecutor,
|
|
||||||
) *Builder {
|
|
||||||
return &Builder{
|
|
||||||
scriptResolver: scriptResolver,
|
|
||||||
scriptExecutor: scriptExecutor,
|
|
||||||
cacheExecutor: cacheExecutor,
|
|
||||||
scriptViewerExecutor: scriptViewerExecutor,
|
|
||||||
checkerExecutor: checkerExecutor,
|
|
||||||
installerExecutor: installerExecutor,
|
|
||||||
sourceExecutor: sourceExecutor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Builder struct {
|
|
||||||
scriptResolver ScriptResolverExecutor
|
|
||||||
scriptExecutor ScriptExecutor
|
|
||||||
cacheExecutor CacheExecutor
|
|
||||||
scriptViewerExecutor ScriptViewerExecutor
|
|
||||||
checkerExecutor CheckerExecutor
|
|
||||||
installerExecutor InstallerExecutor
|
|
||||||
sourceExecutor SourceDownloaderExecutor
|
|
||||||
repos PackageFinder
|
|
||||||
// mgr manager.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
type BuildArgs struct {
|
|
||||||
Opts *types.BuildOpts
|
|
||||||
Info *distro.OSRelease
|
|
||||||
PkgFormat_ string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BuildArgs) BuildOpts() *types.BuildOpts {
|
|
||||||
return b.Opts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BuildArgs) OSRelease() *distro.OSRelease {
|
|
||||||
return b.Info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BuildArgs) PkgFormat() string {
|
|
||||||
return b.PkgFormat_
|
|
||||||
}
|
|
||||||
|
|
||||||
type BuildPackageFromDbArgs struct {
|
|
||||||
BuildArgs
|
|
||||||
Package *alrsh.Package
|
|
||||||
Packages []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type BuildPackageFromScriptArgs struct {
|
|
||||||
BuildArgs
|
|
||||||
Script string
|
|
||||||
Packages []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) BuildPackageFromDb(
|
|
||||||
ctx context.Context,
|
|
||||||
args *BuildPackageFromDbArgs,
|
|
||||||
) ([]*BuiltDep, error) {
|
|
||||||
scriptInfo := b.scriptResolver.ResolveScript(ctx, args.Package)
|
|
||||||
|
|
||||||
return b.BuildPackage(ctx, &BuildInput{
|
|
||||||
script: scriptInfo.Script,
|
|
||||||
repository: scriptInfo.Repository,
|
|
||||||
packages: args.Packages,
|
|
||||||
pkgFormat: args.PkgFormat(),
|
|
||||||
opts: args.Opts,
|
|
||||||
info: args.Info,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) BuildPackageFromScript(
|
|
||||||
ctx context.Context,
|
|
||||||
args *BuildPackageFromScriptArgs,
|
|
||||||
) ([]*BuiltDep, error) {
|
|
||||||
return b.BuildPackage(ctx, &BuildInput{
|
|
||||||
script: args.Script,
|
|
||||||
repository: "default",
|
|
||||||
packages: args.Packages,
|
|
||||||
pkgFormat: args.PkgFormat(),
|
|
||||||
opts: args.Opts,
|
|
||||||
info: args.Info,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) BuildPackage(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
) ([]*BuiltDep, error) {
|
|
||||||
scriptPath := input.script
|
|
||||||
|
|
||||||
slog.Debug("ReadScript")
|
|
||||||
sf, err := b.scriptExecutor.ReadScript(ctx, scriptPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed reading script: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("ExecuteFirstPass")
|
|
||||||
basePkg, varsOfPackages, err := b.scriptExecutor.ExecuteFirstPass(ctx, input, sf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed ExecuteFirstPass: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var builtDeps []*BuiltDep
|
|
||||||
var remainingVars []*alrsh.Package
|
|
||||||
|
|
||||||
if !input.opts.Clean {
|
|
||||||
for _, vars := range varsOfPackages {
|
|
||||||
builtPkgPath, ok, err := b.cacheExecutor.CheckForBuiltPackage(ctx, input, vars)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if ok {
|
|
||||||
builtDeps = append(builtDeps, &BuiltDep{
|
|
||||||
Path: builtPkgPath,
|
|
||||||
Name: vars.Name,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
remainingVars = append(remainingVars, vars)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(remainingVars) == 0 {
|
|
||||||
slog.Info(gotext.Get("Using cached package"), "name", basePkg)
|
|
||||||
return builtDeps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обновляем varsOfPackages только теми пакетами, которые нужно собрать
|
|
||||||
varsOfPackages = remainingVars
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("ViewScript")
|
|
||||||
slog.Debug("", "varsOfPackages", varsOfPackages[0])
|
|
||||||
err = b.scriptViewerExecutor.ViewScript(ctx, input, sf, basePkg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Info(gotext.Get("Building package"), "name", basePkg)
|
|
||||||
|
|
||||||
for _, vars := range varsOfPackages {
|
|
||||||
cont, err := b.checkerExecutor.PerformChecks(ctx, input, vars)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !cont {
|
|
||||||
return nil, errors.New("exit...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildDepends := []string{}
|
|
||||||
optDepends := []string{}
|
|
||||||
depends := []string{}
|
|
||||||
sources := []string{}
|
|
||||||
checksums := []string{}
|
|
||||||
for _, vars := range varsOfPackages {
|
|
||||||
buildDepends = append(buildDepends, vars.BuildDepends.Resolved()...)
|
|
||||||
optDepends = append(optDepends, vars.OptDepends.Resolved()...)
|
|
||||||
depends = append(depends, vars.Depends.Resolved()...)
|
|
||||||
sources = append(sources, vars.Sources.Resolved()...)
|
|
||||||
checksums = append(checksums, vars.Checksums.Resolved()...)
|
|
||||||
}
|
|
||||||
buildDepends = removeDuplicates(buildDepends)
|
|
||||||
optDepends = removeDuplicates(optDepends)
|
|
||||||
depends = removeDuplicates(depends)
|
|
||||||
|
|
||||||
if len(sources) != len(checksums) {
|
|
||||||
slog.Error(gotext.Get("The checksums array must be the same length as sources"))
|
|
||||||
return nil, errors.New("exit...")
|
|
||||||
}
|
|
||||||
sources, checksums = removeDuplicatesSources(sources, checksums)
|
|
||||||
|
|
||||||
slog.Debug("installBuildDeps")
|
|
||||||
alrBuildDeps, installedBuildDeps, err := b.installBuildDeps(ctx, input, buildDepends)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("installOptDeps")
|
|
||||||
_, err = b.installOptDeps(ctx, input, optDepends)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
depNames := make(map[string]struct{})
|
|
||||||
for _, dep := range alrBuildDeps {
|
|
||||||
depNames[dep.Name] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We filter so as not to re-build what has already been built at the `installBuildDeps` stage.
|
|
||||||
var filteredDepends []string
|
|
||||||
|
|
||||||
// Создаем набор подпакетов текущего мультипакета для исключения циклических зависимостей
|
|
||||||
currentPackageNames := make(map[string]struct{})
|
|
||||||
for _, pkg := range input.packages {
|
|
||||||
currentPackageNames[pkg] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range depends {
|
|
||||||
if _, found := depNames[d]; !found {
|
|
||||||
// Исключаем зависимости, которые являются подпакетами текущего мультипакета
|
|
||||||
if _, isCurrentPackage := currentPackageNames[d]; !isCurrentPackage {
|
|
||||||
filteredDepends = append(filteredDepends, d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("BuildALRDeps")
|
|
||||||
newBuiltDeps, repoDeps, err := b.BuildALRDeps(ctx, input, filteredDepends)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("PrepareDirs")
|
|
||||||
err = b.scriptExecutor.PrepareDirs(ctx, input, basePkg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Info(gotext.Get("Downloading sources"))
|
|
||||||
slog.Debug("DownloadSources")
|
|
||||||
err = b.sourceExecutor.DownloadSources(
|
|
||||||
ctx,
|
|
||||||
input,
|
|
||||||
basePkg,
|
|
||||||
SourcesInput{
|
|
||||||
Sources: sources,
|
|
||||||
Checksums: checksums,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
builtDeps = removeDuplicates(append(builtDeps, newBuiltDeps...))
|
|
||||||
|
|
||||||
slog.Debug("ExecuteSecondPass")
|
|
||||||
res, err := b.scriptExecutor.ExecuteSecondPass(
|
|
||||||
ctx,
|
|
||||||
input,
|
|
||||||
sf,
|
|
||||||
varsOfPackages,
|
|
||||||
repoDeps,
|
|
||||||
builtDeps,
|
|
||||||
basePkg,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
builtDeps = removeDuplicates(append(builtDeps, res...))
|
|
||||||
|
|
||||||
err = b.removeBuildDeps(ctx, input, installedBuildDeps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return builtDeps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) removeBuildDeps(ctx context.Context, input interface {
|
|
||||||
BuildOptsProvider
|
|
||||||
}, deps []string,
|
|
||||||
) error {
|
|
||||||
if len(deps) > 0 {
|
|
||||||
remove, err := cliutils.YesNoPrompt(ctx, gotext.Get("Would you like to remove the build dependencies?"), input.BuildOpts().Interactive, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if remove {
|
|
||||||
err = b.installerExecutor.Remove(
|
|
||||||
ctx,
|
|
||||||
deps,
|
|
||||||
&manager.Opts{
|
|
||||||
NoConfirm: !input.BuildOpts().Interactive,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallPkgsArgs struct {
|
|
||||||
BuildArgs
|
|
||||||
AlrPkgs []alrsh.Package
|
|
||||||
NativePkgs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) InstallALRPackages(
|
|
||||||
ctx context.Context,
|
|
||||||
input interface {
|
|
||||||
OsInfoProvider
|
|
||||||
BuildOptsProvider
|
|
||||||
PkgFormatProvider
|
|
||||||
},
|
|
||||||
alrPkgs []alrsh.Package,
|
|
||||||
) error {
|
|
||||||
for _, pkg := range alrPkgs {
|
|
||||||
res, err := b.BuildPackageFromDb(
|
|
||||||
ctx,
|
|
||||||
&BuildPackageFromDbArgs{
|
|
||||||
Package: &pkg,
|
|
||||||
Packages: []string{},
|
|
||||||
BuildArgs: BuildArgs{
|
|
||||||
Opts: input.BuildOpts(),
|
|
||||||
Info: input.OSRelease(),
|
|
||||||
PkgFormat_: input.PkgFormat(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = b.installerExecutor.InstallLocal(
|
|
||||||
ctx,
|
|
||||||
GetBuiltPaths(res),
|
|
||||||
&manager.Opts{
|
|
||||||
NoConfirm: !input.BuildOpts().Interactive,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Отслеживание установки ALR пакетов
|
|
||||||
for _, dep := range res {
|
|
||||||
if stats.ShouldTrackPackage(dep.Name) {
|
|
||||||
stats.TrackInstallation(ctx, dep.Name, "upgrade")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) BuildALRDeps(
|
|
||||||
ctx context.Context,
|
|
||||||
input interface {
|
|
||||||
OsInfoProvider
|
|
||||||
BuildOptsProvider
|
|
||||||
PkgFormatProvider
|
|
||||||
},
|
|
||||||
depends []string,
|
|
||||||
) (buildDeps []*BuiltDep, repoDeps []string, err error) {
|
|
||||||
if len(depends) > 0 {
|
|
||||||
slog.Info(gotext.Get("Installing dependencies"))
|
|
||||||
|
|
||||||
found, notFound, err := b.repos.FindPkgs(ctx, depends) // Поиск зависимостей
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("failed FindPkgs: %w", err)
|
|
||||||
}
|
|
||||||
repoDeps = notFound
|
|
||||||
|
|
||||||
// Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез
|
|
||||||
// Для зависимостей указываем isDependency = true
|
|
||||||
pkgs := cliutils.FlattenPkgsWithContext(
|
|
||||||
ctx,
|
|
||||||
found,
|
|
||||||
"install",
|
|
||||||
input.BuildOpts().Interactive,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
type item struct {
|
|
||||||
pkg *alrsh.Package
|
|
||||||
packages []string
|
|
||||||
}
|
|
||||||
pkgsMap := make(map[string]*item)
|
|
||||||
for _, pkg := range pkgs {
|
|
||||||
name := pkg.BasePkgName
|
|
||||||
if name == "" {
|
|
||||||
name = pkg.Name
|
|
||||||
}
|
|
||||||
if pkgsMap[name] == nil {
|
|
||||||
pkgsMap[name] = &item{
|
|
||||||
pkg: &pkg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pkgsMap[name].packages = append(
|
|
||||||
pkgsMap[name].packages,
|
|
||||||
pkg.Name,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for basePkgName := range pkgsMap {
|
|
||||||
pkg := pkgsMap[basePkgName].pkg
|
|
||||||
res, err := b.BuildPackageFromDb(
|
|
||||||
ctx,
|
|
||||||
&BuildPackageFromDbArgs{
|
|
||||||
Package: pkg,
|
|
||||||
Packages: pkgsMap[basePkgName].packages,
|
|
||||||
BuildArgs: BuildArgs{
|
|
||||||
Opts: input.BuildOpts(),
|
|
||||||
Info: input.OSRelease(),
|
|
||||||
PkgFormat_: input.PkgFormat(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("failed build package from db: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buildDeps = append(buildDeps, res...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repoDeps = removeDuplicates(repoDeps)
|
|
||||||
buildDeps = removeDuplicates(buildDeps)
|
|
||||||
|
|
||||||
return buildDeps, repoDeps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Builder) installBuildDeps(
|
|
||||||
ctx context.Context,
|
|
||||||
input interface {
|
|
||||||
OsInfoProvider
|
|
||||||
BuildOptsProvider
|
|
||||||
PkgFormatProvider
|
|
||||||
},
|
|
||||||
pkgs []string,
|
|
||||||
) ([]*BuiltDep, []string, error) {
|
|
||||||
var builtDeps []*BuiltDep
|
|
||||||
var deps []string
|
|
||||||
var err error
|
|
||||||
if len(pkgs) > 0 {
|
|
||||||
deps, err = i.installerExecutor.RemoveAlreadyInstalled(ctx, pkgs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
builtDeps, err = i.InstallPkgs(ctx, input, deps) // Устанавливаем выбранные пакеты
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builtDeps, deps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Builder) installOptDeps(
|
|
||||||
ctx context.Context,
|
|
||||||
input interface {
|
|
||||||
OsInfoProvider
|
|
||||||
BuildOptsProvider
|
|
||||||
PkgFormatProvider
|
|
||||||
},
|
|
||||||
pkgs []string,
|
|
||||||
) ([]*BuiltDep, error) {
|
|
||||||
var builtDeps []*BuiltDep
|
|
||||||
optDeps, err := i.installerExecutor.RemoveAlreadyInstalled(ctx, pkgs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(optDeps) > 0 {
|
|
||||||
optDeps, err := cliutils.ChooseOptDepends(
|
|
||||||
ctx,
|
|
||||||
optDeps,
|
|
||||||
"install",
|
|
||||||
input.BuildOpts().Interactive,
|
|
||||||
) // Пользователя просят выбрать опциональные зависимости
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(optDeps) == 0 {
|
|
||||||
return builtDeps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
builtDeps, err = i.InstallPkgs(ctx, input, optDeps) // Устанавливаем выбранные пакеты
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builtDeps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Builder) InstallPkgs(
|
|
||||||
ctx context.Context,
|
|
||||||
input interface {
|
|
||||||
OsInfoProvider
|
|
||||||
BuildOptsProvider
|
|
||||||
PkgFormatProvider
|
|
||||||
},
|
|
||||||
pkgs []string,
|
|
||||||
) ([]*BuiltDep, error) {
|
|
||||||
builtDeps, repoDeps, err := i.BuildALRDeps(ctx, input, pkgs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(builtDeps) > 0 {
|
|
||||||
err = i.installerExecutor.InstallLocal(ctx, GetBuiltPaths(builtDeps), &manager.Opts{
|
|
||||||
NoConfirm: !input.BuildOpts().Interactive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Отслеживание установки локальных пакетов
|
|
||||||
for _, dep := range builtDeps {
|
|
||||||
if stats.ShouldTrackPackage(dep.Name) {
|
|
||||||
stats.TrackInstallation(ctx, dep.Name, "install")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(repoDeps) > 0 {
|
|
||||||
err = i.installerExecutor.Install(ctx, repoDeps, &manager.Opts{
|
|
||||||
NoConfirm: !input.BuildOpts().Interactive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Отслеживание установки пакетов из репозитория
|
|
||||||
for _, pkg := range repoDeps {
|
|
||||||
if stats.ShouldTrackPackage(pkg) {
|
|
||||||
stats.TrackInstallation(ctx, pkg, "install")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builtDeps, nil
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Cache struct {
|
|
||||||
cfg Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) CheckForBuiltPackage(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
vars *alrsh.Package,
|
|
||||||
) (string, bool, error) {
|
|
||||||
filename, err := pkgFileName(input, vars)
|
|
||||||
if err != nil {
|
|
||||||
return "", false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgPath := filepath.Join(getBaseDir(c.cfg, vars.Name), filename)
|
|
||||||
|
|
||||||
_, err = os.Stat(pkgPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkgPath, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func pkgFileName(
|
|
||||||
input interface {
|
|
||||||
OsInfoProvider
|
|
||||||
PkgFormatProvider
|
|
||||||
RepositoryProvider
|
|
||||||
},
|
|
||||||
vars *alrsh.Package,
|
|
||||||
) (string, error) {
|
|
||||||
pkgInfo := getBasePkgInfo(vars, input)
|
|
||||||
|
|
||||||
packager, err := nfpm.Get(input.PkgFormat())
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return packager.ConventionalFileName(pkgInfo), nil
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Checker struct {
|
|
||||||
mgr manager.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Checker) PerformChecks(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
vars *alrsh.Package,
|
|
||||||
) (bool, error) {
|
|
||||||
if !cpu.IsCompatibleWith(cpu.Arch(), vars.Architectures) { // Проверяем совместимость архитектуры
|
|
||||||
cont, err := cliutils.YesNoPrompt(
|
|
||||||
ctx,
|
|
||||||
gotext.Get("Your system's CPU architecture doesn't match this package. Do you want to build anyway?"),
|
|
||||||
input.opts.Interactive,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cont {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
installed, err := c.mgr.ListInstalled(nil)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
filename, err := pkgFileName(input, vars)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if instVer, ok := installed[filename]; ok { // Если пакет уже установлен, выводим предупреждение
|
|
||||||
slog.Warn(gotext.Get("This package is already installed"),
|
|
||||||
"name", vars.Name,
|
|
||||||
"version", instVer,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BaseDirProvider interface {
|
|
||||||
BaseDir() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SrcDirProvider interface {
|
|
||||||
SrcDir() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PkgDirProvider interface {
|
|
||||||
PkgDir() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptDirProvider interface {
|
|
||||||
ScriptDir() string
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDirs(
|
|
||||||
cfg Config,
|
|
||||||
scriptPath string,
|
|
||||||
basePkg string,
|
|
||||||
) (types.Directories, error) {
|
|
||||||
pkgsDir := cfg.GetPaths().PkgsDir
|
|
||||||
|
|
||||||
scriptPath, err := filepath.Abs(scriptPath)
|
|
||||||
if err != nil {
|
|
||||||
return types.Directories{}, err
|
|
||||||
}
|
|
||||||
baseDir := filepath.Join(pkgsDir, basePkg)
|
|
||||||
return types.Directories{
|
|
||||||
BaseDir: getBaseDir(cfg, basePkg),
|
|
||||||
SrcDir: getSrcDir(cfg, basePkg),
|
|
||||||
PkgDir: filepath.Join(baseDir, "pkg"),
|
|
||||||
ScriptDir: getScriptDir(scriptPath),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBaseDir(cfg Config, basePkg string) string {
|
|
||||||
return filepath.Join(cfg.GetPaths().PkgsDir, basePkg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSrcDir(cfg Config, basePkg string) string {
|
|
||||||
return filepath.Join(getBaseDir(cfg, basePkg), "src")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getScriptDir(scriptPath string) string {
|
|
||||||
return filepath.Dir(scriptPath)
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 finddeps
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2"
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EmptyFindProvReq struct{}
|
|
||||||
|
|
||||||
func (o *EmptyFindProvReq) FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
|
|
||||||
slog.Info(gotext.Get("AutoProv is not implemented for this package format, so it's skipped"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *EmptyFindProvReq) FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
|
|
||||||
slog.Info(gotext.Get("AutoReq is not implemented for this package format, so it's skipped"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 finddeps
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2"
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FedoraFindProvReq struct{}
|
|
||||||
|
|
||||||
func rpmFindDependenciesFedora(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, command string, args []string, updateFunc func(string)) error {
|
|
||||||
if _, err := exec.LookPath(command); err != nil {
|
|
||||||
slog.Info(gotext.Get("Command not found on the system"), "command", command)
|
|
||||||
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.CommandContext(ctx, command, args...)
|
|
||||||
cmd.Stdin = bytes.NewBufferString(strings.Join(paths, "\n") + "\n")
|
|
||||||
cmd.Env = append(cmd.Env,
|
|
||||||
"RPM_BUILD_ROOT="+dirs.PkgDir,
|
|
||||||
)
|
|
||||||
var out bytes.Buffer
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
cmd.Stdout = &out
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
slog.Error(stderr.String())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slog.Debug(stderr.String())
|
|
||||||
|
|
||||||
dependencies := strings.Split(strings.TrimSpace(out.String()), "\n")
|
|
||||||
for _, dep := range dependencies {
|
|
||||||
if dep != "" {
|
|
||||||
updateFunc(dep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *FedoraFindProvReq) FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
|
|
||||||
return rpmFindDependenciesFedora(
|
|
||||||
ctx,
|
|
||||||
pkgInfo,
|
|
||||||
dirs,
|
|
||||||
"/usr/lib/rpm/rpmdeps",
|
|
||||||
[]string{
|
|
||||||
"--define=_use_internal_dependency_generator 1",
|
|
||||||
"--provides",
|
|
||||||
fmt.Sprintf(
|
|
||||||
"--define=__provides_exclude_from %s\"",
|
|
||||||
strings.Join(skiplist, "|"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
func(dep string) {
|
|
||||||
slog.Info(gotext.Get("Provided dependency found"), "dep", dep)
|
|
||||||
pkgInfo.Overridables.Provides = append(pkgInfo.Overridables.Provides, dep)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *FedoraFindProvReq) FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
|
|
||||||
return rpmFindDependenciesFedora(
|
|
||||||
ctx,
|
|
||||||
pkgInfo,
|
|
||||||
dirs,
|
|
||||||
"/usr/lib/rpm/rpmdeps",
|
|
||||||
[]string{
|
|
||||||
"--define=_use_internal_dependency_generator 1",
|
|
||||||
"--requires",
|
|
||||||
fmt.Sprintf(
|
|
||||||
"--define=__requires_exclude_from %s",
|
|
||||||
strings.Join(skiplist, "|"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
func(dep string) {
|
|
||||||
slog.Info(gotext.Get("Required dependency found"), "dep", dep)
|
|
||||||
pkgInfo.Overridables.Depends = append(pkgInfo.Overridables.Depends, dep)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 finddeps
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProvReqFinder interface {
|
|
||||||
FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error
|
|
||||||
FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProvReqService struct {
|
|
||||||
finder ProvReqFinder
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(info *distro.OSRelease, pkgFormat string) *ProvReqService {
|
|
||||||
s := &ProvReqService{
|
|
||||||
finder: &EmptyFindProvReq{},
|
|
||||||
}
|
|
||||||
if pkgFormat == "rpm" {
|
|
||||||
switch info.ID {
|
|
||||||
case "altlinux":
|
|
||||||
s.finder = &ALTLinuxFindProvReq{}
|
|
||||||
case "fedora":
|
|
||||||
s.finder = &FedoraFindProvReq{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ProvReqService) FindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
|
|
||||||
return s.finder.FindProvides(ctx, pkgInfo, dirs, skiplist)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ProvReqService) FindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, skiplist []string) error {
|
|
||||||
return s.finder.FindRequires(ctx, pkgInfo, dirs, skiplist)
|
|
||||||
}
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2/files"
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
firejailedDir = "/usr/lib/alr/firejailed"
|
|
||||||
defaultDirMode = 0o755
|
|
||||||
defaultScriptMode = 0o755
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInvalidDestination = errors.New("invalid destination path")
|
|
||||||
ErrMissingProfile = errors.New("default profile is missing")
|
|
||||||
ErrEmptyPackageName = errors.New("package name cannot be empty")
|
|
||||||
)
|
|
||||||
|
|
||||||
var binaryDirectories = []string{
|
|
||||||
"/usr/bin/",
|
|
||||||
"/bin/",
|
|
||||||
"/usr/local/bin/",
|
|
||||||
}
|
|
||||||
|
|
||||||
func moveWithSymlinkHandling(src, dst string) error {
|
|
||||||
srcInfo, err := os.Lstat(src)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get source info: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
|
|
||||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if srcInfo.Mode()&os.ModeSymlink != 0 {
|
|
||||||
return moveSymlink(src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Rename(src, dst); err != nil {
|
|
||||||
return copyAndRemove(src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func moveSymlink(src, dst string) error {
|
|
||||||
target, err := os.Readlink(src)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read symlink: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Symlink(target, dst); err != nil {
|
|
||||||
return fmt.Errorf("failed to create symlink: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Remove(src); err != nil {
|
|
||||||
os.Remove(dst)
|
|
||||||
return fmt.Errorf("failed to remove original symlink: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyAndRemove(src, dst string) error {
|
|
||||||
srcFile, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to open source: %w", err)
|
|
||||||
}
|
|
||||||
defer srcFile.Close()
|
|
||||||
|
|
||||||
dstFile, err := os.Create(dst)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create destination: %w", err)
|
|
||||||
}
|
|
||||||
defer dstFile.Close()
|
|
||||||
|
|
||||||
if _, err := io.Copy(dstFile, srcFile); err != nil {
|
|
||||||
return fmt.Errorf("failed to copy content: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
srcInfo, err := srcFile.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get source stats: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := dstFile.Chmod(srcInfo.Mode()); err != nil {
|
|
||||||
return fmt.Errorf("failed to set permissions: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Remove(src); err != nil {
|
|
||||||
return fmt.Errorf("failed to remove source: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func moveFileWithErrorHandling(src, dst string) error {
|
|
||||||
err := moveWithSymlinkHandling(src, dst)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsPermission(err) {
|
|
||||||
return fmt.Errorf("permission denied: %w", err)
|
|
||||||
}
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("source file does not exist: %w", err)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to move file: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyFirejailIntegration(
|
|
||||||
vars *alrsh.Package,
|
|
||||||
dirs types.Directories,
|
|
||||||
contents []*files.Content,
|
|
||||||
) ([]*files.Content, error) {
|
|
||||||
slog.Info(gotext.Get("Applying FireJail integration"), "package", vars.Name)
|
|
||||||
|
|
||||||
if err := createFirejailedDirectory(dirs.PkgDir); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create firejailed directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
newContents, err := processBinaryFiles(vars, contents, dirs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to process binary files: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(contents, newContents...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFirejailedDirectory(pkgDir string) error {
|
|
||||||
firejailedPath := filepath.Join(pkgDir, firejailedDir)
|
|
||||||
return os.MkdirAll(firejailedPath, defaultDirMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func processBinaryFiles(pkg *alrsh.Package, contents []*files.Content, dirs types.Directories) ([]*files.Content, error) {
|
|
||||||
var newContents []*files.Content
|
|
||||||
|
|
||||||
for _, content := range contents {
|
|
||||||
if content.Type == "dir" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isBinaryFile(content.Destination) {
|
|
||||||
slog.Debug("content not binary file", "content", content)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debug("process content", "content", content)
|
|
||||||
|
|
||||||
newContent, err := createFirejailedBinary(pkg, content, dirs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create firejailed binary for %s: %w", content.Destination, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if newContent != nil {
|
|
||||||
newContents = append(newContents, newContent...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newContents, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isBinaryFile(destination string) bool {
|
|
||||||
for _, binDir := range binaryDirectories {
|
|
||||||
if strings.HasPrefix(destination, binDir) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFirejailedBinary(
|
|
||||||
pkg *alrsh.Package,
|
|
||||||
content *files.Content,
|
|
||||||
dirs types.Directories,
|
|
||||||
) ([]*files.Content, error) {
|
|
||||||
origFilePath, err := generateFirejailedPath(content.Destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
profiles := pkg.FireJailProfiles.Resolved()
|
|
||||||
sourceProfilePath, ok := profiles[content.Destination]
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
sourceProfilePath, ok = profiles["default"]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("default profile is missing")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceProfilePath = filepath.Join(dirs.ScriptDir, sourceProfilePath)
|
|
||||||
dest, err := createFirejailProfilePath(content.Destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = createProfile(filepath.Join(dirs.PkgDir, dest), sourceProfilePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := moveFileWithErrorHandling(filepath.Join(dirs.PkgDir, content.Destination), filepath.Join(dirs.PkgDir, origFilePath)); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to move original binary: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
content.Type = "file"
|
|
||||||
content.Source = filepath.Join(dirs.PkgDir, content.Destination)
|
|
||||||
|
|
||||||
// Create wrapper script
|
|
||||||
if err := createWrapperScript(filepath.Join(dirs.PkgDir, content.Destination), origFilePath, dest); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create wrapper script: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return buildContents(pkg, dirs, &[]string{
|
|
||||||
origFilePath,
|
|
||||||
dest,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateSafeName(destination string) (string, error) {
|
|
||||||
cleanPath := strings.TrimPrefix(destination, ".")
|
|
||||||
if cleanPath == "" {
|
|
||||||
return "", fmt.Errorf("invalid destination path: %s", destination)
|
|
||||||
}
|
|
||||||
return strings.ReplaceAll(cleanPath, "/", "_"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateFirejailedPath(destination string) (string, error) {
|
|
||||||
safeName, err := generateSafeName(destination)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return filepath.Join(firejailedDir, safeName), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createProfile(destProfilePath, profilePath string) error {
|
|
||||||
srcFile, err := os.Open(profilePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer srcFile.Close()
|
|
||||||
|
|
||||||
destFile, err := os.Create(destProfilePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(destFile, srcFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return destFile.Sync()
|
|
||||||
}
|
|
||||||
|
|
||||||
func createWrapperScript(scriptPath, origFilePath, profilePath string) error {
|
|
||||||
scriptContent := fmt.Sprintf("#!/bin/bash\nexec firejail --profile=%q %q \"$@\"\n", profilePath, origFilePath)
|
|
||||||
return os.WriteFile(scriptPath, []byte(scriptContent), defaultDirMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFirejailProfilePath(binaryPath string) (string, error) {
|
|
||||||
name, err := generateSafeName(binaryPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return filepath.Join(firejailedDir, fmt.Sprintf("%s.profile", name)), nil
|
|
||||||
}
|
|
||||||
@@ -1,322 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2/files"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIsBinaryFile(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
destination string
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{"usr/bin binary", "/usr/bin/test", true},
|
|
||||||
{"bin binary", "/bin/test", true},
|
|
||||||
{"usr/local/bin binary", "/usr/local/bin/test", true},
|
|
||||||
{"lib file", "/usr/lib/test.so", false},
|
|
||||||
{"etc file", "/etc/config", false},
|
|
||||||
{"empty destination", "", false},
|
|
||||||
{"root level file", "./test", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
result := isBinaryFile(tt.destination)
|
|
||||||
assert.Equal(t, tt.expected, result)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenerateSafeName(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
destination string
|
|
||||||
expected string
|
|
||||||
expectError bool
|
|
||||||
}{
|
|
||||||
{"usr/bin path", "./usr/bin/test", "_usr_bin_test", false},
|
|
||||||
{"bin path", "./bin/test", "_bin_test", false},
|
|
||||||
{"nested path", "./usr/local/bin/app", "_usr_local_bin_app", false},
|
|
||||||
{"path with spaces", "./usr/bin/my app", "_usr_bin_my app", false},
|
|
||||||
{"empty after trim", ".", "", true},
|
|
||||||
{"empty string", "", "", true},
|
|
||||||
{"only dots", "..", ".", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
result, err := generateSafeName(tt.destination)
|
|
||||||
if tt.expectError {
|
|
||||||
assert.Error(t, err)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expected, result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateWrapperScript(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
origFilePath string
|
|
||||||
profilePath string
|
|
||||||
expectedContent string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"basic wrapper",
|
|
||||||
"/usr/lib/alr/firejailed/_usr_bin_test",
|
|
||||||
"/usr/lib/alr/firejailed/_usr_bin_test.profile",
|
|
||||||
"#!/bin/bash\nexec firejail --profile=\"/usr/lib/alr/firejailed/_usr_bin_test.profile\" \"/usr/lib/alr/firejailed/_usr_bin_test\" \"$@\"\n",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path with spaces",
|
|
||||||
"/usr/lib/alr/firejailed/_usr_bin_my_app",
|
|
||||||
"/usr/lib/alr/firejailed/_usr_bin_my_app.profile",
|
|
||||||
"#!/bin/bash\nexec firejail --profile=\"/usr/lib/alr/firejailed/_usr_bin_my_app.profile\" \"/usr/lib/alr/firejailed/_usr_bin_my_app\" \"$@\"\n",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
scriptPath := filepath.Join(tmpDir, "wrapper.sh")
|
|
||||||
|
|
||||||
err := createWrapperScript(scriptPath, tt.origFilePath, tt.profilePath)
|
|
||||||
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.FileExists(t, scriptPath)
|
|
||||||
|
|
||||||
content, err := os.ReadFile(scriptPath)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expectedContent, string(content))
|
|
||||||
|
|
||||||
// Check file permissions
|
|
||||||
info, err := os.Stat(scriptPath)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, os.FileMode(defaultDirMode), info.Mode())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateFirejailedBinary(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
setupFunc func(string) (*alrsh.Package, *files.Content, types.Directories)
|
|
||||||
expectError bool
|
|
||||||
errorMsg string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"successful creation with default profile",
|
|
||||||
func(tmpDir string) (*alrsh.Package, *files.Content, types.Directories) {
|
|
||||||
pkgDir := filepath.Join(tmpDir, "pkg")
|
|
||||||
scriptDir := filepath.Join(tmpDir, "scripts")
|
|
||||||
os.MkdirAll(pkgDir, 0o755)
|
|
||||||
os.MkdirAll(scriptDir, 0o755)
|
|
||||||
|
|
||||||
binDir := filepath.Join(pkgDir, "usr", "bin")
|
|
||||||
os.MkdirAll(binDir, 0o755)
|
|
||||||
|
|
||||||
srcBinary := filepath.Join(binDir, "test-binary")
|
|
||||||
os.WriteFile(srcBinary, []byte("#!/bin/bash\necho test"), 0o755)
|
|
||||||
|
|
||||||
defaultProfile := filepath.Join(scriptDir, "default.profile")
|
|
||||||
os.WriteFile(defaultProfile, []byte("include /etc/firejail/default.profile\nnet none"), 0o644)
|
|
||||||
|
|
||||||
pkg := &alrsh.Package{
|
|
||||||
Name: "test-pkg",
|
|
||||||
FireJailProfiles: alrsh.OverridableFromMap(map[string]map[string]string{
|
|
||||||
"": {"default": "default.profile"},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
alrsh.ResolvePackage(pkg, []string{""})
|
|
||||||
|
|
||||||
content := &files.Content{
|
|
||||||
Source: srcBinary,
|
|
||||||
Destination: "/usr/bin/test-binary",
|
|
||||||
Type: "file",
|
|
||||||
}
|
|
||||||
|
|
||||||
dirs := types.Directories{PkgDir: pkgDir, ScriptDir: scriptDir}
|
|
||||||
return pkg, content, dirs
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"successful creation with specific profile",
|
|
||||||
func(tmpDir string) (*alrsh.Package, *files.Content, types.Directories) {
|
|
||||||
pkgDir := filepath.Join(tmpDir, "pkg")
|
|
||||||
scriptDir := filepath.Join(tmpDir, "scripts")
|
|
||||||
os.MkdirAll(pkgDir, 0o755)
|
|
||||||
os.MkdirAll(scriptDir, 0o755)
|
|
||||||
|
|
||||||
binDir := filepath.Join(pkgDir, "usr", "bin")
|
|
||||||
os.MkdirAll(binDir, 0o755)
|
|
||||||
|
|
||||||
srcBinary := filepath.Join(binDir, "special-binary")
|
|
||||||
os.WriteFile(srcBinary, []byte("#!/bin/bash\necho special"), 0o755)
|
|
||||||
|
|
||||||
defaultProfile := filepath.Join(scriptDir, "default.profile")
|
|
||||||
os.WriteFile(defaultProfile, []byte("include /etc/firejail/default.profile"), 0o644)
|
|
||||||
|
|
||||||
specialProfile := filepath.Join(scriptDir, "special.profile")
|
|
||||||
os.WriteFile(specialProfile, []byte("include /etc/firejail/default.profile\nnet none\nprivate-tmp"), 0o644)
|
|
||||||
|
|
||||||
pkg := &alrsh.Package{
|
|
||||||
Name: "test-pkg",
|
|
||||||
FireJailProfiles: alrsh.OverridableFromMap(map[string]map[string]string{
|
|
||||||
"": {"default": "default.profile", "/usr/bin/special-binary": "special.profile"},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
alrsh.ResolvePackage(pkg, []string{""})
|
|
||||||
|
|
||||||
content := &files.Content{
|
|
||||||
Source: srcBinary,
|
|
||||||
Destination: "/usr/bin/special-binary",
|
|
||||||
Type: "file",
|
|
||||||
}
|
|
||||||
|
|
||||||
dirs := types.Directories{PkgDir: pkgDir, ScriptDir: scriptDir}
|
|
||||||
return pkg, content, dirs
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"missing default profile",
|
|
||||||
func(tmpDir string) (*alrsh.Package, *files.Content, types.Directories) {
|
|
||||||
pkgDir := filepath.Join(tmpDir, "pkg")
|
|
||||||
scriptDir := filepath.Join(tmpDir, "scripts")
|
|
||||||
os.MkdirAll(pkgDir, 0o755)
|
|
||||||
os.MkdirAll(scriptDir, 0o755)
|
|
||||||
|
|
||||||
srcBinary := filepath.Join(tmpDir, "test-binary")
|
|
||||||
os.WriteFile(srcBinary, []byte("#!/bin/bash\necho test"), 0o755)
|
|
||||||
|
|
||||||
pkg := &alrsh.Package{
|
|
||||||
Name: "test-pkg",
|
|
||||||
FireJailProfiles: alrsh.OverridableFromMap(map[string]map[string]string{"": {}}),
|
|
||||||
}
|
|
||||||
alrsh.ResolvePackage(pkg, []string{""})
|
|
||||||
|
|
||||||
content := &files.Content{Source: srcBinary, Destination: "./usr/bin/test-binary", Type: "file"}
|
|
||||||
dirs := types.Directories{PkgDir: pkgDir, ScriptDir: scriptDir}
|
|
||||||
return pkg, content, dirs
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
"default profile is missing",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"profile file not found",
|
|
||||||
func(tmpDir string) (*alrsh.Package, *files.Content, types.Directories) {
|
|
||||||
pkgDir := filepath.Join(tmpDir, "pkg")
|
|
||||||
scriptDir := filepath.Join(tmpDir, "scripts")
|
|
||||||
os.MkdirAll(pkgDir, 0o755)
|
|
||||||
os.MkdirAll(scriptDir, 0o755)
|
|
||||||
|
|
||||||
srcBinary := filepath.Join(tmpDir, "test-binary")
|
|
||||||
os.WriteFile(srcBinary, []byte("#!/bin/bash\necho test"), 0o755)
|
|
||||||
|
|
||||||
pkg := &alrsh.Package{
|
|
||||||
Name: "test-pkg",
|
|
||||||
FireJailProfiles: alrsh.OverridableFromMap(map[string]map[string]string{"": {"default": "nonexistent.profile"}}),
|
|
||||||
}
|
|
||||||
alrsh.ResolvePackage(pkg, []string{""})
|
|
||||||
|
|
||||||
content := &files.Content{Source: srcBinary, Destination: "./usr/bin/test-binary", Type: "file"}
|
|
||||||
dirs := types.Directories{PkgDir: pkgDir, ScriptDir: scriptDir}
|
|
||||||
return pkg, content, dirs
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"invalid destination path",
|
|
||||||
func(tmpDir string) (*alrsh.Package, *files.Content, types.Directories) {
|
|
||||||
pkgDir := filepath.Join(tmpDir, "pkg")
|
|
||||||
scriptDir := filepath.Join(tmpDir, "scripts")
|
|
||||||
os.MkdirAll(pkgDir, 0o755)
|
|
||||||
os.MkdirAll(scriptDir, 0o755)
|
|
||||||
|
|
||||||
srcBinary := filepath.Join(tmpDir, "test-binary")
|
|
||||||
os.WriteFile(srcBinary, []byte("#!/bin/bash\necho test"), 0o755)
|
|
||||||
|
|
||||||
defaultProfile := filepath.Join(scriptDir, "default.profile")
|
|
||||||
os.WriteFile(defaultProfile, []byte("include /etc/firejail/default.profile"), 0o644)
|
|
||||||
|
|
||||||
pkg := &alrsh.Package{Name: "test-pkg", FireJailProfiles: alrsh.OverridableFromMap(map[string]map[string]string{"": {"default": "default.profile"}})}
|
|
||||||
alrsh.ResolvePackage(pkg, []string{""})
|
|
||||||
|
|
||||||
content := &files.Content{Source: srcBinary, Destination: ".", Type: "file"}
|
|
||||||
dirs := types.Directories{PkgDir: pkgDir, ScriptDir: scriptDir}
|
|
||||||
return pkg, content, dirs
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
pkg, content, dirs := tt.setupFunc(tmpDir)
|
|
||||||
|
|
||||||
err := createFirejailedDirectory(dirs.PkgDir)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
result, err := createFirejailedBinary(pkg, content, dirs)
|
|
||||||
|
|
||||||
if tt.expectError {
|
|
||||||
assert.Error(t, err)
|
|
||||||
if tt.errorMsg != "" {
|
|
||||||
assert.Contains(t, err.Error(), tt.errorMsg)
|
|
||||||
}
|
|
||||||
assert.Nil(t, result)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, result, 2)
|
|
||||||
|
|
||||||
binContent := result[0]
|
|
||||||
assert.Contains(t, binContent.Destination, "usr/lib/alr/firejailed/")
|
|
||||||
assert.FileExists(t, binContent.Source)
|
|
||||||
|
|
||||||
profileContent := result[1]
|
|
||||||
assert.Contains(t, profileContent.Destination, "usr/lib/alr/firejailed/")
|
|
||||||
assert.Contains(t, profileContent.Destination, ".profile")
|
|
||||||
assert.FileExists(t, profileContent.Source)
|
|
||||||
|
|
||||||
assert.FileExists(t, content.Source)
|
|
||||||
wrapperBytes, err := os.ReadFile(content.Source)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
wrapper := string(wrapperBytes)
|
|
||||||
assert.Contains(t, wrapper, "#!/bin/bash")
|
|
||||||
assert.Contains(t, wrapper, "firejail --profile=")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewInstaller(mgr manager.Manager) *Installer {
|
|
||||||
return &Installer{
|
|
||||||
mgr: mgr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Installer struct{ mgr manager.Manager }
|
|
||||||
|
|
||||||
func (i *Installer) InstallLocal(ctx context.Context, paths []string, opts *manager.Opts) error {
|
|
||||||
return i.mgr.InstallLocal(opts, paths...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Installer) Install(ctx context.Context, pkgs []string, opts *manager.Opts) error {
|
|
||||||
return i.mgr.Install(opts, pkgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Installer) Remove(ctx context.Context, pkgs []string, opts *manager.Opts) error {
|
|
||||||
return i.mgr.Remove(opts, pkgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Installer) RemoveAlreadyInstalled(ctx context.Context, pkgs []string) ([]string, error) {
|
|
||||||
filteredPackages := []string{}
|
|
||||||
|
|
||||||
for _, dep := range pkgs {
|
|
||||||
installed, err := i.mgr.IsInstalled(dep)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if installed {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
filteredPackages = append(filteredPackages, dep)
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredPackages, nil
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewMainBuilder(
|
|
||||||
cfg Config,
|
|
||||||
mgr manager.Manager,
|
|
||||||
repos PackageFinder,
|
|
||||||
scriptExecutor ScriptExecutor,
|
|
||||||
installerExecutor InstallerExecutor,
|
|
||||||
) (*Builder, error) {
|
|
||||||
builder := &Builder{
|
|
||||||
scriptExecutor: scriptExecutor,
|
|
||||||
cacheExecutor: &Cache{
|
|
||||||
cfg,
|
|
||||||
},
|
|
||||||
scriptResolver: &ScriptResolver{
|
|
||||||
cfg,
|
|
||||||
},
|
|
||||||
scriptViewerExecutor: &ScriptViewer{
|
|
||||||
config: cfg,
|
|
||||||
},
|
|
||||||
checkerExecutor: &Checker{
|
|
||||||
mgr,
|
|
||||||
},
|
|
||||||
installerExecutor: installerExecutor,
|
|
||||||
sourceExecutor: &SourceDownloader{
|
|
||||||
cfg,
|
|
||||||
},
|
|
||||||
repos: repos,
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder, nil
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
|
||||||
"github.com/hashicorp/go-plugin"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
var pluginMap = map[string]plugin.Plugin{
|
|
||||||
"script-executor": &ScriptExecutorPlugin{},
|
|
||||||
"installer": &InstallerExecutorPlugin{},
|
|
||||||
"repos": &ReposExecutorPlugin{},
|
|
||||||
}
|
|
||||||
|
|
||||||
var HandshakeConfig = plugin.HandshakeConfig{
|
|
||||||
ProtocolVersion: 1,
|
|
||||||
MagicCookieKey: "ALR_PLUGIN",
|
|
||||||
MagicCookieValue: "-",
|
|
||||||
}
|
|
||||||
|
|
||||||
func setCommonCmdEnv(cmd *exec.Cmd) {
|
|
||||||
cmd.Env = []string{
|
|
||||||
"HOME=" + os.Getenv("HOME"),
|
|
||||||
"LOGNAME=" + os.Getenv("USER"),
|
|
||||||
"USER=" + os.Getenv("USER"),
|
|
||||||
"PATH=/usr/bin:/bin:/usr/local/bin",
|
|
||||||
}
|
|
||||||
for _, env := range os.Environ() {
|
|
||||||
if strings.HasPrefix(env, "LANG=") ||
|
|
||||||
strings.HasPrefix(env, "LANGUAGE=") ||
|
|
||||||
strings.HasPrefix(env, "LC_") ||
|
|
||||||
strings.HasPrefix(env, "ALR_LOG_LEVEL=") {
|
|
||||||
cmd.Env = append(cmd.Env, env)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPluginServeCommonConfig() *plugin.ServeConfig {
|
|
||||||
return &plugin.ServeConfig{
|
|
||||||
HandshakeConfig: HandshakeConfig,
|
|
||||||
Logger: hclog.New(&hclog.LoggerOptions{
|
|
||||||
Name: "plugin",
|
|
||||||
Output: os.Stderr,
|
|
||||||
Level: hclog.Trace,
|
|
||||||
JSONFormat: true,
|
|
||||||
DisableTime: true,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSafeInstaller() (InstallerExecutor, func(), error) {
|
|
||||||
return getSafeExecutor[InstallerExecutor]("_internal-installer", "installer")
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSafeScriptExecutor() (ScriptExecutor, func(), error) {
|
|
||||||
return getSafeExecutor[ScriptExecutor]("_internal-safe-script-executor", "script-executor")
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSafeReposExecutor() (ReposExecutor, func(), error) {
|
|
||||||
return getSafeExecutor[ReposExecutor]("_internal-repos", "repos")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSafeExecutor[T any](subCommand, pluginName string) (T, func(), error) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
executable, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
var zero T
|
|
||||||
return zero, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command(executable, subCommand)
|
|
||||||
setCommonCmdEnv(cmd)
|
|
||||||
|
|
||||||
client := plugin.NewClient(&plugin.ClientConfig{
|
|
||||||
HandshakeConfig: HandshakeConfig,
|
|
||||||
Plugins: pluginMap,
|
|
||||||
Cmd: cmd,
|
|
||||||
Logger: logger.GetHCLoggerAdapter(),
|
|
||||||
SkipHostEnv: true,
|
|
||||||
UnixSocketConfig: &plugin.UnixSocketConfig{},
|
|
||||||
SyncStderr: os.Stderr,
|
|
||||||
})
|
|
||||||
rpcClient, err := client.Client()
|
|
||||||
if err != nil {
|
|
||||||
var zero T
|
|
||||||
return zero, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var cleanupOnce sync.Once
|
|
||||||
cleanup := func() {
|
|
||||||
cleanupOnce.Do(func() {
|
|
||||||
client.Kill()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("close executor")
|
|
||||||
cleanup()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
raw, err := rpcClient.Dispense(pluginName)
|
|
||||||
if err != nil {
|
|
||||||
var zero T
|
|
||||||
return zero, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
executor, ok := raw.(T)
|
|
||||||
if !ok {
|
|
||||||
var zero T
|
|
||||||
err = fmt.Errorf("dispensed object is not a %T (got %T)", zero, raw)
|
|
||||||
return zero, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return executor, cleanup, nil
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run ../../generators/plugin-generator InstallerExecutor ScriptExecutor ReposExecutor
|
|
||||||
|
|
||||||
// The Executors interfaces must use context.Context as the first parameter,
|
|
||||||
// because the plugin-generator cannot generate code without it.
|
|
||||||
|
|
||||||
type InstallerExecutor interface {
|
|
||||||
InstallLocal(ctx context.Context, paths []string, opts *manager.Opts) error
|
|
||||||
Install(ctx context.Context, pkgs []string, opts *manager.Opts) error
|
|
||||||
Remove(ctx context.Context, pkgs []string, opts *manager.Opts) error
|
|
||||||
RemoveAlreadyInstalled(ctx context.Context, pkgs []string) ([]string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutor interface {
|
|
||||||
ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error)
|
|
||||||
ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error)
|
|
||||||
PrepareDirs(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
basePkg string,
|
|
||||||
) error
|
|
||||||
ExecuteSecondPass(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
sf *alrsh.ScriptFile,
|
|
||||||
varsOfPackages []*alrsh.Package,
|
|
||||||
repoDeps []string,
|
|
||||||
builtDeps []*BuiltDep,
|
|
||||||
basePkg string,
|
|
||||||
) ([]*BuiltDep, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReposExecutor interface {
|
|
||||||
PullOneAndUpdateFromConfig(ctx context.Context, repo *types.Repo) (types.Repo, error)
|
|
||||||
}
|
|
||||||
@@ -1,369 +0,0 @@
|
|||||||
// DO NOT EDIT MANUALLY. This file is generated.
|
|
||||||
|
|
||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"net/rpc"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
"github.com/hashicorp/go-plugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InstallerExecutorPlugin struct {
|
|
||||||
Impl InstallerExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorRPCServer struct {
|
|
||||||
Impl InstallerExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorRPC struct {
|
|
||||||
client *rpc.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *InstallerExecutorPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
|
||||||
return &InstallerExecutorRPC{client: c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *InstallerExecutorPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
|
|
||||||
return &InstallerExecutorRPCServer{Impl: p.Impl}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorPlugin struct {
|
|
||||||
Impl ScriptExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorRPCServer struct {
|
|
||||||
Impl ScriptExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorRPC struct {
|
|
||||||
client *rpc.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ScriptExecutorPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
|
||||||
return &ScriptExecutorRPC{client: c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ScriptExecutorPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
|
|
||||||
return &ScriptExecutorRPCServer{Impl: p.Impl}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReposExecutorPlugin struct {
|
|
||||||
Impl ReposExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReposExecutorRPCServer struct {
|
|
||||||
Impl ReposExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReposExecutorRPC struct {
|
|
||||||
client *rpc.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ReposExecutorPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
|
||||||
return &ReposExecutorRPC{client: c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ReposExecutorPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
|
|
||||||
return &ReposExecutorRPCServer{Impl: p.Impl}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorInstallLocalArgs struct {
|
|
||||||
Paths []string
|
|
||||||
Opts *manager.Opts
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorInstallLocalResp struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPC) InstallLocal(ctx context.Context, paths []string, opts *manager.Opts) error {
|
|
||||||
var resp *InstallerExecutorInstallLocalResp
|
|
||||||
err := s.client.Call("Plugin.InstallLocal", &InstallerExecutorInstallLocalArgs{
|
|
||||||
Paths: paths,
|
|
||||||
Opts: opts,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPCServer) InstallLocal(args *InstallerExecutorInstallLocalArgs, resp *InstallerExecutorInstallLocalResp) error {
|
|
||||||
err := s.Impl.InstallLocal(context.Background(), args.Paths, args.Opts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = InstallerExecutorInstallLocalResp{}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorInstallArgs struct {
|
|
||||||
Pkgs []string
|
|
||||||
Opts *manager.Opts
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorInstallResp struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPC) Install(ctx context.Context, pkgs []string, opts *manager.Opts) error {
|
|
||||||
var resp *InstallerExecutorInstallResp
|
|
||||||
err := s.client.Call("Plugin.Install", &InstallerExecutorInstallArgs{
|
|
||||||
Pkgs: pkgs,
|
|
||||||
Opts: opts,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPCServer) Install(args *InstallerExecutorInstallArgs, resp *InstallerExecutorInstallResp) error {
|
|
||||||
err := s.Impl.Install(context.Background(), args.Pkgs, args.Opts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = InstallerExecutorInstallResp{}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorRemoveArgs struct {
|
|
||||||
Pkgs []string
|
|
||||||
Opts *manager.Opts
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorRemoveResp struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPC) Remove(ctx context.Context, pkgs []string, opts *manager.Opts) error {
|
|
||||||
var resp *InstallerExecutorRemoveResp
|
|
||||||
err := s.client.Call("Plugin.Remove", &InstallerExecutorRemoveArgs{
|
|
||||||
Pkgs: pkgs,
|
|
||||||
Opts: opts,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPCServer) Remove(args *InstallerExecutorRemoveArgs, resp *InstallerExecutorRemoveResp) error {
|
|
||||||
err := s.Impl.Remove(context.Background(), args.Pkgs, args.Opts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = InstallerExecutorRemoveResp{}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorRemoveAlreadyInstalledArgs struct {
|
|
||||||
Pkgs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallerExecutorRemoveAlreadyInstalledResp struct {
|
|
||||||
Result0 []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPC) RemoveAlreadyInstalled(ctx context.Context, pkgs []string) ([]string, error) {
|
|
||||||
var resp *InstallerExecutorRemoveAlreadyInstalledResp
|
|
||||||
err := s.client.Call("Plugin.RemoveAlreadyInstalled", &InstallerExecutorRemoveAlreadyInstalledArgs{
|
|
||||||
Pkgs: pkgs,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Result0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *InstallerExecutorRPCServer) RemoveAlreadyInstalled(args *InstallerExecutorRemoveAlreadyInstalledArgs, resp *InstallerExecutorRemoveAlreadyInstalledResp) error {
|
|
||||||
result0, err := s.Impl.RemoveAlreadyInstalled(context.Background(), args.Pkgs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = InstallerExecutorRemoveAlreadyInstalledResp{
|
|
||||||
Result0: result0,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorReadScriptArgs struct {
|
|
||||||
ScriptPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorReadScriptResp struct {
|
|
||||||
Result0 *alrsh.ScriptFile
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPC) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) {
|
|
||||||
var resp *ScriptExecutorReadScriptResp
|
|
||||||
err := s.client.Call("Plugin.ReadScript", &ScriptExecutorReadScriptArgs{
|
|
||||||
ScriptPath: scriptPath,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Result0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPCServer) ReadScript(args *ScriptExecutorReadScriptArgs, resp *ScriptExecutorReadScriptResp) error {
|
|
||||||
result0, err := s.Impl.ReadScript(context.Background(), args.ScriptPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = ScriptExecutorReadScriptResp{
|
|
||||||
Result0: result0,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorExecuteFirstPassArgs struct {
|
|
||||||
Input *BuildInput
|
|
||||||
Sf *alrsh.ScriptFile
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorExecuteFirstPassResp struct {
|
|
||||||
Result0 string
|
|
||||||
Result1 []*alrsh.Package
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPC) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) {
|
|
||||||
var resp *ScriptExecutorExecuteFirstPassResp
|
|
||||||
err := s.client.Call("Plugin.ExecuteFirstPass", &ScriptExecutorExecuteFirstPassArgs{
|
|
||||||
Input: input,
|
|
||||||
Sf: sf,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
return resp.Result0, resp.Result1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPCServer) ExecuteFirstPass(args *ScriptExecutorExecuteFirstPassArgs, resp *ScriptExecutorExecuteFirstPassResp) error {
|
|
||||||
result0, result1, err := s.Impl.ExecuteFirstPass(context.Background(), args.Input, args.Sf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = ScriptExecutorExecuteFirstPassResp{
|
|
||||||
Result0: result0,
|
|
||||||
Result1: result1,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorPrepareDirsArgs struct {
|
|
||||||
Input *BuildInput
|
|
||||||
BasePkg string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorPrepareDirsResp struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPC) PrepareDirs(ctx context.Context, input *BuildInput, basePkg string) error {
|
|
||||||
var resp *ScriptExecutorPrepareDirsResp
|
|
||||||
err := s.client.Call("Plugin.PrepareDirs", &ScriptExecutorPrepareDirsArgs{
|
|
||||||
Input: input,
|
|
||||||
BasePkg: basePkg,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPCServer) PrepareDirs(args *ScriptExecutorPrepareDirsArgs, resp *ScriptExecutorPrepareDirsResp) error {
|
|
||||||
err := s.Impl.PrepareDirs(context.Background(), args.Input, args.BasePkg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = ScriptExecutorPrepareDirsResp{}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorExecuteSecondPassArgs struct {
|
|
||||||
Input *BuildInput
|
|
||||||
Sf *alrsh.ScriptFile
|
|
||||||
VarsOfPackages []*alrsh.Package
|
|
||||||
RepoDeps []string
|
|
||||||
BuiltDeps []*BuiltDep
|
|
||||||
BasePkg string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptExecutorExecuteSecondPassResp struct {
|
|
||||||
Result0 []*BuiltDep
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPC) ExecuteSecondPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile, varsOfPackages []*alrsh.Package, repoDeps []string, builtDeps []*BuiltDep, basePkg string) ([]*BuiltDep, error) {
|
|
||||||
var resp *ScriptExecutorExecuteSecondPassResp
|
|
||||||
err := s.client.Call("Plugin.ExecuteSecondPass", &ScriptExecutorExecuteSecondPassArgs{
|
|
||||||
Input: input,
|
|
||||||
Sf: sf,
|
|
||||||
VarsOfPackages: varsOfPackages,
|
|
||||||
RepoDeps: repoDeps,
|
|
||||||
BuiltDeps: builtDeps,
|
|
||||||
BasePkg: basePkg,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Result0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptExecutorRPCServer) ExecuteSecondPass(args *ScriptExecutorExecuteSecondPassArgs, resp *ScriptExecutorExecuteSecondPassResp) error {
|
|
||||||
result0, err := s.Impl.ExecuteSecondPass(context.Background(), args.Input, args.Sf, args.VarsOfPackages, args.RepoDeps, args.BuiltDeps, args.BasePkg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = ScriptExecutorExecuteSecondPassResp{
|
|
||||||
Result0: result0,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReposExecutorPullOneAndUpdateFromConfigArgs struct {
|
|
||||||
Repo *types.Repo
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReposExecutorPullOneAndUpdateFromConfigResp struct {
|
|
||||||
Result0 types.Repo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ReposExecutorRPC) PullOneAndUpdateFromConfig(ctx context.Context, repo *types.Repo) (types.Repo, error) {
|
|
||||||
var resp *ReposExecutorPullOneAndUpdateFromConfigResp
|
|
||||||
err := s.client.Call("Plugin.PullOneAndUpdateFromConfig", &ReposExecutorPullOneAndUpdateFromConfigArgs{
|
|
||||||
Repo: repo,
|
|
||||||
}, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return types.Repo{}, err
|
|
||||||
}
|
|
||||||
return resp.Result0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ReposExecutorRPCServer) PullOneAndUpdateFromConfig(args *ReposExecutorPullOneAndUpdateFromConfigArgs, resp *ReposExecutorPullOneAndUpdateFromConfigResp) error {
|
|
||||||
result0, err := s.Impl.PullOneAndUpdateFromConfig(context.Background(), args.Repo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*resp = ReposExecutorPullOneAndUpdateFromConfigResp{
|
|
||||||
Result0: result0,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/repos"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type reposExecutor struct{ r *repos.Repos }
|
|
||||||
|
|
||||||
func NewRepos(r *repos.Repos) ReposExecutor {
|
|
||||||
return &reposExecutor{r}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reposExecutor) PullOneAndUpdateFromConfig(ctx context.Context, repo *types.Repo) (types.Repo, error) {
|
|
||||||
if err := r.r.PullOneAndUpdateFromConfig(ctx, repo); err != nil {
|
|
||||||
return *repo, err
|
|
||||||
}
|
|
||||||
return *repo, nil
|
|
||||||
}
|
|
||||||
@@ -1,364 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"slices"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/shlex"
|
|
||||||
"github.com/goreleaser/nfpm/v2"
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
"mvdan.cc/sh/v3/expand"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
"mvdan.cc/sh/v3/syntax"
|
|
||||||
|
|
||||||
finddeps "gitea.plemya-x.ru/Plemya-x/ALR/internal/build/find_deps"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/helpers"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LocalScriptExecutor struct {
|
|
||||||
cfg Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLocalScriptExecutor(cfg Config) *LocalScriptExecutor {
|
|
||||||
return &LocalScriptExecutor{
|
|
||||||
cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *LocalScriptExecutor) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) {
|
|
||||||
return alrsh.ReadFromLocal(scriptPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *LocalScriptExecutor) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) {
|
|
||||||
return sf.ParseBuildVars(ctx, input.info, input.packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *LocalScriptExecutor) PrepareDirs(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
basePkg string,
|
|
||||||
) error {
|
|
||||||
dirs, err := getDirs(
|
|
||||||
e.cfg,
|
|
||||||
input.script,
|
|
||||||
basePkg,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = prepareDirs(dirs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *LocalScriptExecutor) ExecuteSecondPass(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
sf *alrsh.ScriptFile,
|
|
||||||
varsOfPackages []*alrsh.Package,
|
|
||||||
repoDeps []string,
|
|
||||||
builtDeps []*BuiltDep,
|
|
||||||
basePkg string,
|
|
||||||
) ([]*BuiltDep, error) {
|
|
||||||
dirs, err := getDirs(e.cfg, sf.Path(), basePkg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
env := createBuildEnvVars(input.info, dirs)
|
|
||||||
|
|
||||||
fakeroot := handlers.FakerootExecHandler(2 * time.Second)
|
|
||||||
runner, err := interp.New(
|
|
||||||
interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
|
|
||||||
interp.StdIO(os.Stdin, os.Stderr, os.Stderr), // Устанавливаем стандартный ввод-вывод
|
|
||||||
interp.ExecHandlers(func(next interp.ExecHandlerFunc) interp.ExecHandlerFunc {
|
|
||||||
return helpers.Helpers.ExecHandler(fakeroot)
|
|
||||||
}), // Обрабатываем выполнение через fakeroot
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = runner.Run(ctx, sf.File())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dec := decoder.New(input.info, runner)
|
|
||||||
|
|
||||||
// var builtPaths []string
|
|
||||||
|
|
||||||
err = e.ExecuteFunctions(ctx, dirs, dec)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, vars := range varsOfPackages {
|
|
||||||
packageName := ""
|
|
||||||
if vars.BasePkgName != "" {
|
|
||||||
packageName = vars.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgFormat := input.pkgFormat
|
|
||||||
|
|
||||||
funcOut, err := e.ExecutePackageFunctions(
|
|
||||||
ctx,
|
|
||||||
dec,
|
|
||||||
dirs,
|
|
||||||
packageName,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Info(gotext.Get("Building package metadata"), "name", basePkg)
|
|
||||||
|
|
||||||
pkgInfo, err := buildPkgMetadata(
|
|
||||||
ctx,
|
|
||||||
input,
|
|
||||||
vars,
|
|
||||||
dirs,
|
|
||||||
append(
|
|
||||||
repoDeps,
|
|
||||||
GetBuiltName(builtDeps)...,
|
|
||||||
),
|
|
||||||
funcOut.Contents,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
packager, err := nfpm.Get(pkgFormat) // Получаем упаковщик для формата пакета
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета
|
|
||||||
pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету
|
|
||||||
|
|
||||||
pkgFile, err := os.Create(pkgPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = packager.Package(pkgInfo, pkgFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
builtDeps = append(builtDeps, &BuiltDep{
|
|
||||||
Name: vars.Name,
|
|
||||||
Path: pkgPath,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return builtDeps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildPkgMetadata(
|
|
||||||
ctx context.Context,
|
|
||||||
input interface {
|
|
||||||
OsInfoProvider
|
|
||||||
BuildOptsProvider
|
|
||||||
PkgFormatProvider
|
|
||||||
RepositoryProvider
|
|
||||||
},
|
|
||||||
vars *alrsh.Package,
|
|
||||||
dirs types.Directories,
|
|
||||||
deps []string,
|
|
||||||
preferedContents *[]string,
|
|
||||||
) (*nfpm.Info, error) {
|
|
||||||
pkgInfo := getBasePkgInfo(vars, input)
|
|
||||||
pkgInfo.Description = vars.Description.Resolved()
|
|
||||||
pkgInfo.Platform = "linux"
|
|
||||||
pkgInfo.Homepage = vars.Homepage.Resolved()
|
|
||||||
pkgInfo.License = strings.Join(vars.Licenses, ", ")
|
|
||||||
pkgInfo.Maintainer = vars.Maintainer.Resolved()
|
|
||||||
pkgInfo.Overridables = nfpm.Overridables{
|
|
||||||
Conflicts: append(vars.Conflicts, vars.Name),
|
|
||||||
Replaces: vars.Replaces,
|
|
||||||
Provides: append(vars.Provides, vars.Name),
|
|
||||||
Depends: deps,
|
|
||||||
}
|
|
||||||
pkgInfo.Section = vars.Group.Resolved()
|
|
||||||
|
|
||||||
pkgFormat := input.PkgFormat()
|
|
||||||
info := input.OSRelease()
|
|
||||||
|
|
||||||
if pkgFormat == "apk" {
|
|
||||||
// Alpine отказывается устанавливать пакеты, которые предоставляют сами себя, поэтому удаляем такие элементы
|
|
||||||
pkgInfo.Overridables.Provides = slices.DeleteFunc(pkgInfo.Overridables.Provides, func(s string) bool {
|
|
||||||
return s == pkgInfo.Name
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if pkgFormat == "rpm" {
|
|
||||||
pkgInfo.RPM.Group = vars.Group.Resolved()
|
|
||||||
|
|
||||||
if vars.Summary.Resolved() != "" {
|
|
||||||
pkgInfo.RPM.Summary = vars.Summary.Resolved()
|
|
||||||
} else {
|
|
||||||
lines := strings.SplitN(vars.Description.Resolved(), "\n", 2)
|
|
||||||
pkgInfo.RPM.Summary = lines[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if vars.Epoch != 0 {
|
|
||||||
pkgInfo.Epoch = strconv.FormatUint(uint64(vars.Epoch), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
setScripts(vars, pkgInfo, dirs.ScriptDir)
|
|
||||||
|
|
||||||
if slices.Contains(vars.Architectures, "all") {
|
|
||||||
pkgInfo.Arch = "all"
|
|
||||||
}
|
|
||||||
|
|
||||||
contents, err := buildContents(vars, dirs, preferedContents)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
normalizeContents(contents)
|
|
||||||
|
|
||||||
if vars.FireJailed.Resolved() {
|
|
||||||
contents, err = applyFirejailIntegration(vars, dirs, contents)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgInfo.Overridables.Contents = contents
|
|
||||||
|
|
||||||
if len(vars.AutoProv.Resolved()) == 1 && decoder.IsTruthy(vars.AutoProv.Resolved()[0]) {
|
|
||||||
f := finddeps.New(info, pkgFormat)
|
|
||||||
err = f.FindProvides(ctx, pkgInfo, dirs, vars.AutoProvSkipList.Resolved())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(vars.AutoReq.Resolved()) == 1 && decoder.IsTruthy(vars.AutoReq.Resolved()[0]) {
|
|
||||||
f := finddeps.New(info, pkgFormat)
|
|
||||||
err = f.FindRequires(ctx, pkgInfo, dirs, vars.AutoReqSkipList.Resolved())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkgInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *LocalScriptExecutor) ExecuteFunctions(ctx context.Context, dirs types.Directories, dec *decoder.Decoder) error {
|
|
||||||
prepare, ok := dec.GetFunc("prepare")
|
|
||||||
if ok {
|
|
||||||
slog.Info(gotext.Get("Executing prepare()"))
|
|
||||||
|
|
||||||
err := prepare(ctx, interp.Dir(dirs.SrcDir))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
build, ok := dec.GetFunc("build")
|
|
||||||
if ok {
|
|
||||||
slog.Info(gotext.Get("Executing build()"))
|
|
||||||
|
|
||||||
err := build(ctx, interp.Dir(dirs.SrcDir))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *LocalScriptExecutor) ExecutePackageFunctions(
|
|
||||||
ctx context.Context,
|
|
||||||
dec *decoder.Decoder,
|
|
||||||
dirs types.Directories,
|
|
||||||
packageName string,
|
|
||||||
) (*FunctionsOutput, error) {
|
|
||||||
output := &FunctionsOutput{}
|
|
||||||
var packageFuncName string
|
|
||||||
var filesFuncName string
|
|
||||||
|
|
||||||
if packageName == "" {
|
|
||||||
packageFuncName = "package"
|
|
||||||
filesFuncName = "files"
|
|
||||||
} else {
|
|
||||||
packageFuncName = fmt.Sprintf("package_%s", packageName)
|
|
||||||
filesFuncName = fmt.Sprintf("files_%s", packageName)
|
|
||||||
}
|
|
||||||
packageFn, ok := dec.GetFunc(packageFuncName)
|
|
||||||
if ok {
|
|
||||||
slog.Info(gotext.Get("Executing %s()", packageFuncName))
|
|
||||||
err := packageFn(ctx, interp.Dir(dirs.SrcDir))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
files, ok := dec.GetFuncP(filesFuncName, func(ctx context.Context, s *interp.Runner) error {
|
|
||||||
// It should be done via interp.RunnerOption,
|
|
||||||
// but due to the issues below, it cannot be done.
|
|
||||||
// - https://github.com/mvdan/sh/issues/962
|
|
||||||
// - https://github.com/mvdan/sh/issues/1125
|
|
||||||
script, err := syntax.NewParser().Parse(strings.NewReader("cd $pkgdir && shopt -s globstar"), "")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.Run(ctx, script)
|
|
||||||
})
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
slog.Info(gotext.Get("Executing %s()", filesFuncName))
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := files(
|
|
||||||
ctx,
|
|
||||||
interp.Dir(dirs.PkgDir),
|
|
||||||
interp.StdIO(os.Stdin, buf, os.Stderr),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
contents, err := shlex.Split(buf.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
output.Contents = &contents
|
|
||||||
}
|
|
||||||
|
|
||||||
return output, nil
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ScriptResolver struct {
|
|
||||||
cfg Config
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptInfo struct {
|
|
||||||
Script string
|
|
||||||
Repository string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptResolver) ResolveScript(
|
|
||||||
ctx context.Context,
|
|
||||||
pkg *alrsh.Package,
|
|
||||||
) *ScriptInfo {
|
|
||||||
var repository, script string
|
|
||||||
|
|
||||||
repodir := s.cfg.GetPaths().RepoDir
|
|
||||||
repository = pkg.Repository
|
|
||||||
|
|
||||||
// First, we check if there is a root alr.sh in the repository
|
|
||||||
rootScriptPath := filepath.Join(repodir, repository, "alr.sh")
|
|
||||||
if _, err := os.Stat(rootScriptPath); err == nil {
|
|
||||||
// A repository with a single alr.sh at the root
|
|
||||||
script = rootScriptPath
|
|
||||||
} else {
|
|
||||||
// Multi-package repository - we are looking for alr.sh in the subfolder
|
|
||||||
var scriptPath string
|
|
||||||
if pkg.BasePkgName != "" {
|
|
||||||
scriptPath = filepath.Join(repodir, repository, pkg.BasePkgName, "alr.sh")
|
|
||||||
} else {
|
|
||||||
scriptPath = filepath.Join(repodir, repository, pkg.Name, "alr.sh")
|
|
||||||
}
|
|
||||||
script = scriptPath
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ScriptInfo{
|
|
||||||
Repository: repository,
|
|
||||||
Script: script,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ScriptViewerConfig interface {
|
|
||||||
PagerStyle() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScriptViewer struct {
|
|
||||||
config ScriptViewerConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ScriptViewer) ViewScript(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
a *alrsh.ScriptFile,
|
|
||||||
basePkg string,
|
|
||||||
) error {
|
|
||||||
return cliutils.PromptViewScript(
|
|
||||||
ctx,
|
|
||||||
a.Path(),
|
|
||||||
basePkg,
|
|
||||||
s.config.PagerStyle(),
|
|
||||||
input.opts.Interactive,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"context"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/constants"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/dl"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/dlcache"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SourceDownloader struct {
|
|
||||||
cfg Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSourceDownloader(cfg Config) *SourceDownloader {
|
|
||||||
return &SourceDownloader{
|
|
||||||
cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SourceDownloader) DownloadSources(
|
|
||||||
ctx context.Context,
|
|
||||||
input *BuildInput,
|
|
||||||
basePkg string,
|
|
||||||
si SourcesInput,
|
|
||||||
) error {
|
|
||||||
for i, src := range si.Sources {
|
|
||||||
|
|
||||||
opts := dl.Options{
|
|
||||||
Name: fmt.Sprintf("[%d]", i),
|
|
||||||
URL: src,
|
|
||||||
Destination: getSrcDir(s.cfg, basePkg),
|
|
||||||
Progress: os.Stderr,
|
|
||||||
LocalDir: getScriptDir(input.script),
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.EqualFold(si.Checksums[i], "SKIP") {
|
|
||||||
// Если контрольная сумма содержит двоеточие, используйте часть до двоеточия
|
|
||||||
// как алгоритм, а часть после как фактическую контрольную сумму.
|
|
||||||
// В противном случае используйте sha256 по умолчанию с целой строкой как контрольной суммой.
|
|
||||||
algo, hashData, ok := strings.Cut(si.Checksums[i], ":")
|
|
||||||
if ok {
|
|
||||||
checksum, err := hex.DecodeString(hashData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
opts.Hash = checksum
|
|
||||||
opts.HashAlgorithm = algo
|
|
||||||
} else {
|
|
||||||
checksum, err := hex.DecodeString(si.Checksums[i])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
opts.Hash = checksum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Используем временную директорию для загрузок
|
|
||||||
// dlcache.New добавит свой подкаталог "dl" внутри
|
|
||||||
opts.DlCache = dlcache.New(constants.TempDir)
|
|
||||||
|
|
||||||
err := dl.Download(ctx, opts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mockInput struct {
|
|
||||||
repo string
|
|
||||||
osInfo *distro.OSRelease
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockInput) Repository() string {
|
|
||||||
return m.repo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockInput) OSRelease() *distro.OSRelease {
|
|
||||||
return m.osInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetBasePkgInfo(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
packageName string
|
|
||||||
repoName string
|
|
||||||
expectedName string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "обычный репозиторий",
|
|
||||||
packageName: "test-package",
|
|
||||||
repoName: "default",
|
|
||||||
expectedName: "test-package+default",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "репозиторий с alr- префиксом",
|
|
||||||
packageName: "test-package",
|
|
||||||
repoName: "alr-default",
|
|
||||||
expectedName: "test-package+alr-default",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "репозиторий с двойным alr- префиксом",
|
|
||||||
packageName: "test-package",
|
|
||||||
repoName: "alr-alr-repo",
|
|
||||||
expectedName: "test-package+alr-alr-repo",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
pkg := &alrsh.Package{
|
|
||||||
Name: tt.packageName,
|
|
||||||
Version: "1.0.0",
|
|
||||||
Release: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
input := &mockInput{
|
|
||||||
repo: tt.repoName,
|
|
||||||
osInfo: &distro.OSRelease{
|
|
||||||
ID: "test",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
info := getBasePkgInfo(pkg, input)
|
|
||||||
|
|
||||||
if info.Name != tt.expectedName {
|
|
||||||
t.Errorf("getBasePkgInfo() имя пакета = %v, ожидается %v", info.Name, tt.expectedName)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegexpALRPackageName(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
packageName string
|
|
||||||
expectedPkg string
|
|
||||||
expectedRepo string
|
|
||||||
shouldMatch bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "новый формат - обычный репозиторий",
|
|
||||||
packageName: "test-package+default",
|
|
||||||
expectedPkg: "test-package",
|
|
||||||
expectedRepo: "default",
|
|
||||||
shouldMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "новый формат - alr-default репозиторий",
|
|
||||||
packageName: "test-package+alr-default",
|
|
||||||
expectedPkg: "test-package",
|
|
||||||
expectedRepo: "alr-default",
|
|
||||||
shouldMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "новый формат - двойной alr- префикс",
|
|
||||||
packageName: "test-package+alr-alr-repo",
|
|
||||||
expectedPkg: "test-package",
|
|
||||||
expectedRepo: "alr-alr-repo",
|
|
||||||
shouldMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "некорректный формат - без плюса",
|
|
||||||
packageName: "test-package",
|
|
||||||
shouldMatch: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "некорректный формат - пустое имя пакета",
|
|
||||||
packageName: "+repo",
|
|
||||||
shouldMatch: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
matches := RegexpALRPackageName.FindStringSubmatch(tt.packageName)
|
|
||||||
|
|
||||||
if tt.shouldMatch {
|
|
||||||
if matches == nil {
|
|
||||||
t.Errorf("RegexpALRPackageName должен найти совпадение для %q", tt.packageName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
packageName := matches[RegexpALRPackageName.SubexpIndex("package")]
|
|
||||||
repoName := matches[RegexpALRPackageName.SubexpIndex("repo")]
|
|
||||||
|
|
||||||
if packageName != tt.expectedPkg {
|
|
||||||
t.Errorf("RegexpALRPackageName извлеченное имя пакета = %v, ожидается %v", packageName, tt.expectedPkg)
|
|
||||||
}
|
|
||||||
|
|
||||||
if repoName != tt.expectedRepo {
|
|
||||||
t.Errorf("RegexpALRPackageName извлеченное имя репозитория = %v, ожидается %v", repoName, tt.expectedRepo)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if matches != nil {
|
|
||||||
t.Errorf("RegexpALRPackageName не должен найти совпадение для %q", tt.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 appbuilder
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/repos"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AppDeps struct {
|
|
||||||
Cfg *config.ALRConfig
|
|
||||||
DB *db.Database
|
|
||||||
Repos *repos.Repos
|
|
||||||
Info *distro.OSRelease
|
|
||||||
Manager manager.Manager
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *AppDeps) Defer() {
|
|
||||||
if d.DB != nil {
|
|
||||||
if err := d.DB.Close(); err != nil {
|
|
||||||
slog.Warn("failed to close db", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppBuilder struct {
|
|
||||||
deps AppDeps
|
|
||||||
err error
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context) *AppBuilder {
|
|
||||||
return &AppBuilder{ctx: ctx}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) UseConfig(cfg *config.ALRConfig) *AppBuilder {
|
|
||||||
if b.err != nil {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
b.deps.Cfg = cfg
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) WithConfig() *AppBuilder {
|
|
||||||
if b.err != nil {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := config.New()
|
|
||||||
if err := cfg.Load(); err != nil {
|
|
||||||
b.err = cliutils.FormatCliExit(gotext.Get("Error loading config"), err)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
b.deps.Cfg = cfg
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) WithDB() *AppBuilder {
|
|
||||||
if b.err != nil {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := b.deps.Cfg
|
|
||||||
if cfg == nil {
|
|
||||||
b.err = errors.New("config is required before initializing DB")
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
db := db.New(cfg)
|
|
||||||
if err := db.Init(b.ctx); err != nil {
|
|
||||||
b.err = cliutils.FormatCliExit(gotext.Get("Error initialization database"), err)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
b.deps.DB = db
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) WithRepos() *AppBuilder {
|
|
||||||
b.withRepos(true, false)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) WithReposForcePull() *AppBuilder {
|
|
||||||
b.withRepos(true, true)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) WithReposNoPull() *AppBuilder {
|
|
||||||
b.withRepos(false, false)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) withRepos(enablePull, forcePull bool) *AppBuilder {
|
|
||||||
if b.err != nil {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := b.deps.Cfg
|
|
||||||
db := b.deps.DB
|
|
||||||
info := b.deps.Info
|
|
||||||
|
|
||||||
if info == nil {
|
|
||||||
b.WithDistroInfo()
|
|
||||||
info = b.deps.Info
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg == nil || db == nil || info == nil {
|
|
||||||
b.err = errors.New("config, db and info are required before initializing repos")
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
rs := repos.New(cfg, db)
|
|
||||||
|
|
||||||
if enablePull && (forcePull || cfg.AutoPull()) {
|
|
||||||
if err := rs.Pull(b.ctx, cfg.Repos()); err != nil {
|
|
||||||
b.err = cliutils.FormatCliExit(gotext.Get("Error pulling repositories"), err)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.deps.Repos = rs
|
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) WithDistroInfo() *AppBuilder {
|
|
||||||
if b.err != nil {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
b.deps.Info, b.err = distro.ParseOSRelease(b.ctx)
|
|
||||||
if b.err != nil {
|
|
||||||
b.err = cliutils.FormatCliExit(gotext.Get("Error parsing os release"), b.err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) WithManager() *AppBuilder {
|
|
||||||
if b.err != nil {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
b.deps.Manager = manager.Detect()
|
|
||||||
if b.deps.Manager == nil {
|
|
||||||
b.err = cliutils.FormatCliExit(gotext.Get("Unable to detect a supported package manager on the system"), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AppBuilder) Build() (*AppDeps, error) {
|
|
||||||
if b.err != nil {
|
|
||||||
return nil, b.err
|
|
||||||
}
|
|
||||||
return &b.deps, nil
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -28,8 +28,8 @@ import (
|
|||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
|
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/pager"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/pager"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// YesNoPrompt asks the user a yes or no question, using def as the default answer
|
// YesNoPrompt asks the user a yes or no question, using def as the default answer
|
||||||
@@ -102,65 +102,25 @@ func ShowScript(path, name, style string) error {
|
|||||||
|
|
||||||
// FlattenPkgs attempts to flatten the a map of slices of packages into a single slice
|
// FlattenPkgs attempts to flatten the a map of slices of packages into a single slice
|
||||||
// of packages by prompting the user if multiple packages match.
|
// of packages by prompting the user if multiple packages match.
|
||||||
func FlattenPkgs(ctx context.Context, found map[string][]alrsh.Package, verb string, interactive bool) []alrsh.Package {
|
func FlattenPkgs(ctx context.Context, found map[string][]db.Package, verb string, interactive bool) []db.Package {
|
||||||
return FlattenPkgsWithContext(ctx, found, verb, interactive, false)
|
var outPkgs []db.Package
|
||||||
}
|
|
||||||
|
|
||||||
// FlattenPkgsWithContext расширенная версия FlattenPkgs с контекстом обработки зависимостей
|
|
||||||
func FlattenPkgsWithContext(ctx context.Context, found map[string][]alrsh.Package, verb string, interactive bool, isDependency bool) []alrsh.Package {
|
|
||||||
var outPkgs []alrsh.Package
|
|
||||||
for _, pkgs := range found {
|
for _, pkgs := range found {
|
||||||
if len(pkgs) > 1 {
|
if len(pkgs) > 1 && interactive {
|
||||||
// Проверяем, являются ли пакеты подпакетами одного мультипакета
|
|
||||||
if isMultiPackage(pkgs) && verb == "install" {
|
|
||||||
// Для мультипакетов при установке ВСЕГДА берем все подпакеты без выбора
|
|
||||||
// Это правильное поведение как для прямой установки, так и для зависимостей
|
|
||||||
outPkgs = append(outPkgs, pkgs...)
|
|
||||||
} else if interactive {
|
|
||||||
// Для разных пакетов с одинаковым именем - показываем меню выбора
|
|
||||||
choice, err := PkgPrompt(ctx, pkgs, verb, interactive)
|
choice, err := PkgPrompt(ctx, pkgs, verb, interactive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error(gotext.Get("Error prompting for choice of package"))
|
slog.Error(gotext.Get("Error prompting for choice of package"))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
outPkgs = append(outPkgs, choice)
|
outPkgs = append(outPkgs, choice)
|
||||||
} else {
|
} else if len(pkgs) == 1 || !interactive {
|
||||||
// Если не интерактивный режим - берем первый
|
|
||||||
outPkgs = append(outPkgs, pkgs[0])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Если только один пакет - берем его
|
|
||||||
outPkgs = append(outPkgs, pkgs[0])
|
outPkgs = append(outPkgs, pkgs[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return outPkgs
|
return outPkgs
|
||||||
}
|
}
|
||||||
|
|
||||||
// isMultiPackage проверяет, являются ли пакеты подпакетами одного мультипакета
|
|
||||||
func isMultiPackage(pkgs []alrsh.Package) bool {
|
|
||||||
if len(pkgs) <= 1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверяем, что у всех пакетов одинаковый BasePkgName и Repository
|
|
||||||
firstBasePkg := pkgs[0].BasePkgName
|
|
||||||
firstRepo := pkgs[0].Repository
|
|
||||||
|
|
||||||
if firstBasePkg == "" {
|
|
||||||
return false // Не мультипакет
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pkg := range pkgs[1:] {
|
|
||||||
if pkg.BasePkgName != firstBasePkg || pkg.Repository != firstRepo {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// PkgPrompt asks the user to choose between multiple packages.
|
// PkgPrompt asks the user to choose between multiple packages.
|
||||||
func PkgPrompt(ctx context.Context, options []alrsh.Package, verb string, interactive bool) (alrsh.Package, error) {
|
func PkgPrompt(ctx context.Context, options []db.Package, verb string, interactive bool) (db.Package, error) {
|
||||||
if !interactive {
|
if !interactive {
|
||||||
return options[0], nil
|
return options[0], nil
|
||||||
}
|
}
|
||||||
@@ -178,7 +138,7 @@ func PkgPrompt(ctx context.Context, options []alrsh.Package, verb string, intera
|
|||||||
var choice int
|
var choice int
|
||||||
err := survey.AskOne(prompt, &choice)
|
err := survey.AskOne(prompt, &choice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return alrsh.Package{}, err
|
return db.Package{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return options[choice], nil
|
return options[choice], nil
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 cliutils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/leonelquinteros/gotext"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type BashCompleteWithErrorFunc func(c *cli.Context) error
|
|
||||||
|
|
||||||
func BashCompleteWithError(f BashCompleteWithErrorFunc) cli.BashCompleteFunc {
|
|
||||||
return func(c *cli.Context) { HandleExitCoder(f(c)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleExitCoder(err error) {
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if exitErr, ok := err.(cli.ExitCoder); ok {
|
|
||||||
if err.Error() != "" {
|
|
||||||
if _, ok := exitErr.(cli.ErrorFormatter); ok {
|
|
||||||
slog.Error(fmt.Sprintf("%+v\n", err))
|
|
||||||
} else {
|
|
||||||
slog.Error(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cli.OsExiter(exitErr.ExitCode())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Error(err.Error())
|
|
||||||
cli.OsExiter(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatCliExit(msg string, err error) cli.ExitCoder {
|
|
||||||
return FormatCliExitWithCode(msg, err, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatCliExitWithCode(msg string, err error, exitCode int) cli.ExitCoder {
|
|
||||||
if err == nil {
|
|
||||||
return cli.Exit(errors.New(msg), exitCode)
|
|
||||||
}
|
|
||||||
return cli.Exit(fmt.Errorf("%s: %w", msg, err), exitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WarnLegacyCommand(newSyntax string) {
|
|
||||||
slog.Warn(
|
|
||||||
gotext.Get(
|
|
||||||
"This command is deprecated and would be removed in the future, use \"%s\" instead!", newSyntax,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -20,246 +20,180 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/pelletier/go-toml/v2"
|
||||||
"github.com/knadh/koanf/providers/confmap"
|
|
||||||
"github.com/knadh/koanf/v2"
|
|
||||||
ktoml "github.com/knadh/koanf/parsers/toml/v2"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/constants"
|
"github.com/leonelquinteros/gotext"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ALRConfig struct {
|
type ALRConfig struct {
|
||||||
cfg *types.Config
|
cfg *types.Config
|
||||||
paths *Paths
|
paths *Paths
|
||||||
|
|
||||||
System *SystemConfig
|
cfgOnce sync.Once
|
||||||
env *EnvConfig
|
pathsOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultConfig = &types.Config{
|
||||||
|
RootCmd: "sudo",
|
||||||
|
PagerStyle: "native",
|
||||||
|
IgnorePkgUpdates: []string{},
|
||||||
|
AutoPull: false,
|
||||||
|
Repos: []types.Repo{},
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *ALRConfig {
|
func New() *ALRConfig {
|
||||||
return &ALRConfig{
|
return &ALRConfig{}
|
||||||
System: NewSystemConfig(),
|
|
||||||
env: NewEnvConfig(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultConfigKoanf() *koanf.Koanf {
|
func (c *ALRConfig) Load(ctx context.Context) {
|
||||||
k := koanf.New(".")
|
cfgFl, err := os.Open(c.GetPaths(ctx).ConfigPath)
|
||||||
defaults := map[string]interface{}{
|
|
||||||
"rootCmd": "sudo",
|
|
||||||
"useRootCmd": true,
|
|
||||||
"pagerStyle": "native",
|
|
||||||
"ignorePkgUpdates": []string{},
|
|
||||||
"logLevel": "info",
|
|
||||||
"autoPull": true,
|
|
||||||
"updateSystemOnUpgrade": false,
|
|
||||||
"repos": []types.Repo{
|
|
||||||
{
|
|
||||||
Name: "alr-default",
|
|
||||||
URL: "https://gitea.plemya-x.ru/Plemya-x/alr-default.git",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if err := k.Load(confmap.Provider(defaults, "."), nil); err != nil {
|
|
||||||
panic(k)
|
|
||||||
}
|
|
||||||
return k
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ALRConfig) Load() error {
|
|
||||||
config := types.Config{}
|
|
||||||
|
|
||||||
merged := koanf.New(".")
|
|
||||||
|
|
||||||
if err := c.System.Load(); err != nil {
|
|
||||||
return fmt.Errorf("failed to load system config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.env.Load(); err != nil {
|
|
||||||
return fmt.Errorf("failed to load env config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
systemK := c.System.koanf()
|
|
||||||
envK := c.env.koanf()
|
|
||||||
|
|
||||||
if err := merged.Merge(defaultConfigKoanf()); err != nil {
|
|
||||||
return fmt.Errorf("failed to merge default config: %w", err)
|
|
||||||
}
|
|
||||||
if err := merged.Merge(systemK); err != nil {
|
|
||||||
return fmt.Errorf("failed to merge system config: %w", err)
|
|
||||||
}
|
|
||||||
if err := merged.Merge(envK); err != nil {
|
|
||||||
return fmt.Errorf("failed to merge env config: %w", err)
|
|
||||||
}
|
|
||||||
if err := merged.Unmarshal("", &config); err != nil {
|
|
||||||
return fmt.Errorf("failed to unmarshal merged config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cfg = &config
|
|
||||||
|
|
||||||
c.paths = &Paths{}
|
|
||||||
c.paths.UserConfigPath = constants.SystemConfigPath
|
|
||||||
c.paths.CacheDir = constants.SystemCachePath
|
|
||||||
c.paths.RepoDir = filepath.Join(c.paths.CacheDir, "repo")
|
|
||||||
c.paths.PkgsDir = filepath.Join(constants.TempDir, "pkgs") // Перемещаем в /tmp/alr/pkgs
|
|
||||||
c.paths.DBPath = filepath.Join(c.paths.CacheDir, "alr.db")
|
|
||||||
|
|
||||||
// Проверяем существование кэш-директории, но не пытаемся создать
|
|
||||||
if _, err := os.Stat(c.paths.CacheDir); err != nil {
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("failed to check cache directory: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выполняем миграцию конфигурации при необходимости
|
|
||||||
if err := c.migrateConfig(); err != nil {
|
|
||||||
return fmt.Errorf("failed to migrate config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ALRConfig) ToYAML() (string, error) {
|
|
||||||
data, err := yaml.Marshal(c.cfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
slog.Warn(gotext.Get("Error opening config file, using defaults"), "err", err)
|
||||||
}
|
c.cfg = defaultConfig
|
||||||
return string(data), nil
|
return
|
||||||
}
|
}
|
||||||
|
defer cfgFl.Close()
|
||||||
|
|
||||||
func (c *ALRConfig) migrateConfig() error {
|
// Copy the default configuration into config
|
||||||
// Проверяем, существует ли конфигурационный файл
|
defCopy := *defaultConfig
|
||||||
if _, err := os.Stat(constants.SystemConfigPath); os.IsNotExist(err) {
|
config := &defCopy
|
||||||
// Если файла нет, создаем полный конфигурационный файл с дефолтными значениями
|
config.Repos = nil
|
||||||
if err := c.createDefaultConfig(); err != nil {
|
|
||||||
// Если не удается создать конфиг, это не критично - продолжаем работу
|
|
||||||
// но выводим предупреждение
|
|
||||||
fmt.Fprintf(os.Stderr, "Предупреждение: не удалось создать конфигурационный файл %s: %v\n", constants.SystemConfigPath, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Если файл существует, проверяем, есть ли в нем новая опция
|
|
||||||
if !c.System.k.Exists("updateSystemOnUpgrade") {
|
|
||||||
// Если опции нет, добавляем ее со значением по умолчанию
|
|
||||||
c.System.SetUpdateSystemOnUpgrade(false)
|
|
||||||
// Сохраняем обновленную конфигурацию
|
|
||||||
if err := c.System.Save(); err != nil {
|
|
||||||
// Если не удается сохранить - это не критично, продолжаем работу
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
err = toml.NewDecoder(cfgFl).Decode(config)
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ALRConfig) createDefaultConfig() error {
|
|
||||||
// Проверяем, запущен ли процесс от root
|
|
||||||
if os.Getuid() != 0 {
|
|
||||||
// Если не root, пытаемся запустить создание конфига с повышением привилегий
|
|
||||||
return c.createDefaultConfigWithPrivileges()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если уже root, создаем конфиг напрямую
|
|
||||||
return c.doCreateDefaultConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ALRConfig) createDefaultConfigWithPrivileges() error {
|
|
||||||
// Если useRootCmd отключен, просто пытаемся создать без повышения привилегий
|
|
||||||
if !c.cfg.UseRootCmd {
|
|
||||||
return c.doCreateDefaultConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Определяем команду для повышения привилегий
|
|
||||||
rootCmd := c.cfg.RootCmd
|
|
||||||
if rootCmd == "" {
|
|
||||||
rootCmd = "sudo" // fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
// Создаем временный файл с дефолтной конфигурацией
|
|
||||||
tmpFile, err := os.CreateTemp("", "alr-config-*.toml")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("не удалось создать временный файл: %w", err)
|
slog.Warn(gotext.Get("Error decoding config file, using defaults"), "err", err)
|
||||||
|
c.cfg = defaultConfig
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.cfg = config
|
||||||
}
|
}
|
||||||
defer os.Remove(tmpFile.Name())
|
|
||||||
defer tmpFile.Close()
|
|
||||||
|
|
||||||
// Генерируем дефолтную конфигурацию во временный файл
|
func (c *ALRConfig) initPaths() {
|
||||||
defaults := defaultConfigKoanf()
|
paths := &Paths{}
|
||||||
tempSystemConfig := &SystemConfig{k: defaults}
|
|
||||||
|
|
||||||
bytes, err := tempSystemConfig.k.Marshal(ktoml.Parser())
|
cfgDir, err := os.UserConfigDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("не удалось сериализовать конфигурацию: %w", err)
|
slog.Error(gotext.Get("Unable to detect user config directory"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := tmpFile.Write(bytes); err != nil {
|
paths.ConfigDir = filepath.Join(cfgDir, "alr")
|
||||||
return fmt.Errorf("не удалось записать во временный файл: %w", err)
|
|
||||||
}
|
|
||||||
tmpFile.Close()
|
|
||||||
|
|
||||||
// Используем команду повышения привилегий для создания директории и копирования файла
|
err = os.MkdirAll(paths.ConfigDir, 0o755)
|
||||||
|
if err != nil {
|
||||||
// Создаем директорию с правами
|
slog.Error(gotext.Get("Unable to create ALR config directory"), "err", err)
|
||||||
configDir := filepath.Dir(constants.SystemConfigPath)
|
os.Exit(1)
|
||||||
mkdirCmd := exec.Command(rootCmd, "mkdir", "-p", configDir)
|
|
||||||
if err := mkdirCmd.Run(); err != nil {
|
|
||||||
return fmt.Errorf("не удалось создать директорию %s: %w", configDir, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Копируем файл в нужное место
|
paths.ConfigPath = filepath.Join(paths.ConfigDir, "alr.toml")
|
||||||
cpCmd := exec.Command(rootCmd, "cp", tmpFile.Name(), constants.SystemConfigPath)
|
|
||||||
if err := cpCmd.Run(); err != nil {
|
if _, err := os.Stat(paths.ConfigPath); err != nil {
|
||||||
return fmt.Errorf("не удалось скопировать конфигурацию в %s: %w", constants.SystemConfigPath, err)
|
cfgFl, err := os.Create(paths.ConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Unable to create ALR config file"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Устанавливаем правильные права доступа
|
err = toml.NewEncoder(cfgFl).Encode(&defaultConfig)
|
||||||
chmodCmd := exec.Command(rootCmd, "chmod", "644", constants.SystemConfigPath)
|
if err != nil {
|
||||||
if err := chmodCmd.Run(); err != nil {
|
slog.Error(gotext.Get("Error encoding default configuration"), "err", err)
|
||||||
// Не критично, продолжаем
|
os.Exit(1)
|
||||||
fmt.Fprintf(os.Stderr, "Предупреждение: не удалось установить права доступа для %s: %v\n", constants.SystemConfigPath, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
cfgFl.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ALRConfig) doCreateDefaultConfig() error {
|
cacheDir, err := os.UserCacheDir()
|
||||||
// Проверяем, существует ли директория для конфига
|
if err != nil {
|
||||||
configDir := filepath.Dir(constants.SystemConfigPath)
|
slog.Error(gotext.Get("Unable to detect cache directory"), "err", err)
|
||||||
if _, err := os.Stat(configDir); os.IsNotExist(err) {
|
os.Exit(1)
|
||||||
// Пытаемся создать директорию
|
|
||||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
|
||||||
return fmt.Errorf("не удалось создать директорию %s: %w", configDir, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Загружаем дефолтную конфигурацию
|
paths.CacheDir = filepath.Join(cacheDir, "alr")
|
||||||
defaults := defaultConfigKoanf()
|
paths.RepoDir = filepath.Join(paths.CacheDir, "repo")
|
||||||
|
paths.PkgsDir = filepath.Join(paths.CacheDir, "pkgs")
|
||||||
|
|
||||||
// Копируем все дефолтные значения в системную конфигурацию
|
err = os.MkdirAll(paths.RepoDir, 0o755)
|
||||||
c.System.k = defaults
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Unable to create repo cache directory"), "err", err)
|
||||||
// Сохраняем конфигурацию в файл
|
os.Exit(1)
|
||||||
if err := c.System.Save(); err != nil {
|
|
||||||
return fmt.Errorf("не удалось сохранить конфигурацию в %s: %w", constants.SystemConfigPath, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
err = os.MkdirAll(paths.PkgsDir, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(gotext.Get("Unable to create package cache directory"), "err", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ALRConfig) RootCmd() string { return c.cfg.RootCmd }
|
paths.DBPath = filepath.Join(paths.CacheDir, "db")
|
||||||
func (c *ALRConfig) PagerStyle() string { return c.cfg.PagerStyle }
|
|
||||||
func (c *ALRConfig) AutoPull() bool { return c.cfg.AutoPull }
|
c.paths = paths
|
||||||
func (c *ALRConfig) Repos() []types.Repo { return c.cfg.Repos }
|
}
|
||||||
func (c *ALRConfig) SetRepos(repos []types.Repo) { c.System.SetRepos(repos) }
|
|
||||||
func (c *ALRConfig) IgnorePkgUpdates() []string { return c.cfg.IgnorePkgUpdates }
|
func (c *ALRConfig) GetPaths(ctx context.Context) *Paths {
|
||||||
func (c *ALRConfig) LogLevel() string { return c.cfg.LogLevel }
|
c.pathsOnce.Do(func() {
|
||||||
func (c *ALRConfig) UseRootCmd() bool { return c.cfg.UseRootCmd }
|
c.initPaths()
|
||||||
func (c *ALRConfig) UpdateSystemOnUpgrade() bool { return c.cfg.UpdateSystemOnUpgrade }
|
})
|
||||||
func (c *ALRConfig) GetPaths() *Paths { return c.paths }
|
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) SetRepos(ctx context.Context, repos []types.Repo) {
|
||||||
|
c.cfgOnce.Do(func() {
|
||||||
|
c.Load(ctx)
|
||||||
|
})
|
||||||
|
c.cfg.Repos = repos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ALRConfig) IgnorePkgUpdates(ctx context.Context) []string {
|
||||||
|
c.cfgOnce.Do(func() {
|
||||||
|
c.Load(ctx)
|
||||||
|
})
|
||||||
|
return c.cfg.IgnorePkgUpdates
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ALRConfig) AutoPull(ctx context.Context) bool {
|
||||||
|
c.cfgOnce.Do(func() {
|
||||||
|
c.Load(ctx)
|
||||||
|
})
|
||||||
|
return c.cfg.AutoPull
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ALRConfig) PagerStyle(ctx context.Context) string {
|
||||||
|
c.cfgOnce.Do(func() {
|
||||||
|
c.Load(ctx)
|
||||||
|
})
|
||||||
|
return c.cfg.PagerStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ALRConfig) AllowRunAsRoot(ctx context.Context) bool {
|
||||||
|
c.cfgOnce.Do(func() {
|
||||||
|
c.Load(ctx)
|
||||||
|
})
|
||||||
|
return c.cfg.Unsafe.AllowRunAsRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ALRConfig) RootCmd(ctx context.Context) string {
|
||||||
|
c.cfgOnce.Do(func() {
|
||||||
|
c.Load(ctx)
|
||||||
|
})
|
||||||
|
return c.cfg.RootCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ALRConfig) Save(f *os.File) error {
|
||||||
|
return toml.NewEncoder(f).Encode(c.cfg)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/knadh/koanf/providers/env"
|
|
||||||
"github.com/knadh/koanf/v2"
|
|
||||||
"golang.org/x/text/cases"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EnvConfig struct {
|
|
||||||
k *koanf.Koanf
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEnvConfig() *EnvConfig {
|
|
||||||
return &EnvConfig{
|
|
||||||
k: koanf.New("."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *EnvConfig) koanf() *koanf.Koanf {
|
|
||||||
return c.k
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *EnvConfig) Load() error {
|
|
||||||
allowedKeys := map[string]struct{}{
|
|
||||||
"ALR_LOG_LEVEL": {},
|
|
||||||
"ALR_PAGER_STYLE": {},
|
|
||||||
"ALR_AUTO_PULL": {},
|
|
||||||
}
|
|
||||||
err := c.k.Load(env.Provider("ALR_", ".", func(s string) string {
|
|
||||||
_, ok := allowedKeys[s]
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
withoutPrefix := strings.TrimPrefix(s, "ALR_")
|
|
||||||
lowered := strings.ToLower(withoutPrefix)
|
|
||||||
dotted := strings.ReplaceAll(lowered, "__", ".")
|
|
||||||
parts := strings.Split(dotted, ".")
|
|
||||||
for i, part := range parts {
|
|
||||||
if strings.Contains(part, "_") {
|
|
||||||
parts[i] = toCamelCase(part)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(parts, ".")
|
|
||||||
}), nil)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func toCamelCase(s string) string {
|
|
||||||
parts := strings.Split(s, "_")
|
|
||||||
for i := 1; i < len(parts); i++ {
|
|
||||||
if len(parts[i]) > 0 {
|
|
||||||
parts[i] = cases.Title(language.Und, cases.NoLower).String(parts[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(parts, "")
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -21,8 +21,8 @@ package config
|
|||||||
|
|
||||||
// Paths contains various paths used by ALR
|
// Paths contains various paths used by ALR
|
||||||
type Paths struct {
|
type Paths struct {
|
||||||
SystemConfigPath string
|
ConfigDir string
|
||||||
UserConfigPath string
|
ConfigPath string
|
||||||
CacheDir string
|
CacheDir string
|
||||||
RepoDir string
|
RepoDir string
|
||||||
PkgsDir string
|
PkgsDir string
|
||||||
|
|||||||
@@ -1,151 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
ktoml "github.com/knadh/koanf/parsers/toml/v2"
|
|
||||||
"github.com/knadh/koanf/providers/file"
|
|
||||||
"github.com/knadh/koanf/v2"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/constants"
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SystemConfig struct {
|
|
||||||
k *koanf.Koanf
|
|
||||||
cfg *types.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSystemConfig() *SystemConfig {
|
|
||||||
return &SystemConfig{
|
|
||||||
k: koanf.New("."),
|
|
||||||
cfg: &types.Config{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) koanf() *koanf.Koanf {
|
|
||||||
return c.k
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) Load() error {
|
|
||||||
if _, err := os.Stat(constants.SystemConfigPath); errors.Is(err, os.ErrNotExist) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.k.Load(file.Provider(constants.SystemConfigPath), ktoml.Parser()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.k.Unmarshal("", c.cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) Save() error {
|
|
||||||
bytes, err := c.k.Marshal(ktoml.Parser())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to marshal config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Create(constants.SystemConfigPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create config file: %w", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if cerr := file.Close(); cerr != nil && err == nil {
|
|
||||||
err = cerr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := file.Write(bytes); err != nil {
|
|
||||||
return fmt.Errorf("failed to write config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := file.Sync(); err != nil {
|
|
||||||
return fmt.Errorf("failed to sync config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetRootCmd(v string) {
|
|
||||||
err := c.k.Set("rootCmd", v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetUseRootCmd(v bool) {
|
|
||||||
err := c.k.Set("useRootCmd", v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetPagerStyle(v string) {
|
|
||||||
err := c.k.Set("pagerStyle", v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetIgnorePkgUpdates(v []string) {
|
|
||||||
err := c.k.Set("ignorePkgUpdates", v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetAutoPull(v bool) {
|
|
||||||
err := c.k.Set("autoPull", v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetLogLevel(v string) {
|
|
||||||
err := c.k.Set("logLevel", v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetRepos(v []types.Repo) {
|
|
||||||
b, err := json.Marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
var m []interface{}
|
|
||||||
err = json.Unmarshal(b, &m)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
err = c.k.Set("repo", m)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SetUpdateSystemOnUpgrade(v bool) {
|
|
||||||
err := c.k.Set("updateSystemOnUpgrade", v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 constants
|
|
||||||
|
|
||||||
const (
|
|
||||||
SystemConfigPath = "/etc/alr/alr.toml"
|
|
||||||
SystemCachePath = "/var/cache/alr"
|
|
||||||
TempDir = "/tmp/alr"
|
|
||||||
// PrivilegedGroup - устарело, используйте GetPrivilegedGroup()
|
|
||||||
PrivilegedGroup = "wheel" // оставлено для обратной совместимости
|
|
||||||
)
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -21,31 +21,49 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
_ "modernc.org/sqlite"
|
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const CurrentVersion = 5
|
// CurrentVersion is the current version of the database.
|
||||||
|
// The database is reset if its version doesn't match this.
|
||||||
|
const CurrentVersion = 3
|
||||||
|
|
||||||
type Version struct {
|
// Package is a ALR package's database representation
|
||||||
Version int `xorm:"'version'"`
|
type Package struct {
|
||||||
|
BasePkgName string `sh:"base" db:"basepkg_name"`
|
||||||
|
Name string `sh:"name,required" db:"name"`
|
||||||
|
Version string `sh:"version,required" db:"version"`
|
||||||
|
Release int `sh:"release,required" db:"release"`
|
||||||
|
Epoch uint `sh:"epoch" db:"epoch"`
|
||||||
|
Description JSON[map[string]string] `db:"description"`
|
||||||
|
Homepage JSON[map[string]string] `db:"homepage"`
|
||||||
|
Maintainer JSON[map[string]string] `db:"maintainer"`
|
||||||
|
Architectures JSON[[]string] `sh:"architectures" db:"architectures"`
|
||||||
|
Licenses JSON[[]string] `sh:"license" db:"licenses"`
|
||||||
|
Provides JSON[[]string] `sh:"provides" db:"provides"`
|
||||||
|
Conflicts JSON[[]string] `sh:"conflicts" db:"conflicts"`
|
||||||
|
Replaces JSON[[]string] `sh:"replaces" db:"replaces"`
|
||||||
|
Depends JSON[map[string][]string] `db:"depends"`
|
||||||
|
BuildDepends JSON[map[string][]string] `db:"builddepends"`
|
||||||
|
OptDepends JSON[map[string][]string] `db:"optdepends"`
|
||||||
|
Repository string `db:"repository"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type version struct {
|
||||||
|
Version int `db:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config interface {
|
type Config interface {
|
||||||
GetPaths() *config.Paths
|
GetPaths(ctx context.Context) *config.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
type Database struct {
|
type Database struct {
|
||||||
engine *xorm.Engine
|
conn *sqlx.DB
|
||||||
config Config
|
config Config
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,113 +73,175 @@ func New(config Config) *Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) Connect() error {
|
func (d *Database) Init(ctx context.Context) error {
|
||||||
dsn := d.config.GetPaths().DBPath
|
err := d.Connect(ctx)
|
||||||
|
|
||||||
// Проверяем директорию для БД
|
|
||||||
dbDir := filepath.Dir(dsn)
|
|
||||||
if _, err := os.Stat(dbDir); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
// Директория не существует - не пытаемся создать
|
|
||||||
// Пользователь должен использовать alr fix для создания системных каталогов
|
|
||||||
return fmt.Errorf("cache directory does not exist, please run 'sudo alr fix' to create it")
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("failed to check database directory: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
engine, err := xorm.NewEngine("sqlite", dsn)
|
|
||||||
// engine.SetLogLevel(log.LOG_DEBUG)
|
|
||||||
// engine.ShowSQL(true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.engine = engine
|
return d.initDB(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Database) Connect(ctx context.Context) error {
|
||||||
|
dsn := d.config.GetPaths(ctx).DBPath
|
||||||
|
db, err := sqlx.Open("sqlite", dsn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.conn = db
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) Init(ctx context.Context) error {
|
func (d *Database) GetConn() *sqlx.DB {
|
||||||
if err := d.Connect(); err != nil {
|
return d.conn
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
if err := d.engine.Sync2(new(alrsh.Package), new(Version)); err != nil {
|
func (d *Database) initDB(ctx context.Context) error {
|
||||||
|
d.conn = d.conn.Unsafe()
|
||||||
|
conn := d.conn
|
||||||
|
_, err := conn.ExecContext(ctx, `
|
||||||
|
CREATE TABLE IF NOT EXISTS pkgs (
|
||||||
|
basepkg_name TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
repository TEXT NOT NULL,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
release INT NOT NULL,
|
||||||
|
epoch INT,
|
||||||
|
description TEXT CHECK(description = 'null' OR (JSON_VALID(description) AND JSON_TYPE(description) = 'object')),
|
||||||
|
homepage TEXT CHECK(homepage = 'null' OR (JSON_VALID(homepage) AND JSON_TYPE(homepage) = 'object')),
|
||||||
|
maintainer TEXT CHECK(maintainer = 'null' OR (JSON_VALID(maintainer) AND JSON_TYPE(maintainer) = 'object')),
|
||||||
|
architectures TEXT CHECK(architectures = 'null' OR (JSON_VALID(architectures) AND JSON_TYPE(architectures) = 'array')),
|
||||||
|
licenses TEXT CHECK(licenses = 'null' OR (JSON_VALID(licenses) AND JSON_TYPE(licenses) = 'array')),
|
||||||
|
provides TEXT CHECK(provides = 'null' OR (JSON_VALID(provides) AND JSON_TYPE(provides) = 'array')),
|
||||||
|
conflicts TEXT CHECK(conflicts = 'null' OR (JSON_VALID(conflicts) AND JSON_TYPE(conflicts) = 'array')),
|
||||||
|
replaces TEXT CHECK(replaces = 'null' OR (JSON_VALID(replaces) AND JSON_TYPE(replaces) = 'array')),
|
||||||
|
depends TEXT CHECK(depends = 'null' OR (JSON_VALID(depends) AND JSON_TYPE(depends) = 'object')),
|
||||||
|
builddepends TEXT CHECK(builddepends = 'null' OR (JSON_VALID(builddepends) AND JSON_TYPE(builddepends) = 'object')),
|
||||||
|
optdepends TEXT CHECK(optdepends = 'null' OR (JSON_VALID(optdepends) AND JSON_TYPE(optdepends) = 'object')),
|
||||||
|
UNIQUE(name, repository)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS alr_db_version (
|
||||||
|
version INT NOT NULL
|
||||||
|
);
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ver, ok := d.GetVersion(ctx)
|
ver, ok := d.GetVersion(ctx)
|
||||||
if ok && ver != CurrentVersion {
|
if ok && ver != CurrentVersion {
|
||||||
slog.Warn(gotext.Get("Database version mismatch; resetting"), "version", ver, "expected", CurrentVersion)
|
slog.Warn(gotext.Get("Database version mismatch; resetting"), "version", ver, "expected", CurrentVersion)
|
||||||
if err := d.reset(); err != nil {
|
err = d.reset(ctx)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return d.Init(ctx)
|
return d.initDB(ctx)
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
slog.Warn(gotext.Get("Database version does not exist. Run alr fix if something isn't working."))
|
slog.Warn(gotext.Get("Database version does not exist. Run alr fix if something isn't working."), "version", ver, "expected", CurrentVersion)
|
||||||
return d.addVersion(CurrentVersion)
|
return d.addVersion(ctx, CurrentVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) GetVersion(ctx context.Context) (int, bool) {
|
func (d *Database) GetVersion(ctx context.Context) (int, bool) {
|
||||||
var v Version
|
var ver version
|
||||||
has, err := d.engine.Get(&v)
|
err := d.conn.GetContext(ctx, &ver, "SELECT * FROM alr_db_version LIMIT 1;")
|
||||||
if err != nil || !has {
|
if err != nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
return v.Version, true
|
return ver.Version, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) addVersion(ver int) error {
|
func (d *Database) addVersion(ctx context.Context, ver int) error {
|
||||||
_, err := d.engine.Insert(&Version{Version: ver})
|
_, err := d.conn.ExecContext(ctx, `INSERT INTO alr_db_version(version) VALUES (?);`, ver)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) reset() error {
|
func (d *Database) reset(ctx context.Context) error {
|
||||||
return d.engine.DropTables(new(alrsh.Package), new(Version))
|
_, err := d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS pkgs;")
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Database) InsertPackage(ctx context.Context, pkg alrsh.Package) error {
|
|
||||||
session := d.engine.Context(ctx)
|
|
||||||
|
|
||||||
affected, err := session.Where("name = ? AND repository = ?", pkg.Name, pkg.Repository).Update(&pkg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, err = d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS alr_db_version;")
|
||||||
if affected == 0 {
|
|
||||||
_, err = session.Insert(&pkg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
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 {
|
||||||
func (d *Database) GetPkgs(_ context.Context, where string, args ...any) ([]alrsh.Package, error) {
|
|
||||||
var pkgs []alrsh.Package
|
|
||||||
err := d.engine.Where(where, args...).Find(&pkgs)
|
|
||||||
return pkgs, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Database) GetPkg(where string, args ...any) (*alrsh.Package, error) {
|
|
||||||
var pkg alrsh.Package
|
|
||||||
has, err := d.engine.Where(where, args...).Get(&pkg)
|
|
||||||
if err != nil || !has {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &pkg, nil
|
return stream, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) DeletePkgs(_ context.Context, where string, args ...any) error {
|
func (d *Database) GetPkg(ctx context.Context, where string, args ...any) (*Package, error) {
|
||||||
_, err := d.engine.Where(where, args...).Delete(&alrsh.Package{})
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) IsEmpty() bool {
|
func (d *Database) IsEmpty(ctx context.Context) bool {
|
||||||
count, err := d.engine.Count(new(alrsh.Package))
|
var count int
|
||||||
return err != nil || count == 0
|
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 (
|
||||||
|
basepkg_name,
|
||||||
|
name,
|
||||||
|
repository,
|
||||||
|
version,
|
||||||
|
release,
|
||||||
|
epoch,
|
||||||
|
description,
|
||||||
|
homepage,
|
||||||
|
maintainer,
|
||||||
|
architectures,
|
||||||
|
licenses,
|
||||||
|
provides,
|
||||||
|
conflicts,
|
||||||
|
replaces,
|
||||||
|
depends,
|
||||||
|
builddepends,
|
||||||
|
optdepends
|
||||||
|
) VALUES (
|
||||||
|
:basepkg_name,
|
||||||
|
:name,
|
||||||
|
:repository,
|
||||||
|
:version,
|
||||||
|
:release,
|
||||||
|
:epoch,
|
||||||
|
:description,
|
||||||
|
:homepage,
|
||||||
|
:maintainer,
|
||||||
|
:architectures,
|
||||||
|
:licenses,
|
||||||
|
:provides,
|
||||||
|
:conflicts,
|
||||||
|
:replaces,
|
||||||
|
:depends,
|
||||||
|
:builddepends,
|
||||||
|
:optdepends
|
||||||
|
);
|
||||||
|
`, pkg)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) Close() error {
|
func (d *Database) Close() error {
|
||||||
return d.engine.Close()
|
if d.conn != nil {
|
||||||
|
return d.conn.Close()
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -25,16 +25,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestALRConfig struct{}
|
type TestALRConfig struct{}
|
||||||
|
|
||||||
func (c *TestALRConfig) GetPaths() *config.Paths {
|
func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
|
||||||
return &config.Paths{
|
return &config.Paths{
|
||||||
DBPath: ":memory:",
|
DBPath: ":memory:",
|
||||||
}
|
}
|
||||||
@@ -46,38 +45,35 @@ func prepareDb() *db.Database {
|
|||||||
return database
|
return database
|
||||||
}
|
}
|
||||||
|
|
||||||
var testPkg = alrsh.Package{
|
var testPkg = db.Package{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Version: "0.0.1",
|
Version: "0.0.1",
|
||||||
Release: 1,
|
Release: 1,
|
||||||
Epoch: 2,
|
Epoch: 2,
|
||||||
Description: alrsh.OverridableFromMap(map[string]string{
|
Description: db.NewJSON(map[string]string{
|
||||||
"en": "Test package",
|
"en": "Test package",
|
||||||
"ru": "Проверочный пакет",
|
"ru": "Проверочный пакет",
|
||||||
}),
|
}),
|
||||||
Homepage: alrsh.OverridableFromMap(map[string]string{
|
Homepage: db.NewJSON(map[string]string{
|
||||||
"en": "https://gitea.plemya-x.ru/xpamych/ALR",
|
"en": "https://gitea.plemya-x.ru/xpamych/ALR",
|
||||||
}),
|
}),
|
||||||
Maintainer: alrsh.OverridableFromMap(map[string]string{
|
Maintainer: db.NewJSON(map[string]string{
|
||||||
"en": "Evgeniy Khramov <xpamych@yandex.ru>",
|
"en": "Evgeniy Khramov <xpamych@yandex.ru>",
|
||||||
"ru": "Евгений Храмов <xpamych@yandex.ru>",
|
"ru": "Евгений Храмов <xpamych@yandex.ru>",
|
||||||
}),
|
}),
|
||||||
Architectures: []string{"arm64", "amd64"},
|
Architectures: db.NewJSON([]string{"arm64", "amd64"}),
|
||||||
Licenses: []string{"GPL-3.0-or-later"},
|
Licenses: db.NewJSON([]string{"GPL-3.0-or-later"}),
|
||||||
Provides: []string{"test"},
|
Provides: db.NewJSON([]string{"test"}),
|
||||||
Conflicts: []string{"test"},
|
Conflicts: db.NewJSON([]string{"test"}),
|
||||||
Replaces: []string{"test-old"},
|
Replaces: db.NewJSON([]string{"test-old"}),
|
||||||
Depends: alrsh.OverridableFromMap(map[string][]string{
|
Depends: db.NewJSON(map[string][]string{
|
||||||
"": {"sudo"},
|
"": {"sudo"},
|
||||||
}),
|
}),
|
||||||
BuildDepends: alrsh.OverridableFromMap(map[string][]string{
|
BuildDepends: db.NewJSON(map[string][]string{
|
||||||
"": {"golang"},
|
"": {"golang"},
|
||||||
"arch": {"go"},
|
"arch": {"go"},
|
||||||
}),
|
}),
|
||||||
Repository: "default",
|
Repository: "default",
|
||||||
Summary: alrsh.OverridableFromMap(map[string]string{}),
|
|
||||||
Group: alrsh.OverridableFromMap(map[string]string{}),
|
|
||||||
OptDepends: alrsh.OverridableFromMap(map[string][]string{}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
@@ -103,16 +99,15 @@ func TestInsertPackage(t *testing.T) {
|
|||||||
t.Fatalf("Expected no error, got %s", err)
|
t.Fatalf("Expected no error, got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgs, err := database.GetPkgs(ctx, "name = 'test' AND repository = 'default'")
|
dbPkg := db.Package{}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pkgs) != 1 {
|
if !reflect.DeepEqual(testPkg, dbPkg) {
|
||||||
t.Fatalf("Expected 1 package, got %d", len(pkgs))
|
t.Errorf("Expected test package to be the same as database package")
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, testPkg, pkgs[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPkgs(t *testing.T) {
|
func TestGetPkgs(t *testing.T) {
|
||||||
@@ -135,12 +130,18 @@ func TestGetPkgs(t *testing.T) {
|
|||||||
t.Errorf("Expected no error, got %s", err)
|
t.Errorf("Expected no error, got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgs, err := database.GetPkgs(ctx, "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)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dbPkg := range pkgs {
|
for result.Next() {
|
||||||
|
var dbPkg db.Package
|
||||||
|
err = result.StructScan(&dbPkg)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(dbPkg.Name, "x") {
|
if !strings.HasPrefix(dbPkg.Name, "x") {
|
||||||
t.Errorf("Expected package name to start with 'x', got %s", dbPkg.Name)
|
t.Errorf("Expected package name to start with 'x', got %s", dbPkg.Name)
|
||||||
}
|
}
|
||||||
@@ -167,7 +168,7 @@ func TestGetPkg(t *testing.T) {
|
|||||||
t.Errorf("Expected no error, got %s", err)
|
t.Errorf("Expected no error, got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg, err := database.GetPkg("name LIKE 'x%'")
|
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)
|
||||||
}
|
}
|
||||||
@@ -205,6 +206,16 @@ func TestDeletePkgs(t *testing.T) {
|
|||||||
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
|
||||||
|
err = database.GetConn().Get(&dbPkg, "SELECT * FROM pkgs WHERE name LIKE 'x%' ORDER BY name LIMIT 1;")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dbPkg.Name != "x2" {
|
||||||
|
t.Errorf("Expected x2 package, got %s", dbPkg.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJsonArrayContains(t *testing.T) {
|
func TestJsonArrayContains(t *testing.T) {
|
||||||
@@ -216,7 +227,7 @@ func TestJsonArrayContains(t *testing.T) {
|
|||||||
x1.Name = "x1"
|
x1.Name = "x1"
|
||||||
x2 := testPkg
|
x2 := testPkg
|
||||||
x2.Name = "x2"
|
x2.Name = "x2"
|
||||||
x2.Provides = append(x2.Provides, "x")
|
x2.Provides.Val = append(x2.Provides.Val, "x")
|
||||||
|
|
||||||
err := database.InsertPackage(ctx, x1)
|
err := database.InsertPackage(ctx, x1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -228,24 +239,13 @@ func TestJsonArrayContains(t *testing.T) {
|
|||||||
t.Errorf("Expected no error, got %s", err)
|
t.Errorf("Expected no error, got %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgs, err := database.GetPkgs(ctx, "name = 'x2'")
|
var dbPkg db.Package
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pkgs) != 1 || pkgs[0].Name != "x2" {
|
if dbPkg.Name != "x2" {
|
||||||
t.Errorf("Expected x2 package, got %v", pkgs)
|
t.Errorf("Expected x2 package, got %s", dbPkg.Name)
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the provides field contains 'x'
|
|
||||||
found := false
|
|
||||||
for _, p := range pkgs[0].Provides {
|
|
||||||
if p == "x" {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
t.Errorf("Expected provides to contain 'x'")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
80
internal/db/json.go
Normal file
80
internal/db/json.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -55,7 +55,7 @@ var (
|
|||||||
|
|
||||||
// Массив доступных загрузчиков в порядке их проверки
|
// Массив доступных загрузчиков в порядке их проверки
|
||||||
var Downloaders = []Downloader{
|
var Downloaders = []Downloader{
|
||||||
&GitDownloader{},
|
GitDownloader{},
|
||||||
TorrentDownloader{},
|
TorrentDownloader{},
|
||||||
FileDownloader{},
|
FileDownloader{},
|
||||||
}
|
}
|
||||||
@@ -172,10 +172,15 @@ func Download(ctx context.Context, opts Options) (err error) {
|
|||||||
"downloader", d.Name(),
|
"downloader", d.Name(),
|
||||||
)
|
)
|
||||||
|
|
||||||
newOpts := opts
|
updated, err = d.Update(Options{
|
||||||
newOpts.Destination = cacheDir
|
Hash: opts.Hash,
|
||||||
|
HashAlgorithm: opts.HashAlgorithm,
|
||||||
updated, err = d.Update(newOpts)
|
Name: opts.Name,
|
||||||
|
URL: opts.URL,
|
||||||
|
Destination: cacheDir,
|
||||||
|
Progress: opts.Progress,
|
||||||
|
LocalDir: opts.LocalDir,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -221,10 +226,15 @@ func Download(ctx context.Context, opts Options) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newOpts := opts
|
t, name, err := d.Download(ctx, Options{
|
||||||
newOpts.Destination = cacheDir
|
Hash: opts.Hash,
|
||||||
|
HashAlgorithm: opts.HashAlgorithm,
|
||||||
t, name, err := d.Download(ctx, newOpts)
|
Name: opts.Name,
|
||||||
|
URL: opts.URL,
|
||||||
|
Destination: cacheDir,
|
||||||
|
Progress: opts.Progress,
|
||||||
|
LocalDir: opts.LocalDir,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -280,14 +290,14 @@ func handleCache(cacheDir, dest, name string, t Type) (bool, error) {
|
|||||||
cd.Close()
|
cd.Close()
|
||||||
|
|
||||||
if slices.Contains(names, name) {
|
if slices.Contains(names, name) {
|
||||||
err = linkOrCopy(filepath.Join(cacheDir, name), dest)
|
err = os.Link(filepath.Join(cacheDir, name), dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
case TypeDir:
|
case TypeDir:
|
||||||
err := linkOrCopyDir(cacheDir, dest)
|
err := linkDir(cacheDir, dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -296,40 +306,8 @@ func handleCache(cacheDir, dest, name string, t Type) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkOrCopy пытается создать жесткую ссылку, а если не получается - копирует файл
|
// Функция linkDir рекурсивно создает жесткие ссылки для файлов из каталога src в каталог dest
|
||||||
func linkOrCopy(src, dest string) error {
|
func linkDir(src, dest string) error {
|
||||||
err := os.Link(src, dest)
|
|
||||||
if err != nil {
|
|
||||||
// Если не удалось создать ссылку, копируем файл
|
|
||||||
srcFile, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer srcFile.Close()
|
|
||||||
|
|
||||||
destFile, err := os.Create(dest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(destFile, srcFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Копируем права доступа
|
|
||||||
srcInfo, err := srcFile.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.Chmod(dest, srcInfo.Mode())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// linkOrCopyDir рекурсивно создает жесткие ссылки или копирует файлы из каталога src в каталог dest
|
|
||||||
func linkOrCopyDir(src, dest string) error {
|
|
||||||
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
|
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -349,7 +327,7 @@ func linkOrCopyDir(src, dest string) error {
|
|||||||
return os.MkdirAll(newPath, info.Mode())
|
return os.MkdirAll(newPath, info.Mode())
|
||||||
}
|
}
|
||||||
|
|
||||||
return linkOrCopy(path, newPath)
|
return os.Link(path, newPath)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -32,13 +32,13 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/dl"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dl"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/dlcache"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestALRConfig struct{}
|
type TestALRConfig struct{}
|
||||||
|
|
||||||
func (c *TestALRConfig) GetPaths() *config.Paths {
|
func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
|
||||||
return &config.Paths{
|
return &config.Paths{
|
||||||
CacheDir: "/tmp",
|
CacheDir: "/tmp",
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ func TestDownloadFileWithCache(t *testing.T) {
|
|||||||
CacheDisabled: false,
|
CacheDisabled: false,
|
||||||
URL: server.URL + "/file",
|
URL: server.URL + "/file",
|
||||||
Destination: tmpdir,
|
Destination: tmpdir,
|
||||||
DlCache: dlcache.New(cfg.GetPaths().CacheDir),
|
DlCache: dlcache.New(cfg),
|
||||||
}
|
}
|
||||||
|
|
||||||
outputFile := path.Join(tmpdir, "file")
|
outputFile := path.Join(tmpdir, "file")
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -108,7 +108,7 @@ func (FileDownloader) Download(ctx context.Context, opts Options) (Type, string,
|
|||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
postprocDisabled := opts.PostprocDisabled || archive == "false"
|
opts.PostprocDisabled = archive == "false"
|
||||||
|
|
||||||
path := filepath.Join(opts.Destination, name)
|
path := filepath.Join(opts.Destination, name)
|
||||||
fl, err := os.Create(path)
|
fl, err := os.Create(path)
|
||||||
@@ -154,7 +154,7 @@ func (FileDownloader) Download(ctx context.Context, opts Options) (Type, string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Проверка необходимости постобработки
|
// Проверка необходимости постобработки
|
||||||
if postprocDisabled {
|
if opts.PostprocDisabled {
|
||||||
return TypeFile, name, nil
|
return TypeFile, name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -22,7 +22,6 @@ package dl
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -49,7 +48,7 @@ func (GitDownloader) MatchURL(u string) bool {
|
|||||||
// Download uses git to clone the repository from the specified URL.
|
// Download uses git to clone the repository from the specified URL.
|
||||||
// It allows specifying the revision, depth and recursion options
|
// It allows specifying the revision, depth and recursion options
|
||||||
// via query string
|
// via query string
|
||||||
func (d *GitDownloader) Download(ctx context.Context, opts Options) (Type, string, error) {
|
func (GitDownloader) Download(ctx context.Context, opts Options) (Type, string, error) {
|
||||||
u, err := url.Parse(opts.URL)
|
u, err := url.Parse(opts.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, "", err
|
return 0, "", err
|
||||||
@@ -61,9 +60,6 @@ func (d *GitDownloader) Download(ctx context.Context, opts Options) (Type, strin
|
|||||||
rev := query.Get("~rev")
|
rev := query.Get("~rev")
|
||||||
query.Del("~rev")
|
query.Del("~rev")
|
||||||
|
|
||||||
// Right now, this only affects the return value of name,
|
|
||||||
// which will be used by dl_cache.
|
|
||||||
// It seems wrong, but for now it's better to leave it as it is.
|
|
||||||
name := query.Get("~name")
|
name := query.Get("~name")
|
||||||
query.Del("~name")
|
query.Del("~name")
|
||||||
|
|
||||||
@@ -125,11 +121,6 @@ func (d *GitDownloader) Download(ctx context.Context, opts Options) (Type, strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = VerifyHashFromLocal("", opts)
|
|
||||||
if err != nil {
|
|
||||||
return 0, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = strings.TrimSuffix(path.Base(u.Path), ".git")
|
name = strings.TrimSuffix(path.Base(u.Path), ".git")
|
||||||
}
|
}
|
||||||
@@ -142,7 +133,7 @@ func (d *GitDownloader) Download(ctx context.Context, opts Options) (Type, strin
|
|||||||
// and recursion options via query string. It returns
|
// and recursion options via query string. It returns
|
||||||
// true if update was successful and false if the
|
// true if update was successful and false if the
|
||||||
// repository is already up-to-date
|
// repository is already up-to-date
|
||||||
func (d *GitDownloader) Update(opts Options) (bool, error) {
|
func (GitDownloader) Update(opts Options) (bool, error) {
|
||||||
u, err := url.Parse(opts.URL)
|
u, err := url.Parse(opts.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -150,7 +141,6 @@ func (d *GitDownloader) Update(opts Options) (bool, error) {
|
|||||||
u.Scheme = strings.TrimPrefix(u.Scheme, "git+")
|
u.Scheme = strings.TrimPrefix(u.Scheme, "git+")
|
||||||
|
|
||||||
query := u.Query()
|
query := u.Query()
|
||||||
rev := query.Get("~rev")
|
|
||||||
query.Del("~rev")
|
query.Del("~rev")
|
||||||
|
|
||||||
depthStr := query.Get("~depth")
|
depthStr := query.Get("~depth")
|
||||||
@@ -179,48 +169,6 @@ func (d *GitDownloader) Update(opts Options) (bool, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, we do a fetch to get all the revisions.
|
|
||||||
fo := &git.FetchOptions{
|
|
||||||
Depth: depth,
|
|
||||||
Progress: opts.Progress,
|
|
||||||
}
|
|
||||||
|
|
||||||
m, err := getManifest(opts.Destination)
|
|
||||||
manifestOK := err == nil
|
|
||||||
|
|
||||||
err = r.Fetch(fo)
|
|
||||||
if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a revision is specified, switch to it.
|
|
||||||
if rev != "" {
|
|
||||||
// We are trying to find the revision as a hash of the commit
|
|
||||||
hash, err := r.ResolveRevision(plumbing.Revision(rev))
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("failed to resolve revision %s: %w", rev, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = w.Checkout(&git.CheckoutOptions{
|
|
||||||
Hash: *hash,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("failed to checkout revision %s: %w", rev, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if recursive == "true" {
|
|
||||||
submodules, err := w.Submodules()
|
|
||||||
if err == nil {
|
|
||||||
err = submodules.Update(&git.SubmoduleUpdateOptions{
|
|
||||||
Init: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("failed to update submodules %s: %w", rev, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the revision is not specified, we do a regular pull.
|
|
||||||
po := &git.PullOptions{
|
po := &git.PullOptions{
|
||||||
Depth: depth,
|
Depth: depth,
|
||||||
Progress: opts.Progress,
|
Progress: opts.Progress,
|
||||||
@@ -231,23 +179,22 @@ func (d *GitDownloader) Update(opts Options) (bool, error) {
|
|||||||
po.RecurseSubmodules = git.DefaultSubmoduleRecursionDepth
|
po.RecurseSubmodules = git.DefaultSubmoduleRecursionDepth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m, err := getManifest(opts.Destination)
|
||||||
|
manifestOK := err == nil
|
||||||
|
|
||||||
err = w.Pull(po)
|
err = w.Pull(po)
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, git.NoErrAlreadyUpToDate) {
|
if errors.Is(err, git.NoErrAlreadyUpToDate) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
} else if err != nil {
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = VerifyHashFromLocal("", opts)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if manifestOK {
|
if manifestOK {
|
||||||
err = writeManifest(opts.Destination, m)
|
err = writeManifest(opts.Destination, m)
|
||||||
}
|
if err != nil {
|
||||||
|
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -71,17 +71,7 @@ func (TorrentDownloader) Download(ctx context.Context, opts Options) (Type, stri
|
|||||||
return 0, "", err
|
return 0, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
dlType, name, err := determineType(opts.Destination)
|
return determineType(opts.Destination)
|
||||||
if err != nil {
|
|
||||||
return 0, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = VerifyHashFromLocal(name, opts)
|
|
||||||
if err != nil {
|
|
||||||
return 0, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return dlType, name, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeTorrentFiles(path string) error {
|
func removeTorrentFiles(path string) error {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -28,19 +28,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config interface {
|
type Config interface {
|
||||||
GetPaths() *config.Paths
|
GetPaths(ctx context.Context) *config.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
type DownloadCache struct {
|
type DownloadCache struct {
|
||||||
cacheDir string
|
cfg Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cacheDir string) *DownloadCache {
|
func New(cfg Config) *DownloadCache {
|
||||||
return &DownloadCache{cacheDir}
|
return &DownloadCache{
|
||||||
|
cfg,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DownloadCache) BasePath(ctx context.Context) string {
|
func (dc *DownloadCache) BasePath(ctx context.Context) string {
|
||||||
return filepath.Join(dc.cacheDir, "dl")
|
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.
|
||||||
@@ -61,8 +65,7 @@ func (dc *DownloadCache) New(ctx context.Context, id string) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создаем директорию с правильными правами (различается для prod и тестов)
|
err = os.MkdirAll(itemPath, 0o755)
|
||||||
err = createDir(itemPath, 0o2775)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// This file was originally part of the project "LURE - Linux User REpository", created by Elara Musayelyan.
|
// 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 the ALR Authors.
|
// It has been modified as part of "ALR - Any Linux Repository" by Евгений Храмов.
|
||||||
//
|
//
|
||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -29,14 +29,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
|
||||||
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/dlcache"
|
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestALRConfig struct {
|
type TestALRConfig struct {
|
||||||
CacheDir string
|
CacheDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TestALRConfig) GetPaths() *config.Paths {
|
func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
|
||||||
return &config.Paths{
|
return &config.Paths{
|
||||||
CacheDir: c.CacheDir,
|
CacheDir: c.CacheDir,
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ func (c *TestALRConfig) GetPaths() *config.Paths {
|
|||||||
func prepare(t *testing.T) *TestALRConfig {
|
func prepare(t *testing.T) *TestALRConfig {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
dir, err := os.MkdirTemp("", "alr-dlcache-test.*")
|
dir, err := os.MkdirTemp("/tmp", "alr-dlcache-test.*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -57,14 +57,14 @@ func prepare(t *testing.T) *TestALRConfig {
|
|||||||
|
|
||||||
func cleanup(t *testing.T, cfg *TestALRConfig) {
|
func cleanup(t *testing.T, cfg *TestALRConfig) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
os.RemoveAll(cfg.CacheDir)
|
os.Remove(cfg.CacheDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
cfg := prepare(t)
|
cfg := prepare(t)
|
||||||
defer cleanup(t, cfg)
|
defer cleanup(t, cfg)
|
||||||
|
|
||||||
dc := dlcache.New(cfg.GetPaths().CacheDir)
|
dc := dlcache.New(cfg)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
@@ -82,12 +82,6 @@ func TestNew(t *testing.T) {
|
|||||||
fi, err := os.Stat(dir)
|
fi, err := os.Stat(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("stat: expected no error, got %s", err)
|
t.Errorf("stat: expected no error, got %s", err)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi == nil {
|
|
||||||
t.Errorf("Expected file info to not be nil")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !fi.IsDir() {
|
if !fi.IsDir() {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -1,663 +0,0 @@
|
|||||||
// 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 the ALR Authors.
|
|
||||||
//
|
|
||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Встраиваем шаблон для AUR пакетов
|
|
||||||
//
|
|
||||||
//go:embed tmpls/aur.tmpl.sh
|
|
||||||
var aurTmpl string
|
|
||||||
|
|
||||||
// AUROptions содержит параметры для генерации шаблона AUR
|
|
||||||
type AUROptions struct {
|
|
||||||
Name string // Имя пакета в AUR
|
|
||||||
Version string // Версия пакета (опционально, если не указана - берется последняя)
|
|
||||||
CreateDir bool // Создавать ли директорию для пакета и дополнительные файлы
|
|
||||||
}
|
|
||||||
|
|
||||||
// aurAPIResponse представляет структуру ответа от API AUR
|
|
||||||
type aurAPIResponse struct {
|
|
||||||
Version int `json:"version"` // Версия API
|
|
||||||
Type string `json:"type"` // Тип ответа
|
|
||||||
ResultCount int `json:"resultcount"` // Количество результатов
|
|
||||||
Results []aurResult `json:"results"` // Массив результатов
|
|
||||||
Error string `json:"error"` // Сообщение об ошибке (если есть)
|
|
||||||
}
|
|
||||||
|
|
||||||
// aurResult содержит информацию о пакете из AUR
|
|
||||||
type aurResult struct {
|
|
||||||
ID int `json:"ID"`
|
|
||||||
Name string `json:"Name"`
|
|
||||||
PackageBaseID int `json:"PackageBaseID"`
|
|
||||||
PackageBase string `json:"PackageBase"`
|
|
||||||
Version string `json:"Version"`
|
|
||||||
Description string `json:"Description"`
|
|
||||||
URL string `json:"URL"`
|
|
||||||
NumVotes int `json:"NumVotes"`
|
|
||||||
Popularity float64 `json:"Popularity"`
|
|
||||||
OutOfDate *int `json:"OutOfDate"`
|
|
||||||
Maintainer string `json:"Maintainer"`
|
|
||||||
FirstSubmitted int `json:"FirstSubmitted"`
|
|
||||||
LastModified int `json:"LastModified"`
|
|
||||||
URLPath string `json:"URLPath"`
|
|
||||||
License []string `json:"License"`
|
|
||||||
Keywords []string `json:"Keywords"`
|
|
||||||
Depends []string `json:"Depends"`
|
|
||||||
MakeDepends []string `json:"MakeDepends"`
|
|
||||||
OptDepends []string `json:"OptDepends"`
|
|
||||||
CheckDepends []string `json:"CheckDepends"`
|
|
||||||
Conflicts []string `json:"Conflicts"`
|
|
||||||
Provides []string `json:"Provides"`
|
|
||||||
Replaces []string `json:"Replaces"`
|
|
||||||
// Дополнительные поля для данных из PKGBUILD
|
|
||||||
Sources []string `json:"-"`
|
|
||||||
Checksums []string `json:"-"`
|
|
||||||
BuildFunc string `json:"-"`
|
|
||||||
PackageFunc string `json:"-"`
|
|
||||||
PrepareFunc string `json:"-"`
|
|
||||||
PackageType string `json:"-"` // python, go, rust, cpp, nodejs, bin, git
|
|
||||||
HasDesktop bool `json:"-"` // Есть ли desktop файлы
|
|
||||||
HasSystemd bool `json:"-"` // Есть ли systemd сервисы
|
|
||||||
HasVersion bool `json:"-"` // Есть ли функция version()
|
|
||||||
HasScripts []string `json:"-"` // Дополнительные скрипты (postinstall, postremove, etc)
|
|
||||||
HasPatches bool `json:"-"` // Есть ли патчи
|
|
||||||
Architectures []string `json:"-"` // Поддерживаемые архитектуры
|
|
||||||
|
|
||||||
// Автоматически определяемые файлы для install-* команд
|
|
||||||
BinaryFiles []string `json:"-"` // Исполняемые файлы для install-binary
|
|
||||||
LicenseFiles []string `json:"-"` // Лицензионные файлы для install-license
|
|
||||||
ManualFiles []string `json:"-"` // Man страницы для install-manual
|
|
||||||
DesktopFiles []string `json:"-"` // Desktop файлы для install-desktop
|
|
||||||
ServiceFiles []string `json:"-"` // Systemd сервисы для install-systemd
|
|
||||||
CompletionFiles map[string]string `json:"-"` // Файлы автодополнения по типу (bash, zsh, fish)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Вспомогательные методы для шаблона
|
|
||||||
func (r aurResult) LicenseString() string {
|
|
||||||
if len(r.License) == 0 {
|
|
||||||
return "custom:Unknown"
|
|
||||||
}
|
|
||||||
// Форматируем лицензии для alr.sh
|
|
||||||
licenses := make([]string, len(r.License))
|
|
||||||
for i, l := range r.License {
|
|
||||||
licenses[i] = fmt.Sprintf("'%s'", l)
|
|
||||||
}
|
|
||||||
return strings.Join(licenses, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aurResult) DependsString() string {
|
|
||||||
if len(r.Depends) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
deps := make([]string, len(r.Depends))
|
|
||||||
for i, d := range r.Depends {
|
|
||||||
// Убираем версионные ограничения для простоты
|
|
||||||
dep := strings.Split(d, ">=")[0]
|
|
||||||
dep = strings.Split(dep, "<=")[0]
|
|
||||||
dep = strings.Split(dep, "=")[0]
|
|
||||||
dep = strings.Split(dep, ">")[0]
|
|
||||||
dep = strings.Split(dep, "<")[0]
|
|
||||||
deps[i] = fmt.Sprintf("'%s'", dep)
|
|
||||||
}
|
|
||||||
return strings.Join(deps, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aurResult) MakeDependsString() string {
|
|
||||||
if len(r.MakeDepends) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
deps := make([]string, len(r.MakeDepends))
|
|
||||||
for i, d := range r.MakeDepends {
|
|
||||||
// Убираем версионные ограничения для простоты
|
|
||||||
dep := strings.Split(d, ">=")[0]
|
|
||||||
dep = strings.Split(dep, "<=")[0]
|
|
||||||
dep = strings.Split(dep, "=")[0]
|
|
||||||
dep = strings.Split(dep, ">")[0]
|
|
||||||
dep = strings.Split(dep, "<")[0]
|
|
||||||
deps[i] = fmt.Sprintf("'%s'", dep)
|
|
||||||
}
|
|
||||||
return strings.Join(deps, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aurResult) GitURL() string {
|
|
||||||
// Формируем URL для клонирования из AUR
|
|
||||||
return fmt.Sprintf("https://aur.archlinux.org/%s.git", r.PackageBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aurResult) ArchitecturesString() string {
|
|
||||||
if len(r.Architectures) == 0 {
|
|
||||||
return "'all'"
|
|
||||||
}
|
|
||||||
archs := make([]string, len(r.Architectures))
|
|
||||||
for i, arch := range r.Architectures {
|
|
||||||
archs[i] = fmt.Sprintf("'%s'", arch)
|
|
||||||
}
|
|
||||||
return strings.Join(archs, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aurResult) OptDependsString() string {
|
|
||||||
if len(r.OptDepends) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
optDeps := make([]string, 0, len(r.OptDepends))
|
|
||||||
for _, dep := range r.OptDepends {
|
|
||||||
// Форматируем опциональные зависимости для alr.sh
|
|
||||||
parts := strings.SplitN(dep, ": ", 2)
|
|
||||||
if len(parts) == 2 {
|
|
||||||
optDeps = append(optDeps, fmt.Sprintf("'%s: %s'", parts[0], parts[1]))
|
|
||||||
} else {
|
|
||||||
optDeps = append(optDeps, fmt.Sprintf("'%s'", dep))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(optDeps, "\n\t")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aurResult) ScriptsString() string {
|
|
||||||
if len(r.HasScripts) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
scripts := make([]string, len(r.HasScripts))
|
|
||||||
for i, script := range r.HasScripts {
|
|
||||||
scripts[i] = fmt.Sprintf("['%s']='%s.sh'", script, script)
|
|
||||||
}
|
|
||||||
return strings.Join(scripts, "\n\t")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateInstallCommands генерирует команды install-* для шаблона
|
|
||||||
func (r aurResult) GenerateInstallCommands() string {
|
|
||||||
var commands []string
|
|
||||||
|
|
||||||
// install-binary команды
|
|
||||||
for _, binary := range r.BinaryFiles {
|
|
||||||
if binary == "./"+r.Name {
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-binary %s", binary))
|
|
||||||
} else {
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-binary %s %s", binary, r.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// install-license команды
|
|
||||||
for _, license := range r.LicenseFiles {
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-license %s %s/LICENSE", license, r.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// install-manual команды
|
|
||||||
for _, manual := range r.ManualFiles {
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-manual %s", manual))
|
|
||||||
}
|
|
||||||
|
|
||||||
// install-desktop команды
|
|
||||||
for _, desktop := range r.DesktopFiles {
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-desktop %s", desktop))
|
|
||||||
}
|
|
||||||
|
|
||||||
// install-systemd команды
|
|
||||||
for _, service := range r.ServiceFiles {
|
|
||||||
if strings.Contains(service, "user") {
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-systemd-user %s", service))
|
|
||||||
} else {
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-systemd %s", service))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// install-completion команды
|
|
||||||
for shell, file := range r.CompletionFiles {
|
|
||||||
switch shell {
|
|
||||||
case "bash":
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-completion bash %s < %s", r.Name, file))
|
|
||||||
case "zsh":
|
|
||||||
commands = append(commands, fmt.Sprintf("\tinstall-completion zsh %s < %s", r.Name, file))
|
|
||||||
case "fish":
|
|
||||||
commands = append(commands, fmt.Sprintf("\t%s completion fish | install-completion fish %s", r.Name, r.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(commands) == 0 {
|
|
||||||
return "\t# TODO: Добавьте команды установки файлов"
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(commands, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetchPKGBUILD загружает PKGBUILD файл для пакета
|
|
||||||
func fetchPKGBUILD(packageBase string) (string, error) {
|
|
||||||
// URL для raw PKGBUILD
|
|
||||||
pkgbuildURL := fmt.Sprintf("https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=%s", packageBase)
|
|
||||||
|
|
||||||
res, err := http.Get(pkgbuildURL)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to fetch PKGBUILD: %w", err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
return "", fmt.Errorf("failed to fetch PKGBUILD: status %s", res.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to read PKGBUILD: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseSources извлекает источники из PKGBUILD
|
|
||||||
func parseSources(pkgbuild string) []string {
|
|
||||||
var sources []string
|
|
||||||
|
|
||||||
// Регулярное выражение для поиска массива source
|
|
||||||
// Поддерживает как однострочные, так и многострочные определения
|
|
||||||
sourceRegex := regexp.MustCompile(`(?ms)source=\((.*?)\)`)
|
|
||||||
matches := sourceRegex.FindStringSubmatch(pkgbuild)
|
|
||||||
|
|
||||||
if len(matches) > 1 {
|
|
||||||
// Извлекаем содержимое массива source
|
|
||||||
sourceContent := matches[1]
|
|
||||||
|
|
||||||
// Разбираем элементы массива
|
|
||||||
// Учитываем кавычки и переносы строк
|
|
||||||
elemRegex := regexp.MustCompile(`['"]([^'"]+)['"]`)
|
|
||||||
elements := elemRegex.FindAllStringSubmatch(sourceContent, -1)
|
|
||||||
|
|
||||||
for _, elem := range elements {
|
|
||||||
if len(elem) > 1 {
|
|
||||||
source := elem[1]
|
|
||||||
// Заменяем переменные версии
|
|
||||||
source = strings.ReplaceAll(source, "$pkgver", "${version}")
|
|
||||||
source = strings.ReplaceAll(source, "${pkgver}", "${version}")
|
|
||||||
source = strings.ReplaceAll(source, "$pkgname", "${name}")
|
|
||||||
source = strings.ReplaceAll(source, "${pkgname}", "${name}")
|
|
||||||
// Обрабатываем другие переменные (упрощенно)
|
|
||||||
source = strings.ReplaceAll(source, "$_commit", "${_commit}")
|
|
||||||
sources = append(sources, source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если источники не найдены в source=(), проверяем source_x86_64 и другие архитектуры
|
|
||||||
if len(sources) == 0 {
|
|
||||||
archSourceRegex := regexp.MustCompile(`(?ms)source_(?:x86_64|aarch64)=\((.*?)\)`)
|
|
||||||
matches = archSourceRegex.FindStringSubmatch(pkgbuild)
|
|
||||||
if len(matches) > 1 {
|
|
||||||
sourceContent := matches[1]
|
|
||||||
elemRegex := regexp.MustCompile(`['"]([^'"]+)['"]`)
|
|
||||||
elements := elemRegex.FindAllStringSubmatch(sourceContent, -1)
|
|
||||||
|
|
||||||
for _, elem := range elements {
|
|
||||||
if len(elem) > 1 {
|
|
||||||
source := elem[1]
|
|
||||||
source = strings.ReplaceAll(source, "$pkgver", "${version}")
|
|
||||||
source = strings.ReplaceAll(source, "${pkgver}", "${version}")
|
|
||||||
source = strings.ReplaceAll(source, "$pkgname", "${name}")
|
|
||||||
source = strings.ReplaceAll(source, "${pkgname}", "${name}")
|
|
||||||
sources = append(sources, source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sources
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseChecksums извлекает контрольные суммы из PKGBUILD
|
|
||||||
func parseChecksums(pkgbuild string) []string {
|
|
||||||
var checksums []string
|
|
||||||
|
|
||||||
// Пробуем разные типы контрольных сумм
|
|
||||||
for _, hashType := range []string{"sha256sums", "sha512sums", "sha1sums", "md5sums", "b2sums"} {
|
|
||||||
regex := regexp.MustCompile(fmt.Sprintf(`(?ms)%s=\((.*?)\)`, hashType))
|
|
||||||
matches := regex.FindStringSubmatch(pkgbuild)
|
|
||||||
|
|
||||||
if len(matches) > 1 {
|
|
||||||
content := matches[1]
|
|
||||||
elemRegex := regexp.MustCompile(`['"]([^'"]+)['"]`)
|
|
||||||
elements := elemRegex.FindAllStringSubmatch(content, -1)
|
|
||||||
|
|
||||||
for _, elem := range elements {
|
|
||||||
if len(elem) > 1 {
|
|
||||||
checksums = append(checksums, elem[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(checksums) > 0 {
|
|
||||||
break // Используем первый найденный тип хешей
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return checksums
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseFunctions извлекает функции build(), package() и prepare() из PKGBUILD
|
|
||||||
func parseFunctions(pkgbuild string) (buildFunc, packageFunc, prepareFunc string) {
|
|
||||||
// Извлекаем функцию build()
|
|
||||||
buildRegex := regexp.MustCompile(`(?ms)^build\(\)\s*\{(.*?)^\}`)
|
|
||||||
if matches := buildRegex.FindStringSubmatch(pkgbuild); len(matches) > 1 {
|
|
||||||
buildFunc = strings.TrimSpace(matches[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Извлекаем функцию package()
|
|
||||||
packageRegex := regexp.MustCompile(`(?ms)^package\(\)\s*\{(.*?)^\}`)
|
|
||||||
if matches := packageRegex.FindStringSubmatch(pkgbuild); len(matches) > 1 {
|
|
||||||
packageFunc = strings.TrimSpace(matches[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Извлекаем функцию prepare()
|
|
||||||
prepareRegex := regexp.MustCompile(`(?ms)^prepare\(\)\s*\{(.*?)^\}`)
|
|
||||||
if matches := prepareRegex.FindStringSubmatch(pkgbuild); len(matches) > 1 {
|
|
||||||
prepareFunc = strings.TrimSpace(matches[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return buildFunc, packageFunc, prepareFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// detectInstallableFiles анализирует PKGBUILD и определяет файлы для install-* команд
|
|
||||||
func detectInstallableFiles(pkg *aurResult, pkgbuild string) {
|
|
||||||
// Инициализируем карту для файлов автодополнения
|
|
||||||
pkg.CompletionFiles = make(map[string]string)
|
|
||||||
|
|
||||||
// Для простоты, добавляем стандартные файлы для типа пакета
|
|
||||||
switch pkg.PackageType {
|
|
||||||
case "go":
|
|
||||||
pkg.BinaryFiles = append(pkg.BinaryFiles, "./"+pkg.Name)
|
|
||||||
case "rust":
|
|
||||||
pkg.BinaryFiles = append(pkg.BinaryFiles, "./target/release/"+pkg.Name)
|
|
||||||
case "cpp", "meson":
|
|
||||||
pkg.BinaryFiles = append(pkg.BinaryFiles, "./"+pkg.Name) // обычно в корне после сборки
|
|
||||||
case "bin":
|
|
||||||
pkg.BinaryFiles = append(pkg.BinaryFiles, "./"+pkg.Name)
|
|
||||||
default:
|
|
||||||
if pkg.PackageType != "python" && pkg.PackageType != "nodejs" {
|
|
||||||
pkg.BinaryFiles = append(pkg.BinaryFiles, "./"+pkg.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ищем лицензионные файлы для install-license с более точными паттернами
|
|
||||||
licenseRegex := regexp.MustCompile(`(?i)\b(LICENSE|COPYING|COPYRIGHT|LICENCE)(?:\.[a-zA-Z0-9]+)?\b`)
|
|
||||||
licenseMatches := licenseRegex.FindAllString(pkgbuild, -1)
|
|
||||||
for _, match := range licenseMatches {
|
|
||||||
// Фильтруем только реальные файлы лицензий
|
|
||||||
if strings.Contains(strings.ToLower(match), "license") ||
|
|
||||||
strings.Contains(strings.ToLower(match), "copying") ||
|
|
||||||
strings.Contains(strings.ToLower(match), "copyright") {
|
|
||||||
if !contains(pkg.LicenseFiles, "./"+match) {
|
|
||||||
pkg.LicenseFiles = append(pkg.LicenseFiles, "./"+match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если не найдены лицензионные файлы, добавляем стандартные
|
|
||||||
if len(pkg.LicenseFiles) == 0 {
|
|
||||||
pkg.LicenseFiles = append(pkg.LicenseFiles, "LICENSE")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ищем man страницы для install-manual с более точными паттернами
|
|
||||||
manRegex := regexp.MustCompile(`\b\w+\.(?:1|2|3|4|5|6|7|8)(?:\.gz)?\b`)
|
|
||||||
manMatches := manRegex.FindAllString(pkgbuild, -1)
|
|
||||||
for _, match := range manMatches {
|
|
||||||
// Проверяем, что это не переменная или часть кода
|
|
||||||
if !strings.Contains(match, "$") && !strings.Contains(match, "{") {
|
|
||||||
if !contains(pkg.ManualFiles, "./"+match) {
|
|
||||||
pkg.ManualFiles = append(pkg.ManualFiles, "./"+match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ищем desktop файлы для install-desktop
|
|
||||||
desktopRegex := regexp.MustCompile(`[^/\s]*\.desktop`)
|
|
||||||
desktopMatches := desktopRegex.FindAllString(pkgbuild, -1)
|
|
||||||
for _, match := range desktopMatches {
|
|
||||||
if !contains(pkg.DesktopFiles, "./"+match) {
|
|
||||||
pkg.DesktopFiles = append(pkg.DesktopFiles, "./"+match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ищем systemd сервисы для install-systemd
|
|
||||||
serviceRegex := regexp.MustCompile(`[^/\s]*\.service`)
|
|
||||||
serviceMatches := serviceRegex.FindAllString(pkgbuild, -1)
|
|
||||||
for _, match := range serviceMatches {
|
|
||||||
if !contains(pkg.ServiceFiles, "./"+match) {
|
|
||||||
pkg.ServiceFiles = append(pkg.ServiceFiles, "./"+match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ищем файлы автодополнения
|
|
||||||
completionPatterns := map[string]string{
|
|
||||||
"bash": `completions?/.*\.bash|bash-completion`,
|
|
||||||
"zsh": `completions?/.*\.zsh|zsh.*completion`,
|
|
||||||
"fish": `completions?/.*\.fish|fish.*completion`,
|
|
||||||
}
|
|
||||||
|
|
||||||
for shell, pattern := range completionPatterns {
|
|
||||||
regex := regexp.MustCompile(fmt.Sprintf(`(?i)%s`, pattern))
|
|
||||||
matches := regex.FindAllString(pkgbuild, -1)
|
|
||||||
if len(matches) > 0 {
|
|
||||||
pkg.CompletionFiles[shell] = matches[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// contains проверяет, содержит ли слайс строк указанную строку
|
|
||||||
func contains(slice []string, item string) bool {
|
|
||||||
for _, s := range slice {
|
|
||||||
if s == item {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// detectPackageType определяет тип пакета на основе имени, зависимостей и источников
|
|
||||||
func detectPackageType(pkg *aurResult, pkgbuild string) {
|
|
||||||
name := strings.ToLower(pkg.Name)
|
|
||||||
|
|
||||||
// Определяем тип на основе имени пакета
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(name, "python") || strings.HasPrefix(name, "python3-"):
|
|
||||||
pkg.PackageType = "python"
|
|
||||||
case strings.Contains(name, "nodejs") || strings.Contains(name, "node-"):
|
|
||||||
pkg.PackageType = "nodejs"
|
|
||||||
case strings.HasSuffix(name, "-bin"):
|
|
||||||
pkg.PackageType = "bin"
|
|
||||||
case strings.HasSuffix(name, "-git"):
|
|
||||||
pkg.PackageType = "git"
|
|
||||||
pkg.HasVersion = true // Git пакеты обычно имеют функцию version()
|
|
||||||
case strings.Contains(name, "rust") || hasRustSources(pkg.Sources):
|
|
||||||
pkg.PackageType = "rust"
|
|
||||||
case strings.Contains(name, "go-") || hasGoSources(pkg.Sources):
|
|
||||||
pkg.PackageType = "go"
|
|
||||||
case strings.Contains(name, "-rust") || strings.Contains(name, "paru") || strings.Contains(name, "cargo-"):
|
|
||||||
pkg.PackageType = "rust"
|
|
||||||
default:
|
|
||||||
// Определяем по зависимостям сборки
|
|
||||||
for _, dep := range pkg.MakeDepends {
|
|
||||||
depLower := strings.ToLower(dep)
|
|
||||||
switch {
|
|
||||||
case strings.Contains(depLower, "meson") || strings.Contains(depLower, "ninja"):
|
|
||||||
pkg.PackageType = "meson"
|
|
||||||
case strings.Contains(depLower, "cmake") || strings.Contains(depLower, "gcc") || strings.Contains(depLower, "clang"):
|
|
||||||
pkg.PackageType = "cpp"
|
|
||||||
case strings.Contains(depLower, "python"):
|
|
||||||
pkg.PackageType = "python"
|
|
||||||
case strings.Contains(depLower, "go"):
|
|
||||||
pkg.PackageType = "go"
|
|
||||||
case strings.Contains(depLower, "rust") || strings.Contains(depLower, "cargo"):
|
|
||||||
pkg.PackageType = "rust"
|
|
||||||
case strings.Contains(depLower, "npm") || strings.Contains(depLower, "nodejs"):
|
|
||||||
pkg.PackageType = "nodejs"
|
|
||||||
}
|
|
||||||
if pkg.PackageType != "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Определяем архитектуры на основе типа пакета
|
|
||||||
if pkg.PackageType == "bin" {
|
|
||||||
pkg.Architectures = []string{"amd64"} // Бинарные пакеты обычно специфичны для архитектуры
|
|
||||||
} else {
|
|
||||||
pkg.Architectures = []string{"all"} // Исходный код собирается для любой архитектуры
|
|
||||||
}
|
|
||||||
|
|
||||||
// Определяем наличие desktop файлов
|
|
||||||
pkg.HasDesktop = strings.Contains(pkgbuild, ".desktop") ||
|
|
||||||
strings.Contains(pkgbuild, "install-desktop") ||
|
|
||||||
strings.Contains(pkgbuild, "xdg-desktop")
|
|
||||||
|
|
||||||
// Определяем наличие systemd сервисов
|
|
||||||
pkg.HasSystemd = strings.Contains(pkgbuild, ".service") ||
|
|
||||||
strings.Contains(pkgbuild, "systemctl") ||
|
|
||||||
strings.Contains(pkgbuild, "install-systemd")
|
|
||||||
|
|
||||||
// Определяем наличие функции version() для -git пакетов
|
|
||||||
pkg.HasVersion = strings.Contains(pkgbuild, "pkgver()") ||
|
|
||||||
(strings.HasSuffix(name, "-git") && strings.Contains(pkgbuild, "git describe"))
|
|
||||||
|
|
||||||
// Определяем наличие патчей
|
|
||||||
pkg.HasPatches = strings.Contains(pkgbuild, "patch ") ||
|
|
||||||
strings.Contains(pkgbuild, ".patch") ||
|
|
||||||
strings.Contains(pkgbuild, ".diff")
|
|
||||||
|
|
||||||
// Определяем дополнительные скрипты
|
|
||||||
if strings.Contains(pkgbuild, "post_install") {
|
|
||||||
pkg.HasScripts = append(pkg.HasScripts, "postinstall")
|
|
||||||
}
|
|
||||||
if strings.Contains(pkgbuild, "pre_remove") || strings.Contains(pkgbuild, "post_remove") {
|
|
||||||
pkg.HasScripts = append(pkg.HasScripts, "postremove")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasRustSources проверяет, содержат ли источники Rust проекты
|
|
||||||
func hasRustSources(sources []string) bool {
|
|
||||||
for _, src := range sources {
|
|
||||||
if strings.Contains(src, "crates.io") || strings.Contains(src, "Cargo.toml") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasGoSources проверяет, содержат ли источники Go проекты
|
|
||||||
func hasGoSources(sources []string) bool {
|
|
||||||
for _, src := range sources {
|
|
||||||
if strings.Contains(src, "github.com") && strings.Contains(src, "/go") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// AUR генерирует шаблон alr.sh на основе пакета из AUR
|
|
||||||
func AUR(w io.Writer, opts AUROptions) error {
|
|
||||||
// Создаем шаблон с функциями
|
|
||||||
tmpl, err := template.New("aur").
|
|
||||||
Funcs(funcs).
|
|
||||||
Parse(aurTmpl)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Формируем URL запроса к AUR API
|
|
||||||
apiURL := "https://aur.archlinux.org/rpc/v5/info"
|
|
||||||
params := url.Values{}
|
|
||||||
params.Add("arg[]", opts.Name)
|
|
||||||
fullURL := fmt.Sprintf("%s?%s", apiURL, params.Encode())
|
|
||||||
|
|
||||||
// Выполняем запрос к AUR API
|
|
||||||
res, err := http.Get(fullURL)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to fetch AUR package info: %w", err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
return fmt.Errorf("AUR API returned status: %s", res.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Декодируем ответ
|
|
||||||
var resp aurAPIResponse
|
|
||||||
err = json.NewDecoder(res.Body).Decode(&resp)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to decode AUR response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверяем наличие ошибки в ответе
|
|
||||||
if resp.Error != "" {
|
|
||||||
return fmt.Errorf("AUR API error: %s", resp.Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверяем, что пакет найден
|
|
||||||
if resp.ResultCount == 0 {
|
|
||||||
return fmt.Errorf("package '%s' not found in AUR", opts.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Берем первый результат
|
|
||||||
pkg := resp.Results[0]
|
|
||||||
|
|
||||||
// Если указана версия, проверяем соответствие
|
|
||||||
if opts.Version != "" && pkg.Version != opts.Version {
|
|
||||||
// Предупреждаем, но продолжаем с актуальной версией из AUR
|
|
||||||
fmt.Fprintf(w, "# WARNING: Requested version %s, but AUR has %s\n", opts.Version, pkg.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Загружаем PKGBUILD для получения источников
|
|
||||||
pkgbuild, err := fetchPKGBUILD(pkg.PackageBase)
|
|
||||||
if err != nil {
|
|
||||||
// Если не удалось загрузить PKGBUILD, используем fallback на AUR репозиторий
|
|
||||||
fmt.Fprintf(w, "# WARNING: Could not fetch PKGBUILD: %v\n", err)
|
|
||||||
fmt.Fprintf(w, "# Using AUR repository as source\n")
|
|
||||||
pkg.Sources = []string{fmt.Sprintf("%s::git+%s", pkg.Name, pkg.GitURL())}
|
|
||||||
pkg.Checksums = []string{"SKIP"}
|
|
||||||
} else {
|
|
||||||
// Извлекаем источники из PKGBUILD
|
|
||||||
pkg.Sources = parseSources(pkgbuild)
|
|
||||||
pkg.Checksums = parseChecksums(pkgbuild)
|
|
||||||
pkg.BuildFunc, pkg.PackageFunc, pkg.PrepareFunc = parseFunctions(pkgbuild)
|
|
||||||
|
|
||||||
// Определяем тип пакета
|
|
||||||
detectPackageType(&pkg, pkgbuild)
|
|
||||||
|
|
||||||
// Определяем файлы для install-* команд
|
|
||||||
detectInstallableFiles(&pkg, pkgbuild)
|
|
||||||
|
|
||||||
// Если источники не найдены, используем fallback
|
|
||||||
if len(pkg.Sources) == 0 {
|
|
||||||
fmt.Fprintf(w, "# WARNING: No sources found in PKGBUILD\n")
|
|
||||||
fmt.Fprintf(w, "# Using AUR repository as source\n")
|
|
||||||
pkg.Sources = []string{fmt.Sprintf("%s::git+%s", pkg.Name, pkg.GitURL())}
|
|
||||||
pkg.Checksums = []string{"SKIP"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выполняем шаблон
|
|
||||||
return tmpl.Execute(w, pkg)
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
# 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 the ALR Authors.
|
|
||||||
#
|
|
||||||
# ALR - Any Linux Repository
|
|
||||||
# Copyright (C) 2025 The ALR Authors
|
|
||||||
#
|
|
||||||
# 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/>.
|
|
||||||
|
|
||||||
# Generated from AUR package: {{.Name}}
|
|
||||||
# Package type: {{.PackageType}}
|
|
||||||
# AUR votes: {{.NumVotes}} | Popularity: {{printf "%.2f" .Popularity}}
|
|
||||||
# Original maintainer: {{.Maintainer}}
|
|
||||||
# Adapted for ALR by automation
|
|
||||||
|
|
||||||
name='{{.Name}}'
|
|
||||||
version='{{.Version}}'
|
|
||||||
release='1'
|
|
||||||
desc='{{.Description}}'
|
|
||||||
{{if ne .Description ""}}desc_ru='{{.Description}}'{{end}}
|
|
||||||
homepage='{{.URL}}'
|
|
||||||
maintainer="Евгений Храмов <xpamych@yandex.ru> (imported from AUR)"
|
|
||||||
{{if ne .Description ""}}maintainer_ru="Евгений Храмов <xpamych@yandex.ru> (импортирован из AUR)"{{end}}
|
|
||||||
architectures=({{.ArchitecturesString}})
|
|
||||||
license=({{.LicenseString}})
|
|
||||||
{{if .Provides}}provides=({{range .Provides}}'{{.}}' {{end}}){{end}}
|
|
||||||
{{if .Conflicts}}conflicts=({{range .Conflicts}}'{{.}}' {{end}}){{end}}
|
|
||||||
{{if .Replaces}}replaces=({{range .Replaces}}'{{.}}' {{end}}){{end}}
|
|
||||||
|
|
||||||
# Базовые зависимости
|
|
||||||
{{if .DependsString}}deps=({{.DependsString}}){{else}}deps=(){{end}}
|
|
||||||
{{if .MakeDependsString}}build_deps=({{.MakeDependsString}}){{else}}build_deps=(){{end}}
|
|
||||||
|
|
||||||
# Зависимости для конкретных дистрибутивов (адаптируйте под нужды пакета)
|
|
||||||
{{if .DependsString}}deps_arch=({{.DependsString}})
|
|
||||||
deps_debian=({{.DependsString}})
|
|
||||||
deps_altlinux=({{.DependsString}})
|
|
||||||
deps_alpine=({{.DependsString}}){{end}}
|
|
||||||
|
|
||||||
{{if and .MakeDependsString (ne .PackageType "bin")}}# Зависимости сборки для конкретных дистрибутивов
|
|
||||||
build_deps_arch=({{.MakeDependsString}})
|
|
||||||
build_deps_debian=({{.MakeDependsString}})
|
|
||||||
build_deps_altlinux=({{.MakeDependsString}})
|
|
||||||
build_deps_alpine=({{.MakeDependsString}}){{end}}
|
|
||||||
|
|
||||||
{{if .OptDependsString}}# Опциональные зависимости
|
|
||||||
opt_deps=(
|
|
||||||
{{.OptDependsString}}
|
|
||||||
){{end}}
|
|
||||||
|
|
||||||
# Источники из PKGBUILD
|
|
||||||
sources=({{range .Sources}}"{{.}}" {{end}})
|
|
||||||
checksums=({{range .Checksums}}'{{.}}' {{end}})
|
|
||||||
|
|
||||||
{{if .HasVersion}}# Функция версии для Git-пакетов
|
|
||||||
version() {
|
|
||||||
cd "$srcdir/{{.Name}}"
|
|
||||||
git-version
|
|
||||||
}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .ScriptsString}}# Дополнительные скрипты
|
|
||||||
scripts=(
|
|
||||||
{{.ScriptsString}}
|
|
||||||
){{end}}
|
|
||||||
|
|
||||||
{{if or .PrepareFunc .HasPatches}}prepare() {
|
|
||||||
cd "$srcdir"{{if .PrepareFunc}}
|
|
||||||
# Из PKGBUILD:
|
|
||||||
{{.PrepareFunc}}{{else}}
|
|
||||||
# Применение патчей и подготовка исходников
|
|
||||||
# Раскомментируйте и адаптируйте при необходимости:
|
|
||||||
# patch -p1 < "${scriptdir}/fix.patch"{{end}}
|
|
||||||
}{{else}}# prepare() {
|
|
||||||
# cd "$srcdir"
|
|
||||||
# # Применение патчей и подготовка исходников при необходимости
|
|
||||||
# # patch -p1 < "${scriptdir}/fix.patch"
|
|
||||||
# }{{end}}
|
|
||||||
|
|
||||||
{{if ne .PackageType "bin"}}build() {
|
|
||||||
cd "$srcdir"{{if .BuildFunc}}
|
|
||||||
# Из PKGBUILD:
|
|
||||||
{{.BuildFunc}}{{else}}
|
|
||||||
|
|
||||||
# TODO: Адаптируйте команды сборки под конкретный проект ({{.PackageType}})
|
|
||||||
{{if eq .PackageType "meson"}}# Для Meson проектов:
|
|
||||||
meson setup build --prefix=/usr --buildtype=release
|
|
||||||
ninja -C build -j $(nproc){{else if eq .PackageType "cpp"}}# Для C/C++ проектов:
|
|
||||||
mkdir -p build && cd build
|
|
||||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
make -j$(nproc){{else if eq .PackageType "go"}}# Для Go проектов:
|
|
||||||
go build -buildmode=pie -trimpath -ldflags "-s -w" -o {{.Name}}{{else if eq .PackageType "python"}}# Для Python проектов:
|
|
||||||
python -m build --wheel --no-isolation{{else if eq .PackageType "nodejs"}}# Для Node.js проектов:
|
|
||||||
npm ci --production
|
|
||||||
npm run build{{else if eq .PackageType "rust"}}# Для Rust проектов:
|
|
||||||
cargo build --release --locked{{else if eq .PackageType "git"}}# Для Git проектов (обычно исходный код):
|
|
||||||
make -j$(nproc){{else}}# Стандартная сборка:
|
|
||||||
make -j$(nproc){{end}}{{end}}
|
|
||||||
}{{else}}# Бинарный пакет - сборка не требуется{{end}}
|
|
||||||
|
|
||||||
package() {
|
|
||||||
cd "$srcdir"{{if .PackageFunc}}
|
|
||||||
# Из PKGBUILD (адаптировано для ALR):
|
|
||||||
{{.PackageFunc}}
|
|
||||||
|
|
||||||
# Автоматически сгенерированные команды установки:
|
|
||||||
{{.GenerateInstallCommands}}{{else}}
|
|
||||||
|
|
||||||
# TODO: Адаптируйте установку файлов под конкретный проект {{.Name}}
|
|
||||||
{{if eq .PackageType "meson"}}# Для Meson проектов:
|
|
||||||
meson install -C build --destdir="$pkgdir"{{else if eq .PackageType "cpp"}}# Для C/C++ проектов:
|
|
||||||
cd build
|
|
||||||
make DESTDIR="$pkgdir" install{{else if eq .PackageType "go"}}# Для Go проектов:
|
|
||||||
# Исполняемый файл уже собран в корне{{else if eq .PackageType "python"}}# Для Python проектов:
|
|
||||||
pip install --root="$pkgdir/" . --no-deps --disable-pip-version-check{{else if eq .PackageType "nodejs"}}# Для Node.js проектов:
|
|
||||||
npm install -g --prefix="$pkgdir/usr" .{{else if eq .PackageType "rust"}}# Для Rust проектов:
|
|
||||||
# Исполняемый файл в target/release/{{else if eq .PackageType "bin"}}# Бинарный пакет:
|
|
||||||
# Файлы уже распакованы{{else}}# Стандартная установка:
|
|
||||||
make DESTDIR="$pkgdir" install{{end}}
|
|
||||||
|
|
||||||
# Автоматически сгенерированные команды установки:
|
|
||||||
{{.GenerateInstallCommands}}{{end}}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 logger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
chLog "github.com/charmbracelet/log"
|
|
||||||
"github.com/hashicorp/go-hclog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HCLoggerAdapter struct {
|
|
||||||
logger *Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func hclogLevelTochLog(level hclog.Level) chLog.Level {
|
|
||||||
switch level {
|
|
||||||
case hclog.Debug:
|
|
||||||
return chLog.DebugLevel
|
|
||||||
case hclog.Info:
|
|
||||||
return chLog.InfoLevel
|
|
||||||
case hclog.Warn:
|
|
||||||
return chLog.WarnLevel
|
|
||||||
case hclog.Error:
|
|
||||||
return chLog.ErrorLevel
|
|
||||||
}
|
|
||||||
return chLog.FatalLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Log(level hclog.Level, msg string, args ...interface{}) {
|
|
||||||
filteredArgs := make([]interface{}, 0, len(args))
|
|
||||||
for i := 0; i < len(args); i += 2 {
|
|
||||||
if i+1 >= len(args) {
|
|
||||||
filteredArgs = append(filteredArgs, args[i])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
key, ok := args[i].(string)
|
|
||||||
if !ok || key != "timestamp" {
|
|
||||||
filteredArgs = append(filteredArgs, args[i], args[i+1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start ugly hacks
|
|
||||||
// Ignore exit messages
|
|
||||||
// - https://github.com/hashicorp/go-plugin/issues/331
|
|
||||||
// - https://github.com/hashicorp/go-plugin/issues/203
|
|
||||||
// - https://github.com/hashicorp/go-plugin/issues/192
|
|
||||||
var chLogLevel chLog.Level
|
|
||||||
if msg == "plugin process exited" ||
|
|
||||||
strings.HasPrefix(msg, "[ERR] plugin: stream copy 'stderr' error") ||
|
|
||||||
strings.HasPrefix(msg, "[WARN] error closing client during Kill") ||
|
|
||||||
strings.HasPrefix(msg, "[WARN] plugin failed to exit gracefully") ||
|
|
||||||
strings.HasPrefix(msg, "[DEBUG] plugin") {
|
|
||||||
chLogLevel = chLog.DebugLevel
|
|
||||||
} else {
|
|
||||||
chLogLevel = hclogLevelTochLog(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.logger.l.Log(chLogLevel, msg, filteredArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Trace(msg string, args ...interface{}) {
|
|
||||||
a.Log(hclog.Trace, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Debug(msg string, args ...interface{}) {
|
|
||||||
a.Log(hclog.Debug, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Info(msg string, args ...interface{}) {
|
|
||||||
a.Log(hclog.Info, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Warn(msg string, args ...interface{}) {
|
|
||||||
a.Log(hclog.Warn, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Error(msg string, args ...interface{}) {
|
|
||||||
a.Log(hclog.Error, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) IsTrace() bool {
|
|
||||||
return a.logger.l.GetLevel() <= chLog.DebugLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) IsDebug() bool {
|
|
||||||
return a.logger.l.GetLevel() <= chLog.DebugLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) IsInfo() bool {
|
|
||||||
return a.logger.l.GetLevel() <= chLog.InfoLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) IsWarn() bool {
|
|
||||||
return a.logger.l.GetLevel() <= chLog.WarnLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) IsError() bool {
|
|
||||||
return a.logger.l.GetLevel() <= chLog.ErrorLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) ImpliedArgs() []interface{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) With(args ...interface{}) hclog.Logger {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Name() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) Named(name string) hclog.Logger {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) ResetNamed(name string) hclog.Logger {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) SetLevel(level hclog.Level) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *HCLoggerAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetHCLoggerAdapter() *HCLoggerAdapter {
|
|
||||||
return &HCLoggerAdapter{
|
|
||||||
logger: logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// ALR - Any Linux Repository
|
// ALR - Any Linux Repository
|
||||||
// Copyright (C) 2025 The ALR Authors
|
// 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
|
||||||
@@ -22,90 +22,75 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
chLog "github.com/charmbracelet/log"
|
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
l *chLog.Logger
|
lOut slog.Handler
|
||||||
|
lErr slog.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLogger() *chLog.Logger {
|
func setupOutLogger() *log.Logger {
|
||||||
styles := chLog.DefaultStyles()
|
styles := log.DefaultStyles()
|
||||||
logger := chLog.New(os.Stderr)
|
logger := log.New(os.Stdout)
|
||||||
styles.Levels[chLog.InfoLevel] = lipgloss.NewStyle().
|
styles.Levels[log.InfoLevel] = lipgloss.NewStyle().
|
||||||
SetString("-->").
|
SetString("-->").
|
||||||
Foreground(lipgloss.Color("35"))
|
Foreground(lipgloss.Color("35"))
|
||||||
styles.Levels[chLog.ErrorLevel] = lipgloss.NewStyle().
|
logger.SetStyles(styles)
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupErrorLogger() *log.Logger {
|
||||||
|
styles := log.DefaultStyles()
|
||||||
|
styles.Levels[log.ErrorLevel] = lipgloss.NewStyle().
|
||||||
SetString(gotext.Get("ERROR")).
|
SetString(gotext.Get("ERROR")).
|
||||||
Padding(0, 1, 0, 1).
|
Padding(0, 1, 0, 1).
|
||||||
Background(lipgloss.Color("204")).
|
Background(lipgloss.Color("204")).
|
||||||
Foreground(lipgloss.Color("0"))
|
Foreground(lipgloss.Color("0"))
|
||||||
|
logger := log.New(os.Stderr)
|
||||||
logger.SetStyles(styles)
|
logger.SetStyles(styles)
|
||||||
return logger
|
return logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *Logger {
|
func New() *Logger {
|
||||||
|
standardLogger := setupOutLogger()
|
||||||
|
errLogger := setupErrorLogger()
|
||||||
return &Logger{
|
return &Logger{
|
||||||
l: setupLogger(),
|
lOut: standardLogger,
|
||||||
|
lErr: errLogger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func slogLevelToLog(level slog.Level) chLog.Level {
|
|
||||||
switch level {
|
|
||||||
case slog.LevelDebug:
|
|
||||||
return chLog.DebugLevel
|
|
||||||
case slog.LevelInfo:
|
|
||||||
return chLog.InfoLevel
|
|
||||||
case slog.LevelWarn:
|
|
||||||
return chLog.WarnLevel
|
|
||||||
case slog.LevelError:
|
|
||||||
return chLog.ErrorLevel
|
|
||||||
}
|
|
||||||
return chLog.FatalLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) SetLevel(level slog.Level) {
|
|
||||||
l.l.SetLevel(slogLevelToLog(level))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Enabled(ctx context.Context, level slog.Level) bool {
|
func (l *Logger) Enabled(ctx context.Context, level slog.Level) bool {
|
||||||
return l.l.Enabled(ctx, level)
|
if level <= slog.LevelInfo {
|
||||||
|
return l.lOut.Enabled(ctx, level)
|
||||||
|
}
|
||||||
|
return l.lErr.Enabled(ctx, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) Handle(ctx context.Context, rec slog.Record) error {
|
func (l *Logger) Handle(ctx context.Context, rec slog.Record) error {
|
||||||
return l.l.Handle(ctx, rec)
|
if rec.Level <= slog.LevelInfo {
|
||||||
|
return l.lOut.Handle(ctx, rec)
|
||||||
|
}
|
||||||
|
return l.lErr.Handle(ctx, rec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
|
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
sl := *l
|
sl := *l
|
||||||
sl.l = l.l.WithAttrs(attrs).(*chLog.Logger)
|
sl.lOut = l.lOut.WithAttrs(attrs)
|
||||||
|
sl.lErr = l.lErr.WithAttrs(attrs)
|
||||||
return &sl
|
return &sl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) WithGroup(name string) slog.Handler {
|
func (l *Logger) WithGroup(name string) slog.Handler {
|
||||||
sl := *l
|
sl := *l
|
||||||
sl.l = l.l.WithGroup(name).(*chLog.Logger)
|
sl.lOut = l.lOut.WithGroup(name)
|
||||||
|
sl.lErr = l.lErr.WithGroup(name)
|
||||||
return &sl
|
return &sl
|
||||||
}
|
}
|
||||||
|
|
||||||
var logger *Logger
|
func SetupDefault() {
|
||||||
|
logger := slog.New(New())
|
||||||
func SetupDefault() *Logger {
|
slog.SetDefault(logger)
|
||||||
logger = New()
|
|
||||||
slogLogger := slog.New(logger)
|
|
||||||
slog.SetDefault(slogLogger)
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetupForGoPlugin() {
|
|
||||||
logger.l.SetFormatter(chLog.JSONFormatter)
|
|
||||||
chLog.TimestampKey = "@timestamp"
|
|
||||||
chLog.MessageKey = "@message"
|
|
||||||
chLog.LevelKey = "@level"
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLogger() *Logger {
|
|
||||||
return logger
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
// ALR - Any Linux Repository
|
|
||||||
// Copyright (C) 2025 The ALR Authors
|
|
||||||
//
|
|
||||||
// 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 manager
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CommonPackageManager struct {
|
|
||||||
noConfirmArg string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *CommonPackageManager) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
|
||||||
var cmd *exec.Cmd
|
|
||||||
|
|
||||||
// Проверяем, нужно ли повышение привилегий
|
|
||||||
isRoot := os.Geteuid() == 0
|
|
||||||
isCI := os.Getenv("CI") == "true"
|
|
||||||
|
|
||||||
if !isRoot && !isCI {
|
|
||||||
// Если не root и не в CI, используем sudo
|
|
||||||
cmd = exec.Command("sudo", mgrCmd)
|
|
||||||
} else {
|
|
||||||
// Если root или в CI, запускаем напрямую
|
|
||||||
cmd = exec.Command(mgrCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Args = append(cmd.Args, opts.Args...)
|
|
||||||
cmd.Args = append(cmd.Args, args...)
|
|
||||||
|
|
||||||
if opts.NoConfirm {
|
|
||||||
cmd.Args = append(cmd.Args, m.noConfirmArg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user