Files
ALR/internal/manager/pacman.go
Евгений ХрамычЪ Храмов fcd454691f Добавлено автодополнение системных пакетов в команде install
- Добавлен метод ListAvailable в интерфейс менеджера пакетов
- Реализован поиск доступных пакетов для всех менеджеров (apt, apt-rpm, dnf, yum, pacman, apk, zypper)
- Вынесена общая функция для apt и apt-rpm во избежание дублирования
- Автодополнение теперь выводит и ALR-пакеты, и системные с дедупликацией
- Добавлена фильтрация по префиксу для производительности
2026-02-23 16:02:51 +03:00

220 lines
5.1 KiB
Go

// 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 manager
import (
"bufio"
"fmt"
"os/exec"
"strings"
)
// Pacman represents the Pacman package manager
type Pacman struct {
CommonPackageManager
}
func NewPacman() *Pacman {
return &Pacman{
CommonPackageManager: CommonPackageManager{
noConfirmArg: "--noconfirm",
},
}
}
func (*Pacman) Exists() bool {
_, err := exec.LookPath("pacman")
return err == nil
}
func (*Pacman) Name() string {
return "pacman"
}
func (*Pacman) Format() string {
return "archlinux"
}
func (p *Pacman) Sync(opts *Opts) error {
opts = ensureOpts(opts)
cmd := p.getCmd(opts, "pacman", "-Sy")
setCmdEnv(cmd)
err := cmd.Run()
if err != nil {
return fmt.Errorf("pacman: sync: %w", err)
}
return nil
}
func (p *Pacman) Install(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts)
cmd := p.getCmd(opts, "pacman", "-S", "--needed")
cmd.Args = append(cmd.Args, pkgs...)
setCmdEnv(cmd)
err := cmd.Run()
if err != nil {
return fmt.Errorf("pacman: install: %w", err)
}
return nil
}
func (p *Pacman) InstallLocal(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts)
cmd := p.getCmd(opts, "pacman", "-U", "--needed")
cmd.Args = append(cmd.Args, pkgs...)
setCmdEnv(cmd)
err := cmd.Run()
if err != nil {
return fmt.Errorf("pacman: installlocal: %w", err)
}
return nil
}
func (p *Pacman) Remove(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts)
cmd := p.getCmd(opts, "pacman", "-R")
cmd.Args = append(cmd.Args, pkgs...)
setCmdEnv(cmd)
err := cmd.Run()
if err != nil {
return fmt.Errorf("pacman: remove: %w", err)
}
return nil
}
func (p *Pacman) Upgrade(opts *Opts, pkgs ...string) error {
opts = ensureOpts(opts)
return p.Install(opts, pkgs...)
}
func (p *Pacman) UpgradeAll(opts *Opts) error {
opts = ensureOpts(opts)
cmd := p.getCmd(opts, "pacman", "-Su")
setCmdEnv(cmd)
err := cmd.Run()
if err != nil {
return fmt.Errorf("pacman: upgradeall: %w", err)
}
return nil
}
func (p *Pacman) ListAvailable(prefix string) ([]string, error) {
cmd := exec.Command("pacman", "-Ssq", "^"+prefix)
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("pacman: listavailable: %w", err)
}
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("pacman: listavailable: %w", err)
}
seen := make(map[string]struct{})
var pkgs []string
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
name := scanner.Text()
if _, ok := seen[name]; !ok {
seen[name] = struct{}{}
pkgs = append(pkgs, name)
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("pacman: listavailable: %w", err)
}
if err := cmd.Wait(); err != nil {
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 1 {
return nil, nil
}
return nil, fmt.Errorf("pacman: listavailable: %w", err)
}
return pkgs, nil
}
func (p *Pacman) ListInstalled(opts *Opts) (map[string]string, error) {
out := map[string]string{}
cmd := exec.Command("pacman", "-Q")
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
err = cmd.Start()
if err != nil {
return nil, err
}
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
name, version, ok := strings.Cut(scanner.Text(), " ")
if !ok {
continue
}
out[name] = version
}
err = scanner.Err()
if err != nil {
return nil, err
}
return out, nil
}
func (p *Pacman) IsInstalled(pkg string) (bool, error) {
cmd := exec.Command("pacman", "-Q", pkg)
output, err := cmd.CombinedOutput()
if err != nil {
// Pacman returns exit code 1 if the package is not found
if exitErr, ok := err.(*exec.ExitError); ok {
if exitErr.ExitCode() == 1 {
return false, nil
}
}
return false, fmt.Errorf("pacman: isinstalled: %w, output: %s", err, output)
}
return true, nil
}
func (p *Pacman) GetInstalledVersion(pkg string) (string, error) {
cmd := exec.Command("pacman", "-Q", pkg)
output, err := cmd.CombinedOutput()
if err != nil {
// Pacman returns exit code 1 if the package is not found
if exitErr, ok := err.(*exec.ExitError); ok {
if exitErr.ExitCode() == 1 {
return "", nil
}
}
return "", fmt.Errorf("pacman: getinstalledversion: %w, output: %s", err, output)
}
// Output format: "package-name version"
_, version, ok := strings.Cut(strings.TrimSpace(string(output)), " ")
if !ok {
return "", nil
}
return version, nil
}