Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #41 - Issue with blank spaces in path #355

Merged
merged 3 commits into from
Aug 11, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
219 changes: 134 additions & 85 deletions src/nvm.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package main

import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
"io/ioutil"
"path/filepath"
"regexp"
"bytes"
"strconv"
"strings"
"syscall"
"time"
"./nvm/web"
"./nvm/arch"
"./nvm/file"
"./nvm/node"
"strconv"
"path/filepath"
"github.com/olekukonko/tablewriter"
)

Expand Down Expand Up @@ -57,7 +58,7 @@ func main() {
detail := ""
procarch := arch.Validate(env.arch)

Setup()
setup()

// Capture any additional arguments
if len(args) > 2 {
Expand Down Expand Up @@ -114,13 +115,17 @@ func main() {
env.proxy = detail
saveSettings()
}
case "update": update()

//case "update": update()
case "node_mirror": setNodeMirror(detail)
case "npm_mirror": setNpmMirror(detail)
default: help()
}
}

// ===============================================================
// BEGIN | CLI functions
// ===============================================================
func setNodeMirror(uri string) {
env.node_mirror = uri
saveSettings()
Expand All @@ -131,40 +136,20 @@ func setNpmMirror(uri string) {
saveSettings()
}

/*
func update() {
// cmd := exec.Command("cmd", "/d", "echo", "testing")
// var output bytes.Buffer
// var _stderr bytes.Buffer
// cmd.Stdout = &output
// cmd.Stderr = &_stderr
// perr := cmd.Run()
// if perr != nil {
// fmt.Println(fmt.Sprint(perr) + ": " + _stderr.String())
// return
// }
}

func CheckVersionExceedsLatest(version string) bool{
//content := web.GetRemoteTextFile("http://nodejs.org/dist/latest/SHASUMS256.txt")
url := web.GetFullNodeUrl("latest/SHASUMS256.txt");
content := web.GetRemoteTextFile(url)
re := regexp.MustCompile("node-v(.+)+msi")
reg := regexp.MustCompile("node-v|-x.+")
latest := reg.ReplaceAllString(re.FindString(content),"")
var vArr = strings.Split(version,".")
var lArr = strings.Split(latest, ".")
for index := range lArr {
lat,_ := strconv.Atoi(lArr[index])
ver,_ := strconv.Atoi(vArr[index])
//Should check for valid input (checking for conversion errors) but this tool is made to trust the user
if ver < lat {
return false
} else if ver > lat {
return true
}
}
return false
cmd := exec.Command("cmd", "/d", "echo", "testing")
var output bytes.Buffer
var _stderr bytes.Buffer
cmd.Stdout = &output
cmd.Stderr = &_stderr
perr := cmd.Run()
if perr != nil {
fmt.Println(fmt.Sprint(perr) + ": " + _stderr.String())
return
}
}
*/

func install(version string, cpuarch string) {
args := os.Args
Expand Down Expand Up @@ -213,7 +198,7 @@ func install(version string, cpuarch string) {
version = cleanVersion(version)
}

if CheckVersionExceedsLatest(version) {
if checkVersionExceedsLatest(version) {
fmt.Println("Node.js v"+version+" is not yet released or available.")
return
}
Expand Down Expand Up @@ -356,8 +341,9 @@ func uninstall(version string) {
fmt.Printf("Uninstalling node v"+version+"...")
v, _ := node.GetCurrentVersion()
if v == version {
cmd := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "rmdir", env.symlink)
cmd.Run()
runElevated(fmt.Sprintf(`"%s" cmd /C rmdir "%s"`,
filepath.Join(env.root, "elevate.cmd"),
filepath.Clean(env.symlink)))
}
e := os.RemoveAll(filepath.Join(env.root, "v"+version))
if e != nil {
Expand All @@ -381,24 +367,6 @@ func findLatestSubVersion(version string) string {
return latest
}

func cleanVersion(version string) string {
re := regexp.MustCompile("\\d+.\\d+.\\d+")
matched := re.FindString(version)

if len(matched) == 0 {
re = regexp.MustCompile("\\d+.\\d+")
matched = re.FindString(version)
if len(matched) == 0 {
matched = version + ".0.0"
} else {
matched = matched + ".0"
}
fmt.Println(matched)
}

return matched
}

func use(version string, cpuarch string) {
if version == "32" || version == "64" {
cpuarch = version
Expand Down Expand Up @@ -426,30 +394,22 @@ func use(version string, cpuarch string) {
return
}

// Create or update the symlink
// Remove symlink if it already exists
sym, _ := os.Stat(env.symlink)
if sym != nil {
cmd := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "rmdir", filepath.Clean(env.symlink))
var output bytes.Buffer
var _stderr bytes.Buffer
cmd.Stdout = &output
cmd.Stderr = &_stderr
perr := cmd.Run()
if perr != nil {
fmt.Println(fmt.Sprint(perr) + ": " + _stderr.String())
return
if !runElevated(fmt.Sprintf(`"%s" cmd /C rmdir "%s"`,
filepath.Join(env.root, "elevate.cmd"),
filepath.Clean(env.symlink))) {
return
}
}

c := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "mklink", "/D", filepath.Clean(env.symlink), filepath.Join(env.root, "v"+version))
var out bytes.Buffer
var stderr bytes.Buffer
c.Stdout = &out
c.Stderr = &stderr
err := c.Run()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
return
// Create new symlink
if !runElevated(fmt.Sprintf(`"%s" cmd /C mklink /D "%s" "%s"`,
filepath.Join(env.root, "elevate.cmd"),
filepath.Clean(env.symlink),
filepath.Join(env.root, "v"+version))) {
return
}

// Use the assigned CPU architecture
Expand Down Expand Up @@ -600,8 +560,12 @@ func enable() {
}

func disable() {
cmd := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "rmdir", env.symlink)
cmd.Run()
if !runElevated(fmt.Sprintf(`"%s" cmd /C rmdir "%s"`,
filepath.Join(env.root, "elevate.cmd"),
filepath.Clean(env.symlink))) {
return
}

fmt.Println("nvm disabled")
}

Expand All @@ -614,7 +578,7 @@ func help() {
fmt.Println(" Optionally specify whether to install the 32 or 64 bit version (defaults to system arch).")
fmt.Println(" Set [arch] to \"all\" to install 32 AND 64 bit versions.")
fmt.Println(" Add --insecure to the end of this command to bypass SSL validation of the remote download server.")
fmt.Println(" nvm list [available] : List the node.js installations. Type \"available\" at the end to see what can be installed. Aliased as ls.")
fmt.Println(" nvm list [available] : List the node.js installations. Type \"available\" at the end to see what can be installed. Aliased as ls.")
fmt.Println(" nvm on : Enable node.js version management.")
fmt.Println(" nvm off : Disable node.js version management.")
fmt.Println(" nvm proxy [url] : Set a proxy to use for downloads. Leave [url] blank to see the current proxy.")
Expand All @@ -630,12 +594,56 @@ func help() {
fmt.Println(" nvm version : Displays the current running version of nvm for Windows. Aliased as v.")
fmt.Println(" ")
}
// ===============================================================
// END | CLI functions
// ===============================================================

// ===============================================================
// BEGIN | Utility functions
// ===============================================================
func checkVersionExceedsLatest(version string) bool{
//content := web.GetRemoteTextFile("http://nodejs.org/dist/latest/SHASUMS256.txt")
url := web.GetFullNodeUrl("latest/SHASUMS256.txt");
content := web.GetRemoteTextFile(url)
re := regexp.MustCompile("node-v(.+)+msi")
reg := regexp.MustCompile("node-v|-x.+")
latest := reg.ReplaceAllString(re.FindString(content),"")
var vArr = strings.Split(version,".")
var lArr = strings.Split(latest, ".")
for index := range lArr {
lat,_ := strconv.Atoi(lArr[index])
ver,_ := strconv.Atoi(vArr[index])
//Should check for valid input (checking for conversion errors) but this tool is made to trust the user
if ver < lat {
return false
} else if ver > lat {
return true
}
}
return false
}

func cleanVersion(version string) string {
re := regexp.MustCompile("\\d+.\\d+.\\d+")
matched := re.FindString(version)

if len(matched) == 0 {
re = regexp.MustCompile("\\d+.\\d+")
matched = re.FindString(version)
if len(matched) == 0 {
matched = version + ".0.0"
} else {
matched = matched + ".0"
}
fmt.Println(matched)
}

return matched
}

// Given a node.js version, returns the associated npm version
func getNpmVersion(nodeversion string) string {

_, _, _, _, _, npm := node.GetAvailable()

return npm[nodeversion]
}

Expand All @@ -651,13 +659,54 @@ func updateRootDir(path string) {
fmt.Println("\nRoot has been set to "+path)
}

func runElevated(command string) bool {
c := exec.Command("cmd") // dummy executable that actually needs to exist but we'll overwrite using .SysProcAttr

// Based on the official docs, syscall.SysProcAttr.CmdLine doesn't exist.
// But it does and is vital:
// https://github.com/golang/go/issues/15566#issuecomment-333274825
// https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773
c.SysProcAttr = &syscall.SysProcAttr{CmdLine: command}

var stderr bytes.Buffer
c.Stderr = &stderr

err := c.Run()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
return false
}

return true
}

func saveSettings() {
content := "root: " + strings.Trim(env.root, " \n\r") + "\r\narch: " + strings.Trim(env.arch, " \n\r") + "\r\nproxy: " + strings.Trim(env.proxy, " \n\r") + "\r\noriginalpath: " + strings.Trim(env.originalpath, " \n\r") + "\r\noriginalversion: " + strings.Trim(env.originalversion, " \n\r")
content = content + "\r\nnode_mirror: " + strings.Trim(env.node_mirror, " \n\r") + "\r\nnpm_mirror: " + strings.Trim(env.npm_mirror, " \n\r")
ioutil.WriteFile(env.settings, []byte(content), 0644)
}

func Setup() {
// NOT USED?
/*
func useArchitecture(a string) {
if strings.ContainsAny("32",os.Getenv("PROCESSOR_ARCHITECTURE")) {
fmt.Println("This computer only supports 32-bit processing.")
return
}
if a == "32" || a == "64" {
env.arch = a
saveSettings()
fmt.Println("Set to "+a+"-bit mode")
} else {
fmt.Println("Cannot set architecture to "+a+". Must be 32 or 64 are acceptable values.")
}
}
*/
// ===============================================================
// END | Utility functions
// ===============================================================

func setup() {
lines, err := file.ReadLines(env.settings)
if err != nil {
fmt.Println("\nERROR",err)
Expand Down