blob: e970e1708ffdd6f950af7873202bf3d30e44fa66 [file] [log] [blame]
Aditya Choudhary51f97c12023-11-02 11:18:40 +00001package main
2
3import (
4 "flag"
5 "fmt"
6 "io"
7 "log"
8 "os"
9 "sort"
10 "strings"
11 "sync"
12
13 "android/soong/testing/test_spec_proto"
14 "google.golang.org/protobuf/proto"
15)
16
17type keyToLocksMap struct {
18 locks sync.Map
19}
20
21func (kl *keyToLocksMap) GetLockForKey(key string) *sync.Mutex {
22 mutex, _ := kl.locks.LoadOrStore(key, &sync.Mutex{})
23 return mutex.(*sync.Mutex)
24}
25
26func getSortedKeys(syncMap *sync.Map) []string {
27 var allKeys []string
28 syncMap.Range(
29 func(key, _ interface{}) bool {
30 allKeys = append(allKeys, key.(string))
31 return true
32 },
33 )
34
35 sort.Strings(allKeys)
36 return allKeys
37}
38
39func writeOutput(
40 outputFile string,
41 allMetadata []*test_spec_proto.TestSpec_OwnershipMetadata,
42) {
43 testSpec := &test_spec_proto.TestSpec{
44 OwnershipMetadataList: allMetadata,
45 }
46 data, err := proto.Marshal(testSpec)
47 if err != nil {
48 log.Fatal(err)
49 }
50 file, err := os.Create(outputFile)
51 if err != nil {
52 log.Fatal(err)
53 }
54 defer file.Close()
55
56 _, err = file.Write(data)
57 if err != nil {
58 log.Fatal(err)
59 }
60}
61
62func readFileToString(filePath string) string {
63 file, err := os.Open(filePath)
64 if err != nil {
65 log.Fatal(err)
66 }
67 defer file.Close()
68
69 data, err := io.ReadAll(file)
70 if err != nil {
71 log.Fatal(err)
72 }
73 return string(data)
74}
75
Aditya Choudhary70fb37e2023-11-16 19:52:44 +000076func writeNewlineToOutputFile(outputFile string) {
77 file, err := os.Create(outputFile)
78 data := "\n"
79 if err != nil {
80 log.Fatal(err)
81 }
82 defer file.Close()
83
84 _, err = file.Write([]byte(data))
85 if err != nil {
86 log.Fatal(err)
87 }
88}
89
Aditya Choudharya96ce322023-11-15 11:02:37 +000090func processTestSpecProtobuf(
Aditya Choudhary51f97c12023-11-02 11:18:40 +000091 filePath string, ownershipMetadataMap *sync.Map, keyLocks *keyToLocksMap,
92 errCh chan error, wg *sync.WaitGroup,
93) {
94 defer wg.Done()
95
96 fileContent := strings.TrimRight(readFileToString(filePath), "\n")
97 testData := test_spec_proto.TestSpec{}
98 err := proto.Unmarshal([]byte(fileContent), &testData)
99 if err != nil {
100 errCh <- err
101 return
102 }
103
104 ownershipMetadata := testData.GetOwnershipMetadataList()
105 for _, metadata := range ownershipMetadata {
106 key := metadata.GetTargetName()
107 lock := keyLocks.GetLockForKey(key)
108 lock.Lock()
109
110 value, loaded := ownershipMetadataMap.LoadOrStore(
111 key, []*test_spec_proto.TestSpec_OwnershipMetadata{metadata},
112 )
113 if loaded {
114 existingMetadata := value.([]*test_spec_proto.TestSpec_OwnershipMetadata)
115 isDuplicate := false
116 for _, existing := range existingMetadata {
117 if metadata.GetTrendyTeamId() != existing.GetTrendyTeamId() {
118 errCh <- fmt.Errorf(
119 "Conflicting trendy team IDs found for %s at:\n%s with teamId"+
120 ": %s,\n%s with teamId: %s",
121 key,
122 metadata.GetPath(), metadata.GetTrendyTeamId(), existing.GetPath(),
123 existing.GetTrendyTeamId(),
124 )
125
126 lock.Unlock()
127 return
128 }
129 if metadata.GetTrendyTeamId() == existing.GetTrendyTeamId() && metadata.GetPath() == existing.GetPath() {
130 isDuplicate = true
131 break
132 }
133 }
134 if !isDuplicate {
135 existingMetadata = append(existingMetadata, metadata)
136 ownershipMetadataMap.Store(key, existingMetadata)
137 }
138 }
139
140 lock.Unlock()
141 }
142}
143
144func main() {
145 inputFile := flag.String("inputFile", "", "Input file path")
146 outputFile := flag.String("outputFile", "", "Output file path")
Aditya Choudharya96ce322023-11-15 11:02:37 +0000147 rule := flag.String("rule", "", "Metadata rule (Hint: test_spec or code_metadata)")
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000148 flag.Parse()
149
Aditya Choudharya96ce322023-11-15 11:02:37 +0000150 if *inputFile == "" || *outputFile == "" || *rule == "" {
151 fmt.Println("Usage: metadata -rule <rule> -inputFile <input file path> -outputFile <output file path>")
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000152 os.Exit(1)
153 }
154
155 inputFileData := strings.TrimRight(readFileToString(*inputFile), "\n")
Aditya Choudhary93cd9f62023-11-21 14:01:41 +0000156 filePaths := strings.Split(inputFileData, " ")
Aditya Choudhary70fb37e2023-11-16 19:52:44 +0000157 if len(filePaths) == 1 && filePaths[0] == "" {
158 writeNewlineToOutputFile(*outputFile)
159 return
160 }
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000161 ownershipMetadataMap := &sync.Map{}
162 keyLocks := &keyToLocksMap{}
163 errCh := make(chan error, len(filePaths))
164 var wg sync.WaitGroup
165
Aditya Choudharya96ce322023-11-15 11:02:37 +0000166 switch *rule {
167 case "test_spec":
168 for _, filePath := range filePaths {
169 wg.Add(1)
170 go processTestSpecProtobuf(filePath, ownershipMetadataMap, keyLocks, errCh, &wg)
171 }
172
173 wg.Wait()
174 close(errCh)
175
176 for err := range errCh {
177 log.Fatal(err)
178 }
179
180 allKeys := getSortedKeys(ownershipMetadataMap)
181 var allMetadata []*test_spec_proto.TestSpec_OwnershipMetadata
182
183 for _, key := range allKeys {
184 value, _ := ownershipMetadataMap.Load(key)
185 metadataList := value.([]*test_spec_proto.TestSpec_OwnershipMetadata)
186 allMetadata = append(allMetadata, metadataList...)
187 }
188
189 writeOutput(*outputFile, allMetadata)
190 break
191 case "code_metadata":
192 default:
193 log.Fatalf("No specific processing implemented for rule '%s'.\n", *rule)
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000194 }
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000195}