diff -Nru distro-info-0.7.1/debian/changelog distro-info-0.8.1/debian/changelog --- distro-info-0.7.1/debian/changelog 2012-03-25 23:43:16.000000000 +0000 +++ distro-info-0.8.1/debian/changelog 2012-04-03 11:02:37.000000000 +0000 @@ -1,3 +1,20 @@ +distro-info (0.8.1) unstable; urgency=low + + * Fix build failure due to wrong variable type. + + -- Benjamin Drung Tue, 03 Apr 2012 13:02:26 +0200 + +distro-info (0.8) unstable; urgency=low + + * Run shell scripts with 'set -f' (LP: #965378). + * Rewrite scripts in C. The binaries are 2.3 times bigger than the shell + scripts, but they are between four and six times faster. Forking the process + takes longer than executing it. The plain execution time is around 25 times + faster than the shell scripts. + * Extend command line test cases. + + -- Benjamin Drung Tue, 03 Apr 2012 01:24:23 +0200 + distro-info (0.7.1) unstable; urgency=low * Use shunit2 for testing the command line scripts instead of using an own diff -Nru distro-info-0.7.1/debian/control distro-info-0.8.1/debian/control --- distro-info-0.7.1/debian/control 2012-03-25 11:58:36.000000000 +0000 +++ distro-info-0.8.1/debian/control 2012-04-02 21:52:22.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Benjamin Drung Uploaders: Stefano Rivera Build-Depends: debhelper (>= 8), - distro-info-data, + distro-info-data (>= 0.7~), liblist-compare-perl, pylint, python-all (>= 2.6.3-3~), @@ -17,8 +17,8 @@ Vcs-Browser: http://git.debian.org/?p=collab-maint/distro-info.git Package: distro-info -Architecture: all -Depends: distro-info-data, ${misc:Depends} +Architecture: any +Depends: distro-info-data (>= 0.7~), ${misc:Depends}, ${shlibs:Depends} Suggests: shunit2 (>= 2.1.6) Breaks: ubuntu-dev-tools (<< 0.133~) Replaces: ubuntu-dev-tools (<< 0.127~) diff -Nru distro-info-0.7.1/debian/copyright distro-info-0.8.1/debian/copyright --- distro-info-0.7.1/debian/copyright 2012-03-25 01:03:33.000000000 +0000 +++ distro-info-0.8.1/debian/copyright 2012-04-02 21:52:22.000000000 +0000 @@ -7,7 +7,7 @@ 2010-2011, Stefano Rivera License: ISC -Files: *-distro-info.in distro-info-util.sh +Files: shell/*-distro-info.in shell/distro-info-util.sh Copyright: 2012 Canonical Ltd. License: ISC diff -Nru distro-info-0.7.1/debian-distro-info.c distro-info-0.8.1/debian-distro-info.c --- distro-info-0.7.1/debian-distro-info.c 1970-01-01 00:00:00.000000000 +0000 +++ distro-info-0.8.1/debian-distro-info.c 2012-04-03 00:38:37.000000000 +0000 @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012, Benjamin Drung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// C standard libraries +#include + +#include "distro-info-util.h" + +#define DEBIAN +#define CSV_NAME "debian" +#define CSV_HEADER "version,codename,series,created,release,eol" +#define DISTRO_NAME "Debian" +#define NAME "debian-distro-info" + +static bool filter_devel(const date_t *date, const distro_t *distro) { + return created(date, distro) && !released(date, distro) && + *distro->version == '\0'; +} + +static bool filter_oldstable(const date_t *date, const distro_t *distro) { + return created(date, distro) && released(date, distro); +} + +static bool filter_testing(const date_t *date, const distro_t *distro) { + return created(date, distro) && !released(date, distro); +} + +static const distro_t *select_first(const distro_elem_t *distro_list) { + return distro_list->distro; +} + +static const distro_t *select_oldstable(const distro_elem_t *distro_list) { + const distro_t *newest; + const distro_t *second = NULL; + + newest = distro_list->distro; + while(distro_list != NULL) { + distro_list = distro_list->next; + if(distro_list) { + if(date_ge(distro_list->distro->release, newest->release)) { + second = newest; + newest = distro_list->distro; + } else if(second && date_ge(distro_list->distro->release, + second->release)) { + second = distro_list->distro; + } + } + } + return second; +} + +#include "distro-info-util.c" diff -Nru distro-info-0.7.1/debian-distro-info.in distro-info-0.8.1/debian-distro-info.in --- distro-info-0.7.1/debian-distro-info.in 2012-03-23 20:43:25.000000000 +0000 +++ distro-info-0.8.1/debian-distro-info.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -#!/bin/sh -# Copyright (C) 2012 Canonical Ltd. -# Author: Scott Moser -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -DISTRO_INFO_NAME="Debian" -DISTRO_INFO_ARGS="--all --devel --oldstable --stable --supported - --testing --unsupported" -DISTRO_INFO_DATA="/usr/share/distro-info/debian.csv" - -. "${0%/*}/distro-info-util.sh" - -Usage() { - cat < + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// C standard libraries +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "distro-info-util.h" + +static char *read_full_file(const char *filename) { + char *content; + FILE *f; + size_t size; + struct stat stat; + + f = fopen(filename, "r"); + if(unlikely(f == NULL)) { + fprintf(stderr, NAME ": Failed to open %s: %s\n", filename, + strerror(errno)); + return NULL; + } + fstat(fileno(f), &stat); + if(unlikely(stat.st_size < 0)) { + fprintf(stderr, NAME ": %s has a negative file size.\n", filename); + return NULL; + } + size = stat.st_size; + content = malloc(size + 1); + if(unlikely(fread(content, sizeof(char), size, f) != size)) { + fprintf(stderr, NAME ": Failed to read %zu bytes from %s.\n", size, + filename); + free(content); + return NULL; + } + content[size] = '\0'; + fclose(f); + return content; +} + +inline bool is_leap_year(const int year) { + return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; +} + +inline bool is_valid_date(const date_t *date) { + unsigned int days_in_month[] = {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + if(is_leap_year(date->year)) { + days_in_month[1] = 29; + } + return date->month >= 1 && date->month <= 12 && + date->day >= 1 && date->day <= days_in_month[date->month-1]; +} + +// Read an ISO 8601 formatted date +static date_t *read_date(const char *s, int *failures, const char *filename, + const int lineno, const char *column) { + date_t *date = NULL; + int n; + + if(s) { + date = malloc(sizeof(date_t)); + n = sscanf(s, "%u-%u-%u", &date->year, &date->month, &date->day); + if(unlikely(n != 3 || !is_valid_date(date))) { + fprintf(stderr, NAME ": Invalid date `%s' in file `%s' at line %i " + "in column `%s'.\n", s, filename, lineno, column); + (*failures)++; + free(date); + date = NULL; + } + } + return date; +} + +inline bool date_ge(const date_t *date1, const date_t *date2) { + return date1->year > date2->year || + (date1->year == date2->year && date1->month > date2->month) || + (date1->year == date2->year && date1->month == date2->month && + date1->day >= date2->day); +} + +inline bool created(const date_t *date, const distro_t *distro) { + return distro->created && date_ge(date, distro->created); +} + +inline bool released(const date_t *date, const distro_t *distro) { + return *distro->version != '\0' && + distro->release && date_ge(date, distro->release); +} + +inline bool eol(const date_t *date, const distro_t *distro) { + return distro->eol && date_ge(date, distro->eol) && (!distro->eol_server || + (distro->eol_server && date_ge(date, distro->eol_server))); +} + +// Filter callbacks + +static bool filter_all() { + return true; +} + +static bool filter_stable(const date_t *date, const distro_t *distro) { + return released(date, distro) && !eol(date, distro); +} + +static bool filter_supported(const date_t *date, const distro_t *distro) { + return created(date, distro) && !eol(date, distro); +} + +static bool filter_unsupported(const date_t *date, const distro_t *distro) { + return created(date, distro) && eol(date, distro); +} + +// Select callbacks + +static const distro_t *select_latest_created(const distro_elem_t *distro_list) { + const distro_t *selected; + + selected = distro_list->distro; + while(distro_list != NULL) { + distro_list = distro_list->next; + if(distro_list && date_ge(distro_list->distro->created, + selected->created)) { + selected = distro_list->distro; + } + } + return selected; +} + +static const distro_t *select_latest_release(const distro_elem_t *distro_list) { + const distro_t *selected; + + selected = distro_list->distro; + while(distro_list != NULL) { + distro_list = distro_list->next; + if(distro_list && date_ge(distro_list->distro->release, + selected->release)) { + selected = distro_list->distro; + } + } + return selected; +} + +// Print callbacks + +static void print_codename(const distro_t *distro) { + printf("%s\n", distro->series); +} + +static void print_fullname(const distro_t *distro) { + printf(DISTRO_NAME " %s \"%s\"\n", distro->version, distro->codename); +} + +static void print_release(const distro_t *distro) { + if(unlikely(*distro->version == '\0')) { + printf("%s\n", distro->series); + } else { + printf("%s\n", distro->version); + } +} + +// End of callbacks + +static void free_data(distro_elem_t *list, char **content) { + distro_elem_t *next; + + while(list != NULL) { + next = list->next; + free(list->distro->created); + free(list->distro->release); + free(list->distro->eol); + free(list->distro->eol_server); + free(list->distro); + free(list); + list = next; + } + + free(*content); + *content = NULL; +} + +static distro_elem_t *read_data(const char *filename, char **content) { + char *data; + char *line; + distro_elem_t *current; + distro_elem_t *distro_list = NULL; + distro_elem_t *last = NULL; + distro_t *distro; + int lineno; + int failures = 0; + + data = *content = read_full_file(filename); + line = strsep(&data, "\n"); + lineno = 1; + if(unlikely(strcmp(CSV_HEADER, line) != 0)) { + fprintf(stderr, NAME ": Header `%s' in file `%s' does not match " + "excatly `" CSV_HEADER "'.\n", line, filename); + failures++; + } + + while((line = strsep(&data, "\n")) != NULL) { + lineno++; + // Ignore empty lines and comments (starting with #). + if(likely(*line != '\0' && *line != '#')) { + distro = malloc(sizeof(distro_t)); + distro->version = strsep(&line, ","); + distro->codename = strsep(&line, ","); + distro->series = strsep(&line, ","); + distro->created = read_date(strsep(&line, ","), &failures, filename, + lineno, "created"); + distro->release = read_date(strsep(&line, ","), &failures, filename, + lineno, "release"); + distro->eol = read_date(strsep(&line, ","), &failures, filename, + lineno, "eol"); + distro->eol_server = read_date(strsep(&line, ","), &failures, + filename, lineno, "eol-server"); + + current = malloc(sizeof(distro_elem_t)); + current->distro = distro; + current->next = NULL; + if(last == NULL) { + distro_list = current; + } else { + last->next = current; + } + last = current; + } + } + + if(unlikely(distro_list == NULL)) { + fprintf(stderr, NAME ": No data found in file `%s'.\n", filename); + failures++; + } + + if(unlikely(failures > 0)) { + free_data(distro_list, content); + distro_list = NULL; + } + + return distro_list; +} + +static void filter_data(const distro_elem_t *distro_list, const date_t *date, + bool (*filter_cb)(const date_t*, const distro_t*), + void (*print_cb)(const distro_t*)) { + while(distro_list != NULL) { + if(filter_cb(date, distro_list->distro)) { + print_cb(distro_list->distro); + } + distro_list = distro_list->next; + } +} + +static const distro_t *get_distro(const distro_elem_t *distro_list, const date_t *date, + bool (*filter_cb)(const date_t*, const distro_t*), + const distro_t *(*select_cb)(const distro_elem_t*)) { + distro_elem_t *current; + distro_elem_t *filtered_list = NULL; + distro_elem_t *last = NULL; + const distro_t *selected; + + while(distro_list != NULL) { + if(filter_cb(date, distro_list->distro)) { + current = malloc(sizeof(distro_elem_t)); + current->distro = distro_list->distro; + current->next = NULL; + if(last == NULL) { + filtered_list = current; + } else { + last->next = current; + } + last = current; + } + distro_list = distro_list->next; + } + + if(filtered_list == NULL) { + selected = NULL; + } else { + selected = select_cb(filtered_list); + } + + while(filtered_list != NULL) { + current = filtered_list->next; + free(filtered_list); + filtered_list = current; + } + + return selected; +} + +static void print_help(void) { + printf("Usage: " NAME " [options]\n\ +\n\ +Options:\n\ + -h --help show this help message and exit\n\ + --date=DATE date for calculating the version (default: today)\n\ + -a --all list all known versions\n\ + -d --devel latest development version\n" +#ifdef UBUNTU +" --lts latest long term support (LTS) version\n" +#endif +#ifdef DEBIAN +" -o --oldstable latest oldstable version\n" +#endif +" -s --stable latest stable version\n\ + --supported list of all supported stable versions\n" +#ifdef DEBIAN +" -t --testing current testing version\n" +#endif +" --unsupported list of all unsupported stable versions\n\ + -c --codename print the codename (default)\n\ + -r --release print the release version\n\ + -f --fullname print the full name\n\ +\n\ +See " NAME "(1) for more info.\n"); +} + +inline int not_exactly_one(void) { + fprintf(stderr, NAME ": You have to select exactly one of --all, --devel, " +#ifdef UBUNTU + "--lts, " +#endif +#ifdef DEBIAN + "--oldstable, " +#endif + "--stable, --supported, " +#ifdef DEBIAN + "--testing, " +#endif + "--unsupported.\n"); + return EXIT_FAILURE; +} + +int main(int argc, char *argv[]) { + char *content; + date_t *date = NULL; + distro_elem_t *distro_list; + const distro_t *selected; + int i; + int option; + int option_index; + int return_value = EXIT_SUCCESS; + bool (*filter_cb)(const date_t*, const distro_t*) = NULL; + const distro_t *(*select_cb)(const distro_elem_t*) = NULL; + void (*print_cb)(const distro_t*) = print_codename; + + const struct option long_options[] = { + {"help", no_argument, NULL, 'h' }, + {"date", required_argument, NULL, 'D' }, + {"all", no_argument, NULL, 'a' }, + {"devel", no_argument, NULL, 'd' }, + {"stable", no_argument, NULL, 's' }, + {"supported", no_argument, NULL, 'S' }, + {"unsupported", no_argument, NULL, 'U' }, + {"codename", no_argument, NULL, 'c' }, + {"release", no_argument, NULL, 'r' }, + {"fullname", no_argument, NULL, 'f' }, +#ifdef UBUNTU + {"lts", no_argument, NULL, 'L' }, +#endif +#ifdef DEBIAN + {"oldstable", no_argument, NULL, 'o' }, + {"testing", no_argument, NULL, 't' }, +#endif + {NULL, 0, NULL, '\0' } + }; + +#ifdef UBUNTU + const char *short_options = "hadscrf"; +#endif +#ifdef DEBIAN + const char *short_options = "hadscrfot"; +#endif + + // Suppress error messages from getopt_long + opterr = 0; + + while ((option = getopt_long(argc, argv, short_options, + long_options, &option_index)) != -1) { + switch (option) { + case 'a': + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_all; + select_cb = NULL; + break; + + case 'c': + print_cb = print_codename; + break; + + case 'd': + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_devel; +#ifdef UBUNTU + select_cb = select_latest_created; +#endif +#ifdef DEBIAN + select_cb = select_first; +#endif + break; + + case 'D': + // Only long option --date is used + if(unlikely(date != NULL)) { + fprintf(stderr, NAME ": Date specified multiple times.\n"); + free(date); + return EXIT_FAILURE; + } + date = malloc(sizeof(date_t)); + i = sscanf(optarg, "%u-%u-%u", &date->year, &date->month, + &date->day); + if(i != 3 || !is_valid_date(date)) { + fprintf(stderr, NAME ": invalid date `%s'\n", optarg); + free(date); + return EXIT_FAILURE; + } + break; + + case 'f': + print_cb = print_fullname; + break; + + case 'h': + print_help(); + return EXIT_SUCCESS; + +#ifdef UBUNTU + case 'L': + // Only long option --lts is used + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_lts; + select_cb = select_latest_release; + break; +#endif + +#ifdef DEBIAN + case 'o': + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_oldstable; + select_cb = select_oldstable; + break; +#endif + + case 'r': + print_cb = print_release; + break; + + case 's': + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_stable; + select_cb = select_latest_release; + break; + + case 'S': + // Only long option --supported is used + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_supported; + select_cb = NULL; + break; + +#ifdef DEBIAN + case 't': + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_testing; + select_cb = select_latest_created; + break; +#endif + + case 'U': + // Only long option --unsupported is used + if(unlikely(filter_cb != NULL)) return not_exactly_one(); + filter_cb = filter_unsupported; + select_cb = NULL; + break; + + case '?': + if(optopt == '\0') { + // Long option failed + fprintf(stderr, NAME ": unrecognized option `%s'\n", + argv[optind-1]); + } else if(optopt == 'D') { + fprintf(stderr, NAME ": option `--date' requires " + "an argument DATE\n"); + } else { + fprintf(stderr, NAME ": unrecognized option `-%c'\n", + optopt); + } + return EXIT_FAILURE; + break; + + default: + fprintf(stderr, NAME ": getopt returned character code %i. " + "Please file a bug report.\n", option); + return EXIT_FAILURE; + } + } + + if(unlikely(optind < argc)) { + fprintf(stderr, NAME ": unrecognized arguments: %s", argv[optind]); + for(i = optind + 1; i < argc; i++) { + fprintf(stderr, " %s", argv[i]); + } + fprintf(stderr, "\n"); + return EXIT_FAILURE; + } + + if(unlikely(filter_cb == NULL)) { + return not_exactly_one(); + } + + if(unlikely(date == NULL)) { + time_t time_now = time(NULL); + struct tm *now = gmtime(&time_now); + date = malloc(sizeof(date_t)); + date->year = 1900 + now->tm_year; + date->month = 1 + now->tm_mon; + date->day = now->tm_mday; + } + + distro_list = read_data(DATA_DIR "/" CSV_NAME ".csv", &content); + if(unlikely(distro_list == NULL)) { + return EXIT_FAILURE; + } + + if(select_cb == NULL) { + filter_data(distro_list, date, filter_cb, print_cb); + } else { + selected = get_distro(distro_list, date, filter_cb, select_cb); + if(selected == NULL) { + fprintf(stderr, NAME ": Distribution data outdated.\n"); + return_value = EXIT_FAILURE; + } else { + print_cb(selected); + } + } + free_data(distro_list, &content); + return return_value; +} diff -Nru distro-info-0.7.1/distro-info-util.h distro-info-0.8.1/distro-info-util.h --- distro-info-0.7.1/distro-info-util.h 1970-01-01 00:00:00.000000000 +0000 +++ distro-info-0.8.1/distro-info-util.h 2012-04-03 01:09:32.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012, Benjamin Drung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __DISTRO_INFO_UTIL_H__ +#define __DISTRO_INFO_UTIL_H__ + +// C standard libraries +#include + +#ifdef __GNUC__ +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#define DATA_DIR "/usr/share/distro-info" + +typedef struct { + unsigned int year; + unsigned int month; + unsigned int day; +} date_t; + +typedef struct { + char *version; + char *codename; + char *series; + date_t *created; + date_t *release; + date_t *eol; + date_t *eol_server; +} distro_t; + +typedef struct distro_elem_s { + distro_t *distro; + struct distro_elem_s *next; +} distro_elem_t; + +inline bool date_ge(const date_t *date1, const date_t *date2); +inline bool created(const date_t *date, const distro_t *distro); +inline bool released(const date_t *date, const distro_t *distro); +inline bool eol(const date_t *date, const distro_t *distro); + +#endif // __DISTRO_INFO_UTIL_H__ diff -Nru distro-info-0.7.1/distro-info-util.sh distro-info-0.8.1/distro-info-util.sh --- distro-info-0.7.1/distro-info-util.sh 2012-03-23 21:34:07.000000000 +0000 +++ distro-info-0.8.1/distro-info-util.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ -## Copyright (C) 2012 Canonical Ltd. -## Author: Scott Moser -## -## Permission to use, copy, modify, and/or distribute this software for any -## purpose with or without fee is hereby granted, provided that the above -## copyright notice and this permission notice appear in all copies. -## -## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -## WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -## MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -## ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -## WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -## ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -## OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -STORED="0" - -store() { - # store this result. - # Sets the global 'STORED'. if STORED is set, fmt will be called - # once at the end with the data that is stored. - STORED=1 - s_version=$version; - s_codename=$codename; - s_series=$series; - s_created=$created; - s_release=$release; - s_eol=$eol; - s_eols=$eols; -} -restore() { - # restore data previously stored with store - version=$s_version; - codename=$s_codename; - series=$s_series; - created=$s_created; - release=$s_release; - eol=$s_eol; - eols=$s_eols; -} - -created() { - [ -n "$created" ] && date_ge "$CMP_DATE" "$created" -} - -date_ge() { - # compare 2 dates of format YYYY-MM or YYYY-MM-DD - # assume that YYYY-MM is the 30th of the month - local IFS="-" clean1 clean2 d1="$1" d2="$2" - set -- ${d1} 30 - clean1="$1$2$3" - set -- ${d2} 30 - clean2="$1$2$3" - [ "$clean1" -ge "$clean2" ] -} - -devel() { - created && ! released -} - -next_is() { - # call a function as if you were calling it for next - local version=$n_version codename=$n_codename series=$n_series - local created=$n_created release=$n_release eol=$n_eol eols=$n_eols - "$@" -} - -released() { - [ -n "$version" -a -n "$release" ] && date_ge "$CMP_DATE" "$release" -} - -cb_all() { - : -} -cb_stable() { - released && [ -n "$n_version" ] && ! next_is released && store - return 1; -} -cb_supported() { - date_ge "$eols" "$CMP_DATE" && created -} -cb_unsupported() { - created && ! cb_supported -} - -print_codename() { - echo "$series" -} -print_fullname() { - echo "${DISTRO_INFO_NAME} $version \"$codename\"" -} -print_release() { - echo "${version:-${series}}" -} - -filter_data() { - local OIFS="$IFS" tmpvar="" - local callback="$1" fmt="$2" found=0 - shift 2; - IFS="," - local version codename series created release eol eols - local n_version n_codename n_series n_created n_release n_eol n_eols - { - read tmpvar # header of file - read version codename series created release eol eols - [ -n "$eol" ] || eol="9999-99-99" - [ -n "$eols" ] || eols=$eol - while read n_version n_codename n_series n_created n_release n_eol n_eols; do - [ -n "$n_eol" ] || n_eol="9999-99-99" - [ -n "$n_eols" ] || n_eols=$n_eol - "$callback" && found=$(($found+1)) && "$fmt" - version=$n_version; codename=$n_codename; series=$n_series - created=$n_created; release=$n_release; eol=$n_eol; - eols=$n_eols - done - } < "$DISTRO_INFO_DATA" - - "$callback" && found=$(($found+1)) && "$fmt" - [ "$STORED" = "0" ] || { restore; found=$(($found+1)); "$fmt"; } - [ $found -ne 0 ] -} - -data_outdated() { - error "${0##*/}: Distribution data outdated." -} - -date_requires_arg() { - error "${0##*/}: option \`--date' requires an argument DATE" -} - -error() { echo "$@" >&2; } - -not_exactly_one() { - local arg="" msg="You have to select exactly one of" - for arg in $DISTRO_INFO_ARGS; do - msg="$msg ${arg}," - done - msg="${msg%,}." - error "${0##*/}: ${msg}" -} - -main() { - local CMP_DATE="" callback="" fmt="print_codename" date="now" - local tmp tokenized - - while [ $# -ne 0 ]; do - if [ "${1#-[a-z][a-z]}" != "$1" ]; then - # support combined shortformat arguments, by exploding - cur="${1#-}" - while [ -n "$cur" ]; do - tmp=${cur#?}; - tokenized="${tokenized} -${cur%${tmp}}" - cur=${tmp} - done - shift - set -- ${tokenized} "$@" - fi - case "$1" in - -a|--all) - [ -z "$callback" ] || { not_exactly_one; return 1; } - callback="all";; - --date=*) - date=${1#*=}; - [ -n "$date" ] || { date_requires_arg; return 1; } - ;; - --date) - date="$2"; - [ -n "$2" ] || { date_requires_arg; return 1; } - shift;; - -d|--devel) - [ -z "$callback" ] || { not_exactly_one; return 1; } - callback="devel";; - -s|--stable) - [ -z "$callback" ] || { not_exactly_one; return 1; } - callback="stable";; - --supported|--unsupported) - [ -z "$callback" ] || { not_exactly_one; return 1; } - callback="${1#--}";; - -c|--codename) fmt="print_codename";; - -r|--release) fmt="print_release";; - -f|--fullname) fmt="print_fullname";; -#BEGIN ubuntu# - --lts) - [ -z "$callback" ] || { not_exactly_one; return 1; } - callback="lts";; -#END ubuntu# -#BEGIN debian# - -o|--oldstable) - [ -z "$callback" ] || { not_exactly_one; return 1; } - callback="oldstable";; - -t|--testing) - [ -z "$callback" ] || { not_exactly_one; return 1; } - callback="testing";; -#END debian# - -h|--help) Usage; exit 0;; - --*|-*) - error "${0##*/}: unrecognized option \`$1'"; - return 1;; - *) error "${0##*/}: unrecognized arguments: $*"; - return 1;; - esac - shift; - done - [ -n "$callback" ] || { not_exactly_one; return 1; } - - CMP_DATE=$(date --utc +"%Y-%m-%d" "--date=$date" 2>/dev/null) || - { error "${0##*/}: invalid date \`${date}'"; return 1; } - filter_data "cb_$callback" "$fmt" || { data_outdated; return 1; } - return -} -## vi: ts=4 syntax=sh noexpandtab diff -Nru distro-info-0.7.1/haskell/Makefile distro-info-0.8.1/haskell/Makefile --- distro-info-0.7.1/haskell/Makefile 2012-03-22 23:30:38.000000000 +0000 +++ distro-info-0.8.1/haskell/Makefile 2012-04-02 13:47:53.000000000 +0000 @@ -22,6 +22,6 @@ ./test-distro-info clean: - rm -rf *-distro-info *.hi *.o + rm -f *-distro-info *.hi *.o .PHONY: build clean install test diff -Nru distro-info-0.7.1/Makefile distro-info-0.8.1/Makefile --- distro-info-0.7.1/Makefile 2012-03-25 01:05:46.000000000 +0000 +++ distro-info-0.8.1/Makefile 2012-04-02 14:28:38.000000000 +0000 @@ -5,14 +5,12 @@ PREFIX ?= /usr VENDOR ?= $(shell dpkg-vendor --query Vendor | tr '[:upper:]' '[:lower:]') +CFLAGS += -Wall -Wextra -Werror -O2 -std=gnu99 build: debian-distro-info ubuntu-distro-info -%-distro-info: %-distro-info.in distro-info-util.sh - sed -e '/^\. .*distro-info-util.sh\"$$/r distro-info-util.sh' $< | \ - sed -e '/^##/d;/^\. .*distro-info-util.sh\"$$/d' | \ - python -c 'import re,sys;print re.sub("(?<=\n)#BEGIN \w*#\n(.|\n)*?\n#END \w*#\n", "", re.sub("(?<=\n)#(BEGIN|END) $*#\n", "", sys.stdin.read())),' > $@ - chmod +x $@ +%-distro-info: %-distro-info.c distro-info-util.* + gcc $(CFLAGS) -o $@ $< install: debian-distro-info ubuntu-distro-info install -d $(DESTDIR)$(PREFIX)/bin diff -Nru distro-info-0.7.1/shell/debian-distro-info.in distro-info-0.8.1/shell/debian-distro-info.in --- distro-info-0.7.1/shell/debian-distro-info.in 1970-01-01 00:00:00.000000000 +0000 +++ distro-info-0.8.1/shell/debian-distro-info.in 2012-03-27 10:20:02.000000000 +0000 @@ -0,0 +1,65 @@ +#!/bin/sh +set -f + +# Copyright (C) 2012 Canonical Ltd. +# Author: Scott Moser +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +DISTRO_INFO_NAME="Debian" +DISTRO_INFO_ARGS="--all --devel --oldstable --stable --supported + --testing --unsupported" +DISTRO_INFO_DATA="/usr/share/distro-info/debian.csv" + +. "${0%/*}/distro-info-util.sh" + +Usage() { + cat < +## +## Permission to use, copy, modify, and/or distribute this software for any +## purpose with or without fee is hereby granted, provided that the above +## copyright notice and this permission notice appear in all copies. +## +## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +## WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +## MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +## ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +## WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +## ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +## OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +STORED="0" + +store() { + # store this result. + # Sets the global 'STORED'. if STORED is set, fmt will be called + # once at the end with the data that is stored. + STORED=1 + s_version=$version; + s_codename=$codename; + s_series=$series; + s_created=$created; + s_release=$release; + s_eol=$eol; + s_eols=$eols; +} +restore() { + # restore data previously stored with store + version=$s_version; + codename=$s_codename; + series=$s_series; + created=$s_created; + release=$s_release; + eol=$s_eol; + eols=$s_eols; +} + +created() { + [ -n "$created" ] && date_ge "$CMP_DATE" "$created" +} + +date_ge() { + # compare 2 dates of format YYYY-MM or YYYY-MM-DD + # assume that YYYY-MM is the 30th of the month + local IFS="-" clean1 clean2 d1="$1" d2="$2" + set -- ${d1} 30 + clean1="$1$2$3" + set -- ${d2} 30 + clean2="$1$2$3" + [ "$clean1" -ge "$clean2" ] +} + +devel() { + created && ! released +} + +next_is() { + # call a function as if you were calling it for next + local version=$n_version codename=$n_codename series=$n_series + local created=$n_created release=$n_release eol=$n_eol eols=$n_eols + "$@" +} + +released() { + [ -n "$version" -a -n "$release" ] && date_ge "$CMP_DATE" "$release" +} + +cb_all() { + : +} +cb_stable() { + released && [ -n "$n_version" ] && ! next_is released && store + return 1; +} +cb_supported() { + date_ge "$eols" "$CMP_DATE" && created +} +cb_unsupported() { + created && ! cb_supported +} + +print_codename() { + echo "$series" +} +print_fullname() { + echo "${DISTRO_INFO_NAME} $version \"$codename\"" +} +print_release() { + echo "${version:-${series}}" +} + +filter_data() { + local OIFS="$IFS" tmpvar="" + local callback="$1" fmt="$2" found=0 + shift 2; + IFS="," + local version codename series created release eol eols + local n_version n_codename n_series n_created n_release n_eol n_eols + { + read tmpvar # header of file + read version codename series created release eol eols + [ -n "$eol" ] || eol="9999-99-99" + [ -n "$eols" ] || eols=$eol + while read n_version n_codename n_series n_created n_release n_eol n_eols; do + [ -n "$n_eol" ] || n_eol="9999-99-99" + [ -n "$n_eols" ] || n_eols=$n_eol + "$callback" && found=$(($found+1)) && "$fmt" + version=$n_version; codename=$n_codename; series=$n_series + created=$n_created; release=$n_release; eol=$n_eol; + eols=$n_eols + done + } < "$DISTRO_INFO_DATA" + + "$callback" && found=$(($found+1)) && "$fmt" + [ "$STORED" = "0" ] || { restore; found=$(($found+1)); "$fmt"; } + [ $found -ne 0 ] +} + +data_outdated() { + error "${0##*/}: Distribution data outdated." +} + +date_requires_arg() { + error "${0##*/}: option \`--date' requires an argument DATE" +} + +error() { echo "$@" >&2; } + +not_exactly_one() { + local arg="" msg="You have to select exactly one of" + for arg in $DISTRO_INFO_ARGS; do + msg="$msg ${arg}," + done + msg="${msg%,}." + error "${0##*/}: ${msg}" +} + +main() { + local CMP_DATE="" callback="" fmt="print_codename" date="now" + local tmp tokenized + + while [ $# -ne 0 ]; do + if [ "${1#-[a-z][a-z]}" != "$1" ]; then + # support combined shortformat arguments, by exploding + cur="${1#-}" + while [ -n "$cur" ]; do + tmp=${cur#?}; + tokenized="${tokenized} -${cur%${tmp}}" + cur=${tmp} + done + shift + set -- ${tokenized} "$@" + fi + case "$1" in + -a|--all) + [ -z "$callback" ] || { not_exactly_one; return 1; } + callback="all";; + --date=*) + date=${1#*=}; + [ -n "$date" ] || { date_requires_arg; return 1; } + ;; + --date) + date="$2"; + [ -n "$2" ] || { date_requires_arg; return 1; } + shift;; + -d|--devel) + [ -z "$callback" ] || { not_exactly_one; return 1; } + callback="devel";; + -s|--stable) + [ -z "$callback" ] || { not_exactly_one; return 1; } + callback="stable";; + --supported|--unsupported) + [ -z "$callback" ] || { not_exactly_one; return 1; } + callback="${1#--}";; + -c|--codename) fmt="print_codename";; + -r|--release) fmt="print_release";; + -f|--fullname) fmt="print_fullname";; +#BEGIN ubuntu# + --lts) + [ -z "$callback" ] || { not_exactly_one; return 1; } + callback="lts";; +#END ubuntu# +#BEGIN debian# + -o|--oldstable) + [ -z "$callback" ] || { not_exactly_one; return 1; } + callback="oldstable";; + -t|--testing) + [ -z "$callback" ] || { not_exactly_one; return 1; } + callback="testing";; +#END debian# + -h|--help) Usage; exit 0;; + --*|-*) + error "${0##*/}: unrecognized option \`$1'"; + return 1;; + *) error "${0##*/}: unrecognized arguments: $*"; + return 1;; + esac + shift; + done + [ -n "$callback" ] || { not_exactly_one; return 1; } + + CMP_DATE=$(date --utc +"%Y-%m-%d" "--date=$date" 2>/dev/null) || + { error "${0##*/}: invalid date \`${date}'"; return 1; } + filter_data "cb_$callback" "$fmt" || { data_outdated; return 1; } + return +} +## vi: ts=4 syntax=sh noexpandtab diff -Nru distro-info-0.7.1/shell/Makefile distro-info-0.8.1/shell/Makefile --- distro-info-0.7.1/shell/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ distro-info-0.8.1/shell/Makefile 2012-04-02 13:47:45.000000000 +0000 @@ -0,0 +1,20 @@ +PREFIX ?= /usr +VENDOR ?= $(shell dpkg-vendor --query Vendor | tr '[:upper:]' '[:lower:]') + +build: debian-distro-info ubuntu-distro-info + +%-distro-info: debian-distro-info.in distro-info-util.sh + sed -e '/^\. .*distro-info-util.sh\"$$/r distro-info-util.sh' $< | \ + sed -e '/^##/d;/^\. .*distro-info-util.sh\"$$/d' | \ + python -c 'import re,sys;print re.sub("(?<=\n)#BEGIN \w*#\n(.|\n)*?\n#END \w*#\n", "", re.sub("(?<=\n)#(BEGIN|END) $*#\n", "", sys.stdin.read())),' > $@ + chmod +x $@ + +install: debian-distro-info ubuntu-distro-info + install -d $(DESTDIR)$(PREFIX)/bin + install -m 755 $^ $(DESTDIR)$(PREFIX)/bin + ln -s $(VENDOR)-distro-info $(DESTDIR)$(PREFIX)/bin/distro-info + +clean: + rm -f debian-distro-info ubuntu-distro-info + +.PHONY: build clean install diff -Nru distro-info-0.7.1/shell/ubuntu-distro-info.in distro-info-0.8.1/shell/ubuntu-distro-info.in --- distro-info-0.7.1/shell/ubuntu-distro-info.in 1970-01-01 00:00:00.000000000 +0000 +++ distro-info-0.8.1/shell/ubuntu-distro-info.in 2012-03-27 10:20:06.000000000 +0000 @@ -0,0 +1,57 @@ +#!/bin/sh +set -f + +# Copyright (C) 2012 Canonical Ltd. +# Author: Scott Moser +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +DISTRO_INFO_NAME="Ubuntu" +DISTRO_INFO_ARGS="--all --devel --lts --stable --supported --unsupported" +DISTRO_INFO_DATA="/usr/share/distro-info/ubuntu.csv" + +. "${0%/*}/distro-info-util.sh" + +Usage() { + cat < + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// C standard libraries +#include + +#include "distro-info-util.h" + +#define UBUNTU +#define CSV_NAME "ubuntu" +#define CSV_HEADER "version,codename,series,created,release,eol,eol-server" +#define DISTRO_NAME "Ubuntu" +#define NAME "ubuntu-distro-info" + +static bool filter_devel(const date_t *date, const distro_t *distro) { + return created(date, distro) && !released(date, distro); +} + +static bool filter_lts(const date_t *date, const distro_t *distro) { + return strstr(distro->version, "LTS") != NULL && + released(date, distro) && !eol(date, distro); +} + +#include "distro-info-util.c" diff -Nru distro-info-0.7.1/ubuntu-distro-info.in distro-info-0.8.1/ubuntu-distro-info.in --- distro-info-0.7.1/ubuntu-distro-info.in 2012-03-23 20:58:40.000000000 +0000 +++ distro-info-0.8.1/ubuntu-distro-info.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -#!/bin/sh -# Copyright (C) 2012 Canonical Ltd. -# Author: Scott Moser -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -DISTRO_INFO_NAME="Ubuntu" -DISTRO_INFO_ARGS="--all --devel --lts --stable --supported --unsupported" -DISTRO_INFO_DATA="/usr/share/distro-info/ubuntu.csv" - -. "${0%/*}/distro-info-util.sh" - -Usage() { - cat <