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,19 +890,18 @@ class SubversionTool(BaseTool): ...@@ -892,19 +890,18 @@ 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):
""" """
...@@ -927,87 +924,92 @@ class SubversionTool(BaseTool): ...@@ -927,87 +924,92 @@ 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): Current directory must be the destination working copy
# don't visit SVN directories """
if '.svn' in dirs: # Sets to track svn status in case it is not consistent with existing
dirs.remove('.svn') # files and directories
# get Directories versioned_set = set(x.getPath() for x in self._getClient().status('.')
for name in dirs: if x.getIsVersioned())
i = root.replace(directory, '').count(os.sep) versioned_set.remove('.')
path = os.path.join(root, name) added_set = set()
dir_set.add((i, path.replace(directory,'')))
return dir_set # Walk current tree
svn_file_set = set()
# return a set with files present in the directory svn_dir_set = set()
def getSetFilesForDir(self, directory): prefix_length = len(os.path.join('.', ''))
dir_set = set() for dirpath, dirnames, filenames in os.walk('.'):
for root, dirs, files in cacheWalk(directory): dirpath = dirpath[prefix_length:]
# don't visit SVN directories for i in xrange(len(dirnames) - 1, -1, -1):
if '.svn' in dirs: d = dirnames[i]
dirs.remove('.svn') if d[0] == '.':
# get Files # Ignore hidden directories (in particular '.svn')
for name in files: del dirnames[i]
i = root.replace(directory, '').count(os.sep) else:
path = os.path.join(root, name) svn_dir_set.add(os.path.join(dirpath, d))
dir_set.add((i, path.replace(directory,''))) for f in filenames:
return dir_set svn_file_set.add(os.path.join(dirpath, f))
# return files present in new_dir but not in old_dir # Copy new files/dirs from 'path' to working copy
# return a set of relative paths # Note: we don't use 'copytree' to avoid excessive disk writes
def getNewFiles(self, old_dir, new_dir): prefix_length = len(os.path.join(path, ''))
if old_dir[-1] != os.sep: for dirpath, dirnames, filenames in os.walk(path):
old_dir += os.sep dirpath = dirpath[prefix_length:]
if new_dir[-1] != os.sep: for d in dirnames:
new_dir += os.sep d = os.path.join(dirpath, d)
old_set = self.getSetFilesForDir(old_dir) if d in versioned_set:
new_set = self.getSetFilesForDir(new_dir) versioned_set.remove(d)
return new_set.difference(old_set) else:
added_set.add(d)
# return dirs present in new_dir but not in old_dir if d in svn_dir_set:
# return a set of relative paths svn_dir_set.remove(d)
def getNewDirs(self, old_dir, new_dir): else:
if old_dir[-1] != os.sep: os.mkdir(d)
old_dir += os.sep for f in filenames:
if new_dir[-1] != os.sep: f = os.path.join(dirpath, f)
new_dir += os.sep if f in versioned_set:
old_set = self.getSetDirsForDir(old_dir) versioned_set.remove(f)
new_set = self.getSetDirsForDir(new_dir) else:
return new_set.difference(old_set) added_set.add(f)
# copy file unless unchanged
def deleteOldFiles(self, old_dir, new_dir): file = open(os.path.join(path, f), 'rb')
""" svn del files that have been removed in new dir try:
""" text = file.read()
# detect removed files finally:
files_set = self.getNewFiles(new_dir, old_dir) file.close()
# detect removed directories try:
dirs_set = self.getNewDirs(new_dir, old_dir) if f in svn_file_set:
# svn del svn_file_set.remove(f)
path_list = [x for x in files_set] file = open(f, 'r+b')
path_list.sort() old_size = os.fstat(file.fileno()).st_size
self.remove([os.path.join(old_dir, x[1]) for x in path_list]) if len(text) == old_size and text == file.read():
path_list = [x for x in dirs_set] continue
path_list.sort() file.seek(0)
self.remove([os.path.join(old_dir, x[1]) for x in path_list]) else:
file = open(f, 'wb')
def addNewFiles(self, old_dir, new_dir): file.write(text)
""" copy files and add new files file.truncate()
""" finally:
# detect created files file.close()
files_set = self.getNewFiles(old_dir, new_dir)
# detect created directories # Remove dangling files/dirs
dirs_set = self.getNewDirs(old_dir, new_dir) svn_file_set -= versioned_set # what is in versioned_set
# Copy files svn_dir_set -= versioned_set # is removed after
copytree(new_dir, old_dir) for x in svn_file_set:
# svn add if os.path.dirname(x) not in svn_dir_set:
path_list = [x for x in dirs_set] os.remove(x)
path_list.sort() for x in svn_dir_set:
self.add([os.path.join(old_dir, x[1]) for x in path_list]) if os.path.dirname(x) not in svn_dir_set:
path_list = [x for x in files_set] shutil.rmtree(x)
path_list.sort()
self.add([os.path.join(old_dir, x[1]) for x in path_list]) # 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