v / cmd / tools / vdoc / files.v
99 lines · 94 sloc · 2.62 KB · afc1f92d0a42d1e8bbdd09007825f6947955a53a
Raw
1module main
2
3import os
4
5struct IgnoreRules {
6mut:
7 // Ignore patterns use the path with a `.vdocignore` file as a base. E.g.:
8 // `{'<path>': ['<pattern1>', '<pattern2>'], '<path/subpath>': ['<pattern3>']}`
9 patterns map[string][]string = {
10 // Default ignore patterns.
11 '': ['testdata', 'tests', '*_test.v']
12 }
13 paths map[string]bool
14}
15
16fn get_modules(path string) []string {
17 mut modules := map[string]bool{}
18 for p in get_paths(path, IgnoreRules.get(path)) {
19 modules[os.dir(p)] = true
20 }
21 mut res := modules.keys()
22 res.sort()
23 return res
24}
25
26fn get_paths(path string, ignore_rules IgnoreRules) []string {
27 mut res := []string{}
28 outer: for p in os.ls(path) or { return [] } {
29 fp := os.join_path(path, p)
30 if fp in ignore_rules.paths {
31 continue
32 }
33 is_dir := os.is_dir(fp)
34 for ignore_path, patterns in ignore_rules.patterns {
35 if fp.starts_with(ignore_path) {
36 if patterns.any(p == it
37 || (it.contains('*') && p.ends_with(it.all_after('*')))
38 || (is_dir && it.ends_with('/') && fp.ends_with(it.trim_right('/')))
39 || (!it.ends_with('/') && it.contains('/') && fp.contains(it)))
40 {
41 continue outer
42 }
43 }
44 }
45 if is_dir {
46 res << get_paths(fp, ignore_rules)
47 continue
48 }
49 if p.ends_with('.v') {
50 res << fp
51 }
52 }
53 return res
54}
55
56fn IgnoreRules.get(path string) IgnoreRules {
57 mut res := IgnoreRules{}
58 mut vdocignore_paths := []string{}
59 mut vdocignore_paths_ref := &vdocignore_paths
60 os.walk(path, fn [vdocignore_paths_ref] (p string) {
61 if os.file_name(p) == '.vdocignore' {
62 unsafe {
63 vdocignore_paths_ref << p
64 }
65 }
66 })
67 for ignore_path in vdocignore_paths {
68 ignore_content := os.read_file(ignore_path) or { continue }
69 if ignore_content.trim_space() == '' {
70 continue
71 }
72 rules := ignore_content.split_into_lines().map(it.trim_space())
73 for rule in rules {
74 if rule.starts_with('#') {
75 continue
76 }
77 if rule.contains('*.') || rule.contains('**') {
78 // Skip wildcards that are defined in an ignore file.
79 // For now, only add a basic implementation in `get_paths`
80 // that can handle the default `*_test.v` pattern.
81 eprintln('vdoc: Wildcards in ignore rules are not yet supported.')
82 continue
83 }
84 p := os.dir(ignore_path)
85 if rule.starts_with('/') {
86 // Similar to `.gitignore`, a pattern starting with `/` should only ignore
87 // the pattern relative to the directory of the `.vdocignore` file.
88 // `/a` should ignore `/a` but not `/b/a`. While `a` should ignore `/a` and `/b/a`.
89 res.paths[os.join_path(p, rule.trim_left('/'))] = true
90 } else {
91 if p !in res.patterns {
92 res.patterns[p] = []string{}
93 }
94 res.patterns[p] << rule
95 }
96 }
97 }
98 return res
99}
100