bin_PROGRAMS = ppastats
ppastats_SOURCES = \
cache.h cache.c\
+ chart.h chart.c\
html.h html.c\
list.h list.c\
lp.h lp.c\
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
PROGRAMS = $(bin_PROGRAMS)
-am_ppastats_OBJECTS = cache.$(OBJEXT) html.$(OBJEXT) list.$(OBJEXT) \
- lp.$(OBJEXT) lp_json.$(OBJEXT) lp_ws.$(OBJEXT) main.$(OBJEXT) \
- ppastats.$(OBJEXT)
+am_ppastats_OBJECTS = cache.$(OBJEXT) chart.$(OBJEXT) html.$(OBJEXT) \
+ list.$(OBJEXT) lp.$(OBJEXT) lp_json.$(OBJEXT) lp_ws.$(OBJEXT) \
+ main.$(OBJEXT) ppastats.$(OBJEXT)
ppastats_OBJECTS = $(am_ppastats_OBJECTS)
ppastats_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
ppastats_SOURCES = \
cache.h cache.c\
+ chart.h chart.c\
html.h html.c\
list.h list.c\
lp.h lp.c\
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chart.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/html.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lp.Po@am__quote@
--- /dev/null
+/*
+ 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
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <json/json.h>
+
+#include "chart.h"
+
+#define HTML_TEMPLATE \
+"<html>\n\
+ <head>\n\
+ <script type='text/javascript'\
+ src='https://www.google.com/jsapi'></script>\n\
+ <script type='text/javascript'>\n\
+ google.load('visualization', '1', {packages:['corechart']});\
+ google.setOnLoadCallback(drawChart);\n\
+ function drawChart() {\n\
+ var data = new google.visualization.DataTable();\n\
+ data.addColumn('string', 'Date');\n\
+ data.addColumn('number', 'Daily Download');\n\
+ data.addRows(%s);\n\
+ data.sort(0);\n\
+ var chart = new google.visualization.LineChart\
+ (document.getElementById('chart_div'));\n\
+ chart.draw(data, {width: 1024, height: 768,\
+ title: 'PPA Statistics'});\n\
+ }\n\
+ </script>\n\
+ </head>\n\
+\n\
+ <body>\n\
+ <div id='chart_div'></div>\n\
+ </body>\n\
+</html>\n"
+
+char *tm_to_str(struct tm *date)
+{
+ char *str = malloc(10+1);
+
+ sprintf(str, "%d-%02d-%02d",
+ date->tm_year+1900,
+ date->tm_mon+1,
+ date->tm_mday);
+
+ return str;
+}
+
+void
+generate_chart(const char *path,
+ const char *title,
+ const char *name,
+ struct daily_download_total **totals)
+{
+ FILE *f;
+ struct daily_download_total **cur;
+ struct daily_download_total *total;
+ char *str_date;
+ json_object *arr, *item;
+
+ if (!totals) {
+ fprintf(stderr, "ERROR: no totals\n");
+ return ;
+ }
+
+ f = fopen(path, "w");
+
+ if (!f) {
+ fprintf(stderr, "ERROR: failed to open: %s\n", path);
+ return ;
+ }
+
+ arr = json_object_new_array();
+ cur = totals;
+ while(*cur) {
+ total = *cur;
+
+ str_date = tm_to_str(&(total->date));
+
+ item = json_object_new_array();
+
+ json_object_array_add(item, json_object_new_string(str_date));
+ json_object_array_add(item,
+ json_object_new_int(total->count));
+
+ json_object_array_add(arr, item);
+
+ free(str_date);
+
+ cur++;
+ }
+
+ fprintf(f,
+ HTML_TEMPLATE,
+ json_object_to_json_string(arr));
+
+ json_object_put(arr);
+
+ fclose(f);
+}
--- /dev/null
+/*
+ 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
+*/
+
+#ifndef _PPASTATS_CHART_H_
+#define _PPASTATS_CHART_H_
+
+#include "lp.h"
+
+void
+generate_chart(const char *path,
+ const char *title,
+ const char *name,
+ struct daily_download_total **totals);
+
+#endif
#include <string.h>
+#include "chart.h"
#include "html.h"
#include "list.h"
#include "lp_ws.h"
+#include "ppastats.h"
#include <json/json.h>
return str;
}
-void ppa_to_html(const char *owner, const char *ppa, const char *package_status)
+static char *get_path(const char *dir, const char *file)
+{
+ char *path = malloc(strlen(dir)+1+strlen(file)+1);
+
+ strcpy(path, dir);
+ strcat(path, "/");
+ strcat(path, file);
+
+ return path;
+}
+
+void
+ppa_to_html(const char *owner,
+ const char *ppa,
+ const char *package_status,
+ const char *output_dir)
{
struct binary_package_publishing_history **list;
- char *archive_url = get_archive_url(owner, ppa);
- char *addcolumns_str;
- char *data_str;
+ char *archive_url, *addcolumns_str, *data_str, *path;
+ FILE *f;
+ struct ppa_stats *ppastats;
+ struct daily_download_total **totals;
+
+ ppastats = create_ppa_stats(owner, ppa, package_status);
+ totals = ppastats->daily_download_totals;
+ path = get_path(output_dir, "ppa.html");
+ generate_chart(path, "PPA Statistics", ppa, totals);
+ free(path);
+
+ archive_url = get_archive_url(owner, ppa);
list = get_binary_package_publishing_history_list(archive_url,
package_status);
free(archive_url);
if (!list) {
- fprintf(stderr, "Failed to retrieve PPA information\n");
+ fprintf(stderr, "ERROR: Failed to retrieve PPA information\n");
exit(EXIT_FAILURE);
}
addcolumns_str = build_addcolums_str(list);
data_str = build_data_str(list);
- printf(HTML_TEMPLATE, addcolumns_str, data_str);
+ path = get_path(output_dir, "index.html");
+ f = fopen(path, "w");
+ if (f) {
+ fprintf(f, HTML_TEMPLATE, addcolumns_str, data_str);
+ fclose(f);
+ } else {
+ fprintf(stderr, "ERROR: failed to write %s\n", path);
+ }
+ free(path);
free(addcolumns_str);
free(data_str);
binary_package_publishing_history_list_free(list);
+ ppa_stats_free(ppastats);
}
void ppa_to_html(const char *owner,
const char *ppa,
- const char *package_status);
+ const char *package_status,
+ const char *output_dir);
#endif
new_list = malloc(sizeof(void *)*(n+2));
- if (n)
+ if (n) {
memcpy(new_list, list, sizeof(void *)*n);
+ free(list);
+ }
new_list[n] = new_item;
new_list[n+1] = NULL;
- free(list);
-
return new_list;
}
+void **list_add_list(void **list1, void **list2)
+{
+ int n1, n2, n;
+ void **list;
+
+ n1 = list_length(list1);
+ n2 = list_length(list2);
+
+ n = n1 + n2 + 1;
+
+ list = malloc(sizeof(void *)*(n+1));
+
+ memcpy(list, list1, n1*sizeof(void *));
+ memcpy(list+n1, list2, n2*sizeof(void *));
+
+ list[n1+n2] = NULL;
+
+ free(list1);
+
+ return list;
+}
+
int list_length(void **list);
void **list_add(void **list, void *new_item);
+void **list_add_list(void **list1, void **list2);
#endif
return NULL;
}
-static void **list_add_list(void **list1, void **list2)
-{
- int n1, n2, n;
- void **list;
-
- n1 = list_length(list1);
- n2 = list_length(list2);
-
- n = n1 + n2 + 1;
-
- list = malloc(sizeof(void *)*(n+1));
-
- memcpy(list, list1, n1*sizeof(void *));
- memcpy(list+n1, list2, n2*sizeof(void *));
-
- list[n1+n2] = NULL;
-
- free(list1);
-
- return list;
-}
-
#define json_object_to_bpph_list \
json_object_to_binary_package_publishing_history_list
static struct option long_options[] = {
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
- {"html", no_argument, 0, 't'},
+ {"html", required_argument, 0, 't'},
{"debug", no_argument, 0, 'd'},
{"status", required_argument, 0, 's'},
{0, 0, 0, 0}
int output_html = 0;
char *package_status = NULL;
int cmdok = 1;
+ char *output_dir = NULL;
program_name = argv[0];
- while ((optc = getopt_long(argc, argv, "vhtds:", long_options,
+ while ((optc = getopt_long(argc, argv, "vht:ds:", long_options,
NULL)) != -1) {
switch (optc) {
case 't':
output_html = 1;
+ output_dir = strdup(optarg);
break;
case 'd':
debug = 1;
ppa = argv[optind+1];
if (output_html)
- ppa_to_html(owner, ppa, package_status);
+ ppa_to_html(owner, ppa, package_status, output_dir);
else
display_published_binaries(owner, ppa, package_status);
/* for valgrind.... */
free(package_status);
+ free(output_dir);
lp_ws_cleanup();
cache_cleanup();
}
+static struct daily_download_total **
+add_total(struct daily_download_total **totals,
+ struct daily_download_total *total)
+{
+ struct daily_download_total **cur;
+ struct daily_download_total *item;
+
+ cur = totals;
+ while (*cur) {
+ item = *cur;
+
+ if (item->date.tm_year == total->date.tm_year &&
+ item->date.tm_mon == total->date.tm_mon &&
+ item->date.tm_mday == total->date.tm_mday) {
+ item->count += total->count;
+ return totals;
+ }
+
+ cur++;
+ }
+
+ item = malloc(sizeof(struct daily_download_total));
+ memcpy(item, total, sizeof(struct daily_download_total));
+
+ return (struct daily_download_total **)
+ list_add((void **)totals, (void *)item);
+}
+
+struct daily_download_total **
+add_totals(struct daily_download_total **total1,
+ struct daily_download_total **total2)
+{
+ struct daily_download_total **cur;
+ struct daily_download_total **result;
+
+ if (!total1)
+ return total2;
+
+ result = total1;
+ cur = total2;
+ while (*cur) {
+ result = add_total(result, *cur);
+
+ cur++;
+ }
+
+ return result;
+}
+
struct ppa_stats *
create_ppa_stats(const char *owner,
const char *ppa,
struct distro_stats *distro;
struct arch_stats *arch;
int count;
+ struct daily_download_total **totals;
ppa_url = get_archive_url(owner, ppa);
history = get_binary_package_publishing_history_list(ppa_url,
ppastats->download_count += count;
+ totals = get_daily_download_totals(h->self_link);
+ ppastats->daily_download_totals
+ = add_totals(ppastats->daily_download_totals,
+ totals);
+
+ if (ppastats->daily_download_totals != totals)
+ daily_download_total_list_free(totals);
+
h_cur++;
}
struct package_stats **packages;
int download_count;
- struct daily_download_total *daily_download_totals;
+ struct daily_download_total **daily_download_totals;
};
struct ppa_stats *create_ppa_stats(const char *owner,