Compare commits

...

27 Commits

Author SHA1 Message Date
74ce7bc58a Cleaning up the codebase. 2023-05-04 23:22:35 -07:00
8b2d10209e Clean up the README. 2023-05-04 22:58:21 -07:00
770100b688 fileutil: start working on symlink checking 2023-05-04 22:52:16 -07:00
29630c55a9 packaging is a dead end thus far
I think I'm going to have to write my own rules to do this.
2023-05-04 21:03:08 -07:00
3c2ec896f8 cmd/cruntar: avoid writing files outside archive 2023-05-04 17:20:22 -07:00
7828726ba4 Updating x/sys. 2023-05-04 17:13:06 -07:00
458f3ceaed update dependencies to fix dependabot warnings. 2023-05-04 17:10:41 -07:00
2c45ae7b4e syslog: add new logging package. 2023-05-04 16:20:39 -07:00
c1b8b72cf1 bazel-test: add sizes to all tests.
This gets rid of the warning about mismatched test sizes.
2023-05-04 16:08:18 -07:00
bfc7fedbf9 seekbuf: add test file 2023-05-04 16:08:11 -07:00
965312f48e update README/LICENSE
LICENSE: update years.

README: add missing pieces.
2023-05-04 16:07:34 -07:00
237aa46ddd cmd/diskimg: new disk imaging tool 2023-05-04 16:06:56 -07:00
f8c64d3be5 bazel: updating build files 2023-05-04 15:11:15 -07:00
d66cfe1145 Cut over to Bazel. 2023-05-04 14:00:30 -07:00
ad03c5f991 Mass rewrite imports -> git.wntrmute.dev repo. 2023-05-04 13:58:43 -07:00
Kyle Isom
0dd4e1c6ca Update README.md
Depart for other waters.
2023-05-04 13:46:40 -07:00
078230217d ahash: add SumLimitedReader 2023-05-04 13:41:33 -07:00
90318f861b Add EEPROM image generator. 2022-06-24 14:36:51 -07:00
3bb1362c0e tee: allow writing strings. 2022-02-20 17:43:11 -08:00
30ffbbdbc5 config: add test data for iniconf. 2022-02-20 17:43:11 -08:00
b893e99864 config: add default path, customized configs.
A customised config is an ini file with a [default] section and some
other name sections; a config file is loaded from the default section
with any keys in the named section being added in, overriding keys in
the host. This allows for, e.g. setting different paths based on the
host name or operating system.
2022-02-20 17:43:11 -08:00
c7c51568d8 seekbuf lost the Clear function. 2022-02-05 15:40:13 -08:00
7793021260 New package: seekbuf (a seekable buffer). 2022-02-05 15:00:39 -08:00
692562818c clean README 2020-11-26 20:32:46 -08:00
9e19346fc0 add sum file 2020-11-26 20:09:46 -08:00
cb827169dc switching hosting providers 2020-11-26 20:09:37 -08:00
027d0173bc logging: finish multi implementation 2020-11-11 21:15:02 -08:00
108 changed files with 2741 additions and 155 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
bazel-bin
bazel-goutils
bazel-out
bazel-testlogs

22
BUILD.bazel Normal file
View File

@@ -0,0 +1,22 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix git.wntrmute.dev/kyle/goutils
gazelle(name = "gazelle")
go_library(
name = "goutils",
srcs = ["doc.go"],
importpath = "git.wntrmute.dev/kyle/goutils",
visibility = ["//visibility:public"],
)
gazelle(
name = "gazelle-update-repos",
args = [
"-from_file=go.mod",
"-to_macro=deps.bzl%go_dependencies",
"-prune",
],
command = "update-repos",
)

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015 Kyle Isom <kyle@tyrfingr.is>
Copyright (c) 2015-2023 Kyle Isom <kyle@tyrfingr.is>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above

View File

@@ -2,13 +2,11 @@ GOUTILS
This is a collection of small utility code I've written in Go; the `cmd/`
directory has a number of command-line utilities. Rather than keep all
of these in superfluous repositories of their own, I'm putting them here.
Note that for packaging purposes, the goutils-pkg repo should be used: it
pins the library versions to working copies and vendors all depdencies. See
https://github.com/kisom/goutils-pkg for more details.
of these in superfluous repositories of their own, or rewriting them
for each project, I'm putting them here.
The goutils-pkg repo [1] has stable versions of the command line
utilities here, along with a vendored snapshot of any dependencies.
The project can be built with the standard Go tooling, or it can be built
with Bazel.
Contents:
@@ -29,33 +27,46 @@ Contents:
cruntar/ Untar an archive with hard links, copying instead of
linking.
csrpubdump/ Dump the public key from an X.509 certificate request.
diskimg/ Write a disk image to a device.
eig/ EEPROM image generator.
fragment/ Print a fragment of a file.
jlp/ JSON linter/prettifier.
kgz/ Custom gzip compressor / decompressor that handles 99%
of my use cases.
parts/ Simple parts database management for my collection of
electronic components.
pem2bin/ Dump the binary body of a PEM-encoded block.
pembody/ Print the body of a PEM certificate.
pemit/ Dump data to a PEM file.
showimp/ List the external (e.g. non-stdlib and outside the
current working directory) imports for a Go file.
readchain/ Print the common name for the certificates
in a bundle.
renfnv/ Rename a file to base32-encoded 64-bit FNV-1a hash.
rhash/ Compute the digest of remote files.
showimp Display the external imports in a package.
showimp/ List the external (e.g. non-stdlib and outside the
current working directory) imports for a Go file.
ski Display the SKI for PEM-encoded TLS material.
sprox/ Simple TCP proxy.
stealchain/ Dump the verified chain from a TLS
connection.
connection to a server.
stealchain- Dump the verified chain from a TLS
server/ connection from a client.
subjhash/ Print or match subject info from a certificate.
tlskeypair/ Check whether a TLS certificate and key file match.
utc/ Convert times to UTC.
yamll/ A small YAML linter.
config/ A simple global configuration system where configuration
data is pulled from a file or an environment variable
transparently.
dbg/ A debug printer.
die/ Death of a program.
fileutil/ Common file functions.
lib/ Commonly-useful functions for writing Go programs.
logging/ A logging library.
mwc/ MultiwriteCloser implementation.
rand/ Utilities for working with math/rand.
sbuf/ A byte buffer that can be wiped.
seekbuf/ A read-seekable byte buffer.
syslog/ Syslog-type logging.
tee/ Emulate tee(1)'s functionality in io.Writers.
testio/ Various I/O utilities useful during testing.
testutil/ Various utility functions useful during testing.
@@ -64,6 +75,4 @@ Contents:
Each program should have a small README in the directory with more
information.
All code here is licensed under the MIT license.
[1] https://github.com/kisom/goutils-pkg/
All code here is licensed under the ISC license.

32
WORKSPACE Normal file
View File

@@ -0,0 +1,32 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
### Go tooling, including Gazelle to generate and maintain BUILD files.
http_archive(
name = "io_bazel_rules_go",
sha256 = "6b65cb7917b4d1709f9410ffe00ecf3e160edf674b78c54a894471320862184f",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.39.0/rules_go-v0.39.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.39.0/rules_go-v0.39.0.zip",
],
)
http_archive(
name = "bazel_gazelle",
sha256 = "ecba0f04f96b4960a5b250c8e8eeec42281035970aa8852dda73098274d14a1d",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
load("//:deps.bzl", "go_dependencies")
# gazelle:repository_macro deps.bzl%go_dependencies
go_dependencies()
go_rules_dependencies()
go_register_toolchains(version = "1.20.4")
gazelle_dependencies()

24
ahash/BUILD.bazel Normal file
View File

@@ -0,0 +1,24 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "ahash",
srcs = ["ahash.go"],
importpath = "git.wntrmute.dev/kyle/goutils/ahash",
visibility = ["//visibility:public"],
deps = [
"//assert",
"@org_golang_x_crypto//blake2b",
"@org_golang_x_crypto//blake2s",
"@org_golang_x_crypto//md4",
"@org_golang_x_crypto//ripemd160",
"@org_golang_x_crypto//sha3",
],
)
go_test(
name = "ahash_test",
size = "small",
srcs = ["ahash_test.go"],
embed = [":ahash"],
deps = ["//assert"],
)

View File

@@ -1,5 +1,6 @@
// Package ahash provides support for hashing data with a selectable
// hash function.
//
// hash function.
package ahash
import (
@@ -16,7 +17,7 @@ import (
"io"
"sort"
"github.com/kisom/goutils/assert"
"git.wntrmute.dev/kyle/goutils/assert"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/blake2s"
"golang.org/x/crypto/md4"
@@ -44,13 +45,6 @@ func sha512Slicer(bs []byte) []byte {
return sum[:]
}
var sliceFunctions = map[string]func([]byte) []byte{
"sha224": sha224Slicer,
"sha256": sha256Slicer,
"sha384": sha384Slicer,
"sha512": sha512Slicer,
}
// Hash represents a generic hash function that may or may not be secure. It
// satisfies the hash.Hash interface.
type Hash struct {
@@ -213,6 +207,17 @@ func SumReader(algo string, r io.Reader) ([]byte, error) {
return h.Sum(nil), nil
}
// SumLimitedReader reads n bytes of data from the io.reader and returns the
// digest (not the hex digest) from the specified algorithm.
func SumLimitedReader(algo string, r io.Reader, n int64) ([]byte, error) {
limit := &io.LimitedReader{
R: r,
N: n,
}
return SumReader(algo, limit)
}
var insecureHashList, secureHashList, hashList []string
func init() {

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"testing"
"github.com/kisom/goutils/assert"
"git.wntrmute.dev/kyle/goutils/assert"
)
func TestSecureHash(t *testing.T) {
@@ -139,3 +139,19 @@ func TestListLengthSanity(t *testing.T) {
assert.BoolT(t, len(all) == len(secure)+len(insecure))
}
func TestSumLimitedReader(t *testing.T) {
data := bytes.NewBufferString("hello, world")
dataLen := data.Len()
extendedData := bytes.NewBufferString("hello, world! this is an extended message")
expected := "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b"
hash, err := SumReader("sha256", data)
assert.NoErrorT(t, err)
assert.BoolT(t, fmt.Sprintf("%x", hash) == expected, fmt.Sprintf("have hash %x, want %s", hash, expected))
extendedHash, err := SumLimitedReader("sha256", extendedData, int64(dataLen))
assert.NoErrorT(t, err)
assert.BoolT(t, bytes.Equal(hash, extendedHash), fmt.Sprintf("have hash %x, want %x", extendedHash, hash))
}

8
assert/BUILD.bazel Normal file
View File

@@ -0,0 +1,8 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "assert",
srcs = ["assert.go"],
importpath = "git.wntrmute.dev/kyle/goutils/assert",
visibility = ["//visibility:public"],
)

View File

@@ -94,7 +94,7 @@ func NoError(err error, s ...string) {
}
if nil != err {
die(err.Error())
die(err.Error(), s...)
}
}
@@ -170,5 +170,5 @@ func ErrorEqT(t *testing.T, expected, actual error) {
should = fmt.Sprintf("have '%s'", actual)
}
die(fmt.Sprintf("assert.Error2: expected '%s', but %s", expected, should))
t.Fatalf("assert.Error2: expected '%s', but %s", expected, should)
}

14
cmd/atping/BUILD.bazel Normal file
View File

@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "atping_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/atping",
visibility = ["//visibility:private"],
)
go_binary(
name = "atping",
embed = [":atping_lib"],
visibility = ["//visibility:public"],
)

15
cmd/certchain/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "certchain_lib",
srcs = ["certchain.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/certchain",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "certchain",
embed = [":certchain_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -7,7 +7,7 @@ import (
"fmt"
"regexp"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
var hasPort = regexp.MustCompile(`:\d+$`)

22
cmd/certdump/BUILD.bazel Normal file
View File

@@ -0,0 +1,22 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "certdump_lib",
srcs = [
"certdump.go",
"util.go",
],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/certdump",
visibility = ["//visibility:private"],
deps = [
"@com_github_cloudflare_cfssl//errors",
"@com_github_cloudflare_cfssl//helpers",
"@com_github_kr_text//:text",
],
)
go_binary(
name = "certdump",
embed = [":certdump_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "certexpiry_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/certexpiry",
visibility = ["//visibility:private"],
deps = [
"//die",
"//lib",
"@com_github_cloudflare_cfssl//helpers",
],
)
go_binary(
name = "certexpiry",
embed = [":certexpiry_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -10,9 +10,9 @@ import (
"strings"
"time"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib"
"github.com/cloudflare/cfssl/helpers"
"github.com/kisom/goutils/die"
"github.com/kisom/goutils/lib"
)
var warnOnly bool

View File

@@ -0,0 +1,20 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "certverify_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/certverify",
visibility = ["//visibility:private"],
deps = [
"//die",
"//lib",
"@com_github_cloudflare_cfssl//helpers",
"@com_github_cloudflare_cfssl//revoke",
],
)
go_binary(
name = "certverify",
embed = [":certverify_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -8,10 +8,10 @@ import (
"os"
"time"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/revoke"
"github.com/kisom/goutils/die"
"github.com/kisom/goutils/lib"
)
func printRevocation(cert *x509.Certificate) {

20
cmd/clustersh/BUILD.bazel Normal file
View File

@@ -0,0 +1,20 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "clustersh_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/clustersh",
visibility = ["//visibility:private"],
deps = [
"//lib",
"@com_github_pkg_sftp//:sftp",
"@org_golang_x_crypto//ssh",
"@org_golang_x_crypto//ssh/agent",
],
)
go_binary(
name = "clustersh",
embed = [":clustersh_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -11,7 +11,7 @@ import (
"strings"
"sync"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/lib"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"

15
cmd/cruntar/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "cruntar_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/cruntar",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "cruntar",
embed = [":cruntar_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -11,7 +11,8 @@ import (
"os"
"path/filepath"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/fileutil"
)
var (
@@ -56,7 +57,7 @@ func processFile(tfr *tar.Reader, hdr *tar.Header, top string) error {
}
filePath := filepath.Clean(filepath.Join(top, hdr.Name))
switch hdr.Typeflag {
case tar.TypeReg, tar.TypeRegA:
case tar.TypeReg:
file, err := os.Create(filePath)
if err != nil {
return err
@@ -92,6 +93,17 @@ func processFile(tfr *tar.Reader, hdr *tar.Header, top string) error {
return err
}
case tar.TypeSymlink:
if !fileutil.ValidateSymlink(hdr.Linkname, top) {
return fmt.Errorf("symlink %s is outside the top-level %s",
hdr.Linkname, top)
}
path := linkTarget(hdr.Linkname, top)
if ok, err := filepath.Match(top+"/*", filepath.Clean(path)); !ok {
return fmt.Errorf("symlink %s isn't in %s", hdr.Linkname, top)
} else if err != nil {
return err
}
err := os.Symlink(linkTarget(hdr.Linkname, top), filePath)
if err != nil {
return err

View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "csrpubdump_lib",
srcs = ["pubdump.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/csrpubdump",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "csrpubdump",
embed = [":csrpubdump_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -10,7 +10,7 @@ import (
"io/ioutil"
"log"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
func main() {

19
cmd/diskimg/BUILD.bazel Normal file
View File

@@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "diskimg_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/diskimg",
visibility = ["//visibility:private"],
deps = [
"//ahash",
"//dbg",
"//die",
],
)
go_binary(
name = "diskimg",
embed = [":diskimg_lib"],
visibility = ["//visibility:public"],
)

34
cmd/diskimg/README Normal file
View File

@@ -0,0 +1,34 @@
diskimg: write disk images
Usage:
diskimg [-a algo] [-v] image device
Flags:
-a algo Select the hashing algorithm to use. The default
is 'sha256'. Specifying an algorithm of 'list'
will print the supported algorithms to standard
output and exit with error code 2.
-v Enable verbose (debug) output.
Examples:
Copying images/server.img to /dev/sda:
$ sudo diskimg images/server.img /dev/sda
Write a bladerunner node image to /dev/sda:
$ sudo diskimg -v ~/code/bladerunner/packer/build/cm4-cnode-ubuntu-22.04.2.img /dev/sda
opening image /home/kyle/code/bladerunner/packer/build/cm4-cnode-ubuntu-22.04.2.img for read
/home/kyle/code/bladerunner/packer/build/cm4-cnode-ubuntu-22.04.2.img 416d4c8f890904167419e3d488d097e9c847273376b650546fdb1f6f9809c184
opening device /dev/sda for rw
writing /home/kyle/code/bladerunner/packer/build/cm4-cnode-ubuntu-22.04.2.img -> /dev/sda
wrote 4151312384 bytes to /dev/sda
syncing /dev/sda
verifying the image was written successfully
OK
Motivation:
I wanted to write something like balena's Etcher, but commandline only.

116
cmd/diskimg/main.go Normal file
View File

@@ -0,0 +1,116 @@
package main
import (
"bytes"
"flag"
"fmt"
"io"
"os"
"git.wntrmute.dev/kyle/goutils/ahash"
"git.wntrmute.dev/kyle/goutils/dbg"
"git.wntrmute.dev/kyle/goutils/die"
)
const defaultHashAlgorithm = "sha256"
var (
hAlgo string
debug = dbg.New()
)
func openImage(imageFile string) (image *os.File, hash []byte, err error) {
image, err = os.Open(imageFile)
if err != nil {
return
}
hash, err = ahash.SumReader(hAlgo, image)
if err != nil {
return
}
_, err = image.Seek(0, 0)
if err != nil {
return
}
debug.Printf("%s %x\n", imageFile, hash)
return
}
func openDevice(devicePath string) (device *os.File, err error) {
fi, err := os.Stat(devicePath)
if err != nil {
return
}
device, err = os.OpenFile(devicePath, os.O_RDWR|os.O_SYNC, fi.Mode())
if err != nil {
return
}
return
}
func main() {
flag.StringVar(&hAlgo, "a", defaultHashAlgorithm, "default hash algorithm")
flag.BoolVar(&debug.Enabled, "v", false, "enable debug logging")
flag.Parse()
if hAlgo == "list" {
fmt.Println("Supported hashing algorithms:")
for _, algo := range ahash.SecureHashList() {
fmt.Printf("\t- %s\n", algo)
}
os.Exit(2)
}
if flag.NArg() != 2 {
die.With("usage: diskimg image device")
}
imageFile := flag.Arg(0)
devicePath := flag.Arg(1)
debug.Printf("opening image %s for read\n", imageFile)
image, hash, err := openImage(imageFile)
if image != nil {
defer image.Close()
}
die.If(err)
debug.Printf("opening device %s for rw\n", devicePath)
device, err := openDevice(devicePath)
if device != nil {
defer device.Close()
}
die.If(err)
debug.Printf("writing %s -> %s\n", imageFile, devicePath)
n, err := io.Copy(device, image)
die.If(err)
debug.Printf("wrote %d bytes to %s\n", n, devicePath)
debug.Printf("syncing %s\n", devicePath)
err = device.Sync()
die.If(err)
debug.Println("verifying the image was written successfully")
_, err = device.Seek(0, 0)
die.If(err)
deviceHash, err := ahash.SumLimitedReader(hAlgo, device, n)
die.If(err)
if !bytes.Equal(deviceHash, hash) {
fmt.Fprintln(os.Stderr, "Hash mismatch:")
fmt.Fprintf(os.Stderr, "\t%s: %s\n", imageFile, hash)
fmt.Fprintf(os.Stderr, "\t%s: %s\n", devicePath, deviceHash)
os.Exit(1)
}
debug.Println("OK")
os.Exit(0)
}

15
cmd/eig/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "eig_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/eig",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "eig",
embed = [":eig_lib"],
visibility = ["//visibility:public"],
)

52
cmd/eig/main.go Normal file
View File

@@ -0,0 +1,52 @@
package main
import (
"flag"
"os"
"git.wntrmute.dev/kyle/goutils/die"
)
// size of a kilobit in bytes
const kilobit = 128
const pageSize = 4096
func main() {
size := flag.Int("s", 256*kilobit, "size of EEPROM image in kilobits")
fill := flag.Uint("f", 0, "byte to fill image with")
flag.Parse()
if *fill > 256 {
die.With("`fill` argument must be a byte value")
}
path := "eeprom.img"
if flag.NArg() > 0 {
path = flag.Arg(0)
}
fillByte := uint8(*fill)
buf := make([]byte, pageSize)
for i := 0; i < pageSize; i++ {
buf[i] = fillByte
}
pages := *size / pageSize
last := *size % pageSize
file, err := os.Create(path)
die.If(err)
defer file.Close()
for i := 0; i < pages; i++ {
_, err = file.Write(buf)
die.If(err)
}
if last != 0 {
_, err = file.Write(buf[:last])
die.If(err)
}
}

15
cmd/fragment/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "fragment_lib",
srcs = ["fragment.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/fragment",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "fragment",
embed = [":fragment_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -9,7 +9,7 @@ import (
"path/filepath"
"strconv"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
func init() {

15
cmd/jlp/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "jlp_lib",
srcs = ["jlp.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/jlp",
visibility = ["//visibility:private"],
deps = ["//lib"],
)
go_binary(
name = "jlp",
embed = [":jlp_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -8,7 +8,7 @@ import (
"io/ioutil"
"os"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/lib"
)
func prettify(file string, validateOnly bool) error {

15
cmd/kgz/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "kgz_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/kgz",
visibility = ["//visibility:private"],
deps = ["@com_github_pkg_errors//:errors"],
)
go_binary(
name = "kgz",
embed = [":kgz_lib"],
visibility = ["//visibility:public"],
)

15
cmd/parts/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "parts_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/parts",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "parts",
embed = [":parts_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -11,7 +11,7 @@ import (
"sort"
"strings"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
const dbVersion = "1"

14
cmd/pem2bin/BUILD.bazel Normal file
View File

@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "pem2bin_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/pem2bin",
visibility = ["//visibility:private"],
)
go_binary(
name = "pem2bin",
embed = [":pem2bin_lib"],
visibility = ["//visibility:public"],
)

15
cmd/pembody/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "pembody_lib",
srcs = ["pembody.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/pembody",
visibility = ["//visibility:private"],
deps = ["//lib"],
)
go_binary(
name = "pembody",
embed = [":pembody_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -7,7 +7,7 @@ import (
"io/ioutil"
"os"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/lib"
)
func main() {

19
cmd/pemit/BUILD.bazel Normal file
View File

@@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "pemit_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/pemit",
visibility = ["//visibility:private"],
deps = [
"//assert",
"//die",
"//lib",
],
)
go_binary(
name = "pemit",
embed = [":pemit_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -8,9 +8,9 @@ import (
"io"
"os"
"github.com/kisom/goutils/assert"
"github.com/kisom/goutils/die"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/assert"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib"
)
func usage(w io.Writer) {

14
cmd/readchain/BUILD.bazel Normal file
View File

@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "readchain_lib",
srcs = ["chain.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/readchain",
visibility = ["//visibility:private"],
)
go_binary(
name = "readchain",
embed = [":readchain_lib"],
visibility = ["//visibility:public"],
)

18
cmd/renfnv/BUILD.bazel Normal file
View File

@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "renfnv_lib",
srcs = ["renfnv.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/renfnv",
visibility = ["//visibility:private"],
deps = [
"//fileutil",
"//lib",
],
)
go_binary(
name = "renfnv",
embed = [":renfnv_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -11,8 +11,8 @@ import (
"path/filepath"
"strings"
"github.com/kisom/goutils/fileutil"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/fileutil"
"git.wntrmute.dev/kyle/goutils/lib"
)
func hashName(path, encodedHash string) string {

19
cmd/rhash/BUILD.bazel Normal file
View File

@@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "rhash_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/rhash",
visibility = ["//visibility:private"],
deps = [
"//ahash",
"//die",
"//lib",
],
)
go_binary(
name = "rhash",
embed = [":rhash_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -9,9 +9,9 @@ import (
"os"
"path/filepath"
"github.com/kisom/goutils/ahash"
"github.com/kisom/goutils/die"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/ahash"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib"
)
func usage(w io.Writer) {

18
cmd/showimp/BUILD.bazel Normal file
View File

@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "showimp_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/showimp",
visibility = ["//visibility:private"],
deps = [
"//die",
"//logging",
],
)
go_binary(
name = "showimp",
embed = [":showimp_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -12,36 +12,23 @@ import (
"sort"
"strings"
"github.com/kisom/goutils/die"
"github.com/kisom/goutils/logging"
"git.wntrmute.dev/kyle/goutils/dbg"
"git.wntrmute.dev/kyle/goutils/die"
)
var (
gopath string
project string
debug bool
)
var (
stdLibRegexp = regexp.MustCompile(`^\w+(/\w+)*$`)
sourceRegexp = regexp.MustCompile(`^[^.].*\.go$`)
log = logging.NewConsole()
imports = map[string]bool{}
debug = dbg.New()
fset = &token.FileSet{}
imports = map[string]bool{}
sourceRegexp = regexp.MustCompile(`^[^.].*\.go$`)
stdLibRegexp = regexp.MustCompile(`^\w+(/\w+)*$`)
)
func debugf(format string, args ...interface{}) {
if debug {
fmt.Printf(format, args...)
}
}
func debugln(args ...interface{}) {
if debug {
fmt.Println(args...)
}
}
func init() {
gopath = os.Getenv("GOPATH")
if gopath == "" {
@@ -75,7 +62,7 @@ func walkFile(path string, info os.FileInfo, err error) error {
return nil
}
debugln(path)
debug.Println(path)
f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
if err != nil {
@@ -85,16 +72,16 @@ func walkFile(path string, info os.FileInfo, err error) error {
for _, importSpec := range f.Imports {
importPath := strings.Trim(importSpec.Path.Value, `"`)
if stdLibRegexp.MatchString(importPath) {
debugln("standard lib:", importPath)
debug.Println("standard lib:", importPath)
continue
} else if strings.HasPrefix(importPath, project) {
debugln("internal import:", importPath)
debug.Println("internal import:", importPath)
continue
} else if strings.HasPrefix(importPath, "golang.org/") {
debugln("extended lib:", importPath)
debug.Println("extended lib:", importPath)
continue
}
debugln("import:", importPath)
debug.Println("import:", importPath)
imports[importPath] = true
}
@@ -108,7 +95,7 @@ func main() {
var noVendor bool
flag.StringVar(&ignoreLine, "i", "", "comma-separated list of directories to ignore")
flag.BoolVar(&noVendor, "nv", false, "ignore the vendor directory")
flag.BoolVar(&debug, "v", false, "log debugging information")
flag.BoolVar(&debug.Enabled, "v", false, "log debugging information")
flag.Parse()
if noVendor {

18
cmd/ski/BUILD.bazel Normal file
View File

@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "ski_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/ski",
visibility = ["//visibility:private"],
deps = [
"//die",
"//lib",
],
)
go_binary(
name = "ski",
embed = [":ski_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -17,8 +17,8 @@ import (
"os"
"strings"
"github.com/kisom/goutils/die"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib"
)
func usage(w io.Writer) {

15
cmd/sprox/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "sprox_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/sprox",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "sprox",
embed = [":sprox_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -6,7 +6,7 @@ import (
"log"
"net"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
func proxy(conn net.Conn, inside string) error {

View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "stealchain-server_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/stealchain-server",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "stealchain-server",
embed = [":stealchain-server_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -12,7 +12,7 @@ import (
"net"
"os"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
func main() {

View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "stealchain_lib",
srcs = ["thief.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/stealchain",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "stealchain",
embed = [":stealchain_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -10,7 +10,7 @@ import (
"net"
"os"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
func main() {

18
cmd/subjhash/BUILD.bazel Normal file
View File

@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "subjhash_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/subjhash",
visibility = ["//visibility:private"],
deps = [
"//die",
"//lib",
],
)
go_binary(
name = "subjhash",
embed = [":subjhash_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -9,8 +9,8 @@ import (
"io"
"os"
"github.com/kisom/goutils/die"
"github.com/kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/lib"
)
func init() {

View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "tlskeypair_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/tlskeypair",
visibility = ["//visibility:private"],
deps = ["//die"],
)
go_binary(
name = "tlskeypair",
embed = [":tlskeypair_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -15,7 +15,7 @@ import (
"log"
"os"
"github.com/kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
var validPEMs = map[string]bool{

14
cmd/utc/BUILD.bazel Normal file
View File

@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "utc_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/utc",
visibility = ["//visibility:private"],
)
go_binary(
name = "utc",
embed = [":utc_lib"],
visibility = ["//visibility:public"],
)

15
cmd/yamll/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "yamll_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/goutils/cmd/yamll",
visibility = ["//visibility:private"],
deps = ["@in_gopkg_yaml_v2//:yaml_v2"],
)
go_binary(
name = "yamll",
embed = [":yamll_lib"],
visibility = ["//visibility:public"],
)

23
config/BUILD.bazel Normal file
View File

@@ -0,0 +1,23 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "config",
srcs = [
"config.go",
"path_linux.go",
],
importpath = "git.wntrmute.dev/kyle/goutils/config",
visibility = ["//visibility:public"],
deps = ["//config/iniconf"],
)
go_test(
name = "config_test",
size = "small",
srcs = [
"config_test.go",
"path_test.go",
],
data = glob(["testdata/**"]),
embed = [":config"],
)

View File

@@ -10,9 +10,12 @@ package config
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"git.wntrmute.dev/kyle/goutils/config/iniconf"
)
// NB: Rather than define a singleton type, everything is defined at
@@ -67,6 +70,34 @@ func LoadFile(path string) error {
return nil
}
// LoadFileFor scans the ini file at path, loading the default section
// and overriding any keys found under section. If strict is true, the
// named section must exist (i.e. to catch typos in the section name).
func LoadFileFor(path, section string, strict bool) error {
cmap, err := iniconf.ParseFile(path)
if err != nil {
return err
}
for key, value := range cmap[iniconf.DefaultSection] {
vars[key] = value
}
smap, ok := cmap[section]
if !ok {
if strict {
return fmt.Errorf("config: section '%s' wasn't found in the config file", section)
}
return nil
}
for key, value := range smap {
vars[key] = value
}
return nil
}
// Get retrieves a value from either a configuration file or the
// environment. Note that values from a file will override environment
// variables.

View File

@@ -0,0 +1,16 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "iniconf",
srcs = ["iniconf.go"],
importpath = "git.wntrmute.dev/kyle/goutils/config/iniconf",
visibility = ["//visibility:public"],
)
go_test(
name = "iniconf_test",
size = "small",
srcs = ["iniconf_test.go"],
data = glob(["testdata/**"]),
embed = [":iniconf"],
)

223
config/iniconf/iniconf.go Normal file
View File

@@ -0,0 +1,223 @@
package iniconf
import (
"bufio"
"fmt"
"io"
"os"
"regexp"
)
// ConfigMap is shorthand for the type used as a config struct.
type ConfigMap map[string]map[string]string
var (
configSection = regexp.MustCompile(`^\s*\[\s*(\w+)\s*\]\s*$`)
quotedConfigLine = regexp.MustCompile(`^\s*(\w+)\s*=\s*["'](.*)["']\s*$`)
configLine = regexp.MustCompile(`^\s*(\w+)\s*=\s*(.*)\s*$`)
commentLine = regexp.MustCompile(`^#.*$`)
blankLine = regexp.MustCompile(`^\s*$`)
)
// DefaultSection is the label for the default ini file section.
var DefaultSection = "default"
// ParseFile attempts to load the named config file.
func ParseFile(fileName string) (cfg ConfigMap, err error) {
var file *os.File
file, err = os.Open(fileName)
if err != nil {
return
}
defer file.Close()
return ParseReader(file)
}
// ParseReader reads a configuration from an io.Reader.
func ParseReader(r io.Reader) (cfg ConfigMap, err error) {
cfg = ConfigMap{}
buf := bufio.NewReader(r)
var (
line string
longLine bool
currentSection string
lineBytes []byte
isPrefix bool
)
for {
err = nil
lineBytes, isPrefix, err = buf.ReadLine()
if io.EOF == err {
err = nil
break
} else if err != nil {
break
} else if isPrefix {
line += string(lineBytes)
longLine = true
continue
} else if longLine {
line += string(lineBytes)
longLine = false
} else {
line = string(lineBytes)
}
if commentLine.MatchString(line) {
continue
} else if blankLine.MatchString(line) {
continue
} else if configSection.MatchString(line) {
section := configSection.ReplaceAllString(line,
"$1")
if section == "" {
err = fmt.Errorf("invalid structure in file")
break
} else if !cfg.SectionInConfig(section) {
cfg[section] = make(map[string]string, 0)
}
currentSection = section
} else if configLine.MatchString(line) {
regex := configLine
if quotedConfigLine.MatchString(line) {
regex = quotedConfigLine
}
if currentSection == "" {
currentSection = DefaultSection
if !cfg.SectionInConfig(currentSection) {
cfg[currentSection] = map[string]string{}
}
}
key := regex.ReplaceAllString(line, "$1")
val := regex.ReplaceAllString(line, "$2")
if key == "" {
continue
}
cfg[currentSection][key] = val
} else {
err = fmt.Errorf("invalid config file")
break
}
}
return
}
// SectionInConfig determines whether a section is in the configuration.
func (c ConfigMap) SectionInConfig(section string) bool {
_, ok := c[section]
return ok
}
// ListSections returns the list of sections in the config map.
func (c ConfigMap) ListSections() (sections []string) {
for section := range c {
sections = append(sections, section)
}
return
}
// WriteFile writes out the configuration to a file.
func (c ConfigMap) WriteFile(filename string) (err error) {
file, err := os.Create(filename)
if err != nil {
return
}
defer file.Close()
for _, section := range c.ListSections() {
sName := fmt.Sprintf("[ %s ]\n", section)
_, err = file.Write([]byte(sName))
if err != nil {
return
}
for k, v := range c[section] {
line := fmt.Sprintf("%s = %s\n", k, v)
_, err = file.Write([]byte(line))
if err != nil {
return
}
}
_, err = file.Write([]byte{0x0a})
if err != nil {
return
}
}
return
}
// AddSection creates a new section in the config map.
func (c ConfigMap) AddSection(section string) {
if nil != c[section] {
c[section] = map[string]string{}
}
}
// AddKeyVal adds a key value pair to a config map.
func (c ConfigMap) AddKeyVal(section, key, val string) {
if section == "" {
section = DefaultSection
}
if nil == c[section] {
c.AddSection(section)
}
c[section][key] = val
}
// GetValue retrieves the value from a key map.
func (c ConfigMap) GetValue(section, key string) (val string, present bool) {
if c == nil {
return
}
if section == "" {
section = DefaultSection
}
_, ok := c[section]
if !ok {
return
}
val, present = c[section][key]
return
}
// GetValueDefault retrieves the value from a key map if present,
// otherwise the default value.
func (c ConfigMap) GetValueDefault(section, key, value string) (val string) {
kval, ok := c.GetValue(section, key)
if !ok {
return value
}
return kval
}
// SectionKeys returns the sections in the config map.
func (c ConfigMap) SectionKeys(section string) (keys []string, present bool) {
if c == nil {
return nil, false
}
if section == "" {
section = DefaultSection
}
cm := c
s, ok := cm[section]
if !ok {
return nil, false
}
keys = make([]string, 0, len(s))
for key := range s {
keys = append(keys, key)
}
return keys, true
}

View File

@@ -0,0 +1,142 @@
package iniconf
import (
"errors"
"fmt"
"os"
"sort"
"testing"
)
// FailWithError is a utility for dumping errors and failing the test.
func FailWithError(t *testing.T, err error) {
fmt.Println("failed")
if err != nil {
fmt.Println("[!] ", err.Error())
}
t.FailNow()
}
// UnlinkIfExists removes a file if it exists.
func UnlinkIfExists(file string) {
_, err := os.Stat(file)
if err != nil && os.IsNotExist(err) {
panic("failed to remove " + file)
}
os.Remove(file)
}
// stringSlicesEqual compares two string lists, checking that they
// contain the same elements.
func stringSlicesEqual(slice1, slice2 []string) bool {
if len(slice1) != len(slice2) {
return false
}
for i := range slice1 {
if slice1[i] != slice2[i] {
return false
}
}
for i := range slice2 {
if slice1[i] != slice2[i] {
return false
}
}
return true
}
func TestGoodConfig(t *testing.T) {
testFile := "testdata/test.conf"
fmt.Printf("[+] validating known-good config... ")
cmap, err := ParseFile(testFile)
if err != nil {
FailWithError(t, err)
} else if len(cmap) != 2 {
FailWithError(t, err)
}
fmt.Println("ok")
}
func TestGoodConfig2(t *testing.T) {
testFile := "testdata/test2.conf"
fmt.Printf("[+] validating second known-good config... ")
cmap, err := ParseFile(testFile)
if err != nil {
FailWithError(t, err)
} else if len(cmap) != 1 {
FailWithError(t, err)
} else if len(cmap["default"]) != 3 {
FailWithError(t, err)
}
fmt.Println("ok")
}
func TestBadConfig(t *testing.T) {
testFile := "testdata/bad.conf"
fmt.Printf("[+] ensure invalid config file fails... ")
_, err := ParseFile(testFile)
if err == nil {
err = fmt.Errorf("invalid config file should fail")
FailWithError(t, err)
}
fmt.Println("ok")
}
func TestWriteConfigFile(t *testing.T) {
fmt.Printf("[+] ensure config file is written properly... ")
const testFile = "testdata/test.conf"
const testOut = "testdata/test.out"
cmap, err := ParseFile(testFile)
if err != nil {
FailWithError(t, err)
}
defer UnlinkIfExists(testOut)
err = cmap.WriteFile(testOut)
if err != nil {
FailWithError(t, err)
}
cmap2, err := ParseFile(testOut)
if err != nil {
FailWithError(t, err)
}
sectionList1 := cmap.ListSections()
sectionList2 := cmap2.ListSections()
sort.Strings(sectionList1)
sort.Strings(sectionList2)
if !stringSlicesEqual(sectionList1, sectionList2) {
err = fmt.Errorf("section lists don't match")
FailWithError(t, err)
}
for _, section := range sectionList1 {
for _, k := range cmap[section] {
if cmap[section][k] != cmap2[section][k] {
err = fmt.Errorf("config key doesn't match")
FailWithError(t, err)
}
}
}
fmt.Println("ok")
}
func TestQuotedValue(t *testing.T) {
testFile := "testdata/test.conf"
fmt.Printf("[+] validating quoted value... ")
cmap, _ := ParseFile(testFile)
val := cmap["sectionName"]["key4"]
if val != " space at beginning and end " {
FailWithError(t, errors.New("Wrong value in double quotes ["+val+"]"))
}
val = cmap["sectionName"]["key5"]
if val != " is quoted with single quotes " {
FailWithError(t, errors.New("Wrong value in single quotes ["+val+"]"))
}
fmt.Println("ok")
}

5
config/iniconf/testdata/bad.conf vendored Normal file
View File

@@ -0,0 +1,5 @@
[]
key
another key
key = val

13
config/iniconf/testdata/test.conf vendored Normal file
View File

@@ -0,0 +1,13 @@
[ sectionName ]
key1=some value
key2 = some other value
# we want to explain the importance and great forethought
# in this next value.
key3 = unintuitive value
key4 = " space at beginning and end "
key5 = ' is quoted with single quotes '
[ anotherSection ]
key1 = a value
key2 = yet another value
key1 = overwrites previous value of a value

3
config/iniconf/testdata/test2.conf vendored Normal file
View File

@@ -0,0 +1,3 @@
key1 = some value
key2 = some other value
key3 = unintuitive value

19
config/path.go Normal file
View File

@@ -0,0 +1,19 @@
//go:build ignore
// +build ignore
package config
import (
"os/user"
"path/filepath"
)
// DefaultConfigPath returns a sensible default configuration file path.
func DefaultConfigPath(dir, base string) string {
user, err := user.Current()
if err != nil || user.HomeDir == "" {
return filepath.Join(dir, base)
}
return filepath.Join(user.HomeDir, dir, base)
}

43
config/path_linux.go Normal file
View File

@@ -0,0 +1,43 @@
package config
import (
"os"
"path/filepath"
)
// canUseXDGConfigDir checks whether the XDG config directory exists
// and is accessible by the current user. If it is present, it will
// be returned. Note that if the directory does not exist, it is
// presumed unusable.
func canUseXDGConfigDir() (string, bool) {
xdgDir := os.Getenv("XDG_CONFIG_DIR")
if xdgDir == "" {
userDir := os.Getenv("HOME")
if userDir == "" {
return "", false
}
xdgDir = filepath.Join(userDir, ".config")
}
fi, err := os.Stat(xdgDir)
if err != nil {
return "", false
}
if !fi.IsDir() {
return "", false
}
return xdgDir, true
}
// DefaultConfigPath returns a sensible default configuration file path.
func DefaultConfigPath(dir, base string) string {
dirPath, ok := canUseXDGConfigDir()
if !ok {
dirPath = "/etc"
}
return filepath.Join(dirPath, dir, base)
}

7
config/path_test.go Normal file
View File

@@ -0,0 +1,7 @@
package config
import "testing"
func TestDefaultPath(t *testing.T) {
t.Log(DefaultConfigPath("demoapp", "app.conf"))
}

19
dbg/BUILD.bazel Normal file
View File

@@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "dbg",
srcs = ["dbg.go"],
importpath = "git.wntrmute.dev/kyle/goutils/dbg",
visibility = ["//visibility:public"],
)
go_test(
name = "dbg_test",
size = "small",
srcs = ["dbg_test.go"],
embed = [":dbg"],
deps = [
"//testio",
"@com_github_stretchr_testify//require",
],
)

View File

@@ -55,21 +55,21 @@ func To(w io.WriteCloser) *DebugPrinter {
}
// Print calls fmt.Print if Enabled is true.
func (dbg DebugPrinter) Print(v ...interface{}) {
func (dbg *DebugPrinter) Print(v ...interface{}) {
if dbg.Enabled {
fmt.Fprint(dbg.out, v...)
}
}
// Println calls fmt.Println if Enabled is true.
func (dbg DebugPrinter) Println(v ...interface{}) {
func (dbg *DebugPrinter) Println(v ...interface{}) {
if dbg.Enabled {
fmt.Fprintln(dbg.out, v...)
}
}
// Printf calls fmt.Printf if Enabled is true.
func (dbg DebugPrinter) Printf(format string, v ...interface{}) {
func (dbg *DebugPrinter) Printf(format string, v ...interface{}) {
if dbg.Enabled {
fmt.Fprintf(dbg.out, format, v...)
}

View File

@@ -5,7 +5,7 @@ import (
"os"
"testing"
"github.com/kisom/goutils/testio"
"git.wntrmute.dev/kyle/goutils/testio"
"github.com/stretchr/testify/require"
)

352
deps.bzl Normal file
View File

@@ -0,0 +1,352 @@
load("@bazel_gazelle//:deps.bzl", "go_repository")
def go_dependencies():
go_repository(
name = "com_github_akavel_rsrc",
importpath = "github.com/akavel/rsrc",
sum = "h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=",
version = "v0.8.0",
)
go_repository(
name = "com_github_certifi_gocertifi",
importpath = "github.com/certifi/gocertifi",
sum = "h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg=",
version = "v0.0.0-20180118203423-deb3ae2ef261",
)
go_repository(
name = "com_github_cloudflare_backoff",
importpath = "github.com/cloudflare/backoff",
sum = "h1:8d1CEOF1xldesKds5tRG3tExBsMOgWYownMHNCsev54=",
version = "v0.0.0-20161212185259-647f3cdfc87a",
)
go_repository(
name = "com_github_cloudflare_cfssl",
importpath = "github.com/cloudflare/cfssl",
sum = "h1:vFJDAvQgFSRbCn9zg8KpSrrEZrBAQ4KO5oNK7SXEyb0=",
version = "v1.5.0",
)
go_repository(
name = "com_github_cloudflare_go_metrics",
importpath = "github.com/cloudflare/go-metrics",
sum = "h1:/8sZyuGTAU2+fYv0Sz9lBcipqX0b7i4eUl8pSStk/4g=",
version = "v0.0.0-20151117154305-6a9aea36fb41",
)
go_repository(
name = "com_github_cloudflare_redoctober",
importpath = "github.com/cloudflare/redoctober",
sum = "h1:p0Q1GvgWtVf46XpMMibupKiE7aQxPYUIb+/jLTTK2kM=",
version = "v0.0.0-20171127175943-746a508df14c",
)
go_repository(
name = "com_github_creack_pty",
importpath = "github.com/creack/pty",
sum = "h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=",
version = "v1.1.9",
)
go_repository(
name = "com_github_daaku_go_zipexe",
importpath = "github.com/daaku/go.zipexe",
sum = "h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=",
version = "v1.0.0",
)
go_repository(
name = "com_github_davecgh_go_spew",
importpath = "github.com/davecgh/go-spew",
sum = "h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=",
version = "v1.1.1",
)
go_repository(
name = "com_github_geertjohan_go_incremental",
importpath = "github.com/GeertJohan/go.incremental",
sum = "h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=",
version = "v1.0.0",
)
go_repository(
name = "com_github_geertjohan_go_rice",
importpath = "github.com/GeertJohan/go.rice",
sum = "h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=",
version = "v1.0.0",
)
go_repository(
name = "com_github_getsentry_raven_go",
importpath = "github.com/getsentry/raven-go",
sum = "h1:ELaJ1cjF2nEJeIlHXahGme22yG7TK+3jB6IGCq0Cdrc=",
version = "v0.0.0-20180121060056-563b81fc02b7",
)
go_repository(
name = "com_github_go_sql_driver_mysql",
importpath = "github.com/go-sql-driver/mysql",
sum = "h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=",
version = "v1.4.0",
)
go_repository(
name = "com_github_golang_protobuf",
importpath = "github.com/golang/protobuf",
sum = "h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=",
version = "v1.3.1",
)
go_repository(
name = "com_github_google_certificate_transparency_go",
importpath = "github.com/google/certificate-transparency-go",
sum = "h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=",
version = "v1.0.21",
)
go_repository(
name = "com_github_hashicorp_go_syslog",
importpath = "github.com/hashicorp/go-syslog",
sum = "h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=",
version = "v1.0.0",
)
go_repository(
name = "com_github_jessevdk_go_flags",
importpath = "github.com/jessevdk/go-flags",
sum = "h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=",
version = "v1.4.0",
)
go_repository(
name = "com_github_jmhodges_clock",
importpath = "github.com/jmhodges/clock",
sum = "h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4=",
version = "v0.0.0-20160418191101-880ee4c33548",
)
go_repository(
name = "com_github_jmoiron_sqlx",
importpath = "github.com/jmoiron/sqlx",
sum = "h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=",
version = "v1.2.0",
)
go_repository(
name = "com_github_kisielk_sqlstruct",
importpath = "github.com/kisielk/sqlstruct",
sum = "h1:o/c0aWEP/m6n61xlYW2QP4t9424qlJOsxugn5Zds2Rg=",
version = "v0.0.0-20150923205031-648daed35d49",
)
go_repository(
name = "com_github_kisom_goutils",
importpath = "github.com/kisom/goutils",
sum = "h1:z4HEOgAnFq+e1+O4QdVsyDPatJDu5Ei/7w7DRbYjsIA=",
version = "v1.1.0",
)
go_repository(
name = "com_github_konsorten_go_windows_terminal_sequences",
importpath = "github.com/konsorten/go-windows-terminal-sequences",
sum = "h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=",
version = "v1.0.1",
)
go_repository(
name = "com_github_kr_fs",
importpath = "github.com/kr/fs",
sum = "h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=",
version = "v0.1.0",
)
go_repository(
name = "com_github_kr_pretty",
importpath = "github.com/kr/pretty",
sum = "h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=",
version = "v0.1.0",
)
go_repository(
name = "com_github_kr_pty",
importpath = "github.com/kr/pty",
sum = "h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=",
version = "v1.1.1",
)
go_repository(
name = "com_github_kr_text",
importpath = "github.com/kr/text",
sum = "h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=",
version = "v0.2.0",
)
go_repository(
name = "com_github_kylelemons_go_gypsy",
importpath = "github.com/kylelemons/go-gypsy",
sum = "h1:mkl3tvPHIuPaWsLtmHTybJeoVEW7cbePK73Ir8VtruA=",
version = "v0.0.0-20160905020020-08cad365cd28",
)
go_repository(
name = "com_github_lib_pq",
importpath = "github.com/lib/pq",
sum = "h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=",
version = "v1.3.0",
)
go_repository(
name = "com_github_mattn_go_sqlite3",
importpath = "github.com/mattn/go-sqlite3",
sum = "h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=",
version = "v1.10.0",
)
go_repository(
name = "com_github_mreiferson_go_httpclient",
importpath = "github.com/mreiferson/go-httpclient",
sum = "h1:oKIteTqeSpenyTrOVj5zkiyCaflLa8B+CD0324otT+o=",
version = "v0.0.0-20160630210159-31f0106b4474",
)
go_repository(
name = "com_github_nkovacs_streamquote",
importpath = "github.com/nkovacs/streamquote",
sum = "h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=",
version = "v0.0.0-20170412213628-49af9bddb229",
)
go_repository(
name = "com_github_op_go_logging",
importpath = "github.com/op/go-logging",
sum = "h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=",
version = "v0.0.0-20160315200505-970db520ece7",
)
go_repository(
name = "com_github_pkg_errors",
importpath = "github.com/pkg/errors",
sum = "h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=",
version = "v0.9.1",
)
go_repository(
name = "com_github_pkg_sftp",
importpath = "github.com/pkg/sftp",
sum = "h1:/f3b24xrDhkhddlaobPe2JgBqfdt+gC/NYl0QY9IOuI=",
version = "v1.12.0",
)
go_repository(
name = "com_github_pmezard_go_difflib",
importpath = "github.com/pmezard/go-difflib",
sum = "h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=",
version = "v1.0.0",
)
go_repository(
name = "com_github_sirupsen_logrus",
importpath = "github.com/sirupsen/logrus",
sum = "h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=",
version = "v1.3.0",
)
go_repository(
name = "com_github_stretchr_objx",
importpath = "github.com/stretchr/objx",
sum = "h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=",
version = "v0.1.1",
)
go_repository(
name = "com_github_stretchr_testify",
importpath = "github.com/stretchr/testify",
sum = "h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=",
version = "v1.6.1",
)
go_repository(
name = "com_github_valyala_bytebufferpool",
importpath = "github.com/valyala/bytebufferpool",
sum = "h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=",
version = "v1.0.0",
)
go_repository(
name = "com_github_valyala_fasttemplate",
importpath = "github.com/valyala/fasttemplate",
sum = "h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=",
version = "v1.0.1",
)
go_repository(
name = "com_github_weppos_publicsuffix_go",
importpath = "github.com/weppos/publicsuffix-go",
sum = "h1:0Tu1uzLBd1jPn4k6OnMmOPZH/l/9bj9kUOMMkoRs6Gg=",
version = "v0.13.0",
)
go_repository(
name = "com_github_ziutek_mymysql",
importpath = "github.com/ziutek/mymysql",
sum = "h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=",
version = "v1.5.4",
)
go_repository(
name = "com_github_zmap_rc2",
importpath = "github.com/zmap/rc2",
sum = "h1:kKCF7VX/wTmdg2ZjEaqlq99Bjsoiz7vH6sFniF/vI4M=",
version = "v0.0.0-20131011165748-24b9757f5521",
)
go_repository(
name = "com_github_zmap_zcertificate",
importpath = "github.com/zmap/zcertificate",
sum = "h1:17HHAgFKlLcZsDOjBOUrd5hDihb1ggf+1a5dTbkgkIY=",
version = "v0.0.0-20180516150559-0e3d58b1bac4",
)
go_repository(
name = "com_github_zmap_zcrypto",
importpath = "github.com/zmap/zcrypto",
sum = "h1:PIpcdSOg3pMdFJUBg5yR9xxcj5rm/SGAyaWT/wK6Kco=",
version = "v0.0.0-20200911161511-43ff0ea04f21",
)
go_repository(
name = "com_github_zmap_zlint_v2",
importpath = "github.com/zmap/zlint/v2",
sum = "h1:b2kI/ToXX16h2wjV2c6Da65eT6aTMtkLHKetXuM9EtI=",
version = "v2.2.1",
)
go_repository(
name = "in_gopkg_check_v1",
importpath = "gopkg.in/check.v1",
sum = "h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=",
version = "v1.0.0-20180628173108-788fd7840127",
)
go_repository(
name = "in_gopkg_yaml_v2",
importpath = "gopkg.in/yaml.v2",
sum = "h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=",
version = "v2.4.0",
)
go_repository(
name = "in_gopkg_yaml_v3",
importpath = "gopkg.in/yaml.v3",
sum = "h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=",
version = "v3.0.0-20200313102051-9f266ea9e77c",
)
go_repository(
name = "org_bitbucket_liamstask_goose",
importpath = "bitbucket.org/liamstask/goose",
sum = "h1:bkb2NMGo3/Du52wvYj9Whth5KZfMV6d3O0Vbr3nz/UE=",
version = "v0.0.0-20150115234039-8488cc47d90c",
)
go_repository(
name = "org_golang_google_appengine",
importpath = "google.golang.org/appengine",
sum = "h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=",
version = "v1.6.6",
)
go_repository(
name = "org_golang_x_crypto",
importpath = "golang.org/x/crypto",
sum = "h1:Qwe1rC8PSniVfAFPFJeyUkB+zcysC3RgJBAGk7eqBEU=",
version = "v0.0.0-20220314234659-1baeb1ce4c0b",
)
go_repository(
name = "org_golang_x_lint",
importpath = "golang.org/x/lint",
sum = "h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=",
version = "v0.0.0-20190930215403-16217165b5de",
)
go_repository(
name = "org_golang_x_net",
importpath = "golang.org/x/net",
sum = "h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=",
version = "v0.0.0-20211112202133-69e39bad7dc2",
)
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
sum = "h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=",
version = "v0.0.0-20220412211240-33da011f77ad",
)
go_repository(
name = "org_golang_x_term",
importpath = "golang.org/x/term",
sum = "h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=",
version = "v0.0.0-20201126162022-7de9c90e9dd1",
)
go_repository(
name = "org_golang_x_text",
importpath = "golang.org/x/text",
sum = "h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=",
version = "v0.3.6",
)
go_repository(
name = "org_golang_x_tools",
importpath = "golang.org/x/tools",
sum = "h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=",
version = "v0.0.0-20190311212946-11955173bddd",
)

8
die/BUILD.bazel Normal file
View File

@@ -0,0 +1,8 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "die",
srcs = ["die.go"],
importpath = "git.wntrmute.dev/kyle/goutils/die",
visibility = ["//visibility:public"],
)

9
fileutil/BUILD.bazel Normal file
View File

@@ -0,0 +1,9 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "fileutil",
srcs = ["fileutil.go"],
importpath = "git.wntrmute.dev/kyle/goutils/fileutil",
visibility = ["//visibility:public"],
deps = ["@org_golang_x_sys//unix"],
)

View File

@@ -1,3 +1,6 @@
//go:build !windows
// +build !windows
// Package fileutil contains common file functions.
package fileutil

View File

@@ -0,0 +1,49 @@
//go:build windows
// +build windows
// Package fileutil contains common file functions.
package fileutil
import (
"errors"
"os"
)
// FileDoesExist returns true if the file exists.
func FileDoesExist(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// DirectoryDoesExist returns true if the file exists.
func DirectoryDoesExist(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return false
}
return fi.Mode().IsDir()
}
const (
// AccessExists checks whether the file exists. This is invalid outside of
// Unix systems.
AccessExists = 0
// AccessRead checks whether the user has read permissions on
// the file. This is invalid outside of Unix systems.
AccessRead = 0
// AccessWrite checks whether the user has write permissions
// on the file. This is invalid outside of Unix systems.
AccessWrite = 0
// AccessExec checks whether the user has executable
// permissions on the file. This is invalid outside of Unix systems.
AccessExec = 0
)
// Access is a Unix-only call, and has no meaning on Windows.
func Access(path string, mode int) error {
return errors.New("fileutil: Access is meaningless on Windows")
}

16
fileutil/symlinks.go Normal file
View File

@@ -0,0 +1,16 @@
package fileutil
import (
"path/filepath"
"strings"
)
// ValidateSymlink checks to make sure a symlink exists in some top-level
// directory.
func ValidateSymlink(symlink, topLevel string) bool {
target, err := filepath.EvalSymlinks(symlink)
if err != nil {
return false
}
return strings.HasPrefix(target, topLevel)
}

14
gazelle.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
set -euxo pipefail
BAZEL="bazel"
if [ -z "$(command -v ${BAZEL})" ]
then
BAZEL="bazelisk"
fi
$BAZEL run //:gazelle
$BAZEL run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%go_dependencies
$BAZEL run //:gazelle

16
go.mod
View File

@@ -1,3 +1,15 @@
module github.com/kisom/goutils
module git.wntrmute.dev/kyle/goutils
go 1.13
go 1.20
require (
github.com/cloudflare/cfssl v1.5.0
github.com/hashicorp/go-syslog v1.0.0
github.com/kr/text v0.2.0
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.12.0
github.com/stretchr/testify v1.6.1
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
gopkg.in/yaml.v2 v2.4.0
)

110
go.sum Normal file
View File

@@ -0,0 +1,110 @@
bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY=
github.com/cloudflare/cfssl v1.5.0 h1:vFJDAvQgFSRbCn9zg8KpSrrEZrBAQ4KO5oNK7SXEyb0=
github.com/cloudflare/cfssl v1.5.0/go.mod h1:sPPkBS5L8l8sRc/IOO1jG51Xb34u+TYhL6P//JdODMQ=
github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4=
github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.12.0 h1:/f3b24xrDhkhddlaobPe2JgBqfdt+gC/NYl0QY9IOuI=
github.com/pkg/sftp v1.12.0/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
github.com/zmap/zcrypto v0.0.0-20200513165325-16679db567ff/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4=
github.com/zmap/zcrypto v0.0.0-20200911161511-43ff0ea04f21/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4=
github.com/zmap/zlint/v2 v2.2.1/go.mod h1:ixPWsdq8qLxYRpNUTbcKig3R7WgmspsHGLhCCs6rFAM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b h1:Qwe1rC8PSniVfAFPFJeyUkB+zcysC3RgJBAGk7eqBEU=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

117
lib/BUILD.bazel Normal file
View File

@@ -0,0 +1,117 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "lib",
srcs = [
"defs.go",
"ftime_bsd.go",
"ftime_unix.go",
"lib.go",
],
importpath = "git.wntrmute.dev/kyle/goutils/lib",
visibility = ["//visibility:public"],
deps = select({
"@io_bazel_rules_go//go/platform:android_386": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:android_amd64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:android_arm": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:android_arm64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:darwin_386": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:darwin_amd64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:freebsd_386": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:freebsd_amd64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:freebsd_arm": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:freebsd_arm64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:ios_amd64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_386": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_amd64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_arm": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_arm64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_mips": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_mips64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_mips64le": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_mipsle": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_ppc64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_ppc64le": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_riscv64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux_s390x": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:netbsd_386": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:netbsd_amd64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:netbsd_arm": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:netbsd_arm64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:openbsd_386": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:openbsd_amd64": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:openbsd_arm": [
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:openbsd_arm64": [
"@org_golang_x_sys//unix",
],
"//conditions:default": [],
}),
)
go_test(
name = "lib_test",
size = "small",
srcs = ["lib_test.go"],
embed = [":lib"],
deps = ["//assert"],
)

View File

@@ -89,7 +89,7 @@ func Duration(d time.Duration) string {
if d >= yearDuration {
years := d / yearDuration
s += fmt.Sprintf("%dy", years)
d -= (years * yearDuration)
d -= years * yearDuration
}
if d >= dayDuration {
@@ -103,7 +103,7 @@ func Duration(d time.Duration) string {
d %= 1 * time.Second
hours := d / time.Hour
d -= (hours * time.Hour)
d -= hours * time.Hour
s += fmt.Sprintf("%dh%s", hours, d)
return s
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"testing"
"github.com/kisom/goutils/assert"
"git.wntrmute.dev/kyle/goutils/assert"
)
// some CA certs I found on my computerbox.

24
logging/BUILD.bazel Normal file
View File

@@ -0,0 +1,24 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "logging",
srcs = [
"console_logger.go",
"doc.go",
"file.go",
"levels.go",
"log.go",
],
importpath = "git.wntrmute.dev/kyle/goutils/logging",
visibility = ["//visibility:public"],
)
go_test(
name = "logging_test",
size = "small",
srcs = [
"example_test.go",
"log_test.go",
],
embed = [":logging"],
)

View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "example_lib",
srcs = ["example.go"],
importpath = "git.wntrmute.dev/kyle/goutils/logging/example",
visibility = ["//visibility:private"],
deps = ["//logging"],
)
go_binary(
name = "example",
embed = [":example_lib"],
visibility = ["//visibility:public"],
)

View File

@@ -4,7 +4,7 @@ import (
"os"
"time"
"github.com/kisom/goutils/logging"
"git.wntrmute.dev/kyle/goutils/logging"
)
var log = logging.NewConsole()

View File

@@ -3,7 +3,7 @@ package logging_test
import (
"time"
"github.com/kisom/goutils/logging"
"git.wntrmute.dev/kyle/goutils/logging"
)
var log = logging.NewConsole()

View File

@@ -8,6 +8,67 @@ import (
)
// Logger provides a standardised logging interface.
//
// Log messages consist of four components:
//
// 1. The **level** attaches a notion of priority to the log message.
// Several log levels are available:
//
// + FATAL (32): the system is in an unsuable state, and cannot
// continue to run. Most of the logging for this will cause the
// program to exit with an error code.
// + CRITICAL (16): critical conditions. The error, if uncorrected, is
// likely to cause a fatal condition shortly. An example is running
// out of disk space. This is something that the ops team should get
// paged for.
// + ERROR (8): error conditions. A single error doesn't require an
// ops team to be paged, but repeated errors should often trigger a
// page based on threshold triggers. An example is a network
// failure: it might be a transient failure (these do happen), but
// most of the time it's self-correcting.
// + WARNING (4): warning conditions. An example of this is a bad
// request sent to a server. This isn't an error on the part of the
// program, but it may be indicative of other things. Like errors,
// the ops team shouldn't be paged for errors, but a page might be
// triggered if a certain threshold of warnings is reached (which is
// typically much higher than errors). For example, repeated
// warnings might be a sign that the system is under attack.
// + INFO (2): informational message. This is a normal log message
// that is used to deliver information, such as recording
// requests. Ops teams are never paged for informational
// messages. This is the default log level.
// + DEBUG (1): debug-level message. These are only used during
// development or if a deployed system repeatedly sees abnormal
// errors.
//
// The numeric values indicate the priority of a given level.
//
// 2. The **actor** is used to specify which component is generating
// the log message. This could be the program name, or it could be
// a specific component inside the system.
//
// 3. The **event** is a short message indicating what happened. This is
// most like the traditional log message.
//
// 4. The **attributes** are an optional set of key-value string pairs that
// provide additional information.
//
// Additionally, each log message has an associated timestamp. For the
// text-based logs, this is "%FT%T%z"; for the binary logs, this is a
// 64-bit Unix timestamp. An example text-based timestamp might look like ::
//
// [2016-03-27T20:59:27-0700] [INFO] [actor:server event:request received] client=192.168.2.5 request-size=839
//
// Note that this is organised in a manner that facilitates parsing::
//
// /\[(\d{4}-\d{3}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4})\] \[(\w+\)]\) \[actor:(.+?) event:(.+?)\]/
//
// will cover the header:
//
// + ``$1`` contains the timestamp
// + ``$2`` contains the level
// + ``$3`` contains the actor
// + ``$4`` contains the event
type Logger interface {
// SetLevel sets the minimum log level.
SetLevel(Level)
@@ -23,66 +84,6 @@ type Logger interface {
// Close gives the Logger the opportunity to perform any cleanup.
Close() error
// Log messages consist of four components:
//
// 1. The **level** attaches a notion of priority to the log message.
// Several log levels are available:
//
// + FATAL (32): the system is in an unsuable state, and cannot
// continue to run. Most of the logging for this will cause the
// program to exit with an error code.
// + CRITICAL (16): critical conditions. The error, if uncorrected, is
// likely to cause a fatal condition shortly. An example is running
// out of disk space. This is something that the ops team should get
// paged for.
// + ERROR (8): error conditions. A single error doesn't require an
// ops team to be paged, but repeated errors should often trigger a
// page based on threshold triggers. An example is a network
// failure: it might be a transient failure (these do happen), but
// most of the time it's self-correcting.
// + WARNING (4): warning conditions. An example of this is a bad
// request sent to a server. This isn't an error on the part of the
// program, but it may be indicative of other things. Like errors,
// the ops team shouldn't be paged for errors, but a page might be
// triggered if a certain threshold of warnings is reached (which is
// typically much higher than errors). For example, repeated
// warnings might be a sign that the system is under attack.
// + INFO (2): informational message. This is a normal log message
// that is used to deliver information, such as recording
// requests. Ops teams are never paged for informational
// messages. This is the default log level.
// + DEBUG (1): debug-level message. These are only used during
// development or if a deployed system repeatedly sees abnormal
// errors.
//
// The numeric values indicate the priority of a given level.
//
// 2. The **actor** is used to specify which component is generating
// the log message. This could be the program name, or it could be
// a specific component inside the system.
//
// 3. The **event** is a short message indicating what happened. This is
// most like the traditional log message.
//
// 4. The **attributes** are an optional set of key-value string pairs that
// provide additional information.
//
// Additionally, each log message has an associated timestamp. For the
// text-based logs, this is "%FT%T%z"; for the binary logs, this is a
// 64-bit Unix timestamp. An example text-based timestamp might look like ::
//
// [2016-03-27T20:59:27-0700] [INFO] [actor:server event:request received] client=192.168.2.5 request-size=839
//
// Note that this is organised in a manner that facilitates parsing::
//
// /\[(\d{4}-\d{3}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4})\] \[(\w+\)]\) \[actor:(.+?) event:(.+?)\]/
//
// will cover the header:
//
// + ``$1`` contains the timestamp
// + ``$2`` contains the level
// + ``$3`` contains the actor
// + ``$4`` contains the event
Debug(actor, event string, attrs map[string]string)
Info(actor, event string, attrs map[string]string)
Warn(actor, event string, attrs map[string]string)
@@ -287,6 +288,39 @@ func NewMulti(loggers ...Logger) *Multi {
return &Multi{loggers: loggers}
}
func (m *Multi) SetLevel(level Level) {
for _, l := range m.loggers {
l.SetLevel(level)
}
}
func (m *Multi) Good() bool {
good := true
for _, l := range m.loggers {
good = good && l.Good()
}
return good
}
func (m *Multi) Status() error {
for _, l := range m.loggers {
if err := l.Status(); err != nil {
return err
}
}
return nil
}
func (m *Multi) Close() error {
for _, l := range m.loggers {
l.Close()
}
return nil
}
func (m *Multi) Debug(actor, event string, attrs map[string]string) {
for _, l := range m.loggers {
l.Debug(actor, event, attrs)

View File

@@ -53,3 +53,12 @@ func TestDestroyLogFiles(t *testing.T) {
os.Remove("fw2.log")
os.Remove("fw2.err")
}
func TestMulti(t *testing.T) {
c1 := NewConsole()
c2 := NewConsole()
m := NewMulti(c1, c2)
if !m.Good() {
t.Fatal("failed to set up multi logger")
}
}

19
mwc/BUILD.bazel Normal file
View File

@@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "mwc",
srcs = ["mwc.go"],
importpath = "git.wntrmute.dev/kyle/goutils/mwc",
visibility = ["//visibility:public"],
)
go_test(
name = "mwc_test",
size = "small",
srcs = ["mwc_test.go"],
embed = [":mwc"],
deps = [
"//assert",
"//testio",
],
)

View File

@@ -4,8 +4,8 @@ import (
"bytes"
"testing"
"github.com/kisom/goutils/assert"
"github.com/kisom/goutils/testio"
"git.wntrmute.dev/kyle/goutils/assert"
"git.wntrmute.dev/kyle/goutils/testio"
)
func TestMWC(t *testing.T) {

15
rand/BUILD.bazel Normal file
View File

@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "rand",
srcs = ["rand.go"],
importpath = "git.wntrmute.dev/kyle/goutils/rand",
visibility = ["//visibility:public"],
)
go_test(
name = "rand_test",
size = "small",
srcs = ["rand_test.go"],
embed = [":rand"],
)

16
sbuf/BUILD.bazel Normal file
View File

@@ -0,0 +1,16 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "sbuf",
srcs = ["sbuf.go"],
importpath = "git.wntrmute.dev/kyle/goutils/sbuf",
visibility = ["//visibility:public"],
)
go_test(
name = "sbuf_test",
size = "small",
srcs = ["sbuf_test.go"],
embed = [":sbuf"],
deps = ["@org_golang_x_crypto//nacl/box"],
)

16
seekbuf/BUILD.bazel Normal file
View File

@@ -0,0 +1,16 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "seekbuf",
srcs = ["seekbuf.go"],
importpath = "git.wntrmute.dev/kyle/goutils/seekbuf",
visibility = ["//visibility:public"],
)
go_test(
name = "seekbuf_test",
size = "small",
srcs = ["seekbuf_test.go"],
embed = [":seekbuf"],
deps = ["//assert"],
)

57
seekbuf/seekbuf.go Normal file
View File

@@ -0,0 +1,57 @@
// Package seekbuf implements a read-seekable buffer.
package seekbuf
import "io"
// Buffer is a ReadWriteCloser that supports seeking. It's intended to
// replicate the functionality of bytes.Buffer that I use in my projects.
//
// Note that the seeking is limited to the read marker; all writes are
// append-only.
type Buffer struct {
data []byte
pos int
}
func New(data []byte) *Buffer {
return &Buffer{
data: data,
}
}
func (b *Buffer) Read(p []byte) (int, error) {
if b.pos >= len(b.data) {
return 0, io.EOF
}
n := copy(p, b.data[b.pos:])
b.pos += n
return n, nil
}
func (b *Buffer) Write(p []byte) (int, error) {
b.data = append(b.data, p...)
return len(p), nil
}
// Seek sets the read pointer to pos.
func (b *Buffer) Seek(pos int) {
b.pos = pos
}
// Rewind resets the read pointer to 0.
func (b *Buffer) Rewind() {
b.Seek(0)
}
// Close clears all the data out of the buffer and sets the read position to 0.
func (b *Buffer) Close() error {
b.data = nil
b.pos = 0
return nil
}
// Len returns the length of data remaining to be read.
func (b *Buffer) Len() int {
return len(b.data[b.pos:])
}

Some files were not shown because too many files have changed in this diff Show More