Après la commande de mise à niveau, j'ai implémenté ma propre commande de mise à niveau en utilisant le langage Go.
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", "")) }
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: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: 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 }
下面的代码中,我们基于 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() }
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() }, }
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 核心代码翻译自 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!