-
Notifications
You must be signed in to change notification settings - Fork 24
/
single_app_dep_parser.go
153 lines (126 loc) · 3.06 KB
/
single_app_dep_parser.go
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
// Copyright The KCL Authors. All rights reserved.
package list
import (
"fmt"
"io/fs"
"os"
pathpkg "path"
"sort"
)
type SingleAppDepParser struct {
opt Option
vfs fs.FS
appPkgpath string
importMap map[string][]string
pkgFilesMap map[string][]string
allfiles []string
err error
}
func NewSingleAppDepParser(root string, opt ...Option) *SingleAppDepParser {
root = pathpkg.Clean(root)
return NewSingleAppDepParserWithFS(os.DirFS(root), opt...)
}
func NewSingleAppDepParserWithFS(vfs fs.FS, opts ...Option) *SingleAppDepParser {
p := &SingleAppDepParser{
vfs: vfs,
importMap: make(map[string][]string),
pkgFilesMap: make(map[string][]string),
}
for _, opt := range opts {
p.opt.merge(&opt)
}
p.opt.adjust()
return p
}
func (p *SingleAppDepParser) GetAppFiles(appPkgpath string, includeDependFiles bool) ([]string, error) {
if err := p.parseOnce(appPkgpath); err != nil {
return nil, err
}
if includeDependFiles {
return p.allfiles, nil
}
return p.pkgFilesMap[appPkgpath], nil
}
func (p *SingleAppDepParser) GetAppPkgs(appPkgpath string, includeDependFiles bool) ([]string, error) {
if err := p.parseOnce(appPkgpath); err != nil {
return nil, err
}
if includeDependFiles {
var pkgs []string
for k := range p.importMap {
pkgs = append(pkgs, k)
}
sort.Strings(pkgs)
return pkgs, nil
}
return p.importMap[appPkgpath], nil
}
func (p *SingleAppDepParser) parseOnce(appPkgpath string) error {
if p.appPkgpath == appPkgpath {
return p.err
}
p.appPkgpath = appPkgpath
p.importMap = make(map[string][]string)
p.pkgFilesMap = make(map[string][]string)
p.allfiles = []string{}
if err := p.scanAppFiles(appPkgpath); err != nil {
p.err = err
return err
}
var filesMap = make(map[string]struct{})
for _, files := range p.pkgFilesMap {
for _, s := range files {
filesMap[s] = struct{}{}
}
}
for s := range filesMap {
p.allfiles = append(p.allfiles, s)
}
sort.Strings(p.allfiles)
return nil
}
func (p *SingleAppDepParser) scanAppFiles(pkgpath string) error {
if isBuiltinPkg(pkgpath) || isPluginPkg(pkgpath) {
return nil
}
if p.opt.ExcludeExternalPackage {
if isExternalPkg(p.vfs, pkgpath) {
return nil
}
}
if _, ok := p.pkgFilesMap[pkgpath]; ok {
return nil
}
// 1. loadKFileList
k_files, err := loadKFileList(p.vfs, pkgpath, p.opt)
if err != nil {
return fmt.Errorf("package %s: %w", pkgpath, err)
}
p.pkgFilesMap[pkgpath] = k_files
// 2. parse import
var importMap = make(map[string]string)
for _, file := range k_files {
src, err := fs.ReadFile(p.vfs, file)
if err != nil {
return err
}
for _, import_path := range parseImport(string(src)) {
import_path := fixImportPath(file, import_path)
importMap[import_path] = import_path
}
}
// 3. save import list
var importList []string
for import_path := range importMap {
importList = append(importList, import_path)
}
sort.Strings(importList)
p.importMap[pkgpath] = importList
// 4. scan import
for _, import_path := range importList {
if err := p.scanAppFiles(import_path); err != nil {
return err
}
}
return err
}