This is what I have mentioned earlier this day. This introduces a CONFIG_VERSION define, which is used to represent a certain config file format. Every time we change config fle format (adding features, moving things around), we bump this number. This makes easy to determine, that somebody is using an outdated config file and that it just might not work.
Why such thing? We're using a 'pull' model. We pickup what we need from config virtually ignoring everything else. This is not like HTTP Server, where every configuration directive must make sense, or the web server won't even start. In addition, when some element is missing we asume some reasonable default. So it is possible that running old config against new release of flood which uses new config file format, will produce bad results or no results at all. So we bump CONFIG_VERSION define every time we introduce new feature, or change config file structure. Running such new flood release against old config files would produce a warning, to keep user aware of the problem. If this patch gets accepted, I'll update all config files to config version 1.0. This brings up another problem. We don't really have config file, but data mixed with config. The config part (farm, farmer and profile) is the easy stuff, but the data part (url's) might just be a large block of characters. We can't just say: ohh... we moved some attributes around, please rewrite your urllist from scratch. So we have to come up with some tool to convert one file format to another, when big changes will come. I think since we're in XML world, an stylesheet would be the best solution. Another benefit of having versioned config files, is that when we'll have a bunch of 'URL grabbing apps' (my 'Flood URL Bag' is just around the corner :) it would be extremally helpfull, to know what config file format to output. Such applications would probably have their own development cycle, outside flood repository, so they can't really stay in sync with flood. Anyway... this is how I see it. Please review it and yell if you find something, that is really obscure. regards, Jacek Prucia
diff -urN flood.orig/config.h.in flood/config.h.in --- flood.orig/config.h.in 2003-08-09 23:23:51.000000000 +0200 +++ flood/config.h.in 2003-08-10 13:53:14.000000000 +0200 @@ -8,6 +8,8 @@ #define FLOOD_STRLEN_MAX 256 /* XML symbolic roots to the various objects we define. */ +#define XML_FLOOD "flood" +#define XML_FLOOD_VERSION "version" #define XML_SEED "seed" #define XML_URLLIST "urllist" #define XML_URLLIST_SEQUENCE "sequence" @@ -51,6 +53,7 @@ #define XML_ELEM_DELIM "." #define FLOOD_VERSION "1.1-dev" +#define CONFIG_VERSION "1.0" #define CRLF "\r\n" diff -urN flood.orig/flood.c flood/flood.c --- flood.orig/flood.c 2003-08-09 09:33:27.000000000 +0200 +++ flood/flood.c 2003-08-10 13:57:13.000000000 +0200 @@ -127,6 +127,50 @@ return APR_SUCCESS; } +/* check if config file version matches flood config version */ +static apr_status_t check_versions(config_t *config) +{ + apr_status_t stat; + char *endptr = NULL; + float flood_version = 0; + float config_version = 1.0; + struct apr_xml_elem *root_elem; + + /* we assume that CONFIG_VERSION is sane */ + flood_version = strtof(CONFIG_VERSION, NULL); + + /* get the root element */ + if ((stat = retrieve_root_xml_elem(&root_elem, config)) != APR_SUCCESS) { + return stat; + } + + if (root_elem->attr) { + apr_xml_attr *attr = root_elem->attr; + while (attr) { + if (!strncasecmp(attr->name, XML_FLOOD_VERSION, + FLOOD_STRLEN_MAX)) { + config_version = strtof(attr->value, &endptr); + if (*endptr != '\0') { + apr_file_printf(local_stderr, + "invalid config version '%s'.\n", + attr->value); + return APR_EGENERAL; + } + } + attr = attr->next; + } + } + + if (conf_version != flood_version) { + apr_file_printf(local_stderr, + "your config file version '%.1f' doesn't match flood config version '%.1f'.\n", + config_version, flood_version); + } + + return APR_SUCCESS; + +} + int main(int argc, char** argv) { apr_status_t stat; @@ -172,6 +216,10 @@ exit(-1); } + if ((stat = check_versions(config)) != APR_SUCCESS) { + exit(-1); + } + if ((stat = run_farm(config, "Bingo", local_pool)) != APR_SUCCESS) { char buf[256]; apr_strerror(stat, (char*) &buf, 256);