Commit 5908b4c4 authored by Julien Muchembled's avatar Julien Muchembled

Speed up BT export to subversion working copy

Main optimization consists in reducing disk writes, by not using 'copytree'
anymore. Only modified/new files are copied from the temporary folder.

Also drop 'copyTree' and 'cacheWalk' because they are unused and 'dircache' is
deprecated.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@40326 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 91172319
...@@ -46,8 +46,6 @@ import shutil ...@@ -46,8 +46,6 @@ import shutil
from xml.sax.saxutils import escape from xml.sax.saxutils import escape
from dircache import listdir from dircache import listdir
from OFS.Traversable import NotFound from OFS.Traversable import NotFound
from Products.ERP5Type.patches.copyTree import copytree, Error
from Products.ERP5Type.patches.cacheWalk import cacheWalk
import transaction import transaction
try: try:
...@@ -892,20 +890,19 @@ class SubversionTool(BaseTool): ...@@ -892,20 +890,19 @@ class SubversionTool(BaseTool):
business_template.build() business_template.build()
svn_path = self._getWorkingPath(self.getSubversionPath(business_template) \ svn_path = self._getWorkingPath(self.getSubversionPath(business_template) \
+ os.sep) + os.sep)
old_cwd = os.getcwd()
path = mkdtemp() path = mkdtemp()
try: try:
# XXX: Big hack to make export work as expected. # XXX: Big hack to make export work as expected.
transaction.commit() transaction.commit()
business_template.export(path=path, local=1) business_template.export(path=path, local=1)
# svn del deleted files
self.deleteOldFiles(svn_path, path)
# add new files and copy
self.addNewFiles(svn_path, path)
self.goToWorkingCopy(business_template) self.goToWorkingCopy(business_template)
self._reimportTree(path)
finally: finally:
# Clean up # Clean up
shutil.rmtree(path) shutil.rmtree(path)
os.chdir(old_cwd)
def importBT(self, business_template): def importBT(self, business_template):
""" """
Import business template from local Import business template from local
...@@ -927,88 +924,93 @@ class SubversionTool(BaseTool): ...@@ -927,88 +924,93 @@ class SubversionTool(BaseTool):
res = [x for x in res if not x.startswith(path)] res = [x for x in res if not x.startswith(path)]
return res return res
# return a set with directories present in the directory def _reimportTree(self, path):
def getSetDirsForDir(self, directory): """Overwrite working copy with the tree pointed to by 'path'
dir_set = set()
for root, dirs, _ in cacheWalk(directory):
# don't visit SVN directories
if '.svn' in dirs:
dirs.remove('.svn')
# get Directories
for name in dirs:
i = root.replace(directory, '').count(os.sep)
path = os.path.join(root, name)
dir_set.add((i, path.replace(directory,'')))
return dir_set
# return a set with files present in the directory
def getSetFilesForDir(self, directory):
dir_set = set()
for root, dirs, files in cacheWalk(directory):
# don't visit SVN directories
if '.svn' in dirs:
dirs.remove('.svn')
# get Files
for name in files:
i = root.replace(directory, '').count(os.sep)
path = os.path.join(root, name)
dir_set.add((i, path.replace(directory,'')))
return dir_set
# return files present in new_dir but not in old_dir
# return a set of relative paths
def getNewFiles(self, old_dir, new_dir):
if old_dir[-1] != os.sep:
old_dir += os.sep
if new_dir[-1] != os.sep:
new_dir += os.sep
old_set = self.getSetFilesForDir(old_dir)
new_set = self.getSetFilesForDir(new_dir)
return new_set.difference(old_set)
# return dirs present in new_dir but not in old_dir Current directory must be the destination working copy
# return a set of relative paths
def getNewDirs(self, old_dir, new_dir):
if old_dir[-1] != os.sep:
old_dir += os.sep
if new_dir[-1] != os.sep:
new_dir += os.sep
old_set = self.getSetDirsForDir(old_dir)
new_set = self.getSetDirsForDir(new_dir)
return new_set.difference(old_set)
def deleteOldFiles(self, old_dir, new_dir):
""" svn del files that have been removed in new dir
""" """
# detect removed files # Sets to track svn status in case it is not consistent with existing
files_set = self.getNewFiles(new_dir, old_dir) # files and directories
# detect removed directories versioned_set = set(x.getPath() for x in self._getClient().status('.')
dirs_set = self.getNewDirs(new_dir, old_dir) if x.getIsVersioned())
# svn del versioned_set.remove('.')
path_list = [x for x in files_set] added_set = set()
path_list.sort()
self.remove([os.path.join(old_dir, x[1]) for x in path_list]) # Walk current tree
path_list = [x for x in dirs_set] svn_file_set = set()
path_list.sort() svn_dir_set = set()
self.remove([os.path.join(old_dir, x[1]) for x in path_list]) prefix_length = len(os.path.join('.', ''))
for dirpath, dirnames, filenames in os.walk('.'):
def addNewFiles(self, old_dir, new_dir): dirpath = dirpath[prefix_length:]
""" copy files and add new files for i in xrange(len(dirnames) - 1, -1, -1):
""" d = dirnames[i]
# detect created files if d[0] == '.':
files_set = self.getNewFiles(old_dir, new_dir) # Ignore hidden directories (in particular '.svn')
# detect created directories del dirnames[i]
dirs_set = self.getNewDirs(old_dir, new_dir) else:
# Copy files svn_dir_set.add(os.path.join(dirpath, d))
copytree(new_dir, old_dir) for f in filenames:
# svn add svn_file_set.add(os.path.join(dirpath, f))
path_list = [x for x in dirs_set]
path_list.sort() # Copy new files/dirs from 'path' to working copy
self.add([os.path.join(old_dir, x[1]) for x in path_list]) # Note: we don't use 'copytree' to avoid excessive disk writes
path_list = [x for x in files_set] prefix_length = len(os.path.join(path, ''))
path_list.sort() for dirpath, dirnames, filenames in os.walk(path):
self.add([os.path.join(old_dir, x[1]) for x in path_list]) dirpath = dirpath[prefix_length:]
for d in dirnames:
d = os.path.join(dirpath, d)
if d in versioned_set:
versioned_set.remove(d)
else:
added_set.add(d)
if d in svn_dir_set:
svn_dir_set.remove(d)
else:
os.mkdir(d)
for f in filenames:
f = os.path.join(dirpath, f)
if f in versioned_set:
versioned_set.remove(f)
else:
added_set.add(f)
# copy file unless unchanged
file = open(os.path.join(path, f), 'rb')
try:
text = file.read()
finally:
file.close()
try:
if f in svn_file_set:
svn_file_set.remove(f)
file = open(f, 'r+b')
old_size = os.fstat(file.fileno()).st_size
if len(text) == old_size and text == file.read():
continue
file.seek(0)
else:
file = open(f, 'wb')
file.write(text)
file.truncate()
finally:
file.close()
# Remove dangling files/dirs
svn_file_set -= versioned_set # what is in versioned_set
svn_dir_set -= versioned_set # is removed after
for x in svn_file_set:
if os.path.dirname(x) not in svn_dir_set:
os.remove(x)
for x in svn_dir_set:
if os.path.dirname(x) not in svn_dir_set:
shutil.rmtree(x)
# Remove deleted files/dirs
self.remove([x for x in versioned_set
if os.path.dirname(x) not in versioned_set])
# Add new files/dirs
self.add([x for x in added_set
if os.path.dirname(x) not in added_set])
def treeToXML(self, item, business_template) : def treeToXML(self, item, business_template) :
""" Convert tree in memory to XML """ Convert tree in memory to XML
""" """
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment