6 Commits

Author SHA1 Message Date
Belac Darkstorm 34b8f7c926 Forgot to implement updating 2017-04-03 09:23:41 -05:00
Belac Darkstorm 5d5cedec58 Ready to test then bug fix :)
Also, I'm ALIVE!!!!
2017-04-03 09:17:49 -05:00
Belac Darkstorm 8441a8b752 Working on an auto-update mechanism 2017-04-03 08:23:25 -05:00
Belac Darkstorm d64d88e0a5 Tries to make PortableApps folder before failing 2016-09-23 14:32:30 -05:00
Belac Darkstorm 5eeb9cc702 Fixed some bugs (oops) 2016-09-22 20:25:26 -05:00
Belac Darkstorm fc3411e568 Added Button to launch PortableApps.com launcher. Added back common.sh support (oops) 2016-09-22 08:39:56 -05:00
6 changed files with 240 additions and 27 deletions
+8 -3
View File
@@ -2,10 +2,15 @@
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux. LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
# How to use # 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 # 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. 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
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). 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. 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 # 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 # Screenshots
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6) 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. Add updater for .AppImage files
1. Download .AppImage files (maybe) 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. 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)
+21 -8
View File
@@ -3,7 +3,7 @@ package main
import ( import (
"os" "os"
"os/exec" "os/exec"
"sort" "strings"
"github.com/nelsam/gxui" "github.com/nelsam/gxui"
"github.com/nelsam/gxui/math" "github.com/nelsam/gxui/math"
@@ -28,7 +28,7 @@ type appExNode struct {
func (a *appExNode) launch() { func (a *appExNode) launch() {
if wine { if wine {
var cmd *exec.Cmd 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]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[a.exInd]+"\"")
} else { } else {
if comEnbld { if comEnbld {
@@ -93,11 +93,10 @@ type appNode struct {
} }
func (a *appNode) launch() { func (a *appNode) launch() {
if len(a.ap.ex) == 1 { if len(a.ap.ex) == 1 {
if wine { if wine {
var cmd *exec.Cmd 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]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
} else { } else {
if comEnbld { if comEnbld {
@@ -126,10 +125,17 @@ func (a *appNode) launch() {
if len(a.ap.lin) == 0 { if len(a.ap.lin) == 0 {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
} else { } else {
var ind int
for i, v := range a.ap.lin {
if strings.HasSuffix(v, ".sh") {
ind = i
break
}
}
if comEnbld { 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 { } 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.Stdout = os.Stdout
@@ -137,11 +143,18 @@ func (a *appNode) launch() {
cmd.Start() cmd.Start()
} else { } else {
if len(a.ap.lin) != 0 { 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 var cmd *exec.Cmd
if comEnbld { 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 { } 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.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
+40 -1
View File
@@ -1,9 +1,17 @@
package main package main
import ( import (
"fmt"
"github.com/nelsam/gxui" "github.com/nelsam/gxui"
"github.com/nelsam/gxui/drivers/gl" "github.com/nelsam/gxui/drivers/gl"
"github.com/nelsam/gxui/themes/dark" "github.com/nelsam/gxui/themes/dark"
"github.com/nelsam/gxui/themes/light"
)
const (
version = "0.1.1.1"
defIni = "[basic]\ntheme=dk"
) )
var ( var (
@@ -15,9 +23,26 @@ var (
lin []string lin []string
wine bool wine bool
comEnbld bool comEnbld bool
darkTheme = true
) )
func main() { func main() {
stat := versionDL()
if stat {
res := getVersionFileInfo()
if res != "Error!" {
stat = checkForUpdate(res)
if stat {
downloadUpdate(res)
} else {
fmt.Println("Failed DL")
}
} else {
fmt.Println("Failed Version File Info")
}
} else {
fmt.Println("Failed Version DL")
}
master = make(map[string][]app) master = make(map[string][]app)
linmaster = make(map[string][]app) linmaster = make(map[string][]app)
gl.StartDriver(appMain) gl.StartDriver(appMain)
@@ -25,7 +50,21 @@ func main() {
func appMain(dri gxui.Driver) { func appMain(dri gxui.Driver) {
dr = dri dr = dri
th = dark.CreateTheme(dr)
setup() setup()
if darkTheme {
th = dark.CreateTheme(dr)
} else {
th = light.CreateTheme(dr)
}
th = dark.CreateTheme(dr)
ui() ui()
} }
func contains(arr []string, str string) bool {
for _, v := range arr {
if v == str {
return true
}
}
return false
}
+47 -13
View File
@@ -2,6 +2,7 @@ package main
import ( import (
"bufio" "bufio"
"fmt"
"image" "image"
"image/draw" "image/draw"
_ "image/png" _ "image/png"
@@ -13,10 +14,47 @@ import (
"github.com/nelsam/gxui" "github.com/nelsam/gxui"
) )
const ()
func setup() { func setup() {
PortableAppsFold, err := os.Open("PortableApps") PortableAppsFold, err := os.Open("PortableApps")
if PAStat, _ := PortableAppsFold.Stat(); err != nil || !PAStat.IsDir() { 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) PAFolds, _ := PortableAppsFold.Readdirnames(-1)
sort.Strings(PAFolds) sort.Strings(PAFolds)
@@ -28,23 +66,17 @@ func setup() {
if _, ok := master[ap.cat]; !ok { if _, ok := master[ap.cat]; !ok {
cats = append(cats, ap.cat) cats = append(cats, ap.cat)
sort.Strings(cats) sort.Strings(cats)
if len(ap.lin) != 0 {
lin = append(lin, ap.cat)
sort.Strings(lin)
} }
} else {
if len(ap.lin) != 0 { if len(ap.lin) != 0 {
ind := sort.SearchStrings(lin, ap.cat) if _, ok := linmaster[ap.cat]; !ok {
if ind == len(lin) {
lin = append(lin, ap.cat) lin = append(lin, ap.cat)
sort.Strings(lin) sort.Strings(lin)
} }
} }
} master[ap.cat] = append(master[ap.cat], ap)
if len(ap.lin) != 0 { if len(ap.lin) != 0 {
linmaster[ap.cat] = append(linmaster[ap.cat], ap) 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) btys := make([]byte, 4)
rdr := bufio.NewReader(tmp) rdr := bufio.NewReader(tmp)
rdr.Read(btys) 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.ex = append(out.ex, v)
out.lin = append(out.lin, v) out.lin = append(out.lin, v)
} }
@@ -137,9 +169,11 @@ func getIcon(fold string) gxui.Texture {
} }
sort.Strings(pics) sort.Strings(pics)
if len(pics) > 1 { if len(pics) > 1 {
ind := sort.SearchStrings(pics, "appicon_32.png") var ind int
if ind == len(pics) { if !contains(pics, "appicon_32.png") {
ind-- ind = len(pics) - 1
} else {
ind = sort.SearchStrings(pics, "appicon_32.png")
} }
pic, _ = os.Open(fold + "/App/AppInfo/" + pics[ind]) pic, _ = os.Open(fold + "/App/AppInfo/" + pics[ind])
} }
+13
View File
@@ -1,6 +1,7 @@
package main package main
import ( import (
"os"
"os/exec" "os/exec"
"github.com/nelsam/gxui" "github.com/nelsam/gxui"
@@ -44,6 +45,18 @@ func ui() {
wineBut.SetText("Show Windows Apps") 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) butBox.AddChild(wineBut)
} }
top.AddChild(butBox) top.AddChild(butBox)
+109
View File
@@ -0,0 +1,109 @@
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.Open("PortableApps/LinuxPACom/Version")
if err != nil {
versionFile, err = os.Create("PortableApps/LinuxPACom/Version")
if err != nil {
return false
}
}
defer versionFile.Close()
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)
defer response.Body.Close()
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")
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
}