mirror of
https://gitlab.com/TECHNOFAB/nixtest.git
synced 2025-12-12 02:00:18 +01:00
110 lines
2.8 KiB
Go
110 lines
2.8 KiB
Go
package nix
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
apperrors "gitlab.com/technofab/nixtest/internal/errors"
|
|
)
|
|
|
|
// Service defines operations related to Nix
|
|
type Service interface {
|
|
BuildDerivation(derivation string) (string, error)
|
|
BuildAndParseJSON(derivation string) (any, error)
|
|
BuildAndRunScript(derivation string, pureEnv bool) (exitCode int, stdout string, stderr string, err error)
|
|
}
|
|
|
|
type DefaultService struct {
|
|
commandExecutor func(command string, args ...string) *exec.Cmd
|
|
}
|
|
|
|
func NewDefaultService() *DefaultService {
|
|
return &DefaultService{commandExecutor: exec.Command}
|
|
}
|
|
|
|
// BuildDerivation builds a Nix derivation and returns the output path
|
|
func (s *DefaultService) BuildDerivation(derivation string) (string, error) {
|
|
cmd := s.commandExecutor(
|
|
"nix",
|
|
"build",
|
|
derivation+"^*",
|
|
"--print-out-paths",
|
|
"--no-link",
|
|
)
|
|
var stdout, stderr bytes.Buffer
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
return "", &apperrors.NixBuildError{Derivation: derivation, Stderr: stderr.String(), Err: err}
|
|
}
|
|
|
|
path := strings.TrimSpace(stdout.String())
|
|
if path == "" {
|
|
return "", &apperrors.NixNoOutputPathError{Derivation: derivation, Stderr: stderr.String()}
|
|
}
|
|
return path, nil
|
|
}
|
|
|
|
// BuildAndParseJSON builds a derivation and parses its output file as JSON
|
|
func (s *DefaultService) BuildAndParseJSON(derivation string) (any, error) {
|
|
path, err := s.BuildDerivation(derivation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, &apperrors.FileReadError{Path: path, Err: err}
|
|
}
|
|
|
|
var result any
|
|
err = json.Unmarshal(data, &result)
|
|
if err != nil {
|
|
return nil, &apperrors.JSONUnmarshalError{Source: path, Err: err}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// BuildAndRunScript builds a derivation and runs it as a script
|
|
func (s *DefaultService) BuildAndRunScript(derivation string, pureEnv bool) (exitCode int, stdout string, stderr string, err error) {
|
|
exitCode = -1
|
|
path, err := s.BuildDerivation(derivation)
|
|
if err != nil {
|
|
return exitCode, "", "", err
|
|
}
|
|
|
|
var cmdArgs []string
|
|
if pureEnv {
|
|
cmdArgs = append([]string{"env", "-i"}, "bash", path)
|
|
} else {
|
|
cmdArgs = []string{"bash", path}
|
|
}
|
|
|
|
cmd := s.commandExecutor(cmdArgs[0], cmdArgs[1:]...)
|
|
var outBuf, errBuf bytes.Buffer
|
|
cmd.Stdout = &outBuf
|
|
cmd.Stderr = &errBuf
|
|
|
|
if err = cmd.Start(); err != nil {
|
|
return exitCode, "", "", &apperrors.ScriptExecutionError{Path: path, Err: err}
|
|
}
|
|
|
|
runErr := cmd.Wait()
|
|
stdout = outBuf.String()
|
|
stderr = errBuf.String()
|
|
|
|
if runErr != nil {
|
|
if exitErr, ok := runErr.(*exec.ExitError); ok {
|
|
return exitErr.ExitCode(), stdout, stderr, nil
|
|
}
|
|
return exitCode, stdout, stderr, &apperrors.ScriptExecutionError{Path: path, Err: runErr}
|
|
}
|
|
|
|
return 0, stdout, stderr, nil
|
|
}
|