Add unexport and export.
Signed-off-by: Hadi Chokr <hadichokr@icloud.com>
This commit is contained in:
parent
e3ce0bc457
commit
1dad3c86fe
|
|
@ -0,0 +1,143 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
exportBin string
|
||||
exportApp string
|
||||
exportContainer string
|
||||
)
|
||||
|
||||
var exportCmd = &cobra.Command{
|
||||
Use: "export",
|
||||
Short: "Export binaries or applications from a toolbox container",
|
||||
RunE: runExport,
|
||||
}
|
||||
|
||||
func init() {
|
||||
exportCmd.Flags().StringVar(&exportBin, "bin", "", "Path or name of binary to export")
|
||||
exportCmd.Flags().StringVar(&exportApp, "app", "", "Path or name of application to export")
|
||||
exportCmd.Flags().StringVar(&exportContainer, "container", "", "Name of the toolbox container")
|
||||
rootCmd.AddCommand(exportCmd)
|
||||
}
|
||||
|
||||
func runExport(cmd *cobra.Command, args []string) error {
|
||||
if exportBin == "" && exportApp == "" {
|
||||
return errors.New("must specify either --bin or --app")
|
||||
}
|
||||
if exportContainer == "" {
|
||||
return errors.New("must specify --container")
|
||||
}
|
||||
|
||||
if exportBin != "" {
|
||||
return exportBinary(exportBin, exportContainer)
|
||||
} else if exportApp != "" {
|
||||
return exportApplication(exportApp, exportContainer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func exportBinary(binName, containerName string) error {
|
||||
// Find the binary's full path inside the container
|
||||
checkCmd := fmt.Sprintf("toolbox run -c %s which %s", containerName, binName)
|
||||
out, err := exec.Command("sh", "-c", checkCmd).Output()
|
||||
if err != nil || strings.TrimSpace(string(out)) == "" {
|
||||
return fmt.Errorf("binary %s not found in container %s", binName, containerName)
|
||||
}
|
||||
binPath := strings.TrimSpace(string(out))
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
exportedBinPath := filepath.Join(homeDir, ".local", "bin", binName)
|
||||
|
||||
script := fmt.Sprintf(`#!/bin/sh
|
||||
# toolbox_binary
|
||||
# name: %s
|
||||
exec toolbox run -c %s %s "$@"
|
||||
`, containerName, containerName, binPath)
|
||||
|
||||
if err := os.WriteFile(exportedBinPath, []byte(script), 0755); err != nil {
|
||||
return fmt.Errorf("failed to create wrapper: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully exported %s from container %s to %s\n", binName, containerName, exportedBinPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func exportApplication(appName, containerName string) error {
|
||||
// Find the desktop file inside the container
|
||||
findCmd := fmt.Sprintf("toolbox run -c %s sh -c 'find /usr/share/applications -name \"*%s*.desktop\" | head -1'", containerName, appName)
|
||||
out, err := exec.Command("sh", "-c", findCmd).Output()
|
||||
if err != nil || strings.TrimSpace(string(out)) == "" {
|
||||
return fmt.Errorf("application %s not found in container %s", appName, containerName)
|
||||
}
|
||||
desktopFile := strings.TrimSpace(string(out))
|
||||
|
||||
// Read the desktop file content
|
||||
catCmd := fmt.Sprintf("toolbox run -c %s cat %s", containerName, desktopFile)
|
||||
content, err := exec.Command("sh", "-c", catCmd).Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read desktop file: %v", err)
|
||||
}
|
||||
lines := strings.Split(string(content), "\n")
|
||||
var newLines []string
|
||||
hasNameTranslations := false
|
||||
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Exec=") {
|
||||
execCmd := line[5:]
|
||||
line = fmt.Sprintf("Exec=toolbox run -c %s %s", containerName, execCmd)
|
||||
} else if strings.HasPrefix(line, "Name=") {
|
||||
line = fmt.Sprintf("Name=%s (on %s)", line[5:], containerName)
|
||||
} else if strings.HasPrefix(line, "Name[") {
|
||||
hasNameTranslations = true
|
||||
} else if strings.HasPrefix(line, "GenericName=") {
|
||||
line = fmt.Sprintf("GenericName=%s (on %s)", line[12:], containerName)
|
||||
} else if strings.HasPrefix(line, "TryExec=") || line == "DBusActivatable=true" {
|
||||
continue
|
||||
}
|
||||
newLines = append(newLines, line)
|
||||
}
|
||||
|
||||
if hasNameTranslations {
|
||||
for i, line := range newLines {
|
||||
if strings.HasPrefix(line, "Name[") {
|
||||
lang := line[5:strings.Index(line, "]")]
|
||||
value := line[strings.Index(line, "=")+1:]
|
||||
newLines[i] = fmt.Sprintf("Name[%s]=%s (on %s)", lang, value, containerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appsPath := filepath.Join(homeDir, ".local", "share", "applications")
|
||||
exportedPath := filepath.Join(appsPath, filepath.Base(desktopFile))
|
||||
exportedPath = strings.TrimSuffix(exportedPath, ".desktop") + "-" + containerName + ".desktop"
|
||||
|
||||
if err := os.MkdirAll(appsPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create applications directory: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(exportedPath, []byte(strings.Join(newLines, "\n")), 0644); err != nil {
|
||||
return fmt.Errorf("failed to create desktop file: %v", err)
|
||||
}
|
||||
|
||||
// Update desktop database
|
||||
exec.Command("update-desktop-database", appsPath).Run()
|
||||
|
||||
fmt.Printf("Successfully exported %s from container %s to %s\n", appName, containerName, exportedPath)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
unexportContainer string
|
||||
unexportBin string
|
||||
unexportApp string
|
||||
unexportAll bool
|
||||
)
|
||||
|
||||
var unexportCmd = &cobra.Command{
|
||||
Use: "unexport",
|
||||
Short: "Remove exported binaries and applications for a specific toolbox container",
|
||||
RunE: runUnexport,
|
||||
}
|
||||
|
||||
func init() {
|
||||
unexportCmd.Flags().StringVar(&unexportContainer, "container", "", "Name of the toolbox container")
|
||||
unexportCmd.Flags().StringVar(&unexportBin, "bin", "", "Name of the exported binary to remove")
|
||||
unexportCmd.Flags().StringVar(&unexportApp, "app", "", "Name of the exported application to remove")
|
||||
unexportCmd.Flags().BoolVar(&unexportAll, "all", false, "Remove all exported binaries and applications for the container")
|
||||
rootCmd.AddCommand(unexportCmd)
|
||||
}
|
||||
|
||||
func runUnexport(cmd *cobra.Command, args []string) error {
|
||||
if unexportContainer == "" {
|
||||
return errors.New("must specify --container")
|
||||
}
|
||||
|
||||
if !unexportAll && unexportBin == "" && unexportApp == "" {
|
||||
return errors.New("must specify --bin, --app, or --all")
|
||||
}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
binDir := filepath.Join(homeDir, ".local", "bin")
|
||||
appsDir := filepath.Join(homeDir, ".local", "share", "applications")
|
||||
|
||||
removedBins := []string{}
|
||||
removedApps := []string{}
|
||||
|
||||
if unexportBin != "" {
|
||||
path := filepath.Join(binDir, unexportBin)
|
||||
if fileContainsContainer(path, unexportContainer) {
|
||||
if err := os.Remove(path); err == nil {
|
||||
removedBins = append(removedBins, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if unexportApp != "" {
|
||||
// Remove .desktop file that matches app name and container
|
||||
matches, _ := filepath.Glob(filepath.Join(appsDir, fmt.Sprintf("*%s-%s.desktop", unexportApp, unexportContainer)))
|
||||
for _, path := range matches {
|
||||
if err := os.Remove(path); err == nil {
|
||||
removedApps = append(removedApps, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if unexportAll {
|
||||
// Remove all binaries for this container in .local/bin
|
||||
binFiles, _ := os.ReadDir(binDir)
|
||||
for _, f := range binFiles {
|
||||
if f.IsDir() {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(binDir, f.Name())
|
||||
if fileContainsContainer(path, unexportContainer) {
|
||||
if err := os.Remove(path); err == nil {
|
||||
removedBins = append(removedBins, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all .desktop files for this container in .local/share/applications
|
||||
appFiles, _ := os.ReadDir(appsDir)
|
||||
for _, f := range appFiles {
|
||||
name := f.Name()
|
||||
if strings.HasSuffix(name, "-"+unexportContainer+".desktop") {
|
||||
path := filepath.Join(appsDir, name)
|
||||
if err := os.Remove(path); err == nil {
|
||||
removedApps = append(removedApps, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Removed binaries:\n")
|
||||
for _, b := range removedBins {
|
||||
fmt.Printf(" %s\n", b)
|
||||
}
|
||||
fmt.Printf("Removed desktop files:\n")
|
||||
for _, a := range removedApps {
|
||||
fmt.Printf(" %s\n", a)
|
||||
}
|
||||
if len(removedBins) == 0 && len(removedApps) == 0 {
|
||||
fmt.Println("No exported binaries or desktop files found to remove for container", unexportContainer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fileContainsContainer returns true if the file exists and has a toolbox_binary comment with name: <container>
|
||||
func fileContainsContainer(path, container string) bool {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(string(content), "# toolbox_binary") && strings.Contains(string(content), fmt.Sprintf("name: %s", container))
|
||||
}
|
||||
Loading…
Reference in New Issue