mirror of
https://github.com/CompeyDev/wsl-archlinux-manager.git
synced 2024-12-12 04:30:37 +00:00
init: core structure & RootFS download mechanism
This commit is contained in:
commit
b0a57eed59
5 changed files with 352 additions and 0 deletions
17
go.mod
Normal file
17
go.mod
Normal file
|
@ -0,0 +1,17 @@
|
|||
module github.com/CompeyDev/wsl-archlinux-manager
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/briandowns/spinner v1.19.0
|
||||
github.com/cavaliergopher/grab/v3 v3.0.1
|
||||
github.com/gookit/color v1.5.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.10.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
|
||||
)
|
37
go.sum
Normal file
37
go.sum
Normal file
|
@ -0,0 +1,37 @@
|
|||
github.com/briandowns/spinner v1.19.0 h1:s8aq38H+Qju89yhp89b4iIiMzMm8YN3p6vGpwyh/a8E=
|
||||
github.com/briandowns/spinner v1.19.0/go.mod h1:mQak9GHqbspjC/5iUx3qMlIho8xBS/ppAL/hX5SmPJU=
|
||||
github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4=
|
||||
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
||||
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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
|
||||
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
76
lib/checkers/verifySignature.go
Normal file
76
lib/checkers/verifySignature.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package checkers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/cavaliergopher/grab/v3"
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
// TODO:
|
||||
func VerifySignature(mirrorUrl string) {
|
||||
bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
||||
bar.Prefix = " "
|
||||
bar.Suffix = " Verifying signature of RootFS..."
|
||||
bar.Start()
|
||||
|
||||
success, _ := pullSig(mirrorUrl)
|
||||
|
||||
if !success {
|
||||
color.Red.Println("\r ❎ Failed to download signature of RootFS. Refusing to continue.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
userHomeDir, homeDirErr := os.UserHomeDir()
|
||||
|
||||
if homeDirErr != nil {
|
||||
color.Red.Println("\r ❎ Failed to fetch installation directory, cannot verify authenticity of RootFS.")
|
||||
os.Exit(1)
|
||||
}
|
||||
cwd, dirErr := os.Getwd()
|
||||
|
||||
if dirErr != nil {
|
||||
color.Red.Println("\r ❎ Failed to fetch installation directory, cannot verify authenticity of RootFS.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
unixWd := fmt.Sprintf("/mnt/c/%s", strings.ReplaceAll(strings.Split(userHomeDir, `C:\`)[1], `\`, "/")) + strings.ReplaceAll(strings.Split(cwd, userHomeDir)[1], `\`, "/")
|
||||
|
||||
// does not work?
|
||||
|
||||
getAuthenticity, authenticityErr := exec.Command("powershell.exe", fmt.Sprintf(`wsl bash -c "cd %s && gpg --keyserver-options auto-key-retrieve --verify archlinux-bootstrap-2022.11.01-x86_64.tar.gz.sig"`, unixWd)).Output()
|
||||
|
||||
if authenticityErr != nil {
|
||||
color.Red.Println("\r ❎ Failed to verify authenticity of RootFS. Refusing to continue.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
color.Green.Println("\r ✅ Successfully matched checksums and verified authenticity!")
|
||||
bar.Stop()
|
||||
|
||||
fmt.Println(strings.Trim(string(getAuthenticity), "\n\r"))
|
||||
}
|
||||
|
||||
func pullSig(url string) (isSuccessful bool, error error) {
|
||||
bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
||||
bar.Prefix = " "
|
||||
bar.Suffix = " Downloading Signature..."
|
||||
|
||||
var version = strings.Split(strings.Split(url, "iso/")[1], "/")[0]
|
||||
var structuredUrl = fmt.Sprintf("%s/archlinux-bootstrap-%s-x86_64.tar.gz.sig", url, version)
|
||||
res, err := grab.Get(".", structuredUrl)
|
||||
|
||||
if err != nil {
|
||||
color.Red.Println("\r ❎ Failed to download Signature.")
|
||||
return false, err
|
||||
}
|
||||
|
||||
color.Green.Println("\r ✅ Downloaded Signature", res.Filename)
|
||||
|
||||
return true, nil
|
||||
}
|
125
lib/core/core.go
Normal file
125
lib/core/core.go
Normal file
|
@ -0,0 +1,125 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/CompeyDev/wsl-archlinux-manager/lib/checkers"
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/cavaliergopher/grab/v3"
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
// TODO:
|
||||
|
||||
func Build() {
|
||||
fmt.Println("🔃 Setting up RootFS...")
|
||||
bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
||||
bar.Prefix = " "
|
||||
bar.Suffix = " Determining the fastest mirror..."
|
||||
bar.Start()
|
||||
userLocation, err := http.Get("http://ip-api.com/json/")
|
||||
if err != nil {
|
||||
print(err)
|
||||
}
|
||||
defer userLocation.Body.Close()
|
||||
body, reqErr := io.ReadAll(userLocation.Body)
|
||||
|
||||
if reqErr != nil {
|
||||
color.Red.Println("\r ❎ An internal error occurred when attempting to pull the RootFS. This is probably a bug; you might want to report this.")
|
||||
bar.Stop()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var resStruct struct {
|
||||
Status string
|
||||
Country string
|
||||
CountryCode string
|
||||
Region string
|
||||
RegionName string
|
||||
City string
|
||||
Zip string
|
||||
Lat float64
|
||||
Lon float64
|
||||
Timezone string
|
||||
Isp string
|
||||
Org string
|
||||
As string
|
||||
Query string
|
||||
}
|
||||
|
||||
parseErr := json.Unmarshal([]byte(body), &resStruct)
|
||||
|
||||
if parseErr != nil {
|
||||
color.Red.Println("\r ❎ Failed to parse response body! This is a probably a bug; you might want to report this.")
|
||||
bar.Stop()
|
||||
os.Exit(1)
|
||||
}
|
||||
mirror := getMirror(resStruct.Country)
|
||||
bar.Suffix = fmt.Sprintf(" Using mirror %s...", mirror)
|
||||
time.Sleep(time.Second * 5)
|
||||
bar.Stop()
|
||||
isSuccessful_1, _ := pullArchive(mirror)
|
||||
|
||||
if !isSuccessful_1 {
|
||||
color.Yellow.Println("\r ❎ Attempt #1 to pull RootFS failed, trying again with Worldwide...")
|
||||
|
||||
bar.Suffix = " Attempt #1 to pull RootFS failed, trying again with Worldwide..."
|
||||
|
||||
bar.Start()
|
||||
|
||||
globalMirror := getMirror("Worldwide")
|
||||
isSuccessful_2, _ := pullArchive(globalMirror)
|
||||
|
||||
if !isSuccessful_2 {
|
||||
color.Red.Println("\r ❎ Attempt #2 to pull RootFS failed. Please try again.")
|
||||
bar.Stop()
|
||||
os.Exit(1)
|
||||
} else {
|
||||
checkers.VerifySignature(globalMirror)
|
||||
}
|
||||
|
||||
} else {
|
||||
checkers.VerifySignature(mirror)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getMirror(country string) string {
|
||||
resp, err := http.Get("https://archlinux.org/download/")
|
||||
if err != nil {
|
||||
color.Red.Println("❎ Failed to download RootFS.")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
color.Red.Println("❎ An internal error occurred when attempting to pull the RootFS. This is probably a bug; you might want to report this.")
|
||||
}
|
||||
|
||||
mirrorLink := strings.Split(strings.Split(strings.Split(strings.Split(strings.Split(strings.Split(string(body), fmt.Sprintf(`title="%s"`, country))[1], `title="Download from`)[0], fmt.Sprintf(`></span> %s</h5>`, country))[1], `<ul>`)[1], `<li><a href="`)[1], `"`)[0]
|
||||
return mirrorLink
|
||||
}
|
||||
|
||||
func pullArchive(url string) (isSuccessful bool, error error) {
|
||||
bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
||||
bar.Prefix = " "
|
||||
bar.Suffix = " Downloading RootFS..."
|
||||
|
||||
var version = strings.Split(strings.Split(url, "iso/")[1], "/")[0]
|
||||
var structuredUrl = fmt.Sprintf("%s/archlinux-bootstrap-%s-x86_64.tar.gz", url, version)
|
||||
res, err := grab.Get(".", structuredUrl)
|
||||
|
||||
if err != nil {
|
||||
color.Red.Println("\r ❎ Failed to download RootFS.")
|
||||
return false, err
|
||||
}
|
||||
|
||||
color.Bold.Println("\r ✅ Downloaded RootFS", res.Filename)
|
||||
return true, nil
|
||||
}
|
97
src/main.go
Normal file
97
src/main.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/CompeyDev/wsl-archlinux-manager/lib/core"
|
||||
"github.com/briandowns/spinner"
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if runtime.GOOS == "windows" {
|
||||
checks()
|
||||
core.Build()
|
||||
} else {
|
||||
fmt.Println("WSL is reserved for windows users only.")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func build() {
|
||||
checks()
|
||||
|
||||
}
|
||||
|
||||
// TODO: Add colors
|
||||
func checks() {
|
||||
color.Blueln("======> Pre-installation checks")
|
||||
fmt.Println("🔃 Running checks...")
|
||||
_, permsErr := os.Open("\\\\.\\PHYSICALDRIVE0")
|
||||
|
||||
if permsErr != nil {
|
||||
fmt.Println("Please run this command with elevated priveleges.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
||||
bar.Prefix = " "
|
||||
bar.Suffix = " Checking for WSL..."
|
||||
bar.Start()
|
||||
|
||||
getAvailability, availabilityErr := exec.Command("powershell.exe", "(Get-WindowsOptionalFeature -Online -FeatureName *Subsystem*).State").Output()
|
||||
|
||||
if availabilityErr != nil {
|
||||
color.Red.Println("\r ❎ Failed to check for WSL availability.")
|
||||
}
|
||||
|
||||
if strings.Trim(string(getAvailability), "\n\r") == "Enabled" {
|
||||
color.Green.Println("\r ✅ WSL is enabled.")
|
||||
bar.Stop()
|
||||
|
||||
bar.Prefix = " "
|
||||
bar.Suffix = " Checking for existing WSL distributions..."
|
||||
|
||||
bar.Start()
|
||||
|
||||
preInstalledDistro, installedDistroErr := exec.Command("powershell.exe", "wsl").Output()
|
||||
|
||||
if installedDistroErr != nil {
|
||||
color.Red.Println("\r ❎ Failed to check for preinstalled distributions.")
|
||||
bar.Stop()
|
||||
}
|
||||
|
||||
if strings.Contains(string(preInstalledDistro), "no installed distributions") {
|
||||
color.Red.Println("\r ❎ Preinstalled distributions do exist. (Please make sure the default distribution is Debian-based)")
|
||||
bar.Stop()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
userHomeDir, homeDirErr := os.UserHomeDir()
|
||||
|
||||
bar.Suffix = " Creating install directory..."
|
||||
bar.Start()
|
||||
time.Sleep(300000000)
|
||||
if homeDirErr != nil {
|
||||
fmt.Println("❎ Failed to initialize installation directory.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
installDir := path.Join(userHomeDir, ".wslm")
|
||||
archDir := path.Join(installDir, "arch")
|
||||
|
||||
os.Mkdir(installDir, fs.FileMode(os.O_RDWR))
|
||||
os.Mkdir(archDir, fs.FileMode(os.O_RDWR))
|
||||
bar.Stop()
|
||||
color.Green.Print("\r ✅ Successfully initialized installation directory.")
|
||||
color.Bold.Println("\n✅ Initialized WSLm.")
|
||||
color.Blueln("===============================")
|
||||
}
|
Loading…
Reference in a new issue