Skip to content

Commit 30b844a

Browse files
partoufclaude
andcommitted
Add Go libraries page and API endpoint
- Add libraries_go.html page for displaying Go library binaries - Add /libraries/go API endpoint filtering by language - Fetch Go library metadata from CE API on startup - Add Go to language detection in Conan library scanner - Add link to Go libraries page on index - Make conanserverurl configurable via CONANSERVERURL env var Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent aa2da1b commit 30b844a

File tree

3 files changed

+235
-2
lines changed

3 files changed

+235
-2
lines changed

html/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ <h2>Compiler Explorer Library binaries</h2>
1616
<li><a href="/libraries_cpp.html">C++ library binaries</a></li>
1717
<li><a href="/libraries_rust.html">Rust library binaries</a></li>
1818
<li><a href="/libraries_fortran.html">Fortran library binaries</a></li>
19+
<li><a href="/libraries_go.html">Go library binaries</a></li>
1920
<li><a href="/compilerfailurerates.html">Overall compiler failure rates</a></li>
2021
<li><a href="/failedbuilds.html">Failed library builds</a></li>
2122
<li><a href="/usage.html">Some usage statistics</a></li>

html/libraries_go.html

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
<html>
2+
<head>
3+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
4+
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
5+
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
6+
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
7+
<link rel="stylesheet" href="./conan.css" />
8+
<script language="Javascript">
9+
const urlprefix = "https://conan.compiler-explorer.com";
10+
function refreshLibraries() {
11+
const xhr = new XMLHttpRequest();
12+
xhr.open('GET', urlprefix + '/libraries/go');
13+
xhr.setRequestHeader('Content-Type', 'application/json');
14+
xhr.onload = () => {
15+
const info = JSON.parse(xhr.responseText);
16+
const librariesNode = $('#libraries tbody');
17+
librariesNode.html("");
18+
19+
Object.keys(info).forEach(libraryId => {
20+
const library = info[libraryId];
21+
22+
if (library.name === 'ulib') return; // pretend theres no ulib for the time being
23+
24+
const row = $("<tr class='libraryrow'><td class='libraryname' /><td class='libraryversions' /></tr>");
25+
row.find('.libraryname').html(library.name);
26+
Object.keys(library.versions).forEach(versionId => {
27+
const version = library.versions[versionId];
28+
const versionlink = $("<a class='libraryversion' />");
29+
versionlink.data('libraryId', libraryId);
30+
versionlink.data('versionId', versionId);
31+
versionlink.data('version', version);
32+
versionlink.attr('href', "javascript:;");
33+
versionlink.html(version);
34+
versionlink.click(toggleMatrix);
35+
36+
row.find('.libraryversions').append(versionlink);
37+
});
38+
librariesNode.append(row);
39+
40+
const matrixNode = $("<tr class='librarymatrixrow'><td colspan='2' class='librarymatrix' /></tr>");
41+
matrixNode.attr("id", libraryId);
42+
matrixNode.hide();
43+
librariesNode.append(matrixNode);
44+
});
45+
};
46+
xhr.send();
47+
}
48+
49+
function fetchDownloadUrls(libraryid, version, buildhash, callback) {
50+
const url = urlprefix + '/v1/conans/' + libraryid + '/' + version + '/' + libraryid + '/' + version + '/packages/' + buildhash + '/download_urls';
51+
52+
const xhr = new XMLHttpRequest();
53+
xhr.open('GET', url);
54+
xhr.setRequestHeader('Content-Type', 'application/json');
55+
xhr.onload = () => {
56+
const info = JSON.parse(xhr.responseText);
57+
58+
callback(info);
59+
};
60+
xhr.send();
61+
}
62+
63+
function requestAnnotations(libraryid, version, who) {
64+
const buildhash = who.parent().data('hash');
65+
const xhr = new XMLHttpRequest();
66+
xhr.open('GET', urlprefix + '/annotations/' + libraryid + '/' + version + '/' + buildhash);
67+
xhr.setRequestHeader('Content-Type', 'application/json');
68+
xhr.onload = () => {
69+
const info = JSON.parse(xhr.responseText);
70+
who.data('annotations', info);
71+
72+
let content = "";
73+
content += "buildhash: " + buildhash + "<br />";
74+
Object.keys(info).forEach(key => {
75+
if (key !== 'error') content += key + ": " + info[key] + "<br />";
76+
});
77+
78+
fetchDownloadUrls(libraryid, version, buildhash, function(urls) {
79+
Object.keys(urls).forEach(filename => {
80+
content += "<a href='" + urls[filename] + "'>" + filename + "</a><br />";
81+
});
82+
83+
who.data('content', content);
84+
who.popover('toggle');
85+
});
86+
};
87+
xhr.send();
88+
}
89+
90+
function refreshMatrix(libraryId, libraryVersion, matrixNode) {
91+
$("button.moreinfobtn").popover('dispose');
92+
93+
const xhr = new XMLHttpRequest();
94+
xhr.open('GET', urlprefix + '/binaries/' + libraryId + '/' + libraryVersion);
95+
xhr.setRequestHeader('Content-Type', 'application/json');
96+
xhr.onload = () => {
97+
const info = JSON.parse(xhr.responseText);
98+
matrixNode.find("td").html("");
99+
100+
const matrixTable = $("<table class='table table-striped'><thead><tr class='binmatrixheader' /></thead><tbody /></table>");
101+
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
102+
matrixTable.addClass('table-dark');
103+
}
104+
const header = matrixTable.find('.binmatrixheader');
105+
106+
const tdCompiler = $("<th class='binmatrixheadercompiler' scope='col'>Compiler</th>");
107+
header.append(tdCompiler);
108+
109+
info.possibleCombinations.forEach(combination => {
110+
const td = $("<th class='binmatrixheaderoption' scope='col' />");
111+
td.append($("<div />").addClass("comboos").html(combination.os));
112+
td.append($("<div />").addClass("comboarch").html(combination.arch));
113+
td.append($("<div />").addClass("combobuildtype").html(combination.build_type));
114+
td.append($("<div />").addClass("comboflags").html(combination.flagcollection));
115+
td.append($("<div />").addClass("combostdver").html(combination.stdver));
116+
td.append($("<div />").addClass("combostdlibold").html(combination.stdlib));
117+
td.append($("<div />").addClass("combostdlib").html(combination['compiler.libcxx']));
118+
119+
header.append(td);
120+
});
121+
122+
Object.keys(info.perCompiler).forEach(compilerId => {
123+
const compiler = info.perCompiler[compilerId];
124+
const row = $("<tr class='binmatrixrow'><th class='compilername' scope='row' /></tr>");
125+
row.find('.compilername').html(compiler.name);
126+
row.find('.compilername').data('compilerid', compilerId);
127+
128+
for (let idxCombination = 0; idxCombination < info.possibleCombinations.length; idxCombination++) {
129+
const tdCombinationYesNo = $("<td class='binmatrixheaderoptionyesno' />");
130+
var idxHash = compiler.combinations.indexOf(idxCombination);
131+
if (idxHash !== -1) {
132+
tdCombinationYesNo.addClass("table-success");
133+
tdCombinationYesNo.html("");
134+
135+
tdCombinationYesNo.data('hash', compiler.hashes[idxHash]);
136+
137+
const aMoreInfo = $("<button>More info</button>");
138+
aMoreInfo.addClass("btn");
139+
aMoreInfo.attr("href", "javascript:;");
140+
aMoreInfo.addClass("moreinfobtn");
141+
aMoreInfo.data("placement", "bottom");
142+
aMoreInfo.data("trigger", "manual");
143+
aMoreInfo.data("html", true);
144+
aMoreInfo.data("content", "Hash: " + compiler.hashes[idxHash]);
145+
aMoreInfo.click(function() {
146+
const who = $(this);
147+
if (!who.data("annotations")) {
148+
requestAnnotations(libraryId, libraryVersion, who);
149+
} else {
150+
who.popover('toggle');
151+
}
152+
});
153+
154+
tdCombinationYesNo.append(aMoreInfo);
155+
}
156+
row.append(tdCombinationYesNo);
157+
}
158+
159+
matrixTable.find("tbody").append(row);
160+
});
161+
162+
matrixNode.find("td").append(matrixTable);
163+
};
164+
xhr.send();
165+
}
166+
167+
function toggleMatrix() {
168+
const link = $(this);
169+
const libraryId = link.data("libraryId");
170+
const versionId = link.data("versionId");
171+
const version = link.data("version");
172+
173+
const matrixNode = $("#" + libraryId);
174+
refreshMatrix(libraryId, version, matrixNode);
175+
matrixNode.show();
176+
}
177+
178+
$(document).ready(() => {
179+
refreshLibraries();
180+
181+
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
182+
document.querySelectorAll('.table-striped').forEach(table => {
183+
table.classList.add('table-dark');
184+
});
185+
document.querySelectorAll('#libraries').forEach(table => {
186+
table.classList.add('table-dark');
187+
});
188+
}
189+
});
190+
</script>
191+
<title>CE - All Go library binaries</title>
192+
</head>
193+
<body>
194+
<table id="libraries" class='table'>
195+
<thead>
196+
<th scope='col'>Library</th><th scope='col'>Versions</th>
197+
</thead>
198+
<tbody>
199+
</tbody>
200+
</table>
201+
</body>
202+
</html>

index.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const
1717
const
1818
webServer = express();
1919

20-
const conanserverurl = 'http://127.0.0.1:9300';
20+
const conanserverurl = process.env.CONANSERVERURL || 'http://127.0.0.1:9300';
2121
const ceserverurl = 'https://godbolt.org';
2222

2323
const userhome = "/home/ce";
@@ -29,6 +29,7 @@ let compilersemvers = null;
2929
let allRustLibrariesAndVersions = null;
3030
let allCppLibrariesAndVersions = null;
3131
let allFortranLibrariesAndVersions = null;
32+
let allGoLibrariesAndVersions = null;
3233

3334
let availableLibrariesAndVersions = {};
3435
let availableLibraryIds = [];
@@ -197,6 +198,18 @@ async function refreshCELibraries() {
197198
console.error(err);
198199
reject(err);
199200
});
201+
202+
https.get(`${ceserverurl}/api/libraries/go`, { headers: { Accept: 'application/json' } }, (resp) => {
203+
let data = '';
204+
resp.on('data', (chunk) => data += chunk);
205+
resp.on('end', () => {
206+
allGoLibrariesAndVersions = JSON.parse(data);
207+
resolve(true);
208+
});
209+
}).on('error', (err) => {
210+
console.error(err);
211+
reject(err);
212+
});
200213
});
201214
}
202215

@@ -252,7 +265,12 @@ async function refreshConanLibraries(forceall) {
252265
language = 'rust';
253266
} else {
254267
ceLib = _.find(allFortranLibrariesAndVersions, (lib) => lib.id === libraryId);
255-
if (ceLib) language = 'fortran';
268+
if (ceLib) {
269+
language = 'fortran';
270+
} else {
271+
ceLib = _.find(allGoLibrariesAndVersions, (lib) => lib.id === libraryId);
272+
if (ceLib) language = 'go';
273+
}
256274
}
257275
}
258276

@@ -342,6 +360,7 @@ function main() {
342360
'/libraries_rust.html',
343361
'/libraries_cpp.html',
344362
'/libraries_fortran.html',
363+
'/libraries_go.html',
345364
'/compilerfailurerates.html',
346365
'/failedbuilds.html',
347366
'/usage.html',
@@ -355,6 +374,7 @@ function main() {
355374
'/libraries/cpp',
356375
'/libraries/rust',
357376
'/libraries/fortran',
377+
'/libraries/go',
358378
'/libraries',
359379
'/compilerfailurerates',
360380
'/hasfailedbefore',
@@ -426,6 +446,16 @@ function main() {
426446
});
427447
res.send(filteredlibs);
428448
})
449+
.options('/libraries/go', libraryexpireheaders, async (req, res) => {
450+
res.send();
451+
})
452+
.get('/libraries/go', libraryexpireheaders, async (req, res) => {
453+
const filteredlibs = {};
454+
_.each(availableLibrariesAndVersions, (lib, id) => {
455+
if (lib.language === 'go') filteredlibs[id] = lib;
456+
});
457+
res.send(filteredlibs);
458+
})
429459
.options('/libraries', libraryexpireheaders, async (req, res) => {
430460
res.send();
431461
})

0 commit comments

Comments
 (0)