blob: eb877553d3bfaa9ff98869e4f1e81064cd538a95 [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 Choudharya96ce322023-11-15 11:02:37 +000076func processTestSpecProtobuf(
Aditya Choudhary51f97c12023-11-02 11:18:40 +000077 filePath string, ownershipMetadataMap *sync.Map, keyLocks *keyToLocksMap,
78 errCh chan error, wg *sync.WaitGroup,
79) {
80 defer wg.Done()
81
82 fileContent := strings.TrimRight(readFileToString(filePath), "\n")
83 testData := test_spec_proto.TestSpec{}
84 err := proto.Unmarshal([]byte(fileContent), &testData)
85 if err != nil {
86 errCh <- err
87 return
88 }
89
90 ownershipMetadata := testData.GetOwnershipMetadataList()
91 for _, metadata := range ownershipMetadata {
92 key := metadata.GetTargetName()
93 lock := keyLocks.GetLockForKey(key)
94 lock.Lock()
95
96 value, loaded := ownershipMetadataMap.LoadOrStore(
97 key, []*test_spec_proto.TestSpec_OwnershipMetadata{metadata},
98 )
99 if loaded {
100 existingMetadata := value.([]*test_spec_proto.TestSpec_OwnershipMetadata)
101 isDuplicate := false
102 for _, existing := range existingMetadata {
103 if metadata.GetTrendyTeamId() != existing.GetTrendyTeamId() {
104 errCh <- fmt.Errorf(
105 "Conflicting trendy team IDs found for %s at:\n%s with teamId"+
106 ": %s,\n%s with teamId: %s",
107 key,
108 metadata.GetPath(), metadata.GetTrendyTeamId(), existing.GetPath(),
109 existing.GetTrendyTeamId(),
110 )
111
112 lock.Unlock()
113 return
114 }
115 if metadata.GetTrendyTeamId() == existing.GetTrendyTeamId() && metadata.GetPath() == existing.GetPath() {
116 isDuplicate = true
117 break
118 }
119 }
120 if !isDuplicate {
121 existingMetadata = append(existingMetadata, metadata)
122 ownershipMetadataMap.Store(key, existingMetadata)
123 }
124 }
125
126 lock.Unlock()
127 }
128}
129
130func main() {
131 inputFile := flag.String("inputFile", "", "Input file path")
132 outputFile := flag.String("outputFile", "", "Output file path")
Aditya Choudharya96ce322023-11-15 11:02:37 +0000133 rule := flag.String("rule", "", "Metadata rule (Hint: test_spec or code_metadata)")
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000134 flag.Parse()
135
Aditya Choudharya96ce322023-11-15 11:02:37 +0000136 if *inputFile == "" || *outputFile == "" || *rule == "" {
137 fmt.Println("Usage: metadata -rule <rule> -inputFile <input file path> -outputFile <output file path>")
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000138 os.Exit(1)
139 }
140
141 inputFileData := strings.TrimRight(readFileToString(*inputFile), "\n")
142 filePaths := strings.Split(inputFileData, "\n")
143 ownershipMetadataMap := &sync.Map{}
144 keyLocks := &keyToLocksMap{}
145 errCh := make(chan error, len(filePaths))
146 var wg sync.WaitGroup
147
Aditya Choudharya96ce322023-11-15 11:02:37 +0000148 switch *rule {
149 case "test_spec":
150 for _, filePath := range filePaths {
151 wg.Add(1)
152 go processTestSpecProtobuf(filePath, ownershipMetadataMap, keyLocks, errCh, &wg)
153 }
154
155 wg.Wait()
156 close(errCh)
157
158 for err := range errCh {
159 log.Fatal(err)
160 }
161
162 allKeys := getSortedKeys(ownershipMetadataMap)
163 var allMetadata []*test_spec_proto.TestSpec_OwnershipMetadata
164
165 for _, key := range allKeys {
166 value, _ := ownershipMetadataMap.Load(key)
167 metadataList := value.([]*test_spec_proto.TestSpec_OwnershipMetadata)
168 allMetadata = append(allMetadata, metadataList...)
169 }
170
171 writeOutput(*outputFile, allMetadata)
172 break
173 case "code_metadata":
174 default:
175 log.Fatalf("No specific processing implemented for rule '%s'.\n", *rule)
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000176 }
Aditya Choudhary51f97c12023-11-02 11:18:40 +0000177}