Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9da352a315 | |||
| 34b8f7c926 | |||
| 5d5cedec58 | |||
| 8441a8b752 | |||
| d64d88e0a5 | |||
| 5eeb9cc702 | |||
| fc3411e568 |
@@ -2,10 +2,15 @@
|
||||
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
|
||||
|
||||
# How to use
|
||||
Just double click on an app to launch it! If there are multiple executables, you can either select the specific executable, or if you just double click the app it'll launch the first linux executable, but if one isn't found it launches the first executable in general.
|
||||
Just double click on an app to launch it! If there are multiple executables, you can either select the specific executable, or if you just double click the app it'll launch the first linux executable (.sh script files have priority), but if one isn't found it launches the first executable in general.
|
||||
|
||||
# Apps:
|
||||
Both of the below places provide linux executables that don't need libs installed on the host system:
|
||||
[AppImage](https://bintray.com/probono/AppImages)
|
||||
|
||||
# PortableApps.com Compatibility
|
||||
LinuxPA works will with the PortableApps.com launcher, as it looks for apps in the PortableApps folder and grabs the app's name and icon from where it should be in the PortableApps.com format.
|
||||
My forum at PortableApps.com can be found [here](http://portableapps.com/node/54998).
|
||||
|
||||
# common.sh
|
||||
common.sh is found in the PortableApps/LinuxPACom folder and is executed before the app. I mainly use it to set environment variables (such as HOME).
|
||||
@@ -18,7 +23,7 @@ Because apps aren't natively formated in the PortableApps.com format, if LinuxPA
|
||||
Right now AppImages are simply supported via the native linux executable support, but later I'm hoping to add downloading and automatic updating support later on.
|
||||
|
||||
# USB mount
|
||||
Unfortunately Linux, by default, doesn't support running executables off of flash drives, requiring you to mount your drive with special mount arguments, I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000`
|
||||
Unfortunately Linux, by default, doesn't support running executables off of FAT formated flash drives, requiring you to mount your drive with special mount arguments or format in a linux friendly format (such as EXT4). I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000`
|
||||
|
||||
# Screenshots
|
||||
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
|
||||
@@ -29,4 +34,4 @@ Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
|
||||
1. Add updater for .AppImage files
|
||||
1. Download .AppImage files (maybe)
|
||||
1. Check if all apps are closed when it closes and ask if you want to force stop the apps.
|
||||
1. Portable wine???
|
||||
1. Portable wine (Should be able to get a working version from PlayOnLinux, but I need to add a check to see if filesystem is EXT as Wine doesn't like filesystems w/o permission control)
|
||||
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/nelsam/gxui"
|
||||
"github.com/nelsam/gxui/math"
|
||||
@@ -28,7 +28,7 @@ type appExNode struct {
|
||||
func (a *appExNode) launch() {
|
||||
if wine {
|
||||
var cmd *exec.Cmd
|
||||
if ind := sort.SearchStrings(a.ap.lin, a.ap.ex[a.exInd]); ind == len(a.ap.lin) {
|
||||
if !contains(a.ap.lin, a.ap.ex[a.exInd]) {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[a.exInd]+"\"")
|
||||
} else {
|
||||
if comEnbld {
|
||||
@@ -93,11 +93,10 @@ type appNode struct {
|
||||
}
|
||||
|
||||
func (a *appNode) launch() {
|
||||
|
||||
if len(a.ap.ex) == 1 {
|
||||
if wine {
|
||||
var cmd *exec.Cmd
|
||||
if ind := sort.SearchStrings(a.ap.lin, a.ap.ex[0]); ind == len(a.ap.lin) {
|
||||
if !contains(a.ap.lin, a.ap.ex[0]) {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
|
||||
} else {
|
||||
if comEnbld {
|
||||
@@ -126,10 +125,17 @@ func (a *appNode) launch() {
|
||||
if len(a.ap.lin) == 0 {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
|
||||
} else {
|
||||
var ind int
|
||||
for i, v := range a.ap.lin {
|
||||
if strings.HasSuffix(v, ".sh") {
|
||||
ind = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
|
||||
}
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
@@ -137,11 +143,18 @@ func (a *appNode) launch() {
|
||||
cmd.Start()
|
||||
} else {
|
||||
if len(a.ap.lin) != 0 {
|
||||
var ind int
|
||||
for i, v := range a.ap.lin {
|
||||
if strings.HasSuffix(v, ".sh") {
|
||||
ind = i
|
||||
break
|
||||
}
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/nelsam/gxui"
|
||||
"github.com/nelsam/gxui/drivers/gl"
|
||||
"github.com/nelsam/gxui/themes/dark"
|
||||
"github.com/nelsam/gxui/themes/light"
|
||||
)
|
||||
|
||||
const (
|
||||
version = "1.1.0.0"
|
||||
defIni = "[basic]\ntheme=dk"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -15,17 +25,59 @@ var (
|
||||
lin []string
|
||||
wine bool
|
||||
comEnbld bool
|
||||
darkTheme = true
|
||||
)
|
||||
|
||||
func main() {
|
||||
updated := false
|
||||
os.MkdirAll("PortableApps/LinuxPACom", 0777)
|
||||
stat := versionDL()
|
||||
if stat {
|
||||
res := getVersionFileInfo()
|
||||
if res != "Error!" {
|
||||
stat = checkForUpdate(res)
|
||||
if stat {
|
||||
downloadUpdate(res)
|
||||
updated = true
|
||||
} else {
|
||||
fmt.Println("Failed DL")
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Failed Version File Info")
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Failed Version DL")
|
||||
}
|
||||
if updated {
|
||||
cmd := exec.Command("./LinuxPA")
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Start()
|
||||
fmt.Println("updated!")
|
||||
} else {
|
||||
master = make(map[string][]app)
|
||||
linmaster = make(map[string][]app)
|
||||
gl.StartDriver(appMain)
|
||||
}
|
||||
}
|
||||
|
||||
func appMain(dri gxui.Driver) {
|
||||
dr = dri
|
||||
th = dark.CreateTheme(dr)
|
||||
setup()
|
||||
if darkTheme {
|
||||
th = dark.CreateTheme(dr)
|
||||
} else {
|
||||
th = light.CreateTheme(dr)
|
||||
}
|
||||
th = dark.CreateTheme(dr)
|
||||
ui()
|
||||
}
|
||||
|
||||
func contains(arr []string, str string) bool {
|
||||
for _, v := range arr {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/draw"
|
||||
_ "image/png"
|
||||
@@ -13,10 +14,47 @@ import (
|
||||
"github.com/nelsam/gxui"
|
||||
)
|
||||
|
||||
const ()
|
||||
|
||||
func setup() {
|
||||
PortableAppsFold, err := os.Open("PortableApps")
|
||||
if PAStat, _ := PortableAppsFold.Stat(); err != nil || !PAStat.IsDir() {
|
||||
panic("PortableApps folder not found!!")
|
||||
os.Mkdir("PortableApps", 0777)
|
||||
PortableAppsFold, err = os.Open("PortableApps")
|
||||
if err != nil {
|
||||
panic("Can't find PortableApps folder and can't create one!")
|
||||
}
|
||||
}
|
||||
if _, err = os.Open("PortableApps/LinuxPACom"); err != nil {
|
||||
os.Mkdir("PortableApps/LinuxPACom", 0777)
|
||||
}
|
||||
fmt.Println(err)
|
||||
_, err = os.Open("PortableApps/LinuxPACom/common.sh")
|
||||
if err == nil {
|
||||
comEnbld = true
|
||||
}
|
||||
fi, err := os.Open("PortableApps/LinuxPACom/Info.ini")
|
||||
if err != nil {
|
||||
fi, err = os.Create("PortableApps/LinuxPACom/Info.ini")
|
||||
if err == nil {
|
||||
wrt := bufio.NewWriter(fi)
|
||||
wrt.WriteString(defIni)
|
||||
wrt.Flush()
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
rdr := bufio.NewReader(fi)
|
||||
for err != nil {
|
||||
ln, _, error := rdr.ReadLine()
|
||||
err = error
|
||||
str := string(ln)
|
||||
if strings.HasPrefix(str, "theme=") {
|
||||
str = strings.TrimPrefix(str, "theme=")
|
||||
if str == "lt" {
|
||||
darkTheme = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PAFolds, _ := PortableAppsFold.Readdirnames(-1)
|
||||
sort.Strings(PAFolds)
|
||||
@@ -28,23 +66,17 @@ func setup() {
|
||||
if _, ok := master[ap.cat]; !ok {
|
||||
cats = append(cats, ap.cat)
|
||||
sort.Strings(cats)
|
||||
if len(ap.lin) != 0 {
|
||||
lin = append(lin, ap.cat)
|
||||
sort.Strings(lin)
|
||||
}
|
||||
} else {
|
||||
if len(ap.lin) != 0 {
|
||||
ind := sort.SearchStrings(lin, ap.cat)
|
||||
if ind == len(lin) {
|
||||
if _, ok := linmaster[ap.cat]; !ok {
|
||||
lin = append(lin, ap.cat)
|
||||
sort.Strings(lin)
|
||||
}
|
||||
}
|
||||
}
|
||||
master[ap.cat] = append(master[ap.cat], ap)
|
||||
if len(ap.lin) != 0 {
|
||||
linmaster[ap.cat] = append(linmaster[ap.cat], ap)
|
||||
}
|
||||
master[ap.cat] = append(master[ap.cat], ap)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +116,7 @@ func processApp(fold string) (out app) {
|
||||
btys := make([]byte, 4)
|
||||
rdr := bufio.NewReader(tmp)
|
||||
rdr.Read(btys)
|
||||
if strings.HasPrefix(strings.ToLower(string(btys)), "ELF") || strings.HasPrefix(strings.ToLower(string(btys)), "#!") {
|
||||
if (strings.Contains(strings.ToLower(string(btys)), "elf") && !strings.HasSuffix(strings.ToLower(v), ".so") && !strings.Contains(v, ".so.")) || strings.HasPrefix(strings.ToLower(string(btys)), "#!") {
|
||||
out.ex = append(out.ex, v)
|
||||
out.lin = append(out.lin, v)
|
||||
}
|
||||
@@ -137,9 +169,11 @@ func getIcon(fold string) gxui.Texture {
|
||||
}
|
||||
sort.Strings(pics)
|
||||
if len(pics) > 1 {
|
||||
ind := sort.SearchStrings(pics, "appicon_32.png")
|
||||
if ind == len(pics) {
|
||||
ind--
|
||||
var ind int
|
||||
if !contains(pics, "appicon_32.png") {
|
||||
ind = len(pics) - 1
|
||||
} else {
|
||||
ind = sort.SearchStrings(pics, "appicon_32.png")
|
||||
}
|
||||
pic, _ = os.Open(fold + "/App/AppInfo/" + pics[ind])
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/nelsam/gxui"
|
||||
@@ -44,6 +45,18 @@ func ui() {
|
||||
wineBut.SetText("Show Windows Apps")
|
||||
}
|
||||
})
|
||||
_, err := os.Open("Start.exe")
|
||||
if err == nil {
|
||||
pa := th.CreateButton()
|
||||
pa.SetText("Open PortableApps Launcher")
|
||||
pa.OnClick(func(gxui.MouseEvent) {
|
||||
cmd := exec.Command("wine", "Start.exe")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Start()
|
||||
})
|
||||
butBox.AddChild(pa)
|
||||
}
|
||||
butBox.AddChild(wineBut)
|
||||
}
|
||||
top.AddChild(butBox)
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
versionURL = "https://www.dropbox.com/s/a0xizzo0a4vsfqt/Version?dl=1"
|
||||
downloadURL = "https://github.com/CalebQ42/LinuxPA/releases/download/vXXX/LinuxPA"
|
||||
)
|
||||
|
||||
//Thanks to https://www.socketloop.com/tutorials/golang-download-file-example
|
||||
//For some of the code
|
||||
|
||||
//Returns if success
|
||||
func versionDL() bool {
|
||||
versionFile, err := os.Create("PortableApps/LinuxPACom/Version")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
versionFile.Chmod(0777)
|
||||
check := http.Client{
|
||||
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||
r.URL.Opaque = r.URL.Path
|
||||
return nil
|
||||
},
|
||||
}
|
||||
response, err := check.Get(versionURL)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_, err = io.Copy(versionFile, response.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getVersionFileInfo() string {
|
||||
fil, err := os.Open("PortableApps/LinuxPACom/Version")
|
||||
if err != nil {
|
||||
return "Error!"
|
||||
}
|
||||
rdr := bufio.NewReader(fil)
|
||||
out, _, _ := rdr.ReadLine()
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func checkForUpdate(new string) bool {
|
||||
curSlice := strings.Split(version, ".")
|
||||
newSlice := strings.Split(new, ".")
|
||||
curNums := make([]int, 4)
|
||||
newNums := make([]int, 4)
|
||||
for i, v := range curSlice {
|
||||
num, err := strconv.Atoi(v)
|
||||
if err == nil {
|
||||
curNums[i] = num
|
||||
}
|
||||
num, err = strconv.Atoi(newSlice[i])
|
||||
if err == nil {
|
||||
newNums[i] = num
|
||||
}
|
||||
if newNums[i] > curNums[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func downloadUpdate(newVersion string) bool {
|
||||
url := strings.Replace(downloadURL, "XXX", newVersion, -1)
|
||||
err := os.Rename("LinuxPA", ".LinuxPA.old")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false
|
||||
}
|
||||
fil, err := os.Create("LinuxPA")
|
||||
fil.Chmod(0777)
|
||||
defer fil.Close()
|
||||
if err != nil {
|
||||
os.Rename(".LinuxPA.old", "LinuxPA")
|
||||
return false
|
||||
}
|
||||
check := http.Client{
|
||||
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||
r.URL.Opaque = r.URL.Path
|
||||
return nil
|
||||
},
|
||||
}
|
||||
re, err := check.Get(url)
|
||||
defer re.Body.Close()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_, err = io.Copy(fil, re.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user