使用脚本安装和升级Golang

使用脚本安装和升级Golang 我不明白为什么Go语言没有像Flutter和Rust那样内置升级工具, 我编写了下面的PowerShell脚本 goinstaller.ps1 文件来帮助我在Win10上安装和升级Go语言,无论是全新安装还是升级:

我想在这里分享,如果你发现其中有什么问题,非常感谢你的反馈。

Write-Output " Welcome to GO lang portable installation script"
Write-Output " Written by: Hasan A Yousef, Aug 2020"
Write-Output " =============================================="
Write-Output " GO lang SDK will be installed at C:\go\bin"
Write-Output " GO lang (GOPATH) will be set as 'Documents\GoWorkPlace'"
Write-Output ""

#Here is the installation function, at the bottom of the file are the check for update process
function InstallGo {
    param (
        $latest_version,
        $workDir
    )
        # The download location of the latest version zip file
        $file = 'go' + $latest_version + '.windows-amd64.zip'

        # set defaults
        $path = 'C:\go'
        $url = 'https://golang.org/dl/' + $file
        $dest = [io.path]::combine($Home, 'Downloads', $file)

        If(test-path $path)
        {
            $pathAll = $path + "*"
            Write-Output " Removing the currently installed Go from $path"
            Remove-Item $pathAll -recurse
        } else {
           # New-Item -ItemType Directory -Force -Path $path
           Write-Output " Creating the directory required for GO installation: $path"
           mkdir $path
        }
        # Download the zip file at the defined destination
        Write-Output " Downloading $url"
        #Invoke-WebRequest $url -OutFile $dest
        Write-Output " $url downloaded as $dest"

        # Unzip the file
        Write-Output " Extracting $file to $path"
        Expand-Archive -Force -Path $dest -DestinationPath $path\..
        Write-Output " Extraction completed, Adding GO SDK to path"
        # Add GO to the Path (if not exisiting)
        $addPath = 'C:\go\bin'
        # Iterate through all the existing paths to check if the new path is already included with or without a '\' on the end:
        $env = [Environment]::GetEnvironmentVariable("PATH",1)
        $regexAddPath = [regex]::Escape($addPath)
        $arrPath = $env -split ';' | Where-Object {$_ -notMatch "^$regexAddPath\\?"}
        $env = ($arrPath + $addPath) -join ';'
        [Environment]::SetEnvironmentVariable("PATH", $env, "USER")
        Write-Output " $addPath had been added to path."

        Write-Output " GO SDK is ready in the path, setting up Environment Variables"
        #Setting up variables
        # set the $GOROOT (Aka $GOBIN), GOROOT is a variable that defines where your Go SDK is located
        $goroot = Join-Path $path "bin"
        [Environment]::SetEnvironmentVariable( "GOROOT", $goroot, [System.EnvironmentVariableTarget]::User)
        # set the $GOPATH; GOPATH is a variable that defines the root of your workspace
        $gopath = Join-Path $Home $workDir
        [Environment]::SetEnvironmentVariable( "GOPATH", $gopath, [System.EnvironmentVariableTarget]::User)
        # Setup the Go workspace; if it doesn't exist.
        If (!(Test-Path $workDir)) {
            New-Item -path $workDir -type directory
            Write-Output " Go work space had been created: $gopath"
        } else {
            Write-Output " Go work space already exist: $gopath"
        }
        Write-Output " =============================================="
        Write-Output " GO is ready, Below you'll see list of GO command"
        go
  }

############################################################################
# Here is the check process, based on which the above function may be called.

$workDir = 'Documents\GoWorkPlace'
# Get latest Go lang version
# Parse the remote repository with ls-remote, and get release branches
# The regex matches refs/heads/release-branch.go, so rc and beta won't be mached
$release_branches=$(git ls-remote --heads https://github.com/golang/go/ | 
ConvertFrom-String | Where-Object {$_."P2" -Match 'refs/heads/release-branch.go'})

# Define utility for nat sort (see http://stackoverflow.com/a/5429048/2796058)
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }

# Extract actual tag versions, sort and get latest
$latest_version=$($release_branches.P2 | Select-String -Pattern '(\d+\.\d+)').Matches.Groups.Value |
 Sort-Object $ToNatural | Select-Object -Last 1

 Write-Output " Latest GO lang version is: $latest_version"

# Check installed version of GO lang 
$cmdName = 'go'
Try{
    Get-Command $cmdName -ErrorAction stop
    $goversioncheck = go version
    $goversion = [regex]::Match($goversioncheck, '((\d+\.\d+))').captures.groups[1].value

    if ($goversion -eq $latest_version) {
        Write-Output " You already have latest GO lang version installed, version: $goversion"
    } else {
        Write-Host " Upgrade Install of GO lang will start now"
        InstallGo -latest_version $latest_version -workDir $workDir
    }
  } Catch{
    Write-Host " Fresh Install of GO lang will start now"
    InstallGo -latest_version $latest_version -workDir $workDir
  }

以上使用的是便携式/zip文件,因为它不需要管理员权限。如果你更喜欢使用 msi 文件,那么你需要将文件名从 .windows-amd64.zip 替换为 .windows-amd64.msi,并将文件解压命令 Expand-Archive -Force -Path $dest -DestinationPath $path\.. 替换为文件执行命令 Start-Process $dest


更多关于使用脚本安装和升级Golang的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于使用脚本安装和升级Golang的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个很好的PowerShell脚本,用于在Windows上管理Go语言的安装和升级。不过,我注意到几个可以改进的地方:

主要问题:

  1. 下载逻辑缺失:脚本中注释掉了实际的下载代码
  2. 版本检测可能不准确:从release分支名提取版本号可能不是最佳方式
  3. 路径处理需要调整:解压路径可能需要修正

改进后的脚本示例:

Write-Output "Welcome to GO lang portable installation script"
Write-Output "Written by: Hasan A Yousef, Aug 2020"
Write-Output "Modified with improvements"
Write-Output "=============================================="
Write-Output "GO lang SDK will be installed at C:\go\bin"
Write-Output "GO lang (GOPATH) will be set as 'Documents\GoWorkPlace'"
Write-Output ""

function InstallGo {
    param (
        $latest_version,
        $workDir
    )
    
    $file = "go$latest_version.windows-amd64.zip"
    $path = 'C:\go'
    $url = "https://golang.org/dl/$file"
    $dest = Join-Path $Home "Downloads\$file"
    
    # 清理旧版本
    if (Test-Path $path) {
        Write-Output "Removing the currently installed Go from $path"
        Remove-Item "$path\*" -Recurse -Force
    } else {
        Write-Output "Creating the directory required for GO installation: $path"
        New-Item -ItemType Directory -Force -Path $path | Out-Null
    }
    
    # 下载Go
    Write-Output "Downloading $url"
    try {
        Invoke-WebRequest -Uri $url -OutFile $dest
        Write-Output "Download completed: $dest"
    } catch {
        Write-Error "Failed to download Go: $_"
        return
    }
    
    # 解压文件
    Write-Output "Extracting $file to $path"
    try {
        # 确保目标目录存在
        if (!(Test-Path $path)) {
            New-Item -ItemType Directory -Force -Path $path | Out-Null
        }
        
        # 使用正确的解压方法
        Add-Type -AssemblyName System.IO.Compression.FileSystem
        [System.IO.Compression.ZipFile]::ExtractToDirectory($dest, $path)
        Write-Output "Extraction completed"
    } catch {
        Write-Error "Failed to extract Go: $_"
        return
    }
    
    # 添加到PATH
    $addPath = 'C:\go\bin'
    $currentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
    
    if ($currentPath -notlike "*$addPath*") {
        $newPath = "$currentPath;$addPath"
        [Environment]::SetEnvironmentVariable("PATH", $newPath, "User")
        Write-Output "$addPath has been added to PATH"
    } else {
        Write-Output "$addPath is already in PATH"
    }
    
    # 设置环境变量
    [Environment]::SetEnvironmentVariable("GOROOT", "C:\go", "User")
    
    $gopath = Join-Path $Home $workDir
    [Environment]::SetEnvironmentVariable("GOPATH", $gopath, "User")
    
    # 创建工作空间
    if (!(Test-Path $gopath)) {
        New-Item -ItemType Directory -Force -Path $gopath | Out-Null
        Write-Output "Go workspace created: $gopath"
    } else {
        Write-Output "Go workspace already exists: $gopath"
    }
    
    Write-Output "=============================================="
    Write-Output "Go installation completed"
    
    # 刷新当前会话的PATH
    $env:Path = [Environment]::GetEnvironmentVariable("PATH", "User") + ";" + [Environment]::GetEnvironmentVariable("PATH", "Machine")
    
    # 验证安装
    try {
        go version
    } catch {
        Write-Warning "Go command not found in current session. Please restart your terminal."
    }
}

# 获取最新版本 - 改进的方法
function Get-LatestGoVersion {
    try {
        # 从官方页面获取最新版本
        $response = Invoke-WebRequest -Uri "https://golang.org/dl/" -UseBasicParsing
        $content = $response.Content
        
        # 查找Windows amd64 zip文件的版本
        $pattern = 'go(\d+\.\d+(?:\.\d+)?)\.windows-amd64\.zip'
        $matches = [regex]::Matches($content, $pattern)
        
        if ($matches.Count -gt 0) {
            $versions = $matches | ForEach-Object { $_.Groups[1].Value }
            # 按版本号排序并获取最新
            $latest = $versions | Sort-Object { [version]$_ } | Select-Object -Last 1
            return $latest
        }
    } catch {
        Write-Warning "Failed to fetch latest version: $_"
    }
    
    return $null
}

# 主执行逻辑
$workDir = 'Documents\GoWorkPlace'
$latest_version = Get-LatestGoVersion

if (-not $latest_version) {
    Write-Error "Could not determine latest Go version"
    exit 1
}

Write-Output "Latest GO lang version is: $latest_version"

# 检查已安装版本
try {
    $goVersionOutput = go version 2>&1
    if ($LASTEXITCODE -eq 0) {
        $match = [regex]::Match($goVersionOutput, 'go(\d+\.\d+(?:\.\d+)?)')
        if ($match.Success) {
            $current_version = $match.Groups[1].Value
            
            if ($current_version -eq $latest_version) {
                Write-Output "You already have the latest Go version installed: $current_version"
                exit 0
            } else {
                Write-Output "Current version: $current_version, Latest version: $latest_version"
                Write-Output "Upgrading Go..."
                InstallGo -latest_version $latest_version -workDir $workDir
            }
        }
    }
} catch {
    Write-Output "Go is not installed. Performing fresh installation..."
    InstallGo -latest_version $latest_version -workDir $workDir
}

主要改进:

  1. 修复了下载功能:取消了注释,添加了错误处理
  2. 改进了版本检测:直接从Go官网解析最新版本
  3. 修正了解压逻辑:使用.NET的ZipFile类确保正确解压
  4. 添加了错误处理:对关键操作添加了try-catch
  5. 改进了PATH更新:更可靠地检测和更新PATH变量
  6. 添加了安装验证:安装后验证Go命令是否可用

这个脚本现在应该能更可靠地工作。注意:由于Go官网可能需要代理访问,如果在中国大陆使用,可能需要将golang.org/dl/替换为golang.google.cn/dl/

回到顶部