EYAA7MJYQFEYESCXEHXOZ7QXIFFLYQYB5C6PIKHKBWS734KEFO2QC
4KHO6UPQWK7BD4NKUVYZWYRB4VNI74PGVZAZR4OPFGTMRT5FR2SAC
JFGNTEABCIU4WOBL3G7AHTQFDACXQ4HASQ2YHAG2DWVSIH2CHDMQC
XO72X6PQOB2636JAVQTXC2WC7BYZTYVYTQDAWYFXZIQYCDIP6ALQC
NX5BM2OINIVVOHN23N2DWH5LHVQN7AVRWYPUZ5J54WXFWE5B5XIQC
CHKVSGZGGPIFXFKRHQU4QMEXHJXQMMCRQCY3S5YA4S4JKFLXAAVAC
ABVOFHCVFGVFMTDOI4JZ3G7577NBXYHUKUR3LZBQFXFKYQMKGIFAC
O5ZANJMR27RRDAY7EVZLXZRKCKA24TFRBIZYWW7I72KG3DZQSCJAC
UKFZFDJOMUNXOF2QTVEA6VQG64DSGQCLJVEMH5OSBOSCZWUMKELQC
LBNVQXUBEZ45SOTGVXK5UEZXIAIZTJLWZNUYFI4JZ6J65N3KPDVQC
Q24QXGSMSBGB32S45SNOJO2ZDXEDRZQ2OGYVDVOH4I3QCAWSSIAQC
FQAZTEK6XMBH3RUZO4A72P5EPHCFR7WKDRIWJ45VY3KBR3CGU5RAC
6F4UNDTCAW7LYSKTUUUCX32BLAAGYPUPK2LXMMZ32Y6H3CBWP6TQC
TUMFOKWNUIPBUIO6OHOO2BUKIUFDZVG635VU6HUUXBRUQO4E5X6AC
SAIUFDP3EFXENSB3XS4OKXNOTGLCYGPW3QNHCXASXBDEEDGYRWUAC
Y6AHH4THYQA43V77L43YM42DYRPCMDSWLUV4NKWAQYMPL4NTUIPQC
ZH6B56XRZON7AGKUPGKABU2SWOIQSYBTXVOMR66X6P6MG25Y4WZAC
CNEQ7L4GUZRSS5VTNVW5PRXHASWGYFNW7YTSHIBOFNM7C454NH5AC
KI423DCQYAHL7IRSLKYU6BR5VMEGETWSKUANU4EKZEDWC2S2XSHAC
GJFYEU3SVP7TDSYXVZEYGKN4NVWSZX4754PPPTOYPRHUO5RMDWPQC
KLSDJV75BBXGL6KJYM23INJZCIIN6JKPP6I2UPJ6P4NPGQUIWAWAC
MMDLWWZ2W2XVHHOTG2S5XCPITVNIJQ6F7GLCF2MKQANFNFEID7DAC
CQTN62OHT4DY35E2MJEG7GFTVNEE5KRDMV6ASBQLBHN7BUDK7WHAC
TPNHTE5VJ36IPKMFENDERDBFBHLYFXOVNDLV2QSC4G5STPPMBLMAC
MOX7XJ2E3XISXA7V7T4W6GEAGECGWBZ4PYSLTYBVVR4VAKOI33CQC
RBHHV7P7MMFXUNWCJFNYKLGVLG2NQEDUKJ2IUCZ3WFMHH3SZRUHQC
QE253KG464JLXJHTILULXUIK527FGXT42IHHDE3BR6ASIYC44MWAC
U6UJRDG23EPP3BQ6MGWPZFGQSYWO5NBU6LYKM3FOE63YBPKUNJCQC
6M4KNDXX5S5PBODJAXALFSWBJTRBZBWTWQRX2PTO36LKL56DCMVAC
2MSFKTD5BSZSAYUYVETLZW2GAH65CFUYWWNTQCT3LBBCJGGWPHEQC
J5UVLXOK6EDIL5I7VKWH4V2QDS4DPD7FHRK6XBWSXFRQS4JKXFZQC
FHOH54HQJOWN2HGIKLVADURVYYHIIORLKEFI4NVKE4K457GLG6CAC
WXV6M6XNOKHBGKDFUBKQ5FJTLO6PLZHXHJW44O6BVVIHER2FIQWAC
HRAFVVOEGQJQS4XQNZSMNYN2SUZGKEGPSJUDZUBMI2IN32WFNQ4QC
ZB3JV52WEKVFX4XGSQUX6PCM4XGF62MCQRZAAOKNK4JNGYO2P7QAC
2GK5DOU7ODF4WBSN3QTD3WIO52VTL2LOAXKGCDEMMAQPTEO4A4HAC
VH5ZABDRP565VZIG55YHNYYPST53NQ2J6YM362NSLXCAHI5WPH4AC
O776XDS2CAQ6CMDEWAXU5ZGBH4ETZB77CODANQM233BARYWBRIXQC
5AIYUMTBY6TFQTBRP3MJ2PYWUMRF57I77NIVWYE74UMEVQMBWZVQC
GS4BE6TB6GH2JUZJHDPHL6YG7J7YYESF3YOZJZ2CFABXUTO4VYPQC
IN272KZWHENW2TCR3LWQ6OZAEESJL5S7AEL3GYLJTWHJUDE6HADAC
HPEG2RHVNHOPB5T4ZRXANIRBMVOVY3B5GFETJRYOTDJFVAYH2TQAC
KZ55DLPHCMOBWZRUMNGPNG3N2XK65K7VKFKVZH27W3KVUEQWGCTQC
PY4WQF5GIMT46FAALDW3PR6JURGY56PJOGOPDZ6NIEADQ7GTWJTAC
AFTXA575C6JTVLVXTYJUKQGPLBO3NFORLO5XDSPHNL44HXLRH4TAC
F5RYSE7TNJ6G35LFFV2F6IYDVPV4XG3A5LGDJECA7VJRS4SUER3QC
D5QIOJGPKQJIYBUCSC3MFJ3TXLPNZ2XMI37GXMFRVRFWWR2VMTFAC
3JBUMW3ECBQ5OARJEWPD7U5LIAIVGVMZUB7VG3ZLEWA3AV5EXDKQC
RGRBQI2FZQ6EXGPJITNWKT5JHCCUFMWPUO3WV62YSSNUBGM3ZAFAC
QWVUIGFYW7SJZ4377CNSHJ24NWIGLKJYGERGCDVVHWUQ6XXBO6BQC
YOA2RTLEQ7VK5XJONABRY4K43VVAXDK3FGS5LI57QNOXAHZVFEBQC
PPAE3Z3DP2IB4S5JXMC2FAHPDYEMUUNACP5HXGJ3QK3E5PKJTX3QC
6KIJX24R5RRDR2UQMUAWHF3N6V6DKKL5URYSLB7IT4J5C3RO4G2AC
ZIQRKUMJW6DUD2VIR3KOHFZA6ID5OPEI2XDKY77JQ52KW2GKXBTAC
2GUAKGTBTNFFER343SQWSLFYIXXHJLDSGH5JHF7QMC3AVZB7Q3TQC
MSIHMO45JO5V5ICZ7SKVWH6CLINKQY3UTA7274Q5OZCKPRX7SUNQC
M6WGSGNMB53OI77MZKW4BRFFX3YNARSBKZI37RIOJY5FJKWIRTJAC
3PNG7NIBQQURUUPRVQXYL342OT7JUUYOMY2JJNP6YDX7SYJDZMYAC
4WZQW2N6NJSIKSK7DCOV2YVEG5C45LLUM2FCCZRLISUXUGMBGF6QC
BIVZGPUTQ2C7X6NJQMVIDDO2OYNO4R3GROGQAWBVNSK2HSZ3REOQC
IK53RV4VGOHLCZGQCCIKPB45M3C7M7YMNBOJFBGZJ4LWIZNU4QNQC
QCGCX2BRDJ3MECT45M6KUQDSTVXWRHGLD4KKNG5UOCOTNAW7L3TQC
GAIBDEZZPZ52ASD3GK3WUYG3NOB27MLQ5GGIGKLAD6JQ4UATTT3AC
PMNWRTGJ4GVSMSSAWSUD57B26PCRAHMZIQ5SIWJIK7A74ENKEQLAC
ZWCTAZGLJZQNTYWTC2XQUKMILJF6JGDL5IND6QNYWK4FIGMLRFXAC
V6S6OYIAW3ZCBP6UHUYAZGG4P237WBB6HDG5NQIF3E5YFDTQRA4AC
TQVKZQUGCFYNH5P56LXMXRXZNTD56MH5T5GX2BMQ5YSRPGHAUYMAC
2P7VNAACFSXMH42JCXQZ7GDAAEIFDGDWJOK6XD6G36AGEYQSRO2AC
DAPOSS44WRFQZ7XUWSMYCCORY4POKD42DGAIXMGP4ZRBOEPNNRGAC
JFW656FT5JSDCA5NBNFGTJABIR2LR5VRDRYI7KF54PYNFDSL4DMAC
TX7Q4RASUYPTHIHZFACQ227BIZYLNJGRA5HHIAFQWCL4FHEHVGPQC
# Don't send logs that we can't stream.
my $size = stat($logPath)->size; # FIXME: not so meaningful for compressed logs
error($c, "This build log is too big to display ($size bytes).") unless
$mode eq "raw"
|| (($mode eq "tail" || $mode eq "tail-reload") && $logPath !~ /\.bz2$/)
|| $size < 64 * 1024 * 1024;
$c->stash->{logPath} = $logPath;
$c->stash->{finished} = $finished;
$c->forward('Hydra::View::NixLog');
}
elsif ($mode eq "tail-reload") {
my $url = $c->uri_for($c->request->uri->path);
$url =~ s/tail-reload/tail/g;
$c->stash->{url} = $url;
$c->stash->{reload} = !$c->stash->{build}->finished;
$c->stash->{title} = "";
$c->stash->{contents} = (scalar logContents($logPath, 50)) || " ";
$c->stash->{template} = 'plain-reload.tt';
$c->res->redirect($log_uri);
$c->stash->{'plain'} = { data => (scalar logContents($logPath, 50)) || " " };
$c->forward('Hydra::View::Plain');
my $lines = 50;
$c->stash->{log_uri} = $log_uri . "?tail=$lines";
$c->stash->{tail} = $lines;
$c->stash->{template} = 'log.tt';
$c->stash->{logPath} = $logPath;
$c->forward('Hydra::View::NixLog');
}
die if defined $tail && $tail !~ /^[0-9]+$/;
my $logFile = findLog($c, $drvPath);
if (defined $logFile) {
serveLogFile($c, $logFile, $tail);
return;
}
my $logPrefix = $c->config->{log_prefix};
my $fn = ($ENV{NIX_LOG_DIR} || "/nix/var/log/nix") . "/drvs/";
my $fn2 = Hydra::Model::DB::getHydraPath . "/build-logs/";
for ($fn2 . $bucketed, $fn2 . $bucketed . ".bz2", $fn . $bucketed . ".bz2", $fn . $bucketed, $fn . $base . ".bz2", $fn . $base) {
my $fn = Hydra::Model::DB::getHydraPath . "/build-logs/";
for ($fn . $bucketed, $fn . $bucketed . ".bz2") {
}
sub logContents {
my ($logPath, $tail) = @_;
my $cmd;
if ($logPath =~ /.bz2$/) {
$cmd = "bzip2 -d < $logPath";
$cmd = $cmd . " | tail -n $tail" if defined $tail;
}
else {
$cmd = defined $tail ? "tail -$tail $logPath" : "cat $logPath";
}
return decode("utf-8", `$cmd`);
sub removeAsciiEscapes {
my ($logtext) = @_;
$logtext =~ s/\e\[[0-9]*[A-Za-z]//g;
return $logtext;
}
[% WRAPPER layout.tt title="Log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job $build.project.name:$build.jobset.name:$build.job.name" %]
[% PROCESS common.tt %]
<p>Below are the last 50 log lines. The <a href="[% c.uri_for('/build' build.id 'log') %]">full log</a> is also available.</p>
[% IF reload %]
<script>
function scrollDown() {
$("#contents").scrollTop($("#contents").get(0).scrollHeight);
}
function injectTail() {
$.ajax({
url: "[% url %]",
dataType: "text",
success: function (tail) {
$("#contents").text(tail);
}
});
}
$(document).ready(function() {
injectTail();
setInterval(injectTail, 5000);
});
</script>
[% END %]
<pre class="taillog" id="contents">
[% HTML.escape(contents) %]
</pre>
[% END %]
scrollDown();
scrollDown();
[% project = build.project %]
[% jobset = build.jobset %]
[% job = build.job %]
<a class="btn btn-mini" href="[% c.uri_for('/build' build.id 'log') %]">pretty</a>
<a class="btn btn-mini" href="[% c.uri_for('/build' build.id 'log' 'raw') %]">raw</a>
<a class="btn btn-mini" href="[% c.uri_for('/build' build.id 'log' 'tail-reload') %]">tail</a>
<a class="btn btn-mini" href="[% c.uri_for('/build' actualBuild.id 'log') %]">pretty</a>
<a class="btn btn-mini" href="[% c.uri_for('/build' actualBuild.id 'log' 'raw') %]">raw</a>
<a class="btn btn-mini" href="[% c.uri_for('/build' actualBuild.id 'log' 'tail') %]">tail</a>
(<a [% IF inRow %]class="row-link"[% END %] href="[% url %]">log</a>, <a href="[% "$url/raw" %]">raw</a>, <a href="[% "$url/tail-reload" %]">tail</a>)
(<a [% IF inRow %]class="row-link"[% END %] href="[% url %]">log</a>, <a href="[% "$url/raw" %]">raw</a>, <a href="[% "$url/tail" %]">tail</a>)
This is the build log of derivation <tt>[% IF step; step.drvpath; ELSE; build.drvpath; END %]</tt>.
Below
[% IF tail %]
are the last lines of
[% ELSE %]
is
[% END %]
the build log of derivation <tt>[% IF step; step.drvpath; ELSE; build.drvpath; END %]</tt>.
<script type="text/javascript">
$(document).ready(function() {
requestPlainFile({
url: "[% HTML.escape(log_uri) %]",
dataType: "text",
type: 'GET',
success: function (log_data) {
[% IF tail %]
/* The server may give us a full log (e.g. if the log is in
S3). So extract the last lines. */
log_data = log_data.split("\n").slice(-[%tail%]).join("\n");
[% END %]
$("#contents").text(log_data);
},
error: function () {
bootbox.alert("The log file is not available.");
$("#contents").text("(Unavailable)");
}
});
});
</script>
};
function requestFile(args) {
if (!"error" in args) {
args.error = function(data) {
json = {};
try {
if (data.responseText)
json = $.parseJSON(data.responseText);
} catch (err) {
}
if (json.error)
bootbox.alert(escapeHTML(json.error));
else if (data.responseText)
bootbox.alert("Server error: " + escapeHTML(data.responseText));
else
bootbox.alert("Unknown server error!");
if (args.postError) args.postError(data);
};
}
return $.ajax(args);
args.error = function(data) {
json = {};
try {
if (data.responseText)
json = $.parseJSON(data.responseText);
} catch (err) {
requestFile(args);
};
function requestPlainFile(args) {
args.dataType = 'text';
/* Remove the X-Requested-With header, which would turn trigger
CORS checks for this request.
http://stackoverflow.com/a/24719409/6747243
*/
args.xhr = function() {
var xhr = jQuery.ajaxSettings.xhr();
var setRequestHeader = xhr.setRequestHeader;
xhr.setRequestHeader = function(name, value) {
if (name == 'X-Requested-With') return;
setRequestHeader.call(this, name, value);
if (json.error)
bootbox.alert(escapeHTML(json.error));
else if (data.responseText)
bootbox.alert("Server error: " + escapeHTML(data.responseText));
else
bootbox.alert("Unknown server error!");
if (args.postError) args.postError(data);
return xhr;
<td><a class="row-link" href="[% c.uri_for('/build' step.build.id 'nixlog' step.stepnr 'tail-reload') %]">[% step.stepnr %]</a></td>
<td><a class="row-link" href="[% c.uri_for('/build' step.build.id 'nixlog' step.stepnr 'tail') %]">[% step.stepnr %]</a></td>