Skip to content

Commit 77a77b6

Browse files
refactor: move file detection logic to config package
- Centralized file extension detection and language recognition into the new config/detector.go file. - Updated the config command to utilize the new methods for detecting file extensions and languages. - Removed redundant functions from cmd/config.go to improve clarity and maintainability.
1 parent 2c7f907 commit 77a77b6

File tree

2 files changed

+153
-156
lines changed

2 files changed

+153
-156
lines changed

cmd/config.go

Lines changed: 7 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,15 @@ var configDiscoverCmd = &cobra.Command{
169169
fmt.Printf("Discovering languages and tools for path: %s\n", discoverPath)
170170

171171
// Detect file extensions first
172-
extCount, err := detectFileExtensions(discoverPath)
172+
extCount, err := config.DetectFileExtensions(discoverPath)
173173
if err != nil {
174174
log.Fatalf("Error detecting file extensions: %v", err)
175175
}
176176

177177
defaultToolLangMap := tools.GetDefaultToolLanguageMapping()
178178

179179
if len(extCount) > 0 {
180-
recognizedExts := getRecognizableExtensions(extCount, defaultToolLangMap)
180+
recognizedExts := config.GetRecognizableExtensions(extCount, defaultToolLangMap)
181181
if len(recognizedExts) > 0 {
182182
logger.Debug("Detected recognizable file extensions", logrus.Fields{
183183
"extensions": recognizedExts,
@@ -186,18 +186,14 @@ var configDiscoverCmd = &cobra.Command{
186186
}
187187
}
188188

189-
detectedLanguages, err := detectLanguagesInPath(discoverPath, defaultToolLangMap)
189+
detectedLanguages, err := config.DetectLanguages(discoverPath, defaultToolLangMap)
190190
if err != nil {
191191
log.Fatalf("Error detecting languages: %v", err)
192192
}
193193
if len(detectedLanguages) == 0 {
194194
fmt.Println("No known languages detected in the provided path.")
195195
return
196196
}
197-
logger.Debug("Detected languages in path", logrus.Fields{
198-
"languages": getSortedKeys(detectedLanguages),
199-
"path": discoverPath,
200-
})
201197

202198
toolsConfigDir := config.Config.ToolsConfigsDirectory()
203199
if err := updateLanguagesConfig(detectedLanguages, toolsConfigDir, defaultToolLangMap); err != nil {
@@ -227,73 +223,6 @@ var configDiscoverCmd = &cobra.Command{
227223
},
228224
}
229225

230-
func getSortedKeys(m map[string]struct{}) []string {
231-
keys := make([]string, 0, len(m))
232-
for k := range m {
233-
keys = append(keys, k)
234-
}
235-
sort.Strings(keys)
236-
return keys
237-
}
238-
239-
// detectLanguagesInPath detects languages based on file extensions found in the path.
240-
func detectLanguagesInPath(rootPath string, toolLangMap map[string]domain.ToolLanguageInfo) (map[string]struct{}, error) {
241-
detectedLangs := make(map[string]struct{})
242-
extToLang := make(map[string][]string)
243-
244-
// Build extension to language mapping
245-
for _, toolInfo := range toolLangMap {
246-
for _, lang := range toolInfo.Languages {
247-
if lang == "Multiple" || lang == "Generic" { // Skip generic language types for direct detection
248-
continue
249-
}
250-
for _, ext := range toolInfo.Extensions {
251-
extToLang[ext] = append(extToLang[ext], lang)
252-
}
253-
}
254-
}
255-
256-
// Get file extensions from the path
257-
extCount, err := detectFileExtensions(rootPath)
258-
if err != nil {
259-
return nil, fmt.Errorf("failed to detect file extensions in path %s: %w", rootPath, err)
260-
}
261-
262-
// Map only found extensions to languages
263-
for ext := range extCount {
264-
if langs, ok := extToLang[ext]; ok {
265-
// Log which extensions map to which languages for debugging
266-
logger.Debug("Found files with extension", logrus.Fields{
267-
"extension": ext,
268-
"count": extCount[ext],
269-
"languages": langs,
270-
})
271-
for _, lang := range langs {
272-
detectedLangs[lang] = struct{}{}
273-
}
274-
}
275-
}
276-
277-
// Log the final set of detected languages with their corresponding extensions
278-
if len(detectedLangs) > 0 {
279-
langToExts := make(map[string][]string)
280-
for ext, count := range extCount {
281-
if langs, ok := extToLang[ext]; ok {
282-
for _, lang := range langs {
283-
langToExts[lang] = append(langToExts[lang], fmt.Sprintf("%s (%d files)", ext, count))
284-
}
285-
}
286-
}
287-
288-
logger.Debug("Detected languages in path", logrus.Fields{
289-
"languages_with_files": langToExts,
290-
"path": discoverPath,
291-
})
292-
}
293-
294-
return detectedLangs, nil
295-
}
296-
297226
// updateLanguagesConfig updates the .codacy/tools-configs/languages-config.yaml file.
298227
func updateLanguagesConfig(detectedLanguages map[string]struct{}, toolsConfigDir string, defaultToolLangMap map[string]domain.ToolLanguageInfo) error {
299228
langConfigPath := filepath.Join(toolsConfigDir, "languages-config.yaml")
@@ -340,7 +269,7 @@ func updateLanguagesConfig(detectedLanguages map[string]struct{}, toolsConfigDir
340269
}
341270

342271
if isRelevantTool {
343-
relevantExtsForThisTool := getSortedKeys(relevantExtsForThisToolMap)
272+
relevantExtsForThisTool := config.GetSortedKeys(relevantExtsForThisToolMap)
344273
sort.Strings(relevantLangsForThisTool)
345274

346275
if existingEntry, ok := existingToolsMap[toolName]; ok {
@@ -352,7 +281,7 @@ func updateLanguagesConfig(detectedLanguages map[string]struct{}, toolsConfigDir
352281
for _, lang := range relevantLangsForThisTool {
353282
existingLangsSet[lang] = struct{}{}
354283
}
355-
existingEntry.Languages = getSortedKeys(existingLangsSet)
284+
existingEntry.Languages = config.GetSortedKeys(existingLangsSet)
356285

357286
existingExtsSet := make(map[string]struct{})
358287
for _, ext := range existingEntry.Extensions {
@@ -361,7 +290,7 @@ func updateLanguagesConfig(detectedLanguages map[string]struct{}, toolsConfigDir
361290
for _, ext := range relevantExtsForThisTool {
362291
existingExtsSet[ext] = struct{}{}
363292
}
364-
existingEntry.Extensions = getSortedKeys(existingExtsSet)
293+
existingEntry.Extensions = config.GetSortedKeys(existingExtsSet)
365294

366295
} else {
367296
newEntry := domain.ToolLanguageInfo{
@@ -449,18 +378,9 @@ func updateCodacyYAML(detectedLanguages map[string]struct{}, codacyYAMLPath stri
449378
}
450379
cloudEnabledToolNames := make(map[string]bool)
451380
for _, ct := range cloudTools {
452-
// Assuming ct.Name or similar field exists that matches our short tool names.
453-
// The domain.Tool from GetRepositoryTools usually has a UUID, we need to map it.
454-
// For now, we'll use a helper or assume names match if direct mapping isn't straightforward.
455-
// This might need adjustment based on how GetRepositoryTools returns tool identifiers.
456-
// Let's assume tool.Name from domain.Tool is the short name (e.g., "eslint").
457-
// This requires checking the actual structure returned by GetRepositoryTools.
458-
// For now, we'll use a placeholder map from UUID to short name, or simply compare by name.
459-
// domain.SupportedToolsMetadata maps UUID to name.
460-
461381
var toolShortName string
462382
for uuid, meta := range domain.SupportedToolsMetadata {
463-
if uuid == ct.Uuid { // ct.Uuid is the correct field from domain.Tool
383+
if uuid == ct.Uuid {
464384
toolShortName = meta.Name
465385
break
466386
}
@@ -469,7 +389,6 @@ func updateCodacyYAML(detectedLanguages map[string]struct{}, codacyYAMLPath stri
469389
if toolShortName != "" && ct.Settings.Enabled {
470390
cloudEnabledToolNames[toolShortName] = true
471391
}
472-
473392
}
474393

475394
filteredCandidates := make(map[string]struct{})
@@ -544,10 +463,6 @@ func updateCodacyYAML(detectedLanguages map[string]struct{}, codacyYAMLPath stri
544463
}
545464

546465
// Preserve existing runtimes and their versions if possible, only add new ones.
547-
// Or, simpler: recalculate all needed runtimes based on finalToolsList.
548-
// The current configsetup.ConfigFileTemplate recalculates runtimes.
549-
// For discover, we should be less destructive.
550-
// Let's try to merge:
551466
existingRuntimesRaw, _ := configData["runtimes"].([]interface{})
552467
finalRuntimesList := []string{}
553468
existingRuntimeSet := make(map[string]string) // name -> name@version
@@ -582,70 +497,6 @@ func updateCodacyYAML(detectedLanguages map[string]struct{}, codacyYAMLPath stri
582497
return os.WriteFile(codacyYAMLPath, yamlData, utils.DefaultFilePerms)
583498
}
584499

585-
// detectFileExtensions walks the directory and collects all unique file extensions with their counts
586-
func detectFileExtensions(rootPath string) (map[string]int, error) {
587-
extCount := make(map[string]int)
588-
589-
err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
590-
if err != nil {
591-
return err
592-
}
593-
if !info.IsDir() {
594-
ext := strings.ToLower(filepath.Ext(path))
595-
if ext != "" {
596-
extCount[ext]++
597-
}
598-
}
599-
return nil
600-
})
601-
602-
if err != nil {
603-
return nil, fmt.Errorf("failed to walk path %s: %w", rootPath, err)
604-
}
605-
606-
return extCount, nil
607-
}
608-
609-
// getRecognizableExtensions returns a sorted list of extensions that are mapped to languages
610-
func getRecognizableExtensions(extCount map[string]int, toolLangMap map[string]domain.ToolLanguageInfo) []string {
611-
// Build set of recognized extensions
612-
recognizedExts := make(map[string]struct{})
613-
for _, toolInfo := range toolLangMap {
614-
for _, ext := range toolInfo.Extensions {
615-
recognizedExts[ext] = struct{}{}
616-
}
617-
}
618-
619-
// Filter and format recognized extensions with counts
620-
type extInfo struct {
621-
ext string
622-
count int
623-
}
624-
var recognizedExtList []extInfo
625-
626-
for ext, count := range extCount {
627-
if _, ok := recognizedExts[ext]; ok {
628-
recognizedExtList = append(recognizedExtList, extInfo{ext, count})
629-
}
630-
}
631-
632-
// Sort by count (descending) and then by extension name
633-
sort.Slice(recognizedExtList, func(i, j int) bool {
634-
if recognizedExtList[i].count != recognizedExtList[j].count {
635-
return recognizedExtList[i].count > recognizedExtList[j].count
636-
}
637-
return recognizedExtList[i].ext < recognizedExtList[j].ext
638-
})
639-
640-
// Format extensions with their counts
641-
result := make([]string, len(recognizedExtList))
642-
for i, info := range recognizedExtList {
643-
result[i] = fmt.Sprintf("%s (%d files)", info.ext, info.count)
644-
}
645-
646-
return result
647-
}
648-
649500
func init() {
650501
// Add cloud-related flags to both commands
651502
cmdutils.AddCloudFlags(configResetCmd, &configResetInitFlags)

config/detector.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"sort"
8+
"strings"
9+
10+
"codacy/cli-v2/domain"
11+
"codacy/cli-v2/utils/logger"
12+
13+
"github.com/sirupsen/logrus"
14+
)
15+
16+
// DetectFileExtensions walks the directory and collects all unique file extensions with their counts
17+
func DetectFileExtensions(rootPath string) (map[string]int, error) {
18+
extCount := make(map[string]int)
19+
20+
err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
21+
if err != nil {
22+
return err
23+
}
24+
if !info.IsDir() {
25+
ext := strings.ToLower(filepath.Ext(path))
26+
if ext != "" {
27+
extCount[ext]++
28+
}
29+
}
30+
return nil
31+
})
32+
33+
if err != nil {
34+
return nil, fmt.Errorf("failed to walk path %s: %w", rootPath, err)
35+
}
36+
37+
return extCount, nil
38+
}
39+
40+
// GetRecognizableExtensions returns a sorted list of extensions that are mapped to languages
41+
func GetRecognizableExtensions(extCount map[string]int, toolLangMap map[string]domain.ToolLanguageInfo) []string {
42+
// Build set of recognized extensions
43+
recognizedExts := make(map[string]struct{})
44+
for _, toolInfo := range toolLangMap {
45+
for _, ext := range toolInfo.Extensions {
46+
recognizedExts[ext] = struct{}{}
47+
}
48+
}
49+
50+
// Filter and format recognized extensions with counts
51+
type extInfo struct {
52+
ext string
53+
count int
54+
}
55+
var recognizedExtList []extInfo
56+
57+
for ext, count := range extCount {
58+
if _, ok := recognizedExts[ext]; ok {
59+
recognizedExtList = append(recognizedExtList, extInfo{ext, count})
60+
}
61+
}
62+
63+
// Sort by count (descending) and then by extension name
64+
sort.Slice(recognizedExtList, func(i, j int) bool {
65+
if recognizedExtList[i].count != recognizedExtList[j].count {
66+
return recognizedExtList[i].count > recognizedExtList[j].count
67+
}
68+
return recognizedExtList[i].ext < recognizedExtList[j].ext
69+
})
70+
71+
// Format extensions with their counts
72+
result := make([]string, len(recognizedExtList))
73+
for i, info := range recognizedExtList {
74+
result[i] = fmt.Sprintf("%s (%d files)", info.ext, info.count)
75+
}
76+
77+
return result
78+
}
79+
80+
// DetectLanguages detects languages based on file extensions found in the path
81+
func DetectLanguages(rootPath string, toolLangMap map[string]domain.ToolLanguageInfo) (map[string]struct{}, error) {
82+
detectedLangs := make(map[string]struct{})
83+
extToLang := make(map[string][]string)
84+
85+
// Build extension to language mapping
86+
for _, toolInfo := range toolLangMap {
87+
for _, lang := range toolInfo.Languages {
88+
if lang == "Multiple" || lang == "Generic" { // Skip generic language types for direct detection
89+
continue
90+
}
91+
for _, ext := range toolInfo.Extensions {
92+
extToLang[ext] = append(extToLang[ext], lang)
93+
}
94+
}
95+
}
96+
97+
// Get file extensions from the path
98+
extCount, err := DetectFileExtensions(rootPath)
99+
if err != nil {
100+
return nil, fmt.Errorf("failed to detect file extensions in path %s: %w", rootPath, err)
101+
}
102+
103+
// Map only found extensions to languages
104+
for ext := range extCount {
105+
if langs, ok := extToLang[ext]; ok {
106+
// Log which extensions map to which languages for debugging
107+
logger.Debug("Found files with extension", logrus.Fields{
108+
"extension": ext,
109+
"count": extCount[ext],
110+
"languages": langs,
111+
})
112+
for _, lang := range langs {
113+
detectedLangs[lang] = struct{}{}
114+
}
115+
}
116+
}
117+
118+
// Log the final set of detected languages with their corresponding extensions
119+
if len(detectedLangs) > 0 {
120+
langToExts := make(map[string][]string)
121+
for ext, count := range extCount {
122+
if langs, ok := extToLang[ext]; ok {
123+
for _, lang := range langs {
124+
langToExts[lang] = append(langToExts[lang], fmt.Sprintf("%s (%d files)", ext, count))
125+
}
126+
}
127+
}
128+
129+
logger.Debug("Detected languages in path", logrus.Fields{
130+
"languages_with_files": langToExts,
131+
"path": rootPath,
132+
})
133+
}
134+
135+
return detectedLangs, nil
136+
}
137+
138+
// GetSortedKeys returns a sorted slice of strings from a string set
139+
func GetSortedKeys(m map[string]struct{}) []string {
140+
keys := make([]string, 0, len(m))
141+
for k := range m {
142+
keys = append(keys, k)
143+
}
144+
sort.Strings(keys)
145+
return keys
146+
}

0 commit comments

Comments
 (0)