Files
gibidify/config/getters.go
Ismo Vuorinen 95b7ef6dd3 chore: modernize workflows, security scanning, and linting configuration (#50)
* build: update Go 1.25, CI workflows, and build tooling

- Upgrade to Go 1.25
- Add benchmark targets to Makefile
- Implement parallel gosec execution
- Lock tool versions for reproducibility
- Add shellcheck directives to scripts
- Update CI workflows with improved caching

* refactor: migrate from golangci-lint to revive

- Replace golangci-lint with revive for linting
- Configure comprehensive revive rules
- Fix all EditorConfig violations
- Add yamllint and yamlfmt support
- Remove deprecated .golangci.yml

* refactor: rename utils to shared and deduplicate code

- Rename utils package to shared
- Add shared constants package
- Deduplicate constants across packages
- Address CodeRabbit review feedback

* fix: resolve SonarQube issues and add safety guards

- Fix all 73 SonarQube OPEN issues
- Add nil guards for resourceMonitor, backpressure, metricsCollector
- Implement io.Closer for headerFileReader
- Propagate errors from processing helpers
- Add metrics and templates packages
- Improve error handling across codebase

* test: improve test infrastructure and coverage

- Add benchmarks for cli, fileproc, metrics
- Improve test coverage for cli, fileproc, config
- Refactor tests with helper functions
- Add shared test constants
- Fix test function naming conventions
- Reduce cognitive complexity in benchmark tests

* docs: update documentation and configuration examples

- Update CLAUDE.md with current project state
- Refresh README with new features
- Add usage and configuration examples
- Add SonarQube project configuration
- Consolidate config.example.yaml

* fix: resolve shellcheck warnings in scripts

- Use ./*.go instead of *.go to prevent dash-prefixed filenames
  from being interpreted as options (SC2035)
- Remove unreachable return statement after exit (SC2317)
- Remove obsolete gibidiutils/ directory reference

* chore(deps): upgrade go dependencies

* chore(lint): megalinter fixes

* fix: improve test coverage and fix file descriptor leaks

- Add defer r.Close() to fix pipe file descriptor leaks in benchmark tests
- Refactor TestProcessorConfigureFileTypes with helper functions and assertions
- Refactor TestProcessorLogFinalStats with output capture and keyword verification
- Use shared constants instead of literal strings (TestFilePNG, FormatMarkdown, etc.)
- Reduce cognitive complexity by extracting helper functions

* fix: align test comments with function names

Remove underscores from test comments to match actual function names:
- benchmark/benchmark_test.go (2 fixes)
- fileproc/filetypes_config_test.go (4 fixes)
- fileproc/filetypes_registry_test.go (6 fixes)
- fileproc/processor_test.go (6 fixes)
- fileproc/resource_monitor_types_test.go (4 fixes)
- fileproc/writer_test.go (3 fixes)

* fix: various test improvements and bug fixes

- Remove duplicate maxCacheSize check in filetypes_registry_test.go
- Shorten long comment in processor_test.go to stay under 120 chars
- Remove flaky time.Sleep in collector_test.go, use >= 0 assertion
- Close pipe reader in benchmark_test.go to fix file descriptor leak
- Use ContinueOnError in flags_test.go to match ResetFlags behavior
- Add nil check for p.ui in processor_workers.go before UpdateProgress
- Fix resource_monitor_validation_test.go by setting hardMemoryLimitBytes directly

* chore(yaml): add missing document start markers

Add --- document start to YAML files to satisfy yamllint:
- .github/workflows/codeql.yml
- .github/workflows/build-test-publish.yml
- .github/workflows/security.yml
- .github/actions/setup/action.yml

* fix: guard nil resourceMonitor and fix test deadlock

- Guard resourceMonitor before CreateFileProcessingContext call
- Add ui.UpdateProgress on emergency stop and path error returns
- Fix potential deadlock in TestProcessFile using wg.Go with defer close
2025-12-10 19:07:11 +02:00

332 lines
11 KiB
Go

// Package config handles application configuration management.
package config
import (
"strings"
"github.com/spf13/viper"
"github.com/ivuorinen/gibidify/shared"
)
// FileSizeLimit returns the file size limit from configuration.
// Default: ConfigFileSizeLimitDefault (5MB).
func FileSizeLimit() int64 {
return viper.GetInt64(shared.ConfigKeyFileSizeLimit)
}
// IgnoredDirectories returns the list of directories to ignore.
// Default: ConfigIgnoredDirectoriesDefault.
func IgnoredDirectories() []string {
return viper.GetStringSlice(shared.ConfigKeyIgnoreDirectories)
}
// MaxConcurrency returns the maximum concurrency level.
// Returns 0 if not set (caller should determine appropriate default).
func MaxConcurrency() int {
return viper.GetInt(shared.ConfigKeyMaxConcurrency)
}
// SupportedFormats returns the list of supported output formats.
// Returns empty slice if not set.
func SupportedFormats() []string {
return viper.GetStringSlice(shared.ConfigKeySupportedFormats)
}
// FilePatterns returns the list of file patterns.
// Returns empty slice if not set.
func FilePatterns() []string {
return viper.GetStringSlice(shared.ConfigKeyFilePatterns)
}
// IsValidFormat checks if the given format is valid.
func IsValidFormat(format string) bool {
format = strings.ToLower(strings.TrimSpace(format))
supportedFormats := map[string]bool{
shared.FormatJSON: true,
shared.FormatYAML: true,
shared.FormatMarkdown: true,
}
return supportedFormats[format]
}
// FileTypesEnabled returns whether file types are enabled.
// Default: ConfigFileTypesEnabledDefault (true).
func FileTypesEnabled() bool {
return viper.GetBool(shared.ConfigKeyFileTypesEnabled)
}
// CustomImageExtensions returns custom image extensions.
// Default: ConfigCustomImageExtensionsDefault (empty).
func CustomImageExtensions() []string {
return viper.GetStringSlice(shared.ConfigKeyFileTypesCustomImageExtensions)
}
// CustomBinaryExtensions returns custom binary extensions.
// Default: ConfigCustomBinaryExtensionsDefault (empty).
func CustomBinaryExtensions() []string {
return viper.GetStringSlice(shared.ConfigKeyFileTypesCustomBinaryExtensions)
}
// CustomLanguages returns custom language mappings.
// Default: ConfigCustomLanguagesDefault (empty).
func CustomLanguages() map[string]string {
return viper.GetStringMapString(shared.ConfigKeyFileTypesCustomLanguages)
}
// DisabledImageExtensions returns disabled image extensions.
// Default: ConfigDisabledImageExtensionsDefault (empty).
func DisabledImageExtensions() []string {
return viper.GetStringSlice(shared.ConfigKeyFileTypesDisabledImageExtensions)
}
// DisabledBinaryExtensions returns disabled binary extensions.
// Default: ConfigDisabledBinaryExtensionsDefault (empty).
func DisabledBinaryExtensions() []string {
return viper.GetStringSlice(shared.ConfigKeyFileTypesDisabledBinaryExtensions)
}
// DisabledLanguageExtensions returns disabled language extensions.
// Default: ConfigDisabledLanguageExtensionsDefault (empty).
func DisabledLanguageExtensions() []string {
return viper.GetStringSlice(shared.ConfigKeyFileTypesDisabledLanguageExts)
}
// Backpressure getters
// BackpressureEnabled returns whether backpressure is enabled.
// Default: ConfigBackpressureEnabledDefault (true).
func BackpressureEnabled() bool {
return viper.GetBool(shared.ConfigKeyBackpressureEnabled)
}
// MaxPendingFiles returns the maximum pending files.
// Default: ConfigMaxPendingFilesDefault (1000).
func MaxPendingFiles() int {
return viper.GetInt(shared.ConfigKeyBackpressureMaxPendingFiles)
}
// MaxPendingWrites returns the maximum pending writes.
// Default: ConfigMaxPendingWritesDefault (100).
func MaxPendingWrites() int {
return viper.GetInt(shared.ConfigKeyBackpressureMaxPendingWrites)
}
// MaxMemoryUsage returns the maximum memory usage.
// Default: ConfigMaxMemoryUsageDefault (100MB).
func MaxMemoryUsage() int64 {
return viper.GetInt64(shared.ConfigKeyBackpressureMaxMemoryUsage)
}
// MemoryCheckInterval returns the memory check interval.
// Default: ConfigMemoryCheckIntervalDefault (1000 files).
func MemoryCheckInterval() int {
return viper.GetInt(shared.ConfigKeyBackpressureMemoryCheckInt)
}
// Resource limits getters
// ResourceLimitsEnabled returns whether resource limits are enabled.
// Default: ConfigResourceLimitsEnabledDefault (true).
func ResourceLimitsEnabled() bool {
return viper.GetBool(shared.ConfigKeyResourceLimitsEnabled)
}
// MaxFiles returns the maximum number of files.
// Default: ConfigMaxFilesDefault (10000).
func MaxFiles() int {
return viper.GetInt(shared.ConfigKeyResourceLimitsMaxFiles)
}
// MaxTotalSize returns the maximum total size.
// Default: ConfigMaxTotalSizeDefault (1GB).
func MaxTotalSize() int64 {
return viper.GetInt64(shared.ConfigKeyResourceLimitsMaxTotalSize)
}
// FileProcessingTimeoutSec returns the file processing timeout in seconds.
// Default: ConfigFileProcessingTimeoutSecDefault (30 seconds).
func FileProcessingTimeoutSec() int {
return viper.GetInt(shared.ConfigKeyResourceLimitsFileProcessingTO)
}
// OverallTimeoutSec returns the overall timeout in seconds.
// Default: ConfigOverallTimeoutSecDefault (3600 seconds).
func OverallTimeoutSec() int {
return viper.GetInt(shared.ConfigKeyResourceLimitsOverallTO)
}
// MaxConcurrentReads returns the maximum concurrent reads.
// Default: ConfigMaxConcurrentReadsDefault (10).
func MaxConcurrentReads() int {
return viper.GetInt(shared.ConfigKeyResourceLimitsMaxConcurrentReads)
}
// RateLimitFilesPerSec returns the rate limit files per second.
// Default: ConfigRateLimitFilesPerSecDefault (0 = disabled).
func RateLimitFilesPerSec() int {
return viper.GetInt(shared.ConfigKeyResourceLimitsRateLimitFilesPerSec)
}
// HardMemoryLimitMB returns the hard memory limit in MB.
// Default: ConfigHardMemoryLimitMBDefault (512MB).
func HardMemoryLimitMB() int {
return viper.GetInt(shared.ConfigKeyResourceLimitsHardMemoryLimitMB)
}
// EnableGracefulDegradation returns whether graceful degradation is enabled.
// Default: ConfigEnableGracefulDegradationDefault (true).
func EnableGracefulDegradation() bool {
return viper.GetBool(shared.ConfigKeyResourceLimitsEnableGracefulDeg)
}
// EnableResourceMonitoring returns whether resource monitoring is enabled.
// Default: ConfigEnableResourceMonitoringDefault (true).
func EnableResourceMonitoring() bool {
return viper.GetBool(shared.ConfigKeyResourceLimitsEnableMonitoring)
}
// Template system getters
// OutputTemplate returns the selected output template name.
// Default: ConfigOutputTemplateDefault (empty string).
func OutputTemplate() string {
return viper.GetString(shared.ConfigKeyOutputTemplate)
}
// metadataBool is a helper for metadata boolean configuration values.
// All metadata flags default to false.
func metadataBool(key string) bool {
return viper.GetBool("output.metadata." + key)
}
// TemplateMetadataIncludeStats returns whether to include stats in metadata.
func TemplateMetadataIncludeStats() bool {
return metadataBool("includeStats")
}
// TemplateMetadataIncludeTimestamp returns whether to include timestamp in metadata.
func TemplateMetadataIncludeTimestamp() bool {
return metadataBool("includeTimestamp")
}
// TemplateMetadataIncludeFileCount returns whether to include file count in metadata.
func TemplateMetadataIncludeFileCount() bool {
return metadataBool("includeFileCount")
}
// TemplateMetadataIncludeSourcePath returns whether to include source path in metadata.
func TemplateMetadataIncludeSourcePath() bool {
return metadataBool("includeSourcePath")
}
// TemplateMetadataIncludeFileTypes returns whether to include file types in metadata.
func TemplateMetadataIncludeFileTypes() bool {
return metadataBool("includeFileTypes")
}
// TemplateMetadataIncludeProcessingTime returns whether to include processing time in metadata.
func TemplateMetadataIncludeProcessingTime() bool {
return metadataBool("includeProcessingTime")
}
// TemplateMetadataIncludeTotalSize returns whether to include total size in metadata.
func TemplateMetadataIncludeTotalSize() bool {
return metadataBool("includeTotalSize")
}
// TemplateMetadataIncludeMetrics returns whether to include metrics in metadata.
func TemplateMetadataIncludeMetrics() bool {
return metadataBool("includeMetrics")
}
// markdownBool is a helper for markdown boolean configuration values.
// All markdown flags default to false.
func markdownBool(key string) bool {
return viper.GetBool("output.markdown." + key)
}
// TemplateMarkdownUseCodeBlocks returns whether to use code blocks in markdown.
func TemplateMarkdownUseCodeBlocks() bool {
return markdownBool("useCodeBlocks")
}
// TemplateMarkdownIncludeLanguage returns whether to include language in code blocks.
func TemplateMarkdownIncludeLanguage() bool {
return markdownBool("includeLanguage")
}
// TemplateMarkdownHeaderLevel returns the header level for file sections.
// Default: ConfigMarkdownHeaderLevelDefault (0).
func TemplateMarkdownHeaderLevel() int {
return viper.GetInt(shared.ConfigKeyOutputMarkdownHeaderLevel)
}
// TemplateMarkdownTableOfContents returns whether to include table of contents.
func TemplateMarkdownTableOfContents() bool {
return markdownBool("tableOfContents")
}
// TemplateMarkdownUseCollapsible returns whether to use collapsible sections.
func TemplateMarkdownUseCollapsible() bool {
return markdownBool("useCollapsible")
}
// TemplateMarkdownSyntaxHighlighting returns whether to enable syntax highlighting.
func TemplateMarkdownSyntaxHighlighting() bool {
return markdownBool("syntaxHighlighting")
}
// TemplateMarkdownLineNumbers returns whether to include line numbers.
func TemplateMarkdownLineNumbers() bool {
return markdownBool("lineNumbers")
}
// TemplateMarkdownFoldLongFiles returns whether to fold long files.
func TemplateMarkdownFoldLongFiles() bool {
return markdownBool("foldLongFiles")
}
// TemplateMarkdownMaxLineLength returns the maximum line length.
// Default: ConfigMarkdownMaxLineLengthDefault (0 = unlimited).
func TemplateMarkdownMaxLineLength() int {
return viper.GetInt(shared.ConfigKeyOutputMarkdownMaxLineLen)
}
// TemplateCustomCSS returns custom CSS for markdown output.
// Default: ConfigMarkdownCustomCSSDefault (empty string).
func TemplateCustomCSS() string {
return viper.GetString(shared.ConfigKeyOutputMarkdownCustomCSS)
}
// TemplateCustomHeader returns custom header template.
// Default: ConfigCustomHeaderDefault (empty string).
func TemplateCustomHeader() string {
return viper.GetString(shared.ConfigKeyOutputCustomHeader)
}
// TemplateCustomFooter returns custom footer template.
// Default: ConfigCustomFooterDefault (empty string).
func TemplateCustomFooter() string {
return viper.GetString(shared.ConfigKeyOutputCustomFooter)
}
// TemplateCustomFileHeader returns custom file header template.
// Default: ConfigCustomFileHeaderDefault (empty string).
func TemplateCustomFileHeader() string {
return viper.GetString(shared.ConfigKeyOutputCustomFileHeader)
}
// TemplateCustomFileFooter returns custom file footer template.
// Default: ConfigCustomFileFooterDefault (empty string).
func TemplateCustomFileFooter() string {
return viper.GetString(shared.ConfigKeyOutputCustomFileFooter)
}
// TemplateVariables returns custom template variables.
// Default: ConfigTemplateVariablesDefault (empty map).
func TemplateVariables() map[string]string {
return viper.GetStringMapString(shared.ConfigKeyOutputVariables)
}