X-Git-Url: https://git.wpitchoune.net/gitweb/?a=blobdiff_plain;f=src%2Fhtml.c;h=9d8625520c6bb275b8d9a1636067b18e1b014bac;hb=15efb827ba930217333f96c3fefdcb21434436bb;hp=4eddeb3f8af13d7c8af6a050977ca170f99ff261;hpb=eab64e6ecb435face78646153fe86c22895d8f41;p=ppastats.git diff --git a/src/html.c b/src/html.c index 4eddeb3..9d86255 100644 --- a/src/html.c +++ b/src/html.c @@ -1,21 +1,24 @@ /* - Copyright (C) 2011 jeanfi@gmail.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; 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., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA -*/ + * Copyright (C) 2011-2014 jeanfi@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#define _(String) gettext(String) #include #include @@ -24,137 +27,43 @@ #include #include -#include +#include #include "html.h" -#include "io.h" #include "lp.h" +#include #include "lp_ws.h" #include "ppastats.h" +#include +#include +#include + +static char *css_dir; +static char *js_dir; +static char *tpl_dir; -#define HTML_FOOTER \ -"
Generated by \ -ppastats
\n\ - \n\ -" - -#define HTML_PKG_TEMPLATE \ -"\n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ -

N/A

\n\ -

PPA: \n\ - \n\ - N/A/N/A\n\ -

\n\ -
\n\ -
\n\ -
\n\ -
\n\ -
\n\ -
Versions:
\n\ -
Distros:
\n\ -
\n\ -%s" - -#define HTML_VERSION_TEMPLATE \ -"\n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ -

N/A

\n\ -
Version:
\n\ -

PPA: \n\ - \n\ - N/A/N/A\n\ -

\n\ -
\n\ -
\n\ -
\n\ -
\n\ -
\n\ - Distros:\n\ -
    \n\ -
    \n\ -
    \n\ -%s" - -#define HTML_HEADER \ -"\n\ - \n\ - %s\n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n" - -#define HTML_INDEX_TEMPLATE \ -"

    N/A

    \n\ -
    \n\ -
    \n\ - Packages:\n\ -
      \n\ -
      \n\ -
      \n\ -
      \n\ -
      \n\ -
      \n" +static char *footer; +static char *ppa_body; +static char *pkg_body; +static char *pkg_version_body; +static char *header; + +void html_set_theme_dir(const char *theme_dir) +{ + css_dir = path_append(theme_dir, "css"); + js_dir = path_append(theme_dir, "js"); + tpl_dir = path_append(theme_dir, "templates"); +} static char *path_new(const char *dir, const char *file, const char *suffixe) { - char *path = malloc(strlen(dir)+1+ - strlen(file)+ - strlen(".html")+ - (suffixe ? strlen(suffixe) : 0) + - 1); + char *path; + + /* [dir]/[file][suffixe] */ + path = malloc(strlen(dir)+1+ + strlen(file)+ + (suffixe ? strlen(suffixe) : 0) + + 1); strcpy(path, dir); strcat(path, "/"); @@ -164,53 +73,169 @@ static char *path_new(const char *dir, const char *file, const char *suffixe) return path; } -static struct json_object *date_to_json(struct tm *tm) +static char *get_header(const char *title, const char *script) { - json_object *json; + char *res, *tmp, *path; - json = json_object_new_array(); - json_object_array_add(json, json_object_new_int(tm->tm_year+1900)); - json_object_array_add(json, json_object_new_int(tm->tm_mon+1)); - json_object_array_add(json, json_object_new_int(tm->tm_mday)); + if (!header) { + path = path_append(tpl_dir, "header.tpl"); + header = file_get_content(path); + } else { + path = NULL; + } - return json; + if (header) { + tmp = strdup(header); + res = strrep(tmp, "@SCRIPT@", script); + + if (res != tmp) + free(tmp); + + tmp = res; + res = strrep(tmp, "@TITLE@", title); + + if (res != tmp) + free(tmp); + } else { + log_err("Failed to read header template: %s", path); + res = NULL; + } + + free(path); + + return res; +} + +static const char *get_footer() +{ + char *path; + + if (!footer) { + path = path_append(tpl_dir, "footer.tpl"); + footer = file_get_content(path); + + if (!footer) + log_err("Failed to read footer template: %s", path); + + free(path); + } + + return footer; +} + +static const char *get_pkg_version_body() +{ + char *path; + + if (!pkg_version_body) { + path = path_append(tpl_dir, "pkg_version.tpl"); + pkg_version_body = file_get_content(path); + + if (!pkg_version_body) + log_err("Failed to read package version template: %s", + path); + + free(path); + } + + return pkg_version_body; +} +static const char *get_ppa_body() +{ + char *path; + + if (!ppa_body) { + path = path_append(tpl_dir, "ppa.tpl"); + ppa_body = file_get_content(path); + + if (!ppa_body) + log_err("Failed to read PPA template: %s", path); + + free(path); + } + + return ppa_body; +} + +static const char *get_pkg_body() +{ + char *path; + + if (!pkg_body) { + path = path_append(tpl_dir, "pkg.tpl"); + pkg_body = file_get_content(path); + + if (!pkg_body) + log_err("Failed to read package template: %s", path); + + free(path); + } + + return pkg_body; } static void json_add_ddts(json_object *json, struct daily_download_total **ddts) { - json_object *json_ddt, *json_ddts; - struct daily_download_total *ddt; + json_object_object_add(json, "ddts", ddts_to_json(ddts)); +} - json_ddts = json_object_new_array(); - json_object_object_add(json, "ddts", json_ddts); +static json_object *distro_to_json(struct distro_stats *d) +{ + json_object *json; - if (!ddts) - return ; + json = json_object_new_object(); + + json_object_object_add(json, + "name", + json_object_new_string(d->name)); + + json_object_object_add(json, + "count", + json_object_new_int(d->download_count)); - while (*ddts) { - ddt = *ddts; + json_add_ddts(json, d->ddts); - json_ddt = json_object_new_object(); - json_object_object_add(json_ddt, - "value", - json_object_new_int(ddt->count)); - json_object_object_add(json_ddt, - "time", - date_to_json(&ddt->date)); + return json; +} + +static int version_cmp(const void *o1, const void *o2) +{ + struct version_stats **v1, **v2; - json_object_array_add(json_ddts, json_ddt); + v1 = (struct version_stats **)o1; + v2 = (struct version_stats **)o2; - ddts++; + return (*v1)->date_created <= (*v2)->date_created; +} + +static struct version_stats **sort_versions(struct version_stats **vers) +{ + size_t n; + struct version_stats **tmp, **result; + + tmp = vers; + n = 0; + while (*tmp) { + n++; + tmp++; } + + result = malloc((n + 1) * sizeof(struct version_stats *)); + memcpy(result, vers, n * sizeof(struct version_stats *)); + result[n] = NULL; + + qsort(result, n, sizeof(struct version_stats *), version_cmp); + + return result; } -static char *pkg_to_json(struct ppa_stats *ppa, struct package_stats *pkg) +static json_object * +pkg_to_json(struct ppa_stats *ppa, struct package_stats *pkg) { json_object *json, *json_versions, *json_distros, *json_distro; - char *ret; - struct version_stats **versions; - struct distro_stats **distros, *distro; + struct version_stats **versions, **tmp; + struct distro_stats **distros, *d; json = json_object_new_object(); @@ -225,14 +250,16 @@ static char *pkg_to_json(struct ppa_stats *ppa, struct package_stats *pkg) json_versions = json_object_new_array(); json_object_object_add(json, "versions", json_versions); - versions = pkg->versions; - while (*versions) { + versions = sort_versions(pkg->versions); + tmp = versions; + while (*tmp) { json_object_array_add (json_versions, - json_object_new_string((*versions)->version)); + json_object_new_string((*tmp)->version)); - versions++; + tmp++; } + free(versions); distros = pkg->distros; if (distros) { @@ -240,19 +267,14 @@ static char *pkg_to_json(struct ppa_stats *ppa, struct package_stats *pkg) json_object_object_add(json, "distros", json_distros); while (*distros) { - distro = *distros; + d = *distros; - json_distro = json_object_new_object(); - json_object_array_add(json_distros, json_distro); - json_object_object_add - (json_distro, - "name", json_object_new_string(distro->name)); - json_object_object_add - (json_distro, - "count", - json_object_new_int(distro->download_count)); + if (d->download_count) { + json_distro = distro_to_json(d); - json_add_ddts(json_distro, distro->ddts); + json_object_array_add(json_distros, + json_distro); + } distros++; } @@ -260,11 +282,7 @@ static char *pkg_to_json(struct ppa_stats *ppa, struct package_stats *pkg) json_add_ddts(json, pkg->daily_download_totals); - ret = strdup(json_object_to_json_string(json)); - - json_object_put(json); - - return ret; + return json; } static char *version_to_json(struct ppa_stats *ppa, @@ -290,6 +308,9 @@ static char *version_to_json(struct ppa_stats *ppa, json_object_object_add(json, "name", json_object_new_string(ver->version)); + json_object_object_add(json, + "date_created", time_to_json(ver->date_created)); + json_add_ddts(json, ver->daily_download_totals); distros = ver->distros; @@ -370,143 +391,179 @@ static json_object *ppa_to_json(struct ppa_stats *ppa) return json; } - static void -pkg_to_html(struct ppa_stats *ppa, struct package_stats *pkg, const char *dir) +create_html(const char *path, + const char *title, + const char *body_template, + const char *script) { - char *path; FILE *f; - char *json; + const char *footer; + char *header; + + f = NULL; + + header = get_header(title, script); + if (!header) { + log_err(_("Failed to get the header template")); + goto on_error; + } - path = path_new(dir, pkg->name, ".html"); f = fopen(path, "w"); if (!f) { - fprintf(stderr, "ERROR: failed to open: %s\n", path); - return ; + log_err(_("Failed to open: %s"), path); + goto on_error; } - json = pkg_to_json(ppa, pkg); + fputs(header, f); + fputs(body_template, f); - fprintf(f, HTML_PKG_TEMPLATE, json, HTML_FOOTER); + footer = get_footer(); + if (footer) + fputs(footer, f); - fclose(f); + on_error: + if (header) + free(header); - free(path); - free(json); + if (f) + fclose(f); } -static void -version_to_html(struct ppa_stats *ppa, - struct package_stats *pkg, - struct version_stats *version, - const char *dir) +static char *ppa_display_name(const struct ppa_stats *ppa) { - char *f_name, *path; - FILE *f; - - f_name = malloc(strlen(pkg->name)+1+strlen(version->version)+1); - sprintf(f_name, "%s_%s", pkg->name, version->version); - - path = path_new(dir, f_name, ".html"); - f = fopen(path, "w"); - - if (!f) { - fprintf(stderr, "ERROR: failed to open: %s\n", path); - return ; - } + char *ret; - fprintf(f, HTML_VERSION_TEMPLATE, - version_to_json(ppa, pkg, version), - HTML_FOOTER); + ret = malloc(4+strlen(ppa->name)+1+strlen(ppa->owner)+1); - fclose(f); + sprintf(ret, "ppa:%s/%s", ppa->owner, ppa->name); - free(path); - free(f_name); + return ret; } static void -packages_to_html(struct ppa_stats *ppa, - struct package_stats **packages, - const char *dir) +index_to_html(struct ppa_stats *ppa, const char *dir) { - struct package_stats **cur; - struct version_stats **versions; + char *path, *json_path, *dname; + json_object *json; + const char *body; - cur = packages; - while (*cur) { - pkg_to_html(ppa, *cur, dir); + body = get_ppa_body(); + if (!body) { + log_err("Failed to create PPA page"); + return ; + } - versions = (*cur)->versions; - while (*versions) { - version_to_html(ppa, *cur, *versions, dir); + json = ppa_to_json(ppa); + json_path = path_new(dir, "index", ".json"); - versions++; - } + log_debug(_("generating %s"), json_path); + json_object_to_file(json_path, json); + json_object_put(json); + free(json_path); - cur++; - } + path = path_new(dir, "index", ".html"); + dname = ppa_display_name(ppa); + create_html(path, dname, body, "ppastats_ppa();"); + free(path); + free(dname); } static void -create_html(const char *path, - const char *title, - const char *body_template, - const char *script) +version_to_html(struct ppa_stats *ppa, + struct package_stats *pkg, + struct version_stats *version, + const char *dir) { - FILE *f; - - f = fopen(path, "w"); + char *f_name, *path; + const char *body; + const char *script_tpl; + char *script, *json; - if (!f) { - fprintf(stderr, "ERROR: failed to open: %s\n", path); + body = get_pkg_version_body(); + if (!body) { + log_err("Failed to create package version page"); return ; } - fprintf(f, HTML_HEADER, title, script); - fputs(HTML_INDEX_TEMPLATE, f); - fputs(HTML_FOOTER, f); + json = version_to_json(ppa, pkg, version); + if (!json) { + log_err("Failed to create package version page"); + return ; + } - fclose(f); -} + f_name = malloc(strlen(pkg->name)+1+strlen(version->version)+1); + sprintf(f_name, "%s_%s", pkg->name, version->version); -static char *ppa_display_name(const struct ppa_stats *ppa) -{ - char *ret; + path = path_new(dir, f_name, ".html"); - ret = malloc(4+strlen(ppa->name)+1+strlen(ppa->owner)+1); + script_tpl = "var data = %s;\n ppastats_ver();"; + script = malloc(strlen(script_tpl) - 2 + strlen(json) + 1); + sprintf(script, script_tpl, json); - sprintf(ret, "ppa:%s/%s", ppa->owner, ppa->name); + create_html(path, f_name, body, script); - return ret; + free(script); + free(json); + free(path); + free(f_name); } static void -index_to_html(struct ppa_stats *ppa, const char *dir) +pkg_to_html(struct ppa_stats *ppa, struct package_stats *pkg, const char *dir) { - char *path, *json_path, *dname; + char *path, *json_path, *script; json_object *json; + const char *body; - json = ppa_to_json(ppa); - - json_path = path_new(dir, "index", ".json"); + body = get_pkg_body(); + if (!body) { + log_err("Failed to create package page: %s", pkg->name); + return ; + } - if (debug) - printf("DEBUG: generating %s\n", json_path); + json_path = path_new(dir, pkg->name, ".json"); + json = pkg_to_json(ppa, pkg); + log_debug(_("Generating %s"), json_path); json_object_to_file(json_path, json); - json_object_put(json); + free(json_path); - path = path_new(dir, "index", ".html"); - dname = ppa_display_name(ppa); + path = path_new(dir, pkg->name, ".html"); + script = malloc(strlen("ppastats_pkg(\"\");")+ + strlen(pkg->name)+ + strlen(".json")+ + 1); + sprintf(script, "ppastats_pkg(\"%s%s\");", pkg->name, ".json"); - create_html(path, dname, HTML_INDEX_TEMPLATE, "ppastats_ppa();"); + log_debug(_("Generating %s"), path); + create_html(path, pkg->name, body, script); free(path); - free(dname); - free(json_path); + free(script); +} + +static void +pkgs_to_html(struct ppa_stats *ppa, + struct package_stats **pkgs, + const char *dir) +{ + struct version_stats **versions; + + while (*pkgs) { + pkg_to_html(ppa, *pkgs, dir); + + versions = (*pkgs)->versions; + while (*versions) { + version_to_html(ppa, *pkgs, *versions, dir); + + versions++; + } + + pkgs++; + } } void @@ -514,53 +571,31 @@ ppa_to_html(const char *owner, const char *ppa, const char *package_status, const char *output_dir, - const int install_static_files) + const int install_static_files, + int ws_size) { struct ppa_stats *ppastats; - struct daily_download_total **totals; - char *path, *f_dst; - char *css_dir, *js_dir; - int i; - static char *www_files[] - = { DEFAULT_WWW_DIR"/jquery.min.js", "js/jquery.min.js", - DEFAULT_WWW_DIR"/ppastats.js", "js/ppastats.js", - DEFAULT_WWW_DIR"/jqplot.dateAxisRenderer.min.js", - "js/jqplot.dateAxisRenderer.min.js", - DEFAULT_WWW_DIR"/jquery.jqplot.min.js", - "js/jquery.jqplot.min.js", - DEFAULT_WWW_DIR"/ppastats.css", "css/ppastats.css", - DEFAULT_WWW_DIR"/jquery.jqplot.min.css", - "css/jquery.jqplot.min.css" }; + char *path; + char *css_odir, *js_odir; mkdirs(output_dir, 0777); if (install_static_files) { - css_dir = path_append(output_dir, "css"); - js_dir = path_append(output_dir, "js"); + css_odir = path_append(output_dir, "css"); + js_odir = path_append(output_dir, "js"); - mkdir(css_dir, 0777); - mkdir(js_dir, 0777); + dir_rcopy(css_dir, css_odir); + dir_rcopy(js_dir, js_odir); - for (i = 0; i < 6; i++) { - f_dst = path_append(output_dir, www_files[2*i+1]); - - if (debug) - printf("DEBUG: copying %s %s\n", - www_files[2*i], f_dst); - fcopy(www_files[2*i], f_dst); - - free(f_dst); - } - free(css_dir); - free(js_dir); + free(css_odir); + free(js_odir); } - ppastats = create_ppa_stats(owner, ppa, package_status); - totals = ppastats->daily_download_totals; + ppastats = create_ppa_stats(owner, ppa, package_status, ws_size); path = path_new(output_dir, "ppa", ".html"); - packages_to_html(ppastats, ppastats->packages, output_dir); + pkgs_to_html(ppastats, ppastats->packages, output_dir); index_to_html(ppastats, output_dir); @@ -568,3 +603,15 @@ ppa_to_html(const char *owner, free(path); } + +void html_cleanup() +{ + free(header); + free(footer); + free(ppa_body); + free(pkg_body); + free(pkg_version_body); + free(js_dir); + free(css_dir); + free(tpl_dir); +}