Compare commits

...

16 Commits

Author SHA1 Message Date
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
100 changed files with 2401 additions and 64 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,7 +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.
of these in superfluous repositories of their own, or rewriting them
for each project, I'm putting them here.
The project can be built with the standard Go tooling, or it can be built
with Bazel.
Contents:
@@ -23,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.
stealchain/ Dump the verified chain from a TLS
connection.
sprox/ Simple TCP proxy.
stealchain/ Dump the verified chain from a TLS
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.
@@ -58,4 +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.
All code here is licensed under the ISC license.

43
WORKSPACE Normal file
View File

@@ -0,0 +1,43 @@
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()
### Packaging rules
http_archive(
name = "rules_pkg",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.9.1/rules_pkg-0.9.1.tar.gz",
"https://github.com/bazelbuild/rules_pkg/releases/download/0.9.1/rules_pkg-0.9.1.tar.gz",
],
sha256 = "8f9ee2dc10c1ae514ee599a8b42ed99fa262b757058f65ad3c384289ff70c4b8",
)
load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
rules_pkg_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"
"git.sr.ht/~kisom/goutils/assert"
"git.wntrmute.dev/kyle/goutils/assert"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/blake2s"
"golang.org/x/crypto/md4"
@@ -213,6 +214,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"
"git.sr.ht/~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"],
)

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"
"git.sr.ht/~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

@@ -11,8 +11,8 @@ import (
"time"
"github.com/cloudflare/cfssl/helpers"
"git.sr.ht/~kisom/goutils/die"
"git.sr.ht/~kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/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

@@ -10,8 +10,8 @@ import (
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/revoke"
"git.sr.ht/~kisom/goutils/die"
"git.sr.ht/~kisom/goutils/lib"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/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"
"git.sr.ht/~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,7 @@ import (
"os"
"path/filepath"
"git.sr.ht/~kisom/goutils/die"
"git.wntrmute.dev/kyle/goutils/die"
)
var (

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"
"git.sr.ht/~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"
"git.sr.ht/~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"
"git.sr.ht/~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"
"git.sr.ht/~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"
"git.sr.ht/~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"
"git.sr.ht/~kisom/goutils/assert"
"git.sr.ht/~kisom/goutils/die"
"git.sr.ht/~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"
"git.sr.ht/~kisom/goutils/fileutil"
"git.sr.ht/~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"
"git.sr.ht/~kisom/goutils/ahash"
"git.sr.ht/~kisom/goutils/die"
"git.sr.ht/~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,8 +12,8 @@ import (
"sort"
"strings"
"git.sr.ht/~kisom/goutils/die"
"git.sr.ht/~kisom/goutils/logging"
"git.wntrmute.dev/kyle/goutils/die"
"git.wntrmute.dev/kyle/goutils/logging"
)
var (

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"
"git.sr.ht/~kisom/goutils/die"
"git.sr.ht/~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"
"git.sr.ht/~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"
"git.sr.ht/~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"
"git.sr.ht/~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"
"git.sr.ht/~kisom/goutils/die"
"git.sr.ht/~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"
"git.sr.ht/~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

@@ -5,7 +5,7 @@ import (
"os"
"testing"
"git.sr.ht/~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:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=",
version = "v0.0.0-20210615035016-665e8c7367d1",
)
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"],
)

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

18
go.mod
View File

@@ -1,15 +1,23 @@
module git.sr.ht/~kisom/goutils
module git.wntrmute.dev/kyle/goutils
go 1.13
go 1.20
require (
github.com/cloudflare/cfssl v1.5.0
github.com/kisom/goutils v1.1.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-20201124201722-c8d3bf9c5392
golang.org/x/sys v0.0.0-20201126233918-771906719818
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/certificate-transparency-go v1.0.21 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

15
go.sum
View File

@@ -18,11 +18,12 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
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 h1:z4HEOgAnFq+e1+O4QdVsyDPatJDu5Ei/7w7DRbYjsIA=
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=
@@ -72,8 +73,8 @@ golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68/go.mod h1:yigFU9vqHzYiE8U
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-20201124201722-c8d3bf9c5392 h1:xYJJ3S178yv++9zXV/hnr29plCAGO9vAFG9dorqaFQc=
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
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=
@@ -83,12 +84,10 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY
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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818 h1:f1CIuDlJhwANEC2MM87MBEVMr3jl5bifgsfj90XAF9c=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
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=

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

@@ -4,7 +4,7 @@ import (
"fmt"
"testing"
"git.sr.ht/~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"
"git.sr.ht/~kisom/goutils/logging"
"git.wntrmute.dev/kyle/goutils/logging"
)
var log = logging.NewConsole()

View File

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

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"
"git.sr.ht/~kisom/goutils/assert"
"git.sr.ht/~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"],
)

View File

@@ -1,3 +1,4 @@
// seekbuf implements a read-seekable buffer.
package seekbuf
import "io"
@@ -40,11 +41,17 @@ func (b *Buffer) Seek(pos int) {
// Rewind resets the read pointer to 0.
func (b *Buffer) Rewind() {
b.pos = 0
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.Clear()
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:])
}

39
seekbuf/seekbuf_test.go Normal file
View File

@@ -0,0 +1,39 @@
package seekbuf
import (
"fmt"
"testing"
"git.wntrmute.dev/kyle/goutils/assert"
)
func TestSeeking(t *testing.T) {
partA := []byte("hello, ")
partB := []byte("world!")
buf := New(partA)
assert.BoolT(t, buf.Len() == len(partA), fmt.Sprintf("on init: have length %d, want length %d", buf.Len(), len(partA)))
b := make([]byte, 32)
n, err := buf.Read(b)
assert.NoErrorT(t, err)
assert.BoolT(t, buf.Len() == 0, fmt.Sprintf("after reading 1: have length %d, want length 0", buf.Len()))
assert.BoolT(t, n == len(partA), fmt.Sprintf("after reading 2: have length %d, want length %d", n, len(partA)))
n, err = buf.Write(partB)
assert.NoErrorT(t, err)
assert.BoolT(t, n == len(partB), fmt.Sprintf("after writing: have length %d, want length %d", n, len(partB)))
n, err = buf.Read(b)
assert.NoErrorT(t, err)
assert.BoolT(t, buf.Len() == 0, fmt.Sprintf("after rereading 1: have length %d, want length 0", buf.Len()))
assert.BoolT(t, n == len(partB), fmt.Sprintf("after rereading 2: have length %d, want length %d", n, len(partB)))
partsLen := len(partA) + len(partB)
buf.Rewind()
assert.BoolT(t, buf.Len() == partsLen, fmt.Sprintf("after rewinding: have length %d, want length %d", buf.Len(), partsLen))
buf.Close()
assert.BoolT(t, buf.Len() == 0, fmt.Sprintf("after closing, have length %d, want length 0", buf.Len()))
}

17
syslog/BUILD.bazel Normal file
View File

@@ -0,0 +1,17 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "log",
srcs = ["logger.go"],
importpath = "git.wntrmute.dev/kyle/kdhcp/log",
visibility = ["//visibility:public"],
deps = ["@com_github_hashicorp_go_syslog//:go-syslog"],
)
go_library(
name = "syslog",
srcs = ["logger.go"],
importpath = "git.wntrmute.dev/kyle/goutils/syslog",
visibility = ["//visibility:public"],
deps = ["@com_github_hashicorp_go_syslog//:go-syslog"],
)

257
syslog/logger.go Normal file
View File

@@ -0,0 +1,257 @@
// syslog is a syslog-type facility for logging.
package syslog
import (
"fmt"
"os"
"strings"
"time"
gsyslog "github.com/hashicorp/go-syslog"
)
type logger struct {
l gsyslog.Syslogger
p gsyslog.Priority
}
func (log *logger) printf(p gsyslog.Priority, format string, args ...interface{}) {
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
if p <= log.p {
fmt.Printf("%s [%s] ", prioritiev[p], timestamp())
fmt.Printf(format, args...)
}
if log.l != nil {
log.l.WriteLevel(p, []byte(fmt.Sprintf(format, args...)))
}
}
func (log *logger) print(p gsyslog.Priority, args ...interface{}) {
if p <= log.p {
fmt.Printf("%s [%s] ", prioritiev[p], timestamp())
fmt.Print(args...)
}
if log.l != nil {
log.l.WriteLevel(p, []byte(fmt.Sprint(args...)))
}
}
func (log *logger) println(p gsyslog.Priority, args ...interface{}) {
if p <= log.p {
fmt.Printf("%s [%s] ", prioritiev[p], timestamp())
fmt.Println(args...)
}
if log.l != nil {
log.l.WriteLevel(p, []byte(fmt.Sprintln(args...)))
}
}
func (log *logger) adjustPriority(level string) error {
priority, ok := priorities[level]
if !ok {
return fmt.Errorf("log: unknown priority %s", level)
}
log.p = priority
return nil
}
var log = &logger{p: gsyslog.LOG_WARNING}
var priorities = map[string]gsyslog.Priority{
"EMERG": gsyslog.LOG_EMERG,
"ALERT": gsyslog.LOG_ALERT,
"CRIT": gsyslog.LOG_CRIT,
"ERR": gsyslog.LOG_ERR,
"WARNING": gsyslog.LOG_WARNING,
"NOTICE": gsyslog.LOG_NOTICE,
"INFO": gsyslog.LOG_INFO,
"DEBUG": gsyslog.LOG_DEBUG,
}
var prioritiev = map[gsyslog.Priority]string{
gsyslog.LOG_EMERG: "EMERG",
gsyslog.LOG_ALERT: "ALERT",
gsyslog.LOG_CRIT: "CRIT",
gsyslog.LOG_ERR: "ERR",
gsyslog.LOG_WARNING: "WARNING",
gsyslog.LOG_NOTICE: "NOTICE",
gsyslog.LOG_INFO: "INFO",
gsyslog.LOG_DEBUG: "DEBUG",
}
func timestamp() string {
return time.Now().Format("2006-01-02 15:04:05 MST")
}
type Options struct {
Level string
Tag string
Facility string
WriteSyslog bool
}
// DefaultOptions returns a sane set of defaults for syslog, using the program
// name as the tag name. withSyslog controls whether logs should be sent to
// syslog, too.
func DefaultOptions(tag string, withSyslog bool) {
if tag == "" {
tag = os.Args[0]
}
return &DefaultOptions{
Level: "WARNING",
Tag: tag,
Facility: "daemon",
WriteSyslog: withSyslog,
}
}
// DefaultDefaultOptions returns a sane set of debug defaults for syslog,
// using the program name as the tag name. withSyslog controls whether logs
// should be sent to syslog, too.
func DefaultDebugOptions(tag string, withSyslog bool) {
if tag == "" {
tag = os.Args[0]
}
return &DefaultOptions{
Level: "DEBUG",
Facility: "daemon",
WriteSyslog: withSyslog,
}
}
func Setup(opts *Options) error {
priority, ok := priorities[opts.Level]
if !ok {
return fmt.Errorf("log: unknown priority %s", level)
}
log.p = priority
var err error
log.l, err = gsyslog.NewLogger(priority, opts.Facility, opts.Tag)
if err != nil {
return err
}
return nil
}
func Debug(args ...interface{}) {
log.print(gsyslog.LOG_DEBUG, args...)
}
func Info(args ...interface{}) {
log.print(gsyslog.LOG_INFO, args...)
}
func Notice(args ...interface{}) {
log.print(gsyslog.LOG_NOTICE, args...)
}
func Warning(args ...interface{}) {
log.print(gsyslog.LOG_WARNING, args...)
}
func Err(args ...interface{}) {
log.print(gsyslog.LOG_ERR, args...)
}
func Crit(args ...interface{}) {
log.print(gsyslog.LOG_CRIT, args...)
}
func Alert(args ...interface{}) {
log.print(gsyslog.LOG_ALERT, args...)
}
func Emerg(args ...interface{}) {
log.print(gsyslog.LOG_EMERG, args...)
}
func Debugln(args ...interface{}) {
log.println(gsyslog.LOG_DEBUG, args...)
}
func Infoln(args ...interface{}) {
log.println(gsyslog.LOG_INFO, args...)
}
func Noticeln(args ...interface{}) {
log.println(gsyslog.LOG_NOTICE, args...)
}
func Warningln(args ...interface{}) {
log.print(gsyslog.LOG_WARNING, args...)
}
func Errln(args ...interface{}) {
log.println(gsyslog.LOG_ERR, args...)
}
func Critln(args ...interface{}) {
log.println(gsyslog.LOG_CRIT, args...)
}
func Alertln(args ...interface{}) {
log.println(gsyslog.LOG_ALERT, args...)
}
func Emergln(args ...interface{}) {
log.println(gsyslog.LOG_EMERG, args...)
}
func Debugf(format string, args ...interface{}) {
log.printf(gsyslog.LOG_DEBUG, format, args...)
}
func Infof(format string, args ...interface{}) {
log.printf(gsyslog.LOG_INFO, format, args...)
}
func Noticef(format string, args ...interface{}) {
log.printf(gsyslog.LOG_NOTICE, format, args...)
}
func Warningf(format string, args ...interface{}) {
log.printf(gsyslog.LOG_WARNING, format, args...)
}
func Errf(format string, args ...interface{}) {
log.printf(gsyslog.LOG_ERR, format, args...)
}
func Critf(format string, args ...interface{}) {
log.printf(gsyslog.LOG_CRIT, format, args...)
}
func Alertf(format string, args ...interface{}) {
log.printf(gsyslog.LOG_ALERT, format, args...)
}
func Emergf(format string, args ...interface{}) {
log.printf(gsyslog.LOG_EMERG, format, args...)
os.Exit(1)
}
func Fatal(args ...interface{}) {
log.println(gsyslog.LOG_ERR, args...)
os.Exit(1)
}
func Fatalf(format string, args ...interface{}) {
log.printf(gsyslog.LOG_ERR, format, args...)
os.Exit(1)
}
func ChangePriority(level string) error {
return log.adjustPriority(level)
}

8
tee/BUILD.bazel Normal file
View File

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

View File

@@ -5,9 +5,15 @@ import (
"os"
)
type WriteStringCloser interface {
Write([]byte) (int, error)
WriteString(string) (int, error)
Close() error
}
// Tee emulates the Unix tee(1) command.
type Tee struct {
f *os.File
f WriteStringCloser
Verbose bool
}

15
testio/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 = "testio",
srcs = ["testio.go"],
importpath = "git.wntrmute.dev/kyle/goutils/testio",
visibility = ["//visibility:public"],
)
go_test(
name = "testio_test",
size = "small",
srcs = ["testio_test.go"],
embed = [":testio"],
)

View File

@@ -9,7 +9,7 @@ This is a collection of various utility io types:
* LoggingBuffer
You can check out the
[godoc](https://godoc.org/github.com/kisom/goutils/testio) for dtails.
[godoc](https://godoc.io/git.wntrmute.dev/kyle/goutils/testio) for dtails.
It was imported from [kisom/testio](https://github.com/kisom/testio/). The
original Git directory is preserved in git-hist.tar.xz.

8
testutil/BUILD.bazel Normal file
View File

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