-
Notifications
You must be signed in to change notification settings - Fork 17
/
compiler.go
114 lines (104 loc) · 2.8 KB
/
compiler.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
// Package compiler provides the AspectGo compiler.
package compiler
import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"sort"
"strings"
"github.com/AkihiroSuda/aspectgo/compiler/gopath"
"github.com/AkihiroSuda/aspectgo/compiler/parse"
"github.com/AkihiroSuda/aspectgo/compiler/weave"
)
// Compiler is the type for the AspectGo compiler.
type Compiler struct {
// WovenGOPATH is the GOPATH for woven packages.
WovenGOPATH string
// Target is the target package name.
// Can contain ... for recursive weaving.
Target string
// AspectFilenames are aspect file names.
// currently, only single aspect file is supported
AspectFilenames []string
}
// Do does all the compilation phases.
func (c *Compiler) Do() error {
log.Printf("Phase 0: Checking arguments")
if c.WovenGOPATH == "" {
return errors.New("WovenGOPATH not specified")
}
if c.Target == "" {
return errors.New("Target not specified")
}
if len(c.AspectFilenames) != 1 {
return fmt.Errorf("only single aspect file is supported at the moment: %v", c.AspectFilenames)
}
aspectFilename := c.AspectFilenames[0]
oldGOPATH := os.Getenv("GOPATH")
if oldGOPATH == "" {
return errors.New("GOPATH not set")
}
log.Printf("Phase 1: Parsing the aspects")
aspectFile, err := parse.ParseAspectFile(aspectFilename)
if err != nil {
return err
}
log.Printf("Phase 2: Weaving the aspects to the target packages")
targets, err := resolveTarget(oldGOPATH, c.Target)
if err != nil {
return err
}
var writtenFnames []string
for _, target := range targets {
w, err := weave.Weave(c.WovenGOPATH, target, aspectFile)
if err != nil {
return err
}
writtenFnames = append(writtenFnames, w...)
}
if len(writtenFnames) == 0 {
log.Printf("Nothing to do")
return nil
}
log.Printf("Phase 3: Fixing up GOPATH")
err = gopath.FixUp(oldGOPATH, c.WovenGOPATH, writtenFnames)
if err != nil {
return err
}
return nil
}
// resolveTarget resolves target that can contain ... and returns the list of
// resolved packages.
func resolveTarget(gopath, target string) ([]string, error) {
if strings.HasPrefix(target, ".") {
return nil, errors.New("local package (.) is not supported yet")
}
if filepath.Base(target) != "..." {
return []string{target}, nil
}
gopathSrc := filepath.Join(gopath, "src")
d := filepath.Join(gopathSrc, filepath.Dir(target))
resolvedMap := make(map[string]struct{})
err := filepath.Walk(d,
func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(path, ".go") {
d := filepath.Dir(path)
_, ok := resolvedMap[d]
if !ok {
resolvedMap[d] = struct{}{}
}
}
return nil
})
if err != nil {
return nil, err
}
var resolved []string
for f, _ := range resolvedMap {
resolved = append(resolved, strings.Replace(f, gopathSrc+"/", "", 1))
}
sort.Strings(resolved)
return resolved, nil
}