Skip to content

Commit 067b580

Browse files
author
Richard Jones
committed
WIP
1 parent 5795b27 commit 067b580

File tree

6 files changed

+98
-81
lines changed

6 files changed

+98
-81
lines changed

roundup/admin.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1717
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1818
#
19-
# $Id: admin.py,v 1.73 2004-06-23 23:19:07 richard Exp $
19+
# $Id: admin.py,v 1.74 2004-06-24 06:39:04 richard Exp $
2020

2121
'''Administration commands for maintaining Roundup trackers.
2222
'''
@@ -1037,15 +1037,16 @@ def do_export(self, args):
10371037
writer = rcsv.writer(f, rcsv.colon_separated)
10381038

10391039
properties = cl.getprops()
1040-
propnames = properties.keys()
1041-
propnames.sort()
1040+
propnames = cl.export_propnames()
10421041
fields = propnames[:]
10431042
fields.append('is retired')
10441043
writer.writerow(fields)
10451044

10461045
# all nodes for this class
10471046
for nodeid in cl.getnodeids():
10481047
writer.writerow(cl.export_list(propnames, nodeid))
1048+
if hasattr(cl, 'export_files'):
1049+
cl.export_files(dir, nodeid)
10491050

10501051
# close this file
10511052
f.close()
@@ -1083,7 +1084,11 @@ def do_import(self, args):
10831084
raise UsageError, _(rcsv.error)
10841085
from roundup import hyperdb
10851086

1086-
for file in os.listdir(args[0]):
1087+
# directory to import from
1088+
dir = args[0]
1089+
1090+
# import all the files
1091+
for file in os.listdir(dir):
10871092
classname, ext = os.path.splitext(file)
10881093
# we only care about CSV files
10891094
if ext != '.csv' or classname.endswith('-journals'):
@@ -1092,7 +1097,7 @@ def do_import(self, args):
10921097
cl = self.get_class(classname)
10931098

10941099
# ensure that the properties and the CSV file headings match
1095-
f = open(os.path.join(args[0], file))
1100+
f = open(os.path.join(dir, file))
10961101
reader = rcsv.reader(f, rcsv.colon_separated)
10971102
file_props = None
10981103
maxid = 1
@@ -1102,7 +1107,11 @@ def do_import(self, args):
11021107
file_props = r
11031108
continue
11041109
# do the import and figure the current highest nodeid
1105-
maxid = max(maxid, int(cl.import_list(file_props, r)))
1110+
nodeid = int(cl.import_list(file_props, r))
1111+
if hasattr(cl, 'import_files'):
1112+
cl.import_files(dir, nodeid)
1113+
maxid = max(maxid, nodeid)
1114+
11061115
f.close()
11071116

11081117
# import the journals

roundup/backends/back_anydbm.py

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
#$Id: back_anydbm.py,v 1.156 2004-06-21 05:44:16 richard Exp $
18+
#$Id: back_anydbm.py,v 1.157 2004-06-24 06:39:07 richard Exp $
1919
'''This module defines a backend that saves the hyperdatabase in a
2020
database chosen by anydbm. It is guaranteed to always be available in python
2121
versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several
@@ -2118,25 +2118,6 @@ def create(self, **propvalues):
21182118
self.db.storefile(self.classname, newid, None, content)
21192119
return newid
21202120

2121-
def import_list(self, propnames, proplist):
2122-
''' Trap the "content" property...
2123-
'''
2124-
# dupe this list so we don't affect others
2125-
propnames = propnames[:]
2126-
2127-
# extract the "content" property from the proplist
2128-
i = propnames.index('content')
2129-
content = eval(proplist[i])
2130-
del propnames[i]
2131-
del proplist[i]
2132-
2133-
# do the normal import
2134-
newid = Class.import_list(self, propnames, proplist)
2135-
2136-
# save off the "content" file
2137-
self.db.storefile(self.classname, newid, None, content)
2138-
return newid
2139-
21402121
def get(self, nodeid, propname, default=_marker, cache=1):
21412122
''' Trap the content propname and get it from the file
21422123
@@ -2194,7 +2175,6 @@ def getprops(self, protected=1):
21942175
d['content'] = hyperdb.String()
21952176
return d
21962177

2197-
21982178
# deviation from spec - was called ItemClass
21992179
class IssueClass(Class, roundupdb.IssueClass):
22002180
# Overridden methods:

roundup/backends/blobfiles.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
#$Id: blobfiles.py,v 1.12 2004-03-19 04:47:59 richard Exp $
18+
#$Id: blobfiles.py,v 1.13 2004-06-24 06:39:07 richard Exp $
1919
'''This module exports file storage for roundup backends.
2020
Files are stored into a directory hierarchy.
2121
'''
2222
__docformat__ = 'restructuredtext'
2323

2424
import os
2525

26-
def files_in_dir(dir):
26+
def files_in_dir(dir):
2727
if not os.path.exists(dir):
2828
return 0
2929
num_files = 0

roundup/backends/rdbms_common.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.111 2004-06-23 23:19:07 richard Exp $
1+
# $Id: rdbms_common.py,v 1.112 2004-06-24 06:39:07 richard Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -2580,25 +2580,6 @@ def create(self, **propvalues):
25802580
self.db.storefile(self.classname, newid, None, content)
25812581
return newid
25822582

2583-
def import_list(self, propnames, proplist):
2584-
''' Trap the "content" property...
2585-
'''
2586-
# dupe this list so we don't affect others
2587-
propnames = propnames[:]
2588-
2589-
# extract the "content" property from the proplist
2590-
i = propnames.index('content')
2591-
content = eval(proplist[i])
2592-
del propnames[i]
2593-
del proplist[i]
2594-
2595-
# do the normal import
2596-
newid = Class.import_list(self, propnames, proplist)
2597-
2598-
# save off the "content" file
2599-
self.db.storefile(self.classname, newid, None, content)
2600-
return newid
2601-
26022583
_marker = []
26032584
def get(self, nodeid, propname, default=_marker, cache=1):
26042585
''' Trap the content propname and get it from the file

roundup/hyperdb.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: hyperdb.py,v 1.98 2004-05-18 21:53:18 richard Exp $
18+
# $Id: hyperdb.py,v 1.99 2004-06-24 06:39:06 richard Exp $
1919

2020
"""Hyperdatabase implementation, especially field types.
2121
"""
2222
__docformat__ = 'restructuredtext'
2323

2424
# standard python modules
25-
import sys, os, time, re
25+
import sys, os, time, re, shutil
2626

2727
# roundup modules
2828
import date, password
@@ -588,6 +588,13 @@ def safeget(self, nodeid, propname, default=None):
588588
except IndexError:
589589
return default
590590

591+
def export_propnames(self):
592+
'''List the property names for export from this Class.'''
593+
propnames = self.getprops().keys()
594+
propnames.sort()
595+
return propnames
596+
597+
591598
class HyperdbValueError(ValueError):
592599
''' Error converting a raw value into a Hyperdb value '''
593600
pass
@@ -758,7 +765,36 @@ class FileClass:
758765
''' A class that requires the "content" property and stores it on
759766
disk.
760767
'''
761-
pass
768+
def export_propnames(self):
769+
''' Don't export the "content" property
770+
'''
771+
propnames = self.getprops().keys()
772+
propnames.remove('content')
773+
propnames.sort()
774+
return propnames
775+
776+
def export_files(self, dirname, nodeid):
777+
''' Export the "content" property as a file, not csv column
778+
'''
779+
source = self.db.filename(self.classname, nodeid)
780+
x, filename = os.path.split(source)
781+
x, subdir = os.path.split(x)
782+
dest = os.path.join(dirname, self.classname+'-files', subdir, filename)
783+
if not os.path.exists(os.path.dirname(dest)):
784+
os.makedirs(os.path.dirname(dest))
785+
shutil.copyfile(source, dest)
786+
787+
def import_files(self, dirname, nodeid):
788+
''' Import the "content" property as a file
789+
'''
790+
dest = self.db.filename(self.classname, nodeid)
791+
x, filename = os.path.split(dest)
792+
x, subdir = os.path.split(x)
793+
source = os.path.join(dirname, self.classname+'-files', subdir,
794+
filename)
795+
if not os.path.exists(os.path.dirname(dest)):
796+
os.makedirs(os.path.dirname(dest))
797+
shutil.copyfile(source, dest)
762798

763799
class Node:
764800
''' A convenience wrapper for the given node

test/db_test_base.py

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: db_test_base.py,v 1.33 2004-06-23 23:19:07 richard Exp $
18+
# $Id: db_test_base.py,v 1.34 2004-06-24 06:39:07 richard Exp $
1919

2020
import unittest, os, shutil, errno, imp, sys, time, pprint
2121

@@ -846,6 +846,8 @@ def filteringSetup(self):
846846
'foo': date.Interval('0:10'), 'priority': '1',
847847
'nosy': ['1'], 'deadline': date.Date('2004-03-08')}):
848848
self.db.issue.create(**issue)
849+
file_content = ''.join([chr(i) for i in range(255)])
850+
self.db.file.create(content=file_content)
849851
self.db.commit()
850852
return self.assertEqual, self.db.issue.filter
851853

@@ -981,34 +983,43 @@ def testImportExport(self):
981983
for name in klass.getprops().keys():
982984
it[name] = klass.get(id, name)
983985

984-
# grab the export
985-
export = {}
986-
journals = {}
987-
for cn,klass in self.db.classes.items():
988-
names = klass.getprops().keys()
989-
cl = export[cn] = [names+['is retired']]
990-
for id in klass.getnodeids():
991-
cl.append(klass.export_list(names, id))
992-
journals[cn] = klass.export_journals()
993-
994-
# shut down this db and nuke it
995-
self.db.close()
996-
self.nuke_database()
997-
998-
# open a new, empty database
999-
os.makedirs(config.DATABASE + '/files')
1000-
self.db = self.module.Database(config, 'admin')
1001-
setupSchema(self.db, 0, self.module)
1002-
1003-
# import
1004-
for cn, items in export.items():
1005-
klass = self.db.classes[cn]
1006-
names = items[0]
1007-
maxid = 1
1008-
for itemprops in items[1:]:
1009-
maxid = max(maxid, int(klass.import_list(names, itemprops)))
1010-
self.db.setid(cn, str(maxid+1))
1011-
klass.import_journals(journals[cn])
986+
os.mkdir('_test_export')
987+
try:
988+
# grab the export
989+
export = {}
990+
journals = {}
991+
for cn,klass in self.db.classes.items():
992+
names = klass.export_propnames()
993+
cl = export[cn] = [names+['is retired']]
994+
for id in klass.getnodeids():
995+
cl.append(klass.export_list(names, id))
996+
if hasattr(klass, 'export_files'):
997+
klass.export_files('_test_export', id)
998+
journals[cn] = klass.export_journals()
999+
1000+
# shut down this db and nuke it
1001+
self.db.close()
1002+
self.nuke_database()
1003+
1004+
# open a new, empty database
1005+
os.makedirs(config.DATABASE + '/files')
1006+
self.db = self.module.Database(config, 'admin')
1007+
setupSchema(self.db, 0, self.module)
1008+
1009+
# import
1010+
for cn, items in export.items():
1011+
klass = self.db.classes[cn]
1012+
names = items[0]
1013+
maxid = 1
1014+
for itemprops in items[1:]:
1015+
id = int(klass.import_list(names, itemprops))
1016+
if hasattr(klass, 'import_files'):
1017+
klass.import_files('_test_export', id)
1018+
maxid = max(maxid, id)
1019+
self.db.setid(cn, str(maxid+1))
1020+
klass.import_journals(journals[cn])
1021+
finally:
1022+
shutil.rmtree('_test_export')
10121023

10131024
# compare with snapshot of the database
10141025
for cn, items in orig.items():

0 commit comments

Comments
 (0)