ppa stats graph
authorJean-Philippe Orsini <jeanfi@gmail.com>
Sun, 22 May 2011 22:12:31 +0000 (22:12 +0000)
committerJean-Philippe Orsini <jeanfi@gmail.com>
Sun, 22 May 2011 22:12:31 +0000 (22:12 +0000)
12 files changed:
src/Makefile.am
src/Makefile.in
src/chart.c [new file with mode: 0644]
src/chart.h [new file with mode: 0644]
src/html.c
src/html.h
src/list.c
src/list.h
src/lp_ws.c
src/main.c
src/ppastats.c
src/ppastats.h

index a662a5f..9fc8b01 100644 (file)
@@ -7,6 +7,7 @@ LIBS += $(CURL_LIBS) $(JSON_LIBS)
 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\
index 12908ec..d63cb70 100644 (file)
@@ -46,9 +46,9 @@ CONFIG_CLEAN_FILES =
 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)
@@ -189,6 +189,7 @@ AM_CPPFLAGS = -Wall -std=gnu99 -Werror \
 
 ppastats_SOURCES = \
        cache.h cache.c\
+       chart.h chart.c\
        html.h html.c\
        list.h list.c\
        lp.h lp.c\
@@ -280,6 +281,7 @@ distclean-compile:
        -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@
diff --git a/src/chart.c b/src/chart.c
new file mode 100644 (file)
index 0000000..f11feb8
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+    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);
+}
diff --git a/src/chart.h b/src/chart.h
new file mode 100644 (file)
index 0000000..0791a91
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    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
index 28fe195..aa4c6f1 100644 (file)
 
 #include <string.h>
 
+#include "chart.h"
 #include "html.h"
 #include "list.h"
 #include "lp_ws.h"
+#include "ppastats.h"
 
 #include <json/json.h>
 
@@ -188,28 +190,61 @@ build_data_str(struct binary_package_publishing_history **list)
        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);
 }
index 79ed705..b165f78 100644 (file)
@@ -24,6 +24,7 @@
 
 void ppa_to_html(const char *owner,
                 const char *ppa,
-                const char *package_status);
+                const char *package_status,
+                const char *output_dir);
 
 #endif
index ceb4efa..76a37e6 100644 (file)
@@ -44,14 +44,36 @@ void **list_add(void **list, void *new_item)
 
        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;
+}
+
index f2115c8..69b7b25 100644 (file)
@@ -22,5 +22,6 @@
 
 int list_length(void **list);
 void **list_add(void **list, void *new_item);
+void **list_add_list(void **list1, void **list2);
 
 #endif
index 2370d36..6c2e299 100644 (file)
@@ -116,28 +116,6 @@ static json_object *get_json_object(const char *url)
        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
 
index 1997551..1629053 100644 (file)
@@ -86,7 +86,7 @@ static void display_published_binaries(const char *owner,
 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}
@@ -140,14 +140,16 @@ int main(int argc, char **argv)
        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;
@@ -178,12 +180,13 @@ int main(int argc, char **argv)
        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();
 
index 56a8942..70f6c6f 100644 (file)
@@ -137,6 +137,55 @@ static struct arch_stats *get_arch_stats(struct distro_stats *distro,
 }
 
 
+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,
@@ -154,6 +203,7 @@ create_ppa_stats(const char *owner,
        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,
@@ -198,6 +248,14 @@ create_ppa_stats(const char *owner,
 
                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++;
        }
 
index 1f8ea61..019c5d4 100644 (file)
@@ -61,7 +61,7 @@ struct ppa_stats {
 
        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,