Skip to content

Commit

Permalink
Add debugging option to identify IPv6 configurations and remind users…
Browse files Browse the repository at this point in the history
… it is slow.
  • Loading branch information
coreybutler committed Nov 7, 2023
1 parent c1a6337 commit 3c736ab
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 2 deletions.
35 changes: 35 additions & 0 deletions buildtools/ResourceHacker.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[MRU List]
MRU1=C:\Users\corey\OneDrive\Documents\workspace\libraries\oss\coreybutler\nvm-windows\dist\nvm.exe
MRU2=C:\Users\corey\nvm test\nvm.exe
MRU3=
MRU4=
MRU5=
MRU6=
MRU7=
MRU8=

[Setup]
left=4150
top=798
width=1200
height=660
MaximizedState=0
MenuEditMode=0
DisableGridlines=0
vsplit=300
LastDir=C:\Users\corey\OneDrive\Documents\workspace\libraries\oss\coreybutler\nvm-windows\dist
ToolbarSize=3

[MonospaceFont]
Name=Courier New
Size=9
Color=-16777208
Style=0

[Font]
Name=Tahoma
Size=9
Color=-16777208
CharSet=1
Style=0

14 changes: 14 additions & 0 deletions buildtools/iconize/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module iconize

go 1.20

require (
github.com/coreybutler/go-fsutil v1.2.1
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
)

require (
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 // indirect
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect
)
10 changes: 10 additions & 0 deletions buildtools/iconize/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/coreybutler/go-fsutil v1.2.1 h1:HlnBaPgJAYEDUwQu5zc1MzmaWtB6OSvIWLXnTA11g18=
github.com/coreybutler/go-fsutil v1.2.1/go.mod h1:tLG9p9LcRVBiKWtG8HC7btUpRY7uvl4xqEnCYagf0qc=
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794 h1:NVRJ0Uy0SOFcXSKLsS65OmI1sgCCfiDUPj+cwnH7GZw=
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 h1:5jaG59Zhd+8ZXe8C+lgiAGqkOaZBruqrWclLkgAww34=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc=
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
56 changes: 56 additions & 0 deletions buildtools/iconize/iconize.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package main

import (
"fmt"
"log"
"os"
"os/exec"
"syscall"

fs "github.com/coreybutler/go-fsutil"
)

const (
LR_LOADFROMFILE = 0x00000010
LR_DEFAULTSIZE = 0x00000040
IMAGE_ICON = 1
LR_DEFAULTCOLOR = 0x00000000
RT_ICON = 3
)

var (
modUser32 = syscall.NewLazyDLL("user32.dll")
procDestroyIcon = modUser32.NewProc("DestroyIcon")
modKernel32 = syscall.NewLazyDLL("kernel32.dll")
procUpdateResourceW = modKernel32.NewProc("UpdateResourceW")
procBeginUpdateResource = modKernel32.NewProc("BeginUpdateResourceW")
procEndUpdateResource = modKernel32.NewProc("EndUpdateResourceW")
procLoadImageW = modUser32.NewProc("LoadImageW")
)

func main() {
if len(os.Args) != 3 {
log.Println("Incorrect number of arguments. Expected 2: iconize <file> <icon>")
os.Exit(1)
}

exePath := fs.Abs(os.Args[1])
iconPath := fs.Abs(os.Args[2])

if !fs.Exists(exePath) {
log.Fatal(exePath + " does not exist")
}

if !fs.Exists(iconPath) {
log.Fatal(iconPath + " does not exist")
}

// Run Resource Hacker command to modify the icon
cmd := exec.Command("../ResourceHacker.exe", "-open", exePath, "-save", exePath, "-action", "modify", "-resource", iconPath, "-mask", "ICONGROUP,MAINICON,", "-log", "NUL")
err := cmd.Run()
if err != nil {
log.Fatal(err)
}

fmt.Println("Icon associated with EXE file successfully!")
}
1 change: 1 addition & 0 deletions src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/blang/semver v3.5.1+incompatible
github.com/coreybutler/go-fsutil v1.2.0
github.com/coreybutler/go-where v1.0.2
github.com/gonutz/w32/v2 v2.8.1
github.com/olekukonko/tablewriter v0.0.5
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
golang.org/x/sys v0.1.0
Expand Down
2 changes: 2 additions & 0 deletions src/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/coreybutler/go-fsutil v1.2.0 h1:kbm62NSofawglUppEOhpHC3NDf/J7ZpguBirB
github.com/coreybutler/go-fsutil v1.2.0/go.mod h1:B+6ufEkkRZgFwyR2sHEVG9dMzVBU3GbyGyYmCq7YkEk=
github.com/coreybutler/go-where v1.0.2 h1:Omit67KeTtKpvSJjezVxnVD4qMtvlXDlItiKpVCdcl4=
github.com/coreybutler/go-where v1.0.2/go.mod h1:IqV4saJiDXdNJURfTfVRywDHvY1IG5F+GXb2kmnmEe8=
github.com/gonutz/w32/v2 v2.8.1 h1:fTAzhg35iCGWqroImF18+A8GbI3MdXcTYuhvpBpd5CM=
github.com/gonutz/w32/v2 v2.8.1/go.mod h1:MgtHx0AScDVNKyB+kjyPder4xIi3XAcHS6LDDU2DmdE=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
Expand Down
161 changes: 159 additions & 2 deletions src/nvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func main() {
detail := ""
procarch := arch.Validate(env.arch)

if !isTerminal() {
alert("NVM for Windows should be run from a terminal such as CMD or PowerShell.", "Terminal Only")
os.Exit(0)
}

// Capture any additional arguments
if len(args) > 2 {
detail = args[2]
Expand Down Expand Up @@ -180,6 +185,102 @@ func setNpmMirror(uri string) {
saveSettings()
}

func isTerminal() bool {
fileInfo, err := os.Stdout.Stat()
if err != nil {
return false
}
return (fileInfo.Mode() & os.ModeCharDevice) != 0
}

// const (
// MB_YESNOCANCEL = 0x00000003
// MB_ICONINFORMATION = 0x00000040
// IDYES = 6
// IDNO = 7
// IDCANCEL = 2
// )

// func openTerminal(msg string, caption ...string) {
// title := "Alert"
// if len(caption) > 0 {
// title = caption[0]
// }

// labels := []string{"Open CMD", "Open PowerShell", "Close"}
// var buttons []*uint16
// for _, label := range labels {
// buttons = append(buttons, syscall.StringToUTF16Ptr(label))
// }
// buttons = append(buttons, nil)

// user32 := windows.NewLazySystemDLL("user32.dll")
// mbox := user32.NewProc("MessageBoxW")

// ret, _, _ := mbox.Call(
// uintptr(0),
// uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(msg))),
// uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
// MB_YESNOCANCEL|MB_ICONINFORMATION,
// uintptr(0),
// uintptr(unsafe.Pointer(&buttons[0])),
// )

// getActiveWindow := user32.NewProc("GetActiveWindow")
// activeWindow, _, _ := getActiveWindow.Call()
// hwnd := windows.Handle(activeWindow)

// // Command to open the program or file

// switch ret {
// case IDYES:
// cmd := exec.Command("cmd", "/C", "start", "cmd", "/K", "echo Run \"nvm\" for help...")
// err := cmd.Start()
// if err != nil {
// log.Fatal(err)
// }
// case IDNO:
// cmd := exec.Command("cmd", "/C", "start", "powershell", "/K", "echo Run \"nvm\" for help...")
// err := cmd.Start()
// if err != nil {
// log.Fatal(err)
// }
// case IDCANCEL:
// fmt.Println("User clicked 'Custom Cancel'")
// // Handle 'Custom Cancel' button click here
// default:
// fmt.Println("User closed the message box")
// // Handle message box close event here
// }

// postMessage := user32.NewProc("PostMessageW")
// wmClose := 0x0010
// _, _, _ = postMessage.Call(
// uintptr(hwnd),
// uintptr(wmClose),
// 0,
// 0,
// )
// }

func alert(msg string, caption ...string) {
user32 := windows.NewLazySystemDLL("user32.dll")
mbox := user32.NewProc("MessageBoxW")
getForegroundWindow := user32.NewProc("GetForegroundWindow")
var hwnd uintptr
ret, _, _ := getForegroundWindow.Call()
if ret != 0 {
hwnd = ret
}

title := "Alert"
if len(caption) > 0 {
title = caption[0]
}

mbox.Call(hwnd, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(msg))), uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(title))), uintptr(windows.MB_OK))
}

/*
func update() {
cmd := exec.Command("cmd", "/d", "echo", "testing")
Expand Down Expand Up @@ -862,6 +963,21 @@ func disable() {
fmt.Println("nvm disabled")
}

const (
VER_PLATFORM_WIN32s = 0
VER_PLATFORM_WIN32_WINDOWS = 1
VER_PLATFORM_WIN32_NT = 2
)

type OSVersionInfoEx struct {
OSVersionInfoSize uint32
MajorVersion uint32
MinorVersion uint32
BuildNumber uint32
PlatformId uint32
CSDVersion [128]uint16
}

func checkLocalEnvironment() {
problems := make([]string, 0)

Expand Down Expand Up @@ -955,6 +1071,19 @@ func checkLocalEnvironment() {
}
}

// Get Windows details
getVersionEx := kernel32.NewProc("GetVersionExW")
versionInfo := OSVersionInfoEx{
OSVersionInfoSize: uint32(unsafe.Sizeof(OSVersionInfoEx{})),
}
ret, _, _ := getVersionEx.Call(uintptr(unsafe.Pointer(&versionInfo)))
if ret == 0 {
fmt.Println("Failed to retrieve version information.")
}
// fmt.Printf(" %d.%d\n", versionInfo.MajorVersion, versionInfo.MinorVersion)
maj, min, patch := windows.RtlGetNtVersionNumbers()
fmt.Printf("\nWindows Version: %d.%d (Build %d)\n", maj, min, patch)

// SHELL in Linux
// TERM in Windows
// COMSPEC in Windows provides the terminal path
Expand Down Expand Up @@ -987,8 +1116,10 @@ func checkLocalEnvironment() {
out = string(output)
}

v := node.GetInstalled(env.root)

nvmhome := os.Getenv("NVM_HOME")
fmt.Printf("\nNVM4W Version: %v\nNVM4W Path: %v\nNVM4W Settings: %v\nNVM_HOME: %v\nNVM_SYMLINK: %v\nNode Installations: %v\n\nActive Node.js Version: %v", NvmVersion, path, home, nvmhome, symlink, env.root, out)
fmt.Printf("\nNVM4W Version: %v\nNVM4W Path: %v\nNVM4W Settings: %v\nNVM_HOME: %v\nNVM_SYMLINK: %v\nNode Installations: %v\n\nTotal Node.js Versions: %v\nActive Node.js Version: %v", NvmVersion, path, home, nvmhome, symlink, env.root, len(v), out)

if !nvmsymlinkfound {
problems = append(problems, "The NVM4W symlink ("+env.symlink+") was not found in the PATH environment variable.")
Expand All @@ -998,6 +1129,33 @@ func checkLocalEnvironment() {
problems = append(problems, "NVM_HOME and NVM_SYMLINK cannot be the same value ("+symlink+"). Change NVM_SYMLINK.")
}

fileInfo, err := os.Lstat(symlink)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("NVM_SYMLINK does not exist yet. This is auto-created when \"nvm use\" is run.")
} else {
problems = append(problems, "Could not determine if NVM_SYMLINK is actually a symlink: "+err.Error())
}
} else {
if fileInfo.Mode()&os.ModeSymlink != 0 {
targetPath, _ := os.Readlink(symlink)
targetFileInfo, _ := os.Lstat(targetPath)

if !targetFileInfo.Mode().IsDir() {
problems = append(problems, "NVM_SYMLINK is a symlink linking to a file instead of a directory.")
}
} else {
problems = append(problems, "NVM_SYMLINK ("+symlink+") is not a valid symlink.")
}
}

ipv6, err := web.IsLocalIPv6()
if err != nil {
problems = append(problems, "Connection type cannot be determined: "+err.Error())
} else if !ipv6 {
fmt.Println("\nIPv6 is enabled. This can slow downloads significantly.")
}

nodelist := web.Ping(web.GetFullNodeUrl("index.json"))
if !nodelist {
if len(env.node_mirror) > 0 && env.node_mirror != "none" {
Expand All @@ -1011,7 +1169,6 @@ func checkLocalEnvironment() {
}
}

v := node.GetInstalled(env.root)
invalid := make([]string, 0)
invalidnpm := make([]string, 0)
for i := 0; i < len(v); i++ {
Expand Down
29 changes: 29 additions & 0 deletions src/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"nvm/arch"
Expand Down Expand Up @@ -66,6 +67,34 @@ func GetFullNpmUrl(path string) string {
return npmBaseAddress + path
}

func IsLocalIPv6() (bool, error) {
conn, err := net.Dial("tcp", "[::1]:80")
if err != nil {
if strings.Contains(strings.ToLower(err.Error()), "no connection") {
return false, nil
}

return false, err
}
defer conn.Close()

return true, nil
// addrs, err := net.InterfaceAddrs()
// if err != nil {
// return false, err
// }

// for _, addr := range addrs {
// fmt.Println(addr.String())
// if strings.Contains(addr.String(), ":") {
// return true, nil
// }
// }

// return false, nil
}

// Returns whether the address can be pinged and whether it is using IPv6 or not
func Ping(url string) bool {
req, err := http.NewRequest("HEAD", url, nil)
if err != nil {
Expand Down

0 comments on commit 3c736ab

Please sign in to comment.