[Erp5-report] r12776 - in /spec/debian/unstable/erp5-erp5subversion: ./ ERP5Subversion/ ERP...

nobody at svn.erp5.org nobody at svn.erp5.org
Thu Feb 15 18:21:49 CET 2007


Author: yusei
Date: Thu Feb 15 18:21:43 2007
New Revision: 12776

URL: http://svn.erp5.org?rev=12776&view=rev
Log:
added debian package and workspace.

Added:
    spec/debian/unstable/erp5-erp5subversion/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Constraint/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Constraint/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Document/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Document/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Interface/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Interface/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Permissions.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/PropertySheet/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/PropertySheet/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/README.txt
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/SubversionClient.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/SubversionTool.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/VERSION.txt   (with props)
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/changelog
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/compat
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/control
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/copyright
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/dzproduct
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/postinst
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/rules   (with props)
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/dtml/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/dtml/explainSubversionTool.dtml
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/help/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/help/ERP5Subversion.stx
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/skins/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/skins/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tests/
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tests/__init__.py
    spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tool.png   (with props)
    spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.diff.gz   (with props)
    spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.dsc
    spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_all.deb   (with props)
    spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.build
    spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.changes
    spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14.orig.tar.gz   (with props)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Constraint/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Constraint/__init__.py?rev=12776&view=auto
==============================================================================
    (empty)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Document/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Document/__init__.py?rev=12776&view=auto
==============================================================================
    (empty)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Interface/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Interface/__init__.py?rev=12776&view=auto
==============================================================================
    (empty)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Permissions.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Permissions.py?rev=12776&view=auto
==============================================================================
    (empty)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/PropertySheet/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/PropertySheet/__init__.py?rev=12776&view=auto
==============================================================================
    (empty)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/README.txt
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/README.txt?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/README.txt (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/README.txt Thu Feb 15 18:21:43 2007
@@ -1,0 +1,9 @@
+ERP5Subversion
+
+  ERP5Subversion provides a Subversion interface. This product
+  depends on "pysvn":http://pysvn.tigris.org/.
+
+  To use this product, you must make a directory named 'svn' under
+  your instance home, and check out repositories under the directory.
+  Note that you must make sure that Zope can write to the directory and
+  sub-directories.

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/SubversionClient.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/SubversionClient.py?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/SubversionClient.py (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/SubversionClient.py Thu Feb 15 18:21:43 2007
@@ -1,0 +1,380 @@
+##############################################################################
+#
+# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
+#                    Yoshinori Okuji <yo at nexedi.com>
+#                    Christophe Dumez <christophe at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+from Acquisition import Implicit
+
+import time, os
+from Products.ERP5Type.Utils import convertToUpperCase
+from MethodObject import Method
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.PythonScripts.Utility import allow_class
+from tempfile import mktemp
+from Products.ERP5.Document.BusinessTemplate import removeAll
+
+class SubversionError(Exception):
+  """The base exception class for the Subversion interface.
+  """
+  pass
+  
+class SubversionInstallationError(SubversionError):
+  """Raised when an installation is broken.
+  """
+  pass
+  
+class SubversionTimeoutError(SubversionError):
+  """Raised when a Subversion transaction is too long.
+  """
+  pass
+    
+try:
+  import pysvn
+  
+  class SubversionLoginError(SubversionError):
+    """Raised when an authentication is required.
+    """
+    # Declarative Security
+    security = ClassSecurityInfo()
+    def __init__(self, realm = None):
+      self._realm = realm
+  
+    security.declarePublic('getRealm')
+    def getRealm(self):
+      return self._realm
+      
+  class SubversionSSLTrustError(SubversionError):
+    """Raised when a SSL certificate is not trusted.
+    """
+    # Declarative Security
+    security = ClassSecurityInfo()
+    
+    def __init__(self, trust_dict = None):
+      self._trust_dict = trust_dict
+      
+    security.declarePublic('getTrustDict')
+    def getTrustDict(self):
+      return self._trust_dict
+  
+  class Callback:
+    """The base class for callback functions.
+    """
+    def __init__(self, client):
+      self.client = client
+  
+    def __call__(self, *args):
+      pass
+  
+  class CancelCallback(Callback):
+    def __call__(self):
+      current_time = time.time()
+      if current_time - self.client.creation_time > self.client.getTimeout():
+        raise SubversionTimeoutError, 'too long transaction'
+        #return True
+      return False
+  
+  class GetLogMessageCallback(Callback):
+    def __call__(self):
+      message = self.client.getLogMessage()
+      if message:
+        return True, message
+      return False, ''
+  
+  class GetLoginCallback(Callback):
+    def __call__(self, realm, username, may_save):
+      user, password = self.client.getLogin(realm)
+      if not username or not password:
+        self.client.setException(SubversionLoginError(realm))
+        return False, '', '', False
+      return True, user, password, False
+  
+  class NotifyCallback(Callback):
+    def __call__(self, event_dict):
+      # FIXME: should accumulate information for the user
+      pass
+  
+  class SSLServerTrustPromptCallback(Callback):
+    def __call__(self, trust_dict):
+      trust, permanent = self.client.trustSSLServer(trust_dict)
+      if not trust:
+        self.client.setException(SubversionSSLTrustError(trust_dict))
+        return False, 0, False
+      # XXX SSL server certificate failure bits are not defined in pysvn.
+      # 0x8 means that the CA is unknown.
+      return True, 0x8, permanent
+    
+  class SSLServerPromptCallback(Callback):
+    def __call__(self):
+      return
+    
+  class SSLClientCertPromptCallback(Callback):
+    def __call__(self):
+      return
+    
+  class SSLClientCertPasswordPromptCallback(Callback):
+    def __call__(self):
+      return
+
+  # Wrap objects defined in pysvn so that skins
+  # have access to attributes in the ERP5 way.
+  class Getter(Method):
+    def __init__(self, key):
+      self._key = key
+  
+    def __call__(self, instance):
+      value = getattr(instance._obj, self._key)
+      if type(value) == type(u''):
+        value = value.encode('utf-8')
+      #elif isinstance(value, pysvn.Entry):
+      elif str(type(value)) == "<type 'entry'>":
+        value = Entry(value)
+      #elif isinstance(value, pysvn.Revision):
+      elif str(type(value)) == "<type 'revision'>":
+        value = Revision(value)
+      return value
+
+  def initializeAccessors(klass):
+    klass.security = ClassSecurityInfo()
+    klass.security.declareObjectPublic()
+    for attr in klass.attribute_list:
+      name = 'get' + convertToUpperCase(attr)
+      setattr(klass, name, Getter(attr))
+      klass.security.declarePublic(name)
+    InitializeClass(klass)
+
+  class ObjectWrapper(Implicit):
+    attribute_list = ()
+    
+    def __init__(self, obj):
+      self._obj = obj
+  
+  class Status(ObjectWrapper):
+    # XXX Big Hack to fix a bug
+    __allow_access_to_unprotected_subobjects__ = 1
+    attribute_list = ('path', 'entry', 'is_versioned', 'is_locked', \
+    'is_copied', 'is_switched', 'prop_status', 'text_status', \
+    'repos_prop_status', 'repos_text_status')
+  initializeAccessors(Status)
+  
+  class Entry(ObjectWrapper):
+    attribute_list = ('checksum', 'commit_author', 'commit_revision', \
+    'commit_time', 'conflict_new', 'conflict_old', 'conflict_work', \
+    'copy_from_revision', 'copy_from_url', 'is_absent', 'is_copied', \
+    'is_deleted', 'is_valid', 'kind', 'name', 'properties_time', \
+    'property_reject_file', 'repos', 'revision', 'schedule', \
+    'text_time', 'url', 'uuid')
+
+  class Revision(ObjectWrapper):
+    attribute_list = ('kind', 'date', 'number')
+  initializeAccessors(Revision)
+
+  
+  class SubversionClient(Implicit):
+    """This class wraps pysvn's Client class.
+    """
+    log_message = None
+    timeout = 60 * 5
+    
+    def __init__(self, container, **kw):
+      self.client = pysvn.Client()
+      self.client.set_auth_cache(0)
+      obj = self.__of__(container)
+      self.client.exception_style = 1
+      self.client.callback_cancel = CancelCallback(obj)
+      self.client.callback_get_log_message = GetLogMessageCallback(obj)
+      self.client.callback_get_login = GetLoginCallback(obj)
+      self.client.callback_notify = NotifyCallback(obj)
+      self.client.callback_ssl_server_trust_prompt = \
+      SSLServerTrustPromptCallback(obj)
+      self.client.callback_ssl_server_prompt = SSLServerPromptCallback(obj)
+      self.client.callback_ssl_client_cert_prompt = SSLClientCertPromptCallback(obj)
+      self.client.callback_ssl_client_cert_password_prompt = SSLClientCertPasswordPromptCallback(obj)
+      self.creation_time = time.time()
+      self.__dict__.update(kw)
+      self.exception = None
+
+    def getLogMessage(self):
+      return self.log_message
+    
+    def getLogin(self, realm):
+      return self.aq_parent._getLogin(realm)
+
+    def getTimeout(self):
+      return self.timeout
+        
+    def trustSSLServer(self, trust_dict):
+      return self.aq_parent._trustSSLServer(trust_dict)
+
+    def setException(self, exc):
+      self.exception = exc
+
+    def getException(self):
+      return self.exception
+    
+    def checkin(self, path, log_message, recurse):
+      try:
+        return self.client.checkin(path, log_message=log_message \
+        or 'none', recurse=recurse)
+      except pysvn.ClientError, error:
+        excep = self.getException()
+        if excep:
+          raise excep
+        else:
+          raise error
+        
+    def update(self, path):
+      try:
+        return self.client.update(path)
+      except pysvn.ClientError, error:
+        excep = self.getException()
+        if excep:
+          raise excep
+        else:
+          raise error
+        
+    def status(self, path, **kw):
+      # Since plain Python classes are not convenient in 
+      # Zope, convert the objects.
+      try:
+      	status_list = [Status(x) for x in self.client.status(path=path, **kw)]
+      except pysvn.ClientError, error:
+        excep = self.getException()
+        if excep:
+          raise excep
+        else:
+          raise error
+      # XXX: seems that pysvn return a list that is 
+      # upside-down, we reverse it...
+      status_list.reverse()
+      return status_list
+    
+    def removeAllInList(self, path_list):
+      """Remove all files and folders in list
+      """
+      for file_path in path_list:
+        removeAll(file_path)
+      
+    def diff(self, path, revision1, revision2):
+      tmp = mktemp()
+      os.makedirs(tmp)
+      if not revision1 or not revision2:
+        diff = self.client.diff(tmp_path=tmp, url_or_path=path, recurse=False)
+      else:
+        diff = self.client.diff(tmp_path=tmp, url_or_path=path, \
+        recurse=False, revision1 = pysvn.Revision(pysvn.opt_revision_kind\
+        .number,revision1), revision2=pysvn.Revision(pysvn\
+        .opt_revision_kind.number,revision2))
+      # clean up temp dir
+      self.activate().removeAllInList([tmp, ])
+      return diff
+    
+    def revert(self, path, recurse=False):
+      return self.client.revert(path, recurse)
+    
+    def switch(self, path, url):
+      return self.client.switch(path=path, url=url)
+    
+    def log(self, path):
+      try:
+        log_list = self.client.log(path)
+      except pysvn.ClientError, error:
+        if 'path not found' in error.args[0]:
+          return
+        excep = self.getException()
+        if excep:
+          raise excep
+        else:
+          raise error
+      # Edit list to make it more usable in zope
+      for rev_dict in log_list:
+        rev_dict['revision'] = rev_dict['revision'].number
+        rev_dict['date'] = time.ctime(rev_dict['date'])
+      return log_list
+        
+    def add(self, path):
+      self.client.add(path=path, force=True)
+
+    def resolved(self, path):
+      return self.client.resolved(path=path)
+    
+    def info(self, path):
+      try:
+        entry = self.client.info(path=path)
+      except pysvn.ClientError, error:
+        excep = self.getException()
+        if excep:
+          raise excep
+        else:
+          raise error
+      # transform entry to dict to make it more usable in zope
+      members_tuple = ('url', 'uuid', 'revision', 'kind', \
+      'commit_author', 'commit_revision', 'commit_time',)
+      entry_dict = dict([(member, getattr(entry, member)) \
+      for member in members_tuple])
+      entry_dict['revision'] = entry_dict['revision'].number
+      entry_dict['commit_revision'] = entry_dict['commit_revision'].number
+      entry_dict['commit_time'] = time.ctime(entry_dict['commit_time'])
+      return entry_dict
+      
+    def ls(self, path):
+      try:
+        dict_list = self.client.ls(url_or_path=path, recurse=False)
+      except pysvn.ClientError, error:
+        if 'non-existent' in error.args[0]:
+          return
+        excep = self.getException()
+        if excep:
+          raise excep
+        else:
+          raise error
+       #Modify the list to make it more usable in zope
+      for dictionary in dict_list:
+        dictionary['created_rev'] = dictionary['created_rev'].number
+        dictionary['time'] = time.ctime(dictionary['time'])
+      return dict_list
+
+    def cleanup(self, path):
+      return self.client.cleanup(path=path)
+
+    def remove(self, path):
+      self.client.remove(url_or_path=path, force=True)
+
+  def newSubversionClient(container, **kw):
+    return SubversionClient(container, **kw).__of__(container)
+    
+  InitializeClass(SubversionSSLTrustError)
+  allow_class(SubversionSSLTrustError)
+  InitializeClass(SubversionLoginError)
+  allow_class(SubversionLoginError)
+  
+except ImportError:
+  from zLOG import LOG, WARNING
+  LOG('SubversionTool', WARNING,
+      'could not import pysvn; until pysvn is installed properly, this tool will not work.')
+  def newSubversionClient(container, **kw):
+    raise SubversionInstallationError, 'pysvn library is not installed'

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/SubversionTool.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/SubversionTool.py?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/SubversionTool.py (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/SubversionTool.py Thu Feb 15 18:21:43 2007
@@ -1,0 +1,1292 @@
+##############################################################################
+#
+# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
+#                    Yoshinori Okuji <yo at nexedi.com>
+#                    Christophe Dumez <christophe at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+from Products.CMFCore.utils import UniqueObject
+from Products.ERP5Type.Tool.BaseTool import BaseTool
+from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass, DTMLFile
+from Products.ERP5Type.Core.Folder import Folder
+from Products.ERP5Type import Permissions
+from Products.ERP5Subversion import _dtmldir
+from Products.ERP5Subversion.SubversionClient import newSubversionClient
+import os, re
+from DateTime import DateTime
+from cPickle import dumps, loads
+from App.config import getConfiguration
+from tempfile import gettempdir, mktemp
+from Products.CMFCore.utils import getToolByName
+from Products.ERP5.Document.BusinessTemplate import removeAll
+from xml.sax.saxutils import escape
+from dircache import listdir
+from OFS.Traversable import NotFound
+from Products.ERP5Type.patches.copyTree import copytree, Error
+from Products.ERP5Type.patches.cacheWalk import cacheWalk
+from time import ctime
+
+try:
+  import pysvn
+except ImportError:
+  pysvn = None
+
+try:
+  from base64 import b64encode, b64decode
+except ImportError:
+  from base64 import encodestring as b64encode, decodestring as b64decode
+  
+# To keep compatibility with python 2.3
+try:
+  set
+except NameError:
+  from sets import Set as set
+
+NBSP = '&nbsp;'
+NBSP_TAB = NBSP*8
+
+class File(object):
+  """ Class that represents a file in memory
+  """
+  __slots__ = ('status','name')
+  # Constructor
+  def __init__(self, name, status) :
+    self.status = status
+    self.name = name
+## End of File Class
+
+class Dir(object):
+  """ Class that reprensents a folder in memory
+  """
+  __slots__ = ('status', 'name', 'sub_dirs', 'sub_files')
+  # Constructor
+  def __init__(self, name, status) :
+    self.status = status
+    self.name = name
+    self.sub_dirs = [] # list of sub directories
+    self.sub_files = [] # list of sub files
+
+  def getSubDirsNameList(self) :
+    """ return a list of sub directories' names
+    """
+    return [d.name for d in self.sub_dirs]
+
+  def getDirFromName(self, name):
+    """ return directory in subdirs given its name
+    """
+    for directory in self.sub_dirs:
+      if directory.name == name:
+        return directory
+      
+  def getObjectFromName(self, name):
+    """ return dir object given its name
+    """
+    for directory in self.sub_dirs:
+      if directory.name == name:
+        return directory
+    for sub_file in self.sub_files:
+      if sub_file.name == name:
+        return sub_file
+      
+  def getContent(self):
+    """ return content for directory
+    """
+    content = self.sub_dirs
+    content.extend(self.sub_files)
+    return content
+## End of Dir Class
+
+class SubversionPreferencesError(Exception):
+  """The base exception class for the Subversion preferences.
+  """
+  pass
+  
+class SubversionUnknownBusinessTemplateError(Exception):
+  """The base exception class when business template is unknown.
+  """
+  pass
+
+class SubversionNotAWorkingCopyError(Exception):
+  """The base exception class when directory is not a working copy
+  """
+  pass
+
+class SubversionConflictError(Exception):
+  """The base exception class when there is a conflict
+  """
+  pass
+
+class SubversionSecurityError(Exception): pass
+
+class SubversionBusinessTemplateNotInstalled(Exception):
+  """ Exception called when the business template is not installed
+  """
+  pass
+
+class UnauthorizedAccessToPath(Exception):
+  """ When path is not in zope home instance
+  """
+  pass
+
+    
+def colorizeTag(tag):
+  "Return html colored item"
+  text = tag.group()
+  if text.startswith('#') :
+    color = 'grey'
+  elif text.startswith('\"') :
+    color = 'red'
+  elif 'string' in text:
+    color = 'green'
+  elif 'tuple' in text:
+    color = 'orange'
+  elif 'dictionary' in text:
+    color = 'brown'
+  elif 'item' in text:
+    color = '#a1559a' #light purple
+  elif 'value' in text:
+    color = 'purple'
+  elif 'key' in text:
+    color = '#0c4f0c'#dark green
+  else:
+    color = 'blue'
+  return "<span style='color: %s'>%s</span>" % (color, text, )
+    
+def colorize(text):
+  """Return HTML Code with syntax hightlighting
+  """
+  # Escape xml before adding html tags
+  html = escape(text)
+  html = html.replace(' ', NBSP)
+  html = html.replace('\t', NBSP_TAB)
+  # Colorize comments
+  pattern = re.compile(r'#.*')
+  html = pattern.sub(colorizeTag, html)
+  # Colorize tags
+  pattern = re.compile(r'&lt;.*?&gt;')
+  html = pattern.sub(colorizeTag, html)
+  # Colorize strings
+  pattern = re.compile(r'\".*?\"')
+  html = pattern.sub(colorizeTag, html)
+  html = html.replace(os.linesep, os.linesep+"<br/>")
+  return html
+
+class DiffFile:
+  """
+  # Members :
+   - path : path of the modified file
+   - children : sub codes modified
+   - old_revision
+   - new_revision
+  """
+
+  def __init__(self, raw_diff):
+    if '@@' not in raw_diff:
+      self.binary = True
+      return
+    else:
+      self.binary = False
+    self.header = raw_diff.split('@@')[0][:-1]
+    # Getting file path in header
+    self.path = self.header.split('====')[0][:-1].strip()
+    # Getting revisions in header
+    for line in self.header.split(os.linesep):
+      if line.startswith('--- '):
+        tmp = re.search('\\([^)]+\\)$', line)
+        self.old_revision = tmp.string[tmp.start():tmp.end()][1:-1].strip()
+      if line.startswith('+++ '):
+        tmp = re.search('\\([^)]+\\)$', line)
+        self.new_revision = tmp.string[tmp.start():tmp.end()][1:-1].strip()
+    # Splitting the body from the header
+    self.body = os.linesep.join(raw_diff.strip().split(os.linesep)[4:])
+    # Now splitting modifications
+    self.children = []
+    first = True
+    tmp = []
+    for line in self.body.split(os.linesep):
+      if line:
+        if line.startswith('@@') and not first:
+          self.children.append(CodeBlock(os.linesep.join(tmp)))
+          tmp = [line, ]
+        else:
+          first = False
+          tmp.append(line)
+    self.children.append(CodeBlock(os.linesep.join(tmp)))
+    
+  def toHTML(self):
+    """ return HTML diff
+    """
+    # Adding header of the table
+    if self.binary:
+      return '<b>Folder or binary file or just no changes!</b><br/><br/><br/>'
+    
+    html_list = []
+    html_list.append('''
+    <table style="text-align: left; width: 100%%; border: 0;" cellpadding="0" cellspacing="0">
+  <tbody>
+    <tr>
+      <td style="background-color: grey; text-align: center; font-weight: bold;">%s</td>
+      <td style="background-color: black; width: 2px;"></td>
+      <td style="background-color: grey; text-align: center; font-weight: bold;">%s</td>
+    </tr>''' % (self.old_revision, self.new_revision))
+    header_color = 'grey'
+    child_html_text = '''<tr><td style="background-color: %(headcolor)s">
+    &nbsp;</td><td style="background-color: black; width: 2px;"></td>
+    <td style="background-color: %(headcolor)s">&nbsp;</td></tr><tr>
+    <td style="background-color: rgb(68, 132, 255);font-weight: bold;">Line %(oldline)s</td>
+    <td style="background-color: black; width: 2px;"></td>
+    <td style="background-color: rgb(68, 132, 255);font-weight: bold;">Line %(newline)s</td>
+    </tr>'''
+    for child in self.children:
+      # Adding line number of the modification
+      html_list.append( child_html_text % {'headcolor':header_color, 'oldline':child.old_line, 'newline':child.new_line} )
+      header_color = 'white'
+      # Adding diff of the modification
+      old_code_list = child.getOldCodeList()
+      new_code_list = child.getNewCodeList()
+      i = 0
+      for old_line_tuple in old_code_list:
+        new_line_tuple = new_code_list[i]
+        new_line = new_line_tuple[0] or ' '
+        old_line = old_line_tuple[0] or ' '
+        i += 1
+        html_list.append( '''<tr>
+        <td style="background-color: %s">%s</td>
+        <td style="background-color: black; width: 2px;"></td>
+        <td style="background-color: %s">%s</td>
+        </tr>'''%(old_line_tuple[1],
+        escape(old_line).replace(' ', NBSP).replace('\t', NBSP_TAB),
+        new_line_tuple[1],
+        escape(new_line).replace(' ', NBSP).replace('\t', NBSP_TAB))
+        )
+    html_list.append('''</tbody></table><br/>''')
+    return '\n'.join(html_list)
+      
+
+class CodeBlock:
+  """
+   A code block contains several SubCodeBlocks
+   Members :
+   - old_line : line in old code (before modif)
+   - new line : line in new code (after modif)
+  
+   Methods :
+   - getOldCodeList() : return code before modif
+   - getNewCodeList() : return code after modif
+   Note: the code returned is a list of tuples (code line, background color)
+  """
+
+  def __init__(self, raw_diff):
+    # Splitting body and header
+    self.body = os.linesep.join(raw_diff.split(os.linesep)[1:])
+    self.header = raw_diff.split(os.linesep)[0]
+    # Getting modifications lines
+    tmp = re.search('^@@ -\d+', self.header)
+    self.old_line = tmp.string[tmp.start():tmp.end()][4:]
+    tmp = re.search('\+\d+', self.header)
+    self.new_line = tmp.string[tmp.start():tmp.end()][1:]
+    # Splitting modifications in SubCodeBlocks
+    in_modif = False
+    self.children = []
+    tmp = []
+    for line in self.body.split(os.linesep):
+      if line:
+        if (line.startswith('+') or line.startswith('-')):
+          if in_modif:
+            tmp.append(line)
+          else:
+            self.children.append(SubCodeBlock(os.linesep.join(tmp)))
+            tmp = [line, ]
+            in_modif = True
+        else:
+          if in_modif:
+            self.children.append(SubCodeBlock(os.linesep.join(tmp)))
+            tmp = [line, ]
+            in_modif = False
+          else:
+            tmp.append(line)
+    self.children.append(SubCodeBlock(os.linesep.join(tmp)))
+    
+  def getOldCodeList(self):
+    """ Return code before modification
+    """
+    tmp = []
+    for child in self.children:
+      tmp.extend(child.getOldCodeList())
+    return tmp
+    
+  def getNewCodeList(self):
+    """ Return code after modification
+    """
+    tmp = []
+    for child in self.children:
+      tmp.extend(child.getNewCodeList())
+    return tmp
+    
+class SubCodeBlock:
+  """ a SubCodeBlock contain 0 or 1 modification (not more)
+  """
+  def __init__(self, code):
+    self.body = code
+    self.modification = self._getModif()
+    self.old_code_length = self._getOldCodeLength()
+    self.new_code_length = self._getNewCodeLength()
+    # Choosing background color
+    if self.modification == 'none':
+      self.color = 'white'
+    elif self.modification == 'change':
+      self.color = 'rgb(253, 228, 6);'#light orange
+    elif self.modification == 'deletion':
+      self.color = 'rgb(253, 117, 74);'#light red
+    else: # addition
+      self.color = 'rgb(83, 253, 74);'#light green
+    
+  def _getModif(self):
+    """ Return type of modification :
+        addition, deletion, none
+    """
+    nb_plus = 0
+    nb_minus = 0
+    for line in self.body.split(os.linesep):
+      if line.startswith("-"):
+        nb_minus -= 1
+      elif line.startswith("+"):
+        nb_plus += 1
+    if (nb_plus == 0 and nb_minus == 0):
+      return 'none'
+    if (nb_minus == 0):
+      return 'addition'
+    if (nb_plus == 0):
+      return 'deletion'
+    return 'change'
+      
+  def _getOldCodeLength(self):
+    """ Private function to return old code length
+    """
+    nb_lines = 0
+    for line in self.body.split(os.linesep):
+      if not line.startswith("+"):
+        nb_lines += 1
+    return nb_lines
+      
+  def _getNewCodeLength(self):
+    """ Private function to return new code length
+    """
+    nb_lines = 0
+    for line in self.body.split(os.linesep):
+      if not line.startswith("-"):
+        nb_lines += 1
+    return nb_lines
+  
+  def getOldCodeList(self):
+    """ Return code before modification
+    """
+    if self.modification == 'none':
+      old_code = [(x, 'white') for x in self.body.split(os.linesep)]
+    elif self.modification == 'change':
+      old_code = [self._getOldCodeList(x) for x in self.body.split(os.linesep) \
+      if self._getOldCodeList(x)[0]]
+      # we want old_code_list and new_code_list to have the same length
+      if(self.old_code_length < self.new_code_length):
+        filling = [(None, self.color)] * (self.new_code_length - \
+        self.old_code_length)
+        old_code.extend(filling)
+    else: # deletion or addition
+      old_code = [self._getOldCodeList(x) for x in self.body.split(os.linesep)]
+    return old_code
+  
+  def _getOldCodeList(self, line):
+    """ Private function to return code before modification
+    """
+    if line.startswith('+'):
+      return (None, self.color)
+    if line.startswith('-'):
+      return (' ' + line[1:], self.color)
+    return (line, self.color)
+  
+  def getNewCodeList(self):
+    """ Return code after modification
+    """
+    if self.modification == 'none':
+      new_code = [(x, 'white') for x in self.body.split(os.linesep)]
+    elif self.modification == 'change':
+      new_code = [self._getNewCodeList(x) for x in self.body.split(os.linesep) \
+      if self._getNewCodeList(x)[0]]
+      # we want old_code_list and new_code_list to have the same length
+      if(self.new_code_length < self.old_code_length):
+        filling = [(None, self.color)] * (self.old_code_length - \
+        self.new_code_length)
+        new_code.extend(filling)
+    else: # deletion or addition
+      new_code = [self._getNewCodeList(x) for x in self.body.split(os.linesep)]
+    return new_code
+  
+  def _getNewCodeList(self, line):
+    """ Private function to return code after modification
+    """
+    if line.startswith('-'):
+      return (None, self.color)
+    if line.startswith('+'):
+      return (' ' + line[1:], self.color)
+    return (line, self.color)
+  
+class SubversionTool(BaseTool, UniqueObject, Folder):
+  """The SubversionTool provides a Subversion interface to ERP5.
+  """
+  id = 'portal_subversion'
+  meta_type = 'ERP5 Subversion Tool'
+  portal_type = 'Subversion Tool'
+  allowed_types = ()
+
+  login_cookie_name = 'erp5_subversion_login'
+  ssl_trust_cookie_name = 'erp5_subversion_ssl_trust'
+  
+  top_working_path = getConfiguration().instancehome
+  
+  # Declarative Security
+  security = ClassSecurityInfo()
+
+  #
+  #   ZMI methods
+  #
+  manage_options = ( ( { 'label'      : 'Overview'
+                        , 'action'     : 'manage_overview'
+                        }
+                      ,
+                      )
+                    + Folder.manage_options
+                    )
+
+  security.declareProtected( Permissions.ManagePortal, 'manage_overview' )
+  manage_overview = DTMLFile( 'explainSubversionTool', _dtmldir )
+
+  # Filter content (ZMI))
+  def __init__(self):
+    return Folder.__init__(self, SubversionTool.id)
+
+
+  def filtered_meta_types(self, user=None):
+    """
+     Filter content (ZMI))
+     Filters the list of available meta types.
+    """
+    all = SubversionTool.inheritedAttribute('filtered_meta_types')(self)
+    meta_types = []
+    for meta_type in self.all_meta_types():
+      if meta_type['name'] in self.allowed_types:
+        meta_types.append(meta_type)
+    return meta_types
+    
+  # path is the path in svn working copy
+  # return edit_path in zodb to edit it
+  # return '#' if no zodb path is found
+  def editPath(self, business_template, path):
+    """Return path to edit file
+       path can be relative or absolute
+    """
+    path = self.relativeToAbsolute(path, business_template).replace('\\', '/')
+    if 'bt' in path.split('/'):
+      # not in zodb
+      return '#'
+    # if file have been deleted then not in zodb
+    if not os.path.exists(path):
+      return '#'
+    svn_path = self.getSubversionPath(business_template).replace('\\', '/')
+    edit_path = path.replace(svn_path, '').strip()
+    if edit_path == '':
+      # not in zodb 
+      return '#'
+    if edit_path[0] == '/':
+      edit_path = edit_path[1:]
+    edit_path = '/'.join(edit_path.split('/')[1:]).strip()
+    if edit_path == '':
+      # not in zodb 
+      return '#'
+    # remove file extension
+    edit_path = os.path.splitext(edit_path)[0]
+    # Add beginning and end of url
+    edit_path = os.path.join(business_template.REQUEST["BASE2"], \
+    edit_path, 'manage_main')
+    return edit_path
+    
+  def _encodeLogin(self, realm, user, password):
+    """ Encode login information.
+    """
+    return b64encode(dumps((realm, user, password)))
+
+  def _decodeLogin(self, login):
+    """ Decode login information.
+    """
+    return loads(b64decode(login))
+  
+  def goToWorkingCopy(self, business_template):
+    """ Change to business template directory
+    """
+    working_path = self.getSubversionPath(business_template)
+    os.chdir(working_path)
+    
+  def setLogin(self, realm, user, password):
+    """Set login information.
+    """
+    # Get existing login information. Filter out old information.
+    login_list = []
+    request = self.REQUEST
+    cookie = request.get(self.login_cookie_name)
+    if cookie:
+      for login in cookie.split(','):
+        if self._decodeLogin(login)[0] != realm:
+          login_list.append(login)
+    # Set the cookie.
+    response = request.RESPONSE
+    login_list.append(self._encodeLogin(realm, user, password))
+    value = ','.join(login_list)
+    expires = (DateTime() + 1).toZone('GMT').rfc822()
+    request.set(self.login_cookie_name, value)
+    response.setCookie(self.login_cookie_name, value, path = '/', \
+    expires = expires)
+
+  def _getLogin(self, target_realm):
+    request = self.REQUEST
+    cookie = request.get(self.login_cookie_name)
+    if cookie:
+      for login in cookie.split(','):
+        realm, user, password = self._decodeLogin(login)
+        if target_realm == realm:
+          return user, password
+    return None, None
+      
+  def getHeader(self, business_template, file_path):
+    file_path = self._getWorkingPath(self.relativeToAbsolute(file_path, business_template))
+    header = '<a style="font-weight: bold" href="BusinessTemplate_viewSvnShowFile?file=' + \
+    file_path + '">' + file_path + '</a>'
+    edit_path = self.editPath(business_template, file_path)
+    if edit_path != '#':
+      header += '&nbsp;&nbsp;<a href="'+self.editPath(business_template, \
+      file_path) + '"><img src="imgs/edit.png" style="border: 0" alt="edit" /></a>'
+    return header
+
+  def _encodeSSLTrust(self, trust_dict, permanent=False):
+    # Encode login information.
+    key_list = trust_dict.keys()
+    key_list.sort()
+    trust_item_list = tuple([(key, trust_dict[key]) for key in key_list])
+    return b64encode(dumps((trust_item_list, permanent)))
+
+  def _decodeSSLTrust(self, trust):
+    # Decode login information.
+    trust_item_list, permanent = loads(b64decode(trust))
+    return dict(trust_item_list), permanent
+  
+  def getPreferredUsername(self):
+    """return username in preferences if set of the current username
+    """
+    username = self.getPortalObject().portal_preferences\
+    .getPreferredSubversionUserName()
+    if username is None or username.strip() == "":
+      # not set in preferences, then we get the current username in zope
+      username = self.portal_membership.getAuthenticatedMember().getUserName()
+    return username
+  
+  def diffHTML(self, file_path, business_template, revision1=None, \
+  revision2=None):
+    """ Return HTML diff
+    """
+    raw_diff = self.diff(file_path, business_template, revision1, revision2)
+    return DiffFile(raw_diff).toHTML()
+  
+  def fileHTML(self, business_template, file_path):
+    """ Display a file content in HTML with syntax highlighting
+    """
+    file_path = self._getWorkingPath(self.relativeToAbsolute(file_path, business_template))
+    if os.path.exists(file_path):
+      if os.path.isdir(file_path):
+        text = "<span style='font-weight: bold; color: black;'>"+file_path+"</span><hr/>"
+        text += file_path +" is a folder!"
+      else:
+        input_file = open(file_path, 'r')
+        head = "<span style='font-weight: bold; color: black;'>"+file_path+'</span>  <a href="' + \
+        self.editPath(business_template, file_path) + \
+        '"><img src="imgs/edit.png" style="border: 0" alt="edit" /></a><hr/>'
+        text = head + colorize(input_file.read())
+        input_file.close()
+    else:
+      # see if tmp file is here (svn deleted file)
+      if file_path[-1] == os.sep:
+        file_path = file_path[:-1]
+      filename = file_path.split(os.sep)[-1]
+      tmp_path = os.sep.join(file_path.split(os.sep)[:-1])
+      tmp_path = os.path.join(tmp_path, '.svn', 'text-base', \
+      filename+'.svn-base')
+      if os.path.exists(tmp_path):
+        input_file = open(tmp_path, 'r')
+        head = "<span style='font-weight: bold'>"+tmp_path+"</span> (svn temporary file)<hr/>"
+        text = head + colorize(input_file.read())
+        input_file.close()
+      else : # does not exist
+        text = "<span style='font-weight: bold'>"+file_path+"</span><hr/>"
+        text += file_path +" does not exist!"
+    return text
+      
+  security.declareProtected(Permissions.ManagePortal, 'acceptSSLServer')
+  def acceptSSLServer(self, trust_dict, permanent=False):
+    """Accept a SSL server.
+    """
+    # Get existing trust information.
+    trust_list = []
+    request = self.REQUEST
+    cookie = request.get(self.ssl_trust_cookie_name)
+    if cookie:
+      trust_list.append(cookie)
+    # Set the cookie.
+    response = request.RESPONSE
+    trust_list.append(self._encodeSSLTrust(trust_dict, permanent))
+    value = ','.join(trust_list)
+    expires = (DateTime() + 1).toZone('GMT').rfc822()
+    request.set(self.ssl_trust_cookie_name, value)
+    response.setCookie(self.ssl_trust_cookie_name, value, path = '/', \
+    expires = expires)
+    
+  def acceptSSLPerm(self, trust_dict):
+    """ Accept SSL server permanently
+    """
+    self.acceptSSLServer(self, trust_dict, True)
+
+  def _trustSSLServer(self, target_trust_dict):
+    request = self.REQUEST
+    cookie = request.get(self.ssl_trust_cookie_name)
+    if cookie:
+      for trust in cookie.split(','):
+        trust_dict, permanent = self._decodeSSLTrust(trust)
+        for key in target_trust_dict.keys():
+          if target_trust_dict[key] != trust_dict.get(key):
+            continue
+        else:
+          return True, permanent
+    return False, False
+    
+  def _getClient(self, **kw):
+    # Get the svn client object.
+    return newSubversionClient(self, **kw)
+  
+  security.declareProtected('Import/Export objects', 'getSubversionPath')
+  def getSubversionPath(self, business_template, with_name=True):
+    """
+     return the working copy path corresponding to
+     the given business template browsing
+     working copy list in preferences (looking
+     only at first level of directories)
+     
+     with_name : with business template name at the end of the path
+    """
+    wc_list = self.getPortalObject().portal_preferences\
+    .getPreferredSubversionWorkingCopyList()
+    if not wc_list or len(wc_list) == 0 :
+      raise SubversionPreferencesError, \
+      'Please set at least one Subversion Working Copy in preferences first.'
+    bt_name = business_template.getTitle()
+    for working_copy in wc_list:
+      working_copy = self._getWorkingPath(working_copy)
+      if bt_name in listdir(working_copy) :
+        wc_path = os.path.join(working_copy, bt_name)
+        if os.path.isdir(wc_path):
+          if with_name:
+            return wc_path
+          else:
+            return os.sep.join(wc_path.split(os.sep)[:-1])
+    raise SubversionUnknownBusinessTemplateError, \
+        "Could not find '%s' at first level of working copies." % (bt_name, )
+
+  def _getWorkingPath(self, path):
+    """ Check if the given path is reachable (allowed)
+    """
+    real_path = os.path.abspath(path)
+    if not real_path.startswith(self.top_working_path) and \
+        not real_path.startswith(gettempdir()):
+      raise UnauthorizedAccessToPath, 'Unauthorized access to path %s.' \
+          'It is NOT in your Zope home instance.' % real_path
+    return real_path
+    
+  security.declareProtected('Import/Export objects', 'update')
+  def update(self, business_template):
+    """
+     Update a working copy / business template, 
+     reverting all local changes
+    """
+    path = self._getWorkingPath(self.getSubversionPath(business_template))
+    # First remove unversioned in working copy that could conflict
+    self.removeAllInList([x['uid'] for x in self.unversionedFiles(path)])
+    client = self._getClient()
+    # Revert local changes in working copy first
+    # to import a "pure" BT after update
+    self.revert(path=path, recurse=True)
+    # removed unversioned files due to former added files that were reverted
+    self.removeAllInList([x['uid'] for x in self.unversionedFiles(path)])
+    # Update from SVN
+    client.update(path)
+    # Import in zodb
+    return self.importBT(business_template)
+  
+  security.declareProtected('Import/Export objects', 'updateKeep')
+  def updateKeep(self, business_template):
+    """
+     Update a working copy / business template, 
+     keeping all local changes (appart from revision)
+    """
+    path = self._getWorkingPath(self.getSubversionPath(business_template))
+    client = self._getClient()
+    # Revert revision file so that it does not conflict
+    revision_path = os.path.join(path, 'bt', 'revision')
+    if os.path.exists(revision_path):
+      self.revert(path=revision_path, recurse=False)
+    # remove unversioned files in working copy that could be annoying
+    self.removeAllInList([x['uid'] for x in self.unversionedFiles(path)])
+    # Update from SVN
+    client.update(path)
+    # Check if some files are conflicted to raise an exception
+    conflicted_list = self.conflictedFiles(self.getSubversionPath(business_template))
+    if len(conflicted_list) != 0:
+      raise SubversionConflictError, 'The following files conflicts (%s), please resolve manually.' % repr(conflicted_list)
+    # Import in zodb
+    return self.importBT(business_template)
+
+  security.declareProtected('Import/Export objects', 'switch')
+  def switch(self, business_template, url):
+    """switch SVN repository for a working copy.
+    """
+    path = self._getWorkingPath(self.getSubversionPath(business_template))
+    client = self._getClient()
+    if url[-1] == '/' :
+      url = url[:-1]
+    # Update from SVN
+    client.switch(path=path, url=url)
+  
+  security.declareProtected('Import/Export objects', 'add')
+  # path can be a list or not (relative or absolute)
+  def add(self, path, business_template=None):
+    """Add a file or a directory.
+    """
+    if business_template is not None:
+      if isinstance(path, list) :
+        path = [self._getWorkingPath(self.relativeToAbsolute(x, \
+        business_template)) for x in path]
+      else:
+        path = self._getWorkingPath(self.relativeToAbsolute(path, \
+        business_template))
+    client = self._getClient()
+    return client.add(path)
+
+  security.declareProtected('Import/Export objects', 'info')
+  def info(self, business_template):
+    """return info of working copy
+    """
+    working_copy = self._getWorkingPath(self\
+    .getSubversionPath(business_template))
+    client = self._getClient()
+    return client.info(working_copy)
+  
+  security.declareProtected('Import/Export objects', 'log')
+  # path can be absolute or relative
+  def log(self, path, business_template):
+    """return log of a file or dir
+    """
+    client = self._getClient()
+    return client.log(self._getWorkingPath(self\
+    .relativeToAbsolute(path, business_template)))
+  
+  security.declareProtected('Import/Export objects', 'cleanup')
+  def cleanup(self, business_template):
+    """remove svn locks in working copy
+    """
+    working_copy = self._getWorkingPath(self\
+    .getSubversionPath(business_template))
+    client = self._getClient()
+    return client.cleanup(working_copy)
+
+  security.declareProtected('Import/Export objects', 'remove')
+  # path can be a list or not (relative or absolute)
+  def remove(self, path, business_template=None):
+    """Remove a file or a directory.
+    """
+    if business_template is not None:
+      if isinstance(path, list) :
+        path = [self._getWorkingPath(self\
+        .relativeToAbsolute(x, business_template)) for x in path]
+      else:
+        path = self._getWorkingPath(self.relativeToAbsolute(path, \
+        business_template))
+    client = self._getClient()
+    return client.remove(path)
+
+  security.declareProtected('Import/Export objects', 'move')
+  def move(self, src, dest):
+    """Move/Rename a file or a directory.
+    """
+    client = self._getClient()
+    return client.move(self._getWorkingPath(src), self._getWorkingPath(dest))
+
+  security.declareProtected('Import/Export objects', 'ls')
+  # path can be relative or absolute
+  def ls(self, path, business_template):
+    """Display infos about a file.
+    """
+    client = self._getClient()
+    return client.ls(self._getWorkingPath(self\
+    .relativeToAbsolute(path, business_template)))
+
+  security.declareProtected('Import/Export objects', 'diff')
+  # path can be relative or absolute
+  def diff(self, path, business_template, revision1=None, revision2=None):
+    """Make a diff for a file or a directory.
+    """
+    client = self._getClient()
+    return client.diff(self._getWorkingPath(self.relativeToAbsolute(path, \
+    business_template)), revision1, revision2)
+  
+  security.declareProtected('Import/Export objects', 'revert')
+  # path can be absolute or relative
+  def revert(self, path, business_template=None, recurse=False):
+    """Revert local changes in a file or a directory.
+    """
+    client = self._getClient()
+    if not isinstance(path, list) :
+      path = [self._getWorkingPath(self.relativeToAbsolute(path, \
+      business_template))]
+    if business_template is not None:
+      path = [self._getWorkingPath(self.relativeToAbsolute(x, \
+      business_template)) for x in path]
+    client.revert(path, recurse)
+
+  security.declareProtected('Import/Export objects', 'revertZODB')
+  # path can be absolute or relative
+  def revertZODB(self, business_template, added_files=None, \
+  other_files=None, recurse=False):
+    """Revert local changes in a file or a directory
+       in ZODB and on hard drive
+    """
+    client = self._getClient()
+    object_to_update = {}
+    # Transform params to list if they are not already lists
+    if not added_files :
+      added_files = []
+    if not other_files :
+      other_files = []
+    if not isinstance(added_files, list) :
+      added_files = [added_files]
+    if not isinstance(other_files, list) :
+      other_files = [other_files]
+      
+    # Reinstall removed or modified files
+    for path in other_files :
+      # security check
+      self._getWorkingPath(self.relativeToAbsolute(path, business_template))
+      path_list = path.split(os.sep)
+      if 'bt' not in path_list:
+        if len(path_list) > 2 :
+          tmp = os.sep.join(path_list[2:])
+          # Remove file extension
+          tmp = os.path.splitext(tmp)[0]
+          object_to_update[tmp] = 'install'
+    path_added_list = []
+    # remove added files
+    for path in added_files :
+      # security check
+      self._getWorkingPath(self.relativeToAbsolute(path, business_template))
+      path_list = path.split(os.sep)
+      if 'bt' not in path_list:
+        if len(path_list) > 2 :
+          tmp = os.sep.join(path_list[2:])
+          # Remove file extension
+          tmp = os.path.splitext(tmp)[0]
+          path_added_list.append(tmp)
+    ## hack to remove objects
+    # Create a temporary bt with objects to delete
+    tmp_bt = getToolByName(business_template, 'portal_templates')\
+    .newContent(portal_type="Business Template")
+    tmp_bt.setTemplatePathList(path_added_list)
+    tmp_bt.setTitle('tmp_bt_revert')
+    # Build bt
+    tmp_bt.edit()
+    tmp_bt.build()
+    # Install then uninstall it to remove objects from ZODB
+    tmp_bt.install()
+    tmp_bt.uninstall()
+    # Remove it from portal template
+    business_template.portal_templates.manage_delObjects(ids=tmp_bt.getId())
+    #revert changes
+    added_files.extend(other_files)
+    to_revert = [self.relativeToAbsolute(x, business_template) \
+    for x in added_files]
+    if len(to_revert) != 0 :
+      client.revert(to_revert, recurse)
+      # Partially reinstall installed bt
+      installed_bt = business_template.portal_templates\
+      .getInstalledBusinessTemplate(business_template.getTitle())
+      if installed_bt is None:
+        raise SubversionBusinessTemplateNotInstalled, "Revert won't work if the business template is not installed. Please install it first."
+      installed_bt.reinstall(object_to_update=object_to_update, force=0)
+    
+  security.declareProtected('Import/Export objects', 'resolved')
+  # path can be absolute or relative
+  def resolved(self, path, business_template):
+    """remove conflicted status
+    """
+    client = self._getClient()
+    if isinstance(path, list) :
+      path = [self._getWorkingPath(self.relativeToAbsolute(x, \
+      business_template)) for x in path]
+    else:
+      path = self._getWorkingPath(self.relativeToAbsolute(path, \
+      business_template))
+    return client.resolved(path)
+
+  def relativeToAbsolute(self, path, business_template):
+    """ Return an absolute path given the absolute one
+        and the business template
+    """
+    if path[0] == os.sep:
+      # already absolute
+      return path
+    # relative path
+    if path.split(os.sep)[0] == business_template.getTitle():
+      return os.path.join(self.getSubversionPath(business_template, \
+      False), path)
+    else:
+      return os.path.join(self.getSubversionPath(business_template), path)
+
+  security.declareProtected('Import/Export objects', 'checkin')
+  # path can be relative or absolute (can be a list of paths too)
+  def checkin(self, path, business_template, log_message=None, recurse=True):
+    """Commit local changes.
+    """
+    if isinstance(path, list) :
+      path = [self._getWorkingPath(self.relativeToAbsolute(x, \
+      business_template)) for x in path]
+    else:
+      path = self._getWorkingPath(self.relativeToAbsolute(path, \
+      business_template))
+    client = self._getClient()
+    # Pysvn wants unicode objects
+    if isinstance(log_message, str):
+      log_message = log_message.decode('utf8')
+    return client.checkin(path, log_message, recurse)
+
+  security.declareProtected('Import/Export objects', 'getLastChangelog')
+  def getLastChangelog(self, business_template):
+    """Return last changelog of a business template
+    """
+    bt_path = self._getWorkingPath(self.getSubversionPath(business_template))
+    changelog_path = bt_path + os.sep + 'bt' + os.sep + 'change_log'
+    changelog = ""
+    if os.path.exists(changelog_path):
+      changelog_file = open(changelog_path, 'r')
+      changelog_lines = changelog_file.readlines()
+      changelog_file.close()
+      for line in changelog_lines:
+        if line.strip() == '':
+          break
+        changelog += line
+    return changelog
+    
+
+  security.declareProtected('Import/Export objects', 'status')
+  def status(self, path, **kw):
+    """Get status.
+    """
+    client = self._getClient()
+    return client.status(self._getWorkingPath(path), **kw)
+  
+  security.declareProtected('Import/Export objects', 'unversionedFiles')
+  def unversionedFiles(self, path, **kw):
+    """Return unversioned files
+    """
+    client = self._getClient()
+    status_list = client.status(self._getWorkingPath(path), **kw)
+    unversioned_list = []
+    for status_obj in status_list:
+      if str(status_obj.getTextStatus()) == "unversioned":
+        my_dict = {}
+        my_dict['uid'] = status_obj.getPath()
+        unversioned_list.append(my_dict)
+    return unversioned_list
+      
+  security.declareProtected('Import/Export objects', 'conflictedFiles')
+  def conflictedFiles(self, path, **kw):
+    """Return unversioned files
+    """
+    client = self._getClient()
+    status_list = client.status(self._getWorkingPath(path), **kw)
+    conflicted_list = []
+    for status_obj in status_list:
+      if str(status_obj.getTextStatus()) == "conflicted":
+        my_dict = {}
+        my_dict['uid'] = status_obj.getPath()
+        conflicted_list.append(my_dict)
+    return conflicted_list
+
+  security.declareProtected('Import/Export objects', 'removeAllInList')
+  def removeAllInList(self, path_list, REQUEST=None):
+    """Remove all files and folders in list
+    """
+    if REQUEST is not None:
+      # Security hole fix
+      raise SubversionSecurityError, 'You are not allowed to delete these files'
+    for file_path in path_list:
+      removeAll(self._getWorkingPath(file_path))
+    
+  def getModifiedTree(self, business_template, show_unmodified=False) :
+    """ Return tree of files returned by svn status
+    """
+    # Get subversion path without business template name at the end
+    bt_path = self._getWorkingPath(self.getSubversionPath(business_template, \
+    False))
+    if bt_path[-1] != os.sep:
+      bt_path += os.sep
+    # Business template root directory is the root of the tree
+    root = Dir(business_template.getTitle(), "normal")
+    something_modified = False
+    
+    statusObj_list = self.status(os.path.join(bt_path, \
+    business_template.getTitle()), update=False)
+    # We browse the files returned by svn status
+    for status_obj in statusObj_list :
+      # can be (normal, added, modified, deleted, conflicted, unversioned)
+      status = str(status_obj.getTextStatus())
+      if str(status_obj.getReposTextStatus()) != 'none':
+	status = "outdated"
+      if (show_unmodified or status != "normal") and status != "unversioned":
+        something_modified = True
+        # Get object path
+        full_path = status_obj.getPath()
+        relative_path = full_path.replace(bt_path, '')
+        filename = os.path.basename(relative_path)
+
+        # Always start from root
+        parent = root
+        
+        # First we add the directories present in the path to the tree
+        # if it does not already exist
+        for directory in relative_path.split(os.sep)[1:-1] :
+          if directory :
+            if directory not in parent.getSubDirsNameList() :
+              parent.sub_dirs.append(Dir(directory, "normal"))
+            parent = parent.getDirFromName(directory)
+        
+        # Consider the whole path which can be a folder or a file
+        # We add it the to the tree if it does not already exist
+        if os.path.isdir(full_path) :
+          if filename == parent.name :
+            parent.status = status
+          elif filename not in parent.getSubDirsNameList() :
+            # Add new dir to the tree
+            parent.sub_dirs.append(Dir(filename, str(status)))
+          else :
+            # update msg status
+            tmp = parent.getDirFromName(filename)
+            tmp.status = str(status)
+        else :
+          # add new file to the tree
+          parent.sub_files.append(File(filename, str(status)))
+    return something_modified and root
+  
+  def extractBT(self, business_template):
+    """ 
+     Extract business template to hard drive
+     and do svn add/del stuff comparing it
+     to local working copy
+    """
+    if business_template.getBuildingState() == 'draft':
+      business_template.edit()
+    business_template.build()
+    svn_path = self._getWorkingPath(self.getSubversionPath(business_template) \
+    + os.sep)
+    path = mktemp() + os.sep
+    try:
+      # XXX: Big hack to make export work as expected.
+      get_transaction().commit()
+      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)
+    except (pysvn.ClientError, NotFound, AttributeError, \
+    Error), error:
+      # Clean up
+      removeAll(path)
+      raise error
+    # Clean up
+    self.activate().removeAllInList([path, ])
+    
+  def importBT(self, business_template):
+    """
+     Import business template from local
+     working copy
+    """
+    return business_template.download(self._getWorkingPath(self\
+    .getSubversionPath(business_template)))
+    
+  # Get a list of files and keep only parents
+  # Necessary before recursively commit removals
+  def cleanChildrenInList(self, path_list):
+    """
+     Get a list of files and keep only parents
+     Necessary before recursively commit removals
+    """
+    res = path_list
+    for file_path in path_list:
+      res = [x for x in res if file_path == x or file_path not in x]
+    return res
+
+  # return a set with directories present in the directory
+  def getSetDirsForDir(self, directory):
+    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
+  # 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
+    files_set = self.getNewFiles(new_dir, old_dir)
+    # detect removed directories
+    dirs_set = self.getNewDirs(new_dir, old_dir)
+    # svn del
+    path_list = [x for x in files_set]
+    path_list.sort()
+    self.remove([os.path.join(old_dir, x[1]) for x in path_list])
+    path_list = [x for x in dirs_set]
+    path_list.sort()
+    self.remove([os.path.join(old_dir, x[1]) for x in path_list])
+  
+  def addNewFiles(self, old_dir, new_dir):
+    """ copy files and add new files
+    """
+    # detect created files
+    files_set = self.getNewFiles(old_dir, new_dir)
+    # detect created directories
+    dirs_set = self.getNewDirs(old_dir, new_dir)
+    # Copy files
+    copytree(new_dir, old_dir)
+    # svn add
+    path_list = [x for x in dirs_set]
+    path_list.sort()
+    self.add([os.path.join(old_dir, x[1]) for x in path_list])
+    path_list = [x for x in files_set]
+    path_list.sort()
+    self.add([os.path.join(old_dir, x[1]) for x in path_list])
+  
+  def treeToXML(self, item, business_template) :
+    """ Convert tree in memory to XML
+    """
+    output = '<?xml version="1.0" encoding="UTF-8"?>'+ os.linesep
+    output += "<tree id='0'>" + os.linesep
+    output = self._treeToXML(item, output, business_template.getTitle(), True)
+    output += '</tree>' + os.linesep
+    return output
+  
+  def _treeToXML(self, item, output, relative_path, first) :
+    """
+     Private function to convert recursively tree 
+     in memory to XML
+    """
+    # Choosing a color coresponding to the status
+    status = item.status
+    if status == 'added' :
+      color = 'green'
+    elif status == 'modified' or  status == 'replaced' :
+      color = 'orange'
+    elif status == 'deleted' :
+      color = 'red'
+    elif status == 'conflicted' :
+      color = 'grey'
+    elif status == 'outdated' :
+      color = 'purple'
+    else :
+      color = 'black'
+    if isinstance(item, Dir) :
+      if first :
+        output += '<item open="1" text="%s" id="%s" aCol="%s" '\
+        'im0="folder.png" im1="folder_open.png" '\
+        'im2="folder.png">'%(item.name, relative_path, color) + os.linesep
+        first = False
+      else :
+        output += '<item text="%s" id="%s" aCol="%s" im0="folder.png" ' \
+        'im1="folder_open.png" im2="folder.png">'%(item.name,
+        relative_path, color) + os.linesep
+      for it in item.getContent():
+        output = self._treeToXML(item.getObjectFromName(it.name), output, \
+        os.path.join(relative_path,it.name),first)
+      output += '</item>' + os.linesep
+    else :
+      output += '<item text="%s" id="%s" aCol="%s" im0="document.png"/>'\
+                %(item.name, relative_path, color) + os.linesep
+    return output
+    
+InitializeClass(SubversionTool)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/Tool/__init__.py?rev=12776&view=auto
==============================================================================
    (empty)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/VERSION.txt
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/VERSION.txt?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/VERSION.txt (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/VERSION.txt Thu Feb 15 18:21:43 2007
@@ -1,0 +1,1 @@
+ERP5Subversion 0.14

Propchange: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/VERSION.txt
------------------------------------------------------------------------------
    svn:executable = 

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/__init__.py?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/__init__.py (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/__init__.py Thu Feb 15 18:21:43 2007
@@ -1,0 +1,61 @@
+##############################################################################
+#
+# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
+#                    Yoshinori Okuji <yo at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+"""
+    ERP5 Free Software ERP
+"""
+
+# Update ERP5 Globals
+from Products.ERP5Type.Utils import initializeProduct, updateGlobals
+import sys, Permissions
+this_module = sys.modules[ __name__ ]
+document_classes = updateGlobals( this_module, globals(), permissions_module = Permissions)
+
+from Tool import SubversionTool
+
+# Define object classes and tools
+object_classes = ()
+portal_tools = (SubversionTool.SubversionTool,)
+content_classes = ()
+content_constructors = ()
+
+# Finish installation
+def initialize( context ):
+  import Document
+  initializeProduct(context, this_module, globals(),
+                         document_module = Document,
+                         document_classes = document_classes,
+                         object_classes = object_classes,
+                         portal_tools = portal_tools,
+                         content_constructors = content_constructors,
+                         content_classes = content_classes)
+
+from AccessControl.SecurityInfo import allow_module
+
+allow_module('Products.ERP5Subversion.SubversionClient')
+
+

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/changelog
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/changelog?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/changelog (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/changelog Thu Feb 15 18:21:43 2007
@@ -1,0 +1,6 @@
+erp5-erp5subversion (0.14-1) unstable; urgency=low
+
+  * Initial Release.
+
+ -- Yusei TAHARA <yusei at domen.cx>  Wed, 14 Feb 2007 03:27:56 +0900
+

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/compat
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/compat?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/compat (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/compat Thu Feb 15 18:21:43 2007
@@ -1,0 +1,1 @@
+5

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/control
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/control?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/control (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/control Thu Feb 15 18:21:43 2007
@@ -1,0 +1,13 @@
+Source: erp5-erp5subversion
+Section: web
+Priority: optional
+Maintainer: Yusei TAHARA
+Build-Depends: debhelper (>= 5.0)
+Build-Depends-Indep: zope-debhelper (>= 0.3.6)
+Standards-Version: 3.7.2
+
+Package: erp5-erp5subversion
+Architecture: all
+Depends: erp5-zope
+Description: A zope product to integrate SVN with ERP5 to make developer life easier.
+ This zope product provides a Subversion interface to ERP5.

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/copyright
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/copyright?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/copyright (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/copyright Thu Feb 15 18:21:43 2007
@@ -1,0 +1,2 @@
+Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
+                   Yoshinori Okuji <yo at nexedi.com>

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/dzproduct
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/dzproduct?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/dzproduct (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/dzproduct Thu Feb 15 18:21:43 2007
@@ -1,0 +1,3 @@
+Name: ERP5Subversion
+Package: erp5-erp5subversion
+ZopeVersions: >= 2.7

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/postinst
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/postinst?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/postinst (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/postinst Thu Feb 15 18:21:43 2007
@@ -1,0 +1,7 @@
+#!/bin/sh -e
+
+. /usr/share/debconf/confmodule
+
+#DEBHELPER#
+
+db_stop

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/rules
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/rules?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/rules (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/rules Thu Feb 15 18:21:43 2007
@@ -1,0 +1,44 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+pwd        := $(shell pwd)
+debian     := $(pwd)/debian/erp5-erp5subversion
+
+build: build-stamp
+build-stamp:
+	touch build-stamp
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+	dh_clean
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k
+	dh_installdirs
+	dh_installerp5zope .
+
+binary-indep: build install
+	dh_testdir
+	dh_testroot
+	dh_installdocs
+	dh_installexamples
+	dh_installchangelogs
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary-arch:
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary install

Propchange: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/debian/rules
------------------------------------------------------------------------------
    svn:executable = 

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/dtml/explainSubversionTool.dtml
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/dtml/explainSubversionTool.dtml?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/dtml/explainSubversionTool.dtml (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/dtml/explainSubversionTool.dtml Thu Feb 15 18:21:43 2007
@@ -1,0 +1,6 @@
+<dtml-var manage_page_header>
+<dtml-var manage_tabs>
+
+<p>SubversionTool provides a Subversion interface for ERP5.</p>
+
+<dtml-var manage_page_footer>

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/help/ERP5Subversion.stx
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/help/ERP5Subversion.stx?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/help/ERP5Subversion.stx (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/help/ERP5Subversion.stx Thu Feb 15 18:21:43 2007
@@ -1,0 +1,1 @@
+Help

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/skins/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/skins/__init__.py?rev=12776&view=auto
==============================================================================
    (empty)

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tests/__init__.py
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tests/__init__.py?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tests/__init__.py (added)
+++ spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tests/__init__.py Thu Feb 15 18:21:43 2007
@@ -1,0 +1,1 @@
+# make this directory a package

Added: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tool.png
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tool.png?rev=12776&view=auto
==============================================================================
Binary file - no diff available.

Propchange: spec/debian/unstable/erp5-erp5subversion/ERP5Subversion/tool.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.diff.gz
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.diff.gz?rev=12776&view=auto
==============================================================================
Binary file - no diff available.

Propchange: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.diff.gz
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.dsc
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.dsc?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.dsc (added)
+++ spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1.dsc Thu Feb 15 18:21:43 2007
@@ -1,0 +1,12 @@
+Format: 1.0
+Source: erp5-erp5subversion
+Version: 0.14-1
+Binary: erp5-erp5subversion
+Maintainer: Yusei TAHARA
+Architecture: all
+Standards-Version: 3.7.2
+Build-Depends: debhelper (>= 5.0)
+Build-Depends-Indep: zope-debhelper (>= 0.3.6)
+Files: 
+ 89962a7aa0a3d13b694782492f6a05f3 15956 erp5-erp5subversion_0.14.orig.tar.gz
+ 4ce30c4c392fdf177a589d9578595338 971 erp5-erp5subversion_0.14-1.diff.gz

Added: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_all.deb
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_all.deb?rev=12776&view=auto
==============================================================================
Binary file - no diff available.

Propchange: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_all.deb
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.build
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.build?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.build (added)
+++ spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.build Thu Feb 15 18:21:43 2007
@@ -1,0 +1,34 @@
+ fakeroot debian/rules clean
+dh_testdir
+dh_testroot
+rm -f build-stamp configure-stamp
+dh_clean
+ dpkg-source -b ERP5Subversion
+dpkg-source: warning: source directory `./ERP5Subversion' is not <sourcepackage>-<upstreamversion> `erp5-erp5subversion-0.14'
+dpkg-source: warning: .orig directory name ERP5Subversion.orig is not <package>-<upstreamversion> (wanted erp5-erp5subversion-0.14.orig)
+dpkg-source: building erp5-erp5subversion using existing erp5-erp5subversion_0.14.orig.tar.gz
+dpkg-source: building erp5-erp5subversion in erp5-erp5subversion_0.14-1.diff.gz
+dpkg-source: building erp5-erp5subversion in erp5-erp5subversion_0.14-1.dsc
+ debian/rules build
+touch build-stamp
+ fakeroot debian/rules binary
+dh_testdir
+dh_testroot
+dh_clean -k
+dh_installdirs
+dh_installerp5zope .
+dh_testdir
+dh_testroot
+dh_installdocs
+dh_installexamples
+dh_installchangelogs
+dh_compress
+dh_fixperms
+dh_installdeb
+dh_gencontrol
+dh_md5sums
+dh_builddeb
+dpkg-deb: `../erp5-erp5subversion_0.14-1_all.deb' ¤Ë¥Ñ¥Ã¥±¡¼¥¸ `erp5-erp5subversion' ¤ò¹½ÃÛ¤·¤Æ¤¤¤Þ¤¹¡£
+ dpkg-genchanges
+dpkg-genchanges: including full source code in upload
+dpkg-buildpackage (debuild emulation): full upload (original source is included)

Added: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.changes
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.changes?rev=12776&view=auto
==============================================================================
--- spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.changes (added)
+++ spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14-1_i386.changes Thu Feb 15 18:21:43 2007
@@ -1,0 +1,21 @@
+Format: 1.7
+Date: Wed, 14 Feb 2007 03:27:56 +0900
+Source: erp5-erp5subversion
+Binary: erp5-erp5subversion
+Architecture: source all
+Version: 0.14-1
+Distribution: unstable
+Urgency: low
+Maintainer: Yusei TAHARA
+Changed-By: Yusei TAHARA <yusei at domen.cx>
+Description: 
+ erp5-erp5subversion - A zope product to integrate SVN with ERP5 to make developer life 
+Changes: 
+ erp5-erp5subversion (0.14-1) unstable; urgency=low
+ .
+   * Initial Release.
+Files: 
+ d328da74c539bf2a223ba1bb4408d1af 391 web optional erp5-erp5subversion_0.14-1.dsc
+ 89962a7aa0a3d13b694782492f6a05f3 15956 web optional erp5-erp5subversion_0.14.orig.tar.gz
+ 4ce30c4c392fdf177a589d9578595338 971 web optional erp5-erp5subversion_0.14-1.diff.gz
+ 4f13740d13b00c5b9bdb1686360a4d54 18128 web optional erp5-erp5subversion_0.14-1_all.deb

Added: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14.orig.tar.gz
URL: http://svn.erp5.org/spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14.orig.tar.gz?rev=12776&view=auto
==============================================================================
Binary file - no diff available.

Propchange: spec/debian/unstable/erp5-erp5subversion/erp5-erp5subversion_0.14.orig.tar.gz
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream




More information about the Erp5-report mailing list