Skip to content

Commit 4b7ac4c

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 cf31822 commit 4b7ac4c

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
@@ -168,15 +168,15 @@ var configDiscoverCmd = &cobra.Command{
168168
fmt.Printf("Discovering languages and tools for path: %s\n", discoverPath)
169169

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

176176
defaultToolLangMap := tools.GetDefaultToolLanguageMapping()
177177

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

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

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

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

341270
if isRelevantTool {
342-
relevantExtsForThisTool := getSortedKeys(relevantExtsForThisToolMap)
271+
relevantExtsForThisTool := config.GetSortedKeys(relevantExtsForThisToolMap)
343272
sort.Strings(relevantLangsForThisTool)
344273

345274
if existingEntry, ok := existingToolsMap[toolName]; ok {
@@ -351,7 +280,7 @@ func updateLanguagesConfig(detectedLanguages map[string]struct{}, toolsConfigDir
351280
for _, lang := range relevantLangsForThisTool {
352281
existingLangsSet[lang] = struct{}{}
353282
}
354-
existingEntry.Languages = getSortedKeys(existingLangsSet)
283+
existingEntry.Languages = config.GetSortedKeys(existingLangsSet)
355284

356285
existingExtsSet := make(map[string]struct{})
357286
for _, ext := range existingEntry.Extensions {
@@ -360,7 +289,7 @@ func updateLanguagesConfig(detectedLanguages map[string]struct{}, toolsConfigDir
360289
for _, ext := range relevantExtsForThisTool {
361290
existingExtsSet[ext] = struct{}{}
362291
}
363-
existingEntry.Extensions = getSortedKeys(existingExtsSet)
292+
existingEntry.Extensions = config.GetSortedKeys(existingExtsSet)
364293

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

474393
filteredCandidates := make(map[string]struct{})
@@ -543,10 +462,6 @@ func updateCodacyYAML(detectedLanguages map[string]struct{}, codacyYAMLPath stri
543462
}
544463

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

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