diff --git a/checkin_notes b/checkin_notes
index dddab61ed7..f6e1abac76 100755
--- a/checkin_notes
+++ b/checkin_notes
@@ -6511,6 +6511,7 @@ Karl 2003/10/02
Karl 2003/10/02
- made C parsing of config.xml more flexible (allow multiple tags per
line or tags on multiple lines)
+ - made config.xml and run_state.xml pretty
sched/
sched_config.C
@@ -6519,3 +6520,5 @@ Karl 2003/10/02
parse.C
parse.h
+ py/
+ configxml.py
diff --git a/lib/parse.C b/lib/parse.C
index c0cd793202..0013a49aa4 100644
--- a/lib/parse.C
+++ b/lib/parse.C
@@ -2,18 +2,18 @@
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://boinc.berkeley.edu/license_1.0.txt
-//
+//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
-// under the License.
-//
-// The Original Code is the Berkeley Open Infrastructure for Network Computing.
-//
+// under the License.
+//
+// The Original Code is the Berkeley Open Infrastructure for Network Computing.
+//
// The Initial Developer of the Original Code is the SETI@home project.
// Portions created by the SETI@home project are Copyright (C) 2002
-// University of California at Berkeley. All Rights Reserved.
-//
+// University of California at Berkeley. All Rights Reserved.
+//
// Contributor(s):
//
@@ -74,11 +74,30 @@ bool parse_str(const char* buf, const char* tag, char* dest, int len) {
char* p = strstr(buf, tag);
if (!p) return false;
p = strchr(p, '>');
- char* q = strchr(p+1, '<');
+ ++p;
+ while (isspace(*p)) ++p;
+ char* q = strchr(p, '<');
if (!q) return false;
+ while (isspace(*(q-1))) --q;
+ char save_q = *q;
*q = 0;
- safe_strncpy(dest, p+1, len);
- *q = '<';
+ safe_strncpy(dest, p, len);
+ *q = save_q;
+ return true;
+}
+
+// parse a string of the form string
+//
+bool parse_str(const char* buf, const char* tag, string& dest) {
+ char const* p = strstr(buf, tag);
+ if (!p) return false;
+ p = strchr(p, '>');
+ ++p;
+ while (isspace(*p)) ++p;
+ char const* q = strchr(p, '<');
+ if (!q) return false;
+ while (isspace(*(q-1))) --q;
+ dest.assign(p, q-p);
return true;
}
@@ -251,7 +270,7 @@ bool extract_xml_record(const std::string &field, const char *tag, std::string &
do {
j=field.rfind(">",j-1);
start_pos=field.rfind(tag,j);
- if ((start_pos != std::string::npos) && (field[start_pos-1]!='/')) {
+ if ((start_pos != std::string::npos) && (field[start_pos-1]!='/')) {
start_pos=field.rfind("<",start_pos);
} else {
start_pos=std::string::npos;
diff --git a/lib/parse.h b/lib/parse.h
index d9bf04f145..847670627b 100644
--- a/lib/parse.h
+++ b/lib/parse.h
@@ -2,29 +2,32 @@
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://boinc.berkeley.edu/license_1.0.txt
-//
+//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
-// under the License.
-//
-// The Original Code is the Berkeley Open Infrastructure for Network Computing.
-//
+// under the License.
+//
+// The Original Code is the Berkeley Open Infrastructure for Network Computing.
+//
// The Initial Developer of the Original Code is the SETI@home project.
// Portions created by the SETI@home project are Copyright (C) 2002
-// University of California at Berkeley. All Rights Reserved.
-//
+// University of California at Berkeley. All Rights Reserved.
+//
// Contributor(s):
//
-#include
-#include
+#include
+#include
#include
+using std::string;
+
extern bool parse(char* , char* );
extern bool parse_int(const char* buf, const char*tag, int&);
extern bool parse_double(const char*, const char*, double&);
extern bool parse_str(const char*, const char*, char*, int);
+bool parse_str(const char* buf, const char* tag, string& dest);
extern void parse_attr(const char* buf, const char* attrname, char* out, int len);
extern bool match_tag(const char*, const char*);
extern bool match_tag(const std::string &, const char*);
diff --git a/py/Boinc/configxml.py b/py/Boinc/configxml.py
index 4b88d0882a..540d1d6d05 100644
--- a/py/Boinc/configxml.py
+++ b/py/Boinc/configxml.py
@@ -120,7 +120,7 @@ class XMLConfig:
except IOError, e:
if not failopen_ok:
# raise
- raise SystemExit("%s: Couldn't parse XML config\n%s: %s"%(sys.argv[0],sys.argv[0],e))
+ raise Exception("%s: Couldn't parse XML config\n%s: %s"%(sys.argv[0],sys.argv[0],e))
print >>sys.stderr, "Warning:", e
# self.xml = xml.dom.minidom.Document()
self._init_empty_xml()
@@ -133,7 +133,7 @@ class XMLConfig:
self._set_elements()
if not output:
output = open(self.filename,'w')
- self.xml.writexml(output)
+ self.xml.writexml(output, "", " ", "\n")
print >>output
return self
def _set_elements(self):
diff --git a/py/Boinc/setup_project.py b/py/Boinc/setup_project.py
index 8867ad60e5..92f30c8c7b 100644
--- a/py/Boinc/setup_project.py
+++ b/py/Boinc/setup_project.py
@@ -249,7 +249,7 @@ def num_wus():
def num_wus_assimilated():
return database.Workunits.count(assimilate_state = ASSIMILATE_DONE)
def num_wus_to_transition():
- return database.Workunits.count(_extra_params = 'transition_time<%d'%(time.time()+30*86400))
+ return database.Workunits.count(_extra_params = ['transition_time<%d'%(time.time()+30*86400)])
def build_command_line(cmd, **kwargs):
for (key, value) in kwargs.items():
@@ -308,10 +308,11 @@ class Project:
config.download_url = os.path.join(config.master_url, 'download')
config.cgi_url = cgi_url or os.path.join(options.cgi_url, self.short_name)
config.upload_url = os.path.join(config.cgi_url , 'file_upload_handler')
- self.scheduler_url = os.path.join(config.cgi_url , 'cgi')
config.download_dir = os.path.join(self.project_dir , 'download')
config.upload_dir = os.path.join(self.project_dir , 'upload')
config.key_dir = key_dir or os.path.join(self.project_dir , 'keys')
+ config.app_dir = os.path.join(self.project_dir, 'apps')
+ self.scheduler_url = os.path.join(config.cgi_url , 'cgi')
self.project_php_file = srcdir('html_user/project.inc.sample')
self.project_specific_prefs_php_file = srcdir('html_user/project_specific_prefs.inc.sample')
diff --git a/sched/sched_config.C b/sched/sched_config.C
index 6a37923c45..046ed0c085 100644
--- a/sched/sched_config.C
+++ b/sched/sched_config.C
@@ -19,8 +19,10 @@
// Parse a server configuration file
-#include
-#include
+#include
+#include
+#include
+using std::ifstream;
#include "parse.h"
#include "error_numbers.h"
@@ -29,34 +31,38 @@
const char* CONFIG_FILE = "config.xml";
-int SCHED_CONFIG::parse(FILE* in) {
- char buf[256];
+inline string read_stream(istream& f) {
+ string buf;
+ buf.reserve(8192);
+ char c;
+ while (f >> c)
+ buf += c;
+ return buf;
+}
+
+int SCHED_CONFIG::parse(istream& f) {
+ string buf = read_stream(f);
memset(this, 0, sizeof(SCHED_CONFIG));
- while (fgets(buf, 256, in)) {
- if (match_tag(buf, "")) return 0;
- else if (parse_str(buf, "", db_name, sizeof(db_name))) continue;
- else if (parse_str(buf, "", db_passwd, sizeof(db_passwd))) continue;
- else if (parse_int(buf, "", shmem_key)) continue;
- else if (parse_str(buf, "", key_dir, sizeof(key_dir))) continue;
- else if (parse_str(buf, "", download_url, sizeof(download_url))) continue;
- else if (parse_str(buf, "", download_dir, sizeof(download_dir))) continue;
- else if (parse_str(buf, "", upload_url, sizeof(upload_url))) continue;
- else if (parse_str(buf, "", upload_dir, sizeof(upload_dir))) continue;
- else if (parse_str(buf, "", user_name, sizeof(user_name))) continue;
- }
+ parse_str(buf.c_str(), "", db_name, sizeof(db_name));
+ parse_str(buf.c_str(), "", db_passwd, sizeof(db_passwd));
+ parse_int(buf.c_str(), "", shmem_key);
+ parse_str(buf.c_str(), "", key_dir, sizeof(key_dir));
+ parse_str(buf.c_str(), "", download_url, sizeof(download_url));
+ parse_str(buf.c_str(), "", download_dir, sizeof(download_dir));
+ parse_str(buf.c_str(), "", upload_url, sizeof(upload_url));
+ parse_str(buf.c_str(), "", upload_dir, sizeof(upload_dir));
+ parse_str(buf.c_str(), "", user_name, sizeof(user_name));
+ if (match_tag(buf.c_str(), "")) return 0;
return ERR_XML_PARSE;
}
int SCHED_CONFIG::parse_file(char* dir) {
- FILE* f;
+ ifstream f;
char path[256];
- int retval;
sprintf(path, "%s/%s", dir, CONFIG_FILE);
- f = fopen(path, "r");
+ f.open(path);
if (!f) return ERR_FOPEN;
- retval = parse(f);
- fclose(f);
- return retval;
+ return parse(f);
}
diff --git a/sched/sched_config.h b/sched/sched_config.h
index 0d868c1935..2334e5d33f 100644
--- a/sched/sched_config.h
+++ b/sched/sched_config.h
@@ -20,6 +20,9 @@
#ifndef _SCHED_CONFIG_
#define _SCHED_CONFIG_
+#include
+using std::istream;
+
// parsed version of server configuration file
//
class SCHED_CONFIG {
@@ -34,7 +37,7 @@ public:
char upload_dir[256];
char user_name[256];
- int parse(FILE*);
+ int parse(istream& f);
int parse_file(char* dir=".");
};
diff --git a/test/testbase.py b/test/testbase.py
index f7fd16b441..2859bec41e 100644
--- a/test/testbase.py
+++ b/test/testbase.py
@@ -242,6 +242,8 @@ class TestProject(Project):
kwargs['short_name'] = kwargs.get('short_name') or 'test_'+appname
kwargs['long_name'] = kwargs.get('long_name') or 'Project ' + kwargs['short_name'].replace('_',' ').capitalize()
+ apply(Project.__init__, [self], kwargs)
+
(num_wu, redundancy) = get_redundancy_args(num_wu, redundancy)
self.resource_share = resource_share or 1
self.num_wu = num_wu
@@ -253,9 +255,8 @@ class TestProject(Project):
self.platforms = [Platform()]
self.core_versions = core_versions or [CoreVersion(self.platforms[0])]
- self.app_versions = app_versions or [AppVersion(App(appname),
- self.platforms[0],
- appname)]
+ self.app_versions = app_versions or [
+ AppVersion(App(appname), self.platforms[0], appname)]
self.apps = apps or unique(map(lambda av: av.app, self.app_versions))
# convenience vars:
self.app_version = self.app_versions[0]
@@ -265,7 +266,6 @@ class TestProject(Project):
self.work = self.works[0]
self.user = self.users[0]
self.host = self.hosts[0]
- apply(Project.__init__, [self], kwargs)
self.started = False
def init_install(self):
@@ -433,10 +433,12 @@ class CoreVersion(database.CoreVersion):
database.CoreVersion.__init__(self)
self.version_num = 1
self.platform = platform
+ def commit(self):
self.xml_doc = tools.process_executable_file(
os.path.join(boinc_path_config.TOP_BUILD_DIR,'client',
options.client_bin_filename),
quiet=True)
+ database.CoreVersion.commit(self)
class User(database.User):
def __init__(self):
@@ -457,12 +459,15 @@ class AppVersion(database.AppVersion):
self.app = app
self.version_num = 1
self.platform = platform
- self.xml_doc = tools.process_app_version(
- app, self.version_num,
- [os.path.join(boinc_path_config.TOP_BUILD_DIR,'apps',exec_file)],
- quiet=True)
self.min_core_version = 1
self.max_core_version = 999
+ self._exec_file=exec_file
+ def commit(self):
+ self.xml_doc = tools.process_app_version(
+ self.app, self.version_num,
+ [os.path.join(boinc_path_config.TOP_BUILD_DIR,'apps',self._exec_file)],
+ quiet=True)
+ database.AppVersion.commit(self)
class HostList(list):
def run(self, asynch=False): map(lambda i: i.run(asynch=asynch), self)
diff --git a/tools/update_versions b/tools/update_versions
index cf05c07254..bd1d5ce558 100755
--- a/tools/update_versions
+++ b/tools/update_versions
@@ -6,7 +6,7 @@
Scans apps dir for current core client and application versions and updates
the database as appropriate.
-config.xml must contain an which specifies the directory to search.
+config.xml must contain an which specifies the directory to search.
apps/boinc/ contains core client versions.
apps/APPLICATION_NAME/ contains application versions for each application.