import os
import sys
import struct
import logging
from pylons import c
from bson import BSON
from ming.orm import MappedClass, state, mapper
from allura import model as M
log = logging.getLogger(__name__)
def main():
if len(sys.argv) not in (2,3):
log.error('Usage: %s <shortname> [<backup_dir>]', sys.argv[0])
return 1
pname = sys.argv[1]
project = M.Project.query.get(shortname=pname)
if project is None:
log.fatal('Project %s not found', pname)
print 'Project %s not found' % pname
return 2
if len(sys.argv) == 3:
backup_dir = sys.argv[2]
else:
pname = project.shortname
gid = project.tool_data.get('sfx', {}).get('group_id', project._id)
dirname = '%s-%s.purge' % (pname, gid)
backup_dir = os.path.join(
os.getcwd(), dirname)
log.info('Backing up %s to %s', pname, backup_dir)
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):
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())