Skip to content

Commit

Permalink
feat(cli): basic CLI application coding
Browse files Browse the repository at this point in the history
  • Loading branch information
yeqown committed Nov 18, 2021
1 parent f460202 commit 11b86c9
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 34 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 YeQiang
Copyright (c) 2018 yeqown

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
63 changes: 63 additions & 0 deletions cmd/qrcode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
## `qrcode` CLI Application

The `qrcode` is a command line application that generates QR codes.

### Usage

```sh
$ qrcode -h
NAME:
qrcode - qrcode [options] [source text]

USAGE:
qrcode [global options] command [command options] [arguments...]

VERSION:
v2.0.0-beta

DESCRIPTION:
QR code generator

AUTHOR:
yeqown <[email protected]>

COMMANDS:
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--terminal --terminal (default: false)
--output value, -o value --output=<output file> (default: qrcode.jpg)
--block value, -s value --block=<block size> (default: 5)
--borders value, -b value --borders=<borders> (default: 0,0,0,0)
--circle --circle (default: false)
--help, -h show help (default: false)
--version, -v print the version (default: false)

COPYRIGHT:
Copyright (c) 2018 yeqown

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
```

### Examples

Provides some examples of how to use the `qrcode` command.

```sh
# Generate a QR code into file as default
qrcode "Hello, World!"

# Generate a QR code into file with block size and borders (unit: pixel)
qrcode -o qrcode.png -s 20 -b 20,20,20,20 -m "Hello, World!"

# Generate a QR code into terminal
qrcode --terminal "Hello, World!"
```
193 changes: 193 additions & 0 deletions cmd/qrcode/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package main

import (
"path/filepath"
"strconv"
"strings"

"github.com/yeqown/go-qrcode/v2"
"github.com/yeqown/go-qrcode/writer/standard"
"github.com/yeqown/go-qrcode/writer/terminal"

"github.com/pkg/errors"
"github.com/urfave/cli/v2"
)

var copyright = `Copyright (c) 2018 yeqown
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
`

func newApp() *cli.App {
app := cli.NewApp()
app.Name = "qrcode"
app.Description = "QR code generator"
app.Version = "v2.0.0-beta"
app.Authors = []*cli.Author{
{
Name: "yeqown",
Email: "[email protected]",
},
}
app.Usage = "qrcode [options] [source text]"
app.Copyright = copyright
app.Flags = prepareFlags()
app.Action = func(c *cli.Context) error {
genCtx := parseGenerateContextFrom(c)
return generate(genCtx)
}

return app
}

func generate(ctx *generateContext) error {
qrc, err := qrcode.New(ctx.text)
if err != nil {
return errors.Wrap(err, "generate QRCode failed")
}

var w qrcode.Writer

// construct a writer based generateContext
switch ctx.mode {
case writerMode_TERMINAL:
w = terminal.New()
default:
w, err = standard.New(ctx.FOO.output, ctx.FOO.applyOptions()...)
}
if err != nil {
return errors.Wrap(err, "initialize writer failed")
}

return qrc.Save(w)
}

type writerMode uint8

const (
_ writerMode = iota
writerMode_FILE
writerMode_TERMINAL
)

// generateContext generate qrcode from context
type generateContext struct {
text string
mode writerMode
FOO *fileOutputOptions
TOO *terminalOutputOptions
}

type fileOutputOptions struct {
output string
outputSuffix string
blockSize uint8
borders [4]int
isCircleShape bool
}

func (foo fileOutputOptions) applyOptions() []standard.ImageOption {
options := []standard.ImageOption{
standard.WithQRWidth(foo.blockSize),
standard.WithBorderWidth(foo.borders[:]...),
}

switch foo.outputSuffix {
case "png":
options = append(options, standard.WithBuiltinImageEncoder(standard.PNG_FORMAT))
case "jpg", "jpeg":
fallthrough
default:
options = append(options, standard.WithBuiltinImageEncoder(standard.JPEG_FORMAT))
}

if foo.isCircleShape {
options = append(options, standard.WithCircleShape())
}

return options
}

type terminalOutputOptions struct{}

func parseGenerateContextFrom(c *cli.Context) *generateContext {
genCtx := &generateContext{
text: c.Args().First(),
mode: writerMode_FILE,
FOO: &fileOutputOptions{
output: c.String("output"),
outputSuffix: strings.TrimPrefix(filepath.Ext(c.String("output")), "."),
blockSize: uint8(c.Uint("block")),
borders: [4]int{},
isCircleShape: c.Bool("circle"),
},
TOO: &terminalOutputOptions{},
}

// writer mode
if c.Bool("terminal") {
genCtx.mode = writerMode_TERMINAL
}

// parse borders
borders := c.String("borders")
arr := strings.Split(borders, ",")
if len(arr) != 4 {
panic("invalid borders format, want: uint8,uint8,uint8,uint8")
}
for i, s := range arr {
v, err := strconv.ParseUint(s, 10, 8)
if err != nil {
panic("invalid borders format, want: uint8")
}
genCtx.FOO.borders[i] = int(v)
}

return genCtx
}

func prepareFlags() []cli.Flag {
return []cli.Flag{
&cli.BoolFlag{
Name: "terminal",
Usage: "--terminal",
Value: false,
DefaultText: "false",
},
&cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "--output=<output file>",
Value: "qrcode.jpg",
DefaultText: "qrcode.jpg",
},
&cli.UintFlag{
Name: "block",
Aliases: []string{"s"},
Usage: "--block=<block size>",
Value: 5,
DefaultText: "5",
},
&cli.StringFlag{
Name: "borders",
Aliases: []string{"b"},
Usage: "--borders=<borders>",
Value: "0,0,0,0",
DefaultText: "0,0,0,0",
},
&cli.BoolFlag{
Name: "circle",
Usage: "--circle",
Value: false,
DefaultText: "false",
},
}
}
28 changes: 21 additions & 7 deletions cmd/qrcode/go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
module qrcode
module github.com/yeqown/go-qrcode/cmd/qrcode

go 1.17

require (
github.com/pkg/errors v0.9.1
github.com/urfave/cli/v2 v2.3.0
github.com/yeqown/go-qrcode/v2 v2.0.0-beta
github.com/yeqown/go-qrcode/writer/standard v1.0.0-beta
github.com/yeqown/go-qrcode/writer/terminal v1.0.0-beta
)

require (
github.com/yeqown/go-qrcode/writer/standard v1.0.0
github.com/yeqown/go-qrcode/v2 v2.0.0
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/fogleman/gg v1.3.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/nsf/termbox-go v1.1.1 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
)

replace (
github.com/yeqown/go-qrcode/v2 v2.0.0 => ../../
github.com/yeqown/go-qrcode/writer/standard v1.0.0 => ../../writer/standard
)
//replace (
// github.com/yeqown/go-qrcode/v2 v2.0.0 => ../../
// github.com/yeqown/go-qrcode/writer/standard v1.0.0 => ../../writer/standard
//)
30 changes: 4 additions & 26 deletions cmd/qrcode/main.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,13 @@
package main

import (
"flag"
"fmt"

"github.com/yeqown/go-qrcode/v2"
"github.com/yeqown/go-qrcode/writer/standard"
)

var (
contentFlag = flag.String("c", "https://github.com/yeqown/go-qrcode", "input your content to encode")
outputFlag = flag.String("o", "./qrcode.jpeg", "output filename")
"os"
)

func main() {
flag.Parse()

qrc, err := qrcode.New(*contentFlag)
if err != nil {
fmt.Printf("could not generate QRCode: %v", err)
return
}

w, err := standard.New(*outputFlag)
if err != nil {
fmt.Printf("standard writer failed: %v", err)
return
}
app := newApp()

// save file
if err := qrc.Save(w); err != nil {
fmt.Printf("could not save image: %v", err)
if err := app.Run(os.Args); err != nil {
println(err.Error())
}
}

0 comments on commit 11b86c9

Please sign in to comment.