mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
util: add flatpak introspection utilities (#1234)
ci: run apt as sudo ci: fix flatpak remote in runner ci: flatpak install steps in runner ci: specific version of freedesktop ci: freedesktop install perms
This commit is contained in:
9
.github/workflows/go-ci.yml
vendored
9
.github/workflows/go-ci.yml
vendored
@@ -28,6 +28,15 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install flatpak
|
||||
run: sudo apt update && sudo apt install -y flatpak
|
||||
|
||||
- name: Add flathub
|
||||
run: sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
|
||||
- name: Add a flatpak that mutagen could support
|
||||
run: sudo flatpak install -y org.freedesktop.Platform/x86_64/24.08 app.zen_browser.zen
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
|
||||
78
core/internal/utils/flatpak.go
Normal file
78
core/internal/utils/flatpak.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func FlatpakInPath() bool {
|
||||
_, err := exec.LookPath("flatpak")
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func FlatpakExists(name string) bool {
|
||||
if !FlatpakInPath() {
|
||||
return false
|
||||
}
|
||||
|
||||
cmd := exec.Command("flatpak", "info", name)
|
||||
err := cmd.Run()
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func FlatpakSearchBySubstring(substring string) bool {
|
||||
if !FlatpakInPath() {
|
||||
return false
|
||||
}
|
||||
|
||||
cmd := exec.Command("flatpak", "list", "--app")
|
||||
var stdout bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
out := stdout.String()
|
||||
|
||||
for line := range strings.SplitSeq(out, "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) > 1 {
|
||||
id := fields[1]
|
||||
idParts := strings.Split(id, ".")
|
||||
// We are assuming that the last part of the ID is
|
||||
// the package name we're looking for. This might
|
||||
// not always be true, some developers use arbitrary
|
||||
// suffixes.
|
||||
if len(idParts) > 0 && idParts[len(idParts)-1] == substring {
|
||||
cmd := exec.Command("flatpak", "info", id)
|
||||
err := cmd.Run()
|
||||
return err == nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func FlatpakInstallationDir(name string) (string, error) {
|
||||
if !FlatpakInPath() {
|
||||
return "", errors.New("flatpak not found in PATH")
|
||||
}
|
||||
|
||||
cmd := exec.Command("flatpak", "info", "--show-location", name)
|
||||
var stdout bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", errors.New("flatpak not installed: " + name)
|
||||
}
|
||||
|
||||
location := strings.TrimSpace(stdout.String())
|
||||
if location == "" {
|
||||
return "", errors.New("installation directory not found for: " + name)
|
||||
}
|
||||
|
||||
return location, nil
|
||||
}
|
||||
210
core/internal/utils/flatpak_test.go
Normal file
210
core/internal/utils/flatpak_test.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFlatpakInPathAvailable(t *testing.T) {
|
||||
result := FlatpakInPath()
|
||||
if !result {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
if !result {
|
||||
t.Errorf("expected true when flatpak is in PATH")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakInPathUnavailable(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
t.Setenv("PATH", tempDir)
|
||||
|
||||
result := FlatpakInPath()
|
||||
if result {
|
||||
t.Errorf("expected false when flatpak not in PATH, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakExistsValidPackage(t *testing.T) {
|
||||
if !FlatpakInPath() {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
|
||||
result := FlatpakExists("com.nonexistent.package.test")
|
||||
if result {
|
||||
t.Logf("package exists (unexpected but not an error)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakExistsNoFlatpak(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
t.Setenv("PATH", tempDir)
|
||||
|
||||
result := FlatpakExists("any.package.name")
|
||||
if result {
|
||||
t.Errorf("expected false when flatpak not in PATH, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakSearchBySubstringNoFlatpak(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
t.Setenv("PATH", tempDir)
|
||||
|
||||
result := FlatpakSearchBySubstring("test")
|
||||
if result {
|
||||
t.Errorf("expected false when flatpak not in PATH, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakSearchBySubstringNonexistent(t *testing.T) {
|
||||
if !FlatpakInPath() {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
|
||||
result := FlatpakSearchBySubstring("ThisIsAVeryUnlikelyPackageName12345")
|
||||
if result {
|
||||
t.Errorf("expected false for nonexistent package substring")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakInstallationDirNoFlatpak(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
t.Setenv("PATH", tempDir)
|
||||
|
||||
_, err := FlatpakInstallationDir("any.package.name")
|
||||
if err == nil {
|
||||
t.Errorf("expected error when flatpak not in PATH")
|
||||
}
|
||||
if err != nil && !strings.Contains(err.Error(), "not found in PATH") {
|
||||
t.Errorf("expected 'not found in PATH' error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakInstallationDirNonexistent(t *testing.T) {
|
||||
if !FlatpakInPath() {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
|
||||
_, err := FlatpakInstallationDir("com.nonexistent.package.test")
|
||||
if err == nil {
|
||||
t.Errorf("expected error for nonexistent package")
|
||||
}
|
||||
if err != nil && !strings.Contains(err.Error(), "not installed") {
|
||||
t.Errorf("expected 'not installed' error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakInstallationDirValid(t *testing.T) {
|
||||
if !FlatpakInPath() {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
|
||||
// This test requires a known installed flatpak
|
||||
// We can't guarantee any specific flatpak is installed,
|
||||
// so we'll skip if we can't find a common one
|
||||
commonFlatpaks := []string{
|
||||
"org.mozilla.firefox",
|
||||
"org.gnome.Calculator",
|
||||
"org.freedesktop.Platform",
|
||||
}
|
||||
|
||||
var testPackage string
|
||||
for _, pkg := range commonFlatpaks {
|
||||
if FlatpakExists(pkg) {
|
||||
testPackage = pkg
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if testPackage == "" {
|
||||
t.Skip("no common flatpak packages found for testing")
|
||||
}
|
||||
|
||||
result, err := FlatpakInstallationDir(testPackage)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if result == "" {
|
||||
t.Errorf("expected non-empty installation directory")
|
||||
}
|
||||
if !strings.Contains(result, testPackage) {
|
||||
t.Logf("installation directory %s doesn't contain package name (may be expected)", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakExistsCommandFailure(t *testing.T) {
|
||||
if !FlatpakInPath() {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
|
||||
// Mock a failing flatpak command through PATH interception
|
||||
tempDir := t.TempDir()
|
||||
fakeFlatpak := filepath.Join(tempDir, "flatpak")
|
||||
|
||||
script := "#!/bin/sh\nexit 1\n"
|
||||
err := os.WriteFile(fakeFlatpak, []byte(script), 0755)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create fake flatpak: %v", err)
|
||||
}
|
||||
|
||||
originalPath := os.Getenv("PATH")
|
||||
t.Setenv("PATH", tempDir+":"+originalPath)
|
||||
|
||||
result := FlatpakExists("test.package")
|
||||
if result {
|
||||
t.Errorf("expected false when flatpak command fails, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakSearchBySubstringCommandFailure(t *testing.T) {
|
||||
if !FlatpakInPath() {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
|
||||
// Mock a failing flatpak command through PATH interception
|
||||
tempDir := t.TempDir()
|
||||
fakeFlatpak := filepath.Join(tempDir, "flatpak")
|
||||
|
||||
script := "#!/bin/sh\nexit 1\n"
|
||||
err := os.WriteFile(fakeFlatpak, []byte(script), 0755)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create fake flatpak: %v", err)
|
||||
}
|
||||
|
||||
originalPath := os.Getenv("PATH")
|
||||
t.Setenv("PATH", tempDir+":"+originalPath)
|
||||
|
||||
result := FlatpakSearchBySubstring("test")
|
||||
if result {
|
||||
t.Errorf("expected false when flatpak command fails, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatpakInstallationDirCommandFailure(t *testing.T) {
|
||||
if !FlatpakInPath() {
|
||||
t.Skip("flatpak not in PATH")
|
||||
}
|
||||
|
||||
// Mock a failing flatpak command through PATH interception
|
||||
tempDir := t.TempDir()
|
||||
fakeFlatpak := filepath.Join(tempDir, "flatpak")
|
||||
|
||||
script := "#!/bin/sh\nexit 1\n"
|
||||
err := os.WriteFile(fakeFlatpak, []byte(script), 0755)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create fake flatpak: %v", err)
|
||||
}
|
||||
|
||||
originalPath := os.Getenv("PATH")
|
||||
t.Setenv("PATH", tempDir+":"+originalPath)
|
||||
|
||||
_, err = FlatpakInstallationDir("test.package")
|
||||
if err == nil {
|
||||
t.Errorf("expected error when flatpak command fails")
|
||||
}
|
||||
if err != nil && !strings.Contains(err.Error(), "not installed") {
|
||||
t.Errorf("expected 'not installed' error, got: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user