diff --git a/assets/coverage-badge.svg b/assets/coverage-badge.svg
index ffdf7ae..e1e8356 100644
--- a/assets/coverage-badge.svg
+++ b/assets/coverage-badge.svg
@@ -11,7 +11,7 @@
coverage
coverage
- 19.4%
- 19.4%
+ 18.8%
+ 18.8%
diff --git a/generators/plugin-generator/main.go b/generators/plugin-generator/main.go
new file mode 100644
index 0000000..91b7a0c
--- /dev/null
+++ b/generators/plugin-generator/main.go
@@ -0,0 +1,390 @@
+// 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 .
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ "strings"
+ "text/template"
+
+ "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 .
+
+
+`)
+
+ 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 {
+ 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"
+ default:
+ 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)
+ }
+}
diff --git a/internal.go b/internal.go
index bbea3db..987529c 100644
--- a/internal.go
+++ b/internal.go
@@ -125,7 +125,7 @@ func InternalInstallCmd() *cli.Command {
plugin.Serve(&plugin.ServeConfig{
HandshakeConfig: build.HandshakeConfig,
Plugins: map[string]plugin.Plugin{
- "installer": &build.InstallerPlugin{
+ "installer": &build.InstallerExecutorPlugin{
Impl: build.NewInstaller(
manager.Detect(),
),
diff --git a/internal/build/build.go b/internal/build/build.go
index ae3b732..8b33905 100644
--- a/internal/build/build.go
+++ b/internal/build/build.go
@@ -176,25 +176,6 @@ type ScriptResolverExecutor interface {
ResolveScript(ctx context.Context, pkg *alrsh.Package) *ScriptInfo
}
-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 CacheExecutor interface {
CheckForBuiltPackage(ctx context.Context, input *BuildInput, vars *alrsh.Package) (string, bool, error)
}
@@ -211,14 +192,6 @@ type CheckerExecutor interface {
) (bool, error)
}
-type InstallerExecutor interface {
- InstallLocal(paths []string, opts *manager.Opts) error
- Install(pkgs []string, opts *manager.Opts) error
- Remove(pkgs []string, opts *manager.Opts) error
-
- RemoveAlreadyInstalled(pkgs []string) ([]string, error)
-}
-
type SourcesInput struct {
Sources []string
Checksums []string
@@ -499,6 +472,7 @@ func (b *Builder) removeBuildDeps(ctx context.Context, input interface {
if remove {
err = b.installerExecutor.Remove(
+ ctx,
deps,
&manager.Opts{
NoConfirm: !input.BuildOpts().Interactive,
@@ -545,6 +519,7 @@ func (b *Builder) InstallALRPackages(
}
err = b.installerExecutor.InstallLocal(
+ ctx,
GetBuiltPaths(res),
&manager.Opts{
NoConfirm: !input.BuildOpts().Interactive,
@@ -645,7 +620,7 @@ func (i *Builder) installBuildDeps(
var deps []string
var err error
if len(pkgs) > 0 {
- deps, err = i.installerExecutor.RemoveAlreadyInstalled(pkgs)
+ deps, err = i.installerExecutor.RemoveAlreadyInstalled(ctx, pkgs)
if err != nil {
return nil, nil, err
}
@@ -668,7 +643,7 @@ func (i *Builder) installOptDeps(
pkgs []string,
) ([]*BuiltDep, error) {
var builtDeps []*BuiltDep
- optDeps, err := i.installerExecutor.RemoveAlreadyInstalled(pkgs)
+ optDeps, err := i.installerExecutor.RemoveAlreadyInstalled(ctx, pkgs)
if err != nil {
return nil, err
}
@@ -710,7 +685,7 @@ func (i *Builder) InstallPkgs(
}
if len(builtDeps) > 0 {
- err = i.installerExecutor.InstallLocal(GetBuiltPaths(builtDeps), &manager.Opts{
+ err = i.installerExecutor.InstallLocal(ctx, GetBuiltPaths(builtDeps), &manager.Opts{
NoConfirm: !input.BuildOpts().Interactive,
})
if err != nil {
@@ -719,7 +694,7 @@ func (i *Builder) InstallPkgs(
}
if len(repoDeps) > 0 {
- err = i.installerExecutor.Install(repoDeps, &manager.Opts{
+ err = i.installerExecutor.Install(ctx, repoDeps, &manager.Opts{
NoConfirm: !input.BuildOpts().Interactive,
})
if err != nil {
diff --git a/internal/build/installer.go b/internal/build/installer.go
index eba512e..80973d5 100644
--- a/internal/build/installer.go
+++ b/internal/build/installer.go
@@ -17,6 +17,8 @@
package build
import (
+ "context"
+
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
)
@@ -28,19 +30,19 @@ func NewInstaller(mgr manager.Manager) *Installer {
type Installer struct{ mgr manager.Manager }
-func (i *Installer) InstallLocal(paths []string, opts *manager.Opts) error {
+func (i *Installer) InstallLocal(ctx context.Context, paths []string, opts *manager.Opts) error {
return i.mgr.InstallLocal(opts, paths...)
}
-func (i *Installer) Install(pkgs []string, opts *manager.Opts) error {
+func (i *Installer) Install(ctx context.Context, pkgs []string, opts *manager.Opts) error {
return i.mgr.Install(opts, pkgs...)
}
-func (i *Installer) Remove(pkgs []string, opts *manager.Opts) error {
+func (i *Installer) Remove(ctx context.Context, pkgs []string, opts *manager.Opts) error {
return i.mgr.Remove(opts, pkgs...)
}
-func (i *Installer) RemoveAlreadyInstalled(pkgs []string) ([]string, error) {
+func (i *Installer) RemoveAlreadyInstalled(ctx context.Context, pkgs []string) ([]string, error) {
filteredPackages := []string{}
for _, dep := range pkgs {
diff --git a/internal/build/plugins.go b/internal/build/plugins.go
new file mode 100644
index 0000000..62a605a
--- /dev/null
+++ b/internal/build/plugins.go
@@ -0,0 +1,125 @@
+// 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 .
+
+package build
+
+import (
+ "fmt"
+ "log/slog"
+ "os"
+ "os/exec"
+ "strings"
+ "sync"
+
+ "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{},
+}
+
+var HandshakeConfig = plugin.HandshakeConfig{
+ ProtocolVersion: 1,
+ MagicCookieKey: "ALR_PLUGIN",
+ MagicCookieValue: "-",
+}
+
+func setCommonCmdEnv(cmd *exec.Cmd) {
+ cmd.Env = []string{
+ "HOME=/var/cache/alr",
+ "LOGNAME=alr",
+ "USER=alr",
+ "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 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 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{
+ Group: "alr",
+ },
+ 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
+}
diff --git a/internal/build/plugins_executors.go b/internal/build/plugins_executors.go
new file mode 100644
index 0000000..cd2dfa5
--- /dev/null
+++ b/internal/build/plugins_executors.go
@@ -0,0 +1,55 @@
+// 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 .
+
+package build
+
+import (
+ "context"
+
+ "gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
+ "gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
+)
+
+//go:generate go run ../../generators/plugin-generator InstallerExecutor ScriptExecutor
+
+// 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)
+}
diff --git a/internal/build/plugins_executors_gen.go b/internal/build/plugins_executors_gen.go
new file mode 100644
index 0000000..9469262
--- /dev/null
+++ b/internal/build/plugins_executors_gen.go
@@ -0,0 +1,318 @@
+// 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 .
+
+package build
+
+import (
+ "net/rpc"
+
+ "context"
+ "gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
+ "gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
+ "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 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
+}
diff --git a/internal/build/safe_common.go b/internal/build/safe_common.go
deleted file mode 100644
index 33cb66f..0000000
--- a/internal/build/safe_common.go
+++ /dev/null
@@ -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 .
-
-package build
-
-import (
- "os"
- "os/exec"
- "strings"
-)
-
-func setCommonCmdEnv(cmd *exec.Cmd) {
- cmd.Env = []string{
- "HOME=/var/cache/alr",
- "LOGNAME=alr",
- "USER=alr",
- "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)
- }
- }
-}
diff --git a/internal/build/safe_installer.go b/internal/build/safe_installer.go
deleted file mode 100644
index e7c8447..0000000
--- a/internal/build/safe_installer.go
+++ /dev/null
@@ -1,161 +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 .
-
-package build
-
-import (
- "fmt"
- "log/slog"
- "net/rpc"
- "os"
- "os/exec"
- "sync"
- "syscall"
-
- "github.com/hashicorp/go-plugin"
-
- "gitea.plemya-x.ru/Plemya-x/ALR/internal/logger"
- "gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
-)
-
-type InstallerPlugin struct {
- Impl InstallerExecutor
-}
-
-type InstallerRPC struct {
- client *rpc.Client
-}
-
-type InstallerRPCServer struct {
- Impl InstallerExecutor
-}
-
-type InstallArgs struct {
- PackagesOrPaths []string
- Opts *manager.Opts
-}
-
-func (r *InstallerRPC) InstallLocal(paths []string, opts *manager.Opts) error {
- return r.client.Call("Plugin.InstallLocal", &InstallArgs{
- PackagesOrPaths: paths,
- Opts: opts,
- }, nil)
-}
-
-func (s *InstallerRPCServer) InstallLocal(args *InstallArgs, reply *struct{}) error {
- return s.Impl.InstallLocal(args.PackagesOrPaths, args.Opts)
-}
-
-func (r *InstallerRPC) Install(pkgs []string, opts *manager.Opts) error {
- return r.client.Call("Plugin.Install", &InstallArgs{
- PackagesOrPaths: pkgs,
- Opts: opts,
- }, nil)
-}
-
-func (s *InstallerRPCServer) Install(args *InstallArgs, reply *struct{}) error {
- return s.Impl.Install(args.PackagesOrPaths, args.Opts)
-}
-
-func (r *InstallerRPC) Remove(pkgs []string, opts *manager.Opts) error {
- return r.client.Call("Plugin.Remove", &InstallArgs{
- PackagesOrPaths: pkgs,
- Opts: opts,
- }, nil)
-}
-
-func (s *InstallerRPCServer) Remove(args *InstallArgs, reply *struct{}) error {
- return s.Impl.Remove(args.PackagesOrPaths, args.Opts)
-}
-
-func (r *InstallerRPC) RemoveAlreadyInstalled(paths []string) ([]string, error) {
- var val []string
- err := r.client.Call("Plugin.RemoveAlreadyInstalled", paths, &val)
- return val, err
-}
-
-func (s *InstallerRPCServer) RemoveAlreadyInstalled(pkgs []string, res *[]string) error {
- vars, err := s.Impl.RemoveAlreadyInstalled(pkgs)
- if err != nil {
- return err
- }
- *res = vars
- return nil
-}
-
-func (p *InstallerPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
- return &InstallerRPC{client: c}, nil
-}
-
-func (p *InstallerPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
- return &InstallerRPCServer{Impl: p.Impl}, nil
-}
-
-func GetSafeInstaller() (InstallerExecutor, func(), error) {
- var err error
-
- executable, err := os.Executable()
- if err != nil {
- return nil, nil, err
- }
- cmd := exec.Command(executable, "_internal-installer")
- setCommonCmdEnv(cmd)
-
- slog.Debug("safe installer setup", "uid", syscall.Getuid(), "gid", syscall.Getgid())
-
- client := plugin.NewClient(&plugin.ClientConfig{
- HandshakeConfig: HandshakeConfig,
- Plugins: pluginMap,
- Cmd: cmd,
- Logger: logger.GetHCLoggerAdapter(),
- SkipHostEnv: true,
- UnixSocketConfig: &plugin.UnixSocketConfig{
- Group: "alr",
- },
- SyncStderr: os.Stderr,
- })
- rpcClient, err := client.Client()
- if err != nil {
- return nil, nil, err
- }
-
- var cleanupOnce sync.Once
- cleanup := func() {
- cleanupOnce.Do(func() {
- client.Kill()
- })
- }
-
- defer func() {
- if err != nil {
- slog.Debug("close installer")
- cleanup()
- }
- }()
-
- raw, err := rpcClient.Dispense("installer")
- if err != nil {
- return nil, nil, err
- }
-
- executor, ok := raw.(InstallerExecutor)
- if !ok {
- err = fmt.Errorf("dispensed object is not a ScriptExecutor (got %T)", raw)
- return nil, nil, err
- }
-
- return executor, cleanup, nil
-}
diff --git a/internal/build/safe_script_executor.go b/internal/build/safe_script_executor.go
deleted file mode 100644
index 3342e7b..0000000
--- a/internal/build/safe_script_executor.go
+++ /dev/null
@@ -1,273 +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 .
-
-package build
-
-import (
- "context"
- "fmt"
- "log/slog"
- "net/rpc"
- "os"
- "os/exec"
- "sync"
-
- "github.com/hashicorp/go-plugin"
-
- "gitea.plemya-x.ru/Plemya-x/ALR/internal/logger"
- "gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh"
-)
-
-var HandshakeConfig = plugin.HandshakeConfig{
- ProtocolVersion: 1,
- MagicCookieKey: "ALR_PLUGIN",
- MagicCookieValue: "-",
-}
-
-type ScriptExecutorPlugin struct {
- Impl ScriptExecutor
-}
-
-type ScriptExecutorRPCServer struct {
- Impl ScriptExecutor
-}
-
-// =============================
-//
-// ReadScript
-//
-
-func (s *ScriptExecutorRPC) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) {
- var resp *alrsh.ScriptFile
- err := s.client.Call("Plugin.ReadScript", scriptPath, &resp)
- return resp, err
-}
-
-func (s *ScriptExecutorRPCServer) ReadScript(scriptPath string, resp *alrsh.ScriptFile) error {
- file, err := s.Impl.ReadScript(context.Background(), scriptPath)
- if err != nil {
- return err
- }
- *resp = *file
- return nil
-}
-
-// =============================
-//
-// ExecuteFirstPass
-//
-
-type ExecuteFirstPassArgs struct {
- Input *BuildInput
- Sf *alrsh.ScriptFile
-}
-
-type ExecuteFirstPassResp struct {
- BasePkg string
- VarsOfPackages []*alrsh.Package
-}
-
-func (s *ScriptExecutorRPC) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) {
- var resp *ExecuteFirstPassResp
- err := s.client.Call("Plugin.ExecuteFirstPass", &ExecuteFirstPassArgs{
- Input: input,
- Sf: sf,
- }, &resp)
- if err != nil {
- return "", nil, err
- }
- return resp.BasePkg, resp.VarsOfPackages, nil
-}
-
-func (s *ScriptExecutorRPCServer) ExecuteFirstPass(args *ExecuteFirstPassArgs, resp *ExecuteFirstPassResp) error {
- basePkg, varsOfPackages, err := s.Impl.ExecuteFirstPass(context.Background(), args.Input, args.Sf)
- if err != nil {
- return err
- }
- *resp = ExecuteFirstPassResp{
- BasePkg: basePkg,
- VarsOfPackages: varsOfPackages,
- }
- return nil
-}
-
-// =============================
-//
-// PrepareDirs
-//
-
-type PrepareDirsArgs struct {
- Input *BuildInput
- BasePkg string
-}
-
-func (s *ScriptExecutorRPC) PrepareDirs(
- ctx context.Context,
- input *BuildInput,
- basePkg string,
-) error {
- err := s.client.Call("Plugin.PrepareDirs", &PrepareDirsArgs{
- Input: input,
- BasePkg: basePkg,
- }, nil)
- if err != nil {
- return err
- }
- return err
-}
-
-func (s *ScriptExecutorRPCServer) PrepareDirs(args *PrepareDirsArgs, reply *struct{}) error {
- err := s.Impl.PrepareDirs(
- context.Background(),
- args.Input,
- args.BasePkg,
- )
- if err != nil {
- return err
- }
- return err
-}
-
-// =============================
-//
-// ExecuteSecondPass
-//
-
-type ExecuteSecondPassArgs struct {
- Input *BuildInput
- Sf *alrsh.ScriptFile
- VarsOfPackages []*alrsh.Package
- RepoDeps []string
- BuiltDeps []*BuiltDep
- BasePkg string
-}
-
-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 []*BuiltDep
- err := s.client.Call("Plugin.ExecuteSecondPass", &ExecuteSecondPassArgs{
- Input: input,
- Sf: sf,
- VarsOfPackages: varsOfPackages,
- RepoDeps: repoDeps,
- BuiltDeps: builtDeps,
- BasePkg: basePkg,
- }, &resp)
- if err != nil {
- return nil, err
- }
- return resp, nil
-}
-
-func (s *ScriptExecutorRPCServer) ExecuteSecondPass(args *ExecuteSecondPassArgs, resp *[]*BuiltDep) error {
- res, err := s.Impl.ExecuteSecondPass(
- context.Background(),
- args.Input,
- args.Sf,
- args.VarsOfPackages,
- args.RepoDeps,
- args.BuiltDeps,
- args.BasePkg,
- )
- if err != nil {
- return err
- }
- *resp = res
- return err
-}
-
-//
-// ============================
-//
-
-func (p *ScriptExecutorPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
- return &ScriptExecutorRPCServer{Impl: p.Impl}, nil
-}
-
-func (p *ScriptExecutorPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
- return &ScriptExecutorRPC{client: c}, nil
-}
-
-type ScriptExecutorRPC struct {
- client *rpc.Client
-}
-
-var pluginMap = map[string]plugin.Plugin{
- "script-executor": &ScriptExecutorPlugin{},
- "installer": &InstallerPlugin{},
-}
-
-func GetSafeScriptExecutor() (ScriptExecutor, func(), error) {
- var err error
-
- executable, err := os.Executable()
- if err != nil {
- return nil, nil, err
- }
-
- cmd := exec.Command(executable, "_internal-safe-script-executor")
- setCommonCmdEnv(cmd)
-
- client := plugin.NewClient(&plugin.ClientConfig{
- HandshakeConfig: HandshakeConfig,
- Plugins: pluginMap,
- Cmd: cmd,
- Logger: logger.GetHCLoggerAdapter(),
- SkipHostEnv: true,
- UnixSocketConfig: &plugin.UnixSocketConfig{
- Group: "alr",
- },
- SyncStderr: os.Stderr,
- })
- rpcClient, err := client.Client()
- if err != nil {
- return nil, nil, err
- }
-
- var cleanupOnce sync.Once
- cleanup := func() {
- cleanupOnce.Do(func() {
- client.Kill()
- })
- }
-
- defer func() {
- if err != nil {
- slog.Debug("close script-executor")
- cleanup()
- }
- }()
-
- raw, err := rpcClient.Dispense("script-executor")
- if err != nil {
- return nil, nil, err
- }
-
- executor, ok := raw.(ScriptExecutor)
- if !ok {
- err = fmt.Errorf("dispensed object is not a ScriptExecutor (got %T)", raw)
- return nil, nil, err
- }
-
- return executor, cleanup, nil
-}
diff --git a/internal/translations/default.pot b/internal/translations/default.pot
index 354adf8..2d098e1 100644
--- a/internal/translations/default.pot
+++ b/internal/translations/default.pot
@@ -218,23 +218,23 @@ msgstr ""
msgid "Error removing packages"
msgstr ""
-#: internal/build/build.go:378
+#: internal/build/build.go:351
msgid "Building package"
msgstr ""
-#: internal/build/build.go:407
+#: internal/build/build.go:380
msgid "The checksums array must be the same length as sources"
msgstr ""
-#: internal/build/build.go:449
+#: internal/build/build.go:422
msgid "Downloading sources"
msgstr ""
-#: internal/build/build.go:495
+#: internal/build/build.go:468
msgid "Would you like to remove the build dependencies?"
msgstr ""
-#: internal/build/build.go:571
+#: internal/build/build.go:546
msgid "Installing dependencies"
msgstr ""
diff --git a/internal/translations/po/ru/default.po b/internal/translations/po/ru/default.po
index f2c9932..2c054f1 100644
--- a/internal/translations/po/ru/default.po
+++ b/internal/translations/po/ru/default.po
@@ -225,23 +225,23 @@ msgstr "Для команды remove ожидался хотя бы 1 аргум
msgid "Error removing packages"
msgstr "Ошибка при удалении пакетов"
-#: internal/build/build.go:378
+#: internal/build/build.go:351
msgid "Building package"
msgstr "Сборка пакета"
-#: internal/build/build.go:407
+#: internal/build/build.go:380
msgid "The checksums array must be the same length as sources"
msgstr "Массив контрольных сумм должен быть той же длины, что и источники"
-#: internal/build/build.go:449
+#: internal/build/build.go:422
msgid "Downloading sources"
msgstr "Скачивание источников"
-#: internal/build/build.go:495
+#: internal/build/build.go:468
msgid "Would you like to remove the build dependencies?"
msgstr "Хотели бы вы удалить зависимости сборки?"
-#: internal/build/build.go:571
+#: internal/build/build.go:546
msgid "Installing dependencies"
msgstr "Установка зависимостей"