forked from sneak/secret
Add blank lines before return statements in all files to satisfy the nlreturn linter. This improves code readability by providing visual separation before return statements. Changes made across 24 files: - internal/cli/*.go - internal/secret/*.go - internal/vault/*.go - pkg/agehd/agehd.go - pkg/bip85/bip85.go All 143 nlreturn issues have been resolved.
99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"git.eeqj.de/sneak/secret/internal/secret"
|
|
"github.com/spf13/afero"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
// Global scanner for consistent stdin reading
|
|
var stdinScanner *bufio.Scanner //nolint:gochecknoglobals // Needed for consistent stdin handling
|
|
|
|
// Instance encapsulates all CLI functionality and state
|
|
type Instance struct {
|
|
fs afero.Fs
|
|
stateDir string
|
|
cmd *cobra.Command
|
|
}
|
|
|
|
// NewCLIInstance creates a new CLI instance with the real filesystem
|
|
func NewCLIInstance() *Instance {
|
|
fs := afero.NewOsFs()
|
|
stateDir := secret.DetermineStateDir("")
|
|
|
|
return &Instance{
|
|
fs: fs,
|
|
stateDir: stateDir,
|
|
}
|
|
}
|
|
|
|
// NewCLIInstanceWithFs creates a new CLI instance with the given filesystem (for testing)
|
|
func NewCLIInstanceWithFs(fs afero.Fs) *Instance {
|
|
stateDir := secret.DetermineStateDir("")
|
|
|
|
return &Instance{
|
|
fs: fs,
|
|
stateDir: stateDir,
|
|
}
|
|
}
|
|
|
|
// NewCLIInstanceWithStateDir creates a new CLI instance with custom state directory (for testing)
|
|
func NewCLIInstanceWithStateDir(fs afero.Fs, stateDir string) *Instance {
|
|
return &Instance{
|
|
fs: fs,
|
|
stateDir: stateDir,
|
|
}
|
|
}
|
|
|
|
// SetFilesystem sets the filesystem for this CLI instance (for testing)
|
|
func (cli *Instance) SetFilesystem(fs afero.Fs) {
|
|
cli.fs = fs
|
|
}
|
|
|
|
// SetStateDir sets the state directory for this CLI instance (for testing)
|
|
func (cli *Instance) SetStateDir(stateDir string) {
|
|
cli.stateDir = stateDir
|
|
}
|
|
|
|
// GetStateDir returns the state directory for this CLI instance
|
|
func (cli *Instance) GetStateDir() string {
|
|
return cli.stateDir
|
|
}
|
|
|
|
// getStdinScanner returns a shared scanner for stdin to avoid buffering issues
|
|
func getStdinScanner() *bufio.Scanner {
|
|
if stdinScanner == nil {
|
|
stdinScanner = bufio.NewScanner(os.Stdin)
|
|
}
|
|
|
|
return stdinScanner
|
|
}
|
|
|
|
// readLineFromStdin reads a single line from stdin with a prompt
|
|
// Uses a shared scanner to avoid buffering issues between multiple calls
|
|
func readLineFromStdin(prompt string) (string, error) {
|
|
// Check if stderr is a terminal - if not, we can't prompt interactively
|
|
if !term.IsTerminal(syscall.Stderr) {
|
|
return "", fmt.Errorf("cannot prompt for input: stderr is not a terminal (running in non-interactive mode)")
|
|
}
|
|
|
|
fmt.Fprint(os.Stderr, prompt) // Write prompt to stderr, not stdout
|
|
scanner := getStdinScanner()
|
|
if !scanner.Scan() {
|
|
if err := scanner.Err(); err != nil {
|
|
return "", fmt.Errorf("failed to read from stdin: %w", err)
|
|
}
|
|
|
|
return "", fmt.Errorf("failed to read from stdin: EOF")
|
|
}
|
|
|
|
return strings.TrimSpace(scanner.Text()), nil
|
|
}
|