From a82324ca88708dfdfb77587ec32cefc0b709a7f1 Mon Sep 17 00:00:00 2001
From: Julien Muchembled <jm@nexedi.com>
Date: Fri, 5 Sep 2014 14:59:03 +0200
Subject: [PATCH] BT: read metadata (bt/* files) through
 BusinessTemplateArchive

---
 product/ERP5/Document/BusinessTemplate.py | 32 +++++++--
 product/ERP5/Tool/TemplateTool.py         | 87 +----------------------
 2 files changed, 30 insertions(+), 89 deletions(-)

diff --git a/product/ERP5/Document/BusinessTemplate.py b/product/ERP5/Document/BusinessTemplate.py
index 0394ae3647..932b0e4aa4 100644
--- a/product/ERP5/Document/BusinessTemplate.py
+++ b/product/ERP5/Document/BusinessTemplate.py
@@ -76,7 +76,6 @@ customImporters={
 
 from zLOG import LOG, WARNING, INFO
 from warnings import warn
-from gzip import GzipFile
 from lxml.etree import parse
 from xml.sax.saxutils import escape
 from Products.CMFCore.Expression import Expression
@@ -360,7 +359,7 @@ class BusinessTemplateFolder(BusinessTemplateArchive):
       d.setdefault(klass, []).append(f)
     self.file_list_dict = d
 
-  def importFiles(self, item, **kw):
+  def importFiles(self, item):
     """
       Import file from a local folder
     """
@@ -415,7 +414,7 @@ class BusinessTemplateTarball(BusinessTemplateArchive):
     return self.fobj
 
   def _initImport(self, file, **kw):
-    self.tar = tarfile.TarFile(fileobj=StringIO(GzipFile(fileobj=file).read()))
+    self.tar = tarfile.open(file, 'r:gz')
     self.item_dict = {}
     setdefault = self.item_dict.setdefault
     for info in self.tar.getmembers():
@@ -428,7 +427,7 @@ class BusinessTemplateTarball(BusinessTemplateArchive):
           file_name = unquote(file_name)
         setdefault(path[1], []).append((file_name, info))
 
-  def importFiles(self, item, **kw):
+  def importFiles(self, item):
     """
       Import all file from the archive to the site
     """
@@ -535,7 +534,7 @@ class BaseTemplateItem(Implicit, Persistent):
     return self._objects.keys()
 
   def importFile(self, bta, **kw):
-    bta.importFiles(item=self)
+    bta.importFiles(self)
 
   def removeProperties(self, obj, export, keep_workflow_history=False):
     """
@@ -4704,6 +4703,13 @@ class LocalRolesTemplateItem(BaseTemplateItem):
           delattr(obj, '__ac_local_roles_group_id_dict__')
         obj.reindexObject()
 
+class bt(dict):
+  """Fake 'bt' item to read bt/* files through BusinessTemplateArchive"""
+
+  def _importFile(self, file_name, file):
+    self[file_name] = file.read()
+
+
 class BusinessTemplate(XMLObject):
     """
     A business template allows to construct ERP5 modules
@@ -5615,6 +5621,22 @@ Business Template is a set of definitions, such as skins, portal types and categ
       else:
         bta = BusinessTemplateTarball(importing=1, file=file)
 
+      bt_item = bt()
+      bta.importFiles(bt_item)
+      prop_dict = {}
+      for prop in self.propertyMap():
+        pid = prop['id']
+        if pid != 'id':
+          prop_type = prop['type']
+          value = bt_item.get(pid)
+          if prop_type in ('text', 'string'):
+            prop_dict[pid] = value or ''
+          elif prop_type in ('int', 'boolean'):
+            prop_dict[pid] = value or 0
+          elif prop_type in ('lines', 'tokens'):
+            prop_dict[pid[:-5]] = (value or '').splitlines()
+      self._edit(**prop_dict)
+
       self.storeTemplateItemData()
 
       # Create temporary modules/classes for classes defined by this BT.
diff --git a/product/ERP5/Tool/TemplateTool.py b/product/ERP5/Tool/TemplateTool.py
index bb77d2732f..1be6efdb76 100644
--- a/product/ERP5/Tool/TemplateTool.py
+++ b/product/ERP5/Tool/TemplateTool.py
@@ -33,7 +33,6 @@ from App.config import getConfiguration
 import os
 import shutil
 import sys
-import tarfile
 
 from Acquisition import Implicit, Explicit
 from AccessControl import ClassSecurityInfo
@@ -56,7 +55,6 @@ from xml.dom.minidom import parse
 from xml.parsers.expat import ExpatError
 import struct
 import cPickle
-import posixpath
 from base64 import b64encode, b64decode
 from Products.ERP5Type.Message import translateString
 from zLOG import LOG, INFO, WARNING
@@ -298,58 +296,6 @@ class TemplateTool (BaseTool):
       self.deleteContent(id)
       self._importObjectFromFile(StringIO(export_string), id=id)
 
-    def _importBT(self, path=None, id=id):
-      """
-        Import template from a temp file (as uploaded by the user)
-      """
-      with open(path, 'rb') as file:
-        # read magic key to determine wich kind of bt we use
-        file.seek(0)
-        magic = file.read(5)
-
-      if magic == '<?xml': # old version
-        self._importObjectFromFile(path, id=id)
-        bt = self[id]
-        bt.id = id # Make sure id is consistent
-        bt.setProperty('template_format_version', 0, type='int')
-      else: # new version
-        # XXX: should really check for a magic and offer a falback if it
-        # doens't correspond to anything handled.
-        tar = tarfile.open(path, 'r:gz')
-        dir_name = tar.members[0].name.split(posixpath.sep, 1)[0]
-        try:
-          # create bt object
-          bt = self.newContent(portal_type='Business Template', id=id)
-          prop_dict = {}
-          for prop in bt.propertyMap():
-            prop_type = prop['type']
-            pid = prop['id']
-            prop_path = posixpath.join(dir_name, 'bt', pid)
-            try:
-              info = tar.getmember(prop_path)
-              value = tar.extractfile(info).read()
-            except KeyError:
-              value = None
-            if value is 'None':
-              # At export time, we used to export non-existent properties:
-              #   str(obj.getProperty('non-existing')) == 'None'
-              # Discard them
-              continue
-            if prop_type in ('text', 'string'):
-              prop_dict[pid] = value or ''
-            elif prop_type in ('int', 'boolean'):
-              prop_dict[pid] = value or 0
-            elif prop_type in ('lines', 'tokens'):
-              prop_dict[pid[:-5]] = (value or '').splitlines()
-          prop_dict.pop('id', '')
-          bt.edit(**prop_dict)
-          # import all other files from bt
-          with open(path, 'rb') as fobj:
-            bt.importFile(file=fobj)
-        finally:
-          tar.close()
-      return bt
-
     security.declareProtected( Permissions.ManagePortal, 'manage_download' )
     def manage_download(self, url, id=None, REQUEST=None):
       """The management interface for download.
@@ -368,6 +314,7 @@ class TemplateTool (BaseTool):
     def _download_local(self, path, bt_id):
       """Download Business Template from local directory or file
       """
+      bt = self.newContent(portal_type='Business Template', id=bt_id)
       if os.path.isdir(os.path.normpath(path)):
         path = os.path.normpath(path)
         def callback(file_list, directory, files):
@@ -385,39 +332,11 @@ class TemplateTool (BaseTool):
         os.path.walk(path, callback, file_list)
         file_list.sort()
         # import bt object
-        bt = self.newContent(portal_type='Business Template', id=bt_id)
-        bt_path = os.path.join(path, 'bt')
-
-        # import properties
-        prop_dict = {}
-        for prop in bt.propertyMap():
-          prop_type = prop['type']
-          pid = prop['id']
-          prop_path = os.path.join('.', bt_path, pid)
-          if not os.path.exists(prop_path):
-            value = None
-          else:
-            with open(prop_path, 'rb') as f:
-              value = f.read()
-          if value is 'None':
-            # At export time, we used to export non-existent properties:
-            #   str(obj.getProperty('non-existing')) == 'None'
-            # Discard them
-            value = None
-          if prop_type in ('text', 'string'):
-            prop_dict[pid] = value or ''
-          elif prop_type in ('int', 'boolean'):
-            prop_dict[pid] = value or 0
-          elif prop_type in ('lines', 'tokens'):
-            prop_dict[pid[:-5]] = (value or '').splitlines()
-        prop_dict.pop('id', '')
-        bt.edit(**prop_dict)
-        # import all others objects
         bt.importFile(dir=True, file=file_list, root_path=path)
-        return bt
       else:
         # this should be a file
-        return self._importBT(path, bt_id)
+        bt.importFile(file=path)
+      return bt
 
     def _download_url(self, url, bt_id):
       tempid, temppath = mkstemp()
-- 
2.30.9