package executables import ( "embed" "errors" "io" "io/fs" "os/exec" "path" "strings" "velvettear/badger/internal/log" ) const FFPROBE = "ffprobe" const FPCALC = "fpcalc" var MandatoryExecutables []string var Executables []Executable // exported function(s) func Initialize(mandatoryExecutables ...string) { if len(mandatoryExecutables) == 0 { MandatoryExecutables = []string{FFPROBE, FPCALC} } else { MandatoryExecutables = mandatoryExecutables } Executables = locateSystemExecutables() } func GetExecutable(executableName string) (Executable, error) { for _, executable := range Executables { if strings.ToLower(executable.Name) == strings.ToLower(executableName) { return executable, nil } } return Executable{}, errors.New("executable '" + executableName + "' is unavailable") } func GetMissingExecutables() []string { missingExecutables := []string{} for _, mandatoryExecutableName := range MandatoryExecutables { mandatoryExecutableName = strings.ToLower(mandatoryExecutableName) for _, availableExecutable := range Executables { availableExecutableName := strings.ToLower(availableExecutable.Name) if strings.Contains(availableExecutableName, mandatoryExecutableName) { continue } } missingExecutables = append(missingExecutables, mandatoryExecutableName) } return missingExecutables } func ExportExecutables(embeddedFS *embed.FS) { error := fs.WalkDir(embeddedFS, ".", func(file string, entry fs.DirEntry, error error) error { if entry.IsDir() || file == "." { return nil } executable, error := exportThirdPartyExecutable(embeddedFS, path.Base(file)) if error != nil { return error } Executables = append(Executables, executable) return nil }) if error != nil { log.Fatal("encountered one or more errors exporting third party executables", error.Error()) } } func AreMandatoryExecutablesAvailable() bool { for { mandatoryExecutable := MandatoryExecutables[0] for _, availableExecutable := range Executables { if availableExecutable.Name != mandatoryExecutable { continue } MandatoryExecutables = MandatoryExecutables[1:] break } if len(MandatoryExecutables) == 0 { break } } return len(MandatoryExecutables) == 0 } func (executable Executable) Spawn(arguments ...string) (string, error) { return spawnProcess(executable.Path, arguments...) } func spawnProcess(command string, arguments ...string) (string, error) { cmd := exec.Command(command, arguments...) stdout, stdoutError := cmd.StdoutPipe() stderr, stderrError := cmd.StderrPipe() cmd.Start() if stdoutError != nil { return "", stdoutError } if stderrError != nil { return "", stderrError } resultBytes, stdoutError := io.ReadAll(stdout) if stdoutError != nil { return "", stdoutError } errorBytes, stderrError := io.ReadAll(stderr) if stderrError != nil { return "", stderrError } cmd.Wait() error := strings.Trim(string(errorBytes), "\n") if len(error) > 0 { return "", errors.New(error) } return strings.Trim(string(resultBytes), "\n"), nil } // struct(s) type Executable struct { Name string Path string }