让我们开始:使用Golang的命令行程序

总览

Go语言是一种令人兴奋的新语言,它有很好的理由而获得了广泛的欢迎。 在本教程中,您将学习如何使用Go编写命令行程序。 该示例程序称为multi-git,它使您可以同时在多个存储库上执行git命令。

快速入门

Go是一种由C语言和Unix最初的黑客在Google创建的类似于C语言的开源语言,他们是由对C ++的厌恶所激发的。 它显示在Go的设计中,该设计做出了一些非常规的选择,例如避免实现继承,模板和异常。 Go简单,可靠且高效。 它最独特的功能是通过所谓的goroutine和通道显式支持并发编程。

在开始剖析示例程序之前,请遵循官方指南为Go开发做好准备。

Multi-Git程序

multi-git程序是一个简单但有用的Go程序。 如果您的团队的代码库分散在多个git存储库中,则通常需要在多个存储库中执行更改。 这是一个问题,因为git没有多个存储库的概念。 一切都围绕一个单一的存储库。

如果使用分支,这将变得特别麻烦。 如果您使用的功能涉及三个存储库,则必须在每个存储库中创建一个功能分支,然后记住同时签出,拉出,推送和合并所有存储库。 这不是小事。 Multi-git管理一组存储库,并允许您一次对整个存储库进行操作。 请注意,当前版本的multi-git要求您单独创建分支,但是我可能会在以后添加此功能。

通过探索实现multi-git的方式,您将学到很多有关在Go中编写命令行程序的知识。

包装和进口

Go程序以程序包形式组织。 multi-git程序包含一个名为main.go的文件。 在文件的顶部,指定包名称“ main”,然后是导入列表。 导入是multi-git使用的其他软件包。

package main



import (

    "flag"

    "fmt"

    "log"

    "os"

    "strings"

    "os/exec"

)

例如, fmt包用于格式化的I / O,类似于C的printf和scanf。 Go支持通过go get命令从各种来源安装软件包。 安装软件包时,它们最终会位于$ GOPATH环境变量下的命名空间中。 您可以通过git,subversion,mercurial和bazaar等几种常见的版本控制格式,从GitHub,Bitbucket,Google代码,Launchpad甚至IBM DevOps服务等各种来源安装软件包。

命令行参数

命令行参数是向程序提供输入的最常见形式之一。 它们易于使用,可让您在一行中运行和配置程序,并具有多种语言的强大解析支持。 Go将其称为命令行“标志”,并具有用于指定和解析命令行参数(或标志)的标志包。

通常,您在程序开始时解析命令行参数,并且multi-git遵循此约定。 入口点是main()函数。 前两行定义了两个标记,分别称为“命令”和“ ignoreErrors”。 每个标志都有一个名称,数据类型,默认值和帮助字符串。 flag.Parse()调用将解析传递给程序的实际命令行,并填充定义的标志。

func main() {

    command := flag.String("command", "", "The git command")

    ignoreErrors := flag.Bool(

        "ignore-errors",

        false,

        "Keep running after error if true")

    flag.Parse()

也可以通过flag.Args()函数访问未定义的参数。 因此,标志代表预定义的参数,而“ args”是未处理的参数。 未处理的参数是从0开始的索引。

环境变量

程序配置的另一种常见形式是环境变量。 使用环境变量时,可能会在同一环境中多次运行同一程序,并且所有运行都将使用同一环境变量。

Multi-git使用两个环境变量:“ MG_ROOT”和“ MG_REPOS”。 Multi-git旨在管理一组具有公共父目录的git存储库。 那是“ MG_ROOT”。 存储库名称在“ MG_REPOS”中指定为逗号分隔的字符串。 要读取环境变量的值,可以使用os.Getenv()函数。

// Get managed repos from environment variables

    root := os.Getenv("MG_ROOT")

    if root[len(root) - 1] != '/' {

        root += "/"

    }



    repo_names := strings.Split(os.Getenv("MG_REPOS"), ",")

验证存储库列表

现在,它找到了根目录和所有存储库的名称,multi-git验证每个存储库都位于root下,并且它确实是一个git存储库。 检查就像在每个存储库目录中查找.git子目录一样简单。

首先,定义一个名为“ repos”的字符串数组。 然后,迭代所有回购名称,并通过串联根目录和回购名称来构建存储库路径。 如果对.git子目录的[os.Stat()]()调用失败,它将记录错误并退出。 否则,存储库路径将附加到repos数组。

var repos []string

    // Verify all repos exist and are actually git repos (have .git sub-dir)

    for _, r := range repo_names {

        path := root + r

        _, err := os.Stat(path + "/.git")

        if err != nil {

            log.Fatal(err)

        }

        repos = append(repos, path)

    }

Go具有独特的错误处理工具,其中函数通常同时返回返回值和错误对象。 查看os.Stat()如何返回两个值。 在这种情况下,“ _”占位符用于保存实际结果,因为您只关心错误。 Go非常严格,需要使用命名变量。 如果您不打算使用值,则应将其分配给“ _”,以避免编译错误。

执行Shell命令

至此,您已经有了我们要执行git命令的存储库路径列表。 您还记得,我们将git命令行作为单个命令行参数(标志)(称为“ command”)接收到。 需要将其拆分为组件数组(git命令,子命令和选项)。 整个命令也以字符串形式存储,以用于显示。

// Break the git command into components (needed to execute)

    var git_components []string

    for _, component := range strings.Split(*command, " ") {

        git_components = append(git_components, component)

    }

    command_string := "git " + *command

现在,您已经准备好遍历每个存储库并在每个存储库中执行git命令。 再次使用“ for ... range”循环构造。 首先,multi-git将其工作目录更改为当前目标存储库“ r”,并输出git命令。 然后,它使用exec.Command()函数执行命令并打印组合的输出(标准输出和标准错误)。

最后,它检查执行期间是否有错误。 如果出现错误并且ignoreErrors标志为false,则multi-git会退出。 可以选择忽略错误的原因是,如果命令在某些存储库上失败,则有时可以。 例如,如果要在具有该分支的所有存储库上签出一个名为“ cool feature”的分支,则不必在没有该分支的存储库上签出失败。

for _, r := range repos {

        // Go to the repo's directory

        os.Chdir(r);



        // Print the command

        fmt.Printf("[%s] %s\n", r, command_string)



        // Execute the command

        out, err := exec.Command("git", git_components...).CombinedOutput()



        // Print the result

        fmt.Println(string(out))



        // Bail out if there was an error and NOT ignoring errors

        if err != nil && !*ignoreErrors {

            os.Exit(1)

        }

    }



    fmt.Println("Done.")

结论

Go是一种简单而强大的语言。 它是为大型系统编程而设计的,但对于小型命令行程序也同样适用。 Go的最小化设计与其他现代语言(例如Scale和Rust)形成了鲜明的对比,Scale和Rust也非常强大且设计合理,但是学习曲线非常陡峭。 我鼓励您尝试去尝试。 其乐无穷。

翻译自: https://code.tutsplus.com/tutorials/lets-go-command-line-programs-with-golang--cms-26341

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值