Switch to side-by-side view

--- a/scripts/backup_project.py
+++ b/scripts/backup_project.py
@@ -1,20 +1,16 @@
 import os
 import sys
-import json
+import struct
 import logging
 
-from pylons import g
+from pylons import c
+from pymongo.bson import BSON
 
-from ming.orm import state, session
+from ming.orm import MappedClass, state, mapper
 
-from pymongo.json_util import default
 from allura import model as M
 
 log = logging.getLogger(__name__)
-
-MONGO_HOME=os.environ.get('MONGO_HOME', '/usr')
-MONGO_DUMP=os.path.join(MONGO_HOME, 'bin/mongodump')
-MONGO_RESTORE=os.path.join(MONGO_HOME, 'bin/mongorestore')
 
 def main():
     if len(sys.argv) not in (2,3):
@@ -38,11 +34,38 @@
     dump_project(project, backup_dir)
     return 0
 
+def _write_bson(fp, doc):
+    bson = BSON.from_dict(doc)
+    fp.write(struct.pack('!l', len(bson)))
+    fp.write(bson)
+
 def dump_project(project, dirname):
-    os.system('%s --db %s -o %s' % (
-            MONGO_DUMP, project.database, dirname))
-    with open(os.path.join(dirname, 'project.json'), 'w') as fp:
-        json.dump(state(project).document, fp, default=default)
+    if not os.path.exists(dirname):
+        os.mkdir(dirname)
+    with open(os.path.join(dirname, 'project.bson'), 'w') as fp:
+        _write_bson(fp, state(project).document)
+    c.project = project
+    app_config_ids = [
+        ac._id for ac in M.AppConfig.query.find(dict(project_id=c.project._id)) ]
+    for name, cls in MappedClass._registry.iteritems():
+        if 'project_id' in mapper(cls).property_index:
+            # Dump the things directly related to the project
+            oq = cls.query.find(dict(project_id=project._id))
+        elif 'app_config_id' in mapper(cls).property_index:
+            # ... and the things related to its apps
+            oq = cls.query.find(dict(app_config_id={'$in':app_config_ids}))
+        else:
+            # Don't dump other things
+            continue
+        num_objs = oq.count()
+        if num_objs == 0: continue
+        fname = os.path.join(
+            dirname,
+            '%s.bson' % (cls.__mongometa__.name))
+        log.info('%s: dumping %s objects to %s',
+                 name, num_objs, fname)
+        with open(os.path.join(dirname, fname), 'w') as fp:
+            for obj in oq.ming_cursor: _write_bson(fp, obj)
 
 if __name__ == '__main__':
     sys.exit(main())