Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fixes #222

Merged
merged 4 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,6 @@ if [ $GITHUB_ACTIONS ]; then
sudo apt-get install --yes wget file
fi

# Install zig, it comes with musl libc
if [ ! -e /usr/local/bin/zig ]; then
wget -c -q "https://ziglang.org/builds/zig-linux-x86_64-0.10.0-dev.2112+0df28f9d4.tar.xz"
tar xf zig-linux-*-*.tar.xz
sudo mv zig-linux-*/* /usr/local/bin/
which zig
fi

if [ -z $BUILDTOOL ]; then
BUILDTOOL=(appimaged appimagetool mkappimage)
fi
Expand All @@ -249,6 +241,17 @@ fi
mkdir -p $BUILDDIR || true
cd $BUILDDIR

# Install zig, it comes with musl libc
if [ ! -e $BUILDDIR/zig ]; then
wget -c -q "https://ziglang.org/builds/zig-linux-x86_64-0.10.0-dev.2112+0df28f9d4.tar.xz"
tar xf zig-linux-*.tar.xz
rm zig-linux-*.tar.xz
mv zig-linux-* zig
CLEANUP+=($BUILDDIR/zig)
fi

PATH=$BUILDDIR/zig:$PATH

# We always want the amd64 appimagetool built first so that other AppImages can be built.
# If this isn't wanted, we clean it up afterwards
build amd64 appimagetool
Expand All @@ -267,7 +270,7 @@ if [ -z $BUILDINGAPPIMAGETOOL ]; then
CLEANUP+=($BUILDDIR/appimagetool-$VERSION-x86_64.AppImage)
fi

if [ -z $DONTCLEAN]; then
if [ -z $DONTCLEAN ]; then
for file in ${CLEANUP[@]}; do
echo $file
rm -rf $file || true
Expand Down
9 changes: 0 additions & 9 deletions src/appimaged/appimaged.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,6 @@ func moveDesktopFiles(ai *AppImage) error {
if !integrate {
return nil
}
desktopcachedir := xdg.CacheHome + "/applications/" // FIXME: Do not hardcode here and in other places

err := os.Rename(desktopcachedir+"/appimagekit_"+ai.md5+".desktop", ai.desktopfilepath)
if err != nil {
return err
}
if *verbosePtr {
log.Println("main: Moved ", desktopcachedir+"/appimagekit_"+ai.md5+".desktop to", xdg.DataHome+"/applications/")
}

if !ai.startup {
// If one single application has been integrated, then the user probably cares about it
Expand Down
2 changes: 2 additions & 0 deletions src/appimaged/appwrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ func appwrap() {
}

cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout

var out bytes.Buffer
cmd.Stderr = &out
Expand Down
108 changes: 42 additions & 66 deletions src/appimaged/desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ package main
// but eventually may be rewritten to do things natively in Go.

import (
"bufio"
"bytes"
"io/ioutil"
"log"
"os"
"path/filepath"
Expand All @@ -16,7 +14,6 @@ import (

"golang.org/x/sys/unix"

"github.com/adrg/xdg"
"github.com/probonopd/go-appimage/internal/helpers"
"gopkg.in/ini.v1"
)
Expand All @@ -27,65 +24,32 @@ import (
// for a while
func writeDesktopFile(ai AppImage) {

filename := "appimagekit_" + ai.md5 + ".desktop"

// log.Println(md5s)
// XDG directories
// log.Println(xdg.DataHome)
// log.Println(xdg.DataDirs)
// log.Println(xdg.ConfigHome)
// log.Println(xdg.ConfigDirs)
desktopcachedir := xdg.CacheHome + "/applications/" // FIXME: Do not hardcode here and in other places

err := os.MkdirAll(desktopcachedir, os.ModePerm)
if err != nil {
log.Printf("desktop: %v", err)
}
// log.Println(xdg.RuntimeDir)
var cfg *ini.File
ini.PrettyFormat = false
startingPoint := false //An easy way to tell if extracting the desktop file worked.
arg0abs, err := filepath.Abs(os.Args[0])

// FIXME: KDE seems to have a problem when the AppImage is on a partition of which the disklabel contains "_"?
// Then the desktop file won't run the application
if err != nil {
log.Println(err)
}
if ai.Desktop != nil {
//Start with a fresh copy of the desktop file so we don't make edits to ai.Desktop

desktopRdr, _ := ai.ExtractFileReader("*.desktop")
defer desktopRdr.Close()
//cleaning the desktop file so it can be parsed properly
var desktop []byte
buf := bufio.NewReader(desktopRdr)
for err == nil {
var line string
line, err = buf.ReadString('\n')
if strings.Contains(line, ";") {
line = strings.ReplaceAll(line, ";", ";") //replacing it with a fullwidth semicolon (unicode FF1B)
}
desktop = append(desktop, line...)
}
cfg, err = ini.Load(desktop)
if err == nil {
startingPoint = true
}
//TODO: check if the thumbnail is already present and only extract it and set it's value if it isn't
}
//Create a copy of the desktop file to edit.
deskCopy := new(bytes.Buffer)
ai.Desktop.WriteTo(deskCopy)
cfg, _ := ini.Load(deskCopy)

if !startingPoint {
cfg = ini.Empty()
cfg.Section("Desktop Entry").Key("Type").SetValue("Application")
if !cfg.Section("Desktop Entry").HasKey("Name") {
cfg.Section("Desktop Entry").Key("Name").SetValue(ai.Name)
} else {
if !cfg.Section("Desktop Entry").HasKey("Name") {
cfg.Section("Desktop Entry").Key("Name").SetValue(ai.Name)
}
if !cfg.Section("Desktop Entry").HasKey("Type") {
cfg.Section("Desktop Entry").Key("Type").SetValue("Application")
}
}
if !cfg.Section("Desktop Entry").HasKey("Type") {
cfg.Section("Desktop Entry").Key("Type").SetValue("Application")
}
thumbnail := ThumbnailsDirNormal + ai.md5 + ".png"
cfg.Section("Desktop Entry").Key("Icon").SetValue(thumbnail)
Expand Down Expand Up @@ -125,8 +89,28 @@ func writeDesktopFile(ai AppImage) {
cfg.Section("Desktop Entry").Key(helpers.UpdateInformationKey).SetValue("\"" + ui + "\"")
}
// Actions

var actions []string
if strings.TrimSpace(cfg.Section("Desktop Entry").Key("Actions").String()) != "" {
actions = strings.Split(cfg.Section("Desktop Entry").Key("Actions").String(), ";")
for i := 0; i < len(actions); i++ {
if actions[i] == "" {
actions = append(actions[:i], actions[i+1:]...)
}
}
}
for _, a := range actions {
sec := cfg.Section("Desktop Action " + a)
exec := sec.Key("Exec").String()
if exec != "" {
if strings.HasPrefix(exec, "\"") {
if strings.Contains(exec[1:], "\"") {
exec = exec[1 : strings.Index(exec[1:], "\"")+1]
}
}
spl := strings.Split(exec, " ")
sec.Key("Exec").SetValue(arg0abs + " wrap \"" + ai.Path + "\" " + strings.Join(spl[1:], " "))
}
}

if isWritable(ai.Path) {
// Add "Move to Trash" action
Expand Down Expand Up @@ -235,24 +219,24 @@ func writeDesktopFile(ai AppImage) {
cfg.Section("Desktop Action FirejailOverlayTmpfs").Key("Exec").SetValue("firejail --env=DESKTOPINTEGRATION=appimaged --noprofile --overlay-tmpfs --appimage \"" + ai.Path + "\"")
}

as := ""
for _, action := range actions {
as = as + action + ";"
}
as := strings.Join(actions, ";")
cfg.Section("Desktop Entry").Key("Actions").SetValue(as)

if *verbosePtr {
log.Println("desktop: Saving to", desktopcachedir+"/"+filename)
log.Println("desktop: Saving to", ai.desktopfilepath)
}
err = cfg.SaveTo(desktopcachedir + "/" + filename)
buf := new(bytes.Buffer)
cfg.WriteTo(buf)
out := fixDesktopFile(buf.Bytes())
os.Remove(ai.desktopfilepath)
deskFil, err := os.Create(ai.desktopfilepath)
if err != nil {
log.Printf("Fail to write file: %v", err)
log.Printf("Fail to create file: %v", err)
return
}

err = fixDesktopFile(desktopcachedir + "/" + filename)
_, err = deskFil.Write(out)
if err != nil {
helpers.PrintError("desktop fixDesktopFile", err)
os.Exit(1)
log.Printf("Fail to write file: %v", err)
}
}

Expand All @@ -263,20 +247,12 @@ func isWritable(path string) bool {

// Really ugly workaround for
// https://github.com/go-ini/ini/issues/90
func fixDesktopFile(path string) error {
input, err := ioutil.ReadFile(path)
if err != nil {
return err
}
func fixDesktopFile(input []byte) []byte {
var output []byte
if bytes.Contains(input, []byte("=`")) {
output = bytes.Replace(input, []byte("=`"), []byte("="), -1)
output = bytes.Replace(output, []byte("`\n"), []byte("\n"), -1)
}
output = bytes.ReplaceAll(output, []byte(";"), []byte(";"))

if err = ioutil.WriteFile(path, output, 0755); err != nil {
return err
}
return nil
return output
}
35 changes: 25 additions & 10 deletions src/goappimage/appimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ type AppImage struct {
// NewAppImage creates an AppImage object from the location defined by path.
// Returns an error if the given path is not an appimage, or is a temporary file.
// In all instances, will still return the AppImage.
func NewAppImage(path string) (*AppImage, error) {
ai := AppImage{Path: path, imageType: -1}
func NewAppImage(path string) (ai *AppImage, err error) {
ai = &AppImage{Path: path, imageType: -1}
// If we got a temp file, exit immediately
// E.g., ignore typical Internet browser temporary files used during download
if strings.HasSuffix(path, ".temp") ||
Expand All @@ -51,24 +51,35 @@ func NewAppImage(path string) (*AppImage, error) {
strings.HasSuffix(path, ".partial") ||
strings.HasSuffix(path, ".zs-old") ||
strings.HasSuffix(path, ".crdownload") {
return &ai, errors.New("given path is a temporary file")
return ai, errors.New("given path is a temporary file")
}
ai.imageType = ai.determineImageType()
// Don't waste more time if the file is not actually an AppImage
if ai.imageType < 0 {
return &ai, errors.New("given path is NOT an AppImage")
return ai, errors.New("given path is NOT an AppImage")
}
if ai.imageType > 1 {
ai.offset = helpers.CalculateElfSize(ai.Path)
}
err := ai.populateReader(true, false)
err = ai.populateReader(true, false)
if err != nil {
return &ai, err
return
}
//try to load up the desktop file for some information.
desktopFil, err := ai.reader.FileReader("*.desktop")
var desk string
files := ai.reader.ListFiles(".")
for _, f := range files {
if strings.HasSuffix(f, ".desktop") {
desk = f
break
}
}
if desk == "" {
return ai, errors.New("cannot find desktop file")
}
desktopFil, err := ai.reader.FileReader(desk)
if err != nil {
return nil, err
return
}

//cleaning the desktop file so it can be parsed properly
Expand All @@ -83,7 +94,7 @@ func NewAppImage(path string) (*AppImage, error) {

ai.Desktop, err = ini.Load(desktop)
if err != nil {
return nil, err
return
}

ai.Name = ai.Desktop.Section("Desktop Entry").Key("Name").Value()
Expand All @@ -96,7 +107,7 @@ func NewAppImage(path string) (*AppImage, error) {
}

ai.UpdateInfo, _ = helpers.ReadUpdateInfo(ai.Path)
return &ai, nil
return
}

func (ai AppImage) calculateNiceName() string {
Expand Down Expand Up @@ -173,6 +184,10 @@ func (ai AppImage) Type() int {
return ai.imageType
}

func (ai AppImage) ListFiles(folder string) []string {
return ai.reader.ListFiles(folder)
}

// ExtractFile extracts a file from from filepath (which may contain * wildcards) in an AppImage to the destinationdirpath.
//
// If resolveSymlinks is true, if the filepath specified is a symlink, the actual file is extracted in it's place.
Expand Down