xref: /dragonfly/usr.bin/dsynth/html.c (revision 51705b28)
1ea37671dSMatthew Dillon /*
28b485838SMatthew Dillon  * Copyright (c) 2019-2020 The DragonFly Project.  All rights reserved.
3ea37671dSMatthew Dillon  *
4ea37671dSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5ea37671dSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6ea37671dSMatthew Dillon  *
7ea37671dSMatthew Dillon  * This code uses concepts and configuration based on 'synth', by
8ea37671dSMatthew Dillon  * John R. Marino <draco@marino.st>, which was written in ada.
9ea37671dSMatthew Dillon  *
10ea37671dSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
11ea37671dSMatthew Dillon  * modification, are permitted provided that the following conditions
12ea37671dSMatthew Dillon  * are met:
13ea37671dSMatthew Dillon  *
14ea37671dSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
15ea37671dSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
16ea37671dSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
17ea37671dSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
18ea37671dSMatthew Dillon  *    the documentation and/or other materials provided with the
19ea37671dSMatthew Dillon  *    distribution.
20ea37671dSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
21ea37671dSMatthew Dillon  *    contributors may be used to endorse or promote products derived
22ea37671dSMatthew Dillon  *    from this software without specific, prior written permission.
23ea37671dSMatthew Dillon  *
24ea37671dSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25ea37671dSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26ea37671dSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27ea37671dSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28ea37671dSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29ea37671dSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30ea37671dSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31ea37671dSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32ea37671dSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33ea37671dSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34ea37671dSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35ea37671dSMatthew Dillon  * SUCH DAMAGE.
36ea37671dSMatthew Dillon  */
37ea37671dSMatthew Dillon #include "dsynth.h"
38ea37671dSMatthew Dillon 
398b485838SMatthew Dillon #define SNPRINTF(buf, ctl, ...)         \
408b485838SMatthew Dillon 	snprintf((buf), sizeof(buf), ctl, ## __VA_ARGS__)
418b485838SMatthew Dillon 
428b485838SMatthew Dillon static char *ReportPath;
438b485838SMatthew Dillon static int HistNum;
448b485838SMatthew Dillon static int EntryNum;
458b485838SMatthew Dillon static char KickOff_Buf[64];
468b485838SMatthew Dillon 
47d50f9ae3SSascha Wildner static const char *CopyFilesAry[] = {
488b485838SMatthew Dillon 	"favicon.png",
498b485838SMatthew Dillon 	"progress.html",
508b485838SMatthew Dillon 	"progress.css",
518b485838SMatthew Dillon 	"progress.js",
528b485838SMatthew Dillon 	"dsynth.png",
538b485838SMatthew Dillon 	NULL
548b485838SMatthew Dillon };
558b485838SMatthew Dillon 
56d50f9ae3SSascha Wildner static char **HtmlSlots;
57d50f9ae3SSascha Wildner static time_t HtmlStart;
58d50f9ae3SSascha Wildner static time_t HtmlLast;
598b485838SMatthew Dillon 
608b485838SMatthew Dillon /*
618b485838SMatthew Dillon  * Get rid of stuff that might blow up the json output.
628b485838SMatthew Dillon  */
638b485838SMatthew Dillon static const char *
dequote(const char * reason)648b485838SMatthew Dillon dequote(const char *reason)
658b485838SMatthew Dillon {
661e79c7a7SMatthew Dillon 	static char *buf;
678b485838SMatthew Dillon 	int i;
688b485838SMatthew Dillon 
698b485838SMatthew Dillon 	for (i = 0; reason[i]; ++i) {
7032f84edaSMatthew Dillon 		if (reason[i] == '\"' || reason[i] == '\n' ||
7132f84edaSMatthew Dillon 		    reason[i] == '\\') {
728b485838SMatthew Dillon 			if (reason != buf) {
731e79c7a7SMatthew Dillon 				if (buf)
741e79c7a7SMatthew Dillon 					free(buf);
751e79c7a7SMatthew Dillon 				buf = strdup(reason);
768b485838SMatthew Dillon 				reason = buf;
778b485838SMatthew Dillon 			}
788b485838SMatthew Dillon 			buf[i] = ' ';
798b485838SMatthew Dillon 		}
808b485838SMatthew Dillon 	}
818b485838SMatthew Dillon 	return reason;
828b485838SMatthew Dillon }
838b485838SMatthew Dillon 
84ea37671dSMatthew Dillon static void
HtmlInit(void)85ea37671dSMatthew Dillon HtmlInit(void)
86ea37671dSMatthew Dillon {
878b485838SMatthew Dillon 	struct dirent *den;
888b485838SMatthew Dillon 	DIR *dir;
898b485838SMatthew Dillon 	struct stat st;
908b485838SMatthew Dillon 	struct tm tmm;
918b485838SMatthew Dillon 	size_t len;
928b485838SMatthew Dillon 	char *src;
938b485838SMatthew Dillon 	char *dst;
948b485838SMatthew Dillon 	time_t t;
958b485838SMatthew Dillon 	int i;
968b485838SMatthew Dillon 
978b485838SMatthew Dillon 	HtmlSlots = calloc(sizeof(char *), MaxWorkers);
988b485838SMatthew Dillon 	HtmlLast = 0;
998b485838SMatthew Dillon 	HtmlStart = time(NULL);
1008b485838SMatthew Dillon 
1018b485838SMatthew Dillon 	asprintf(&ReportPath, "%s/Report", LogsPath);
1028b485838SMatthew Dillon 	if (stat(ReportPath, &st) < 0 && mkdir(ReportPath, 0755) < 0)
1038b485838SMatthew Dillon 		dfatal("Unable to create %s", ReportPath);
1048b485838SMatthew Dillon 	for (i = 0; CopyFilesAry[i]; ++i) {
1058b485838SMatthew Dillon 		asprintf(&src, "%s/%s", SCRIPTPATH(SCRIPTDIR), CopyFilesAry[i]);
1068b485838SMatthew Dillon 		if (strcmp(CopyFilesAry[i], "progress.html") == 0) {
1078b485838SMatthew Dillon 			asprintf(&dst, "%s/index.html", ReportPath);
1088b485838SMatthew Dillon 		} else {
1098b485838SMatthew Dillon 			asprintf(&dst, "%s/%s", ReportPath, CopyFilesAry[i]);
1108b485838SMatthew Dillon 		}
1118b485838SMatthew Dillon 		copyfile(src, dst);
1128b485838SMatthew Dillon 		free(src);
1138b485838SMatthew Dillon 		free(dst);
1148b485838SMatthew Dillon 	}
1158b485838SMatthew Dillon 
1168b485838SMatthew Dillon 	asprintf(&src, "%s/summary.json", ReportPath);
1178b485838SMatthew Dillon 	remove(src);
1188b485838SMatthew Dillon 	free(src);
1198b485838SMatthew Dillon 
1208b485838SMatthew Dillon 	t = time(NULL);
1218b485838SMatthew Dillon 	gmtime_r(&t, &tmm);
1228b485838SMatthew Dillon 	strftime(KickOff_Buf, sizeof(KickOff_Buf),
1238b485838SMatthew Dillon 		 " %d-%b-%Y %H:%M:%S %Z", &tmm);
1248b485838SMatthew Dillon 
1258b485838SMatthew Dillon 	dir = opendir(ReportPath);
1268b485838SMatthew Dillon 	if (dir == NULL)
1278b485838SMatthew Dillon 		dfatal("Unable to scan %s", ReportPath);
1288b485838SMatthew Dillon 	while ((den = readdir(dir)) != NULL) {
1298b485838SMatthew Dillon 		len = strlen(den->d_name);
1308b485838SMatthew Dillon 		if (len > 13 &&
1318b485838SMatthew Dillon 		    strcmp(den->d_name + len - 13, "_history.json") == 0) {
1328b485838SMatthew Dillon 			asprintf(&src, "%s/%s", ReportPath, den->d_name);
1338b485838SMatthew Dillon 			remove(src);
1348b485838SMatthew Dillon 			free(src);
1358b485838SMatthew Dillon 		}
1368b485838SMatthew Dillon 	}
1378b485838SMatthew Dillon 	closedir(dir);
1388b485838SMatthew Dillon 
1398b485838SMatthew Dillon 	/*
1408b485838SMatthew Dillon 	 * First history file
1418b485838SMatthew Dillon 	 */
1428b485838SMatthew Dillon 	HistNum = 0;
1438b485838SMatthew Dillon 	EntryNum = 1;
144ea37671dSMatthew Dillon }
145ea37671dSMatthew Dillon 
146ea37671dSMatthew Dillon static void
HtmlDone(void)147ea37671dSMatthew Dillon HtmlDone(void)
148ea37671dSMatthew Dillon {
1498b485838SMatthew Dillon 	int i;
1508b485838SMatthew Dillon 
1518b485838SMatthew Dillon 	for (i = 0; i < MaxWorkers; ++i) {
1528b485838SMatthew Dillon 		if (HtmlSlots[i])
1538b485838SMatthew Dillon 			free(HtmlSlots[i]);
1548b485838SMatthew Dillon 	}
1558b485838SMatthew Dillon 	free(HtmlSlots);
1568b485838SMatthew Dillon 	HtmlSlots = NULL;
157ea37671dSMatthew Dillon }
158ea37671dSMatthew Dillon 
159ea37671dSMatthew Dillon static void
HtmlReset(void)160ea37671dSMatthew Dillon HtmlReset(void)
161ea37671dSMatthew Dillon {
162ea37671dSMatthew Dillon }
163ea37671dSMatthew Dillon 
164ea37671dSMatthew Dillon static void
HtmlUpdate(worker_t * work,const char * portdir)1658b485838SMatthew Dillon HtmlUpdate(worker_t *work, const char *portdir)
166ea37671dSMatthew Dillon {
1678b485838SMatthew Dillon 	const char *phase;
1688b485838SMatthew Dillon 	const char *origin;
1698b485838SMatthew Dillon 	time_t t;
1708b485838SMatthew Dillon 	int i = work->index;
1718b485838SMatthew Dillon 	int h;
1728b485838SMatthew Dillon 	int m;
1738b485838SMatthew Dillon 	int s;
1748b485838SMatthew Dillon 	int clear;
1758b485838SMatthew Dillon 	char elapsed_buf[32];
1768b485838SMatthew Dillon 	char lines_buf[32];
1778b485838SMatthew Dillon 
1788b485838SMatthew Dillon 	phase = "Unknown";
1798b485838SMatthew Dillon 	origin = "";
1808b485838SMatthew Dillon 	clear = 0;
1818b485838SMatthew Dillon 
1828b485838SMatthew Dillon 	switch(work->state) {
1838b485838SMatthew Dillon 	case WORKER_NONE:
1848b485838SMatthew Dillon 		phase = "None";
1858b485838SMatthew Dillon 		/* fall through */
1868b485838SMatthew Dillon 	case WORKER_IDLE:
1878b485838SMatthew Dillon 		if (work->state == WORKER_IDLE)
1888b485838SMatthew Dillon 			phase = "Idle";
1898b485838SMatthew Dillon 		clear = 1;
1908b485838SMatthew Dillon 		break;
1918b485838SMatthew Dillon 	case WORKER_FAILED:
1928b485838SMatthew Dillon 		if (work->state == WORKER_FAILED)
1938b485838SMatthew Dillon 			phase = "Failed";
1948b485838SMatthew Dillon 		/* fall through */
1958b485838SMatthew Dillon 	case WORKER_EXITING:
1968b485838SMatthew Dillon 		if (work->state == WORKER_EXITING)
1978b485838SMatthew Dillon 			phase = "Exiting";
1988b485838SMatthew Dillon 		return;
1998b485838SMatthew Dillon 		/* NOT REACHED */
2008b485838SMatthew Dillon 	case WORKER_PENDING:
2018b485838SMatthew Dillon 		phase = "Pending";
2028b485838SMatthew Dillon 		break;
2038b485838SMatthew Dillon 	case WORKER_RUNNING:
2048b485838SMatthew Dillon 		phase = "Running";
2058b485838SMatthew Dillon 		break;
2068b485838SMatthew Dillon 	case WORKER_DONE:
2078b485838SMatthew Dillon 		phase = "Done";
2088b485838SMatthew Dillon 		break;
2098b485838SMatthew Dillon 	case WORKER_FROZEN:
2108b485838SMatthew Dillon 		phase = "FROZEN";
2118b485838SMatthew Dillon 		break;
2128b485838SMatthew Dillon 	default:
2138b485838SMatthew Dillon 		break;
2148b485838SMatthew Dillon 	}
2158b485838SMatthew Dillon 
2168b485838SMatthew Dillon 	if (clear) {
2178b485838SMatthew Dillon 		SNPRINTF(elapsed_buf, "%s", " --:--:--");
2188b485838SMatthew Dillon 		SNPRINTF(lines_buf, "%s", "");
2198b485838SMatthew Dillon 		origin = "";
2208b485838SMatthew Dillon 	} else {
2218b485838SMatthew Dillon 		t = time(NULL) - work->start_time;
2228b485838SMatthew Dillon 		s = t % 60;
2238b485838SMatthew Dillon 		m = t / 60 % 60;
2248b485838SMatthew Dillon 		h = t / 60 / 60;
2258b485838SMatthew Dillon 		if (h > 99)
2268b485838SMatthew Dillon 			SNPRINTF(elapsed_buf, "%3d:%02d:%02d", h, m, s);
2278b485838SMatthew Dillon 		else
2288b485838SMatthew Dillon 			SNPRINTF(elapsed_buf, " %02d:%02d:%02d", h, m, s);
2298b485838SMatthew Dillon 
2308b485838SMatthew Dillon 		if (work->state == WORKER_RUNNING)
2318b485838SMatthew Dillon 			phase = getphasestr(work->phase);
2328b485838SMatthew Dillon 
2338b485838SMatthew Dillon 		/*
2348b485838SMatthew Dillon 		 * When called from the monitor frontend portdir has to be
2358b485838SMatthew Dillon 		 * passed in directly because work->pkg is not mapped.
2368b485838SMatthew Dillon 		 */
2378b485838SMatthew Dillon 		if (portdir)
2388b485838SMatthew Dillon 			origin = portdir;
2398b485838SMatthew Dillon 		else if (work->pkg)
2408b485838SMatthew Dillon 			origin = work->pkg->portdir;
2418b485838SMatthew Dillon 		else
2428b485838SMatthew Dillon 			origin = "";
2438b485838SMatthew Dillon 
2448b485838SMatthew Dillon 		SNPRINTF(lines_buf, "%ld", work->lines);
2458b485838SMatthew Dillon 	}
2468b485838SMatthew Dillon 
2478b485838SMatthew Dillon 	/*
2488b485838SMatthew Dillon 	 * Update the summary information
2498b485838SMatthew Dillon 	 */
2508b485838SMatthew Dillon 	if (HtmlSlots[i])
2518b485838SMatthew Dillon 		free(HtmlSlots[i]);
2528b485838SMatthew Dillon 	asprintf(&HtmlSlots[i],
2538b485838SMatthew Dillon 		 "  {\n"
2548b485838SMatthew Dillon 		 "     \"ID\":\"%02d\"\n"
2558b485838SMatthew Dillon 		 "     ,\"elapsed\":\"%s\"\n"
2568b485838SMatthew Dillon 		 "     ,\"phase\":\"%s\"\n"
2578b485838SMatthew Dillon 		 "     ,\"origin\":\"%s\"\n"
2588b485838SMatthew Dillon 		 "     ,\"lines\":\"%s\"\n"
2598b485838SMatthew Dillon 		 "  }\n",
2608b485838SMatthew Dillon 		 i,
2618b485838SMatthew Dillon 		 elapsed_buf,
2628b485838SMatthew Dillon 		 phase,
2638b485838SMatthew Dillon 		 origin,
2648b485838SMatthew Dillon 		 lines_buf
2658b485838SMatthew Dillon 	);
266ea37671dSMatthew Dillon }
267ea37671dSMatthew Dillon 
268ea37671dSMatthew Dillon static void
HtmlUpdateTop(topinfo_t * info)2698b485838SMatthew Dillon HtmlUpdateTop(topinfo_t *info)
270ea37671dSMatthew Dillon {
2718b485838SMatthew Dillon 	char *path;
2728b485838SMatthew Dillon 	char *dst;
2738b485838SMatthew Dillon 	FILE *fp;
2748b485838SMatthew Dillon 	int i;
2758b485838SMatthew Dillon 	char elapsed_buf[32];
2768b485838SMatthew Dillon 	char swap_buf[32];
2778b485838SMatthew Dillon 	char load_buf[32];
2788b485838SMatthew Dillon 
2798b485838SMatthew Dillon 	/*
2808b485838SMatthew Dillon 	 * Be sure to do the first update and final update, but otherwise
2818b485838SMatthew Dillon 	 * only update every 10 seconds or so.
2828b485838SMatthew Dillon 	 */
2838b485838SMatthew Dillon 	if (HtmlLast && (int)(time(NULL) - HtmlLast) < 10 && info->active)
2848b485838SMatthew Dillon 		return;
2858b485838SMatthew Dillon 	HtmlLast = time(NULL);
2868b485838SMatthew Dillon 
2878b485838SMatthew Dillon 	if (info->h > 99) {
2888b485838SMatthew Dillon 		SNPRINTF(elapsed_buf, "%3d:%02d:%02d",
2898b485838SMatthew Dillon 			 info->h, info->m, info->s);
2908b485838SMatthew Dillon 	} else {
2918b485838SMatthew Dillon 		SNPRINTF(elapsed_buf, " %02d:%02d:%02d",
2928b485838SMatthew Dillon 			 info->h, info->m, info->s);
2938b485838SMatthew Dillon 	}
2948b485838SMatthew Dillon 
2958b485838SMatthew Dillon 	if (info->noswap)
2968b485838SMatthew Dillon 		SNPRINTF(swap_buf, "-    ");
2978b485838SMatthew Dillon 	else
2988b485838SMatthew Dillon 		SNPRINTF(swap_buf, "%5.1f", info->dswap);
2998b485838SMatthew Dillon 
3008b485838SMatthew Dillon 	if (info->dload[0] > 999.9)
3018b485838SMatthew Dillon 		SNPRINTF(load_buf, "%5.0f", info->dload[0]);
3028b485838SMatthew Dillon 	else
3038b485838SMatthew Dillon 		SNPRINTF(load_buf, "%5.1f", info->dload[0]);
3048b485838SMatthew Dillon 
3058b485838SMatthew Dillon 	asprintf(&path, "%s/summary.json.new", ReportPath);
3068b485838SMatthew Dillon 	asprintf(&dst, "%s/summary.json", ReportPath);
3078b485838SMatthew Dillon 	fp = fopen(path, "we");
3088b485838SMatthew Dillon 	if (!fp)
3098b485838SMatthew Dillon 		ddassert(0);
3108b485838SMatthew Dillon 	if (fp) {
3118b485838SMatthew Dillon 		fprintf(fp,
3128b485838SMatthew Dillon 			"{\n"
3138b485838SMatthew Dillon 			"  \"profile\":\"%s\"\n"
3148b485838SMatthew Dillon 			"  ,\"kickoff\":\"%s\"\n"
3158b485838SMatthew Dillon 			"  ,\"kfiles\":%d\n"
3168b485838SMatthew Dillon 			"  ,\"active\":%d\n"
3178b485838SMatthew Dillon 			"  ,\"stats\":{\n"
3188b485838SMatthew Dillon 			"    \"queued\":%d\n"
3198b485838SMatthew Dillon 			"    ,\"built\":%d\n"
3208b485838SMatthew Dillon 			"    ,\"failed\":%d\n"
3218b485838SMatthew Dillon 			"    ,\"ignored\":%d\n"
3228b485838SMatthew Dillon 			"    ,\"skipped\":%d\n"
3238b485838SMatthew Dillon 			"    ,\"remains\":%d\n"
324*51705b28SAntonio Huete Jimenez 			"    ,\"meta\":%d\n"
3258b485838SMatthew Dillon 			"    ,\"elapsed\":\"%s\"\n"
3268b485838SMatthew Dillon 			"    ,\"pkghour\":%d\n"
3278b485838SMatthew Dillon 			"    ,\"impulse\":%d\n"
3288b485838SMatthew Dillon 			"    ,\"swapinfo\":\"%s\"\n"
3298b485838SMatthew Dillon 			"    ,\"load\":\"%s\"\n"
3308b485838SMatthew Dillon 			"  }\n",
3318b485838SMatthew Dillon 			Profile,
3328b485838SMatthew Dillon 			KickOff_Buf,
3338b485838SMatthew Dillon 			HistNum,		/* kfiles */
3348b485838SMatthew Dillon 			info->active,		/* active */
3358b485838SMatthew Dillon 
3368b485838SMatthew Dillon 			info->total,		/* queued */
3378b485838SMatthew Dillon 			info->successful,	/* built */
3388b485838SMatthew Dillon 			info->failed,		/* failed */
3398b485838SMatthew Dillon 			info->ignored,		/* ignored */
3408b485838SMatthew Dillon 			info->skipped,		/* skipped */
3418b485838SMatthew Dillon 			info->remaining,	/* remaining */
342*51705b28SAntonio Huete Jimenez 			info->meta,		/* meta-nodes */
3438b485838SMatthew Dillon 			elapsed_buf,		/* elapsed */
3448b485838SMatthew Dillon 			info->pkgrate,		/* pkghour */
3458b485838SMatthew Dillon 			info->pkgimpulse,	/* impulse */
3468b485838SMatthew Dillon 			swap_buf,		/* swapinfo */
3478b485838SMatthew Dillon 			load_buf		/* load */
3488b485838SMatthew Dillon 		);
3498b485838SMatthew Dillon 		fprintf(fp,
3508b485838SMatthew Dillon 			"  ,\"builders\":[\n"
3518b485838SMatthew Dillon 		);
3528b485838SMatthew Dillon 		for (i = 0; i < MaxWorkers; ++i) {
3538b485838SMatthew Dillon 			if (HtmlSlots[i]) {
3548b485838SMatthew Dillon 				if (i)
3558b485838SMatthew Dillon 					fprintf(fp, ",");
3568b485838SMatthew Dillon 				fwrite(HtmlSlots[i], 1,
3578b485838SMatthew Dillon 				       strlen(HtmlSlots[i]), fp);
3588b485838SMatthew Dillon 			} else {
3598b485838SMatthew Dillon 				fprintf(fp,
3608b485838SMatthew Dillon 					"   %s{\n"
3618b485838SMatthew Dillon 					"     \"ID\":\"%02d\"\n"
3628b485838SMatthew Dillon 					"     ,\"elapsed\":\"Shutdown\"\n"
3638b485838SMatthew Dillon 					"     ,\"phase\":\"\"\n"
3648b485838SMatthew Dillon 					"     ,\"origin\":\"\"\n"
3658b485838SMatthew Dillon 					"     ,\"lines\":\"\"\n"
3668b485838SMatthew Dillon 					"    }\n",
3678b485838SMatthew Dillon 					(i ? "," : ""),
3688b485838SMatthew Dillon 					i
3698b485838SMatthew Dillon 				);
3708b485838SMatthew Dillon 			}
3718b485838SMatthew Dillon 		}
3728b485838SMatthew Dillon 		fprintf(fp,
3738b485838SMatthew Dillon 			"  ]\n"
3748b485838SMatthew Dillon 			"}\n");
3758b485838SMatthew Dillon 		fflush(fp);
3768b485838SMatthew Dillon 		fclose(fp);
3778b485838SMatthew Dillon 	}
3788b485838SMatthew Dillon 	rename(path, dst);
3798b485838SMatthew Dillon 	free(path);
3808b485838SMatthew Dillon 	free(dst);
381ea37671dSMatthew Dillon }
382ea37671dSMatthew Dillon 
383ea37671dSMatthew Dillon static void
HtmlUpdateLogs(void)384ea37671dSMatthew Dillon HtmlUpdateLogs(void)
385ea37671dSMatthew Dillon {
386ea37671dSMatthew Dillon }
387ea37671dSMatthew Dillon 
388ea37671dSMatthew Dillon static void
HtmlUpdateCompletion(worker_t * work,int dlogid,pkg_t * pkg,const char * reason,const char * skipbuf)38964b61b2eSMatthew Dillon HtmlUpdateCompletion(worker_t *work, int dlogid, pkg_t *pkg,
39064b61b2eSMatthew Dillon 		     const char *reason, const char *skipbuf)
3918b485838SMatthew Dillon {
3928b485838SMatthew Dillon 	FILE *fp;
3938b485838SMatthew Dillon 	char *path;
3948b485838SMatthew Dillon 	char elapsed_buf[64];
3958b485838SMatthew Dillon 	struct stat st;
3968b485838SMatthew Dillon 	time_t t;
3978b485838SMatthew Dillon 	int s, m, h;
3988b485838SMatthew Dillon 	int slot;
3998b485838SMatthew Dillon 	const char *result;
4006f22c855SMatthew Dillon 	char *mreason;
4018b485838SMatthew Dillon 
40264b61b2eSMatthew Dillon 	if (skipbuf[0] == 0)
40364b61b2eSMatthew Dillon 		skipbuf = "0";
40464b61b2eSMatthew Dillon 	else if (skipbuf[0] == ' ')
40564b61b2eSMatthew Dillon 		++skipbuf;
40664b61b2eSMatthew Dillon 
4076f22c855SMatthew Dillon 	mreason = NULL;
4088b485838SMatthew Dillon 	if (work) {
4098b485838SMatthew Dillon 		t = time(NULL) - work->start_time;
4108b485838SMatthew Dillon 		s = t % 60;
4118b485838SMatthew Dillon 		m = t / 60 % 60;
4128b485838SMatthew Dillon 		h = t / 60 / 60;
4138b485838SMatthew Dillon 		SNPRINTF(elapsed_buf, "%02d:%02d:%02d", h, m, s);
4148b485838SMatthew Dillon 		slot = work->index;
4158b485838SMatthew Dillon 	} else {
4168b485838SMatthew Dillon 		slot = -1;
4178b485838SMatthew Dillon 		elapsed_buf[0] = 0;
4188b485838SMatthew Dillon 	}
4198b485838SMatthew Dillon 
4208b485838SMatthew Dillon 	switch(dlogid) {
4218b485838SMatthew Dillon 	case DLOG_SUCC:
422*51705b28SAntonio Huete Jimenez 		if (pkg->flags & PKGF_DUMMY)
423*51705b28SAntonio Huete Jimenez 			result = "meta";
424*51705b28SAntonio Huete Jimenez 		else
4258b485838SMatthew Dillon 			result = "built";
4268b485838SMatthew Dillon 		break;
4278b485838SMatthew Dillon 	case DLOG_FAIL:
4288b485838SMatthew Dillon 		result = "failed";
4296f22c855SMatthew Dillon 		if (work) {
4306f22c855SMatthew Dillon 			asprintf(&mreason, "%s:%s",
4316f22c855SMatthew Dillon 				 getphasestr(work->phase),
4326f22c855SMatthew Dillon 				 reason);
4336f22c855SMatthew Dillon 		} else {
4346f22c855SMatthew Dillon 			asprintf(&mreason, "unknown:%s", reason);
4356f22c855SMatthew Dillon 		}
4366f22c855SMatthew Dillon 		reason = mreason;
4378b485838SMatthew Dillon 		break;
4388b485838SMatthew Dillon 	case DLOG_IGN:
4398b485838SMatthew Dillon 		result = "ignored";
44064b61b2eSMatthew Dillon 		asprintf(&mreason, "%s:|:%s", reason, skipbuf);
4416f22c855SMatthew Dillon 		reason = mreason;
4428b485838SMatthew Dillon 		break;
4438b485838SMatthew Dillon 	case DLOG_SKIP:
4448b485838SMatthew Dillon 		result = "skipped";
4458b485838SMatthew Dillon 		break;
4468b485838SMatthew Dillon 	default:
4478b485838SMatthew Dillon 		result = "Unknown";
4488b485838SMatthew Dillon 		break;
4498b485838SMatthew Dillon 	}
4508b485838SMatthew Dillon 
4518b485838SMatthew Dillon 	t = time(NULL) - HtmlStart;
4528b485838SMatthew Dillon 	s = t % 60;
4538b485838SMatthew Dillon 	m = t / 60 % 60;
4548b485838SMatthew Dillon 	h = t / 60 / 60;
4558b485838SMatthew Dillon 
4568b485838SMatthew Dillon 	/*
4578b485838SMatthew Dillon 	 * Cycle history file as appropriate, includes initial file handling.
4588b485838SMatthew Dillon 	 */
4598b485838SMatthew Dillon 	if (HistNum == 0)
4608b485838SMatthew Dillon 		HistNum = 1;
4618b485838SMatthew Dillon 	asprintf(&path, "%s/%02d_history.json", ReportPath, HistNum);
4628b485838SMatthew Dillon 	if (stat(path, &st) < 0) {
4638b485838SMatthew Dillon 		fp = fopen(path, "we");
4648b485838SMatthew Dillon 	} else if (st.st_size > 50000) {
4658b485838SMatthew Dillon 		++HistNum;
4668b485838SMatthew Dillon 		free(path);
4678b485838SMatthew Dillon 		asprintf(&path, "%s/%02d_history.json", ReportPath, HistNum);
4688b485838SMatthew Dillon 		fp = fopen(path, "we");
4698b485838SMatthew Dillon 	} else {
4708b485838SMatthew Dillon 		fp = fopen(path, "r+e");
4718b485838SMatthew Dillon 		fseek(fp, 0, SEEK_END);
4728b485838SMatthew Dillon 	}
4738b485838SMatthew Dillon 
4748b485838SMatthew Dillon 	if (fp) {
4758b485838SMatthew Dillon 		if (ftell(fp) == 0) {
4768b485838SMatthew Dillon 			fprintf(fp, "[\n");
4778b485838SMatthew Dillon 		} else {
4788b485838SMatthew Dillon 			fseek(fp, -2, SEEK_END);
4798b485838SMatthew Dillon 		}
4808b485838SMatthew Dillon 		fprintf(fp,
4818b485838SMatthew Dillon 			"  %s{\n"
4828b485838SMatthew Dillon 			"   \"entry\":%d\n"
4838b485838SMatthew Dillon 			"   ,\"elapsed\":\"%02d:%02d:%02d\"\n"
4848b485838SMatthew Dillon 			"   ,\"ID\":\"%02d\"\n"
4858b485838SMatthew Dillon 			"   ,\"result\":\"%s\"\n"
4868b485838SMatthew Dillon 			"   ,\"origin\":\"%s\"\n"
4876f22c855SMatthew Dillon 			"   ,\"info\":\"%s\"\n"
4888b485838SMatthew Dillon 			"   ,\"duration\":\"%s\"\n"
4898b485838SMatthew Dillon 			"  }\n"
4908b485838SMatthew Dillon 			"]\n",
4918b485838SMatthew Dillon 			((ftell(fp) > 10) ? "," : ""),
4928b485838SMatthew Dillon 			EntryNum,
4938b485838SMatthew Dillon 			h, m, s,
4948b485838SMatthew Dillon 			slot,
4958b485838SMatthew Dillon 			result,
4968b485838SMatthew Dillon 			pkg->portdir,
4978b485838SMatthew Dillon 			dequote(reason),
4988b485838SMatthew Dillon 			elapsed_buf
4998b485838SMatthew Dillon 		);
5008b485838SMatthew Dillon 		++EntryNum;
5018b485838SMatthew Dillon 		fclose(fp);
5028b485838SMatthew Dillon 
5038b485838SMatthew Dillon 	}
5048b485838SMatthew Dillon 	free(path);
5056f22c855SMatthew Dillon 	if (mreason)
5066f22c855SMatthew Dillon 		free(mreason);
5078b485838SMatthew Dillon }
5088b485838SMatthew Dillon 
5098b485838SMatthew Dillon static void
HtmlSync(void)510ea37671dSMatthew Dillon HtmlSync(void)
511ea37671dSMatthew Dillon {
512ea37671dSMatthew Dillon }
513ea37671dSMatthew Dillon 
514ea37671dSMatthew Dillon runstats_t HtmlRunStats = {
515ea37671dSMatthew Dillon 	.init = HtmlInit,
516ea37671dSMatthew Dillon 	.done = HtmlDone,
517ea37671dSMatthew Dillon 	.reset = HtmlReset,
518ea37671dSMatthew Dillon 	.update = HtmlUpdate,
519ea37671dSMatthew Dillon 	.updateTop = HtmlUpdateTop,
520ea37671dSMatthew Dillon 	.updateLogs = HtmlUpdateLogs,
5218b485838SMatthew Dillon 	.updateCompletion = HtmlUpdateCompletion,
522ea37671dSMatthew Dillon 	.sync = HtmlSync
523ea37671dSMatthew Dillon };
524