Skip to content

Commit 08fb700

Browse files
authored
Merge pull request #355 from s-h-a-d-o-w/master
Fixes #41 - Issue with blank spaces in path
2 parents 943cae1 + be7f20a commit 08fb700

File tree

1 file changed

+134
-85
lines changed

1 file changed

+134
-85
lines changed

src/nvm.go

Lines changed: 134 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
package main
22

33
import (
4+
"bytes"
45
"fmt"
6+
"io/ioutil"
57
"log"
68
"os"
79
"os/exec"
8-
"strings"
9-
"io/ioutil"
10+
"path/filepath"
1011
"regexp"
11-
"bytes"
12+
"strconv"
13+
"strings"
14+
"syscall"
1215
"time"
1316
"./nvm/web"
1417
"./nvm/arch"
1518
"./nvm/file"
1619
"./nvm/node"
17-
"strconv"
18-
"path/filepath"
1920
"github.com/olekukonko/tablewriter"
2021
)
2122

@@ -57,7 +58,7 @@ func main() {
5758
detail := ""
5859
procarch := arch.Validate(env.arch)
5960

60-
Setup()
61+
setup()
6162

6263
// Capture any additional arguments
6364
if len(args) > 2 {
@@ -114,13 +115,17 @@ func main() {
114115
env.proxy = detail
115116
saveSettings()
116117
}
117-
case "update": update()
118+
119+
//case "update": update()
118120
case "node_mirror": setNodeMirror(detail)
119121
case "npm_mirror": setNpmMirror(detail)
120122
default: help()
121123
}
122124
}
123125

126+
// ===============================================================
127+
// BEGIN | CLI functions
128+
// ===============================================================
124129
func setNodeMirror(uri string) {
125130
env.node_mirror = uri
126131
saveSettings()
@@ -131,40 +136,20 @@ func setNpmMirror(uri string) {
131136
saveSettings()
132137
}
133138

139+
/*
134140
func update() {
135-
// cmd := exec.Command("cmd", "/d", "echo", "testing")
136-
// var output bytes.Buffer
137-
// var _stderr bytes.Buffer
138-
// cmd.Stdout = &output
139-
// cmd.Stderr = &_stderr
140-
// perr := cmd.Run()
141-
// if perr != nil {
142-
// fmt.Println(fmt.Sprint(perr) + ": " + _stderr.String())
143-
// return
144-
// }
145-
}
146-
147-
func CheckVersionExceedsLatest(version string) bool{
148-
//content := web.GetRemoteTextFile("http://nodejs.org/dist/latest/SHASUMS256.txt")
149-
url := web.GetFullNodeUrl("latest/SHASUMS256.txt");
150-
content := web.GetRemoteTextFile(url)
151-
re := regexp.MustCompile("node-v(.+)+msi")
152-
reg := regexp.MustCompile("node-v|-x.+")
153-
latest := reg.ReplaceAllString(re.FindString(content),"")
154-
var vArr = strings.Split(version,".")
155-
var lArr = strings.Split(latest, ".")
156-
for index := range lArr {
157-
lat,_ := strconv.Atoi(lArr[index])
158-
ver,_ := strconv.Atoi(vArr[index])
159-
//Should check for valid input (checking for conversion errors) but this tool is made to trust the user
160-
if ver < lat {
161-
return false
162-
} else if ver > lat {
163-
return true
164-
}
165-
}
166-
return false
141+
cmd := exec.Command("cmd", "/d", "echo", "testing")
142+
var output bytes.Buffer
143+
var _stderr bytes.Buffer
144+
cmd.Stdout = &output
145+
cmd.Stderr = &_stderr
146+
perr := cmd.Run()
147+
if perr != nil {
148+
fmt.Println(fmt.Sprint(perr) + ": " + _stderr.String())
149+
return
150+
}
167151
}
152+
*/
168153

169154
func install(version string, cpuarch string) {
170155
args := os.Args
@@ -213,7 +198,7 @@ func install(version string, cpuarch string) {
213198
version = cleanVersion(version)
214199
}
215200

216-
if CheckVersionExceedsLatest(version) {
201+
if checkVersionExceedsLatest(version) {
217202
fmt.Println("Node.js v"+version+" is not yet released or available.")
218203
return
219204
}
@@ -356,8 +341,9 @@ func uninstall(version string) {
356341
fmt.Printf("Uninstalling node v"+version+"...")
357342
v, _ := node.GetCurrentVersion()
358343
if v == version {
359-
cmd := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "rmdir", env.symlink)
360-
cmd.Run()
344+
runElevated(fmt.Sprintf(`"%s" cmd /C rmdir "%s"`,
345+
filepath.Join(env.root, "elevate.cmd"),
346+
filepath.Clean(env.symlink)))
361347
}
362348
e := os.RemoveAll(filepath.Join(env.root, "v"+version))
363349
if e != nil {
@@ -381,24 +367,6 @@ func findLatestSubVersion(version string) string {
381367
return latest
382368
}
383369

384-
func cleanVersion(version string) string {
385-
re := regexp.MustCompile("\\d+.\\d+.\\d+")
386-
matched := re.FindString(version)
387-
388-
if len(matched) == 0 {
389-
re = regexp.MustCompile("\\d+.\\d+")
390-
matched = re.FindString(version)
391-
if len(matched) == 0 {
392-
matched = version + ".0.0"
393-
} else {
394-
matched = matched + ".0"
395-
}
396-
fmt.Println(matched)
397-
}
398-
399-
return matched
400-
}
401-
402370
func use(version string, cpuarch string) {
403371
if version == "32" || version == "64" {
404372
cpuarch = version
@@ -426,30 +394,22 @@ func use(version string, cpuarch string) {
426394
return
427395
}
428396

429-
// Create or update the symlink
397+
// Remove symlink if it already exists
430398
sym, _ := os.Stat(env.symlink)
431399
if sym != nil {
432-
cmd := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "rmdir", filepath.Clean(env.symlink))
433-
var output bytes.Buffer
434-
var _stderr bytes.Buffer
435-
cmd.Stdout = &output
436-
cmd.Stderr = &_stderr
437-
perr := cmd.Run()
438-
if perr != nil {
439-
fmt.Println(fmt.Sprint(perr) + ": " + _stderr.String())
440-
return
400+
if !runElevated(fmt.Sprintf(`"%s" cmd /C rmdir "%s"`,
401+
filepath.Join(env.root, "elevate.cmd"),
402+
filepath.Clean(env.symlink))) {
403+
return
441404
}
442405
}
443406

444-
c := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "mklink", "/D", filepath.Clean(env.symlink), filepath.Join(env.root, "v"+version))
445-
var out bytes.Buffer
446-
var stderr bytes.Buffer
447-
c.Stdout = &out
448-
c.Stderr = &stderr
449-
err := c.Run()
450-
if err != nil {
451-
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
452-
return
407+
// Create new symlink
408+
if !runElevated(fmt.Sprintf(`"%s" cmd /C mklink /D "%s" "%s"`,
409+
filepath.Join(env.root, "elevate.cmd"),
410+
filepath.Clean(env.symlink),
411+
filepath.Join(env.root, "v"+version))) {
412+
return
453413
}
454414

455415
// Use the assigned CPU architecture
@@ -600,8 +560,12 @@ func enable() {
600560
}
601561

602562
func disable() {
603-
cmd := exec.Command(filepath.Join(env.root, "elevate.cmd"), "cmd", "/C", "rmdir", env.symlink)
604-
cmd.Run()
563+
if !runElevated(fmt.Sprintf(`"%s" cmd /C rmdir "%s"`,
564+
filepath.Join(env.root, "elevate.cmd"),
565+
filepath.Clean(env.symlink))) {
566+
return
567+
}
568+
605569
fmt.Println("nvm disabled")
606570
}
607571

@@ -614,7 +578,7 @@ func help() {
614578
fmt.Println(" Optionally specify whether to install the 32 or 64 bit version (defaults to system arch).")
615579
fmt.Println(" Set [arch] to \"all\" to install 32 AND 64 bit versions.")
616580
fmt.Println(" Add --insecure to the end of this command to bypass SSL validation of the remote download server.")
617-
fmt.Println(" nvm list [available] : List the node.js installations. Type \"available\" at the end to see what can be installed. Aliased as ls.")
581+
fmt.Println(" nvm list [available] : List the node.js installations. Type \"available\" at the end to see what can be installed. Aliased as ls.")
618582
fmt.Println(" nvm on : Enable node.js version management.")
619583
fmt.Println(" nvm off : Disable node.js version management.")
620584
fmt.Println(" nvm proxy [url] : Set a proxy to use for downloads. Leave [url] blank to see the current proxy.")
@@ -630,12 +594,56 @@ func help() {
630594
fmt.Println(" nvm version : Displays the current running version of nvm for Windows. Aliased as v.")
631595
fmt.Println(" ")
632596
}
597+
// ===============================================================
598+
// END | CLI functions
599+
// ===============================================================
600+
601+
// ===============================================================
602+
// BEGIN | Utility functions
603+
// ===============================================================
604+
func checkVersionExceedsLatest(version string) bool{
605+
//content := web.GetRemoteTextFile("http://nodejs.org/dist/latest/SHASUMS256.txt")
606+
url := web.GetFullNodeUrl("latest/SHASUMS256.txt");
607+
content := web.GetRemoteTextFile(url)
608+
re := regexp.MustCompile("node-v(.+)+msi")
609+
reg := regexp.MustCompile("node-v|-x.+")
610+
latest := reg.ReplaceAllString(re.FindString(content),"")
611+
var vArr = strings.Split(version,".")
612+
var lArr = strings.Split(latest, ".")
613+
for index := range lArr {
614+
lat,_ := strconv.Atoi(lArr[index])
615+
ver,_ := strconv.Atoi(vArr[index])
616+
//Should check for valid input (checking for conversion errors) but this tool is made to trust the user
617+
if ver < lat {
618+
return false
619+
} else if ver > lat {
620+
return true
621+
}
622+
}
623+
return false
624+
}
625+
626+
func cleanVersion(version string) string {
627+
re := regexp.MustCompile("\\d+.\\d+.\\d+")
628+
matched := re.FindString(version)
629+
630+
if len(matched) == 0 {
631+
re = regexp.MustCompile("\\d+.\\d+")
632+
matched = re.FindString(version)
633+
if len(matched) == 0 {
634+
matched = version + ".0.0"
635+
} else {
636+
matched = matched + ".0"
637+
}
638+
fmt.Println(matched)
639+
}
640+
641+
return matched
642+
}
633643

634644
// Given a node.js version, returns the associated npm version
635645
func getNpmVersion(nodeversion string) string {
636-
637646
_, _, _, _, _, npm := node.GetAvailable()
638-
639647
return npm[nodeversion]
640648
}
641649

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

662+
func runElevated(command string) bool {
663+
c := exec.Command("cmd") // dummy executable that actually needs to exist but we'll overwrite using .SysProcAttr
664+
665+
// Based on the official docs, syscall.SysProcAttr.CmdLine doesn't exist.
666+
// But it does and is vital:
667+
// https://github.com/golang/go/issues/15566#issuecomment-333274825
668+
// https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773
669+
c.SysProcAttr = &syscall.SysProcAttr{CmdLine: command}
670+
671+
var stderr bytes.Buffer
672+
c.Stderr = &stderr
673+
674+
err := c.Run()
675+
if err != nil {
676+
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
677+
return false
678+
}
679+
680+
return true
681+
}
682+
654683
func saveSettings() {
655684
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")
656685
content = content + "\r\nnode_mirror: " + strings.Trim(env.node_mirror, " \n\r") + "\r\nnpm_mirror: " + strings.Trim(env.npm_mirror, " \n\r")
657686
ioutil.WriteFile(env.settings, []byte(content), 0644)
658687
}
659688

660-
func Setup() {
689+
// NOT USED?
690+
/*
691+
func useArchitecture(a string) {
692+
if strings.ContainsAny("32",os.Getenv("PROCESSOR_ARCHITECTURE")) {
693+
fmt.Println("This computer only supports 32-bit processing.")
694+
return
695+
}
696+
if a == "32" || a == "64" {
697+
env.arch = a
698+
saveSettings()
699+
fmt.Println("Set to "+a+"-bit mode")
700+
} else {
701+
fmt.Println("Cannot set architecture to "+a+". Must be 32 or 64 are acceptable values.")
702+
}
703+
}
704+
*/
705+
// ===============================================================
706+
// END | Utility functions
707+
// ===============================================================
708+
709+
func setup() {
661710
lines, err := file.ReadLines(env.settings)
662711
if err != nil {
663712
fmt.Println("\nERROR",err)

0 commit comments

Comments
 (0)