提交 8e6cecd6 编写于 作者: C Corey Butler

Fixed symlink issues and added a settings file

上级 70d972c1
......@@ -11,21 +11,31 @@ import (
"io/ioutil"
"regexp"
"bytes"
"encoding/json"
"archive/zip"
"log"
"bufio"
)
var root = ""
var symlink = ""
func main() {
args := os.Args
detail := ""
setRootDir(filepath.Dir(args[0]))
setRootDir()
// Capture any additional arguments
if (len(args) > 2) {
detail = strings.ToLower(args[2])
}
if (len(args) < 2){
help()
return
}
// Run the appropriate method
switch args[1] {
case "install": install(detail)
......@@ -58,27 +68,47 @@ func install(version string) {
// Check to see if the version is already installed
if !isVersionInstalled(version) {
// If the version does not exist, download it to the temp directory.
success := download(version);
// Make the output directories
os.Mkdir(root+"\\v"+version,os.ModeDir)
os.Mkdir(root+"\\v"+version+"\\node_modules",os.ModeDir)
// Download node
success := downloadNodeJs(version);
// Run the installer
// If successful, add npm
if success {
fmt.Printf("Installing v"+version+"... ")
os.Mkdir(root+"\\v"+version,os.ModeDir)
cmd := exec.Command("msiexec.exe","/i",os.TempDir()+"\\"+"node-v"+version+".msi","INSTALLDIR="+root+"\\v"+version,"/qb")
err := cmd.Run()
if err != nil {
fmt.Println("ERROR")
fmt.Print(err)
os.Exit(1)
npmv := getNpmVersion(version)
success = downloadNpm(getNpmVersion(version))
if success {
fmt.Printf("Installing npm v"+npmv+"...")
// Extract npm to the temp directory
unzip(os.TempDir()+"\\npm-v"+npmv+".zip",os.TempDir()+"\\nvm-npm")
// Copy the npm and npm.cmd files to the installation directory
os.Rename(os.TempDir()+"\\nvm-npm\\npm-"+npmv+"\\bin\\npm",root+"\\v"+version+"\\npm")
os.Rename(os.TempDir()+"\\nvm-npm\\npm-"+npmv+"\\bin\\npm.cmd",root+"\\v"+version+"\\npm.cmd")
os.Rename(os.TempDir()+"\\nvm-npm\\npm-"+npmv,root+"\\v"+version+"\\node_modules\\npm")
// Remove the source file
os.RemoveAll(os.TempDir()+"\\nvm-npm")
fmt.Printf(" done.")
fmt.Println("\n\nInstallation complete. If you want to use this version, type\n\nnvm use "+version)
} else {
fmt.Println("Could not download npm for node v"+version+".")
fmt.Println("Please visit https://github.com/npm/npm/releases/tag/v"+npmv+" to download npm.")
fmt.Println("It should be extracted to "+root+"\\v"+version)
}
fmt.Printf("done.")
} else {
fmt.Println("Could not download node.js executable for version "+version+".")
}
return
// Clean up
fmt.Printf("\nCleaning up... ")
os.Remove(os.TempDir()+"\\"+"node-v"+version+".msi")
fmt.Printf("done.\n")
// Move node and npm to their directory, then update the symlink
// Remember to set the symlink path in the PATH during the installation
// If this is ever shipped for Mac, it should use homebrew.
// If this ever ships on Linux, it should be on bintray so it can use yum, apt-get, etc.
return
} else {
......@@ -98,7 +128,7 @@ func uninstall(version string) {
// Determine if the version exists and skip if it doesn't
if isVersionInstalled(version) {
fmt.Printf("\nUninstalling node v"+version+"...")
fmt.Printf("Uninstalling node v"+version+"...")
e := os.RemoveAll(root+"\\v"+version)
if e != nil {
fmt.Println("Error removing node v"+version)
......@@ -118,8 +148,23 @@ func use(version string) {
return
}
// Create the symlink
c := exec.Command(root+"\\elevate.cmd", "cmd", "/C", "mklink", "/D", root+"\\action", root+"\\v"+version)
// Create or update the symlink
sym, serr := os.Stat(symlink)
sym = sym
if serr == nil {
cmd := exec.Command(root+"\\elevate.cmd", "cmd", "/C", "rmdir", 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
}
}
c := exec.Command(root+"\\elevate.cmd", "cmd", "/C", "mklink", "/D", symlink, root+"\\v"+version)
var out bytes.Buffer
var stderr bytes.Buffer
c.Stdout = &out
......@@ -137,7 +182,7 @@ func list(listtype string) {
listtype = "installed"
}
if listtype != "installed" && listtype != "available" {
fmt.Println("\nInvalid list option.\n\nPlease use on of the following\n - wnvm list\n - wnvm list installed\n - wnvm list available")
fmt.Println("\nInvalid list option.\n\nPlease use on of the following\n - nvm list\n - nvm list installed\n - nvm list available")
help()
return
}
......@@ -154,28 +199,18 @@ func disable() {
fmt.Printf("Disable by removing the symlink in PATH var")
}
func setRootDir(path string) {
// Prompt user, warning them what they're going to do
rootdir, err := filepath.Abs(filepath.Dir(path+"\\"))
if err != nil {
fmt.Println("Error setting root directory")
os.Exit(1)
}
root = rootdir
fmt.Println("\nSet the root path to "+root)
}
func help() {
fmt.Println("\nUsage:\n")
fmt.Println(" nvm install <version> : The version can be a node.js version or \"latest\" for the latest stable version.")
fmt.Println(" nvm uninstall <version> : The version must be a specific version.")
fmt.Println(" nvm use <version> : Switch to use the specified version.")
fmt.Println(" nvm list [type] : type can be \"available\" (from nodejs.org),")
fmt.Println(" \"installed\" (what is currently on the computer),")
fmt.Println(" or left blank (same as \"installed\").")
fmt.Println(" nvm enable : Enable node.js version management.")
fmt.Println(" nvm disable : Disable node.js version management.")
fmt.Println(" nvm root <path> : Set the directory where wnvm should install different node.js versions.\n")
fmt.Println(" \"installed\" (what is currently on the computer),")
fmt.Println(" or left blank (same as \"installed\").")
fmt.Println(" nvm on : Enable node.js version management.")
fmt.Println(" nvm off : Disable node.js version management.")
fmt.Println(" nvm root <path> : Set the directory where wnvm should install different node.js versions.")
fmt.Println(" If <path> is not set, the current root will be displayed.\n")
}
func getRemoteTextFile(url string) string {
......@@ -197,13 +232,61 @@ func getRemoteTextFile(url string) string {
return ""
}
// Download an MSI to the temp directory
func download(v string) bool {
// Given a node.js version, returns the associated npm version
func getNpmVersion(nodeversion string) string {
// Get raw text
text := getRemoteTextFile("https://raw.githubusercontent.com/coreybutler/nodedistro/master/nodeversions.json")
// Parse
var data interface{}
json.Unmarshal([]byte(text), &data);
body := data.(map[string]interface{})
all := body["all"]
npm := all.(map[string]interface{})
return npm[nodeversion].(string)
}
func downloadNodeJs(v string) bool {
url := "http://nodejs.org/dist/v"+v+"/node-v"+v+"-x86.msi"
fileName := os.TempDir()+"\\"+"node-v"+v+".msi"
url := "http://nodejs.org/dist/v"+v+"/node.exe"
fileName := root+"\\v"+v+"\\node.exe"
fmt.Printf("\nDownloading node.js version "+v+"... ")
fmt.Printf("Downloading node.js version "+v+"... ")
output, err := os.Create(fileName)
if err != nil {
fmt.Println("Error while creating", fileName, "-", err)
}
defer output.Close()
response, err := http.Get(url)
if err != nil {
fmt.Println("Error while downloading", url, "-", err)
}
defer response.Body.Close()
n, err := io.Copy(output, response.Body)
if err != nil {
fmt.Println("Error while downloading", url, "-", err)
}
if response.Status[0:3] == "200" {
fmt.Println(n, "bytes downloaded.")
} else {
fmt.Println("ERROR")
}
return response.Status[0:3] == "200"
}
func downloadNpm(v string) bool {
url := "https://github.com/npm/npm/archive/v"+v+".zip"
fileName := os.TempDir()+"\\"+"npm-v"+v+".zip"
fmt.Printf("Downloading npm version "+v+"... ")
output, err := os.Create(fileName)
if err != nil {
......@@ -236,3 +319,79 @@ func isVersionInstalled(version string) bool {
src = src
return err == nil
}
// Function courtesy http://stackoverflow.com/users/1129149/swtdrgn
func unzip(src, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer r.Close()
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()
fpath := filepath.Join(dest, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, f.Mode())
} else {
var fdir string
if lastIndex := strings.LastIndex(fpath,string(os.PathSeparator)); lastIndex > -1 {
fdir = fpath[:lastIndex]
}
err = os.MkdirAll(fdir, f.Mode())
if err != nil {
log.Fatal(err)
return err
}
f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
}
return nil
}
func readLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
func setRootDir() {
lines, err := readLines(os.Getenv("APPDATA")+"\\nvm\\settings.txt")
if err != nil {
fmt.Println("\nERROR",err)
os.Exit(1)
}
// Process each line and extract the value
for _, line := range lines {
if strings.Contains(line,"root:") {
root = strings.Trim(regexp.MustCompile("root:").ReplaceAllString(line,"")," ")
} else if strings.Contains(line,"path:") {
symlink = strings.Trim(regexp.MustCompile("path:").ReplaceAllString(line,"")," ")
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册