Compare commits
7 Commits
v0.0.3
...
cfb3764412
Author | SHA1 | Date | |
---|---|---|---|
cfb3764412 | |||
df87bfcc63 | |||
5d1d3d7c45 | |||
a711edbcc0 | |||
d5636e8094 | |||
5d17875813 | |||
41eec2fc98 |
26
.golangci.yml
Normal file
26
.golangci.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
run:
|
||||||
|
timeout: 5m
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
goimports:
|
||||||
|
local-prefixes: "plemya-x.ru/alr"
|
||||||
|
gofmt:
|
||||||
|
simplify: true
|
||||||
|
gofumpt:
|
||||||
|
extra-rules: true
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- gofmt
|
||||||
|
- gofumpt
|
||||||
|
- goimports
|
||||||
|
- gocritic
|
||||||
|
- govet
|
||||||
|
- staticcheck
|
||||||
|
- unused
|
||||||
|
- errcheck
|
||||||
|
- typecheck
|
||||||
|
# - forbidigo
|
||||||
|
|
||||||
|
issues:
|
||||||
|
fix: true
|
6
Makefile
6
Makefile
@@ -11,6 +11,8 @@ 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)
|
||||||
|
|
||||||
|
GOLANGCI_LINT := go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
|
||||||
|
|
||||||
.PHONY: build install clean clear uninstall check-no-root
|
.PHONY: build install clean clear uninstall check-no-root
|
||||||
|
|
||||||
build: check-no-root $(BIN)
|
build: check-no-root $(BIN)
|
||||||
@@ -25,6 +27,10 @@ check-no-root:
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# TODO: remove --tests=false
|
||||||
|
fmt:
|
||||||
|
$(GOLANGCI_LINT) run --fix --tests=false
|
||||||
|
|
||||||
install: \
|
install: \
|
||||||
$(INSTALED_BIN) \
|
$(INSTALED_BIN) \
|
||||||
$(INSTALLED_BASH_COMPLETION) \
|
$(INSTALLED_BASH_COMPLETION) \
|
||||||
|
1
build.go
1
build.go
@@ -23,6 +23,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/osutils"
|
"plemya-x.ru/alr/internal/osutils"
|
||||||
"plemya-x.ru/alr/internal/types"
|
"plemya-x.ru/alr/internal/types"
|
||||||
|
1
fix.go
1
fix.go
@@ -22,6 +22,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
|
1
gen.go
1
gen.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"plemya-x.ru/alr/pkg/gen"
|
"plemya-x.ru/alr/pkg/gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -6,12 +6,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"mvdan.cc/sh/v3/expand"
|
||||||
|
"mvdan.cc/sh/v3/interp"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/cpu"
|
"plemya-x.ru/alr/internal/cpu"
|
||||||
"plemya-x.ru/alr/internal/shutils/helpers"
|
"plemya-x.ru/alr/internal/shutils/helpers"
|
||||||
"plemya-x.ru/alr/pkg/distro"
|
"plemya-x.ru/alr/pkg/distro"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
"mvdan.cc/sh/v3/expand"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var helperCmd = &cli.Command{
|
var helperCmd = &cli.Command{
|
||||||
|
3
info.go
3
info.go
@@ -23,13 +23,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/cliutils"
|
"plemya-x.ru/alr/internal/cliutils"
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/overrides"
|
"plemya-x.ru/alr/internal/overrides"
|
||||||
"plemya-x.ru/alr/pkg/distro"
|
"plemya-x.ru/alr/pkg/distro"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
"plemya-x.ru/alr/pkg/repos"
|
"plemya-x.ru/alr/pkg/repos"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var infoCmd = &cli.Command{
|
var infoCmd = &cli.Command{
|
||||||
|
@@ -22,6 +22,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/cliutils"
|
"plemya-x.ru/alr/internal/cliutils"
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
|
@@ -24,6 +24,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"github.com/AlecAivazis/survey/v2"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/internal/pager"
|
"plemya-x.ru/alr/internal/pager"
|
||||||
|
@@ -24,6 +24,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/types"
|
"plemya-x.ru/alr/internal/types"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
)
|
)
|
||||||
|
@@ -24,8 +24,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@@ -25,6 +25,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
|
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -28,10 +28,11 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"plemya-x.ru/alr/internal/config"
|
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"modernc.org/sqlite"
|
"modernc.org/sqlite"
|
||||||
|
|
||||||
|
"plemya-x.ru/alr/internal/config"
|
||||||
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CurrentVersion is the current version of the database.
|
// CurrentVersion is the current version of the database.
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Пакет dl содержит абстракции для загрузки файлов и каталогов
|
// Пакет dl содержит абстракции для загрузки файлов и каталогов
|
||||||
// из различных источников.
|
// из различных источников.
|
||||||
@@ -39,6 +39,7 @@ import (
|
|||||||
"golang.org/x/crypto/blake2b"
|
"golang.org/x/crypto/blake2b"
|
||||||
"golang.org/x/crypto/blake2s"
|
"golang.org/x/crypto/blake2s"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/dlcache"
|
"plemya-x.ru/alr/internal/dlcache"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
)
|
)
|
||||||
@@ -299,8 +300,6 @@ func linkDir(src, dest string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
rel, err := filepath.Rel(src, path)
|
rel, err := filepath.Rel(src, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@@ -33,6 +33,7 @@ import (
|
|||||||
|
|
||||||
"github.com/mholt/archiver/v4"
|
"github.com/mholt/archiver/v4"
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/shutils/handlers"
|
"plemya-x.ru/alr/internal/shutils/handlers"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -222,7 +223,7 @@ func extractFile(r io.Reader, format archiver.Format, name string, opts Options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f.IsDir() {
|
if f.IsDir() {
|
||||||
err = os.Mkdir(path, 0o755)
|
err = os.MkdirAll(path, 0o755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -279,4 +280,4 @@ func getFilename(res *http.Response) (name string) {
|
|||||||
} else {
|
} else {
|
||||||
return path.Base(res.Request.URL.Path)
|
return path.Base(res.Request.URL.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,11 +22,12 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/cpu"
|
"plemya-x.ru/alr/internal/cpu"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/pkg/distro"
|
"plemya-x.ru/alr/pkg/distro"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Opts struct {
|
type Opts struct {
|
||||||
|
@@ -25,12 +25,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"plemya-x.ru/alr/internal/overrides"
|
|
||||||
"plemya-x.ru/alr/pkg/distro"
|
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"mvdan.cc/sh/v3/expand"
|
"mvdan.cc/sh/v3/expand"
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
"mvdan.cc/sh/v3/syntax"
|
"mvdan.cc/sh/v3/syntax"
|
||||||
|
|
||||||
|
"plemya-x.ru/alr/internal/overrides"
|
||||||
|
"plemya-x.ru/alr/pkg/distro"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNotPointerToStruct = errors.New("val must be a pointer to a struct")
|
var ErrNotPointerToStruct = errors.New("val must be a pointer to a struct")
|
||||||
|
@@ -10,9 +10,9 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"plemya-x.ru/fakeroot"
|
|
||||||
"mvdan.cc/sh/v3/expand"
|
"mvdan.cc/sh/v3/expand"
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
|
"plemya-x.ru/fakeroot"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FakerootExecHandler was extracted from github.com/mvdan/sh/interp/handler.go
|
// FakerootExecHandler was extracted from github.com/mvdan/sh/interp/handler.go
|
||||||
|
@@ -31,8 +31,9 @@ import (
|
|||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"plemya-x.ru/alr/internal/shutils/handlers"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
|
|
||||||
|
"plemya-x.ru/alr/internal/shutils/handlers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@@ -24,9 +24,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"go.elara.ws/logger"
|
"go.elara.ws/logger"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
|
||||||
"go.elara.ws/translate"
|
"go.elara.ws/translate"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed files
|
//go:embed files
|
||||||
|
3
list.go
3
list.go
@@ -22,12 +22,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
"plemya-x.ru/alr/pkg/manager"
|
"plemya-x.ru/alr/pkg/manager"
|
||||||
"plemya-x.ru/alr/pkg/repos"
|
"plemya-x.ru/alr/pkg/repos"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var listCmd = &cli.Command{
|
var listCmd = &cli.Command{
|
||||||
|
1
main.go
1
main.go
@@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"go.elara.ws/logger"
|
"go.elara.ws/logger"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/internal/translations"
|
"plemya-x.ru/alr/internal/translations"
|
||||||
|
@@ -41,7 +41,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
// Импортируем пакеты для поддержки различных форматов пакетов (APK, DEB, RPM и ARCH).
|
// Импортируем пакеты для поддержки различных форматов пакетов (APK, DEB, RPM и ARCH).
|
||||||
_ "github.com/goreleaser/nfpm/v2/apk"
|
_ "github.com/goreleaser/nfpm/v2/apk"
|
||||||
_ "github.com/goreleaser/nfpm/v2/arch"
|
_ "github.com/goreleaser/nfpm/v2/arch"
|
||||||
_ "github.com/goreleaser/nfpm/v2/deb"
|
_ "github.com/goreleaser/nfpm/v2/deb"
|
||||||
@@ -52,6 +52,7 @@ import (
|
|||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2"
|
"github.com/goreleaser/nfpm/v2"
|
||||||
"github.com/goreleaser/nfpm/v2/files"
|
"github.com/goreleaser/nfpm/v2/files"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/cliutils"
|
"plemya-x.ru/alr/internal/cliutils"
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/cpu"
|
"plemya-x.ru/alr/internal/cpu"
|
||||||
@@ -82,8 +83,8 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Первый проход предназначен для получения значений переменных и выполняется
|
// Первый проход предназначен для получения значений переменных и выполняется
|
||||||
// до отображения скрипта, чтобы предотвратить выполнение вредоносного кода.
|
// до отображения скрипта, чтобы предотвратить выполнение вредоносного кода.
|
||||||
vars, err := executeFirstPass(ctx, info, fl, opts.Script)
|
vars, err := executeFirstPass(ctx, info, fl, opts.Script)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -91,8 +92,8 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
|
|
||||||
dirs := getDirs(ctx, vars, opts.Script)
|
dirs := getDirs(ctx, vars, opts.Script)
|
||||||
|
|
||||||
// Если флаг opts.Clean не установлен, и пакет уже собран,
|
// Если флаг opts.Clean не установлен, и пакет уже собран,
|
||||||
// возвращаем его, а не собираем заново.
|
// возвращаем его, а не собираем заново.
|
||||||
if !opts.Clean {
|
if !opts.Clean {
|
||||||
builtPkgPath, ok, err := checkForBuiltPackage(opts.Manager, vars, getPkgFormat(opts.Manager), dirs.BaseDir)
|
builtPkgPath, ok, err := checkForBuiltPackage(opts.Manager, vars, getPkgFormat(opts.Manager), dirs.BaseDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,7 +105,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Спрашиваем у пользователя, хочет ли он увидеть скрипт сборки.
|
// Спрашиваем у пользователя, хочет ли он увидеть скрипт сборки.
|
||||||
err = cliutils.PromptViewScript(ctx, opts.Script, vars.Name, config.Config(ctx).PagerStyle, opts.Interactive)
|
err = cliutils.PromptViewScript(ctx, opts.Script, vars.Name, config.Config(ctx).PagerStyle, opts.Interactive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to prompt user to view build script").Err(err).Send()
|
log.Fatal("Failed to prompt user to view build script").Err(err).Send()
|
||||||
@@ -112,9 +113,9 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
|
|
||||||
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
|
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
|
||||||
|
|
||||||
// Второй проход будет использоваться для выполнения реального кода,
|
// Второй проход будет использоваться для выполнения реального кода,
|
||||||
// поэтому он не ограничен. Скрипт уже был показан
|
// поэтому он не ограничен. Скрипт уже был показан
|
||||||
// пользователю к этому моменту, так что это должно быть безопасно.
|
// пользователю к этому моменту, так что это должно быть безопасно.
|
||||||
dec, err := executeSecondPass(ctx, info, fl, dirs)
|
dec, err := executeSecondPass(ctx, info, fl, dirs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -133,7 +134,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
os.Exit(1) // Если проверки не пройдены, выходим из программы
|
os.Exit(1) // Если проверки не пройдены, выходим из программы
|
||||||
}
|
}
|
||||||
|
|
||||||
// Подготавливаем директории для сборки
|
// Подготавливаем директории для сборки
|
||||||
err = prepareDirs(dirs)
|
err = prepareDirs(dirs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -170,7 +171,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
|
|
||||||
pkgFormat := getPkgFormat(opts.Manager) // Получаем формат пакета
|
pkgFormat := getPkgFormat(opts.Manager) // Получаем формат пакета
|
||||||
|
|
||||||
pkgInfo, err := buildPkgMetadata(vars, dirs, pkgFormat, info, append(repoDeps, builtNames...)) // Собираем метаданные пакета
|
pkgInfo, err := buildPkgMetadata(ctx, vars, dirs, pkgFormat, info, append(repoDeps, builtNames...)) // Собираем метаданные пакета
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -181,7 +182,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
}
|
}
|
||||||
|
|
||||||
pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета
|
pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета
|
||||||
pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету
|
pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету
|
||||||
|
|
||||||
pkgFile, err := os.Create(pkgPath) // Создаём файл пакета
|
pkgFile, err := os.Create(pkgPath) // Создаём файл пакета
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -200,14 +201,14 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Добавляем путь и имя только что собранного пакета в
|
// Добавляем путь и имя только что собранного пакета в
|
||||||
// соответствующие срезы
|
// соответствующие срезы
|
||||||
pkgPaths := append(builtPaths, pkgPath)
|
pkgPaths := append(builtPaths, pkgPath)
|
||||||
pkgNames := append(builtNames, vars.Name)
|
pkgNames := append(builtNames, vars.Name)
|
||||||
|
|
||||||
// Удаляем дубликаты из pkgPaths и pkgNames.
|
// Удаляем дубликаты из pkgPaths и pkgNames.
|
||||||
// Дубликаты могут появиться, если несколько зависимостей
|
// Дубликаты могут появиться, если несколько зависимостей
|
||||||
// зависят от одних и тех же пакетов.
|
// зависят от одних и тех же пакетов.
|
||||||
pkgPaths = removeDuplicates(pkgPaths)
|
pkgPaths = removeDuplicates(pkgPaths)
|
||||||
pkgNames = removeDuplicates(pkgNames)
|
pkgNames = removeDuplicates(pkgNames)
|
||||||
|
|
||||||
@@ -233,16 +234,16 @@ func parseScript(info *distro.OSRelease, script string) (*syntax.File, error) {
|
|||||||
// Функция executeFirstPass выполняет парсированный скрипт в ограниченной среде,
|
// Функция executeFirstPass выполняет парсированный скрипт в ограниченной среде,
|
||||||
// чтобы извлечь переменные сборки без выполнения реального кода.
|
// чтобы извлечь переменные сборки без выполнения реального кода.
|
||||||
func executeFirstPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, script string) (*types.BuildVars, error) {
|
func executeFirstPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, script string) (*types.BuildVars, error) {
|
||||||
scriptDir := filepath.Dir(script) // Получаем директорию скрипта
|
scriptDir := filepath.Dir(script) // Получаем директорию скрипта
|
||||||
env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir}) // Создаём переменные окружения для сборки
|
env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir}) // Создаём переменные окружения для сборки
|
||||||
|
|
||||||
runner, err := interp.New(
|
runner, err := interp.New(
|
||||||
interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
|
interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
|
||||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
|
interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
|
||||||
interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)), // Ограничиваем выполнение
|
interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)), // Ограничиваем выполнение
|
||||||
interp.ReadDirHandler(handlers.RestrictedReadDir(scriptDir)), // Ограничиваем чтение директорий
|
interp.ReadDirHandler(handlers.RestrictedReadDir(scriptDir)), // Ограничиваем чтение директорий
|
||||||
interp.StatHandler(handlers.RestrictedStat(scriptDir)), // Ограничиваем доступ к статистике файлов
|
interp.StatHandler(handlers.RestrictedStat(scriptDir)), // Ограничиваем доступ к статистике файлов
|
||||||
interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), // Ограничиваем открытие файлов
|
interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), // Ограничиваем открытие файлов
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -282,8 +283,8 @@ func executeSecondPass(ctx context.Context, info *distro.OSRelease, fl *syntax.F
|
|||||||
|
|
||||||
fakeroot := handlers.FakerootExecHandler(2 * time.Second) // Настраиваем "fakeroot" для выполнения
|
fakeroot := handlers.FakerootExecHandler(2 * time.Second) // Настраиваем "fakeroot" для выполнения
|
||||||
runner, err := interp.New(
|
runner, err := interp.New(
|
||||||
interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
|
interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
|
||||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
|
interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
|
||||||
interp.ExecHandler(helpers.Helpers.ExecHandler(fakeroot)), // Обрабатываем выполнение через fakeroot
|
interp.ExecHandler(helpers.Helpers.ExecHandler(fakeroot)), // Обрабатываем выполнение через fakeroot
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -396,30 +397,30 @@ func buildALRDeps(ctx context.Context, opts types.BuildOpts, vars *types.BuildVa
|
|||||||
}
|
}
|
||||||
repoDeps = notFound
|
repoDeps = notFound
|
||||||
|
|
||||||
// Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез
|
// Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез
|
||||||
pkgs := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive)
|
pkgs := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive)
|
||||||
scripts := GetScriptPaths(ctx, pkgs)
|
scripts := GetScriptPaths(ctx, pkgs)
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
newOpts := opts
|
newOpts := opts
|
||||||
newOpts.Script = script
|
newOpts.Script = script
|
||||||
|
|
||||||
// Собираем зависимости
|
// Собираем зависимости
|
||||||
pkgPaths, pkgNames, err := BuildPackage(ctx, newOpts)
|
pkgPaths, pkgNames, err := BuildPackage(ctx, newOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Добавляем пути всех собранных пакетов в builtPaths
|
// Добавляем пути всех собранных пакетов в builtPaths
|
||||||
builtPaths = append(builtPaths, pkgPaths...)
|
builtPaths = append(builtPaths, pkgPaths...)
|
||||||
// Добавляем пути всех собранных пакетов в builtPaths
|
// Добавляем пути всех собранных пакетов в builtPaths
|
||||||
builtNames = append(builtNames, pkgNames...)
|
builtNames = append(builtNames, pkgNames...)
|
||||||
// Добавляем имя текущего пакета в builtNames
|
// Добавляем имя текущего пакета в builtNames
|
||||||
builtNames = append(builtNames, filepath.Base(filepath.Dir(script)))
|
builtNames = append(builtNames, filepath.Base(filepath.Dir(script)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Удаляем возможные дубликаты, которые могут быть введены, если
|
// Удаляем возможные дубликаты, которые могут быть введены, если
|
||||||
// несколько зависимостей зависят от одних и тех же пакетов.
|
// несколько зависимостей зависят от одних и тех же пакетов.
|
||||||
repoDeps = removeDuplicates(repoDeps)
|
repoDeps = removeDuplicates(repoDeps)
|
||||||
builtPaths = removeDuplicates(builtPaths)
|
builtPaths = removeDuplicates(builtPaths)
|
||||||
builtNames = removeDuplicates(builtNames)
|
builtNames = removeDuplicates(builtNames)
|
||||||
@@ -474,35 +475,35 @@ func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Dire
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Выполнение всех функций, начинающихся с package_
|
// Выполнение всех функций, начинающихся с package_
|
||||||
for {
|
for {
|
||||||
packageFn, ok := dec.GetFunc("package")
|
packageFn, ok := dec.GetFunc("package")
|
||||||
if ok {
|
if ok {
|
||||||
log.Info("Executing package()").Send()
|
log.Info("Executing package()").Send()
|
||||||
err = packageFn(ctx, interp.Dir(dirs.SrcDir))
|
err = packageFn(ctx, interp.Dir(dirs.SrcDir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверка на наличие дополнительных функций package_*
|
// Проверка на наличие дополнительных функций package_*
|
||||||
packageFuncName := "package_"
|
packageFuncName := "package_"
|
||||||
if packageFunc, ok := dec.GetFunc(packageFuncName); ok {
|
if packageFunc, ok := dec.GetFunc(packageFuncName); ok {
|
||||||
log.Info("Executing " + packageFuncName).Send()
|
log.Info("Executing " + packageFuncName).Send()
|
||||||
err = packageFunc(ctx, interp.Dir(dirs.SrcDir))
|
err = packageFunc(ctx, interp.Dir(dirs.SrcDir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break // Если больше нет функций package_*, выходим из цикла
|
break // Если больше нет функций package_*, выходим из цикла
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция buildPkgMetadata создает метаданные для пакета, который будет собран.
|
// Функция buildPkgMetadata создает метаданные для пакета, который будет собран.
|
||||||
func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat string, info *distro.OSRelease, deps []string) (*nfpm.Info, error) {
|
func buildPkgMetadata(ctx context.Context, vars *types.BuildVars, dirs types.Directories, pkgFormat string, info *distro.OSRelease, deps []string) (*nfpm.Info, error) {
|
||||||
pkgInfo := getBasePkgInfo(vars)
|
pkgInfo := getBasePkgInfo(vars)
|
||||||
pkgInfo.Description = vars.Description
|
pkgInfo.Description = vars.Description
|
||||||
pkgInfo.Platform = "linux"
|
pkgInfo.Platform = "linux"
|
||||||
@@ -517,7 +518,7 @@ func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pkgFormat == "apk" {
|
if pkgFormat == "apk" {
|
||||||
// Alpine отказывается устанавливать пакеты, которые предоставляют сами себя, поэтому удаляем такие элементы
|
// Alpine отказывается устанавливать пакеты, которые предоставляют сами себя, поэтому удаляем такие элементы
|
||||||
pkgInfo.Overridables.Provides = slices.DeleteFunc(pkgInfo.Overridables.Provides, func(s string) bool {
|
pkgInfo.Overridables.Provides = slices.DeleteFunc(pkgInfo.Overridables.Provides, func(s string) bool {
|
||||||
return s == pkgInfo.Name
|
return s == pkgInfo.Name
|
||||||
})
|
})
|
||||||
@@ -543,6 +544,17 @@ func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat s
|
|||||||
}
|
}
|
||||||
pkgInfo.Overridables.Contents = contents
|
pkgInfo.Overridables.Contents = contents
|
||||||
|
|
||||||
|
if pkgFormat == "rpm" {
|
||||||
|
err = rpmFindProvides(ctx, pkgInfo, dirs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = rpmFindRequires(ctx, pkgInfo, dirs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return pkgInfo, nil
|
return pkgInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,7 +571,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если директория пустая, пропускаем её
|
// Если директория пустая, пропускаем её
|
||||||
_, err = f.Readdirnames(1)
|
_, err = f.Readdirnames(1)
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
return nil
|
return nil
|
||||||
@@ -576,13 +588,13 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
|
|||||||
|
|
||||||
return f.Close()
|
return f.Close()
|
||||||
}
|
}
|
||||||
// Если файл является символической ссылкой, прорабатываем это
|
// Если файл является символической ссылкой, прорабатываем это
|
||||||
if fi.Mode()&os.ModeSymlink != 0 {
|
if fi.Mode()&os.ModeSymlink != 0 {
|
||||||
link, err := os.Readlink(path)
|
link, err := os.Readlink(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Удаляем pkgdir из пути символической ссылки
|
// Удаляем pkgdir из пути символической ссылки
|
||||||
link = strings.TrimPrefix(link, dirs.PkgDir)
|
link = strings.TrimPrefix(link, dirs.PkgDir)
|
||||||
|
|
||||||
contents = append(contents, &files.Content{
|
contents = append(contents, &files.Content{
|
||||||
@@ -597,7 +609,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Обрабатываем обычные файлы
|
// Обрабатываем обычные файлы
|
||||||
fileContent := &files.Content{
|
fileContent := &files.Content{
|
||||||
Source: path,
|
Source: path,
|
||||||
Destination: trimmed,
|
Destination: trimmed,
|
||||||
@@ -608,7 +620,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если файл должен быть сохранен, установите его тип как config|noreplace
|
// Если файл должен быть сохранен, установите его тип как config|noreplace
|
||||||
if slices.Contains(vars.Backup, trimmed) {
|
if slices.Contains(vars.Backup, trimmed) {
|
||||||
fileContent.Type = "config|noreplace"
|
fileContent.Type = "config|noreplace"
|
||||||
}
|
}
|
||||||
@@ -744,9 +756,9 @@ func getSources(ctx context.Context, dirs types.Directories, bv *types.BuildVars
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !strings.EqualFold(bv.Checksums[i], "SKIP") {
|
if !strings.EqualFold(bv.Checksums[i], "SKIP") {
|
||||||
// Если контрольная сумма содержит двоеточие, используйте часть до двоеточия
|
// Если контрольная сумма содержит двоеточие, используйте часть до двоеточия
|
||||||
// как алгоритм, а часть после как фактическую контрольную сумму.
|
// как алгоритм, а часть после как фактическую контрольную сумму.
|
||||||
// В противном случае используйте sha256 по умолчанию с целой строкой как контрольной суммой.
|
// В противном случае используйте sha256 по умолчанию с целой строкой как контрольной суммой.
|
||||||
algo, hashData, ok := strings.Cut(bv.Checksums[i], ":")
|
algo, hashData, ok := strings.Cut(bv.Checksums[i], ":")
|
||||||
if ok {
|
if ok {
|
||||||
checksum, err := hex.DecodeString(hashData)
|
checksum, err := hex.DecodeString(hashData)
|
||||||
|
81
pkg/build/findDeps.go
Normal file
81
pkg/build/findDeps.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/goreleaser/nfpm/v2"
|
||||||
|
|
||||||
|
"plemya-x.ru/alr/internal/types"
|
||||||
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rpmFindDependencies(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories, command string, updateFunc func(string)) error {
|
||||||
|
log := loggerctx.From(ctx)
|
||||||
|
|
||||||
|
if _, err := exec.LookPath(command); err != nil {
|
||||||
|
log.Info("Command not found on the system").Str("command", command).Send()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var paths []string
|
||||||
|
for _, content := range pkgInfo.Contents {
|
||||||
|
if content.Type != "dir" {
|
||||||
|
paths = append(paths,
|
||||||
|
path.Join(dirs.PkgDir, content.Destination),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(paths) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(command)
|
||||||
|
cmd.Stdin = bytes.NewBufferString(strings.Join(paths, "\n"))
|
||||||
|
cmd.Env = append(cmd.Env,
|
||||||
|
"RPM_BUILD_ROOT="+dirs.PkgDir,
|
||||||
|
"RPM_FINDPROV_METHOD=",
|
||||||
|
"RPM_FINDREQ_METHOD=",
|
||||||
|
"RPM_DATADIR=",
|
||||||
|
"RPM_SUBPACKAGE_NAME=",
|
||||||
|
)
|
||||||
|
var out bytes.Buffer
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &out
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Error(stderr.String())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies := strings.Split(strings.TrimSpace(out.String()), "\n")
|
||||||
|
for _, dep := range dependencies {
|
||||||
|
if dep != "" {
|
||||||
|
updateFunc(dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func rpmFindProvides(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories) error {
|
||||||
|
log := loggerctx.From(ctx)
|
||||||
|
|
||||||
|
return rpmFindDependencies(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-provides", func(dep string) {
|
||||||
|
log.Info("Provided dependency found").Str("dep", dep).Send()
|
||||||
|
pkgInfo.Overridables.Provides = append(pkgInfo.Overridables.Provides, dep)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func rpmFindRequires(ctx context.Context, pkgInfo *nfpm.Info, dirs types.Directories) error {
|
||||||
|
log := loggerctx.From(ctx)
|
||||||
|
|
||||||
|
return rpmFindDependencies(ctx, pkgInfo, dirs, "/usr/lib/rpm/find-requires", func(dep string) {
|
||||||
|
log.Info("Required dependency found").Str("dep", dep).Send()
|
||||||
|
pkgInfo.Overridables.Depends = append(pkgInfo.Overridables.Depends, dep)
|
||||||
|
})
|
||||||
|
}
|
@@ -46,15 +46,15 @@ func InstallPkgs(ctx context.Context, alrPkgs []db.Package, nativePkgs []string,
|
|||||||
|
|
||||||
if len(nativePkgs) > 0 {
|
if len(nativePkgs) > 0 {
|
||||||
err := opts.Manager.Install(nil, nativePkgs...)
|
err := opts.Manager.Install(nil, nativePkgs...)
|
||||||
// Если есть нативные пакеты, выполняем их установку
|
// Если есть нативные пакеты, выполняем их установку
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error installing native packages").Err(err).Send()
|
log.Fatal("Error installing native packages").Err(err).Send()
|
||||||
// Логируем и завершаем выполнение при ошибке
|
// Логируем и завершаем выполнение при ошибке
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallScripts(ctx, GetScriptPaths(ctx, alrPkgs), opts)
|
InstallScripts(ctx, GetScriptPaths(ctx, alrPkgs), opts)
|
||||||
// Устанавливаем скрипты сборки через функцию InstallScripts
|
// Устанавливаем скрипты сборки через функцию InstallScripts
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetScriptPaths возвращает срез путей к скриптам, соответствующий
|
// GetScriptPaths возвращает срез путей к скриптам, соответствующий
|
||||||
@@ -62,7 +62,7 @@ func InstallPkgs(ctx context.Context, alrPkgs []db.Package, nativePkgs []string,
|
|||||||
func GetScriptPaths(ctx context.Context, pkgs []db.Package) []string {
|
func GetScriptPaths(ctx context.Context, pkgs []db.Package) []string {
|
||||||
var scripts []string
|
var scripts []string
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
// Для каждого пакета создаем путь к скрипту сборки
|
// Для каждого пакета создаем путь к скрипту сборки
|
||||||
scriptPath := filepath.Join(config.GetPaths(ctx).RepoDir, pkg.Repository, pkg.Name, "alr.sh")
|
scriptPath := filepath.Join(config.GetPaths(ctx).RepoDir, pkg.Repository, pkg.Name, "alr.sh")
|
||||||
scripts = append(scripts, scriptPath)
|
scripts = append(scripts, scriptPath)
|
||||||
}
|
}
|
||||||
@@ -75,17 +75,17 @@ func InstallScripts(ctx context.Context, scripts []string, opts types.BuildOpts)
|
|||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
opts.Script = script // Устанавливаем текущий скрипт в опции
|
opts.Script = script // Устанавливаем текущий скрипт в опции
|
||||||
builtPkgs, _, err := BuildPackage(ctx, opts)
|
builtPkgs, _, err := BuildPackage(ctx, opts)
|
||||||
// Выполняем сборку пакета
|
// Выполняем сборку пакета
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error building package").Err(err).Send()
|
log.Fatal("Error building package").Err(err).Send()
|
||||||
// Логируем и завершаем выполнение при ошибке сборки
|
// Логируем и завершаем выполнение при ошибке сборки
|
||||||
}
|
}
|
||||||
|
|
||||||
err = opts.Manager.InstallLocal(nil, builtPkgs...)
|
err = opts.Manager.InstallLocal(nil, builtPkgs...)
|
||||||
// Устанавливаем локально собранные пакеты
|
// Устанавливаем локально собранные пакеты
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error installing package").Err(err).Send()
|
log.Fatal("Error installing package").Err(err).Send()
|
||||||
// Логируем и завершаем выполнение при ошибке установки
|
// Логируем и завершаем выполнение при ошибке установки
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,10 +23,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/shutils/handlers"
|
|
||||||
"mvdan.cc/sh/v3/expand"
|
"mvdan.cc/sh/v3/expand"
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
"mvdan.cc/sh/v3/syntax"
|
"mvdan.cc/sh/v3/syntax"
|
||||||
|
|
||||||
|
"plemya-x.ru/alr/internal/shutils/handlers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OSRelease contains information from an os-release file
|
// OSRelease contains information from an os-release file
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
package gen
|
package gen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Определяем переменную funcs типа template.FuncMap, которая будет использоваться для
|
// Определяем переменную funcs типа template.FuncMap, которая будет использоваться для
|
||||||
// предоставления пользовательских функций в шаблонах
|
// предоставления пользовательских функций в шаблонах
|
||||||
var funcs = template.FuncMap{
|
var funcs = template.FuncMap{
|
||||||
// Функция "tolower" использует strings.ToLower
|
// Функция "tolower" использует strings.ToLower
|
||||||
// для преобразования строки в нижний регистр
|
// для преобразования строки в нижний регистр
|
||||||
"tolower": strings.ToLower,
|
"tolower": strings.ToLower,
|
||||||
|
|
||||||
// Функция "firstchar" — это лямбда-функция, которая берет строку
|
// Функция "firstchar" — это лямбда-функция, которая берет строку
|
||||||
// и возвращает её первый символ
|
// и возвращает её первый символ
|
||||||
"firstchar": func(s string) string {
|
"firstchar": func(s string) string {
|
||||||
return s[:1]
|
return s[:1]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
121
pkg/gen/pip.go
121
pkg/gen/pip.go
@@ -1,98 +1,99 @@
|
|||||||
package gen
|
package gen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed" // Пакет для встраивания содержимого файлов в бинарники Go, использовав откладку //go:embed
|
_ "embed" // Пакет для встраивания содержимого файлов в бинарники Go, использовав откладку //go:embed
|
||||||
"encoding/json" // Пакет для работы с JSON: декодирование и кодирование
|
"encoding/json" // Пакет для работы с JSON: декодирование и кодирование
|
||||||
"errors" // Пакет для создания и обработки ошибок
|
"errors" // Пакет для создания и обработки ошибок
|
||||||
"fmt" // Пакет для форматированного ввода и вывода
|
"fmt" // Пакет для форматированного ввода и вывода
|
||||||
"io" // Пакет для интерфейсов ввода и вывода
|
"io" // Пакет для интерфейсов ввода и вывода
|
||||||
"net/http" // Пакет для HTTP-клиентов и серверов
|
"net/http" // Пакет для HTTP-клиентов и серверов
|
||||||
"text/template" // Пакет для обработки текстовых шаблонов
|
"text/template" // Пакет для обработки текстовых шаблонов
|
||||||
)
|
)
|
||||||
|
|
||||||
// Используем директиву //go:embed для встраивания содержимого файла шаблона в строку pipTmpl
|
// Используем директиву //go:embed для встраивания содержимого файла шаблона в строку pipTmpl
|
||||||
// Встраивание файла tmpls/pip.tmpl.sh
|
// Встраивание файла tmpls/pip.tmpl.sh
|
||||||
|
//
|
||||||
//go:embed tmpls/pip.tmpl.sh
|
//go:embed tmpls/pip.tmpl.sh
|
||||||
var pipTmpl string
|
var pipTmpl string
|
||||||
|
|
||||||
// PipOptions содержит параметры, которые будут переданы в шаблон
|
// PipOptions содержит параметры, которые будут переданы в шаблон
|
||||||
type PipOptions struct {
|
type PipOptions struct {
|
||||||
Name string // Имя пакета
|
Name string // Имя пакета
|
||||||
Version string // Версия пакета
|
Version string // Версия пакета
|
||||||
Description string // Описание пакета
|
Description string // Описание пакета
|
||||||
}
|
}
|
||||||
|
|
||||||
// pypiAPIResponse представляет структуру ответа от API PyPI
|
// pypiAPIResponse представляет структуру ответа от API PyPI
|
||||||
type pypiAPIResponse struct {
|
type pypiAPIResponse struct {
|
||||||
Info pypiInfo `json:"info"` // Информация о пакете
|
Info pypiInfo `json:"info"` // Информация о пакете
|
||||||
URLs []pypiURL `json:"urls"` // Список URL-адресов для загрузки пакета
|
URLs []pypiURL `json:"urls"` // Список URL-адресов для загрузки пакета
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод SourceURL ищет и возвращает URL исходного distribution для пакета, если он существует
|
// Метод SourceURL ищет и возвращает URL исходного distribution для пакета, если он существует
|
||||||
func (res pypiAPIResponse) SourceURL() (pypiURL, error) {
|
func (res pypiAPIResponse) SourceURL() (pypiURL, error) {
|
||||||
for _, url := range res.URLs {
|
for _, url := range res.URLs {
|
||||||
if url.PackageType == "sdist" {
|
if url.PackageType == "sdist" {
|
||||||
return url, nil
|
return url, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pypiURL{}, errors.New("package doesn't have a source distribution")
|
return pypiURL{}, errors.New("package doesn't have a source distribution")
|
||||||
}
|
}
|
||||||
|
|
||||||
// pypiInfo содержит основную информацию о пакете, такую как имя, версия и пр.
|
// pypiInfo содержит основную информацию о пакете, такую как имя, версия и пр.
|
||||||
type pypiInfo struct {
|
type pypiInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Summary string `json:"summary"`
|
Summary string `json:"summary"`
|
||||||
Homepage string `json:"home_page"`
|
Homepage string `json:"home_page"`
|
||||||
License string `json:"license"`
|
License string `json:"license"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// pypiURL представляет информацию об одном из доступных для загрузки URL
|
// pypiURL представляет информацию об одном из доступных для загрузки URL
|
||||||
type pypiURL struct {
|
type pypiURL struct {
|
||||||
Digests map[string]string `json:"digests"` // Контрольные суммы для файлов
|
Digests map[string]string `json:"digests"` // Контрольные суммы для файлов
|
||||||
Filename string `json:"filename"` // Имя файла
|
Filename string `json:"filename"` // Имя файла
|
||||||
PackageType string `json:"packagetype"` // Тип пакета (например sdist)
|
PackageType string `json:"packagetype"` // Тип пакета (например sdist)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция Pip загружает информацию о пакете из PyPI и использует шаблон для вывода информации
|
// Функция Pip загружает информацию о пакете из PyPI и использует шаблон для вывода информации
|
||||||
func Pip(w io.Writer, opts PipOptions) error {
|
func Pip(w io.Writer, opts PipOptions) error {
|
||||||
// Создаем новый шаблон с добавлением функций из FuncMap
|
// Создаем новый шаблон с добавлением функций из FuncMap
|
||||||
tmpl, err := template.New("pip").
|
tmpl, err := template.New("pip").
|
||||||
Funcs(funcs).
|
Funcs(funcs).
|
||||||
Parse(pipTmpl)
|
Parse(pipTmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Формируем URL для запроса к PyPI на основании имени и версии пакета
|
// Формируем URL для запроса к PyPI на основании имени и версии пакета
|
||||||
url := fmt.Sprintf(
|
url := fmt.Sprintf(
|
||||||
"https://pypi.org/pypi/%s/%s/json",
|
"https://pypi.org/pypi/%s/%s/json",
|
||||||
opts.Name,
|
opts.Name,
|
||||||
opts.Version,
|
opts.Version,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Выполняем HTTP GET запрос к PyPI
|
// Выполняем HTTP GET запрос к PyPI
|
||||||
res, err := http.Get(url)
|
res, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer res.Body.Close() // Закрываем тело ответа после завершения работы
|
defer res.Body.Close() // Закрываем тело ответа после завершения работы
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
return fmt.Errorf("pypi: %s", res.Status)
|
return fmt.Errorf("pypi: %s", res.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Раскодируем ответ JSON от PyPI в структуру pypiAPIResponse
|
// Раскодируем ответ JSON от PyPI в структуру pypiAPIResponse
|
||||||
var resp pypiAPIResponse
|
var resp pypiAPIResponse
|
||||||
err = json.NewDecoder(res.Body).Decode(&resp)
|
err = json.NewDecoder(res.Body).Decode(&resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если в opts указано описание, используем его вместо описания из PyPI
|
// Если в opts указано описание, используем его вместо описания из PyPI
|
||||||
if opts.Description != "" {
|
if opts.Description != "" {
|
||||||
resp.Info.Summary = opts.Description
|
resp.Info.Summary = opts.Description
|
||||||
}
|
}
|
||||||
|
|
||||||
// Выполняем шаблон с использованием данных из resp и записываем результат в w
|
// Выполняем шаблон с использованием данных из resp и записываем результат в w
|
||||||
return tmpl.Execute(w, resp)
|
return tmpl.Execute(w, resp)
|
||||||
}
|
}
|
||||||
|
@@ -107,6 +107,7 @@ func (a *APTRpm) UpgradeAll(opts *Opts) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *APTRpm) ListInstalled(opts *Opts) (map[string]string, error) {
|
func (y *APTRpm) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
@@ -19,154 +19,154 @@
|
|||||||
package manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNF представляет менеджер пакетов DNF
|
// DNF представляет менеджер пакетов DNF
|
||||||
type DNF struct {
|
type DNF struct {
|
||||||
rootCmd string // rootCmd хранит команду, используемую для выполнения команд с правами root
|
rootCmd string // rootCmd хранит команду, используемую для выполнения команд с правами root
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists проверяет, доступен ли DNF в системе, возвращает true если да
|
// Exists проверяет, доступен ли DNF в системе, возвращает true если да
|
||||||
func (*DNF) Exists() bool {
|
func (*DNF) Exists() bool {
|
||||||
_, err := exec.LookPath("dnf")
|
_, err := exec.LookPath("dnf")
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name возвращает имя менеджера пакетов, в данном случае "dnf"
|
// Name возвращает имя менеджера пакетов, в данном случае "dnf"
|
||||||
func (*DNF) Name() string {
|
func (*DNF) Name() string {
|
||||||
return "dnf"
|
return "dnf"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format возвращает формат пакетов "rpm", используемый DNF
|
// Format возвращает формат пакетов "rpm", используемый DNF
|
||||||
func (*DNF) Format() string {
|
func (*DNF) Format() string {
|
||||||
return "rpm"
|
return "rpm"
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRootCmd устанавливает команду, используемую для выполнения операций с правами root
|
// SetRootCmd устанавливает команду, используемую для выполнения операций с правами root
|
||||||
func (d *DNF) SetRootCmd(s string) {
|
func (d *DNF) SetRootCmd(s string) {
|
||||||
d.rootCmd = s
|
d.rootCmd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync выполняет upgrade всех установленных пакетов, обновляя их до более новых версий
|
// Sync выполняет upgrade всех установленных пакетов, обновляя их до более новых версий
|
||||||
func (d *DNF) Sync(opts *Opts) error {
|
func (d *DNF) Sync(opts *Opts) error {
|
||||||
opts = ensureOpts(opts) // Гарантирует, что opts не равен nil и содержит допустимые значения
|
opts = ensureOpts(opts) // Гарантирует, что opts не равен nil и содержит допустимые значения
|
||||||
cmd := d.getCmd(opts, "dnf", "upgrade")
|
cmd := d.getCmd(opts, "dnf", "upgrade")
|
||||||
setCmdEnv(cmd) // Устанавливает переменные окружения для команды
|
setCmdEnv(cmd) // Устанавливает переменные окружения для команды
|
||||||
err := cmd.Run() // Выполняет команду
|
err := cmd.Run() // Выполняет команду
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("dnf: sync: %w", err)
|
return fmt.Errorf("dnf: sync: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install устанавливает указанные пакеты с помощью DNF
|
// Install устанавливает указанные пакеты с помощью DNF
|
||||||
func (d *DNF) Install(opts *Opts, pkgs ...string) error {
|
func (d *DNF) Install(opts *Opts, pkgs ...string) error {
|
||||||
opts = ensureOpts(opts)
|
opts = ensureOpts(opts)
|
||||||
cmd := d.getCmd(opts, "dnf", "install", "--allowerasing")
|
cmd := d.getCmd(opts, "dnf", "install", "--allowerasing")
|
||||||
cmd.Args = append(cmd.Args, pkgs...) // Добавляем названия пакетов к команде
|
cmd.Args = append(cmd.Args, pkgs...) // Добавляем названия пакетов к команде
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("dnf: install: %w", err)
|
return fmt.Errorf("dnf: install: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallLocal расширяет метод Install для установки пакетов, расположенных локально
|
// InstallLocal расширяет метод Install для установки пакетов, расположенных локально
|
||||||
func (d *DNF) InstallLocal(opts *Opts, pkgs ...string) error {
|
func (d *DNF) InstallLocal(opts *Opts, pkgs ...string) error {
|
||||||
opts = ensureOpts(opts)
|
opts = ensureOpts(opts)
|
||||||
return d.Install(opts, pkgs...)
|
return d.Install(opts, pkgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove удаляет указанные пакеты с помощью DNF
|
// Remove удаляет указанные пакеты с помощью DNF
|
||||||
func (d *DNF) Remove(opts *Opts, pkgs ...string) error {
|
func (d *DNF) Remove(opts *Opts, pkgs ...string) error {
|
||||||
opts = ensureOpts(opts)
|
opts = ensureOpts(opts)
|
||||||
cmd := d.getCmd(opts, "dnf", "remove")
|
cmd := d.getCmd(opts, "dnf", "remove")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("dnf: remove: %w", err)
|
return fmt.Errorf("dnf: remove: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upgrade обновляет указанные пакеты до более новых версий
|
// Upgrade обновляет указанные пакеты до более новых версий
|
||||||
func (d *DNF) Upgrade(opts *Opts, pkgs ...string) error {
|
func (d *DNF) Upgrade(opts *Opts, pkgs ...string) error {
|
||||||
opts = ensureOpts(opts)
|
opts = ensureOpts(opts)
|
||||||
cmd := d.getCmd(opts, "dnf", "upgrade")
|
cmd := d.getCmd(opts, "dnf", "upgrade")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("dnf: upgrade: %w", err)
|
return fmt.Errorf("dnf: upgrade: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpgradeAll обновляет все установленные пакеты
|
// UpgradeAll обновляет все установленные пакеты
|
||||||
func (d *DNF) UpgradeAll(opts *Opts) error {
|
func (d *DNF) UpgradeAll(opts *Opts) error {
|
||||||
opts = ensureOpts(opts)
|
opts = ensureOpts(opts)
|
||||||
cmd := d.getCmd(opts, "dnf", "upgrade")
|
cmd := d.getCmd(opts, "dnf", "upgrade")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("dnf: upgradeall: %w", err)
|
return fmt.Errorf("dnf: upgradeall: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListInstalled возвращает список установленных пакетов и их версий
|
// ListInstalled возвращает список установленных пакетов и их версий
|
||||||
func (d *DNF) ListInstalled(opts *Opts) (map[string]string, error) {
|
func (d *DNF) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner := bufio.NewScanner(stdout)
|
scanner := bufio.NewScanner(stdout)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
name, version, ok := strings.Cut(scanner.Text(), "\u200b")
|
name, version, ok := strings.Cut(scanner.Text(), "\u200b")
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
version = strings.TrimPrefix(version, "0:")
|
version = strings.TrimPrefix(version, "0:")
|
||||||
out[name] = version
|
out[name] = version
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scanner.Err()
|
err = scanner.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCmd создает и возвращает команду exec.Cmd для менеджера пакетов DNF
|
// getCmd создает и возвращает команду exec.Cmd для менеджера пакетов DNF
|
||||||
func (d *DNF) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
func (d *DNF) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
if opts.AsRoot {
|
if opts.AsRoot {
|
||||||
cmd = exec.Command(getRootCmd(d.rootCmd), mgrCmd)
|
cmd = exec.Command(getRootCmd(d.rootCmd), mgrCmd)
|
||||||
cmd.Args = append(cmd.Args, opts.Args...)
|
cmd.Args = append(cmd.Args, opts.Args...)
|
||||||
cmd.Args = append(cmd.Args, args...)
|
cmd.Args = append(cmd.Args, args...)
|
||||||
} else {
|
} else {
|
||||||
cmd = exec.Command(mgrCmd, args...)
|
cmd = exec.Command(mgrCmd, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.NoConfirm {
|
if opts.NoConfirm {
|
||||||
cmd.Args = append(cmd.Args, "-y") // Добавляет параметр автоматического подтверждения (-y)
|
cmd.Args = append(cmd.Args, "-y") // Добавляет параметр автоматического подтверждения (-y)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,10 @@ import (
|
|||||||
"github.com/go-git/go-git/v5/plumbing/format/diff"
|
"github.com/go-git/go-git/v5/plumbing/format/diff"
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
"go.elara.ws/vercmp"
|
"go.elara.ws/vercmp"
|
||||||
|
"mvdan.cc/sh/v3/expand"
|
||||||
|
"mvdan.cc/sh/v3/interp"
|
||||||
|
"mvdan.cc/sh/v3/syntax"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/internal/shutils/decoder"
|
"plemya-x.ru/alr/internal/shutils/decoder"
|
||||||
@@ -42,9 +46,6 @@ import (
|
|||||||
"plemya-x.ru/alr/internal/types"
|
"plemya-x.ru/alr/internal/types"
|
||||||
"plemya-x.ru/alr/pkg/distro"
|
"plemya-x.ru/alr/pkg/distro"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
"mvdan.cc/sh/v3/expand"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
"mvdan.cc/sh/v3/syntax"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pull pulls the provided repositories. If a repo doesn't exist, it will be cloned
|
// Pull pulls the provided repositories. If a repo doesn't exist, it will be cloned
|
||||||
|
3
repo.go
3
repo.go
@@ -24,12 +24,13 @@ import (
|
|||||||
|
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/internal/types"
|
"plemya-x.ru/alr/internal/types"
|
||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
"plemya-x.ru/alr/pkg/repos"
|
"plemya-x.ru/alr/pkg/repos"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var addrepoCmd = &cli.Command{
|
var addrepoCmd = &cli.Command{
|
||||||
|
@@ -23,6 +23,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"go.elara.ws/vercmp"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
"plemya-x.ru/alr/internal/config"
|
"plemya-x.ru/alr/internal/config"
|
||||||
"plemya-x.ru/alr/internal/db"
|
"plemya-x.ru/alr/internal/db"
|
||||||
"plemya-x.ru/alr/internal/types"
|
"plemya-x.ru/alr/internal/types"
|
||||||
@@ -31,9 +35,6 @@ import (
|
|||||||
"plemya-x.ru/alr/pkg/loggerctx"
|
"plemya-x.ru/alr/pkg/loggerctx"
|
||||||
"plemya-x.ru/alr/pkg/manager"
|
"plemya-x.ru/alr/pkg/manager"
|
||||||
"plemya-x.ru/alr/pkg/repos"
|
"plemya-x.ru/alr/pkg/repos"
|
||||||
"go.elara.ws/vercmp"
|
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var upgradeCmd = &cli.Command{
|
var upgradeCmd = &cli.Command{
|
||||||
|
Reference in New Issue
Block a user