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