github.com/zkry/enry@v1.6.3/cli/enry/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "flag" 7 "fmt" 8 "io/ioutil" 9 "log" 10 "os" 11 "path/filepath" 12 "sort" 13 "strings" 14 15 "gopkg.in/src-d/enry.v1" 16 "gopkg.in/src-d/enry.v1/data" 17 ) 18 19 var ( 20 version = "undefined" 21 build = "undefined" 22 commit = "undefined" 23 ) 24 25 func main() { 26 flag.Usage = usage 27 breakdownFlag := flag.Bool("breakdown", false, "") 28 jsonFlag := flag.Bool("json", false, "") 29 showVersion := flag.Bool("version", false, "Show the enry version information") 30 flag.Parse() 31 32 if *showVersion { 33 fmt.Println(version) 34 return 35 } 36 37 root, err := filepath.Abs(flag.Arg(0)) 38 if err != nil { 39 log.Fatal(err) 40 } 41 42 fileInfo, err := os.Stat(root) 43 if err != nil { 44 log.Fatal(err) 45 } 46 47 if fileInfo.Mode().IsRegular() { 48 printFileAnalysis(root) 49 return 50 } 51 52 out := make(map[string][]string, 0) 53 err = filepath.Walk(root, func(path string, f os.FileInfo, err error) error { 54 if err != nil { 55 log.Println(err) 56 return filepath.SkipDir 57 } 58 59 if !f.Mode().IsDir() && !f.Mode().IsRegular() { 60 return nil 61 } 62 63 relativePath, err := filepath.Rel(root, path) 64 if err != nil { 65 log.Println(err) 66 return nil 67 } 68 69 if relativePath == "." { 70 return nil 71 } 72 73 if f.IsDir() { 74 relativePath = relativePath + "/" 75 } 76 77 if enry.IsVendor(relativePath) || enry.IsDotFile(relativePath) || 78 enry.IsDocumentation(relativePath) || enry.IsConfiguration(relativePath) { 79 if f.IsDir() { 80 return filepath.SkipDir 81 } 82 83 return nil 84 } 85 86 if f.IsDir() { 87 return nil 88 } 89 90 language, ok := enry.GetLanguageByExtension(path) 91 if !ok { 92 if language, ok = enry.GetLanguageByFilename(path); !ok { 93 content, err := ioutil.ReadFile(path) 94 if err != nil { 95 log.Println(err) 96 return nil 97 } 98 99 language = enry.GetLanguage(filepath.Base(path), content) 100 if language == enry.OtherLanguage { 101 return nil 102 } 103 } 104 } 105 106 out[language] = append(out[language], relativePath) 107 return nil 108 }) 109 110 if err != nil { 111 log.Fatal(err) 112 } 113 114 var buff bytes.Buffer 115 switch { 116 case *jsonFlag && !*breakdownFlag: 117 printJson(out, &buff) 118 case *jsonFlag && *breakdownFlag: 119 printBreakDown(out, &buff) 120 case *breakdownFlag: 121 printPercents(out, &buff) 122 buff.WriteByte('\n') 123 printBreakDown(out, &buff) 124 default: 125 printPercents(out, &buff) 126 } 127 128 fmt.Print(buff.String()) 129 } 130 131 func usage() { 132 fmt.Fprintf( 133 os.Stderr, 134 ` %[1]s %[2]s build: %[3]s commit: %[4]s, based on linguist commit: %[5]s 135 %[1]s, A simple (and faster) implementation of github/linguist 136 usage: %[1]s <path> 137 %[1]s [-json] [-breakdown] <path> 138 %[1]s [-json] [-breakdown] 139 %[1]s [-version] 140 `, 141 os.Args[0], version, build, commit, data.LinguistCommit[:7], 142 ) 143 } 144 145 func printBreakDown(out map[string][]string, buff *bytes.Buffer) { 146 for name, language := range out { 147 writeStringLn(name, buff) 148 for _, file := range language { 149 writeStringLn(file, buff) 150 } 151 152 writeStringLn("", buff) 153 } 154 } 155 156 func printJson(out map[string][]string, buff *bytes.Buffer) { 157 data, _ := json.Marshal(out) 158 buff.Write(data) 159 buff.WriteByte('\n') 160 } 161 162 func printPercents(out map[string][]string, buff *bytes.Buffer) { 163 var fileCountList enry.FileCountList 164 total := 0 165 for name, language := range out { 166 fc := enry.FileCount{Name: name, Count: len(language)} 167 fileCountList = append(fileCountList, fc) 168 total += len(language) 169 } 170 // Sort the fileCountList in descending order of their count value. 171 sort.Sort(sort.Reverse(fileCountList)) 172 173 for _, fc := range fileCountList { 174 percent := float32(fc.Count) / float32(total) * 100 175 buff.WriteString(fmt.Sprintf("%.2f%% %s\n", percent, fc.Name)) 176 } 177 } 178 179 func printFileAnalysis(file string) { 180 content, err := ioutil.ReadFile(file) 181 if err != nil { 182 fmt.Println(err) 183 } 184 185 totalLines, nonBlank := getLines(file, string(content)) 186 fileType := getFileType(file, content) 187 language := enry.GetLanguage(file, content) 188 mimeType := enry.GetMimeType(file, language) 189 190 fmt.Printf( 191 `%s: %d lines (%d sloc) 192 type: %s 193 mime_type: %s 194 language: %s 195 `, 196 filepath.Base(file), totalLines, nonBlank, fileType, mimeType, language, 197 ) 198 } 199 200 func getLines(file string, content string) (int, int) { 201 totalLines := strings.Count(content, "\n") 202 nonBlank := totalLines - strings.Count(content, "\n\n") 203 return totalLines, nonBlank 204 } 205 206 func getFileType(file string, content []byte) string { 207 switch { 208 case enry.IsImage(file): 209 return "Image" 210 case enry.IsBinary(content): 211 return "Binary" 212 default: 213 return "Text" 214 } 215 } 216 217 func writeStringLn(s string, buff *bytes.Buffer) { 218 buff.WriteString(s) 219 buff.WriteByte('\n') 220 }