refactor(project): rethink directory structure

This commit is contained in:
Dustin Stiles 2025-03-21 22:51:04 -04:00
parent 1876033e13
commit 330fa5dd37
Signed by: duwstiles
GPG Key ID: BCD9912EC231FC87
36 changed files with 564 additions and 95 deletions

1
CHANGELOG.md Normal file
View File

@ -0,0 +1 @@
# Changelog

View File

@ -3,9 +3,9 @@ package main
import ( import (
"context" "context"
"koti.casa/numenor-labs/dsfx/cmd/dsfxctl/client" "koti.casa/numenor-labs/dsfx/internal/client/client"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
"koti.casa/numenor-labs/dsfx/pkg/system" "koti.casa/numenor-labs/dsfx/internal/lib/system"
) )
func main() { func main() {

View File

@ -4,10 +4,11 @@ import (
"context" "context"
"log/slog" "log/slog"
"koti.casa/numenor-labs/dsfx/cmd/dsfxnode/node" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/system"
"koti.casa/numenor-labs/dsfx/pkg/storage/scoped" "koti.casa/numenor-labs/dsfx/internal/peer/node"
"koti.casa/numenor-labs/dsfx/pkg/system"
"koti.casa/numenor-labs/dsfx/internal/lib/storage/scoped"
) )
func main() { func main() {

View File

@ -8,13 +8,14 @@ import (
"log/slog" "log/slog"
"net" "net"
"koti.casa/numenor-labs/dsfx/cmd/dsfxctl/conf" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/identity"
"koti.casa/numenor-labs/dsfx/pkg/crypto/identity" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/logging"
"koti.casa/numenor-labs/dsfx/pkg/logging" "koti.casa/numenor-labs/dsfx/internal/lib/network"
"koti.casa/numenor-labs/dsfx/pkg/network" "koti.casa/numenor-labs/dsfx/internal/lib/storage/scoped"
"koti.casa/numenor-labs/dsfx/pkg/storage/scoped" "koti.casa/numenor-labs/dsfx/internal/lib/system"
"koti.casa/numenor-labs/dsfx/pkg/system"
"koti.casa/numenor-labs/dsfx/internal/client/conf"
) )
// Client represents the client application for dsfxctl. // Client represents the client application for dsfxctl.

View File

@ -1,6 +1,6 @@
package conf package conf
import "koti.casa/numenor-labs/dsfx/pkg/system" import "koti.casa/numenor-labs/dsfx/internal/lib/system"
const ( const (
// DefaultConfigDir is the default directory for the dsfxctl configuration. // DefaultConfigDir is the default directory for the dsfxctl configuration.

View File

@ -4,7 +4,7 @@ import (
"crypto/rand" "crypto/rand"
"testing" "testing"
"koti.casa/numenor-labs/dsfx/pkg/crypto/encryption" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/encryption"
) )
func TestEncryptDecrypt(t *testing.T) { func TestEncryptDecrypt(t *testing.T) {

View File

@ -3,7 +3,7 @@ package disk_test
import ( import (
"testing" "testing"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
) )
func TestDefaultDisk(t *testing.T) { func TestDefaultDisk(t *testing.T) {

View File

@ -5,7 +5,7 @@ import (
"bytes" "bytes"
"testing" "testing"
"koti.casa/numenor-labs/dsfx/pkg/frame" "koti.casa/numenor-labs/dsfx/internal/lib/frame"
) )
func TestLenPrefixedWriteTo(t *testing.T) { func TestLenPrefixedWriteTo(t *testing.T) {

View File

@ -0,0 +1,7 @@
goos: linux
goarch: amd64
pkg: koti.casa/numenor-labs/dsfx/internal/lib/handshake
cpu: Intel(R) Core(TM) Ultra 9 185H
BenchmarkHandshake 4508 285270 ns/op 12976 B/op 131 allocs/op
PASS
ok koti.casa/numenor-labs/dsfx/internal/lib/handshake 1.291s

View File

@ -10,12 +10,12 @@ import (
"io" "io"
"log/slog" "log/slog"
"koti.casa/numenor-labs/dsfx/pkg/assert" "koti.casa/numenor-labs/dsfx/internal/lib/assert"
"koti.casa/numenor-labs/dsfx/pkg/buffer" "koti.casa/numenor-labs/dsfx/internal/lib/buffer"
"koti.casa/numenor-labs/dsfx/pkg/crypto/encryption" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/encryption"
"koti.casa/numenor-labs/dsfx/pkg/crypto/identity" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/identity"
"koti.casa/numenor-labs/dsfx/pkg/crypto/keyexchange" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/keyexchange"
"koti.casa/numenor-labs/dsfx/pkg/logging" "koti.casa/numenor-labs/dsfx/internal/lib/logging"
) )
const ( const (

View File

@ -10,8 +10,8 @@ import (
"sync" "sync"
"testing" "testing"
"koti.casa/numenor-labs/dsfx/pkg/crypto/identity" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/identity"
"koti.casa/numenor-labs/dsfx/pkg/handshake" "koti.casa/numenor-labs/dsfx/internal/lib/handshake"
) )
func TestHandshake(t *testing.T) { func TestHandshake(t *testing.T) {

View File

@ -8,7 +8,7 @@ import (
"net" "net"
"strings" "strings"
"koti.casa/numenor-labs/dsfx/pkg/crypto/identity" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/identity"
) )
var ( var (

View File

@ -5,8 +5,8 @@ import (
"net" "net"
"time" "time"
"koti.casa/numenor-labs/dsfx/pkg/crypto/encryption" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/encryption"
"koti.casa/numenor-labs/dsfx/pkg/frame" "koti.casa/numenor-labs/dsfx/internal/lib/frame"
) )
// Conn is a wrapper around net.TCPConn that encrypts and decrypts data as it is // Conn is a wrapper around net.TCPConn that encrypts and decrypts data as it is

View File

@ -6,8 +6,8 @@ import (
"log/slog" "log/slog"
"net" "net"
"koti.casa/numenor-labs/dsfx/pkg/crypto/identity" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/identity"
"koti.casa/numenor-labs/dsfx/pkg/handshake" "koti.casa/numenor-labs/dsfx/internal/lib/handshake"
) )
// Listener ... // Listener ...

View File

@ -5,8 +5,8 @@ import (
"crypto/ed25519" "crypto/ed25519"
"net" "net"
"koti.casa/numenor-labs/dsfx/pkg/handshake" "koti.casa/numenor-labs/dsfx/internal/lib/handshake"
"koti.casa/numenor-labs/dsfx/pkg/logging" "koti.casa/numenor-labs/dsfx/internal/lib/logging"
) )
// Dial ... // Dial ...

View File

@ -4,7 +4,7 @@ import (
"io/fs" "io/fs"
"path/filepath" "path/filepath"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
) )
// StorageScope is an interface that extends the disk.Disk interface by ensuring // StorageScope is an interface that extends the disk.Disk interface by ensuring

View File

@ -4,8 +4,8 @@ import (
"io/fs" "io/fs"
"testing" "testing"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
"koti.casa/numenor-labs/dsfx/pkg/storage/scoped" "koti.casa/numenor-labs/dsfx/internal/lib/storage/scoped"
) )
func TestScopedStorage_Scope(t *testing.T) { func TestScopedStorage_Scope(t *testing.T) {

View File

@ -3,7 +3,7 @@ package system
import ( import (
"os" "os"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
) )
// Default returns a default implementation of the System interface. // Default returns a default implementation of the System interface.

View File

@ -1,7 +1,7 @@
package system package system
import ( import (
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
) )
type System interface { type System interface {

View File

@ -1,6 +1,6 @@
package conf package conf
import "koti.casa/numenor-labs/dsfx/pkg/system" import "koti.casa/numenor-labs/dsfx/internal/lib/system"
const ( const (
// DefaultConfigDir is the default directory for the dsfxctl configuration. // DefaultConfigDir is the default directory for the dsfxctl configuration.

View File

@ -10,12 +10,13 @@ import (
"os" "os"
"strings" "strings"
"koti.casa/numenor-labs/dsfx/cmd/dsfxnode/conf" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/identity"
"koti.casa/numenor-labs/dsfx/pkg/crypto/identity" "koti.casa/numenor-labs/dsfx/internal/lib/disk"
"koti.casa/numenor-labs/dsfx/pkg/disk" "koti.casa/numenor-labs/dsfx/internal/lib/logging"
"koti.casa/numenor-labs/dsfx/pkg/logging" "koti.casa/numenor-labs/dsfx/internal/lib/network"
"koti.casa/numenor-labs/dsfx/pkg/network" "koti.casa/numenor-labs/dsfx/internal/lib/system"
"koti.casa/numenor-labs/dsfx/pkg/system"
"koti.casa/numenor-labs/dsfx/internal/peer/conf"
) )
type Node struct { type Node struct {

287
internal/sim/disk.go Normal file
View File

@ -0,0 +1,287 @@
package sim
import (
"errors"
"io"
"io/fs"
"math/rand"
"sync"
"time"
"koti.casa/numenor-labs/dsfx/internal/lib/disk"
)
// Tolerance defines simulation tolerance parameters.
type Tolerance struct {
// Latency to wait before executing an operation.
Latency time.Duration
// FailureChance is the probability (0.01.0) that an operation fails.
FailureChance float64
// CorruptionChance is the probability (0.01.0) that a write is corrupted.
CorruptionChance float64
}
// simEntry represents an entry in our inmemory file system.
type simEntry struct {
name string
isDir bool
perm fs.FileMode
modTime time.Time
// For files, data holds the file contents.
data []byte
mu sync.Mutex
}
// simFile is a simulated file object. It implements fs.File and io.Writer.
// The same underlying simEntry is shared among all handles to a given file.
type simFile struct {
entry *simEntry
// offset to simulate reading sequentially.
offset int
// readOnly indicates whether writes are allowed.
readOnly bool
// closed is set once Close() has been called.
closed bool
// You could add a mutex here if you want to protect concurrent access per handle.
mu sync.Mutex
// tol copied from the SimDisk for perfile simulation.
tol Tolerance
}
// Ensure simFile implements the interfaces.
var _ disk.File = (*simFile)(nil)
// Read reads from the simulated file starting at the current offset.
func (sf *simFile) Read(p []byte) (int, error) {
sf.mu.Lock()
defer sf.mu.Unlock()
if sf.closed {
return 0, errors.New("read from closed file")
}
// Lock the underlying data.
sf.entry.mu.Lock()
defer sf.entry.mu.Unlock()
if sf.offset >= len(sf.entry.data) {
return 0, io.EOF
}
n := copy(p, sf.entry.data[sf.offset:])
sf.offset += n
return n, nil
}
// Write writes the given bytes at the end of the file (for a writable file).
// It may simulate corruption.
func (sf *simFile) Write(p []byte) (int, error) {
if sf.readOnly {
return 0, errors.New("cannot write to read-only file")
}
sf.mu.Lock()
defer sf.mu.Unlock()
if sf.closed {
return 0, errors.New("write to closed file")
}
// simulate latency
time.Sleep(sf.tol.Latency)
// simulate failure
if rand.Float64() < sf.tol.FailureChance {
return 0, errors.New("simulated write failure")
}
// prepare data to write
dataToWrite := make([]byte, len(p))
copy(dataToWrite, p)
// simulate corruption by flipping bits in the data (if triggered)
if rand.Float64() < sf.tol.CorruptionChance {
for i := range dataToWrite {
dataToWrite[i] = ^dataToWrite[i] // simple corruption: bitwise complement
}
}
// lock the underlying entry and append data
sf.entry.mu.Lock()
defer sf.entry.mu.Unlock()
sf.entry.data = append(sf.entry.data, dataToWrite...)
// update modification time
sf.entry.modTime = time.Now()
return len(p), nil
}
// Close marks the file as closed.
func (sf *simFile) Close() error {
sf.mu.Lock()
defer sf.mu.Unlock()
if sf.closed {
return errors.New("file already closed")
}
sf.closed = true
return nil
}
// Stat returns file information for the simulated file.
func (sf *simFile) Stat() (fs.FileInfo, error) {
sf.mu.Lock()
defer sf.mu.Unlock()
if sf.closed {
return nil, errors.New("stat on closed file")
}
return &simFileInfo{entry: sf.entry}, nil
}
// simFileInfo implements fs.FileInfo for a simEntry.
type simFileInfo struct {
entry *simEntry
}
var _ fs.FileInfo = (*simFileInfo)(nil)
func (fi *simFileInfo) Name() string { return fi.entry.name }
func (fi *simFileInfo) Size() int64 {
fi.entry.mu.Lock()
defer fi.entry.mu.Unlock()
return int64(len(fi.entry.data))
}
func (fi *simFileInfo) Mode() fs.FileMode { return fi.entry.perm }
func (fi *simFileInfo) ModTime() time.Time { return fi.entry.modTime }
func (fi *simFileInfo) IsDir() bool { return fi.entry.isDir }
func (fi *simFileInfo) Sys() interface{} { return nil }
// SimDisk is our inmemory simulation that implements the disk.Disk interface.
type SimDisk struct {
// tol holds the tolerance parameters to simulate latency, failures, corruption.
tol Tolerance
// entries is a map from file or directory name to its corresponding simEntry.
entries map[string]*simEntry
mu sync.Mutex
}
// NewSimDisk returns a new simulated disk with the given tolerance parameters.
func NewSimDisk(tol Tolerance) disk.Disk {
return &SimDisk{
tol: tol,
entries: make(map[string]*simEntry),
}
}
// simulateOp sleeps for the configured latency and then returns an error if a failure is simulated.
func (sd *SimDisk) simulateOp() error {
time.Sleep(sd.tol.Latency)
if rand.Float64() < sd.tol.FailureChance {
return errors.New("simulated disk operation failure")
}
return nil
}
// Mkdir creates a directory in the simulated file system.
func (sd *SimDisk) Mkdir(name string, perm fs.FileMode) error {
if err := sd.simulateOp(); err != nil {
return err
}
sd.mu.Lock()
defer sd.mu.Unlock()
if _, exists := sd.entries[name]; exists {
return errors.New("directory already exists")
}
sd.entries[name] = &simEntry{
name: name,
isDir: true,
perm: perm,
modTime: time.Now(),
}
return nil
}
// Create creates (or truncates) a file in the simulated file system and returns a writable file.
func (sd *SimDisk) Create(name string) (disk.File, error) {
if err := sd.simulateOp(); err != nil {
return nil, err
}
sd.mu.Lock()
// For simplicity, Create always truncates (or creates new)
se := &simEntry{
name: name,
isDir: false,
perm: 0644,
modTime: time.Now(),
data: []byte{},
}
sd.entries[name] = se
sd.mu.Unlock()
// Return a writable file handle
return &simFile{
entry: se,
offset: 0,
readOnly: false,
tol: sd.tol,
}, nil
}
// Open opens an existing file in the simulated file system.
// The returned file is "read-only" (write attempts will error),
func (sd *SimDisk) Open(name string) (disk.File, error) {
if err := sd.simulateOp(); err != nil {
return nil, err
}
sd.mu.Lock()
se, exists := sd.entries[name]
sd.mu.Unlock()
if !exists {
return nil, errors.New("file does not exist")
}
if se.isDir {
return nil, errors.New("cannot open directory")
}
// Return a new file handle starting at offset 0; marked as readOnly.
return &simFile{
entry: se,
offset: 0,
readOnly: true,
tol: sd.tol,
}, nil
}
// Stat returns information about the file or directory.
func (sd *SimDisk) Stat(name string) (fs.FileInfo, error) {
if err := sd.simulateOp(); err != nil {
return nil, err
}
sd.mu.Lock()
se, exists := sd.entries[name]
sd.mu.Unlock()
if !exists {
return nil, errors.New("no such file or directory")
}
return &simFileInfo{entry: se}, nil
}
// Remove deletes a file or directory from the simulated file system.
func (sd *SimDisk) Remove(name string) error {
if err := sd.simulateOp(); err != nil {
return err
}
sd.mu.Lock()
defer sd.mu.Unlock()
if _, exists := sd.entries[name]; !exists {
return errors.New("file or directory does not exist")
}
delete(sd.entries, name)
return nil
}

219
internal/sim/system.go Normal file
View File

@ -0,0 +1,219 @@
package sim
import (
"errors"
"math/rand"
"sync"
"time"
"koti.casa/numenor-labs/dsfx/internal/lib/disk"
"koti.casa/numenor-labs/dsfx/internal/lib/system"
)
// SimSystem is a simulated implementation of system.System.
// It allows the caller to set parameters for latency and failure chance (from tol)
// and provides inmemory values for commandline arguments, environment variables,
// and standard output/error.
type SimSystem struct {
// Simulation tolerance parameters (latency, failure chance, corruption chance).
tol Tolerance
// Simulated commandline arguments.
args []string
// Inmemory environment variables. Protected by mu.
mu sync.Mutex
env map[string]string
// Simulated directory paths.
homeDir string
configDir string
cacheDir string
tempDir string
// Simulated standard output and error.
stdout disk.File
stderr disk.File
}
// NewSimSystem returns a new simulated system that implements system.System.
// The caller provides a tolerance value and a slice of commandline arguments.
// Other fields (directories, environment) are prepopulated for simulation purposes.
func NewSimSystem(tol Tolerance, args []string) system.System {
s := &SimSystem{
tol: tol,
args: args,
env: make(map[string]string),
homeDir: "/home/simuser",
configDir: "/home/simuser/.config",
cacheDir: "/home/simuser/.cache",
tempDir: "/tmp",
}
// Create simulated stdout and stderr.
s.stdout = newSimOutput("stdout", tol)
s.stderr = newSimOutput("stderr", tol)
return s
}
// simulateOp applies the configured latency and possibly simulates an operation failure.
func (s *SimSystem) simulateOp() error {
time.Sleep(s.tol.Latency)
if rand.Float64() < s.tol.FailureChance {
return errors.New("simulated system operation failure")
}
return nil
}
// Args returns the simulated commandline arguments (skipping the program name).
func (s *SimSystem) Args() []string {
// Simulate latency even for argument access.
_ = s.simulateOp()
// Return a copy so that callers cannot modify the underlying slice.
cpy := make([]string, len(s.args))
copy(cpy, s.args)
return cpy
}
// Arg returns the simulated commandline argument at index i.
// If the index is outofrange, it returns an empty string.
func (s *SimSystem) Arg(i int) string {
_ = s.simulateOp()
if i < 0 || i >= len(s.args) {
return ""
}
return s.args[i]
}
// UserHomeDir returns the simulated home directory.
func (s *SimSystem) UserHomeDir() (string, error) {
if err := s.simulateOp(); err != nil {
return "", err
}
return s.homeDir, nil
}
// UserConfigDir returns the simulated configuration directory.
func (s *SimSystem) UserConfigDir() (string, error) {
if err := s.simulateOp(); err != nil {
return "", err
}
return s.configDir, nil
}
// UserCacheDir returns the simulated cache directory.
func (s *SimSystem) UserCacheDir() (string, error) {
if err := s.simulateOp(); err != nil {
return "", err
}
return s.cacheDir, nil
}
// TempDir returns the simulated temporary directory.
func (s *SimSystem) TempDir() string {
// We simulate latency even though TempDir cannot fail.
_ = s.simulateOp()
return s.tempDir
}
// Stdout returns a simulated disk.File representing standard output.
func (s *SimSystem) Stdout() disk.File {
// In a real simulation you might add latency/failure to writes on stdout.
_ = s.simulateOp()
return s.stdout
}
// Stderr returns a simulated disk.File representing standard error.
func (s *SimSystem) Stderr() disk.File {
_ = s.simulateOp()
return s.stderr
}
// Exit simulates terminating the program with the given exit code.
// As with many tests, we simulate exit by panicing with a special error.
// This allows tests to catch the panic and inspect the exit code.
func (s *SimSystem) Exit(code int) {
_ = s.simulateOp()
panic(&SimExitError{Code: code})
}
// GetEnv retrieves the simulated value for the environment variable named by key.
func (s *SimSystem) GetEnv(key string) string {
_ = s.simulateOp()
s.mu.Lock()
defer s.mu.Unlock()
return s.env[key]
}
// SetEnv sets the simulated environment variable named by key to value.
func (s *SimSystem) SetEnv(key, value string) error {
_ = s.simulateOp()
s.mu.Lock()
defer s.mu.Unlock()
s.env[key] = value
return nil
}
// SimExitError is the error value used to simulate a program exit.
type SimExitError struct {
Code int
}
// Error implements the error interface.
func (e *SimExitError) Error() string {
return "simulated program exit"
}
// --------------------------------------------------------------------------
// Helper functions and types for simulated standard output/error
// --------------------------------------------------------------------------
// newSimOutput creates a new simulated disk.File that acts as an output.
// Internally it creates a simulated file with an inmemory entry.
func newSimOutput(name string, tol Tolerance) disk.File {
entry := &simEntry{
name: name,
isDir: false,
perm: 0644,
modTime: time.Now(),
data: []byte{},
}
// Return a simFile which implements disk.File.
// (Note: simFile and simEntry are the types defined in dsfx/sim/disk.go.)
return &simFile{
entry: entry,
offset: 0,
readOnly: false,
tol: tol,
}
}
/*
Usage example:
// Define a tolerance for simulation.
tol := sim.Tolerance{
Latency: 10 * time.Millisecond,
FailureChance: 0.01,
CorruptionChance: 0.005,
}
// Simulate a system with custom commandline arguments.
sys := sim.NewSimSystem(tol, []string{"--verbose", "--config=sim.conf"})
// Calling system methods:
args := sys.Args()
home, err := sys.UserHomeDir()
// ... etc.
// To simulate an exit:
func run() {
defer func() {
if r := recover(); r != nil {
if exitErr, ok := r.(*sim.SimExitError); ok {
fmt.Printf("simulated exit(%d)\n", exitErr.Code)
}
}
}()
sys.Exit(3)
}
*/

View File

@ -7,7 +7,7 @@ import (
) )
func main() { func main() {
cmd := exec.Command("go", "test", "-bench=Handshake", "-cpu=1", "-benchmem", "./pkg/handshake/...") cmd := exec.Command("go", "test", "-bench=Handshake", "-cpu=1", "-benchmem", "./internal/lib/handshake/...")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"koti.casa/numenor-labs/dsfx/pkg/crypto/identity" "koti.casa/numenor-labs/dsfx/internal/lib/crypto/identity"
) )
func main() { func main() {

View File

@ -1,7 +0,0 @@
goos: linux
goarch: amd64
pkg: koti.casa/numenor-labs/dsfx/pkg/handshake
cpu: Intel(R) Core(TM) Ultra 9 185H
BenchmarkHandshake 4214 274337 ns/op 12976 B/op 131 allocs/op
PASS
ok koti.casa/numenor-labs/dsfx/pkg/handshake 1.163s

View File

@ -1,41 +0,0 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 1
warningCode = 1
[rule.bare-return]
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.empty-block]
[rule.empty-lines]
[rule.enforce-map-style]
[rule.enforce-slice-style]
[rule.error-naming]
[rule.error-return]
[rule.error-strings]
[rule.errorf]
[rule.exported]
[rule.filename-format]
# Override the default pattern to forbid .go files with uppercase letters and dashes.
arguments=["^[_a-z][_a-z0-9]*\\.go$"]
[rule.increment-decrement]
[rule.indent-error-flow]
[rule.line-length-limit]
arguments = [200]
# [rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.redefines-builtin-id]
[rule.superfluous-else]
[rule.time-naming]
[rule.unexported-naming]
[rule.unexported-return]
[rule.unreachable-code]
[rule.unused-parameter]
[rule.useless-break]
[rule.use-any]
[rule.var-declaration]
[rule.var-naming]