当前位置:网站首页>Learn to create command line tools with go in an hour

Learn to create command line tools with go in an hour

2020-12-08 08:27:03 crossoverJie

Preface

Recently because of the project need to write a period of time Go , be relative to Java The grammar is simple, but there are some Python Such grammatical sugar , Let people shout ” It's delicious “.

But at this stage, it is still relatively Python Write more , Sometimes I have to write something back Java ; Nature is right Go I don't know much about it .

So it's convenient to use weekend time to do a small project to deepen some use experience . So I thought about using Java Write a blog Gadget .

At that time, a large number of pictures were banned from outside the microblog map bed , As a result, many pictures in personal blogs cannot be viewed . This tool can back up the images in the article to local , It can also replace pictures directly with other picture beds .

I personally have been using , It is usually used when coding words iPic Tools like this upload images to the microblog map bed ( Mainly convenience + free ). After writing, you can switch to [SM.MS](http://sm.MS) This kind of paid picture bed , At the same time, the pictures will be backed up to the local disk .

Instead of using Go Rewrite as cli After using the tool, the effect is as follows :

3-min.gif

What skills need to be mastered

I chose this tool to use Go To rewrite ; One is that the function is relatively simple , But it's also possible to use Go Some characteristics of , Such as network IO、 Coprocess synchronization and so on .

At the same time, after changing to command line tool, does it feel more geek .

I'm not familiar with it before I start again Go Of Javaer What knowledge points will be used in the next Introduction :

  • Use and manage third-party dependency packages (go mod)
  • The use of synergetics .
  • Multi platform packaging .

The following is the specific operation , I think even if I haven't been exposed to Go After watching, you can also quickly implement a small tool .

Using and managing third party dependencies

  • Not installed yet Go Please refer to the official website for self installation .

Let's first introduce Go Dependency management for , In version 1.11 After that, the government brought its own dependency management module , So in the current version 1.15 It has been strongly recommended in .

Its purpose and function are similar to Java Medium maven,Python Medium pip similar , But compared with maven Simple and many .

According to its use reference , It needs to be executed in the project directory first go mod init Used to initialize a go.mod file , Of course, if you use GoLang In this way IDE, When creating a new project, it will automatically help us create a directory structure , And of course go.mod This file .

In this document we introduce the third party packages we need :

module btb

go 1.15

require (
    github.com/cheggaaa/pb/v3 v3.0.5
    github.com/fatih/color v1.10.0
    github.com/urfave/cli/v2 v2.3.0
)

I use three bags here , Namely :

  • pb: progress bar, Used to output progress bar in the console .
  • color: Used to output different colors of text on the console .
  • cli: Command line tools development kit .

import (
    "btb/constants"
    "btb/service"
    "github.com/urfave/cli/v2"
    "log"
    "os"
)

func main() {
    var model string
    downloadPath := constants.DownloadPath
    markdownPath := constants.MarkdownPath

    app := &cli.App{
        Flags: []cli.Flag{
            &cli.StringFlag{
                Name:        "model",
                Usage:       "operating mode; r:replace, b:backup",
                DefaultText: "b",
                Aliases:     []string{"m"},
                Required:    true,
                Destination: &model,
            },
            &cli.StringFlag{
                Name:        "download-path",
                Usage:       "The path where the image is stored",
                Aliases:     []string{"dp"},
                Destination: &downloadPath,
                Required:    true,
                Value:       constants.DownloadPath,
            },
            &cli.StringFlag{
                Name:        "markdown-path",
                Usage:       "The path where the markdown file is stored",
                Aliases:     []string{"mp"},
                Destination: &markdownPath,
                Required:    true,
                Value:       constants.MarkdownPath,
            },
        },
        Action: func(c *cli.Context) error {
            service.DownLoadPic(markdownPath, downloadPath)

            return nil
        },
        Name:  "btb",
        Usage: "Help you backup and replace your blog's images",
    }

    err := app.Run(os.Args)
    if err != nil {
        log.Fatal(err)
    }
}

The code is very simple , It's just the use of cli Provided by the api Created several commands , Enter the -dp-mp Parameter mapping to downloadPathmarkdownPath variable .

And then you can use these two data to scan all the pictures , And download the pictures to the corresponding directory .

More user guides can be referred to directly Official documents .

You can see part of the grammar and Java Completely different , such as :

  • When you declare a variable, the type is put after it , First define the variable name ; Method parameters are similar to .
  • Type derivation , You can not specify the variable type ( The new version of the Java Also support )
  • Method supports the return of multiple values at the same time , This is very useful .
  • public 、 Private functions use uppercase and lowercase to distinguish .
  • There are others that I won't list one by one .

coroutines

Then the command execution calls service.DownLoadPic(markdownPath, downloadPath) Process business logic .

Here's a file scan 、 Image download and other code will not be analyzed ; official SDK It's very clear , It's easier .

Focus on Go Inside goroutime That is to say, the cooperative process .

The scenario I use here is to use a coprocessor to parse and download images every time I scan a file , So as to improve the overall operation efficiency .

func DownLoadPic(markdownPath, downloadPath string) {
    wg := sync.WaitGroup{}
    allFile, err := util.GetAllFile(markdownPath)
    wg.Add(len(*allFile))

    if err != nil {
        log.Fatal("read file error")
    }

    for _, filePath := range *allFile {

        go func(filePath string) {
            allLine, err := util.ReadFileLine(filePath)
            if err != nil {
                log.Fatal(err)
            }
            availableImgs := util.MatchAvailableImg(allLine)
            bar := pb.ProgressBarTemplate(constants.PbTmpl).Start(len(*availableImgs))
            bar.Set("fileName", filePath).
                SetWidth(120)

            for _, url := range *availableImgs {
                if err != nil {
                    log.Fatal(err)
                }
                err := util.DownloadFile(url, *genFullFileName(downloadPath, filePath, &url))
                if err != nil {
                    log.Fatal(err)
                }
                bar.Increment()

            }
            bar.Finish()
            wg.Done()

        }(filePath)
    }
    wg.Wait()
    color.Green("Successful handling of [%v] files.\n", len(*allFile))

    if err != nil {
        log.Fatal(err)
    }
}

In terms of code usage, it seems that it is better than Java It's a lot simpler , We don't have to be like Java That requires maintaining a executorService, There is no need to consider the size of the thread pool , Everything to Go Dispatch yourself .

When using, you only need to add go keyword , It's just that this is an anonymous function .

And because of goroutime Very light weight , And Java Medium thread Compared with taking up very little memory , So we don't need to precisely control the number of creations .


But there's also a and here Java Something very similar :WaitGroup.

Its usage and function are similar to Java Medium CountDownLatch Very similar ; It's mainly used to wait for all the goroutime completion of enforcement , Here is naturally waiting for all the pictures to download and then exit the program .

There are three steps to use :

  • Create and initialize goruntime The number of :wg.Add(len(number)
  • Whenever a goruntime After execution, call wg.Done() Subtract the count by one .
  • The final call wg.Wait() wait for WaitGroup The quantity of is reduced to 0.

For the coprocessor Go Recommended chanel To communicate with each other , This will be discussed in the future .

pack

So much for the core logic , Let's talk about packaging and running ; This and Java The difference is bigger .

as everyone knows ,Java There is a famous saying :write once run anywhere

It's because of JVM virtual machine , So no matter which platform the code will eventually run on, we just need to type out a package ; but Go How can it run on different platforms without a virtual machine .

Simply speaking Go You can package different binaries for different platforms , This file contains all the dependencies needed to run , It doesn't even need to be installed on the target platform Go Environmental Science .

  • although Java In the end, you just need to pack one bag , But you have to install compatible Java Running environment .

I wrote one here Makefile Used to perform packaging :make release

# Binary name
BINARY=btb
GOBUILD=go build -ldflags "-s -w" -o ${BINARY}
GOCLEAN=go clean
RMTARGZ=rm -rf *.gz
VERSION=0.0.1

release:
    # Clean
    $(GOCLEAN)
    $(RMTARGZ)
    # Build for mac
    CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(GOBUILD)
    tar czvf ${BINARY}-mac64-${VERSION}.tar.gz ./${BINARY}
    # Build for arm
    $(GOCLEAN)
    CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GOBUILD)
    tar czvf ${BINARY}-arm64-${VERSION}.tar.gz ./${BINARY}
    # Build for linux
    $(GOCLEAN)
    CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD)
    tar czvf ${BINARY}-linux64-${VERSION}.tar.gz ./${BINARY}
    # Build for win
    $(GOCLEAN)
    CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GOBUILD).exe
    tar czvf ${BINARY}-win64-${VERSION}.tar.gz ./${BINARY}.exe
    $(GOCLEAN)

As you can see, we just need to be in go build You can print packages from different platforms by specifying system variables , For example, we do it for Linux Systematic arm64 Architecture package file :

CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build main.go -o btb

It can be executed directly on the target platform ./btb Run the program .

summary

All the code in this article has been uploaded Github: https://github.com/crossoverJie/btb

If you are interested, you can run the installation script directly .

curl -fsSL https://raw.githubusercontent.com/crossoverJie/btb/master/install.sh | bash
  • At present, this version only implements image download and backup , In the future, we will improve the replacement of map bed and other functions .

During this period of time Go After that, I felt deeply , For age 25 Year old Java Come on ,Go It's really daunting for the future , What's more infuriating is that we have caught up with the wave of cloud primordial , It's even more infuriating .

Some small problems that didn't seem so important in the past have also been highlighted , For example, it starts slowly 、 It takes up a lot of memory 、 Grammar, etc ; However, I still look forward to the grandmaster who enjoys food , From the new version of Java It can be seen that there are also positive changes , Not to mention the huge ecology that no one shakes .

more Java Follow up content can refer to teacher Zhou Zhiming's article : The age of cloud Nativity ,Java In danger ?

版权声明
本文为[crossoverJie]所创,转载请带上原文链接,感谢
https://chowdera.com/2020/12/202012080826386743.html