1
1
package main
2
2
3
3
import (
4
+ "bytes"
4
5
"fmt"
6
+ "io/ioutil"
5
7
"log"
6
8
"os"
7
9
"os/exec"
8
- "strings"
9
- "io/ioutil"
10
+ "path/filepath"
10
11
"regexp"
11
- "bytes"
12
+ "strconv"
13
+ "strings"
14
+ "syscall"
12
15
"time"
13
16
"./nvm/web"
14
17
"./nvm/arch"
15
18
"./nvm/file"
16
19
"./nvm/node"
17
- "strconv"
18
- "path/filepath"
19
20
"github.com/olekukonko/tablewriter"
20
21
)
21
22
@@ -57,7 +58,7 @@ func main() {
57
58
detail := ""
58
59
procarch := arch .Validate (env .arch )
59
60
60
- Setup ()
61
+ setup ()
61
62
62
63
// Capture any additional arguments
63
64
if len (args ) > 2 {
@@ -114,13 +115,17 @@ func main() {
114
115
env .proxy = detail
115
116
saveSettings ()
116
117
}
117
- case "update" : update ()
118
+
119
+ //case "update": update()
118
120
case "node_mirror" : setNodeMirror (detail )
119
121
case "npm_mirror" : setNpmMirror (detail )
120
122
default : help ()
121
123
}
122
124
}
123
125
126
+ // ===============================================================
127
+ // BEGIN | CLI functions
128
+ // ===============================================================
124
129
func setNodeMirror (uri string ) {
125
130
env .node_mirror = uri
126
131
saveSettings ()
@@ -131,40 +136,20 @@ func setNpmMirror(uri string) {
131
136
saveSettings ()
132
137
}
133
138
139
+ /*
134
140
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
+ }
167
151
}
152
+ */
168
153
169
154
func install (version string , cpuarch string ) {
170
155
args := os .Args
@@ -213,7 +198,7 @@ func install(version string, cpuarch string) {
213
198
version = cleanVersion (version )
214
199
}
215
200
216
- if CheckVersionExceedsLatest (version ) {
201
+ if checkVersionExceedsLatest (version ) {
217
202
fmt .Println ("Node.js v" + version + " is not yet released or available." )
218
203
return
219
204
}
@@ -356,8 +341,9 @@ func uninstall(version string) {
356
341
fmt .Printf ("Uninstalling node v" + version + "..." )
357
342
v , _ := node .GetCurrentVersion ()
358
343
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 )))
361
347
}
362
348
e := os .RemoveAll (filepath .Join (env .root , "v" + version ))
363
349
if e != nil {
@@ -381,24 +367,6 @@ func findLatestSubVersion(version string) string {
381
367
return latest
382
368
}
383
369
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
-
402
370
func use (version string , cpuarch string ) {
403
371
if version == "32" || version == "64" {
404
372
cpuarch = version
@@ -426,30 +394,22 @@ func use(version string, cpuarch string) {
426
394
return
427
395
}
428
396
429
- // Create or update the symlink
397
+ // Remove symlink if it already exists
430
398
sym , _ := os .Stat (env .symlink )
431
399
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
441
404
}
442
405
}
443
406
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
453
413
}
454
414
455
415
// Use the assigned CPU architecture
@@ -600,8 +560,12 @@ func enable() {
600
560
}
601
561
602
562
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
+
605
569
fmt .Println ("nvm disabled" )
606
570
}
607
571
@@ -614,7 +578,7 @@ func help() {
614
578
fmt .Println (" Optionally specify whether to install the 32 or 64 bit version (defaults to system arch)." )
615
579
fmt .Println (" Set [arch] to \" all\" to install 32 AND 64 bit versions." )
616
580
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." )
618
582
fmt .Println (" nvm on : Enable node.js version management." )
619
583
fmt .Println (" nvm off : Disable node.js version management." )
620
584
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() {
630
594
fmt .Println (" nvm version : Displays the current running version of nvm for Windows. Aliased as v." )
631
595
fmt .Println (" " )
632
596
}
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
+ }
633
643
634
644
// Given a node.js version, returns the associated npm version
635
645
func getNpmVersion (nodeversion string ) string {
636
-
637
646
_ , _ , _ , _ , _ , npm := node .GetAvailable ()
638
-
639
647
return npm [nodeversion ]
640
648
}
641
649
@@ -651,13 +659,54 @@ func updateRootDir(path string) {
651
659
fmt .Println ("\n Root has been set to " + path )
652
660
}
653
661
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
+
654
683
func saveSettings () {
655
684
content := "root: " + strings .Trim (env .root , " \n \r " ) + "\r \n arch: " + strings .Trim (env .arch , " \n \r " ) + "\r \n proxy: " + strings .Trim (env .proxy , " \n \r " ) + "\r \n originalpath: " + strings .Trim (env .originalpath , " \n \r " ) + "\r \n originalversion: " + strings .Trim (env .originalversion , " \n \r " )
656
685
content = content + "\r \n node_mirror: " + strings .Trim (env .node_mirror , " \n \r " ) + "\r \n npm_mirror: " + strings .Trim (env .npm_mirror , " \n \r " )
657
686
ioutil .WriteFile (env .settings , []byte (content ), 0644 )
658
687
}
659
688
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 () {
661
710
lines , err := file .ReadLines (env .settings )
662
711
if err != nil {
663
712
fmt .Println ("\n ERROR" ,err )
0 commit comments