Maison >développement back-end >Golang >Implémenter la mise à niveau Deno basée sur Go

Implémenter la mise à niveau Deno basée sur Go

Go语言进阶学习
Go语言进阶学习avant
2023-07-24 15:12:44828parcourir

Après la commande de mise à niveau, j'ai implémenté ma propre commande de mise à niveau en utilisant le langage Go.

Obtenez la dernière version

Jetons d'abord un coup d'œil au code source de Deno :

use deno_runtime::deno_fetch::reqwest::Client;
const RELEASE_URL: &str = "https://github.com/denoland/deno/releases";
...
async fn get_latest_release_version(
  client: &Client,
) -> Result<String, AnyError> {
  println!("Looking up latest version");

  let res = client
    .get(&format!("{}/latest", RELEASE_URL))
    .send()
    .await?;
  let version = res.url().path_segments().unwrap().last().unwrap();

  Ok(version.replace("v", ""))
}
  • Analysez le code ci-dessus pour effectuer les choses suivantes : Puisqu'il s'agit d'une fonction asynchrone, utilisez la fonction println pour demander cela vous recherchez une nouvelle version et utilisez la demande de méthode GET https://github.com/denoland/deno/releases/latest
  • https://github.com/denoland/deno/releases/latest sera redirigé vers le dernière version https://github.com/denoland/deno/releases/tag/v1.7.1, via une opération de chaîne, nous avons supprimé le Obtenir le numéro de version</section ><code style=" padding: mono consolas monaco menlo monospace break-all rgb bolder none initial>replace 方法替换 v"" 得到版本号

  • 让我们用 Go 来实现它:

    代码看起来差不多,比如模板字符串写法、字符串处理

    package release
    
    import (
     "net/http"
     "strings"
    )
    
    func getLatestVersion() string{
     releaseURL := fmt.Sprintf("https://github.com/%s/%s/releases/latest", user, repo)
     resp, _ := http.Get(releaseURL)
     defer resp.Body.Close() // 为了防止内存泄漏
    
     pathArr := strings.Split(resp.Request.URL.Path, "/")
     latest := strings.Replace(pathArr[len(pathArr)-1], "v", "", 1)
     return latest
    }

    版本检测

    版本的处理少不了SemVer。我们使用 go-version 来处理版本相关工作,有了版本比较我们便可以实现一个版本检查的功能。以下代码是 我封装的 go-release 中的一段代码:

    type UpdateInfo struct {
     IsUpdate      bool
     LatestVersion string
    }
    
    func CheckUpdate(user string, repo string, current string) (updateInfo *UpdateInfo, err error) {
     releaseURL := fmt.Sprintf("https://github.com/%s/%s/releases/latest", user, repo)
     resp, err := http.Get(releaseURL)
     if err != nil {
      return nil, err
     }
     defer resp.Body.Close()
    
     current = strings.Replace(current, "v", "", 1)
     pathArr := strings.Split(resp.Request.URL.Path, "/")
     latest := strings.Replace(pathArr[len(pathArr)-1], "v", "", 1)
    
     currentVersion, err := version.NewVersion(current)
     if err != nil {
      return nil, err
     }
     latestVersion, err := version.NewVersion(latest)
     if err != nil {
      return nil, err
     }
     updateInfo = &UpdateInfo{
      IsUpdate:      currentVersion.LessThan(latestVersion),
      LatestVersion: latest,
     }
     return updateInfo, nil
    }

    cobra 实现 upgrade

    下面的代码中,我们基于 go-release 实现了一个带 upgrade

    Implémentons-le avec Go :

    Les codes se ressemblent, comme l'écriture de chaîne de modèle et le traitement de chaîne🎜
    const Version = "0.0.1"
    
    func checkUpgrade(current string) {
      fmt.Println("Looking up latest version")
     update, err := release.CheckUpdate("youngjuning", "tpc", current)
     if err != nil {
      panic(err)
     }
     if update.IsUpdate {
      fmt.Printf("Found latest version %v \n", update.LatestVersion)
      sh.Command("bash", "-c", "curl -fsSL https://raw.githubusercontent.com/youngjuning/tpc/main/install.sh | sh").Run()
     } else {
      fmt.Printf("Local version %v is the most recent release \n", current)
     }
    }
    
    var rootCmd = &cobra.Command{
     Use:     "app",
     Version: Version,
    }
    
    var cmdUpgrade = &cobra.Command{
     Use: "upgrade",
     Run: func(cmd *cobra.Command, args []string) {
      checkUpgrade(Version, force)
     },
    }
    
    func main() {
     rootCmd.AddCommand(cmdUpgrade)
     rootCmd.Execute()
    }
    🎜🎜🎜🎜détection de version🎜🎜

    Version le traitement de SemVer est indispensable. Nous utilisons go-version pour gérer le travail lié à la version. Avec la comparaison des versions, nous pouvons implémenter une fonction de vérification de version. Le code suivant est un morceau de code dans ma version packagée : 🎜

    // rootCmd 代表没有调用子命令时的基础命令
    var rootCmd = &cobra.Command{
     Use:     "tpc",
     Version: Version,
     Run: func(cmd *cobra.Command, args []string) {
      sh.Command("tpc", "-h").Run()
      },
      // 每次执行完命令后去执行检查更新,Start 表示不阻塞原来的任务,还有一个 Run 方法则是会阻塞
     PersistentPostRun: func(cmd *cobra.Command, args []string) {
      sh.Command("bash", "-c", "tpc upgrade --force=false").Start()
     },
    }
    🎜🎜🎜🎜cobra implémente la mise à niveau🎜🎜

    Dans le code suivant, nous implémentons un upgrade simple CLI, la logique de base est de comparer si la version locale est la dernière, et sinon, d'installer la dernière. 🎜

    const Version = "0.0.1"
    
    func checkUpgrade(current string) {
      fmt.Println("Looking up latest version")
     update, err := release.CheckUpdate("youngjuning", "tpc", current)
     if err != nil {
      panic(err)
     }
     if update.IsUpdate {
      fmt.Printf("Found latest version %v \n", update.LatestVersion)
      sh.Command("bash", "-c", "curl -fsSL https://raw.githubusercontent.com/youngjuning/tpc/main/install.sh | sh").Run()
     } else {
      fmt.Printf("Local version %v is the most recent release \n", current)
     }
    }
    
    var rootCmd = &cobra.Command{
     Use:     "app",
     Version: Version,
    }
    
    var cmdUpgrade = &cobra.Command{
     Use: "upgrade",
     Run: func(cmd *cobra.Command, args []string) {
      checkUpgrade(Version, force)
     },
    }
    
    func main() {
     rootCmd.AddCommand(cmdUpgrade)
     rootCmd.Execute()
    }

    强制更新方案

    Node.js 命令行工具检查更新的正确姿势 对这个问题做了很深入的研究并实现了 Node 版的工具。核心逻辑就是每次执行命令时异步去执行检查更新。这句话翻译成 Go 就是用协程去执行检查更新的动作,这样执行命令还是会立马得到反馈,程序则会在后台执行检查更新,当检测到有新版本则强制更新。

    完整代码在go-release/example,对 Cobra 不熟悉的同学可以看一下 Cobra 中文文档。

    执行 shell 命令推荐 go-sh,它对 exec 包做了封装,提供了更好地使用体验( PS:还不是因为我菜)

    // rootCmd 代表没有调用子命令时的基础命令
    var rootCmd = &cobra.Command{
     Use:     "tpc",
     Version: Version,
     Run: func(cmd *cobra.Command, args []string) {
      sh.Command("tpc", "-h").Run()
      },
      // 每次执行完命令后去执行检查更新,Start 表示不阻塞原来的任务,还有一个 Run 方法则是会阻塞
     PersistentPostRun: func(cmd *cobra.Command, args []string) {
      sh.Command("bash", "-c", "tpc upgrade --force=false").Start()
     },
    }

    go-release 的诞生

    go-release 核心代码翻译自 Deno 的 upgrade,开源项目,点赞是我维护的动力,在此求个 Star。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer