cb8e6f205a2715096123961b259b9772d11d6d66
[WebKit.git] / Websites / perf.webkit.org / public / v3 / models / commit-set.js
1 'use strict';
2
3 class CommitSet extends DataModelObject {
4
5     constructor(id, object)
6     {
7         super(id);
8         this._repositories = [];
9         this._repositoryToCommitMap = new Map;
10         this._repositoryToPatchMap = new Map;
11         this._repositoryToRootMap = new Map;
12         this._repositoryToCommitOwnerMap = new Map;
13         this._repositoryRequiresBuildMap = new Map;
14         this._latestCommitTime = null;
15         this._customRoots = [];
16         this._allRootFiles = [];
17
18         if (!object)
19             return;
20
21         this._updateFromObject(object);
22     }
23
24     updateSingleton(object)
25     {
26         this._repositoryToCommitMap.clear();
27         this._repositoryToPatchMap.clear();
28         this._repositoryToRootMap.clear();
29         this._repositoryToCommitOwnerMap.clear();
30         this._repositoryRequiresBuildMap.clear();
31         this._repositories = [];
32         this._updateFromObject(object);
33     }
34
35     _updateFromObject(object)
36     {
37         const rootFiles = new Set;
38         for (const item of object.revisionItems) {
39             const commit = item.commit;
40             console.assert(commit instanceof CommitLog);
41             console.assert(!item.patch || item.patch instanceof UploadedFile);
42             console.assert(!item.rootFile || item.rootFile instanceof UploadedFile);
43             console.assert(!item.commitOwner || item.commitOwner instanceof CommitLog);
44             const repository = commit.repository();
45             this._repositoryToCommitMap.set(repository, commit);
46             this._repositoryToPatchMap.set(repository, item.patch);
47             this._repositoryToCommitOwnerMap.set(repository, item.commitOwner);
48             this._repositoryRequiresBuildMap.set(repository, item.requiresBuild);
49             this._repositoryToRootMap.set(repository, item.rootFile);
50             if (item.rootFile)
51                 rootFiles.add(item.rootFile);
52             this._repositories.push(commit.repository());
53         }
54         this._customRoots = object.customRoots;
55         this._allRootFiles = Array.from(rootFiles).concat(object.customRoots);
56     }
57
58     repositories() { return this._repositories; }
59     customRoots() { return this._customRoots; }
60     allRootFiles() { return this._allRootFiles; }
61     commitForRepository(repository) { return this._repositoryToCommitMap.get(repository); }
62
63     revisionForRepository(repository)
64     {
65         var commit = this._repositoryToCommitMap.get(repository);
66         return commit ? commit.revision() : null;
67     }
68
69     ownerRevisionForRepository(repository)
70     {
71         const commit = this._repositoryToCommitOwnerMap.get(repository);
72         return commit ? commit.revision() : null;
73     }
74
75     patchForRepository(repository) { return this._repositoryToPatchMap.get(repository); }
76     rootForRepository(repository) { return this._repositoryToRootMap.get(repository); }
77     requiresBuildForRepository(repository) { return this._repositoryRequiresBuildMap.get(repository); }
78
79     // FIXME: This should return a Date object.
80     latestCommitTime()
81     {
82         if (this._latestCommitTime == null) {
83             var maxTime = 0;
84             for (const [repository, commit] of this._repositoryToCommitMap)
85                 maxTime = Math.max(maxTime, +commit.time());
86             this._latestCommitTime = maxTime;
87         }
88         return this._latestCommitTime;
89     }
90
91     equals(other)
92     {
93         if (this._repositories.length != other._repositories.length)
94             return false;
95         for (const [repository, commit] of this._repositoryToCommitMap) {
96             if (commit != other._repositoryToCommitMap.get(repository))
97                 return false;
98             if (this._repositoryToPatchMap.get(repository) != other._repositoryToPatchMap.get(repository))
99                 return false;
100             if (this._repositoryToRootMap.get(repository) != other._repositoryToRootMap.get(repository))
101                 return false;
102             if (this._repositoryToCommitOwnerMap.get(repository) != other._repositoryToCommitMap.get(repository))
103                 return false;
104             if (this._repositoryRequiresBuildMap.get(repository) != other._repositoryRequiresBuildMap.get(repository))
105                 return false;
106         }
107         return CommitSet.areCustomRootsEqual(this._customRoots, other._customRoots);
108     }
109
110     static areCustomRootsEqual(customRoots1, customRoots2)
111     {
112         if (customRoots1.length != customRoots2.length)
113             return false;
114         const set2 = new Set(customRoots2);
115         for (let file of customRoots1) {
116             if (!set2.has(file))
117                 return false;
118         }
119         return true;
120     }
121
122     static containsMultipleCommitsForRepository(commitSets, repository)
123     {
124         console.assert(repository instanceof Repository);
125         if (commitSets.length < 2)
126             return false;
127         const firstCommit = commitSets[0].commitForRepository(repository);
128         for (let set of commitSets) {
129             const anotherCommit = set.commitForRepository(repository);
130             if (!firstCommit != !anotherCommit || (firstCommit && firstCommit.revision() != anotherCommit.revision()))
131                 return true;
132         }
133         return false;
134     }
135 }
136
137 class MeasurementCommitSet extends CommitSet {
138
139     constructor(id, revisionList)
140     {
141         super(id, null);
142         for (var values of revisionList) {
143             // [<commit-id>, <repository-id>, <revision>, <time>]
144             var commitId = values[0];
145             var repositoryId = values[1];
146             var revision = values[2];
147             var time = values[3];
148             var repository = Repository.findById(repositoryId);
149             if (!repository)
150                 continue;
151
152             // FIXME: Add a flag to remember the fact this commit log is incomplete.
153             const commit = CommitLog.ensureSingleton(commitId, {repository: repository, revision: revision, time: time});
154             this._repositoryToCommitMap.set(repository, commit);
155             this._repositories.push(repository);
156         }
157     }
158
159     // Use CommitSet's static maps because MeasurementCommitSet and CommitSet are logically of the same type.
160     // FIXME: Ideally, DataModel should take care of this but traversing prototype chain is expensive.
161     namedStaticMap(name) { return CommitSet.namedStaticMap(name); }
162     ensureNamedStaticMap(name) { return CommitSet.ensureNamedStaticMap(name); }
163     static namedStaticMap(name) { return CommitSet.namedStaticMap(name); }
164     static ensureNamedStaticMap(name) { return CommitSet.ensureNamedStaticMap(name); }
165
166     static ensureSingleton(measurementId, revisionList)
167     {
168         const commitSetId = measurementId + '-commitset';
169         return CommitSet.findById(commitSetId) || (new MeasurementCommitSet(commitSetId, revisionList));
170     }
171 }
172
173 class CustomCommitSet {
174
175     constructor()
176     {
177         this._revisionListByRepository = new Map;
178         this._customRoots = [];
179     }
180
181     setRevisionForRepository(repository, revision, patch = null, ownerRevision = null)
182     {
183         console.assert(repository instanceof Repository);
184         console.assert(!patch || patch instanceof UploadedFile);
185         this._revisionListByRepository.set(repository, {revision, patch, ownerRevision});
186     }
187
188     equals(other)
189     {
190         console.assert(other instanceof CustomCommitSet);
191         if (this._revisionListByRepository.size != other._revisionListByRepository.size)
192             return false;
193
194         for (const [repository, thisRevision] of this._revisionListByRepository) {
195             const otherRevision = other._revisionListByRepository.get(repository);
196             if (!thisRevision != !otherRevision)
197                 return false;
198             if (thisRevision && (thisRevision.revision != otherRevision.revision
199                 || thisRevision.patch != otherRevision.patch
200                 || thisRevision.ownerRevision != otherRevision.ownerRevision))
201                 return false;
202         }
203         return CommitSet.areCustomRootsEqual(this._customRoots, other._customRoots);
204     }
205
206     repositories() { return Array.from(this._revisionListByRepository.keys()); }
207     revisionForRepository(repository)
208     {
209         const entry = this._revisionListByRepository.get(repository);
210         if (!entry)
211             return null;
212         return entry.revision;
213     }
214     patchForRepository(repository)
215     {
216         const entry = this._revisionListByRepository.get(repository);
217         if (!entry)
218             return null;
219         return entry.patch;
220     }
221     ownerRevisionForRepository(repository)
222     {
223         const entry = this._revisionListByRepository.get(repository);
224         if (!entry)
225             return null;
226         return entry.ownerRevision;
227     }
228     customRoots() { return this._customRoots; }
229
230     addCustomRoot(uploadedFile)
231     {
232         console.assert(uploadedFile instanceof UploadedFile);
233         this._customRoots.push(uploadedFile);
234     }
235 }
236
237 if (typeof module != 'undefined') {
238     module.exports.CommitSet = CommitSet;
239     module.exports.MeasurementCommitSet = MeasurementCommitSet;
240     module.exports.CustomCommitSet = CustomCommitSet;
241 }