Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2e91baa6b | |||
| a0f22e480b | |||
| 57f921c2cb | |||
| 55f897db46 | |||
| 3d9583281e | |||
| ec4d66f6b2 | |||
| c442ef5688 | |||
| 78d3723bf4 | |||
| 828b9f4cda | |||
| be64aa083f | |||
| 3111705cae | |||
| 868ae8f700 | |||
| 226e9d6210 | |||
| 56748f043e | |||
| 3d3239fe0a | |||
| 6e643b68ac | |||
| 539f33d25e | |||
| 4d3cb9f486 | |||
| a55c82483a | |||
| 9e9bb82025 | |||
| ea91d3cd80 | |||
| 2a0d53db09 | |||
| a0213d1886 | |||
| 695ce815d9 | |||
| 01556c1eb0 | |||
| d7410bb88f | |||
| bc63e6d10f | |||
| 0403825c3d | |||
| 0f1bb3fabd | |||
| 78c6842fab | |||
| dc1edbad3a | |||
| 6dd00c5f8f | |||
| e68337886f | |||
| 3b639f53fd | |||
| 3199ad88fd | |||
| a221d18d33 | |||
| a9eeb3bb1c | |||
| 844a282fd7 | |||
| 9da352a315 | |||
| 34b8f7c926 | |||
| 5d5cedec58 | |||
| 8441a8b752 | |||
| d64d88e0a5 | |||
| 5eeb9cc702 | |||
| fc3411e568 | |||
| 77ce9e8ad4 | |||
| 63dd8ebb83 | |||
| 7cf45c9ac8 | |||
| 2f8de0bed2 | |||
| 67ca030bb2 | |||
| da46399ded | |||
| e5d0b6a9a2 | |||
| f4ca2115d4 | |||
| 0cc7f8f445 | |||
| 767e894acd | |||
| 06e2afef1d | |||
| f614c14013 | |||
| 998c07b90b | |||
| 3d44c82e65 | |||
| 08a453b5d5 | |||
| be42963441 | |||
| 50ad374124 |
@@ -1,33 +1,39 @@
|
|||||||
# LinuxPA
|
# LinuxPA
|
||||||
The goal is to create a fully functional PortableApps.com type launcher that can properly parse data from the PortableApps.com format. Apps are launched by a .sh file in the app's directory. Currently pulls out the Name and Category from App/AppInfo/appinfo.ini
|
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
|
||||||
Works well with AppImage apps.
|
|
||||||
|
|
||||||
# Why?
|
# How to use
|
||||||
I know that Linux only has about 2% desktop usage and I know that the traditional way to install apps isn't portable, but over the past year or so I've started to put linux apps on my flash drive (AppImage is a great example of a portable solution to linux apps. Also a lot of DRM-free games can be run portably), but there was no easy way to organize my linux apps, so I created one. I personally have used the PortableApps.com launcher for years now and I love how properly formated the apps are, which allows me to grab info about the app easily.
|
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 it finds. .sh script files have priority over other executable files.
|
||||||
|
|
||||||
# Why script files?
|
# Apps:
|
||||||
In general linux executable files have no extensions and can be a pain when trying to figure out what is executable and what isn't. I figured script files are easy to detect and allow a large amount of flexibility for me (and others who want to make apps work with this launcher). See below for .AppImage support (Get AppImages from [here](https://bintray.com/probono/AppImages))
|
The below place provides linux executables that don't need libs installed on the host system:
|
||||||
|
[https://appimage.github.io/](https://appimage.github.io/)
|
||||||
|
|
||||||
# Why Go?
|
# PortableApps.com Compatibility
|
||||||
Because I like Go :) Also the way it includes all it needs into one friendly executable.
|
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).
|
||||||
# What is needed?
|
|
||||||
Basically you need go to compile the source, AND YOU ALSO NEED TO MOUNT YOUR FLASH DRIVE SO YOU CAN EXECUTE FILES ON IT!!!! I've found that the mount arguments of `exec,noauto,nodev,nosuid,umask=0000` works well (I personally put my flash drive into /etc/fstab).
|
|
||||||
|
|
||||||
# Format
|
|
||||||
The first place the program looks for an app's icon and info is in the /App/AppInfo directory (icon defaults to appicon_32.png, otherwise it just picks the last one it finds), but if it can't find the appinfo.ini or app icon, it looks in the apps root directory for appinfo.ini and appicon.png for info and icon respectively(Just to make it easier for custom settings in an app).
|
|
||||||
|
|
||||||
# common.sh
|
# common.sh
|
||||||
common.sh is run before any program so you can set environment variables (such as HOME). common.sh should be in PortableApps/LinuxPACom folder.
|
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). You can create and edit the common.sh from settings
|
||||||
|
|
||||||
# AppImage support
|
# Simple App Setup
|
||||||
It will now launch .AppImage files! If a .sh script and an .AppImage executable are both in a directory, the .sh script takes precedence. You can get AppImages from [here](https://bintray.com/probono/AppImages).
|
Because apps aren't natively formated in the PortableApps.com format, LinuxPA will look in the root directory for a AppInfo.ini (for basic info such as category and name) and appicon.png. If they aren't found, it looks where the appicon_\*.png and AppInfo.ini is in PortableApps format. You can set what the AppInfo.ini and appicon.png are from LinuxPA.
|
||||||
|
|
||||||
|
# AppImage Support
|
||||||
|
[AppImage Website](http://appimage.org)
|
||||||
|
Right now AppImages are simply supported via the native linux executable support, and you can download AppImages. (Woo)
|
||||||
|
|
||||||
|
# USB mount
|
||||||
|
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). The screenshots are with the adapta gtk theme
|
||||||
|
|
||||||
# TODO (Might be in order)
|
# TODO (Might be in order)
|
||||||
1. MAKE IT BETTER
|
1. MAKE IT BETTER
|
||||||
1. Improve linux executable detection (A.K.A. a pain in the butt)
|
1. Manual update check
|
||||||
1. Launching of .exe files via wine (wine will have to be installed on the host system, unless there is some portable wine, I may have found one)
|
1. Better AppImage integrations (Specifically updating, getting information from the appimage, and better appimage downloading)
|
||||||
1. Add settings menu
|
1. Automagic appimage updating (It will of course ask you beforehand)
|
||||||
1. Add updater for .AppImage files
|
1. Get information (such as name and icon) directly from an appimage
|
||||||
1. Download .AppImage files (maybe)
|
1. Better appimage downloading (probably based around [AppImageHub](https://appimage.github.io/apps/))
|
||||||
1. Check if all apps are closed when it closes and ask if you want to force stop the apps.
|
1. Sandboxing support
|
||||||
|
1. Check if all apps are closed when it closes and ask if you want to force stop the apps
|
||||||
|
|||||||
@@ -0,0 +1,319 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gdk"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
type app struct {
|
||||||
|
name string
|
||||||
|
cat string
|
||||||
|
appimg []string
|
||||||
|
lin []string
|
||||||
|
ex []string
|
||||||
|
icon *gdk.Pixbuf
|
||||||
|
dir string
|
||||||
|
ini *os.File
|
||||||
|
wine bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) getTreeIter(store *gtk.TreeStore) *gtk.TreeIter {
|
||||||
|
it := store.Append(nil)
|
||||||
|
scaled, _ := a.icon.ScaleSimple(32, 32, gdk.INTERP_HYPER)
|
||||||
|
store.SetValue(it, 0, scaled)
|
||||||
|
if portableHide {
|
||||||
|
store.SetValue(it, 1, strings.TrimSuffix(a.name, "Portable"))
|
||||||
|
} else {
|
||||||
|
store.SetValue(it, 1, a.name)
|
||||||
|
}
|
||||||
|
if len(a.ex) > 1 {
|
||||||
|
if wine {
|
||||||
|
for _, v := range a.ex {
|
||||||
|
i := store.Append(it)
|
||||||
|
store.SetValue(i, 1, v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range a.lin {
|
||||||
|
i := store.Append(it)
|
||||||
|
store.SetValue(i, 1, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) launch() {
|
||||||
|
if len(a.ex) == 1 {
|
||||||
|
if wine {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if !contains(a.lin, a.ex[0]) {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[0]), ".appimage") {
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[0]+".home", 0777)
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[0]+".config", 0777)
|
||||||
|
}
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[0]), ".appimage") {
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[0]+".home", 0777)
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[0]+".config", 0777)
|
||||||
|
}
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if wine {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if len(a.lin) == 0 {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var ind int
|
||||||
|
for i, v := range a.lin {
|
||||||
|
if strings.HasSuffix(v, ".sh") {
|
||||||
|
ind = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[ind]), ".appimage") {
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[ind]+".home", 0777)
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[ind]+".config", 0777)
|
||||||
|
}
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[ind]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
if len(a.lin) != 0 {
|
||||||
|
var ind int
|
||||||
|
for i, v := range a.lin {
|
||||||
|
if strings.HasSuffix(v, ".sh") {
|
||||||
|
ind = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[ind]), ".appimage") {
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[ind]+".home", 0777)
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[ind]+".config", 0777)
|
||||||
|
}
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[ind]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) launchSub(sub int) {
|
||||||
|
if wine {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if !contains(a.lin, a.ex[sub]) {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[sub]), ".appimage") {
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[sub]+".home", 0777)
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[sub]+".config", 0777)
|
||||||
|
}
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[sub]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[sub]), ".appimage") {
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[sub]+".home", 0777)
|
||||||
|
os.Mkdir(a.dir+"/"+a.ex[sub]+".config", 0777)
|
||||||
|
}
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[sub]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) edit(parent *gtk.Window, reload func()) {
|
||||||
|
tmp := *a
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
master = make(map[string][]app)
|
||||||
|
linmaster = make(map[string][]app)
|
||||||
|
cats = make([]string, 0)
|
||||||
|
lin = make([]string, 0)
|
||||||
|
setup()
|
||||||
|
reload()
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
win.SetDefaultSize(400, 135)
|
||||||
|
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
topLvl.SetMarginStart(10)
|
||||||
|
topLvl.SetMarginEnd(10)
|
||||||
|
topLvl.SetMarginTop(10)
|
||||||
|
topLvl.SetMarginBottom(10)
|
||||||
|
top, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
|
img, _ := gtk.ImageNewFromPixbuf(a.icon)
|
||||||
|
imgBut, _ := gtk.ButtonNew()
|
||||||
|
imgBut.SetImage(img)
|
||||||
|
imgBut.SetSizeRequest(100, 100)
|
||||||
|
imgBut.Connect("clicked", func() {
|
||||||
|
fil, _ := gtk.FileChooserDialogNewWith1Button("Select Icon", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Open", gtk.RESPONSE_ACCEPT)
|
||||||
|
filter, _ := gtk.FileFilterNew()
|
||||||
|
filter.AddPixbufFormats()
|
||||||
|
filter.SetName("Supported Pictures")
|
||||||
|
fil.AddFilter(filter)
|
||||||
|
but, _ := fil.AddButton("Cancel", gtk.RESPONSE_CANCEL)
|
||||||
|
but.Connect("clicked", func() {
|
||||||
|
fil.Close()
|
||||||
|
})
|
||||||
|
resp := fil.Run()
|
||||||
|
if resp == gtk.RESPONSE_ACCEPT {
|
||||||
|
filename := fil.GetFilename()
|
||||||
|
_, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pix, _ := gdk.PixbufNewFromFileAtSize(filename, 32, 32)
|
||||||
|
tmp.icon = pix
|
||||||
|
img.SetFromPixbuf(pix)
|
||||||
|
fil.Close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
topRt, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
nameLbl, _ := gtk.LabelNew("Name:")
|
||||||
|
nameLbl.SetHAlign(gtk.ALIGN_START)
|
||||||
|
txtgtbl, _ := gtk.TextTagTableNew()
|
||||||
|
txtBuf, _ := gtk.TextBufferNew(txtgtbl)
|
||||||
|
nameTxt, _ := gtk.TextViewNewWithBuffer(txtBuf)
|
||||||
|
nameTxt.SetAcceptsTab(false)
|
||||||
|
nameTxt.SetWrapMode(gtk.WRAP_CHAR)
|
||||||
|
nameTxt.SetPixelsBelowLines(5)
|
||||||
|
nameTxt.SetHExpand(true)
|
||||||
|
nameTxt.SetVExpand(false)
|
||||||
|
nameTxt.SetBorderWindowSize(gtk.TEXT_WINDOW_BOTTOM, 5)
|
||||||
|
nameShow := tmp.name
|
||||||
|
if tmp.wine {
|
||||||
|
nameShow = strings.TrimSuffix(nameShow, " (Wine)")
|
||||||
|
}
|
||||||
|
txtBuf.SetText(nameShow)
|
||||||
|
vScrollName, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScrollName, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
nameScr, _ := gtk.ScrolledWindowNew(hScrollName, vScrollName)
|
||||||
|
nameScr.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
|
||||||
|
nameScr.SetSizeRequest(300, 25)
|
||||||
|
nameScr.SetVExpand(false)
|
||||||
|
nameScr.Add(nameTxt)
|
||||||
|
catLbl, _ := gtk.LabelNew("Category:")
|
||||||
|
catLbl.SetHAlign(gtk.ALIGN_START)
|
||||||
|
catTbl, _ := gtk.TextTagTableNew()
|
||||||
|
catBuf, _ := gtk.TextBufferNew(catTbl)
|
||||||
|
catTxt, _ := gtk.TextViewNewWithBuffer(catBuf)
|
||||||
|
catBuf.SetText(tmp.cat)
|
||||||
|
catTxt.SetAcceptsTab(false)
|
||||||
|
catTxt.SetWrapMode(gtk.WRAP_CHAR)
|
||||||
|
catTxt.SetPixelsBelowLines(5)
|
||||||
|
catTxt.SetHExpand(true)
|
||||||
|
catTxt.SetVExpand(false)
|
||||||
|
catTxt.SetBorderWindowSize(gtk.TEXT_WINDOW_BOTTOM, 5)
|
||||||
|
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
catScr, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
|
||||||
|
catScr.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
|
||||||
|
catScr.SetSizeRequest(300, 25)
|
||||||
|
catScr.SetVExpand(false)
|
||||||
|
catScr.Add(catTxt)
|
||||||
|
topRt.Add(nameLbl)
|
||||||
|
topRt.Add(nameScr)
|
||||||
|
topRt.Add(catLbl)
|
||||||
|
topRt.Add(catScr)
|
||||||
|
top.Add(imgBut)
|
||||||
|
top.Add(topRt)
|
||||||
|
bot, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
|
sv, _ := gtk.ButtonNewWithLabel("Save")
|
||||||
|
sv.Connect("clicked", func() {
|
||||||
|
tmp.name, _ = txtBuf.GetText(txtBuf.GetStartIter(), txtBuf.GetEndIter(), true)
|
||||||
|
tmp.cat, _ = catBuf.GetText(catBuf.GetStartIter(), catBuf.GetEndIter(), true)
|
||||||
|
tmp.makeIni()
|
||||||
|
os.Remove(a.dir + "/appicon.png")
|
||||||
|
tmp.icon.SavePNG(a.dir+"/appicon.png", 0)
|
||||||
|
win.Close()
|
||||||
|
})
|
||||||
|
cnl, _ := gtk.ButtonNewWithLabel("Cancel")
|
||||||
|
cnl.Connect("clicked", func() {
|
||||||
|
win.Close()
|
||||||
|
})
|
||||||
|
bot.PackEnd(sv, false, false, 0)
|
||||||
|
bot.PackEnd(cnl, false, false, 0)
|
||||||
|
topLvl.Add(top)
|
||||||
|
topLvl.Add(bot)
|
||||||
|
win.Add(topLvl)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) makeIni() {
|
||||||
|
os.Remove(a.dir + "/appinfo.ini")
|
||||||
|
fil, err := os.Create(a.dir + "/appinfo.ini")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ini := "[General]\n"
|
||||||
|
ini += "Category=" + a.cat + "\n"
|
||||||
|
ini += "Name=" + a.name + "\n"
|
||||||
|
wrt := bufio.NewWriter(fil)
|
||||||
|
wrt.WriteString(ini)
|
||||||
|
wrt.Flush()
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
func convert(in string) (out []tag) {
|
||||||
|
for i := 0; i < len(in); i++ {
|
||||||
|
v := in[i]
|
||||||
|
if v == '<' {
|
||||||
|
for j := i; j < len(in); j++ {
|
||||||
|
val := in[j]
|
||||||
|
if val == '>' {
|
||||||
|
var tmp tag
|
||||||
|
tmp.process(in[i+1 : j+1])
|
||||||
|
if !tmp.end && tmp.typ == "a" {
|
||||||
|
tmp.index[0] = i
|
||||||
|
tmp.index[1] = j
|
||||||
|
nd := fndend(tmp, in[j+1:])
|
||||||
|
if !reflect.DeepEqual(nd, tag{}) {
|
||||||
|
tmp.Meat = in[j+1 : nd.index[0]]
|
||||||
|
out = append(out, tmp)
|
||||||
|
str := in[tmp.index[1]:nd.index[0]]
|
||||||
|
in = in[:i] + str + in[nd.index[1]+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func fndend(fnt tag, area string) tag {
|
||||||
|
var count int
|
||||||
|
for i, v := range area {
|
||||||
|
if v == '<' {
|
||||||
|
for j, val := range area[i:] {
|
||||||
|
if val == '>' {
|
||||||
|
var tmp tag
|
||||||
|
tmp.process(area[i+1 : i+j+1])
|
||||||
|
if tmp.typ == fnt.typ {
|
||||||
|
if tmp.end {
|
||||||
|
if count == 0 {
|
||||||
|
tmp.index[0] = fnt.index[1] + 1 + i
|
||||||
|
tmp.index[1] = fnt.index[1] + j + i + 1
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
count--
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
count++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tag{}
|
||||||
|
}
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type tag struct {
|
||||||
|
typ string
|
||||||
|
end bool
|
||||||
|
params map[string]string
|
||||||
|
index [2]int
|
||||||
|
Meat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) value(param string) string {
|
||||||
|
return t.params[param]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) setValue(param, value string) {
|
||||||
|
if t.params == nil {
|
||||||
|
t.params = make(map[string]string)
|
||||||
|
}
|
||||||
|
t.params[strings.TrimSpace(strings.ToLower(param))] = strings.TrimSpace(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) process(bbtag string) {
|
||||||
|
if strings.HasPrefix(bbtag, "/") {
|
||||||
|
t.end = true
|
||||||
|
t.typ = strings.ToLower(strings.TrimPrefix(bbtag[:len(bbtag)-1], "/"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i, v := range bbtag {
|
||||||
|
if v == '=' || v == ' ' || v == '>' {
|
||||||
|
t.typ = strings.ToLower(bbtag[:i])
|
||||||
|
switch v {
|
||||||
|
case '=':
|
||||||
|
if qt := bbtag[i+1]; qt == '\'' || qt == '"' {
|
||||||
|
for j := i + 2; j < len(bbtag); j++ {
|
||||||
|
if bbtag[j] == qt {
|
||||||
|
t.setValue("starting", bbtag[i+2:j])
|
||||||
|
bbtag = bbtag[j+1:]
|
||||||
|
break
|
||||||
|
} else if bbtag[j] == '>' {
|
||||||
|
t.setValue("starting", bbtag[i+2:j])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for j := i + 1; j < len(bbtag); j++ {
|
||||||
|
if bbtag[j] == '>' {
|
||||||
|
t.setValue("starting", bbtag[i+1:j])
|
||||||
|
return
|
||||||
|
} else if bbtag[j] == ' ' {
|
||||||
|
t.setValue("starting", bbtag[i+1:j])
|
||||||
|
bbtag = bbtag[j+1:]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '>':
|
||||||
|
return
|
||||||
|
case ' ':
|
||||||
|
bbtag = bbtag[i:]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.processFurther(bbtag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) processFurther(further string) {
|
||||||
|
further = strings.TrimSpace(further)
|
||||||
|
for i := 0; i < len(further); i++ {
|
||||||
|
switch further[i] {
|
||||||
|
case ' ':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[:i])
|
||||||
|
further = strings.TrimSpace(further[i:])
|
||||||
|
i = -1
|
||||||
|
case '=':
|
||||||
|
if qt := further[i+1]; qt == '\'' || qt == '"' {
|
||||||
|
outloopqt:
|
||||||
|
for j := i + 2; j < len(further); j++ {
|
||||||
|
switch further[j] {
|
||||||
|
case '>':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+2:j])
|
||||||
|
return
|
||||||
|
case qt:
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+2:j])
|
||||||
|
further = strings.TrimSpace(further[j+1:])
|
||||||
|
i = -1
|
||||||
|
break outloopqt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outloop:
|
||||||
|
for j := i + 1; j < len(further); j++ {
|
||||||
|
switch further[j] {
|
||||||
|
case '>':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+1:j])
|
||||||
|
return
|
||||||
|
case ' ':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+1:j])
|
||||||
|
further = strings.TrimSpace(further[j:])
|
||||||
|
i = -1
|
||||||
|
break outloop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '>':
|
||||||
|
if i != 0 {
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[:i])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
type appimg struct {
|
||||||
|
full string
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApp(name string) appimg {
|
||||||
|
var out appimg
|
||||||
|
out.full = name
|
||||||
|
return out
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func downloadApp(parent *gtk.Window, ap appimg) {
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
spn, _ := gtk.SpinnerNew()
|
||||||
|
spn.Start()
|
||||||
|
lbl, _ := gtk.LabelNew("Downloading " + ap.full + "...")
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
box.SetMarginStart(10)
|
||||||
|
box.SetMarginEnd(10)
|
||||||
|
box.SetMarginTop(10)
|
||||||
|
box.SetMarginBottom(10)
|
||||||
|
box.Add(spn)
|
||||||
|
box.Add(lbl)
|
||||||
|
win.Add(box)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
go func(win *gtk.Window, ap appimg) {
|
||||||
|
defer win.Close()
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := check.Get(urlBase + ap.full)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
name := strings.Split(ap.full, "-")[0]
|
||||||
|
var foldName string
|
||||||
|
if _, err = os.Open("PortableApps/" + name + "Portable"); err == nil {
|
||||||
|
foldName = "PortableApps/" + name + "Portable"
|
||||||
|
} else if _, err = os.Open("PortableApps/" + name); err == nil {
|
||||||
|
foldName = "PortableApps/" + name
|
||||||
|
} else {
|
||||||
|
os.Mkdir("PortableApps/"+name+"Portable", 0777)
|
||||||
|
foldName = "PortableApps/" + name + "Portable"
|
||||||
|
}
|
||||||
|
os.Remove(foldName + "/" + ap.full)
|
||||||
|
fil, err := os.Create(foldName + "/" + ap.full)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
io.Copy(fil, resp.Body)
|
||||||
|
fil.Chmod(0777)
|
||||||
|
}(win, ap)
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
//Package appimg is for downloading new AppImages for LinuxPA
|
||||||
|
package appimg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
urlBase = "https://dl.bintray.com/probono/AppImages/"
|
||||||
|
)
|
||||||
|
|
||||||
|
//ShowUI shows the list of possible AppImages to be downloaded in a gtk.Window
|
||||||
|
func ShowUI(newestVersionOnly bool, clsFunc func()) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
clsFunc()
|
||||||
|
})
|
||||||
|
apps := make([]appimg, 0)
|
||||||
|
win.SetSizeRequest(400, 400)
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
appList, _ := gtk.ListBoxNew()
|
||||||
|
apch := make(chan appimg)
|
||||||
|
appList.SetHExpand(true)
|
||||||
|
appList.SetVExpand(true)
|
||||||
|
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
lst, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
|
||||||
|
lst.SetSizeRequest(170, 500)
|
||||||
|
lst.Add(appList)
|
||||||
|
box.Add(lst)
|
||||||
|
win.Add(box)
|
||||||
|
appList.Connect("row-activated", func() {
|
||||||
|
if appList.GetSelectedRow().GetIndex() >= 0 {
|
||||||
|
downloadApp(win, apps[appList.GetSelectedRow().GetIndex()])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
getList(win, apch)
|
||||||
|
go func(win *gtk.Window, apch chan appimg, list *gtk.ListBox) {
|
||||||
|
if newestVersionOnly {
|
||||||
|
imgs := make([]appimg, 0)
|
||||||
|
a := make(map[string][]appimg)
|
||||||
|
names := make([]string, 0)
|
||||||
|
for i := range apch {
|
||||||
|
imgs = append(imgs, i)
|
||||||
|
}
|
||||||
|
for i, v := range imgs {
|
||||||
|
sp := strings.Split(v.full, "-")
|
||||||
|
if len(sp) >= 2 {
|
||||||
|
vers := sp[1]
|
||||||
|
removeLetters(vers)
|
||||||
|
imgs[i].version = vers
|
||||||
|
imgs[i].name = sp[0]
|
||||||
|
if _, ok := a[imgs[i].name]; !ok {
|
||||||
|
names = append(names, imgs[i].name)
|
||||||
|
}
|
||||||
|
a[imgs[i].name] = append(a[imgs[i].name], imgs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
for _, name := range names {
|
||||||
|
glib.IdleAdd(func(name string, list *gtk.ListBox, i appimg) {
|
||||||
|
lbl, _ := gtk.LabelNew(name)
|
||||||
|
list.Add(lbl)
|
||||||
|
apps = append(apps, i)
|
||||||
|
lbl.Show()
|
||||||
|
}, name, list, a[name][compareVersions(a[name])])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := range apch {
|
||||||
|
glib.IdleAdd(func(list *gtk.ListBox, i appimg) {
|
||||||
|
lbl, _ := gtk.LabelNew(i.full)
|
||||||
|
list.Add(lbl)
|
||||||
|
apps = append(apps, i)
|
||||||
|
lbl.Show()
|
||||||
|
}, list, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(win, apch, appList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getList(parent *gtk.Window, apch chan appimg) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
win.SetDestroyWithParent(true)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
spin, _ := gtk.SpinnerNew()
|
||||||
|
spin.Start()
|
||||||
|
txt, _ := gtk.LabelNew("Getting List...")
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
box.SetMarginBottom(10)
|
||||||
|
box.SetMarginEnd(10)
|
||||||
|
box.SetMarginStart(10)
|
||||||
|
box.SetMarginTop(10)
|
||||||
|
box.Add(spin)
|
||||||
|
box.Add(txt)
|
||||||
|
win.Add(box)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
go func(win *gtk.Window, apch chan appimg) {
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := check.Get(urlBase)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
close(apch)
|
||||||
|
win.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
btys, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
close(apch)
|
||||||
|
win.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tgs := convert(string(btys))
|
||||||
|
for _, v := range tgs {
|
||||||
|
if strings.HasSuffix(strings.ToLower(v.Meat), ".appimage") {
|
||||||
|
apch <- newApp(v.Meat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(apch)
|
||||||
|
win.Close()
|
||||||
|
}(win, apch)
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func removeLetters(vers string) string {
|
||||||
|
vers = strings.ToLower(vers)
|
||||||
|
letters := []string{"abcdefghijklmnopqrstuvwxyz"}
|
||||||
|
for _, v := range letters {
|
||||||
|
vers = strings.Replace(vers, v, "", -1)
|
||||||
|
}
|
||||||
|
return vers
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func compareVersions(imgs []appimg) int {
|
||||||
|
for i := range imgs {
|
||||||
|
imgs[i].version = removeLetters(imgs[i].version)
|
||||||
|
}
|
||||||
|
highest := 0
|
||||||
|
higharr := strings.Split(imgs[0].version, ".")
|
||||||
|
for i := 0; i < len(imgs); i++ {
|
||||||
|
if i != highest {
|
||||||
|
varr := strings.Split(imgs[i].version, ".")
|
||||||
|
if len(higharr) < len(varr) {
|
||||||
|
for j := 0; j < len(higharr); j++ {
|
||||||
|
h, _ := strconv.Atoi(higharr[j])
|
||||||
|
c, _ := strconv.Atoi(varr[j])
|
||||||
|
if h > c {
|
||||||
|
break
|
||||||
|
} else if c > h {
|
||||||
|
highest = i
|
||||||
|
higharr = varr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return highest
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
module github.com/CalebQ42/LinuxPA
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/CalebQ42/GoAppImage v0.1.1
|
||||||
|
github.com/gotk3/gotk3 v0.5.0
|
||||||
|
github.com/mholt/archiver/v3 v3.5.0
|
||||||
|
)
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo=
|
||||||
|
github.com/adrg/xdg v0.2.2/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ=
|
||||||
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||||
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||||
|
github.com/alokmenghrajani/gpgeez v0.0.0-20161206084504-1a06f1c582f9 h1:Zio/mdDEpJDG1yeH9y2Kcb9ATWXkE7WIBkO+IMqRbbM=
|
||||||
|
github.com/alokmenghrajani/gpgeez v0.0.0-20161206084504-1a06f1c582f9/go.mod h1:u65XFfs2+s//7QVkp5Q1NEZl4zVep2BtubxiSXJERN8=
|
||||||
|
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
|
||||||
|
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||||
|
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||||
|
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0=
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||||
|
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||||
|
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||||
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||||
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
|
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||||
|
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gotk3/gotk3 v0.5.0 h1:GOkq4cFgAfeK6YAukLi64bz8zPayZKeCSSRr4mcFReQ=
|
||||||
|
github.com/gotk3/gotk3 v0.5.0/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||||
|
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||||
|
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
|
||||||
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
|
github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
|
||||||
|
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
|
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
|
||||||
|
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE=
|
||||||
|
github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
||||||
|
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
|
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||||
|
github.com/pierrec/lz4/v4 v4.0.3 h1:vNQKSVZNYUEAvRY9FaUXAF1XPbSOHJtDTiP41kzDz2E=
|
||||||
|
github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||||
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||||
|
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
|
github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
|
||||||
|
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
|
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
|
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||||
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||||
|
go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo=
|
||||||
|
go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I=
|
||||||
|
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
||||||
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||||
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0=
|
||||||
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||||
|
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
||||||
|
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||||
|
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
|
||||||
|
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||||
|
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
|
||||||
|
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
@@ -1,127 +1,61 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nelsam/gxui/drivers/gl"
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
version = "2.1.5.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
appMaster map[string][]prtap
|
master map[string][]app
|
||||||
|
linmaster map[string][]app
|
||||||
cats []string
|
cats []string
|
||||||
conf *os.File
|
lin []string
|
||||||
common string
|
comEnbld bool
|
||||||
commEnbl bool
|
populated bool
|
||||||
)
|
)
|
||||||
|
|
||||||
type prtap struct {
|
|
||||||
name string
|
|
||||||
cat string
|
|
||||||
ex string
|
|
||||||
desc string
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
commEnbl = true
|
forced := flag.Bool("force-update", false, "Force the update dialog to be shown")
|
||||||
appMaster = make(map[string][]prtap)
|
flag.Parse()
|
||||||
os.Mkdir("PortableApps", 0777)
|
os.MkdirAll("PortableApps/LinuxPACom", 0777)
|
||||||
os.Mkdir("PortableApps/LinuxPACom", 0777)
|
master = make(map[string][]app)
|
||||||
common = "PortableApps/LinuxPACom/common.sh"
|
linmaster = make(map[string][]app)
|
||||||
_, err := os.Open(common)
|
uiStart(*forced)
|
||||||
if os.IsNotExist(err) {
|
}
|
||||||
commEnbl = false
|
|
||||||
}
|
func uiStart(forced bool) {
|
||||||
pa, err := os.Open("PortableApps")
|
gtk.Init(nil)
|
||||||
|
setup()
|
||||||
|
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
fmt.Println("Window not created", err)
|
||||||
}
|
}
|
||||||
appstmp, _ := pa.Readdir(-1)
|
win.SetTitle("LinuxPA")
|
||||||
var folds []string
|
win.Connect("destroy", func() {
|
||||||
for _, v := range appstmp {
|
savePrefs()
|
||||||
if v.IsDir() && v.Name() != "LinuxPACom" {
|
gtk.MainQuit()
|
||||||
folds = append(folds, v.Name())
|
})
|
||||||
}
|
win.SetDefaultSize(500, 500)
|
||||||
}
|
win.SetPosition(gtk.WIN_POS_CENTER)
|
||||||
sort.Strings(folds)
|
ui(win)
|
||||||
for _, v := range folds {
|
win.ShowAll()
|
||||||
fi, _ := os.Open("PortableApps/" + v)
|
win.Show()
|
||||||
pat := processApp(fi)
|
update(win, forced)
|
||||||
if (pat != prtap{}) {
|
gtk.Main()
|
||||||
if _, ok := appMaster[pat.cat]; !ok {
|
|
||||||
cats = append(cats, pat.cat)
|
|
||||||
}
|
|
||||||
appMaster[pat.cat] = append(appMaster[pat.cat], pat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gl.StartDriver(uiMain)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func processApp(fi *os.File) (out prtap) {
|
func contains(arr []string, str string) bool {
|
||||||
fis, _ := fi.Readdir(-1)
|
for _, v := range arr {
|
||||||
if fil, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini"); err == nil {
|
if v == str {
|
||||||
out.name = getName(fil)
|
return true
|
||||||
fil, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini")
|
|
||||||
out.cat = getCat(fil)
|
|
||||||
} else if fil, err := os.Open(fi.Name() + "/appinfo.ini"); err == nil {
|
|
||||||
out.name = getName(fil)
|
|
||||||
fil, _ = os.Open(fi.Name() + "/appinfo.ini")
|
|
||||||
out.cat = getCat(fil)
|
|
||||||
} else {
|
|
||||||
out.cat = "other"
|
|
||||||
}
|
|
||||||
if out.name == "" {
|
|
||||||
out.name = path.Base(fi.Name())
|
|
||||||
}
|
|
||||||
if out.cat == "" {
|
|
||||||
out.cat = "other"
|
|
||||||
}
|
|
||||||
for _, v := range fis {
|
|
||||||
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".sh") {
|
|
||||||
//do os check here for possible cross platform support
|
|
||||||
out.ex = fi.Name() + "/" + v.Name()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, v := range fis {
|
return false
|
||||||
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".appimage") {
|
|
||||||
//do os check here for possible cross platform support
|
|
||||||
out.ex = fi.Name() + "/" + v.Name()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prtap{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCat(fi *os.File) (out string) {
|
|
||||||
rdr := bufio.NewReader(fi)
|
|
||||||
var err error
|
|
||||||
var ln []byte
|
|
||||||
for err == nil {
|
|
||||||
ln, _, err = rdr.ReadLine()
|
|
||||||
str := string(ln)
|
|
||||||
if strings.HasPrefix(str, "Category=") {
|
|
||||||
out = strings.TrimPrefix(str, "Category=")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getName(fi *os.File) (out string) {
|
|
||||||
rdr := bufio.NewReader(fi)
|
|
||||||
var err error
|
|
||||||
var ln []byte
|
|
||||||
for err == nil {
|
|
||||||
ln, _, err = rdr.ReadLine()
|
|
||||||
str := string(ln)
|
|
||||||
if strings.HasPrefix(str, "Name=") {
|
|
||||||
out = strings.TrimPrefix(str, "Name=")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
wine bool
|
||||||
|
wineAvail bool
|
||||||
|
portableHide bool
|
||||||
|
betaUpdate bool
|
||||||
|
versionNewest = true
|
||||||
|
paDirs = true
|
||||||
|
)
|
||||||
|
|
||||||
|
func savePrefs() {
|
||||||
|
os.Remove("PortableApps/LinuxPACom/Prefs.gob")
|
||||||
|
fil, err := os.Create("PortableApps/LinuxPACom/Prefs.gob")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
enc := gob.NewEncoder(fil)
|
||||||
|
err = enc.Encode(wine)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = enc.Encode(portableHide)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = enc.Encode(versionNewest)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = enc.Encode(paDirs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = enc.Encode(betaUpdate)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadPrefs() {
|
||||||
|
fil, err := os.Open("PortableApps/LinuxPACom/Prefs.gob")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dec := gob.NewDecoder(fil)
|
||||||
|
err = dec.Decode(&wine)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = dec.Decode(&portableHide)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = dec.Decode(&versionNewest)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = dec.Decode(&paDirs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = dec.Decode(&betaUpdate)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
-103
@@ -1,103 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image"
|
|
||||||
"image/draw"
|
|
||||||
_ "image/png"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nelsam/gxui"
|
|
||||||
"github.com/nelsam/gxui/math"
|
|
||||||
)
|
|
||||||
|
|
||||||
type prtapAdap struct {
|
|
||||||
gxui.AdapterBase
|
|
||||||
apps []prtap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) SetApps(apps []prtap) {
|
|
||||||
p.apps = apps
|
|
||||||
p.DataChanged(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) Count() int {
|
|
||||||
return len(p.apps)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) Create(th gxui.Theme, index int) gxui.Control {
|
|
||||||
box := th.CreateLinearLayout()
|
|
||||||
box.SetPadding(math.CreateSpacing(2))
|
|
||||||
box.SetDirection(gxui.LeftToRight)
|
|
||||||
box.SetVerticalAlignment(gxui.AlignMiddle)
|
|
||||||
dir := path.Dir(p.apps[index].ex)
|
|
||||||
if fold, err := os.Open(dir + "/App/AppInfo"); err == nil {
|
|
||||||
var pics []string
|
|
||||||
fi, _ := fold.Readdirnames(-1)
|
|
||||||
for _, v := range fi {
|
|
||||||
if strings.HasPrefix(v, "appicon_") && strings.HasSuffix(v, ".png") {
|
|
||||||
pics = append(pics, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(pics) > 0 {
|
|
||||||
ind := sort.SearchStrings(pics, "appicon_128.png")
|
|
||||||
if ind == len(pics) {
|
|
||||||
ind = len(pics) - 1
|
|
||||||
}
|
|
||||||
imgfi, _ := os.Open(dir + "/App/AppInfo/" + pics[ind])
|
|
||||||
img, _, err := image.Decode(imgfi)
|
|
||||||
if err == nil {
|
|
||||||
rgba := image.NewRGBA(img.Bounds())
|
|
||||||
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
|
|
||||||
tex := dr.CreateTexture(rgba, 1)
|
|
||||||
icon := th.CreateImage()
|
|
||||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
|
||||||
icon.SetTexture(tex)
|
|
||||||
box.AddChild(icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if fi, err := os.Open(dir + "/appicon.png"); err == nil {
|
|
||||||
img, _, err := image.Decode(fi)
|
|
||||||
if err == nil {
|
|
||||||
rgba := image.NewRGBA(img.Bounds())
|
|
||||||
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
|
|
||||||
tex := dr.CreateTexture(rgba, 1)
|
|
||||||
icon := th.CreateImage()
|
|
||||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
|
||||||
icon.SetTexture(tex)
|
|
||||||
box.AddChild(icon)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Creating empty Image so that names line up
|
|
||||||
icon := th.CreateImage()
|
|
||||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
|
||||||
box.AddChild(icon)
|
|
||||||
}
|
|
||||||
lbl := th.CreateLabel()
|
|
||||||
lbl.SetText(p.apps[index].name)
|
|
||||||
box.AddChild(lbl)
|
|
||||||
return box
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) ItemAt(index int) gxui.AdapterItem {
|
|
||||||
return p.apps[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) ItemIndex(item gxui.AdapterItem) int {
|
|
||||||
it, ok := item.(prtap)
|
|
||||||
if !ok {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
for i, v := range p.apps {
|
|
||||||
if v == it {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) Size(gxui.Theme) math.Size {
|
|
||||||
return math.Size{W: math.MaxSize.W, H: 36}
|
|
||||||
}
|
|
||||||
+206
@@ -0,0 +1,206 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
commonHelp = "The common.sh is run before every app is launched and allows you to set variables such as $HOME. For directories, ALWAYS start the directory with $PWD which points to the directory where LinuxPA is. To allow for greater customization and isolation, you can use the $FILENAME variable which is the filename of the executable you're using and the $APPNAME variable which is the name of the app being lanched."
|
||||||
|
)
|
||||||
|
|
||||||
|
func settingsUI(parent *gtk.Window, onExit func()) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
win.SetDefaultSize(600, 300)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
savePrefs()
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
onExit()
|
||||||
|
})
|
||||||
|
comTagTbl, _ := gtk.TextTagTableNew()
|
||||||
|
comBuf, _ := gtk.TextBufferNew(comTagTbl)
|
||||||
|
ntbk, _ := gtk.NotebookNew()
|
||||||
|
gnrl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
gnrl.SetMarginStart(10)
|
||||||
|
gnrl.SetMarginEnd(10)
|
||||||
|
gnrl.SetMarginTop(10)
|
||||||
|
gnrl.SetMarginBottom(10)
|
||||||
|
dlWine, _ := gtk.ButtonNewWithLabel("Download Wine")
|
||||||
|
wineCheck, _ := gtk.CheckButtonNewWithLabel("Show Windows apps (Wine)")
|
||||||
|
wineLbl, _ := gtk.LabelNew("PortableApps/LinuxPACom/Wine present")
|
||||||
|
dlWine.Connect("clicked", func() {
|
||||||
|
cb := make(chan bool)
|
||||||
|
downloadWine(win, cb)
|
||||||
|
go func() {
|
||||||
|
v := <-cb
|
||||||
|
if v {
|
||||||
|
setupTxt(comBuf)
|
||||||
|
wineLbl.Show()
|
||||||
|
}
|
||||||
|
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); os.IsNotExist(err) {
|
||||||
|
if _, errd := exec.LookPath("wine"); errd == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
glib.IdleAdd(func() {
|
||||||
|
if !wineAvail {
|
||||||
|
wineCheck.SetSensitive(false)
|
||||||
|
wineCheck.SetTooltipText("Download wine to run windows apps")
|
||||||
|
} else {
|
||||||
|
wineCheck.SetSensitive(true)
|
||||||
|
wineCheck.SetTooltipText("")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
if !comEnbld {
|
||||||
|
dlWine.SetSensitive(false)
|
||||||
|
dlWine.SetTooltipText("common.sh needed")
|
||||||
|
}
|
||||||
|
pthdCheck, _ := gtk.CheckButtonNewWithLabel("Hide \"Portable\" from app name")
|
||||||
|
pthdCheck.Connect("toggled", func() {
|
||||||
|
portableHide = pthdCheck.GetActive()
|
||||||
|
master = make(map[string][]app)
|
||||||
|
linmaster = make(map[string][]app)
|
||||||
|
cats = make([]string, 0)
|
||||||
|
lin = make([]string, 0)
|
||||||
|
setup()
|
||||||
|
})
|
||||||
|
pthdCheck.SetActive(portableHide)
|
||||||
|
if !wineAvail {
|
||||||
|
wineCheck.SetSensitive(false)
|
||||||
|
wineCheck.SetTooltipText("Download wine to run windows apps")
|
||||||
|
}
|
||||||
|
wineCheck.SetActive(wine)
|
||||||
|
wineCheck.Connect("toggled", func() {
|
||||||
|
wine = wineCheck.GetActive()
|
||||||
|
})
|
||||||
|
versCheck, _ := gtk.CheckButtonNewWithLabel("Only show newest app version in downloads (A bit iffy ATM)")
|
||||||
|
versCheck.SetActive(versionNewest)
|
||||||
|
versCheck.Connect("toggled", func() {
|
||||||
|
versionNewest = versCheck.GetActive()
|
||||||
|
})
|
||||||
|
paDirsCheck, _ := gtk.CheckButtonNewWithLabel("Create .home and .config directories for AppImages")
|
||||||
|
paDirsCheck.SetActive(paDirs)
|
||||||
|
paDirsCheck.Connect("toggled", func() {
|
||||||
|
paDirs = paDirsCheck.GetActive()
|
||||||
|
})
|
||||||
|
betaCheck, _ := gtk.CheckButtonNewWithLabel("Update to beta releases")
|
||||||
|
gnrl.Add(wineLbl)
|
||||||
|
gnrl.Add(dlWine)
|
||||||
|
gnrl.Add(pthdCheck)
|
||||||
|
gnrl.Add(wineCheck)
|
||||||
|
gnrl.Add(versCheck)
|
||||||
|
gnrl.Add(paDirsCheck)
|
||||||
|
gnrl.Add(betaCheck)
|
||||||
|
ntbk.AppendPage(gnrl, getLabel("General"))
|
||||||
|
com, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
com.SetMarginStart(10)
|
||||||
|
com.SetMarginEnd(10)
|
||||||
|
com.SetMarginTop(10)
|
||||||
|
com.SetMarginBottom(10)
|
||||||
|
comEdit, _ := gtk.TextViewNewWithBuffer(comBuf)
|
||||||
|
comEdit.SetVExpand(true)
|
||||||
|
comEdit.SetHExpand(true)
|
||||||
|
vScroll, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScroll, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
comScrl, _ := gtk.ScrolledWindowNew(hScroll, vScroll)
|
||||||
|
comScrl.Add(comEdit)
|
||||||
|
svBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
|
sv, _ := gtk.ButtonNewWithLabel("Save")
|
||||||
|
sv.Connect("clicked", func() {
|
||||||
|
beg, end := comBuf.GetBounds()
|
||||||
|
txt, _ := comBuf.GetText(beg, end, true)
|
||||||
|
ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", []byte(txt), 0777)
|
||||||
|
})
|
||||||
|
cnl, _ := gtk.ButtonNewWithLabel("Cancel")
|
||||||
|
cnl.Connect("clicked", func() {
|
||||||
|
setupTxt(comBuf)
|
||||||
|
})
|
||||||
|
info, _ := gtk.ButtonNewWithLabel("Info")
|
||||||
|
info.Connect("clicked", func() {
|
||||||
|
infoBox, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
infoBox.SetTransientFor(parent)
|
||||||
|
infoBox.SetDefaultSize(300, 80)
|
||||||
|
infoBox.SetName("common.sh info")
|
||||||
|
infoBox.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
infolbl, _ := gtk.LabelNew(commonHelp)
|
||||||
|
infolbl.SetLineWrap(true)
|
||||||
|
infolbl.SetSizeRequest(200, 50)
|
||||||
|
box.Add(infolbl)
|
||||||
|
infoBox.Add(box)
|
||||||
|
infoBox.ShowAll()
|
||||||
|
infoBox.Show()
|
||||||
|
})
|
||||||
|
svBox.Add(sv)
|
||||||
|
svBox.Add(cnl)
|
||||||
|
svBox.Add(info)
|
||||||
|
com.Add(comScrl)
|
||||||
|
com.Add(svBox)
|
||||||
|
ntbk.AppendPage(com, getLabel("common.sh"))
|
||||||
|
win.Add(ntbk)
|
||||||
|
win.ShowAll()
|
||||||
|
if !comEnbld {
|
||||||
|
comScrl.Hide()
|
||||||
|
svBox.Hide()
|
||||||
|
mkCom, _ := gtk.ButtonNewWithLabel("Create common.sh")
|
||||||
|
mkCom.Connect("clicked", func() {
|
||||||
|
err := ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", []byte("export HOME=$PWD/PortableApps/LinuxPACom/Home"), 0777)
|
||||||
|
if err == nil {
|
||||||
|
mkCom.Hide()
|
||||||
|
comScrl.Show()
|
||||||
|
svBox.Show()
|
||||||
|
setupTxt(comBuf)
|
||||||
|
comEnbld = true
|
||||||
|
dlWine.SetSensitive(true)
|
||||||
|
dlWine.SetTooltipText("")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
in, _ := gtk.ButtonNewWithLabel("Info")
|
||||||
|
in.Connect("clicked", func() {
|
||||||
|
infoBox, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
infoBox.SetTransientFor(parent)
|
||||||
|
infoBox.SetDefaultSize(300, 80)
|
||||||
|
infoBox.SetName("common.sh info")
|
||||||
|
infoBox.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
infolbl, _ := gtk.LabelNew(commonHelp)
|
||||||
|
infolbl.SetLineWrap(true)
|
||||||
|
infolbl.SetSizeRequest(200, 50)
|
||||||
|
box.Add(infolbl)
|
||||||
|
infoBox.Add(box)
|
||||||
|
infoBox.ShowAll()
|
||||||
|
infoBox.Show()
|
||||||
|
})
|
||||||
|
mkCom.Show()
|
||||||
|
com.Add(mkCom)
|
||||||
|
com.Add(in)
|
||||||
|
} else {
|
||||||
|
setupTxt(comBuf)
|
||||||
|
}
|
||||||
|
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); err != nil && os.IsNotExist(err) {
|
||||||
|
wineLbl.Hide()
|
||||||
|
}
|
||||||
|
win.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTxt(buf *gtk.TextBuffer) {
|
||||||
|
fil, _ := os.Open("PortableApps/LinuxPACom/common.sh")
|
||||||
|
btys, _ := ioutil.ReadAll(fil)
|
||||||
|
buf.SetText(string(btys))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLabel(name string) *gtk.Label {
|
||||||
|
lbl, _ := gtk.LabelNew(name)
|
||||||
|
return lbl
|
||||||
|
}
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
_ "image/png"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
goappimage "github.com/CalebQ42/GoAppImage"
|
||||||
|
"github.com/gotk3/gotk3/gdk"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
loadPrefs()
|
||||||
|
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); os.IsNotExist(err) {
|
||||||
|
if _, errd := exec.LookPath("wine"); errd == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
if !wineAvail {
|
||||||
|
wine = false
|
||||||
|
}
|
||||||
|
PortableAppsFold, err := os.Open("PortableApps")
|
||||||
|
if PAStat, _ := PortableAppsFold.Stat(); err != nil || !PAStat.IsDir() {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
_, err = os.Open("PortableApps/LinuxPACom/common.sh")
|
||||||
|
if err == nil {
|
||||||
|
comEnbld = true
|
||||||
|
}
|
||||||
|
PAFolds, _ := PortableAppsFold.Readdirnames(-1)
|
||||||
|
sort.Strings(PAFolds)
|
||||||
|
for _, v := range PAFolds {
|
||||||
|
fold, _ := os.Open("PortableApps/" + v)
|
||||||
|
if stat, _ := fold.Stat(); stat.IsDir() && stat.Name() != "PortableApps.com" && stat.Name() != "LinuxPACom" {
|
||||||
|
ap := processApp("PortableApps/" + v)
|
||||||
|
if !reflect.DeepEqual(ap, app{}) {
|
||||||
|
if _, ok := master[ap.cat]; !ok {
|
||||||
|
cats = append(cats, ap.cat)
|
||||||
|
sort.Strings(cats)
|
||||||
|
}
|
||||||
|
if len(ap.lin) != 0 {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
populated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func processApp(fold string) (out app) {
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
out.dir = wd + "/" + fold
|
||||||
|
folder, _ := os.Open(fold)
|
||||||
|
fis, _ := folder.Readdirnames(-1)
|
||||||
|
for _, v := range fis {
|
||||||
|
tmp, _ := os.Open(fold + "/" + v)
|
||||||
|
if stat, _ := tmp.Stat(); stat.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(strings.ToLower(v), ".appimage") {
|
||||||
|
out.appimg = append(out.appimg, v)
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
out.lin = append(out.lin, v)
|
||||||
|
} else if strings.HasSuffix(strings.ToLower(v), ".exe") {
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
} else {
|
||||||
|
btys := make([]byte, 4)
|
||||||
|
rdr := bufio.NewReader(tmp)
|
||||||
|
rdr.Read(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(out.ex) == 0 {
|
||||||
|
return app{}
|
||||||
|
}
|
||||||
|
if len(out.lin) == 0 {
|
||||||
|
out.name += " (Wine)"
|
||||||
|
out.wine = true
|
||||||
|
}
|
||||||
|
out.icon = getIcon(fold)
|
||||||
|
out.ini = findInfo(fold)
|
||||||
|
if out.ini != nil {
|
||||||
|
out.name = getName(out.ini)
|
||||||
|
out.cat = getCat(out.ini)
|
||||||
|
}
|
||||||
|
if len(out.appimg) > 0 && out.name == "" && out.cat == "" && out.icon == nil {
|
||||||
|
os.Mkdir(out.dir+"/.appimageconfig", 0777)
|
||||||
|
ai := goappimage.NewAppImage(out.dir + "/" + out.appimg[0])
|
||||||
|
fil, err := os.Open(out.dir + "/.appimageconfig/the.md5")
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
ai.ExtractFile("*.desktop", out.dir+"/.appimageconfig/", false)
|
||||||
|
appimageconfig, _ := os.Open(out.dir + "/.appimageconfig")
|
||||||
|
appdirs, _ := appimageconfig.Readdirnames(-1)
|
||||||
|
for _, dirs := range appdirs {
|
||||||
|
desktopFil, _ := os.Open(out.dir + "/.appimageconfig/" + dirs)
|
||||||
|
if stat, _ := desktopFil.Stat(); strings.HasSuffix(dirs, ".desktop") && !stat.IsDir() {
|
||||||
|
os.Rename(out.dir+"/.appimageconfig/"+dirs, out.dir+"/.appimageconfig/the.desktop")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
desk, _ := os.Open(out.dir + "/.appimageconfig/the.desktop")
|
||||||
|
name, cat, icon := extractDesktopInfo(desk)
|
||||||
|
if out.name == "" {
|
||||||
|
out.name = name
|
||||||
|
}
|
||||||
|
if out.cat == "" {
|
||||||
|
out.cat = cat
|
||||||
|
}
|
||||||
|
if out.icon == nil {
|
||||||
|
it, _ := gtk.IconThemeGetDefault()
|
||||||
|
out.icon, err = it.LoadIcon(icon, 64, gtk.ICON_LOOKUP_GENERIC_FALLBACK)
|
||||||
|
}
|
||||||
|
fil, _ = os.Create(out.dir + "/.appimageconfig/the.md5")
|
||||||
|
wrtr := bufio.NewWriter(fil)
|
||||||
|
wrtr.WriteString(ai.Md5)
|
||||||
|
wrtr.Flush()
|
||||||
|
} else {
|
||||||
|
rdr := bufio.NewReader(fil)
|
||||||
|
filMd, _, _ := rdr.ReadLine()
|
||||||
|
oldMd := string(filMd)
|
||||||
|
if oldMd != ai.Md5 {
|
||||||
|
ai.ExtractFile("*.desktop", out.dir+"/.appimageconfig/", false)
|
||||||
|
appimageconfig, _ := os.Open(out.dir + "/.appimageconfig")
|
||||||
|
appdirs, _ := appimageconfig.Readdirnames(-1)
|
||||||
|
for _, dirs := range appdirs {
|
||||||
|
desktopFil, _ := os.Open(out.dir + "/.appimageconfig/" + dirs)
|
||||||
|
if stat, _ := desktopFil.Stat(); strings.HasSuffix(dirs, ".desktop") && !stat.IsDir() {
|
||||||
|
os.Rename(out.dir+"/.appimageconfig/"+dirs, out.dir+"/.appimageconfig/the.desktop")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Remove(out.dir + "/.appimageconfig/the.md5")
|
||||||
|
fil, _ = os.Create(out.dir + "/.appimageconfig/the.md5")
|
||||||
|
wrtr := bufio.NewWriter(fil)
|
||||||
|
wrtr.WriteString(ai.Md5)
|
||||||
|
wrtr.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
desk, _ := os.Open(out.dir + "/.appimageconfig/the.desktop")
|
||||||
|
name, cat, icon := extractDesktopInfo(desk)
|
||||||
|
if out.name == "" {
|
||||||
|
out.name = name
|
||||||
|
}
|
||||||
|
if out.cat == "" {
|
||||||
|
out.cat = cat
|
||||||
|
}
|
||||||
|
if out.icon == nil {
|
||||||
|
it, _ := gtk.IconThemeGetDefault()
|
||||||
|
out.icon, err = it.LoadIcon(icon, 32, gtk.ICON_LOOKUP_GENERIC_FALLBACK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if out.name == "" {
|
||||||
|
out.name = strings.TrimPrefix(fold, "PortableApps/")
|
||||||
|
}
|
||||||
|
if out.cat == "" {
|
||||||
|
out.cat = "Other"
|
||||||
|
}
|
||||||
|
if portableHide {
|
||||||
|
out.name = strings.TrimSuffix(out.name, "Portable")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCat(ini *os.File) string {
|
||||||
|
rdr := bufio.NewReader(ini)
|
||||||
|
var ret string
|
||||||
|
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
|
||||||
|
if strings.HasPrefix(string(line), "Category=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "Category=")
|
||||||
|
break
|
||||||
|
} else if strings.HasPrefix(string(line), "category=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "category=")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdr.Reset(ini)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractDesktopInfo(desk *os.File) (name, category, iconName string) {
|
||||||
|
rdr := bufio.NewReader(desk)
|
||||||
|
var nameGot, catGot, iconGot bool
|
||||||
|
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
|
||||||
|
ln := string(line)
|
||||||
|
if !nameGot && strings.HasPrefix(ln, "Name=") {
|
||||||
|
name = strings.TrimPrefix(ln, "Name=")
|
||||||
|
nameGot = true
|
||||||
|
} else if !catGot && strings.HasPrefix(ln, "Categories=") {
|
||||||
|
cats := strings.Split(strings.TrimPrefix(ln, "Categories="), ";")
|
||||||
|
if len(cats) > 0 {
|
||||||
|
category = cats[0]
|
||||||
|
}
|
||||||
|
catGot = true
|
||||||
|
} else if !iconGot && strings.HasPrefix(ln, "Icon=") {
|
||||||
|
iconName = strings.TrimPrefix(ln, "Icon=")
|
||||||
|
iconGot = true
|
||||||
|
}
|
||||||
|
if nameGot && catGot && iconGot {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getName(ini *os.File) string {
|
||||||
|
rdr := bufio.NewReader(ini)
|
||||||
|
var ret string
|
||||||
|
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
|
||||||
|
if strings.HasPrefix(string(line), "Name=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "Name=")
|
||||||
|
break
|
||||||
|
} else if strings.HasPrefix(string(line), "name=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "name=")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdr.Reset(ini)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIcon(fold string) *gdk.Pixbuf {
|
||||||
|
var pic string
|
||||||
|
if _, err := os.Open(fold + "/appicon.png"); err == nil {
|
||||||
|
pic = fold + "/appicon.png"
|
||||||
|
} else if folder, err := os.Open(fold + "/App/AppInfo"); err == nil {
|
||||||
|
fis, _ := folder.Readdir(-1)
|
||||||
|
var pics []string
|
||||||
|
for _, v := range fis {
|
||||||
|
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".png") && strings.HasPrefix(strings.ToLower(v.Name()), "appicon_") {
|
||||||
|
pics = append(pics, v.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(pics)
|
||||||
|
if len(pics) > 1 {
|
||||||
|
var ind int
|
||||||
|
if !contains(pics, "appicon_32.png") {
|
||||||
|
ind = len(pics) - 1
|
||||||
|
} else {
|
||||||
|
ind = sort.SearchStrings(pics, "appicon_32.png")
|
||||||
|
}
|
||||||
|
pic = fold + "/App/AppInfo/" + pics[ind]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
img, _ := gtk.ImageNewFromIconName("application-x-executable", gtk.ICON_SIZE_BUTTON)
|
||||||
|
buf := img.GetPixbuf()
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
img, _ := gtk.ImageNewFromFile(pic)
|
||||||
|
buf, _ := img.GetPixbuf().ScaleSimple(32, 32, gdk.INTERP_BILINEAR)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInfo(fold string) *os.File {
|
||||||
|
if fi, err := os.Open(fold + "/appinfo.ini"); err == nil {
|
||||||
|
return fi
|
||||||
|
}
|
||||||
|
tmp, err := os.Open(fold + "/App/AppInfo")
|
||||||
|
if err == nil {
|
||||||
|
fis, _ := tmp.Readdirnames(-1)
|
||||||
|
for _, v := range fis {
|
||||||
|
if strings.ToLower(v) == "appinfo.ini" {
|
||||||
|
tmp, _ := os.Open(fold + "/App/AppInfo/" + v)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
-65
@@ -1,65 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nelsam/gxui"
|
|
||||||
"github.com/nelsam/gxui/math"
|
|
||||||
)
|
|
||||||
|
|
||||||
//StrList TODO
|
|
||||||
type StrList struct {
|
|
||||||
gxui.AdapterBase
|
|
||||||
strs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
//AddString TODO
|
|
||||||
func (s *StrList) AddString(add string) {
|
|
||||||
s.strs = append(s.strs, add)
|
|
||||||
s.DataChanged(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Remove TODO
|
|
||||||
func (s *StrList) Remove(index int) {
|
|
||||||
s.strs = append(s.strs[:index], s.strs[index+1:]...)
|
|
||||||
s.DataChanged(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
//SetStrings TODO
|
|
||||||
func (s *StrList) SetStrings(strs []string) {
|
|
||||||
s.strs = strs
|
|
||||||
s.DataChanged(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Count TODO
|
|
||||||
func (s *StrList) Count() int {
|
|
||||||
return len(s.strs)
|
|
||||||
}
|
|
||||||
|
|
||||||
//ItemAt TODO
|
|
||||||
func (s *StrList) ItemAt(index int) gxui.AdapterItem {
|
|
||||||
return s.strs[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
//ItemIndex TODO
|
|
||||||
func (s *StrList) ItemIndex(item gxui.AdapterItem) int {
|
|
||||||
for i, v := range s.strs {
|
|
||||||
if v == item {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create TODO
|
|
||||||
func (s *StrList) Create(th gxui.Theme, index int) gxui.Control {
|
|
||||||
box := th.CreateLinearLayout()
|
|
||||||
box.SetDirection(gxui.LeftToRight)
|
|
||||||
lbl := th.CreateLabel()
|
|
||||||
lbl.SetText(s.strs[index])
|
|
||||||
box.AddChild(lbl)
|
|
||||||
return box
|
|
||||||
}
|
|
||||||
|
|
||||||
//Size TODO
|
|
||||||
func (s *StrList) Size(gxui.Theme) math.Size {
|
|
||||||
return math.Size{W: math.MaxSize.W, H: 20}
|
|
||||||
}
|
|
||||||
@@ -1,64 +1,188 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"github.com/CalebQ42/LinuxPA/appimg"
|
||||||
"os/exec"
|
"github.com/gotk3/gotk3/glib"
|
||||||
"path"
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
|
||||||
"github.com/nelsam/gxui"
|
|
||||||
"github.com/nelsam/gxui/themes/dark"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func ui(win *gtk.Window) {
|
||||||
dr gxui.Driver
|
ls := getCatRows()
|
||||||
)
|
var treeApps []*gtk.TreeIter
|
||||||
|
header, _ := gtk.HeaderBarNew()
|
||||||
func uiMain(dri gxui.Driver) {
|
header.SetShowCloseButton(true)
|
||||||
dr = dri
|
header.SetTitle("LinuxPA")
|
||||||
catAdap := &StrList{}
|
header.SetSubtitle("PortableApps.com type launcher")
|
||||||
catAdap.SetStrings(cats)
|
settings, _ := gtk.ButtonNewFromIconName("applications-system", gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||||
appAdap := &prtapAdap{}
|
settings.SetTooltipText("Settings")
|
||||||
th := dark.CreateTheme(dr)
|
dnl, _ := gtk.ButtonNewFromIconName("emblem-downloads", gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||||
win := th.CreateWindow(500, 500, "LinuxPA")
|
dnl.SetTooltipText("Download Apps")
|
||||||
top := th.CreateLinearLayout()
|
header.PackStart(settings)
|
||||||
top.SetDirection(gxui.BottomToTop)
|
header.PackEnd(dnl)
|
||||||
top.SetHorizontalAlignment(gxui.AlignRight)
|
win.SetTitlebar(header)
|
||||||
spl := th.CreateSplitterLayout()
|
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
||||||
spl.SetOrientation(gxui.Horizontal)
|
lrBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
catlist := th.CreateList()
|
catList, _ := gtk.ListBoxNew()
|
||||||
catlist.SetAdapter(catAdap)
|
catList.SetActivateOnSingleClick(true)
|
||||||
catlist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) {
|
store, _ := gtk.TreeStoreNew(glib.TYPE_OBJECT, glib.TYPE_STRING)
|
||||||
str := it.(string)
|
appsList, _ := gtk.TreeViewNewWithModel(store)
|
||||||
appAdap.SetApps(appMaster[str])
|
render, _ := gtk.CellRendererPixbufNew()
|
||||||
})
|
pixColumn, _ := gtk.TreeViewColumnNewWithAttribute("", render, "pixbuf", 0)
|
||||||
applist := th.CreateList()
|
txtRender, _ := gtk.CellRendererTextNew()
|
||||||
applist.SetAdapter(appAdap)
|
txtColumn, _ := gtk.TreeViewColumnNewWithAttribute("", txtRender, "text", 1)
|
||||||
spl.AddChild(catlist)
|
appsList.AppendColumn(pixColumn)
|
||||||
spl.AddChild(applist)
|
appsList.AppendColumn(txtColumn)
|
||||||
but := th.CreateLinearLayout()
|
appsList.SetHeadersVisible(false)
|
||||||
but.SetDirection(gxui.RightToLeft)
|
catList.SetHExpand(true)
|
||||||
launch := th.CreateButton()
|
catList.SetVExpand(true)
|
||||||
launch.SetText("Launch!")
|
appsList.SetHExpand(true)
|
||||||
launch.OnClick(func(gxui.MouseEvent) {
|
appsList.SetVExpand(true)
|
||||||
if appAdap.ItemIndex(applist.Selected()) != -1 {
|
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
app := applist.Selected().(prtap)
|
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
dir, fi := path.Split(app.ex)
|
vScrollApp, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
var cmd *exec.Cmd
|
hScrollApp, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
if commEnbl {
|
catScrl, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
|
||||||
cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
|
catScrl.Add(catList)
|
||||||
|
catScrl.SetSizeRequest(170, 500)
|
||||||
|
appScrl, _ := gtk.ScrolledWindowNew(hScrollApp, vScrollApp)
|
||||||
|
appScrl.Add(appsList)
|
||||||
|
appScrl.SetSizeRequest(300, 500)
|
||||||
|
lrBox.Add(catScrl)
|
||||||
|
lrBox.Add(appScrl)
|
||||||
|
botBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 2)
|
||||||
|
botBox.SetMarginStart(10)
|
||||||
|
botBox.SetMarginEnd(10)
|
||||||
|
botBox.SetMarginTop(10)
|
||||||
|
botBox.SetMarginBottom(10)
|
||||||
|
edit, _ := gtk.ButtonNewWithLabel("Edit App..")
|
||||||
|
edit.Connect("clicked", func() {
|
||||||
|
selec, _ := appsList.GetSelection()
|
||||||
|
_, it, ok := selec.GetSelected()
|
||||||
|
if ok {
|
||||||
|
pth, _ := store.GetPath(it)
|
||||||
|
ind := pth.GetIndices()
|
||||||
|
if wine {
|
||||||
|
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.edit(win, func() {
|
||||||
|
store.Clear()
|
||||||
|
for i := range ls {
|
||||||
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
|
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.edit(win, func() {
|
||||||
|
store.Clear()
|
||||||
|
for i := range ls {
|
||||||
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
cmd.Stdin = os.Stdin
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Start()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
but.AddChild(launch)
|
botBox.PackEnd(edit, false, false, 0)
|
||||||
top.AddChild(but)
|
topLvl.Add(lrBox)
|
||||||
top.AddChild(spl)
|
topLvl.PackEnd(botBox, false, true, 0)
|
||||||
win.AddChild(top)
|
win.Add(topLvl)
|
||||||
win.OnClose(func() {
|
for _, v := range ls {
|
||||||
dr.Terminate()
|
catList.Add(v)
|
||||||
|
}
|
||||||
|
catList.Connect("row-selected", func() {
|
||||||
|
store.Clear()
|
||||||
|
if catList.GetSelectedRow().GetIndex() >= 0 {
|
||||||
|
treeApps = make([]*gtk.TreeIter, 0)
|
||||||
|
if wine {
|
||||||
|
apps := master[cats[catList.GetSelectedRow().GetIndex()]]
|
||||||
|
for _, v := range apps {
|
||||||
|
treeApps = append(treeApps, v.getTreeIter(store))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apps := linmaster[lin[catList.GetSelectedRow().GetIndex()]]
|
||||||
|
for _, v := range apps {
|
||||||
|
treeApps = append(treeApps, v.getTreeIter(store))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
appsList.Connect("row-activated", func() {
|
||||||
|
selec, _ := appsList.GetSelection()
|
||||||
|
_, it, ok := selec.GetSelected()
|
||||||
|
if ok {
|
||||||
|
pth, _ := store.GetPath(it)
|
||||||
|
ind := pth.GetIndices()
|
||||||
|
if len(ind) == 1 {
|
||||||
|
if wine {
|
||||||
|
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launch()
|
||||||
|
} else {
|
||||||
|
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launch()
|
||||||
|
}
|
||||||
|
} else if len(ind) == 2 {
|
||||||
|
if wine {
|
||||||
|
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launchSub(ind[1])
|
||||||
|
} else {
|
||||||
|
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launchSub(ind[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dnl.Connect("clicked", func() {
|
||||||
|
appimg.ShowUI(versionNewest, func() {
|
||||||
|
master = make(map[string][]app)
|
||||||
|
linmaster = make(map[string][]app)
|
||||||
|
cats = make([]string, 0)
|
||||||
|
lin = make([]string, 0)
|
||||||
|
setup()
|
||||||
|
store.Clear()
|
||||||
|
for i := range ls {
|
||||||
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
settings.Connect("clicked", func() {
|
||||||
|
settingsUI(win, func() {
|
||||||
|
store.Clear()
|
||||||
|
for i := range ls {
|
||||||
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCatRows() (out []*gtk.Label) {
|
||||||
|
if wine {
|
||||||
|
for _, v := range cats {
|
||||||
|
txt, _ := gtk.LabelNew(v)
|
||||||
|
out = append(out, txt)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range lin {
|
||||||
|
txt, _ := gtk.LabelNew(v)
|
||||||
|
out = append(out, txt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
versionURL = "https://www.dropbox.com/s/a0xizzo0a4vsfqt/Version?dl=1"
|
||||||
|
downloadURL = "https://github.com/CalebQ42/LinuxPA/releases/download/vXXX/LinuxPA"
|
||||||
|
changelogURL = "https://www.dropbox.com/s/nmbk318er5kej5h/Changelog?dl=1"
|
||||||
|
changelogBetaURL = "https://www.dropbox.com/s/m8mo2o3nsvfqbfx/ChangelogBeta?dl=1"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Thanks to https://www.socketloop.com/tutorials/golang-download-file-example
|
||||||
|
//For some of the code
|
||||||
|
|
||||||
|
//Returns if success
|
||||||
|
func versionDL() (bool, error) {
|
||||||
|
versionFile, err := os.Create("PortableApps/LinuxPACom/Version")
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
_, err = io.Copy(versionFile, response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersionFileInfo() (stable string, beta string) {
|
||||||
|
fil, err := os.Open("PortableApps/LinuxPACom/Version")
|
||||||
|
if err != nil {
|
||||||
|
return "Error!", ""
|
||||||
|
}
|
||||||
|
rdr := bufio.NewReader(fil)
|
||||||
|
out, _, _ := rdr.ReadLine()
|
||||||
|
stable = string(out)
|
||||||
|
out, _, _ = rdr.ReadLine()
|
||||||
|
beta = string(out)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func changelogDL() (bool, error) {
|
||||||
|
changelogFile, err := os.Create("PortableApps/LinuxPACom/Changelog")
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
changelogFile.Chmod(0777)
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var response *http.Response
|
||||||
|
if betaUpdate {
|
||||||
|
response, err = check.Get(changelogBetaURL)
|
||||||
|
} else {
|
||||||
|
response, err = check.Get(changelogURL)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(changelogFile, response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChangelog() string {
|
||||||
|
fil, err := os.Open("PortableApps/LinuxPACom/Changelog")
|
||||||
|
if err != nil {
|
||||||
|
return "Error!"
|
||||||
|
}
|
||||||
|
out, _ := ioutil.ReadAll(fil)
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkForUpdate(stable, beta string) (bool, error) {
|
||||||
|
new := stable
|
||||||
|
if betaUpdate {
|
||||||
|
new = beta
|
||||||
|
}
|
||||||
|
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
|
||||||
|
} else {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if newNums[i] > curNums[i] {
|
||||||
|
return true, nil
|
||||||
|
} else if curNums[i] > newNums[i] {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadUpdate(newVersion string) (bool, error) {
|
||||||
|
url := strings.Replace(downloadURL, "XXX", newVersion, -1)
|
||||||
|
err := os.Rename("LinuxPA", ".LinuxPA.old")
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
fil, err := os.Create("LinuxPA")
|
||||||
|
fil.Chmod(0777)
|
||||||
|
defer fil.Close()
|
||||||
|
if err != nil {
|
||||||
|
os.Rename(".LinuxPA.old", "LinuxPA")
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer re.Body.Close()
|
||||||
|
_, err = io.Copy(fil, re.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(win *gtk.Window, forced bool) {
|
||||||
|
stat, err := versionDL()
|
||||||
|
if stat {
|
||||||
|
stable, beta := getVersionFileInfo()
|
||||||
|
if stable != "Error!" {
|
||||||
|
stat, err = checkForUpdate(stable, beta)
|
||||||
|
if stat || forced {
|
||||||
|
stat, err = changelogDL()
|
||||||
|
if stat {
|
||||||
|
updateWin, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
updateWin.SetTransientFor(win)
|
||||||
|
updateWin.SetPosition(gtk.WIN_POS_CENTER)
|
||||||
|
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
lbl, _ := gtk.LabelNew("There's a new update! Here's the changelog:")
|
||||||
|
tagTbl, _ := gtk.TextTagTableNew()
|
||||||
|
buf, _ := gtk.TextBufferNew(tagTbl)
|
||||||
|
tv, _ := gtk.TextViewNewWithBuffer(buf)
|
||||||
|
tv.SetEditable(false)
|
||||||
|
buf.SetText(getChangelog())
|
||||||
|
butBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
|
upBut, _ := gtk.ButtonNewWithLabel("Update")
|
||||||
|
upBut.Connect("clicked", func() {
|
||||||
|
updateWin.Close()
|
||||||
|
actuallyUpdate(win, forced)
|
||||||
|
})
|
||||||
|
cnlBut, _ := gtk.ButtonNewWithLabel("Cancel")
|
||||||
|
cnlBut.Connect("clicked", func() {
|
||||||
|
updateWin.Close()
|
||||||
|
})
|
||||||
|
butBox.Add(upBut)
|
||||||
|
butBox.Add(cnlBut)
|
||||||
|
topLvl.Add(lbl)
|
||||||
|
topLvl.Add(tv)
|
||||||
|
topLvl.Add(butBox)
|
||||||
|
topLvl.SetMarginBottom(10)
|
||||||
|
topLvl.SetMarginEnd(10)
|
||||||
|
topLvl.SetMarginStart(10)
|
||||||
|
topLvl.SetMarginTop(10)
|
||||||
|
updateWin.Add(topLvl)
|
||||||
|
updateWin.ShowAll()
|
||||||
|
updateWin.Show()
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Failed Version File Info")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func actuallyUpdate(win *gtk.Window, forced bool) {
|
||||||
|
updateWin, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
|
||||||
|
updateWin.SetTransientFor(win)
|
||||||
|
updateWin.SetSizeRequest(150, 50)
|
||||||
|
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
spin, _ := gtk.SpinnerNew()
|
||||||
|
spin.Start()
|
||||||
|
lbl, _ := gtk.LabelNew("Updating")
|
||||||
|
topLvl.Add(spin)
|
||||||
|
topLvl.Add(lbl)
|
||||||
|
topLvl.SetMarginBottom(10)
|
||||||
|
topLvl.SetMarginEnd(10)
|
||||||
|
topLvl.SetMarginStart(10)
|
||||||
|
topLvl.SetMarginTop(10)
|
||||||
|
updateWin.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
updateWin.Add(topLvl)
|
||||||
|
updateWin.ShowAll()
|
||||||
|
updateWin.Show()
|
||||||
|
go func(win, updateWin *gtk.Window) {
|
||||||
|
defer updateWin.Close()
|
||||||
|
stat, err := versionDL()
|
||||||
|
if stat {
|
||||||
|
stable, beta := getVersionFileInfo()
|
||||||
|
if stable != "Error!" {
|
||||||
|
stat, err = checkForUpdate(stable, beta)
|
||||||
|
if stat || forced {
|
||||||
|
if betaUpdate {
|
||||||
|
downloadUpdate(beta)
|
||||||
|
} else {
|
||||||
|
downloadUpdate(stable)
|
||||||
|
}
|
||||||
|
win.Close()
|
||||||
|
cmd := exec.Command("./LinuxPA")
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Failed Version File Info")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}(win, updateWin)
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
"github.com/mholt/archiver/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
wineURL = "https://www.playonlinux.com/wine/binaries/phoenicis/staging-linux-amd64/PlayOnLinux-wine-5.20-staging-linux-amd64.tar.gz"
|
||||||
|
)
|
||||||
|
|
||||||
|
func downloadWine(parent *gtk.Window, cb chan bool) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
win.SetDestroyWithParent(true)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
spin, _ := gtk.SpinnerNew()
|
||||||
|
spin.Start()
|
||||||
|
txt, _ := gtk.LabelNew("Downloading Wine")
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
box.SetMarginBottom(10)
|
||||||
|
box.SetMarginEnd(10)
|
||||||
|
box.SetMarginStart(10)
|
||||||
|
box.SetMarginTop(10)
|
||||||
|
box.Add(spin)
|
||||||
|
box.Add(txt)
|
||||||
|
win.Add(box)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
go func(win *gtk.Window, txt *gtk.Label) {
|
||||||
|
defer win.Close()
|
||||||
|
wineTar, err := os.Create("PortableApps/LinuxPACom/wine5.20.tar.bz2")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer wineTar.Close()
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := check.Get(wineURL)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.RemoveAll("PortableApps/LinuxPACom/Wine")
|
||||||
|
defer resp.Body.Close()
|
||||||
|
_, err = io.Copy(wineTar, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
txt.SetText("Extracting Wine")
|
||||||
|
err = archiver.DefaultTarBz2.Unarchive("PortableApps/LinuxPACom/wine2.5.tar.bz2", "PortableApps/LinuxPACom/Wine")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fil, err := os.Open("PortableApps/LinuxPACom/common.sh")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tmp, err := ioutil.ReadAll(fil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(tmp), "export PATH=$PWD/PortableApps/LinuxPACom/Wine/wineversion/2.5/bin:$PATH") {
|
||||||
|
tmp = append(tmp, []byte("\nexport PATH=$PWD/PortableApps/LinuxPACom/Wine/wineversion/2.5/bin:$PATH")...)
|
||||||
|
ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", tmp, 0777)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb <- true
|
||||||
|
return
|
||||||
|
}(win, txt)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user