Initial
This commit is contained in:
commit
9b83d7beea
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# ---> Go
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
r2mod-go
|
||||||
|
main
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
37
README.md
Normal file
37
README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# r2mod-go
|
||||||
|
risk of rain 2 mod updater/manager/installer/uninstaller/lister/searcher/info-getter
|
||||||
|
|
||||||
|
## currently implemented
|
||||||
|
- downloading
|
||||||
|
- info getting
|
||||||
|
- uninstalling
|
||||||
|
- toggling mods
|
||||||
|
- listing mods
|
||||||
|
- updating api cache and mods
|
||||||
|
|
||||||
|
## todo for feature parity with other tools
|
||||||
|
- 'edit' command
|
||||||
|
- 'hold' command
|
||||||
|
- 'run' command
|
||||||
|
- 'setup' functionality
|
||||||
|
- 'version' command
|
||||||
|
- 'search' command
|
||||||
|
|
||||||
|
## normal todo
|
||||||
|
- move the print statements out of api.go, give my functions returns
|
||||||
|
|
||||||
|
## longer-term todo
|
||||||
|
- self updater
|
||||||
|
- tui?
|
||||||
|
- multi threaded updating
|
||||||
|
- cache the api in non-json format for easier searching
|
||||||
|
- different function for multi-addon updating/installing so it doesn't unmarshal the json for every mod
|
||||||
|
- fuzzy mod searching
|
||||||
|
- better info command
|
||||||
|
- fully separate api and frontend
|
||||||
|
- segment the program into r2mod-api and r2mod-cli
|
||||||
|
- make some fun gui or smth in gtk/qt/whatever
|
||||||
|
|
||||||
|
## fuck
|
||||||
|
- windows support
|
||||||
|
- macos support? (does risk of rain even run?)
|
108
api/api.go
Normal file
108
api/api.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"r2mod-go/utils"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
// TODO: eliminate this dependency
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mod contains info about a mod from thunderstore API
|
||||||
|
type Mod struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
PackageURL string `json:"package_url"`
|
||||||
|
DateCreated string `json:"date_created"`
|
||||||
|
DateUpdated string `json:"date_updated"`
|
||||||
|
UUID4 string `json:"uuid4"`
|
||||||
|
RatingScore int `json:"rating_score"`
|
||||||
|
IsPinned bool `json:"is_pinned"`
|
||||||
|
IsDeprecated bool `json:"is_deprecated"`
|
||||||
|
HasNSFWContent bool `json:"has_nsfw_content"`
|
||||||
|
Categories []string `json:"categories"`
|
||||||
|
Versions []Version `json:"versions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version contains info about a specific version of a mod
|
||||||
|
type Version struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
VersionNumber string `json:"version_number"`
|
||||||
|
Dependencies []string `json:"dependencies"`
|
||||||
|
DownloadURL string `json:"download_url"`
|
||||||
|
Downloads int `json:"downloads"`
|
||||||
|
DateCreated string `json:"date_created"`
|
||||||
|
WebsiteURL string `json:"website_url"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
UUID4 string `json:"uuid4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckAPICache checks if the cached json is expired
|
||||||
|
func CheckAPICache() {
|
||||||
|
// TODO: move the printing out, add returns
|
||||||
|
|
||||||
|
color.Blue("> Checking API Cache")
|
||||||
|
|
||||||
|
if !utils.PathExists(utils.SystemInfo.TmpDir + "/pkg.json") {
|
||||||
|
color.Red("> API Cache is outdated")
|
||||||
|
UpdateAPICache()
|
||||||
|
} else {
|
||||||
|
info, err := os.Stat(utils.SystemInfo.TmpDir + "/pkg.json")
|
||||||
|
utils.CheckErr(err)
|
||||||
|
|
||||||
|
lastModTime := info.ModTime()
|
||||||
|
currentTime := time.Now()
|
||||||
|
|
||||||
|
if currentTime.Sub(lastModTime).Seconds() > 7200 {
|
||||||
|
color.Red("> API Cache is outdated")
|
||||||
|
color.Blue("> Updating API Cache")
|
||||||
|
UpdateAPICache()
|
||||||
|
} else {
|
||||||
|
color.Green("> API Cache is up to date")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAPICache gets a new copy of the thunderstore pkgfile
|
||||||
|
func UpdateAPICache() {
|
||||||
|
apiURL := "https://thunderstore.io/api/v1/package/"
|
||||||
|
|
||||||
|
err := utils.DownloadFile(utils.SystemInfo.TmpDir+"/pkg.json", apiURL)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetModData gets object of mod by depString
|
||||||
|
func GetModData(depString string) Mod {
|
||||||
|
if depString == "R2API" {
|
||||||
|
depString = "tristanmcpherson-R2API"
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgFile, err := os.Open(utils.SystemInfo.TmpDir + "/pkg.json")
|
||||||
|
utils.CheckErr(err)
|
||||||
|
|
||||||
|
byteValue, err := ioutil.ReadAll(pkgFile)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
|
||||||
|
var mods []Mod
|
||||||
|
|
||||||
|
err = json.Unmarshal(byteValue, &mods)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
|
||||||
|
var selectedMod Mod
|
||||||
|
for i := 0; i < len(mods); i++ {
|
||||||
|
if mods[i].FullName == depString {
|
||||||
|
selectedMod = mods[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defer pkgFile.Close()
|
||||||
|
|
||||||
|
// TODO: export this lol
|
||||||
|
return selectedMod
|
||||||
|
}
|
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module r2mod-go
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require github.com/fatih/color v1.10.0
|
9
go.sum
Normal file
9
go.sum
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||||
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
97
main.go
Normal file
97
main.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"r2mod-go/api"
|
||||||
|
"r2mod-go/tools"
|
||||||
|
"r2mod-go/utils"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
logFile, err := os.OpenFile(utils.SystemInfo.TmpDir+"/r2mod-go.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
|
||||||
|
defer logFile.Close()
|
||||||
|
log.SetOutput(logFile)
|
||||||
|
|
||||||
|
// Setup CLI switch
|
||||||
|
|
||||||
|
var operation string
|
||||||
|
if len(os.Args) >= 2 {
|
||||||
|
operation = os.Args[1]
|
||||||
|
} else {
|
||||||
|
operation = "help"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Color
|
||||||
|
white := color.New(color.FgWhite).SprintFunc()
|
||||||
|
|
||||||
|
// CLI Operations
|
||||||
|
|
||||||
|
switch operation {
|
||||||
|
case "help":
|
||||||
|
fmt.Println(`Commands:
|
||||||
|
> info -- get info about a mod
|
||||||
|
> install, ins, i -- install mod(s)
|
||||||
|
> remove, rem, r -- remove mod(s)
|
||||||
|
> list, ls, li -- list mods
|
||||||
|
> update, upgrade, up -- update mods and API cache
|
||||||
|
> toggle, tg, togglemods -- toggle mods
|
||||||
|
> filter -- remove version numbers using regex from stdin
|
||||||
|
`)
|
||||||
|
case "info":
|
||||||
|
var selectedmod api.Mod = api.GetModData(os.Args[2])
|
||||||
|
color.Cyan("Mod Info: %s", os.Args[2])
|
||||||
|
fmt.Println(" Name: " + selectedmod.Versions[0].FullName)
|
||||||
|
fmt.Println(" Desc: " + selectedmod.Versions[0].Description)
|
||||||
|
fmt.Println(" Version: " + selectedmod.Versions[0].VersionNumber)
|
||||||
|
fmt.Println(" Download URL: " + selectedmod.Versions[0].DownloadURL)
|
||||||
|
case "install", "ins", "i":
|
||||||
|
api.CheckAPICache()
|
||||||
|
for _, m := range os.Args[2:] {
|
||||||
|
fmt.Println(" >", tools.ExposeModString(m))
|
||||||
|
tools.DownloadMod(tools.ExposeModString(m))
|
||||||
|
}
|
||||||
|
case "remove", "rem", "r":
|
||||||
|
api.CheckAPICache()
|
||||||
|
for _, m := range os.Args[2:] {
|
||||||
|
fmt.Println(" >", tools.ExposeModString(m))
|
||||||
|
tools.RemoveMod(tools.ExposeModString(m))
|
||||||
|
}
|
||||||
|
case "list", "ls", "li":
|
||||||
|
files, err := ioutil.ReadDir(utils.SystemInfo.PluginDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, f := range files {
|
||||||
|
color.Blue("%3v %s", i, white(f.Name()))
|
||||||
|
}
|
||||||
|
case "update", "upgrade", "up":
|
||||||
|
color.Cyan("> Updating")
|
||||||
|
api.CheckAPICache()
|
||||||
|
files, err := ioutil.ReadDir(utils.SystemInfo.PluginDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
fmt.Println(" >", tools.ExposeModString(f.Name()))
|
||||||
|
tools.DownloadMod(tools.ExposeModString(f.Name()))
|
||||||
|
}
|
||||||
|
|
||||||
|
color.Green("> Complete!")
|
||||||
|
case "toggle", "tm", "togglemods":
|
||||||
|
tools.ToggleMods()
|
||||||
|
case "filter":
|
||||||
|
fmt.Println(tools.ExposeModString(os.Args[2]))
|
||||||
|
default:
|
||||||
|
fmt.Println("Unknown command, use 'r2go help' for a list of commands.")
|
||||||
|
}
|
||||||
|
}
|
96
tools/tools.go
Normal file
96
tools/tools.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"r2mod-go/api"
|
||||||
|
"r2mod-go/utils"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExposeModString removes user-error surrounding the mod string.
|
||||||
|
func ExposeModString(input string) string {
|
||||||
|
reg := regexp.MustCompile(`\-([0-9]+)\.([0-9]+)\.([0-9]+)`)
|
||||||
|
res := reg.ReplaceAllString(input, "")
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadMod gets the download URL and installs the mod in the correct folder
|
||||||
|
func DownloadMod(depString string) {
|
||||||
|
if depString == "R2API" {
|
||||||
|
depString = "tristanmcpherson-R2API"
|
||||||
|
}
|
||||||
|
|
||||||
|
sysinfo := utils.GetSysInfo()
|
||||||
|
downloadURL := api.GetModData(depString).Versions[0].DownloadURL
|
||||||
|
|
||||||
|
modName := sysinfo.TmpDir + "/dl/" + depString + ".zip"
|
||||||
|
|
||||||
|
modVersion := api.GetModData(depString).Versions[0].VersionNumber
|
||||||
|
modFolder := sysinfo.PluginDir + "/" + depString + "-" + modVersion
|
||||||
|
|
||||||
|
if utils.PathExists(modFolder) {
|
||||||
|
color.Green(" > Already installed and up to date")
|
||||||
|
} else {
|
||||||
|
if len(api.GetModData(depString).Versions) >= 2 {
|
||||||
|
modVersionOld := api.GetModData(depString).Versions[1].VersionNumber
|
||||||
|
modFolderOld := sysinfo.PluginDir + "/" + depString + "-" + modVersionOld
|
||||||
|
|
||||||
|
if utils.PathExists(modFolderOld) {
|
||||||
|
color.Magenta(" > Updating to version %s", modVersion)
|
||||||
|
defer os.RemoveAll(modFolderOld)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color.Blue(" > Downloading...")
|
||||||
|
|
||||||
|
err := utils.DownloadFile(modName, downloadURL)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
|
||||||
|
color.Blue(" > Unzipping")
|
||||||
|
|
||||||
|
unzip, err := utils.Unzip(modName, modFolder)
|
||||||
|
log.Println(unzip)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveMod uninstalls a mod
|
||||||
|
func RemoveMod(depString string) {
|
||||||
|
modVersion := api.GetModData(depString).Versions[0].VersionNumber
|
||||||
|
modFolder := utils.SystemInfo.PluginDir + "/" + depString + "-" + modVersion
|
||||||
|
|
||||||
|
if !utils.PathExists(modFolder) {
|
||||||
|
color.Red(" > Not installed")
|
||||||
|
} else {
|
||||||
|
defer os.RemoveAll(modFolder)
|
||||||
|
color.Blue(" > Uninstalled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToggleMods toggles mods on or off.
|
||||||
|
// TODO: make this not hardcoded as shit, perhaps implement a proper parser
|
||||||
|
func ToggleMods() {
|
||||||
|
var configFile string = utils.SystemInfo.GameDir + "/doorstop_config.ini"
|
||||||
|
|
||||||
|
input, err := ioutil.ReadFile(configFile)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
|
||||||
|
lines := strings.Split(string(input), "\n")
|
||||||
|
|
||||||
|
if strings.Contains(lines[2], "true") {
|
||||||
|
color.Cyan("> Mods Disabled")
|
||||||
|
lines[2] = "enabled=false"
|
||||||
|
} else {
|
||||||
|
color.Cyan("> Mods Enabled")
|
||||||
|
lines[2] = "enabled=true"
|
||||||
|
}
|
||||||
|
|
||||||
|
output := strings.Join(lines, "\n")
|
||||||
|
err = ioutil.WriteFile(configFile, []byte(output), 0644)
|
||||||
|
utils.CheckErr(err)
|
||||||
|
}
|
187
utils/utils.go
Normal file
187
utils/utils.go
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SysInfo holds information about the user's installation
|
||||||
|
type SysInfo struct {
|
||||||
|
SteamDir string
|
||||||
|
HomeDir string
|
||||||
|
FlatpakDir string
|
||||||
|
SteamGameID string
|
||||||
|
GameDir string
|
||||||
|
CompatDir string
|
||||||
|
BepinDir string
|
||||||
|
PluginDir string
|
||||||
|
ConfigDir string
|
||||||
|
TmpDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckErr checks for an error, prints if it happened
|
||||||
|
func CheckErr(e error) {
|
||||||
|
if e != nil {
|
||||||
|
log.Fatal(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathExists checks if file or directory exists
|
||||||
|
func PathExists(path string) bool {
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
return true
|
||||||
|
} else if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSysInfo gathers information about the user's installation
|
||||||
|
func GetSysInfo() SysInfo {
|
||||||
|
|
||||||
|
var steamDir string = "/.local/share/Steam"
|
||||||
|
var homeDir string = os.Getenv("HOME")
|
||||||
|
var flatpakDir string = "/.var/app/com.valvesoftware.Steam" + steamDir
|
||||||
|
var steamGameID string = "632360"
|
||||||
|
|
||||||
|
var gameDir string
|
||||||
|
if os.Getenv("R2MOD_INSTALL_DIR") != "" {
|
||||||
|
gameDir = os.Getenv("R2MOD_INSTALL_DIR")
|
||||||
|
} else if PathExists(homeDir + flatpakDir + "/steamapps/common/Risk of Rain 2") {
|
||||||
|
gameDir = homeDir + flatpakDir + "/steamapps/common/Risk of Rain 2"
|
||||||
|
} else {
|
||||||
|
gameDir = homeDir + steamDir + "/steamapps/common/Risk of Rain 2"
|
||||||
|
}
|
||||||
|
|
||||||
|
var compatDir string
|
||||||
|
if PathExists(homeDir + flatpakDir + "/steamapps/compatdata/" + steamGameID) {
|
||||||
|
compatDir = homeDir + flatpakDir + "/steamapps/compatdata/" + steamGameID
|
||||||
|
} else {
|
||||||
|
compatDir = homeDir + steamDir + "/steamapps/compatdata/" + steamGameID
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemInfo := SysInfo{
|
||||||
|
SteamDir: "/.local/share/Steam",
|
||||||
|
HomeDir: os.Getenv("HOME"),
|
||||||
|
FlatpakDir: "/.var/app/com.valvesoftware.Steam/.local/share/Steam",
|
||||||
|
SteamGameID: "632360",
|
||||||
|
GameDir: gameDir,
|
||||||
|
CompatDir: compatDir,
|
||||||
|
BepinDir: gameDir + "/BepInEx",
|
||||||
|
ConfigDir: gameDir + "/BepInEx/config",
|
||||||
|
PluginDir: gameDir + "/BepInEx/plugins",
|
||||||
|
TmpDir: "/tmp/r2mod-go",
|
||||||
|
}
|
||||||
|
|
||||||
|
if !PathExists(SystemInfo.TmpDir) {
|
||||||
|
log.Println("temp directory does not exist; creating...")
|
||||||
|
err := os.Mkdir(SystemInfo.TmpDir, 0755)
|
||||||
|
CheckErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !PathExists(SystemInfo.TmpDir + "/dl") {
|
||||||
|
log.Println("temp dl directory does not exist; creating...")
|
||||||
|
err := os.Mkdir(SystemInfo.TmpDir+"/dl", 0755)
|
||||||
|
CheckErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup log file
|
||||||
|
if PathExists(SystemInfo.TmpDir + "/r2mod-go.log") {
|
||||||
|
err := os.Remove(SystemInfo.TmpDir + "/r2mod-go.log")
|
||||||
|
CheckErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logFile, err := os.OpenFile(SystemInfo.TmpDir+"/r2mod-go.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
|
||||||
|
CheckErr(err)
|
||||||
|
|
||||||
|
log.SetOutput(logFile)
|
||||||
|
|
||||||
|
log.Println("System Information : ")
|
||||||
|
log.Println(" gameDir:", SystemInfo.GameDir)
|
||||||
|
log.Println(" compatDir:", SystemInfo.CompatDir)
|
||||||
|
log.Println(" bepinDir:", SystemInfo.BepinDir)
|
||||||
|
log.Println(" configDir:", SystemInfo.ConfigDir)
|
||||||
|
log.Println(" pluginDir:", SystemInfo.PluginDir)
|
||||||
|
log.Println(" tmpDir:", SystemInfo.TmpDir)
|
||||||
|
|
||||||
|
return SystemInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemInfo contains information about the user's computer.
|
||||||
|
var SystemInfo SysInfo = GetSysInfo()
|
||||||
|
|
||||||
|
// Unzip takes input src and dest, unzips file.
|
||||||
|
func Unzip(src string, dest string) ([]string, error) {
|
||||||
|
var filenames []string
|
||||||
|
|
||||||
|
r, err := zip.OpenReader(src)
|
||||||
|
CheckErr(err)
|
||||||
|
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
for _, f := range r.File {
|
||||||
|
fpath := filepath.Join(dest, f.Name)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
|
||||||
|
return filenames, fmt.Errorf("%s: illegal file path", fpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
filenames = append(filenames, fpath)
|
||||||
|
|
||||||
|
if f.FileInfo().IsDir() {
|
||||||
|
os.MkdirAll(fpath, os.ModePerm)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
|
||||||
|
return filenames, err
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return filenames, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rc, err := f.Open()
|
||||||
|
if err != nil {
|
||||||
|
return filenames, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(outFile, rc)
|
||||||
|
|
||||||
|
outFile.Close()
|
||||||
|
rc.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return filenames, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filenames, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadFile Downloads a file through http
|
||||||
|
func DownloadFile(filepath string, url string) error {
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
out, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(out, resp.Body)
|
||||||
|
return err
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user