-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscan.go
More file actions
155 lines (137 loc) · 3.96 KB
/
scan.go
File metadata and controls
155 lines (137 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
"os/user"
"strings"
)
// getDotFilePath defines a fixed location to store repo data (~/.gogitlocalstats)
func getDotFilePath() string {
usr, err := user.Current()
if err != nil {
log.Fatal(err)
}
dotFile := usr.HomeDir + "/.gogitlocalstats"
return dotFile
}
// openFile opens the file located at filepath. Creates it if it does not exist.
func openFile(filePath string) *os.File {
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_RDWR, 0644)
if err != nil {
if os.IsNotExist(err) {
// File does not exist → create it
f, err = os.Create(filePath)
if err != nil {
panic(err)
}
} else {
// Other error
panic(err)
}
}
return f
}
// parseFileLinesToSlice reads a file line by line and stores each line in a slice of strings
func parseFileLinesToSlice(filePath string) []string {
f := openFile(filePath)
defer f.Close()
var lines []string
scanner := bufio.NewScanner(f)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
if err != io.EOF {
panic(err)
}
}
return lines
}
// sliceContains returns true if slice contains value
func sliceContains(slice []string, value string) bool {
for _, v := range slice {
if v == value {
return true
}
}
return false
}
// joinSlices adds elements from the 'new' slice into 'existing', avoiding duplicates
func joinSlices(new []string, existing []string) []string {
for _, i := range new {
if !sliceContains(existing, i) {
existing = append(existing, i)
}
}
return existing
}
// dumpStringsSliceToFile writes the content of a string slice to a file (overwriting existing content)
func dumpStringsSliceToFile(repos []string, filePath string) {
content := strings.Join(repos, "\n")
err := os.WriteFile(filePath, []byte(content), 0644)
if err != nil {
log.Fatal(err)
}
}
// addNewSliceElementsToFile merges new repo paths with the ones already stored in file,
// removes duplicates, and saves the updated list back to the file.
func addNewSliceElementsToFile(filePath string, newRepos []string) {
existingRepos := parseFileLinesToSlice(filePath) // File → Slice
repos := joinSlices(newRepos, existingRepos) // Merge without duplicates
dumpStringsSliceToFile(repos, filePath) // Slice → File
}
// recursiveScanFolder starts a recursive search for Git repositories in the folder subtree
func recursiveScanFolder(folder string) []string {
return scanGitFolders(make([]string, 0), folder)
}
// scan scans a folder for Git repositories and writes results to the dotfile
func scan(folder string) {
fmt.Printf("Found folders:\n\n")
repositories := recursiveScanFolder(folder) // Get slice of repo paths
filePath := getDotFilePath() // Path of dotfile
addNewSliceElementsToFile(filePath, repositories)
fmt.Printf("\n\nSuccessfully added\n\n")
}
// scanGitFolders recursively searches a folder for Git repositories (.git folders)
// Returns a slice of repo root paths, skipping vendor and node_modules directories
func scanGitFolders(folders []string, folder string) []string {
// Remove trailing slash
folder = strings.TrimSuffix(folder, "/")
f, err := os.Open(folder)
if err != nil {
log.Fatal(err)
}
files, err := f.Readdir(-1) // Read all directory entries (files + subdirectories)
f.Close()
if err != nil {
log.Fatal(err)
}
for _, file := range files {
if file.IsDir() {
path := folder + "/" + file.Name()
if file.Name() == ".git" {
// Found a git repo → store its parent folder
repoPath := strings.TrimSuffix(path, "/.git")
fmt.Println(repoPath)
folders = append(folders, repoPath)
continue
}
if file.Name() == "vendor" || file.Name() == "node_modules" {
continue // Skip dependencies folders
}
// Recurse into subfolder
folders = scanGitFolders(folders, path)
}
}
return folders
}
/*
// main function for testing
func main() {
// Example: scan your home directory (or any folder you want)
scan(os.Getenv("HOME"))
}
*/