2089 lines
79 KiB
C
2089 lines
79 KiB
C
/*
|
|
* distromatic - tool for RPM based repositories
|
|
*
|
|
* Copyright (C) 2004-2022 by Silvan Calarco <silvan.calarco@mambasoft.it>
|
|
* Copyright (C) 2006 by Davide Madrisan <davide.madrisan@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of version 2 of the GNU General Public License as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY, to the extent permitted by law; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <linux/limits.h>
|
|
|
|
#include "distromatic.h"
|
|
#include "changelog.h"
|
|
#include "reports.h"
|
|
#include "rpmfunctions.h"
|
|
#include "functions.h"
|
|
#include "requirelist.h"
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
|
|
#define HTMLSTATS_NUM 400
|
|
#define HTMLOLDSTATS_NUM 400
|
|
#define RSSSTATS_NUM 20
|
|
|
|
char *groupdirname(char *group,char *dest)
|
|
{
|
|
strcpy(dest,group);
|
|
|
|
unsigned int i=0;
|
|
|
|
while (dest[i] && i<PATH_MAX) {
|
|
switch (dest[i]) {
|
|
case '/': dest[i]=':'; break;
|
|
case ' ': dest[i]='_'; break;
|
|
default: break;
|
|
}
|
|
i++;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
int
|
|
comparePackagers(const void *ptr1, const void *ptr2)
|
|
{
|
|
int ret;
|
|
|
|
if (! (*(struct headerSourceList **)ptr1)->packager) return -1;
|
|
else if (! (*(struct headerSourceList **)ptr2)->packager) return +1;
|
|
else {
|
|
ret=strcasecmp((*(struct headerSourceList **)ptr1)->packager->name,
|
|
(*(struct headerSourceList **)ptr2)->packager->name);
|
|
|
|
if (!ret) {
|
|
ret=strcasecmp((*(struct headerSourceList **)ptr1)->name,
|
|
(*(struct headerSourceList **)ptr2)->name);
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
int
|
|
printHTMLWarnings(FILE *fout, struct configTag *configtag, struct headerSourceList* pkg, int mode) {
|
|
|
|
char warningsfile[PATH_MAX];
|
|
char buf[PATH_MAX];
|
|
struct stat s;
|
|
FILE *fin;
|
|
int n;
|
|
struct warningList *firstwarning,*currwarning;
|
|
|
|
if (!pkg) return 0;
|
|
|
|
snprintf(warningsfile,PATH_MAX,"%swarnings/%s.in",configtag->html_dir,pkg->name);
|
|
|
|
/* find pointer to first warning also looking into old packages */
|
|
firstwarning = pkg->firstwarning;
|
|
while (!firstwarning && pkg->old) {
|
|
pkg = pkg->old;
|
|
firstwarning = pkg->firstwarning;
|
|
}
|
|
|
|
if (firstwarning || !stat(warningsfile,&s)) {
|
|
if (mode == 0) {
|
|
fprintf(fout,
|
|
"<img src=\"%s/warning-icon.png\" title=\"",
|
|
configtag->configdefaults->url_dir);
|
|
} else if (mode == 1) {
|
|
fprintf(fout,
|
|
"<div class=\"warning\"><img src=\"%s/warning-icon.png\" title=\"Beware: this package has warnings.\"> <b>Beware, this package has warnings:</b><br>",
|
|
configtag->configdefaults->url_dir);
|
|
}
|
|
}
|
|
|
|
if (!stat(warningsfile,&s)) {
|
|
|
|
if ((fin = fopen(warningsfile, "r")) == NULL) {
|
|
perror(warningsfile);
|
|
return 0;
|
|
}
|
|
|
|
fprintf(fout," • Comment:");
|
|
while (!feof(fin)) {
|
|
n = fread(buf, 1, sizeof(buf), fin);
|
|
fwrite(buf,1,n,fout);
|
|
}
|
|
if (mode == 0) {
|
|
fprintf(fout,"\n");
|
|
} else if (mode == 1) {
|
|
fprintf(fout,"<br>");
|
|
}
|
|
fclose(fin);
|
|
}
|
|
|
|
currwarning = firstwarning;
|
|
while (currwarning || pkg->old) {
|
|
if (currwarning) {
|
|
if (mode == 0) {
|
|
fprintf(fout," • %s\n",currwarning->text);
|
|
} else if (mode == 1) {
|
|
fprintf(fout," • %s<br>",currwarning->text);
|
|
} else if (mode == 2) {
|
|
fprintf(fout,"%s %s\n",pkg->name,currwarning->text);
|
|
}
|
|
currwarning = currwarning->next;
|
|
}
|
|
while (!currwarning && pkg->old) {
|
|
/* print warnings coming from updated packages */
|
|
pkg = pkg->old;
|
|
currwarning = pkg->firstwarning;
|
|
}
|
|
}
|
|
if (firstwarning || !stat(warningsfile,&s)) {
|
|
if (mode == 0) {
|
|
fprintf(fout,"\">");
|
|
} else if (mode == 1) {
|
|
fprintf(fout,"</div><br>\n");
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void printpkgicon(FILE *fout, struct configTag *configtag, struct headerSourceList *s) {
|
|
|
|
char buffer[PATH_MAX];
|
|
char strdate[16];
|
|
int i;
|
|
|
|
if (s->old) {
|
|
fprintf(fout,
|
|
"<img src=\"%s/pkgup.png\" ",
|
|
configtag->configdefaults->url_dir);
|
|
} else {
|
|
fprintf(fout,
|
|
"<img src=\"%s/pkg.png\" ",
|
|
configtag->configdefaults->url_dir);
|
|
}
|
|
|
|
if (s->changelog) {
|
|
simpleTimeToHuman(s->changelog->time, (humanDate *) & strdate);
|
|
fprintf(fout,
|
|
"title=\"%s - %s (%s)\n%s",
|
|
strdate,
|
|
s->changelog->pkg->name,
|
|
s->changelog->release,
|
|
htmlcleanNoBr(s->changelog->text,buffer,PATH_MAX));
|
|
if (s->changelog->next) {
|
|
simpleTimeToHuman(s->changelog->next->time, (humanDate *) & strdate);
|
|
fprintf(fout,
|
|
"\n%s - %s (%s)\n%s",
|
|
strdate,
|
|
s->changelog->next->pkg->name,
|
|
s->changelog->next->release,
|
|
htmlcleanNoBr(s->changelog->next->text,buffer,PATH_MAX));
|
|
}
|
|
} else {
|
|
fprintf(fout,
|
|
"title=\"WARNING: missing changelog");
|
|
}
|
|
|
|
fprintf(fout,"\n\nArchs:");
|
|
for (i = 0; i < ARCHS_MAX && configtag->arch[i]; i++) {
|
|
if (s->firstchild[i]) fprintf(fout," %s", configtag->arch[i]);
|
|
}
|
|
|
|
if (s->old) {
|
|
fprintf(fout,
|
|
"\n\nUpdates %s(%s,%s,%ld:%s-%s)\">",
|
|
s->old->name,
|
|
configtag->repository[s->old->altrepository]->tag,
|
|
s->old->arch,
|
|
s->old->epoch,
|
|
s->old->version,
|
|
s->old->release);
|
|
} else {
|
|
fprintf(fout, "\">");
|
|
}
|
|
|
|
}
|
|
|
|
int
|
|
generateMaintainersPages(struct configTag *configtag)
|
|
{
|
|
char idxfile[PATH_MAX],outfile[PATH_MAX],unmaintfile[PATH_MAX];
|
|
FILE *idx=NULL,*out=NULL,*unmaint=NULL;
|
|
int i,pkgnum,unmaintpkgnum;
|
|
struct stat buf;
|
|
struct Packager *currpackager = NULL;
|
|
|
|
/* sort headersourcelistvec by packager name */
|
|
qsort((void *) &configtag->stats.headersourcelistvec[0],
|
|
configtag->stats.headersourcecount, sizeof(struct headerSourceList *),
|
|
comparePackagers);
|
|
|
|
snprintf(outfile, PATH_MAX, "%smaintainers", configtag->html_dir);
|
|
if (stat(outfile,&buf)) {
|
|
if (mkdir(outfile,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory; aborting.",outfile);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(buf.st_mode)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory, a file with this name already exists; aborting.",outfile);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
snprintf(idxfile, PATH_MAX, "%s_maintainers.inc", configtag->html_dir);
|
|
|
|
if ((idx = fopen(idxfile, "w")) == NULL) {
|
|
perror(idxfile);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(idx,
|
|
"<br>Maintainers for packages in the <b>%s</b> repository (%s):<br><br>\n",
|
|
configtag->tag,
|
|
configtag->description);
|
|
|
|
snprintf(unmaintfile, PATH_MAX, "%smaintainers/unmaintained.inc", configtag->html_dir);
|
|
|
|
if ((unmaint = fopen(unmaintfile, "w")) == NULL) {
|
|
perror(unmaintfile);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(unmaint,
|
|
"<br>Packages that are <b>unmaintained</b> in the %s repository:<br><br>\n",configtag->tag);
|
|
|
|
i=0;
|
|
out=NULL;
|
|
pkgnum=0;
|
|
unmaintpkgnum=0;
|
|
|
|
while (i < configtag->stats.headersourcecount) {
|
|
if ((configtag->stats.headersourcelistvec[i])->packager) {
|
|
|
|
if ((i == 0) ||
|
|
((configtag->stats.headersourcelistvec[i-1])->packager != (configtag->stats.headersourcelistvec[i])->packager)) {
|
|
|
|
if ((configtag->stats.headersourcelistvec[i])->packager->role &
|
|
PACKAGER_ROLE_MAINTAINER) {
|
|
|
|
snprintf(outfile, PATH_MAX, "%smaintainers/%s.inc",
|
|
configtag->html_dir,
|
|
(configtag->stats.headersourcelistvec[i])->packager->name);
|
|
|
|
if ((out = fopen(outfile, "w")) == NULL) {
|
|
perror(outfile);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(out,
|
|
"<br>Packages maintained by <b>%s</b> in the %s repository:<br><br>\n",
|
|
(configtag->stats.headersourcelistvec[i])->packager->name,
|
|
configtag->tag);
|
|
} // new maintainer file created
|
|
|
|
} // check for changed packager
|
|
|
|
if ((configtag->stats.headersourcelistvec[i])->packager->role & PACKAGER_ROLE_MAINTAINER) {
|
|
fprintf(out,
|
|
"<a href=\"%stag=%s&pkg=%s.source\">%s</a>: %s<br>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->summary);
|
|
pkgnum++;
|
|
|
|
if ((i+1 >= configtag->stats.headersourcecount) ||
|
|
((configtag->stats.headersourcelistvec[i])->packager !=
|
|
(configtag->stats.headersourcelistvec[i+1])->packager)) {
|
|
|
|
fprintf(idx,
|
|
"<a href=\"%stag=%s&maintainer=%s\">%s </a>(pkg:%d; act:%5.2f%%)<br>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
configtag->stats.headersourcelistvec[i]->packager->name,
|
|
configtag->stats.headersourcelistvec[i]->packager->name,
|
|
pkgnum,
|
|
((double)(configtag->stats.headersourcelistvec[i]->packager->changes_count) * 100) / configtag->stats.changelog_total );
|
|
pkgnum=0;
|
|
fclose(out);
|
|
|
|
}
|
|
|
|
} else { // unmaintained package
|
|
|
|
fprintf(unmaint,
|
|
"<a href=\"%stag=%s&pkg=%s.source\">%s</a>: %s<br>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->summary);
|
|
unmaintpkgnum++;
|
|
|
|
}
|
|
|
|
}
|
|
i++;
|
|
} // while
|
|
|
|
fclose(unmaint);
|
|
|
|
currpackager = firstPackager();
|
|
|
|
// write stats for maintainer with 0 packages but changes (e.g. autodist)
|
|
while (currpackager) {
|
|
if ((currpackager->role & PACKAGER_ROLE_MAINTAINER) &&
|
|
(currpackager->packages_count == 0) &&
|
|
(currpackager->changes_count > 0) ) {
|
|
fprintf(idx,
|
|
"%s (pkg:%d; act:%5.2f%%)<br>\n",
|
|
currpackager->name,
|
|
0,
|
|
((double)(currpackager->changes_count) * 100) / configtag->stats.changelog_total );
|
|
}
|
|
/* else {
|
|
printf("skipped %s packages:%d changes:%d\n",currpackager->name,currpackager->packages_count,currpackager->changes_count);
|
|
}*/
|
|
currpackager = currpackager->next;
|
|
}
|
|
|
|
if (unmaintpkgnum)
|
|
fprintf(idx,
|
|
"<a href=\"%stag=%s&maintainer=unmaintained\">unmaintained packages</a> (pkg:%d)<br>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
unmaintpkgnum);
|
|
|
|
fclose(idx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
generateStats(struct configTag *configtag,int arch)
|
|
{
|
|
char outfile[PATH_MAX];
|
|
char rssfile[PATH_MAX];
|
|
char buffer[PATH_MAX];
|
|
FILE *htmlout=NULL,*htmloldout,*rssout,*groupout;
|
|
struct stat buf;
|
|
int i,pkgnum;
|
|
humanDate strdate,strolddate;
|
|
sizeString strsize;
|
|
|
|
struct tm *ytm;
|
|
time_t timesec;
|
|
|
|
timesec = time(×ec);
|
|
ytm = localtime((time_t *) ×ec);
|
|
ytm->tm_sec = 0;
|
|
ytm->tm_min = 0;
|
|
ytm->tm_hour = 0;
|
|
ytm->tm_mday = 1;
|
|
ytm->tm_mon = 0;
|
|
timesec = mktime(ytm);
|
|
|
|
if (!configtag->configdefaults->html_basedir) {
|
|
return 2;
|
|
}
|
|
|
|
/* sort headersourcelistvec by Group */
|
|
qsort((void *) &configtag->stats.headersourcelistvec[0],
|
|
configtag->stats.headersourcecount, sizeof(struct headerSourceList *),
|
|
compareGroup);
|
|
|
|
snprintf(outfile, PATH_MAX, "%s_groups.inc", configtag->html_dir);
|
|
|
|
if ((groupout = fopen(outfile, "w")) == NULL) {
|
|
perror(outfile);
|
|
return 1;
|
|
}
|
|
|
|
/* create groups directory */
|
|
snprintf(outfile, PATH_MAX, "%sgroups",configtag->html_dir);
|
|
if (stat(outfile,&buf)) {
|
|
if (mkdir(outfile,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory; aborting.",outfile);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(buf.st_mode)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory, a file with this name already exists; aborting.",outfile);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
fprintf(groupout,
|
|
"<br>Groups in the <b>%s</b> repository (%s):<br><br>\n",
|
|
configtag->tag,
|
|
configtag->description);
|
|
|
|
i=0;
|
|
pkgnum=0;
|
|
if (configtag->stats.headersourcecount) do {
|
|
|
|
if (pkgnum==0) {
|
|
|
|
sprintf(outfile, "%sgroups/%s",
|
|
configtag->html_dir,
|
|
groupdirname(configtag->stats.headersourcelistvec[i]->group,buffer));
|
|
|
|
if (stat(outfile,&buf)) {
|
|
if (mkdir(outfile,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory; aborting.",outfile);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(buf.st_mode)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory, a file with this name already exists; aborting.",outfile);
|
|
exit(1);
|
|
}
|
|
}
|
|
strncat(outfile, "/_index.inc", sizeof(outfile) - strlen(outfile));
|
|
if ((htmlout = fopen(outfile, "w")) == NULL) {
|
|
perror(outfile);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(htmlout,
|
|
"<br>Packages in the <b>%s</b> group of the <b>%s</b> repository (%s):<br><br>\n",
|
|
configtag->stats.headersourcelistvec[i]->group,
|
|
configtag->tag,
|
|
configtag->description);
|
|
|
|
}
|
|
fprintf(htmlout,
|
|
"<a href=\"%stag=%s&pkg=%s.source\">%s</a>: %s<br>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->summary);
|
|
i++;
|
|
pkgnum++;
|
|
|
|
if ((i >= configtag->stats.headersourcecount) ||
|
|
(strcmp(configtag->stats.headersourcelistvec[i-1]->group,
|
|
configtag->stats.headersourcelistvec[i]->group))) {
|
|
fprintf(groupout,
|
|
"<a href=\"%stag=%s&group=%s\">%s <b>(%d)</b></a><br>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
groupdirname(configtag->stats.headersourcelistvec[i-1]->group,buffer),
|
|
(configtag->stats.headersourcelistvec)[i-1]->group,
|
|
pkgnum);
|
|
pkgnum=0;
|
|
fclose(htmlout);
|
|
}
|
|
|
|
} while (i < configtag->stats.headersourcecount);
|
|
|
|
if (i>0) {
|
|
fclose(groupout);
|
|
}
|
|
|
|
strcpy(outfile, configtag->html_dir);
|
|
strncat(outfile, "_recent.inc", sizeof(outfile) - strlen(outfile));
|
|
if ((htmlout = fopen(outfile, "w")) == NULL) {
|
|
perror(outfile);
|
|
return 1;
|
|
}
|
|
/*else {
|
|
fprintf(htmlout, "<a href=\"%s/%s/recent.rss\">"
|
|
"<img src=\"%s/feed-icon.png\" "
|
|
"alt=\"RSS 2.0 news feed\"></a>",
|
|
configtag->configdefaults->url_dir,
|
|
configtag->tag,
|
|
configtag->configdefaults->url_dir);
|
|
fprintf(htmlout, "Recent builds:<br>\n");
|
|
}*/
|
|
|
|
strcpy(outfile, configtag->html_dir);
|
|
strncat(outfile, "_oldest.inc", sizeof(outfile) - strlen(outfile));
|
|
if ((htmloldout = fopen(outfile, "w")) == NULL) {
|
|
perror(outfile);
|
|
return 1;
|
|
}
|
|
|
|
/* else {
|
|
fprintf(htmloldout, "Oldest builds:<br>\n");
|
|
}*/
|
|
|
|
strcpy(rssfile, configtag->html_dir);
|
|
strncat(rssfile, "recent.rss", sizeof(rssfile) - strlen(rssfile));
|
|
if ((rssout = fopen(rssfile, "w")) == NULL) {
|
|
perror(rssfile);
|
|
return 1;
|
|
} else {
|
|
fprintf(rssout,"<?xml version=\"1.0\" ?>\n");
|
|
fprintf(rssout,"<rss version=\"2.0\">\n");
|
|
fprintf(rssout,"<channel>\n");
|
|
fprintf(rssout," <title>Recent packages for the %s repository</title>\n",configtag->tag);
|
|
fprintf(rssout," <link>http://%s/%s</link>\n",
|
|
configtag->configdefaults->url_address,
|
|
configtag->configdefaults->url_prefix);
|
|
//fprintf(rssout," <description></description>\n");
|
|
fprintf(rssout," <language>en-us</language>\n");
|
|
fprintf(rssout," <docs>http://blogs.law.harvard.edu/tech/rss</docs>");
|
|
fprintf(rssout," <generator>Distromatic %s</generator>\n",PACKAGE_VERSION);
|
|
}
|
|
|
|
/* sort headersourcelistvec by BuildDate */
|
|
qsort((void *) &configtag->stats.headersourcelistvec[0],
|
|
configtag->stats.headersourcecount, sizeof(struct headerSourceList *),
|
|
compareSourceHeaderBuildDate);
|
|
|
|
fprintf(htmlout, "<a href=\"%stag=%s\">SRPMS</a>(%d;%s)",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
configtag->stats.headersourcecount,
|
|
humanSize(configtag->stats.headersourcesize, &strsize));
|
|
for (i = 0; i < ARCHS_MAX && configtag->arch[i]; i++) {
|
|
fprintf(htmlout, " <a href=\"%stag=%s&arch=%s\">%s</a>(%d;%s) ",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
configtag->arch[i],
|
|
configtag->arch[i],
|
|
configtag->stats.headercount[i],
|
|
humanSize(configtag->stats.headersize[i], &strsize));
|
|
if (i % 2 == 0) fprintf(htmlout,"<br>");
|
|
}
|
|
if (i % 2 == 0) fprintf(htmlout,"<br>");
|
|
|
|
i=0;
|
|
while ((i < configtag->stats.headersourcecount) &&
|
|
((i < HTMLSTATS_NUM) || (i < RSSSTATS_NUM))) {
|
|
if ((configtag->stats.headersourcelistvec)[i]->buildtime < timesec) {
|
|
simpleTimeToTemplate(
|
|
(configtag->stats.headersourcelistvec)[i]->buildtime,
|
|
"%Y/%m/%d",&strdate);
|
|
} else {
|
|
simpleTimeToTemplate(
|
|
(configtag->stats.headersourcelistvec)[i]->buildtime,
|
|
"%m/%d",&strdate);
|
|
}
|
|
if (i < HTMLSTATS_NUM) {
|
|
// HTML statistics
|
|
printpkgicon(htmlout, configtag, (configtag->stats.headersourcelistvec)[i]);
|
|
fprintf(htmlout,
|
|
"<a href=\"%stag=%s&pkg=%s.source\" title=\"%s\">%s %s %s-%s</a> ",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
htmlclean((configtag->stats.headersourcelistvec)[i]->summary,buffer,PATH_MAX),
|
|
strdate,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->version,
|
|
(configtag->stats.headersourcelistvec)[i]->release);
|
|
|
|
// FIXME: warnings are printed before SRPMS warning are added below so SRPMS warning are missing in HTML pages
|
|
printHTMLWarnings(htmlout,configtag,(configtag->stats.headersourcelistvec)[i],0);
|
|
fprintf(htmlout,"<br>\n");
|
|
}
|
|
|
|
if (i < HTMLOLDSTATS_NUM) {
|
|
// HTML statistics
|
|
simpleTimeToTemplate((configtag->stats.headersourcelistvec)[configtag->stats.headersourcecount-1-i]->buildtime,"%Y/%m/%d",&strolddate);
|
|
|
|
fprintf(htmloldout,
|
|
"<a href=\"%stag=%s&pkg=%s.source\">%s %s %s-%s</a><br>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
(configtag->stats.headersourcelistvec)[configtag->stats.headersourcecount-1-i]->name,
|
|
strolddate,
|
|
(configtag->stats.headersourcelistvec)[configtag->stats.headersourcecount-1-i]->name,
|
|
(configtag->stats.headersourcelistvec)[configtag->stats.headersourcecount-1-i]->version,
|
|
(configtag->stats.headersourcelistvec)[configtag->stats.headersourcecount-1-i]->release);
|
|
}
|
|
|
|
if (i < RSSSTATS_NUM) {
|
|
// RSS recent packages
|
|
fprintf(rssout," <item>\n");
|
|
fprintf(rssout," <title>%s %s %s-%s</title>\n",
|
|
strdate,
|
|
(configtag->stats.headersourcelistvec)[i]->name,
|
|
(configtag->stats.headersourcelistvec)[i]->version,
|
|
(configtag->stats.headersourcelistvec)[i]->release);
|
|
|
|
fprintf(rssout," <link>http://%s%stag=%s&pkg=%s.source</link>\n",
|
|
configtag->configdefaults->url_address,
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
(configtag->stats.headersourcelistvec)[i]->name);
|
|
fprintf(rssout," </item>\n");
|
|
}
|
|
i++;
|
|
}
|
|
|
|
|
|
fclose(htmlout);
|
|
|
|
// fprintf(rssout, "</feed>\n");
|
|
|
|
fprintf(rssout, "</channel>\n");
|
|
fprintf(rssout, "</rss>\n");
|
|
fclose(rssout);
|
|
|
|
/* create APT repository file */
|
|
snprintf(outfile, PATH_MAX, "%s%s-%s.list",
|
|
configtag->html_dir,
|
|
configtag->configdefaults->distribution_name,
|
|
configtag->tag);
|
|
|
|
if ((htmlout = fopen(outfile, "w")) == NULL) {
|
|
perror(outfile);
|
|
return 1;
|
|
} else {
|
|
|
|
/* remove final slashes from download_prefix as required by apt */
|
|
strcpy(buffer, configtag->download_dir);
|
|
|
|
i=strlen(buffer);
|
|
while ((i > 0) && (buffer[i-1] == '/' )) {
|
|
buffer[i-1]='\0';
|
|
i--;
|
|
}
|
|
|
|
fprintf(htmlout, "#\n# %s %s repository sources list for APT\n#\n\n",
|
|
configtag->configdefaults->distribution_name,
|
|
configtag->tag);
|
|
fprintf(htmlout, "#\n# %s %s repository from %s\n#\n",
|
|
configtag->tag,
|
|
configtag->arch[arch],
|
|
configtag->configdefaults->url_address);
|
|
fprintf(htmlout, "rpm http://%s %s %s\n\n",
|
|
configtag->configdefaults->url_address,
|
|
buffer,
|
|
configtag->arch[arch]);
|
|
fprintf(htmlout, "#\n# %s sources repository from %s\n#\n",
|
|
configtag->tag,
|
|
configtag->configdefaults->url_address);
|
|
fprintf(htmlout, "rpm-src http://%s %s base\n\n",
|
|
configtag->configdefaults->url_address,
|
|
buffer);
|
|
fclose(htmlout);
|
|
}
|
|
|
|
/* create Changelog page */
|
|
struct tm tmdate;
|
|
tmdate.tm_min = 0;
|
|
tmdate.tm_hour = 0;
|
|
tmdate.tm_sec = 0;
|
|
tmdate.tm_year = 90;
|
|
tmdate.tm_mday = 1;
|
|
tmdate.tm_mon = 0;
|
|
|
|
snprintf(outfile, PATH_MAX, "%s_changelog.inc", configtag->html_dir);
|
|
|
|
if ((htmlout = fopen(outfile, "w")) == NULL) {
|
|
perror(outfile);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(htmlout,
|
|
"<h1>Changelog for the <b>%s</b> repository (%s):</h1>\n",
|
|
configtag->tag,
|
|
configtag->description);
|
|
|
|
printChangelogSince(htmlout, configtag, &tmdate, 1);
|
|
|
|
fclose(htmlout);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
generateHTMLMainIndex(struct configTag *configtag)
|
|
{
|
|
char indexfile[PATH_MAX],buffer[PATH_MAX];
|
|
FILE *fout;
|
|
int i;
|
|
|
|
if (!configtag->configdefaults->html_basedir) {
|
|
return 2;
|
|
}
|
|
|
|
strcpy(indexfile, configtag->configdefaults->html_basedir);
|
|
strncat(indexfile, "_index.inc", sizeof(indexfile) - strlen(indexfile));
|
|
|
|
if ((fout = fopen(indexfile, "w")) == NULL) {
|
|
perror(indexfile);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(fout,"<b>Available repositories:</b><br><br>\n");
|
|
while (configtag) {
|
|
fprintf(fout,
|
|
"<a href=\"%stag=%s\">%s</a>: %s<br>",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
configtag->tag,
|
|
configtag->description);
|
|
|
|
/* remove final slashes from download_prefix as required by apt */
|
|
strcpy(buffer, configtag->download_dir);
|
|
i=strlen(buffer);
|
|
while ((i > 0) && (buffer[i-1] == '/' )) {
|
|
buffer[i-1]='\0';
|
|
i--;
|
|
}
|
|
configtag = configtag->next;
|
|
}
|
|
fclose(fout);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
generateHTML_SRPMSFiles(struct configTag *configtag)
|
|
{
|
|
humanDate strdate;
|
|
char indexfile[PATH_MAX];
|
|
char htmlfile[PATH_MAX];
|
|
char warningsdir[PATH_MAX];
|
|
char buffer[PATH_MAX],buffer2[PATH_MAX];
|
|
int c,i,j,arch,idx;
|
|
char *st;
|
|
char curr_letter,curr_anchor ='a'-1;
|
|
FILE *findexout[ARCHS_MAX+1], *fout;
|
|
struct changeLog *currchangelog;
|
|
struct headerSourceList *currheadersourcelist;
|
|
struct headerList *currchild;
|
|
struct stat buf;
|
|
sizeString strsize;
|
|
|
|
// create packages directory
|
|
snprintf(buffer,PATH_MAX,"%spackages",configtag->html_dir);
|
|
if (stat(buffer,&buf)) {
|
|
if (mkdir(buffer,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory; aborting.",buffer);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(buf.st_mode)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory, a file with this name already exists; aborting.",buffer);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// write an empty index.html file to avoid directory files browsing
|
|
snprintf(indexfile,PATH_MAX,"%sindex.html",configtag->html_dir);
|
|
|
|
if ((fout = fopen(indexfile, "w")) == NULL) {
|
|
perror(indexfile);
|
|
return 1;
|
|
}
|
|
fclose(fout);
|
|
|
|
// create warnings directory
|
|
snprintf(warningsdir,PATH_MAX,"%swarnings",configtag->html_dir);
|
|
if (stat(warningsdir,&buf)) {
|
|
if (mkdir(warningsdir,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory; aborting.",warningsdir);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(buf.st_mode)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory, a file with this name already exists; aborting.",warningsdir);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* open full SRPM index file */
|
|
snprintf(indexfile,PATH_MAX,"%s_index.inc",configtag->html_dir);
|
|
if ((findexout[0] = fopen(indexfile, "w")) == NULL) {
|
|
perror(indexfile);
|
|
return 1;
|
|
}
|
|
|
|
/* open arch specific SRPM index files */
|
|
for (arch = 0; arch < ARCHS_MAX; arch++) {
|
|
if (configtag->arch[arch]) {
|
|
snprintf(indexfile,PATH_MAX,"%s_index-%s.inc",configtag->html_dir,configtag->arch[arch]);
|
|
if ((findexout[arch+1] = fopen(indexfile, "w")) == NULL) {
|
|
perror(indexfile);
|
|
return 1;
|
|
}
|
|
} else {
|
|
findexout[arch+1] = NULL;
|
|
}
|
|
}
|
|
|
|
for (arch = 0; arch < ARCHS_MAX + 1 && findexout[arch]; arch++) {
|
|
fprintf(findexout[arch], "<h1><b>%s</b> - %s</h1>\n",
|
|
configtag->tag, configtag->description);
|
|
if (configtag->repository_level > 0) {
|
|
fprintf(findexout[arch],"<h2>Depends on:</h2> ");
|
|
for (c=0; c < configtag->repository_level; c++) {
|
|
fprintf(findexout[arch],"<a href=\"%stag=%s\">%s</a> - %s<br>",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->repository[c]->tag,
|
|
configtag->repository[c]->tag,
|
|
configtag->repository[c]->description);
|
|
}
|
|
fprintf(findexout[arch],"\n");
|
|
}
|
|
fprintf(findexout[arch], "<br><h2>List of packages:</h2>\n[ ");
|
|
// <th width=18></th><th nowrap align=left><b>Source</b></th><th nowrap align=left><b>Release</b></th><th width=100%% nowrap align=left><b>Builds</b></th></tr>\n");
|
|
|
|
for (c='a'; c <= 'z'; c++) {
|
|
fprintf(findexout[arch],"<a href=\"#%c\">%c</a> ",c,c);
|
|
}
|
|
fprintf(findexout[arch]," ]<br><br><table>\n");
|
|
}
|
|
|
|
currheadersourcelist = configtag->headersourcelist;
|
|
while (currheadersourcelist) {
|
|
if ((configtag->repository_level == 0) ||
|
|
(currheadersourcelist->altrepository == configtag->repository_level)) {
|
|
curr_letter=currheadersourcelist->name[0];
|
|
if (curr_letter >= 'A' && curr_letter <= 'Z') curr_letter=curr_letter+'a'-'A';
|
|
snprintf(htmlfile,PATH_MAX,"%spackages/%s.source.inc",
|
|
configtag->html_dir,currheadersourcelist->name);
|
|
if ((fout = fopen(htmlfile, "w")) == NULL) {
|
|
perror(htmlfile);
|
|
return 1;
|
|
}
|
|
|
|
get_favicon_from_url(currheadersourcelist->url, buffer2, PATH_MAX);
|
|
fprintf(fout, "<h1><img src=\"%s\" width=\"16\" height=\"16\">"
|
|
" %s: %s (source)</h1><table class=\"pkgpage\" width=\"100%%\">\n",
|
|
buffer2,
|
|
currheadersourcelist->name,
|
|
htmlclean(currheadersourcelist->summary,buffer,PATH_MAX));
|
|
|
|
fprintf(fout,"<p>");
|
|
printHTMLWarnings(fout,configtag,currheadersourcelist,1);
|
|
|
|
fprintf(fout,
|
|
"<tr><td width=\"25%%\">Name:</td><td><b>%s</b></td></tr>\n",
|
|
currheadersourcelist->name);
|
|
if (currheadersourcelist->epoch > 0) {
|
|
fprintf(fout,
|
|
"<tr><td>Release:</td><td><b>%ld:%s-%s</b></td></tr>\n",
|
|
currheadersourcelist->epoch,
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release);
|
|
} else {
|
|
fprintf(fout,
|
|
"<tr><td>Release:</td><td><b>%s-%s</b></td></tr>\n",
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release);
|
|
}
|
|
/* fprintf(fout,
|
|
"<tr><td>Summary:</td><td><b>%s</b></td></tr>\n",
|
|
htmlclean(currheadersourcelist->summary,buffer,PATH_MAX));*/
|
|
fprintf(fout,
|
|
"<tr><td>Group:</td><td><a href=\"%stag=%s&group=%s\">%s</a></td></tr>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
groupdirname(currheadersourcelist->group, buffer2),
|
|
htmlclean(currheadersourcelist->group,buffer,PATH_MAX));
|
|
|
|
fprintf(fout, "<tr><td>Maintainer:</td><td>");
|
|
|
|
if (currheadersourcelist->packager &&
|
|
(currheadersourcelist->packager->role & PACKAGER_ROLE_MAINTAINER)) {
|
|
fprintf(fout,
|
|
"<a href=\"%stag=%s&maintainer=%s\">%s</a></td></tr>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
currheadersourcelist->packager->name,
|
|
currheadersourcelist->packager->name);
|
|
// currheadersourcelist->packager->packages_count++;
|
|
} else {
|
|
fprintf(fout,
|
|
"<a href=\"%stag=%s&maintainer=unmaintained\"><b>unmaintained</b></a></td></tr>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag);
|
|
}
|
|
fprintf(fout,
|
|
"<tr><td>Description:</td><td><font size=\"-1\">%s</font></td></tr>\n",
|
|
htmlclean(currheadersourcelist->description,buffer,PATH_MAX));
|
|
fprintf(fout,
|
|
"<tr><td>License:</td><td><font size=\"-1\">%s</font></td></tr>\n",
|
|
currheadersourcelist->license);
|
|
fprintf(fout,
|
|
"<tr><td>Size:</td><td><font size=\"-1\">%s</font></td></tr>\n",
|
|
humanSize(currheadersourcelist->size, &strsize));
|
|
|
|
if (configtag->download_prefix) {
|
|
fprintf(fout,"<tr><td>Download:</td><td><font size=\"-1\">");
|
|
fprintf(fout,"<a href=\"%s%s/SRPMS.base/%s-%s-%s.src.rpm\">%s-%s-%s.src.rpm</a>",
|
|
configtag->download_prefix,
|
|
configtag->download_dir,
|
|
currheadersourcelist->name,
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release,
|
|
currheadersourcelist->name,
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release);
|
|
fprintf(fout,"</font></td></tr>\n");
|
|
}
|
|
|
|
if (currheadersourcelist->url) {
|
|
fprintf(fout,
|
|
"<tr><td>URL:</td><td><font size=\"-1\"><a href=\"%s\" target=\"_new\">%s</a></font></td></tr>\n",
|
|
currheadersourcelist->url,
|
|
currheadersourcelist->url);
|
|
}
|
|
|
|
fprintf(fout,
|
|
"<tr><td>Specfile:</td><td><font size=\"-1\"><a href=\"%s%s/specs/%s.spec\">%s.spec</a>",
|
|
configtag->showfile_prefix,
|
|
configtag->download_dir,
|
|
currheadersourcelist->name,
|
|
currheadersourcelist->name);
|
|
|
|
if (currheadersourcelist->source) {
|
|
fprintf(fout,"<tr><td>Sources:</td><td><font size=\"-1\">");
|
|
i=0;
|
|
while (currheadersourcelist->source[i+1]) i++;
|
|
for (; i>=0; i--) fprintf(fout,"%s ",currheadersourcelist->source[i]);
|
|
fprintf(fout,"</font></td></tr>\n");
|
|
}
|
|
|
|
if (currheadersourcelist->patch) {
|
|
fprintf(fout,"<tr><td>Patches:</td><td><font size=\"-1\">");
|
|
i=0;
|
|
while (currheadersourcelist->patch[i+1]) i++;
|
|
for (; i>=0; i--) {
|
|
// fprintf(fout,"%s ",currheadersourcelist->patch[i]);
|
|
fprintf(fout,"<a href=\"%s%s/patches/%s\">%s</a> ",
|
|
configtag->showfile_prefix,
|
|
configtag->download_dir,
|
|
currheadersourcelist->patch[i],
|
|
currheadersourcelist->patch[i]);
|
|
}
|
|
fprintf(fout,"</font></td></tr>\n");
|
|
}
|
|
|
|
fprintf(fout,
|
|
"<tr><td>Build time:</td><td><font size=\"-1\">%s</font></td></tr>\n",
|
|
*simpleTimeToHuman(currheadersourcelist->buildtime,
|
|
& strdate));
|
|
|
|
for (idx = 0; idx < ARCHS_MAX + 1; idx++) {
|
|
if ((idx > 0) && ((!configtag->arch[idx-1]) || (!currheadersourcelist->firstchild[idx-1]))) continue;
|
|
if (curr_anchor < curr_letter) {
|
|
fprintf(findexout[idx],"<tr><td>");
|
|
while (curr_anchor < curr_letter) {
|
|
curr_anchor += 1;
|
|
fprintf(findexout[idx],"<a name=\"%c\"></a>",curr_anchor);
|
|
}
|
|
fprintf(findexout[idx],"</td></tr>");
|
|
}
|
|
fprintf(findexout[idx],"<tr><td>");
|
|
printpkgicon(findexout[idx], configtag, currheadersourcelist);
|
|
fprintf(findexout[idx],"</td><td><b>%s</b>: <i>%s</i>",currheadersourcelist->name,htmlclean(currheadersourcelist->summary,buffer,PATH_MAX));
|
|
st=strstr(currheadersourcelist->url,"://");
|
|
if (st) {
|
|
strcpy(buffer,st+3);
|
|
st=strchr(buffer,'/');
|
|
if (st) st[0]='\0';
|
|
fprintf(findexout[idx],
|
|
" <a href=\"%s\" target=\"_new\"><img src=\"%s/external.png\" title=\"%s\" ></a>",
|
|
currheadersourcelist->url,
|
|
configtag->configdefaults->url_dir,
|
|
buffer);
|
|
}
|
|
fprintf(findexout[idx],"</td></tr><tr><td></td><td><i>");
|
|
|
|
if (currheadersourcelist->epoch) {
|
|
fprintf(findexout[idx],"%ld:%s-%s",
|
|
currheadersourcelist->epoch,
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release);
|
|
} else {
|
|
fprintf(findexout[idx],
|
|
"%s-%s",
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release);
|
|
}
|
|
fprintf(findexout[idx]," - ");
|
|
} // for
|
|
|
|
fprintf(fout,"<tr><td>Built RPMS:</td><td><font size=\"-1\">");
|
|
for (arch = 0; arch < ARCHS_MAX && configtag->arch[arch]; arch++) {
|
|
/* write children to both fout and findexout */
|
|
currchild = currheadersourcelist->firstchild[arch];
|
|
c = 0;
|
|
while (currchild) {
|
|
for (idx = 0; idx < ARCHS_MAX + 1 && findexout[idx]; idx++) {
|
|
if ((idx > 0) && ((!configtag->arch[idx-1]) || (arch != idx -1))) continue;
|
|
fprintf(findexout[idx],
|
|
"<a href=\"%stag=%s&pkg=%s.%s\">%s(%s)</a><a href=\"apt:%s\"><img src=\"%s/pkg.png\" title=\"Install\" ></a> ",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag, currchild->name, configtag->arch[arch],
|
|
currchild->name, configtag->arch[arch],
|
|
currchild->name,
|
|
configtag->configdefaults->url_dir);
|
|
}
|
|
fprintf(fout, "<a href=\"%stag=%s&pkg=%s.%s\">%s(%s)</a> ",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag, currchild->name, configtag->arch[arch],
|
|
currchild->name, configtag->arch[arch]);
|
|
|
|
currchild = currchild->nextbrother;
|
|
c++;
|
|
}
|
|
}
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
|
|
for (idx = 0; idx < ARCHS_MAX + 1 && findexout[idx]; idx++) {
|
|
if ((idx > 0) && ((!configtag->arch[idx-1]) || (!currheadersourcelist->firstchild[idx-1]))) continue;
|
|
fprintf(findexout[idx],
|
|
"<a href=\"%stag=%s&pkg=%s.source\">%s(source)</a></td></tr><tr><td colspan=2><hr></td></tr>\n",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
currheadersourcelist->name,
|
|
currheadersourcelist->name);
|
|
}
|
|
|
|
/* list build requirements */
|
|
fprintf(fout, "<tr><td nowrap>Build requirements:</td><td><font size=\"-1\">");
|
|
|
|
for (i = 0; i < currheadersourcelist->requirecount; i++) {
|
|
if (currheadersourcelist->require[i]->resolved) {
|
|
if (currheadersourcelist->require[i]->resolved->numbuildproviders == 0) {
|
|
// missing provider
|
|
fprintf(fout,"<b>%s(unresolved)</b>",currheadersourcelist->require[i]->resolved->name);
|
|
} else if (currheadersourcelist->require[i]->resolved->numbuildproviders == 1) {
|
|
// single provider
|
|
if ((i == 0 ||
|
|
strcmp(currheadersourcelist->require[i-1]->name,
|
|
currheadersourcelist->require[i]->name)) &&
|
|
strcmp(currheadersourcelist->name,
|
|
currheadersourcelist->require[i]->name)) {
|
|
fprintf(fout,"<a href=\"%stag=%s&pkg=%s.%s\">%s</a>",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->repository[currheadersourcelist->require[i]->resolved->buildprovider[0]->altrepository]->tag,
|
|
currheadersourcelist->require[i]->resolved->name,
|
|
configtag->arch[0],
|
|
currheadersourcelist->require[i]->resolved->name);
|
|
if ((configtag->repository_level > 0) &&
|
|
currheadersourcelist->require[i]->resolved->buildprovider[0]->sourceheader &&
|
|
(currheadersourcelist->require[i]->resolved->buildprovider[0]->altrepository == configtag->repository_level))
|
|
{
|
|
snprintf(buffer, PATH_MAX, "has build requirement %s which is only provided in this repository",
|
|
currheadersourcelist->require[i]->resolved->name);
|
|
addWarning(currheadersourcelist, buffer);
|
|
}
|
|
}
|
|
} else {
|
|
// multiple providers
|
|
if (i == 0 ||
|
|
!currheadersourcelist->require[i-1]->resolved ||
|
|
strcmp(currheadersourcelist->require[i-1]->resolved->name,
|
|
currheadersourcelist->require[i]->resolved->name))
|
|
fprintf(fout,"<i>%s</i>(",currheadersourcelist->require[i]->resolved->name);
|
|
for (j = 0; j < currheadersourcelist->require[i]->resolved->numbuildproviders; j++) {
|
|
fprintf(fout,"<a href=\"%stag=%s&pkg=%s.%s\">%s</a>",
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->repository[currheadersourcelist->require[i]->resolved->buildprovider[j]->altrepository]->tag,
|
|
currheadersourcelist->require[i]->resolved->buildprovider[j]->name,
|
|
configtag->arch[0],
|
|
currheadersourcelist->require[i]->resolved->buildprovider[j]->name);
|
|
if (j+1 < currheadersourcelist->require[i]->resolved->numbuildproviders) fprintf(fout,"|");
|
|
}
|
|
fprintf(fout,")");
|
|
} // if numproviders
|
|
if (currheadersourcelist->require[i]->flags & (RPMSENSE_LESS|RPMSENSE_GREATER|RPMSENSE_EQUAL)) {
|
|
fprintf(fout,"[");
|
|
if (currheadersourcelist->require[i]->flags & RPMSENSE_LESS) fprintf(fout, "<");
|
|
if (currheadersourcelist->require[i]->flags & RPMSENSE_GREATER) fprintf(fout, ">");
|
|
if (currheadersourcelist->require[i]->flags & RPMSENSE_EQUAL) fprintf(fout, "=");
|
|
fprintf(fout, "%s", currheadersourcelist->require[i]->version);
|
|
fprintf(fout,"]");
|
|
}
|
|
fprintf(fout," ");
|
|
} // if required
|
|
} // for
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
|
|
/* print changelog to fout */
|
|
fprintf(fout,
|
|
"<tr><td>Changelog:</td><td><font size=\"-1\" face=\"Courier,Courier New,monospace\">");
|
|
currchangelog = currheadersourcelist->changelog;
|
|
while (currchangelog) {
|
|
// changelog_total++;
|
|
simpleTimeToHuman(currchangelog->time, (humanDate *) & strdate);
|
|
if (currchangelog->pkg) {
|
|
if ((currchangelog->pkg->role & PACKAGER_ROLE_MAINTAINER) &&
|
|
(currchangelog->pkg->packages_count)) {
|
|
fprintf(fout, "%s - <a href=\"%stag=%s&maintainer=%s\">%s</a> (%s)<br>%s<br>",
|
|
&strdate[0],
|
|
configtag->configdefaults->url_prefix,
|
|
configtag->tag,
|
|
currchangelog->pkg->name,
|
|
currchangelog->pkg->name,
|
|
currchangelog->release,
|
|
htmlclean(currchangelog->text,buffer,PATH_MAX));
|
|
// currchangelog->pkg->changes_count++;
|
|
} else {
|
|
fprintf(fout, "%s - %s (%s)<br>%s<br>",
|
|
&strdate[0],
|
|
currchangelog->pkg->name,
|
|
currchangelog->release,
|
|
htmlclean(currchangelog->text,buffer,PATH_MAX));
|
|
// currchangelog->pkg->changes_count++;
|
|
}
|
|
} else {
|
|
fprintf(fout, "%s - (noname) (%s)<br>%s<br>",
|
|
&strdate[0],
|
|
currchangelog->release,
|
|
htmlclean(currchangelog->text,buffer,PATH_MAX));
|
|
}
|
|
currchangelog = currchangelog->next;
|
|
}
|
|
|
|
/* close fout */
|
|
fprintf(fout, "</font></td></tr></table>");
|
|
fclose(fout);
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
} // while currheadersourcelist
|
|
|
|
for (idx = 0; idx < ARCHS_MAX + 1 && findexout[idx]; idx++) {
|
|
fprintf(findexout[idx], "</table>\n");
|
|
fclose(findexout[idx]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
htmlincselector(const struct dirent *entry)
|
|
{
|
|
char *ptr;
|
|
|
|
ptr = strstr(entry->d_name, ".inc");
|
|
if (entry->d_type != DT_REG) return 0; /* skip if not a file */
|
|
if (ptr == NULL) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
cleanHTMLFilesInc(char* dir)
|
|
{
|
|
int n,cnt,r;
|
|
struct dirent **namelist;
|
|
const char* errstr;
|
|
char uf[PATH_MAX];
|
|
|
|
n = scansdir(dir, &namelist, htmlincselector, NULL);
|
|
if (n < 0) {
|
|
errstr = strerror(errno);
|
|
logmsg(LOG_ERROR, "cannot scan directory '%s' (%s)", dir, errstr);
|
|
return 1;
|
|
}
|
|
|
|
for (cnt = 0; cnt < n; ++cnt) {
|
|
snprintf(uf,PATH_MAX,"%s/%s",dir,namelist[cnt]->d_name);
|
|
logmsg(LOG_DEBUG,"unlinking %s",uf);
|
|
r=unlink(uf);
|
|
if (r < 0) {
|
|
errstr = strerror(errno);
|
|
logmsg(LOG_WARNING, "cannot remove file '%s' (%s)", uf, errstr);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cleanHTMLPackagesFiles(struct configTag *ct)
|
|
{
|
|
char dir[PATH_MAX];
|
|
|
|
snprintf(dir,PATH_MAX,"%spackages",ct->html_dir);
|
|
if (cleanHTMLFilesInc(dir)) {
|
|
logmsg(LOG_WARNING,"cannot clean %s directory",dir);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cleanHTMLFiles(struct configTag *ct)
|
|
{
|
|
int s;
|
|
char uf[PATH_MAX],dir[PATH_MAX];
|
|
const char* clean_subdir[] = { "", "maintainers" };
|
|
struct headerSourceList *currheadersourcelist;
|
|
struct stat buf;
|
|
|
|
for (s = 0; s < 2; s++) {
|
|
snprintf(dir,PATH_MAX,"%s%s",ct->html_dir,clean_subdir[s]);
|
|
if (cleanHTMLFilesInc(dir)) {
|
|
logmsg(LOG_WARNING,"cannot clean %s directory",dir);
|
|
}
|
|
}
|
|
|
|
currheadersourcelist = ct->headersourcelist;
|
|
while (currheadersourcelist) {
|
|
snprintf(dir, PATH_MAX, "%sgroups/%s",
|
|
ct->html_dir,
|
|
groupdirname(currheadersourcelist->group,uf));
|
|
|
|
if (!stat(dir,&buf)) {
|
|
logmsg(LOG_DEBUG,"removing directory %s",dir);
|
|
if (cleanHTMLFilesInc(dir)) {
|
|
logmsg(LOG_ERROR,"cannot clean %s directory; aborting",dir);
|
|
exit(1);
|
|
}
|
|
if (rmdir(dir)) {
|
|
logmsg(LOG_ERROR,"cannot remove %s directory; aborting.",dir);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* legacy: clean old group dirs */
|
|
snprintf(dir, PATH_MAX, "%s%s",
|
|
ct->html_dir,
|
|
groupdirname(currheadersourcelist->group,uf));
|
|
|
|
if (!stat(dir,&buf)) {
|
|
logmsg(LOG_DEBUG,"removing legacy directory %s",dir);
|
|
if (cleanHTMLFilesInc(dir)) {
|
|
logmsg(LOG_ERROR,"cannot clean %s directory; aborting.",dir);
|
|
exit(1);
|
|
}
|
|
if (rmdir(dir)) {
|
|
logmsg(LOG_ERROR,"cannot remove %s directory; aborting.",dir);
|
|
exit(1);
|
|
}
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
generateHTMLFiles(struct configTag *ct, int arch)
|
|
{
|
|
char buffer[PATH_MAX];
|
|
char htmlfile[PATH_MAX];
|
|
int i,j;
|
|
sizeString strsize;
|
|
FILE *fout;
|
|
struct headerList *currheaderlist, *auxheaderlist;
|
|
struct headerSourceList *auxheadersourcelist;
|
|
int found;
|
|
struct stat buf;
|
|
|
|
snprintf(buffer,PATH_MAX,"%spackages",ct->html_dir);
|
|
if (stat(buffer,&buf)) {
|
|
if (mkdir(buffer,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory; aborting.",buffer);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(buf.st_mode)) {
|
|
logmsg(LOG_ERROR,"cannot create %s directory, a file with this name already exists; aborting.",buffer);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
currheaderlist = ct->headerlist[arch];
|
|
|
|
while (currheaderlist) {
|
|
if ((ct->repository_level == 0) ||
|
|
((currheaderlist->sourceheader) &&
|
|
(currheaderlist->altrepository == ct->repository_level))) {
|
|
|
|
logmsg(LOG_DEBUG,"generating HTML pages for %s",currheaderlist->name);
|
|
snprintf(htmlfile,PATH_MAX,"%spackages/%s.%s.inc",ct->html_dir,currheaderlist->name,ct->arch[arch]);
|
|
|
|
if ((fout = fopen(htmlfile, "w")) == NULL) {
|
|
perror(htmlfile);
|
|
return 1;
|
|
}
|
|
get_favicon_from_url(currheaderlist->sourceheader->url, buffer, PATH_MAX);
|
|
|
|
fprintf(fout,
|
|
"<h1><img src=\"%s\" width=\"16\" height=\"16\">"
|
|
" %s: %s</h1><table class=\"pkgpage\" width=\"100%%\">",
|
|
buffer,
|
|
currheaderlist->name,
|
|
currheaderlist->summary);
|
|
fprintf(fout,
|
|
"<tr><td width=\"15%%\">Name:</td><td><b>%s</b></td></tr>\n",
|
|
currheaderlist->name);
|
|
fprintf(fout,
|
|
"<tr><td>Release:</td><td><b>%s-%s</b></td></tr>\n",
|
|
currheaderlist->version, currheaderlist->release);
|
|
fprintf(fout,
|
|
"<tr><td>Architecture:</td><td>%s</td></tr>\n",
|
|
currheaderlist->arch);
|
|
//fprintf(fout,
|
|
// "<tr><td>Summary:</td><td><b>%s</b></td></tr>\n",
|
|
// htmlclean(currheaderlist->summary,buffer,PATH_MAX));
|
|
fprintf(fout,
|
|
"<tr><td>Group:</td><td>%s</td></tr>\n",
|
|
htmlclean(currheaderlist->group,buffer,PATH_MAX));
|
|
fprintf(fout, "<tr><td>Description:</td><td>%s</td></tr>\n",
|
|
htmlclean(currheaderlist->description,buffer,PATH_MAX));
|
|
fprintf(fout,
|
|
"<tr><td>Size:</td><td><font size=\"-1\">%s</font></td></tr>\n",
|
|
humanSize(currheaderlist->size, &strsize));
|
|
//fprintf(fout,
|
|
// "<tr><td>Arch:</td><td><font size=\"-1\">%s</font></td></tr>\n",
|
|
// currheaderlist->arch);
|
|
|
|
if (ct->download_prefix) {
|
|
fprintf(fout,"<tr><td>Download:</td><td><font size=\"-1\">");
|
|
fprintf(fout,"<a href=\"%s%s/RPMS.%s/%s-%s-%s.%s.rpm\">%s-%s-%s.%s.rpm</a>",
|
|
ct->download_prefix,
|
|
ct->download_dir,
|
|
ct->arch[arch],
|
|
currheaderlist->name,
|
|
currheaderlist->version,
|
|
currheaderlist->release,
|
|
currheaderlist->arch,
|
|
currheaderlist->name,
|
|
currheaderlist->version,
|
|
currheaderlist->release,
|
|
currheaderlist->arch);
|
|
|
|
fprintf(fout,"</font></td></tr>\n");
|
|
}
|
|
|
|
if (currheaderlist->sourcename && currheaderlist->sourceheader) {
|
|
fprintf(fout,
|
|
"<tr><td>Source RPM:</td><td><font size=\"-1\"><a href=\"%stag=%s&pkg=%s.source\">%s</a></font></td></tr>\n",
|
|
ct->configdefaults->url_prefix,
|
|
ct->tag,
|
|
currheaderlist->sourceheader->name,
|
|
currheaderlist->sourcename);
|
|
}
|
|
|
|
/* list obsoletes */
|
|
if (currheaderlist->obsoletecount > 0) {
|
|
fprintf(fout,
|
|
"<tr><td>Obsoletes:</td><td><font size=\"-1\">");
|
|
for (i = 0; i < currheaderlist->obsoletecount; i++) {
|
|
fprintf(fout, "%s", currheaderlist->obsoletename[i]);
|
|
if (currheaderlist->obsoleteflags[i] & (RPMSENSE_LESS|RPMSENSE_GREATER|RPMSENSE_EQUAL)) {
|
|
fprintf(fout, "[");
|
|
if (currheaderlist->obsoleteflags[i] & RPMSENSE_LESS) fprintf(fout, "<");
|
|
if (currheaderlist->obsoleteflags[i] & RPMSENSE_GREATER) fprintf(fout, ">");
|
|
if (currheaderlist->obsoleteflags[i] & RPMSENSE_EQUAL) fprintf(fout, "=");
|
|
fprintf(fout, "%s]", currheaderlist->obsoleteversion[i]);
|
|
}
|
|
fprintf(fout," ");
|
|
}
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
}
|
|
|
|
/* list provides */
|
|
fprintf(fout,
|
|
"<tr><td>Provides:</td><td><font size=\"-1\">");
|
|
for (i = 0; i < currheaderlist->providecount; i++) {
|
|
fprintf(fout, "%s", currheaderlist->providename[i]);
|
|
if (currheaderlist->provideflags[i] & (RPMSENSE_LESS|RPMSENSE_GREATER|RPMSENSE_EQUAL)) {
|
|
fprintf(fout, "[");
|
|
if (currheaderlist->provideflags[i] & RPMSENSE_LESS) fprintf(fout, "<");
|
|
if (currheaderlist->provideflags[i] & RPMSENSE_GREATER) fprintf(fout, ">");
|
|
if (currheaderlist->provideflags[i] & RPMSENSE_EQUAL) fprintf(fout, "=");
|
|
fprintf(fout, "%s]", currheaderlist->provideversion[i]);
|
|
}
|
|
fprintf(fout," ");
|
|
}
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
|
|
/* list requires */
|
|
fprintf(fout, "<tr><td>Requires:</td><td><font size=\"-1\">");
|
|
for (i = 0; i < currheaderlist->requirecount; i++) {
|
|
if (currheaderlist->require[i]->resolved) {
|
|
if (currheaderlist->require[i]->resolved->numproviders == 0) {
|
|
// no provider
|
|
fprintf(fout,"%s",currheaderlist->require[i]->resolved->name);
|
|
} else if (currheaderlist->require[i]->resolved->numproviders == 1) {
|
|
// single provider
|
|
if (currheaderlist->require[i]->resolved->provider[0]->sourceheader) {
|
|
fprintf(fout,"<a href=\"%stag=%s&pkg=%s.%s\">%s</a>",
|
|
ct->configdefaults->url_prefix,
|
|
ct->repository[currheaderlist->require[i]->resolved->provider[0]->altrepository]->tag,
|
|
currheaderlist->require[i]->resolved->provider[0]->name,
|
|
ct->arch[arch],
|
|
currheaderlist->require[i]->resolved->name);
|
|
} else {
|
|
fprintf(fout,"%s",currheaderlist->require[i]->resolved->name);
|
|
}
|
|
} else {
|
|
// multiple providers
|
|
logmsg(LOG_DEBUG,"Requirement %s has multiple providers",currheaderlist->require[i]->resolved->name);
|
|
fprintf(fout,"<i>%s</i>(",currheaderlist->require[i]->resolved->name);
|
|
for (j = 0; j < currheaderlist->require[i]->resolved->numproviders; j++) {
|
|
if (currheaderlist->require[i]->resolved->provider[j]->sourceheader)
|
|
fprintf(fout,"<a href=\"%stag=%s&pkg=%s.%s\">%s</a>",
|
|
ct->configdefaults->url_prefix,
|
|
ct->repository[currheaderlist->require[i]->resolved->provider[j]->altrepository]->tag,
|
|
currheaderlist->require[i]->resolved->provider[j]->name,
|
|
ct->arch[arch],
|
|
currheaderlist->require[i]->resolved->provider[j]->name);
|
|
else
|
|
fprintf(fout,"%s",currheaderlist->require[i]->resolved->provider[j]->name);
|
|
if (j+1 < currheaderlist->require[i]->resolved->numproviders) fprintf(fout,"|");
|
|
}
|
|
fprintf(fout,")");
|
|
} // if numproviders
|
|
if (currheaderlist->require[i]->flags & (RPMSENSE_LESS|RPMSENSE_GREATER|RPMSENSE_EQUAL)) {
|
|
fprintf(fout,"[");
|
|
if (currheaderlist->require[i]->flags & RPMSENSE_LESS) fprintf(fout, "<");
|
|
if (currheaderlist->require[i]->flags & RPMSENSE_GREATER) fprintf(fout, ">");
|
|
if (currheaderlist->require[i]->flags & RPMSENSE_EQUAL) fprintf(fout, "=");
|
|
fprintf(fout, "%s", currheaderlist->require[i]->version);
|
|
fprintf(fout,"]");
|
|
}
|
|
fprintf(fout," ");
|
|
} // if required
|
|
} // for
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
|
|
/* list RPM requirements */
|
|
fprintf(fout, "<tr><td>RPM requirements:</td><td><font size=\"-1\">");
|
|
|
|
for (i = 0; i < currheaderlist->requirecount; i++) {
|
|
if (currheaderlist->require[i]->resolved) {
|
|
if (currheaderlist->require[i]->resolved->numproviders == 0) {
|
|
// missing provider
|
|
fprintf(fout,"<b>%s(unresolved)</b> ",currheaderlist->require[i]->resolved->name);
|
|
} else if (currheaderlist->require[i]->resolved->numproviders == 1) {
|
|
// single provider
|
|
if ((i == 0 ||
|
|
!currheaderlist->require[i-1]->resolved ||
|
|
!currheaderlist->require[i-1]->resolved->numproviders ||
|
|
strcmp(currheaderlist->require[i-1]->resolved->provider[0]->name,
|
|
currheaderlist->require[i]->resolved->provider[0]->name)) &&
|
|
strcmp(currheaderlist->name,
|
|
currheaderlist->require[i]->resolved->provider[0]->name)) {
|
|
fprintf(fout,"<a href=\"%stag=%s&pkg=%s.%s\">%s</a> ",
|
|
ct->configdefaults->url_prefix,
|
|
ct->repository[currheaderlist->require[i]->resolved->provider[0]->altrepository]->tag,
|
|
currheaderlist->require[i]->resolved->provider[0]->name,
|
|
ct->arch[arch],
|
|
currheaderlist->require[i]->resolved->provider[0]->name);
|
|
if ((ct->repository_level > 0) &&
|
|
(currheaderlist->sourceheader != currheaderlist->require[i]->resolved->provider[0]->sourceheader) &&
|
|
(currheaderlist->require[i]->resolved->provider[0]->altrepository == ct->repository_level)) {
|
|
snprintf(buffer, PATH_MAX, "%s(%s,%s) requires %s(%s,%s) which is only in this repository",
|
|
currheaderlist->name,
|
|
ct->arch[arch],
|
|
ct->repository[currheaderlist->altrepository]->tag,
|
|
currheaderlist->require[i]->resolved->provider[0]->name,
|
|
ct->arch[arch],
|
|
ct->repository[currheaderlist->require[i]->resolved->provider[0]->altrepository]->tag);
|
|
addWarning(currheaderlist->sourceheader, buffer);
|
|
}
|
|
}
|
|
} else {
|
|
// multiple providers
|
|
if (i == 0 ||
|
|
!currheaderlist->require[i-1]->resolved ||
|
|
!currheaderlist->require[i-1]->resolved->numproviders ||
|
|
strcmp(currheaderlist->require[i-1]->resolved->name,
|
|
currheaderlist->require[i]->resolved->name)) {
|
|
fprintf(fout,"<i>%s</i>(",currheaderlist->require[i]->resolved->name);
|
|
for (j = 0; j < currheaderlist->require[i]->resolved->numproviders; j++) {
|
|
fprintf(fout,"<a href=\"%stag=%s&pkg=%s.%s\">%s</a>",
|
|
ct->configdefaults->url_prefix,
|
|
ct->repository[currheaderlist->require[i]->resolved->provider[j]->altrepository]->tag,
|
|
currheaderlist->require[i]->resolved->provider[j]->name,
|
|
ct->arch[arch],
|
|
currheaderlist->require[i]->resolved->provider[j]->name);
|
|
if (j+1 < currheaderlist->require[i]->resolved->numproviders) fprintf(fout,"|");
|
|
}
|
|
fprintf(fout,") ");
|
|
}
|
|
} // if numproviders
|
|
} // if required
|
|
} // for
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
|
|
/* list required by */
|
|
fprintf(fout, "<tr><td>Required by:</td><td><font size=\"-1\">");
|
|
auxheaderlist = ct->headerlist[arch];
|
|
while (auxheaderlist) {
|
|
found = 0;
|
|
if (auxheaderlist != currheaderlist) {
|
|
for (i = 0; i < auxheaderlist->requirecount; i++) {
|
|
if (auxheaderlist->require[i]->resolved) {
|
|
for (j = 0; j < auxheaderlist->require[i]->resolved->numproviders; j++) {
|
|
if (!strcmp(auxheaderlist->require[i]->resolved->provider[j]->name, currheaderlist->name)) {
|
|
fprintf(fout, "<a href=\"%stag=%s&pkg=%s.%s\">%s(%s)</a> ",
|
|
ct->configdefaults->url_prefix,
|
|
ct->repository[auxheaderlist->altrepository]->tag,
|
|
auxheaderlist->name,
|
|
ct->arch[arch],
|
|
auxheaderlist->name,
|
|
ct->arch[arch]);
|
|
found = 1;
|
|
}
|
|
if (found) break;
|
|
}
|
|
}
|
|
if (found) break;
|
|
}
|
|
}
|
|
auxheaderlist = auxheaderlist->next;
|
|
} // while auxheaderlist
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
|
|
/* list build required by */
|
|
fprintf(fout,
|
|
"<tr><td nowrap>Build required by:</td><td><font size=\"-1\">");
|
|
auxheadersourcelist = ct->headersourcelist;
|
|
while (auxheadersourcelist) {
|
|
found=0;
|
|
if (auxheadersourcelist != currheaderlist->sourceheader) {
|
|
for (i = 0; i < auxheadersourcelist->requirecount; i++) {
|
|
if (auxheadersourcelist->require[i]->resolved) {
|
|
for (j = 0; j < auxheadersourcelist->require[i]->resolved->numbuildproviders; j++) {
|
|
if (!strcmp(auxheadersourcelist->require[i]->resolved->buildprovider[j]->name,
|
|
currheaderlist->name)) {
|
|
fprintf(fout,
|
|
"<a href=\"%stag=%s&pkg=%s.source\">%s</a> ",
|
|
ct->configdefaults->url_prefix,
|
|
ct->repository[auxheadersourcelist->altrepository]->tag,
|
|
auxheadersourcelist->name,
|
|
auxheadersourcelist->name);
|
|
found=1;
|
|
}
|
|
}
|
|
}
|
|
if (found) break;
|
|
}
|
|
}
|
|
auxheadersourcelist = auxheadersourcelist->next;
|
|
}
|
|
fprintf(fout, "</font></td></tr>\n");
|
|
|
|
/* list filenames */
|
|
fprintf(fout, "<tr><td>Filenames:</td><td><font size=\"-1\">");
|
|
for (i = 0; i < currheaderlist->filenamecount; i++) {
|
|
ftname((currheaderlist->file)[i], buffer);
|
|
fprintf(fout, "/%s ",buffer);
|
|
}
|
|
fprintf(fout, "</font></td></tr></table>\n");
|
|
fclose(fout);
|
|
}
|
|
currheaderlist = currheaderlist->next;
|
|
} // while currheaderlist
|
|
return 0;
|
|
}
|
|
|
|
char *ftname(struct fileTree* ft, char* buf) {
|
|
|
|
buf[0]='\0';
|
|
int l;
|
|
|
|
if (ft) {
|
|
strcpy(buf,ft->name);
|
|
ft=ft->parent;
|
|
}
|
|
|
|
while (ft) {
|
|
l=strlen(ft->name);
|
|
if (strlen(buf)+l+1 <= PATH_MAX) {
|
|
memmove(buf+l+1,buf,strlen(buf)+1);
|
|
memcpy(buf,ft->name,l);
|
|
buf[l]='/';
|
|
} else break;
|
|
ft=ft->parent;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
void print_contents_subtree(FILE *f,
|
|
struct fileTree* ft,
|
|
struct configTag* ct,
|
|
char* buf, int bufsize) {
|
|
int i,j,k;
|
|
|
|
while (ft) {
|
|
if (ft->firstchild) {
|
|
print_contents_subtree(f,ft->firstchild,ct,buf,bufsize);
|
|
} else {
|
|
for (k = 0; k < ft->numproviders; k++) {
|
|
if ((ct->repository_level == 0) ||
|
|
((ft->provider[k]) &&
|
|
(ft->provider[k]->sourceheader) &&
|
|
(ft->provider[k]->altrepository == ct->repository_level))) {
|
|
ftname(ft,buf);
|
|
if ((j=strlen(buf)) < 60) {
|
|
for (i=(60-j)/8; i>0; i--) strncat(buf, "\t", bufsize - strlen(buf));
|
|
while (strlen(buf) < 60) strncat(buf, " ", bufsize - strlen(buf));
|
|
}
|
|
fprintf(f, "%s %s/%s\n",buf,ct->tag,ft->provider[0]->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
ft=ft->next;
|
|
}
|
|
|
|
}
|
|
|
|
int print_contentslist(struct configTag *ct, int arch) {
|
|
FILE *fc;
|
|
char contents_filename[PATH_MAX],buf[PATH_MAX];
|
|
|
|
snprintf(contents_filename, PATH_MAX, "%scontentslist-%s", ct->repository_dir, ct->arch[arch]);
|
|
|
|
fc=fopen(contents_filename,"w");
|
|
if (!fc) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", contents_filename);
|
|
return 1;
|
|
}
|
|
|
|
//write contents (filenames)
|
|
logmsg(LOG_DEBUG,"writing contents file");
|
|
print_contents_subtree(fc, ct->filetree[arch], ct, buf, PATH_MAX);
|
|
|
|
fclose(fc);
|
|
return 0;
|
|
}
|
|
|
|
#define OBSOLETEBUF_SIZE 8096
|
|
|
|
int print_datatables(struct configTag *ct, int arch) {
|
|
|
|
FILE *fbd,*fd,*fv,*fb,*fbsh,*fs,*fw;
|
|
char builddeps_filename[PATH_MAX], deps_filename[PATH_MAX], virtual_filename[PATH_MAX],
|
|
builds_filename[PATH_MAX], builds_sh_filename[PATH_MAX], sources_filename[PATH_MAX],
|
|
warnings_filename[PATH_MAX];
|
|
char obsoletebuf[OBSOLETEBUF_SIZE];
|
|
struct headerList *currheaderlist, *currchild;
|
|
struct headerSourceList *currheadersourcelist, *oldheadersourcelist;
|
|
struct rebuildList *currrebuild;
|
|
int i, nonobsoletednumproviders;
|
|
|
|
snprintf(builddeps_filename, PATH_MAX, "%sbuilddeps-%s", ct->html_dir, ct->arch[arch]);
|
|
snprintf(deps_filename, PATH_MAX, "%sdeps-%s", ct->html_dir, ct->arch[arch]);
|
|
snprintf(virtual_filename, PATH_MAX, "%svirtual-%s", ct->html_dir, ct->arch[arch]);
|
|
snprintf(builds_filename, PATH_MAX, "%sbuilds-%s", ct->html_dir, ct->arch[arch]);
|
|
snprintf(builds_sh_filename, PATH_MAX, "%sbuilds-%s.sh", ct->html_dir, ct->arch[arch]);
|
|
snprintf(sources_filename, PATH_MAX, "%ssources-%s", ct->html_dir, ct->arch[arch]);
|
|
snprintf(warnings_filename, PATH_MAX, "%swarnings-%s", ct->repository_dir, ct->arch[arch]);
|
|
|
|
fbd=fopen(builddeps_filename,"w");
|
|
if (!fbd) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", builddeps_filename);
|
|
return 1;
|
|
}
|
|
|
|
fd=fopen(deps_filename,"w");
|
|
if (!fd) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", deps_filename);
|
|
return 1;
|
|
}
|
|
|
|
fv=fopen(virtual_filename,"w");
|
|
if (!fv) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", virtual_filename);
|
|
return 1;
|
|
}
|
|
|
|
fb=fopen(builds_filename,"w");
|
|
if (!fb) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", builds_filename);
|
|
return 1;
|
|
}
|
|
|
|
fbsh=fopen(builds_sh_filename,"w");
|
|
if (!fbsh) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", builds_filename);
|
|
return 1;
|
|
}
|
|
|
|
fs=fopen(sources_filename,"w");
|
|
if (!fs) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", sources_filename);
|
|
return 1;
|
|
}
|
|
|
|
fw=fopen(warnings_filename,"w");
|
|
if (!fw) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s. Aborting.\n", warnings_filename);
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// headerlist scan: write top of deps and sources files
|
|
//
|
|
fprintf(fd,"ALL_PACKAGES = ");
|
|
fprintf(fb,"ALL_BUILDS=");
|
|
currheaderlist = ct->headerlist[arch];
|
|
while (currheaderlist) {
|
|
fprintf(fs,"%s: _%s\n", currheaderlist->name, currheaderlist->sourceheader->name);
|
|
fprintf(fd,"%s ", currheaderlist->name);
|
|
fprintf(fb,"%s ",currheaderlist->name);
|
|
currheaderlist = currheaderlist->next;
|
|
}
|
|
fprintf(fd,"\n");
|
|
|
|
//
|
|
// source headerlist scan: write top of deps and sources files
|
|
//
|
|
fprintf(fbd,"ALL_SOURCES = ");
|
|
fprintf(fs,"ALL_SOURCES = ");
|
|
currheadersourcelist = ct->headersourcelist;
|
|
while (currheadersourcelist) {
|
|
if (currheadersourcelist->firstchild[arch]) {
|
|
fprintf(fbd,"%s ", currheadersourcelist->name);
|
|
fprintf(fs,"_%s ", currheadersourcelist->name);
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
fprintf(fbd,"\n");
|
|
fprintf(fs,"\n");
|
|
fprintf(fb,"\n");
|
|
|
|
// write deps file
|
|
logmsg(LOG_DEBUG,"writing deps files (1)");
|
|
struct providedList* provided = ct->providedlist_idx[arch][0];
|
|
while (provided) {
|
|
if (!strncmp("debuginfo(build-id)", provided->name, 20) ||
|
|
provided->name[0] == '(') { // Filter out complex deps like "(name >= ver1 with name < ver2)
|
|
provided = provided->next;
|
|
continue;
|
|
}
|
|
nonobsoletednumproviders=0;
|
|
for (i = 0; i < provided->numproviders; i++) {
|
|
// skip duplicated provides
|
|
if (i > 0) {
|
|
if (provided->provider[i] == provided->provider[i-1]) continue;
|
|
else if (!strcmp(provided->provider[i]->name,provided->provider[i-1]->name) &&
|
|
!provided->provider[i-1]->obsoleted) continue;
|
|
}
|
|
if (!provided->provider[i]->obsoleted) nonobsoletednumproviders++;
|
|
}
|
|
if (nonobsoletednumproviders > 1) {
|
|
fprintf(fd,"ifndef ");
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd,"\n");
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd," := ");
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd,"_to_be_defined # ");
|
|
fprintf_depstable_filtered_var(fs,provided->name);
|
|
fprintf(fs,":");
|
|
for (i = 0; i < provided->numproviders; i++) {
|
|
if (!provided->provider[i]->obsoleted) {
|
|
if (i == 0 || strcmp(provided->provider[i-1]->name,
|
|
provided->provider[i]->name))
|
|
fprintf(fd,"%s ",provided->provider[i]->name);
|
|
if (i == 0 || strcmp(provided->provider[i-1]->sourceheader->name,
|
|
provided->provider[i]->sourceheader->name))
|
|
fprintf(fs," _%s",provided->provider[i]->sourceheader->name);
|
|
}
|
|
}
|
|
fprintf(fs,"\n");
|
|
|
|
fprintf(fd,"\nendif\n");
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd,": ");
|
|
fprintf(fd,"$(");
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd,")\n");
|
|
|
|
fprintf(fv,"%s= # ",provided->name);
|
|
for (i = 0; i < provided->numproviders; i++) {
|
|
if (!provided->provider[i]->obsoleted) {
|
|
if (i == 0 || strcmp(provided->provider[i-1]->name,
|
|
provided->provider[i]->name))
|
|
fprintf(fv,"%s ",provided->provider[i]->name);
|
|
}
|
|
}
|
|
fprintf(fv,"\n");
|
|
} else if (nonobsoletednumproviders == 1) {
|
|
for (i = 0; i < provided->numproviders; i++) {
|
|
if (!provided->provider[i]->obsoleted) break;
|
|
}
|
|
if (strcmp(provided->name,provided->provider[i]->name)) {
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd,": ");
|
|
fprintf(fd,"%s\n",provided->provider[i]->name);
|
|
fprintf_depstable_filtered_var(fs,provided->name);
|
|
fprintf(fs,": _%s\n",provided->provider[i]->sourceheader->name);
|
|
}
|
|
} else {
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd,": ");
|
|
fprintf(fd,"__missing_provider_for_");
|
|
fprintf_depstable_filtered_var(fd,provided->name);
|
|
fprintf(fd,"\n");
|
|
}
|
|
provided = provided->next;
|
|
}
|
|
|
|
logmsg(LOG_DEBUG,"writing deps files (2)");
|
|
currheaderlist = ct->headerlist[arch];
|
|
while (currheaderlist) {
|
|
fprintf(fd,"%s: ", currheaderlist->name);
|
|
for (i = 0; i < currheaderlist->requirecount; i++) {
|
|
if (currheaderlist->require[i]->resolved) {
|
|
if (currheaderlist->require[i]->resolved->numproviders == 0) {
|
|
// Filter out complex deps like "(name >= ver1 with name < ver2)
|
|
if (currheaderlist->require[i]->resolved->name[0] != '(') {
|
|
fprintf_depstable_filtered_var(fd,
|
|
currheaderlist->require[i]->resolved->name);
|
|
fprintf(fd,"_unresolved_ ");
|
|
}
|
|
} else if (currheaderlist->require[i]->resolved->numproviders == 1) {
|
|
if ((i == 0 ||
|
|
!currheaderlist->require[i-1]->resolved ||
|
|
!currheaderlist->require[i-1]->resolved->numproviders ||
|
|
strcmp(currheaderlist->require[i-1]->resolved->provider[0]->name,
|
|
currheaderlist->require[i]->resolved->provider[0]->name)) &&
|
|
strcmp(currheaderlist->name,
|
|
currheaderlist->require[i]->resolved->provider[0]->name)) {
|
|
fprintf(fd,"%s ",currheaderlist->require[i]->resolved->provider[0]->name);
|
|
}
|
|
} else {
|
|
if (i == 0 ||
|
|
!currheaderlist->require[i-1]->resolved ||
|
|
!currheaderlist->require[i-1]->resolved->numproviders ||
|
|
strcmp(currheaderlist->require[i-1]->resolved->name,
|
|
currheaderlist->require[i]->resolved->name)) {
|
|
fprintf_depstable_filtered_var(fd,currheaderlist->require[i]->resolved->name);
|
|
fprintf(fd," ");
|
|
}
|
|
}
|
|
for (int j = 0; j < currheaderlist->require[i]->resolved->numproviders; j++) {
|
|
if (currheaderlist->require[i]->resolved->provider[j]->sourceheader != currheaderlist->sourceheader)
|
|
currheaderlist->require[i]->resolved->provider[j]->sourceheader->childrenrequiredcount[arch]++;
|
|
}
|
|
}
|
|
}
|
|
fprintf(fd,"\n");
|
|
|
|
//
|
|
// write builddeps file
|
|
//
|
|
fprintf(fbd,"%s:",currheaderlist->name);
|
|
for (i = 0; i < currheaderlist->sourceheader->requirecount; i++) {
|
|
if (strncmp("rpmlib(",currheaderlist->sourceheader->require[i]->name,7) &&
|
|
strncmp("debuginfo(build-id)",currheaderlist->sourceheader->require[i]->name,20)) {
|
|
fprintf(fbd," ");
|
|
fprintf_depstable_filtered_var(fbd,currheaderlist->sourceheader->require[i]->name);
|
|
if (currheaderlist->sourceheader->require[i]->resolved) {
|
|
for (int j = 0; j < currheaderlist->sourceheader->require[i]->resolved->numproviders; j++) {
|
|
if (currheaderlist->sourceheader->require[i]->resolved->provider[j]->sourceheader != currheaderlist->sourceheader)
|
|
currheaderlist->sourceheader->require[i]->resolved->provider[j]->sourceheader->childrenrequiredcount[arch]++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(fbd,"\n");
|
|
|
|
/*for (i = 0; i < currheaderlist->obsoletecount; i++) {
|
|
fprintf(fbd,"%s: %s\n",currheaderlist->obsoletename[i],currheaderlist->name);
|
|
}*/
|
|
|
|
for (i = 0; i < currheaderlist->providecount; i++) {
|
|
if (strncmp(currheaderlist->provided[i]->name,currheaderlist->name,PATH_MAX) != 0) {
|
|
fprintf_depstable_filtered_var(fbd,currheaderlist->provided[i]->name);
|
|
fprintf(fbd,": %s\n",currheaderlist->name);
|
|
}
|
|
}
|
|
|
|
currheaderlist = currheaderlist->next;
|
|
}
|
|
|
|
//
|
|
// headersourcelist scan: write builds and sources files
|
|
//
|
|
logmsg(LOG_DEBUG,"writing builds and sources files (1)");
|
|
fprintf(fbsh,"pkg_list=(");
|
|
currheadersourcelist = ct->headersourcelist;
|
|
while (currheadersourcelist != NULL) {
|
|
if (((ct->repository_level == 0) ||
|
|
(currheadersourcelist->altrepository == ct->repository_level)) &&
|
|
(currheadersourcelist->firstchild[arch])) {
|
|
fprintf(fbsh,"%s ",currheadersourcelist->name);
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
fprintf(fbsh,");\n");
|
|
|
|
fprintf(fbsh,"needport_list=(");
|
|
currheadersourcelist = ct->headersourcelist;
|
|
while (currheadersourcelist != NULL) {
|
|
if (!currheadersourcelist->firstchild[arch] &&
|
|
currheadersourcelist->old &&
|
|
currheadersourcelist->old->firstchild[arch] &&
|
|
(currheadersourcelist->altrepository == ct->repository_level)) {
|
|
fprintf(fbsh,"%s ",currheadersourcelist->name);
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
fprintf(fbsh,");\n");
|
|
|
|
fprintf(fbsh,"warnings_list=(");
|
|
currheadersourcelist = ct->headersourcelist;
|
|
while (currheadersourcelist != NULL) {
|
|
if ((currheadersourcelist->altrepository == ct->repository_level) &&
|
|
(printHTMLWarnings(fw,ct,currheadersourcelist,2) == 1)) {
|
|
fprintf(fbsh,"%s ",currheadersourcelist->name);
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
fprintf(fbsh,");\n");
|
|
|
|
currheadersourcelist = ct->headersourcelist;
|
|
logmsg(LOG_DEBUG,"writing builds and sources files (2)");
|
|
while (currheadersourcelist != NULL) {
|
|
currchild = currheadersourcelist->firstchild[arch];
|
|
if (currchild) {
|
|
fprintf(fbsh,"[ \"$pkg\" = \"%s\" ] && { pkg_header=(%s %s %s %s \"%s\" \"%s\" %ld %ld %d %s %ld); ",
|
|
currheadersourcelist->name,
|
|
currheadersourcelist->name,
|
|
currchild->arch,
|
|
currheadersourcelist->version,
|
|
currheadersourcelist->release,
|
|
currheadersourcelist->group,
|
|
currheadersourcelist->license,
|
|
currheadersourcelist->size,
|
|
currheadersourcelist->buildtime,
|
|
currheadersourcelist->altrepository,
|
|
ct->repository[currheadersourcelist->altrepository]->tag,
|
|
currheadersourcelist->epoch);
|
|
fprintf(fb,"%s:",
|
|
currheadersourcelist->name);
|
|
fprintf(fbsh,"pkg_builds=(");
|
|
|
|
obsoletebuf[0] = '\0';
|
|
|
|
while (currchild) {
|
|
fprintf(fbsh,"%s",currchild->name);
|
|
fprintf(fb," %s",currchild->name);
|
|
for (i = 0; i < currchild->obsoletecount; i++ ) {
|
|
if ((i > 0) && (!strcmp(currchild->obsoletename[i],currchild->obsoletename[i-1]))) continue;
|
|
if (strlen(obsoletebuf) + strlen(currchild->obsoletename[i]) >= OBSOLETEBUF_SIZE - 2) {
|
|
logmsg(LOG_WARNING, "%s: reached obsoletebuf maximum size (%d); skipping further obsoletes in output file",
|
|
currheadersourcelist->name, OBSOLETEBUF_SIZE);
|
|
break;
|
|
}
|
|
if (obsoletebuf[0] != '\0') strncat(obsoletebuf, " ", sizeof(obsoletebuf) - strlen(obsoletebuf));
|
|
strncat(obsoletebuf, currchild->obsoletename[i], sizeof(obsoletebuf) - strlen(obsoletebuf));
|
|
}
|
|
currchild = currchild->nextbrother;
|
|
if (currchild) fprintf(fbsh," ");
|
|
}
|
|
fprintf(fbsh,"); pkg_obsoletes=(%s);",obsoletebuf);
|
|
|
|
/* find pointer to firstrebuild also looking into old packages */
|
|
currrebuild = currheadersourcelist->firstrebuild;
|
|
oldheadersourcelist = currheadersourcelist->old;
|
|
while (!currrebuild && oldheadersourcelist) {
|
|
currrebuild = oldheadersourcelist->firstrebuild;
|
|
oldheadersourcelist = oldheadersourcelist->old;
|
|
}
|
|
fprintf(fbsh," pkg_needrebuild=(");
|
|
while (currrebuild) {
|
|
if (!strcmp(currrebuild->provider->arch, ct->arch[arch])) {
|
|
fprintf(fbsh, "%s@%s ", currrebuild->sourceheader->name, currrebuild->provider->name);
|
|
}
|
|
currrebuild = currrebuild->next;
|
|
}
|
|
fprintf(fbsh,"); }\n");
|
|
fprintf(fb,"\n");
|
|
}
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
|
|
fclose(fd);
|
|
fclose(fv);
|
|
fclose(fbsh);
|
|
fclose(fb);
|
|
fclose(fs);
|
|
fclose(fw);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
generateSrcPkgList(struct configTag *ct)
|
|
{
|
|
FILE *fd;
|
|
char fn[PATH_MAX];
|
|
struct headerSourceList *currheadersourcelist;
|
|
humanDate strdate;
|
|
int i;
|
|
|
|
snprintf(fn, PATH_MAX, "%ssrcpkglist",ct->repository_dir);
|
|
fd=fopen(fn,"w");
|
|
|
|
if (!fd) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s\n", fn);
|
|
return 1;
|
|
}
|
|
|
|
currheadersourcelist = ct->headersourcelist;
|
|
while (currheadersourcelist != NULL) {
|
|
fprintf(fd, "%s %s %s %s %ld %s ",
|
|
currheadersourcelist->name,
|
|
currheadersourcelist->version,
|
|
(char *)simpleTimeToTemplate(currheadersourcelist->buildtime,"%Y%m%d",&strdate),
|
|
ct->repository[currheadersourcelist->altrepository]->tag,
|
|
currheadersourcelist->epoch,
|
|
currheadersourcelist->release);
|
|
|
|
if (currheadersourcelist->source) {
|
|
i=0;
|
|
while (currheadersourcelist->source[i+1]) i++;
|
|
for (; i>=0; i--)
|
|
fprintf(fd, "%s ",currheadersourcelist->source[i]);
|
|
}
|
|
fprintf(fd, "\n");
|
|
currheadersourcelist = currheadersourcelist->next;
|
|
}
|
|
fclose(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
generatePkgList(struct configTag *ct, int arch)
|
|
{
|
|
FILE *fd;
|
|
char fn[PATH_MAX];
|
|
struct headerList *currheaderlist;
|
|
|
|
snprintf(fn, PATH_MAX, "%spkglist.%s",ct->repository_dir,ct->arch[arch]);
|
|
fd=fopen(fn,"w");
|
|
|
|
if (!fd) {
|
|
fprintf(stderr, "Error: can't open file for writing: %s\n", fn);
|
|
return 1;
|
|
}
|
|
|
|
/* currheaderlist = headerlist; */
|
|
currheaderlist = ct->headerlist[arch];
|
|
while (currheaderlist != NULL) {
|
|
fprintf(fd, "%s %s %ld %d %s %ld %s\n",
|
|
currheaderlist->name,
|
|
currheaderlist->version,
|
|
currheaderlist->size, currheaderlist->filenamecount,
|
|
ct->repository[currheaderlist->altrepository]->tag,
|
|
currheaderlist->epoch,
|
|
currheaderlist->release);
|
|
currheaderlist = currheaderlist->next;
|
|
}
|
|
fclose(fd);
|
|
|
|
return 0;
|
|
}
|