Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapted CLI Command #1

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/go.rtnl.ai/ulid)
[![Apache 2 licensed](https://img.shields.io/badge/license-Apache2-blue.svg)](https://raw.githubusercontent.com/oklog/ulid/master/LICENSE)

This go module is a derivative work of [github.com/oklog/ulid](https://github.com/oklog/ulid), created under the terms of the [Apache 2](LICENSE). We created this port of the original package because we found ourselves wrapping the package with helper functionality that didn't seem useful to anyone but us. This package is intended for a Rotational audience; if you need ULIDs we do recommend that you use the original package.
This go module is a derivative work of [github.com/oklog/ulid](https://github.com/oklog/ulid), created under the terms of the [Apache 2](LICENSE) license. We created this port of the original package because we found ourselves wrapping the package with helper functionality that didn't seem useful to anyone but us. This package is intended for a Rotational audience; if you need ULIDs we do recommend that you use the original package.

## Install

Expand Down
158 changes: 117 additions & 41 deletions cmd/ulid/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,104 @@ import (
"fmt"
mathrand "math/rand"
"os"
"path/filepath"
"strings"
"time"

"go.rtnl.ai/ulid"
)

const usageText = `Rotational ULID debugging utility
Usage: generate or inspect a ULID

Generate:

ulid [options]

-n INT, --num INT number of ULIDs to generate
-q, --quick use quick entropy (not cryptographic)
-m, --mono use monotonic entropy (for more than one ULID)
-z, --zero use zero entropy

Inspect:

ulid [options] ULID [ULID ...]

-f, --format string time format (default, rfc3339, unix, ms)
-l, --local use local time instead of UTC
-p, --path assumes argument is a path with a ULID filename (strips directory and extension)

Options:

-h, --help display this help and exit
`

const (
defaultms = "Mon Jan 02 15:04:05.999 MST 2006"
rfc3339ms = "2006-01-02T15:04:05.000Z07:00"
)

var (
num int
quick bool
mono bool
zero bool
format string
local bool
path bool
help bool
)

func main() {
var (
format = flag.String("format", "default", "when parsing, show times in this format: default, rfc3339, unix, ms")
local = flag.Bool("local", false, "when parsing, show local time instead of UTC")
quick = flag.Bool("quick", false, "when generating, use non-crypto-grade entropy")
zero = flag.Bool("zero", false, "when generating, fix entropy to all-zeroes")
help = flag.Bool("help", false, "print this help text")
)
// Set command line flags
// Generate Options
flag.IntVar(&num, "num", 1, "")
flag.IntVar(&num, "n", 1, "")
flag.BoolVar(&quick, "quick", false, "")
flag.BoolVar(&quick, "q", false, "")
flag.BoolVar(&mono, "mono", false, "")
flag.BoolVar(&mono, "m", false, "")
flag.BoolVar(&zero, "zero", false, "")
flag.BoolVar(&zero, "z", false, "")

// Inspect Options
flag.StringVar(&format, "format", "default", "")
flag.StringVar(&format, "f", "default", "")
flag.BoolVar(&local, "local", false, "")
flag.BoolVar(&local, "l", false, "")
flag.BoolVar(&path, "path", false, "")
flag.BoolVar(&path, "p", false, "")

// General Options
flag.BoolVar(&help, "help", false, "")
flag.BoolVar(&help, "h", false, "")

// Parse command line flags
flag.Parse()
if *help {
flag.Usage()
if help {
usage()
os.Exit(0)
}

var formatFunc func(time.Time) string
switch strings.ToLower(*format) {
case "default":
formatFunc = func(t time.Time) string { return t.Format(defaultms) }
case "rfc3339":
formatFunc = func(t time.Time) string { return t.Format(rfc3339ms) }
case "unix":
formatFunc = func(t time.Time) string { return fmt.Sprint(t.Unix()) }
case "ms":
formatFunc = func(t time.Time) string { return fmt.Sprint(t.UnixNano() / 1e6) }
default:
fmt.Fprintf(os.Stderr, "invalid --format %s\n", *format)
os.Exit(1)
}

switch flag.NArg() {
case 0:
generate(*quick, *zero)
generate()
default:
parse(flag.Arg(0), *local, formatFunc)
parse()
}
}

func generate(quick, zero bool) {
func usage() {
fmt.Fprint(os.Stderr, usageText)
}

func generate() {
if num < 1 {
fmt.Fprintf(os.Stderr, "invalid --num %d\n", num)
os.Exit(1)
}

// Create entropy from options
entropy := cryptorand.Reader
if quick {
seed := time.Now().UnixNano()
Expand All @@ -65,28 +113,56 @@ func generate(quick, zero bool) {
if zero {
entropy = zeroReader{}
}

id, err := ulid.New(ulid.Timestamp(time.Now()), entropy)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
if mono {
entropy = ulid.Monotonic(entropy, 0)
}

fmt.Fprintf(os.Stdout, "%s\n", id)
// Generate ULIDs
for i := 0; i < num; i++ {
id, err := ulid.New(ulid.Timestamp(time.Now()), entropy)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}

fmt.Fprintf(os.Stdout, "%s\n", id)
}
}

func parse(s string, local bool, f func(time.Time) string) {
id, err := ulid.Parse(s)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
func parse() {
var formatFunc func(time.Time) string
switch strings.ToLower(format) {
case "default":
formatFunc = func(t time.Time) string { return t.Format(defaultms) }
case "rfc3339":
formatFunc = func(t time.Time) string { return t.Format(rfc3339ms) }
case "unix":
formatFunc = func(t time.Time) string { return fmt.Sprint(t.Unix()) }
case "ms":
formatFunc = func(t time.Time) string { return fmt.Sprint(t.UnixNano() / 1e6) }
default:
fmt.Fprintf(os.Stderr, "invalid --format %s\n", format)
os.Exit(1)
}

t := ulid.Time(id.Time())
if !local {
t = t.UTC()
for _, s := range flag.Args() {
if path {
s = filepath.Base(s)
s = strings.TrimSuffix(s, filepath.Ext(s))
}

id, err := ulid.Parse(s)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}

t := ulid.Time(id.Time())
if !local {
t = t.UTC()
}
fmt.Fprintf(os.Stderr, "%s\n", formatFunc(t))
}
fmt.Fprintf(os.Stderr, "%s\n", f(t))
}

type zeroReader struct{}
Expand Down
Loading