[Zope3-checkins] CVS: Zope3/utilities/fssync - README.txt:1.2 add.py:1.2 checkout.py:1.2 commit.py:1.2 common.py:1.2 diff.py:1.2 sync.py:1.2 update.py:1.2 usage.py:1.2

Guido van Rossum guido@python.org
Mon, 5 May 2003 14:01:05 -0400


Update of /cvs-repository/Zope3/utilities/fssync
In directory cvs.zope.org:/tmp/cvs-serv2527/utilities/fssync

Added Files:
	README.txt add.py checkout.py commit.py common.py diff.py 
	sync.py update.py usage.py 
Log Message:
Merge fssync stuff back to trunk.  A few things actually work (I
successfully did a checkout of some files and diffed them; though
commit doesn't seem to work yet), and you know how I love long-living
branches....



=== Zope3/utilities/fssync/README.txt 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/README.txt	Mon May  5 14:01:03 2003
@@ -0,0 +1,16 @@
+Filesystem synchronization
+--------------------------
+
+This directory contains a utility (sync.py) and the modules it uses
+that implement filesystem synchronization.  This is a little like CVS,
+with the Data.fs service as the repository.  
+
+Jim Fulton's original proposal explains the theory and background:
+
+  http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/
+  FileSystemSynchronizationProposal
+
+The command line syntax of the utility is given in usage.py.
+
+The implementation was originally written by Jim Fulton and ZeOmega's
+deb_h.  It is now maintained by Guido van Rossum.


=== Zope3/utilities/fssync/add.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/add.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,176 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import string, os
+
+from common import getZODBPath, getApplicationRoot, getObject
+from common import getObjectAdapter, setPrint, IObjectDirectory
+from zope.app.fssync.classes import FSAddRequest
+from zope.component import getView, queryView
+from zope.app.content.folder import Folder
+from zope.app.fssync.syncer import toFS, fromFS
+from zope.xmlpickle.xmlpickle import loads
+
+from zope.component.view import viewService
+
+
+env = os.environ
+
+def add(fspath
+        , dbpath
+        , siteconfpath
+        , newobjecttype
+        , newobjectname):
+
+    """Adds objects to File system
+
+    Creates an object in the file system based on the object type
+    passed with -t  option.
+    """
+    fspath = os.path.abspath(fspath)
+    if not os.path.isdir(fspath):
+        return 'sync [add aborted] : %s is not a directory' %(fspath)
+
+    if not os.path.exists(os.path.join(fspath, '@@Zope')):
+        return 'sync [add aborted] : @@Zope administrative folder not found in %s' \
+               %(fspath)
+
+    objpath = getZODBPath(fspath)
+    root = getApplicationRoot(dbpath, siteconfpath)
+    container = getObject(objpath, root)
+    if container is None:
+        container, name, path = getObject(objpath, root, 'Y')
+        fsroot = os.path.abspath(fspath[:string.find(fspath, objpath)])
+        location = os.path.abspath(os.path.join(fsroot, path[1:]))
+        fromFS(container, name, location, 'T')
+
+    container = getObject(objpath, root)
+
+    adapter = getObjectAdapter(container)
+
+    if newobjecttype:
+        newobjecttype = '.'+newobjecttype
+        for file in newobjectname:
+            entries_path = os.path.join(os.path.join(fspath, os.path.dirname(file)),'@@Zope','Entries.xml')
+            entries = {}
+            if os.path.exists(entries_path):
+                entries = loads(open(entries_path).read())
+            if getObject(objpath+'/'+file, root) is not None:
+                setPrint('Object already exist in the ZODB : %s' \
+                          %(os.path.join(fspath,file)))
+            elif entries.has_key(os.path.basename(file)):
+                setPrint('Object already exist in sandbox : %s' \
+                          %(os.path.join(fspath,file)))
+            else:
+                err = addObject(adapter, fspath, newobjecttype, file, objpath)
+                if err is not None:
+                    setPrint(err)
+                    break
+    else:
+        for file in newobjectname:
+            entries_path = os.path.join(os.path.join(fspath, os.path.dirname(file)),'@@Zope','Entries.xml')
+            entries = {}
+            if os.path.exists(entries_path):
+                entries = loads(open(entries_path).read())
+            if getObject(objpath+'/'+file, root) is not None:
+                setPrint('Object already exist in the ZODB : %s' \
+                          %(os.path.join(fspath,file)))
+            elif entries.has_key(os.path.basename(file)):
+                setPrint('Object already exist in sandbox : %s' \
+                          %(os.path.join(fspath,file)))
+            else:
+                newobjecttype = '.'+string.split(file,'.')[-1]
+                err = addObject(adapter
+                                , fspath
+                                , newobjecttype
+                                , file
+                                , objpath)
+                if err is not None:
+                    setPrint(err)
+    return None
+
+def addObject(adapter
+              , fspath
+              , newobjecttype
+              , newobjectname
+              , objpath):
+
+    mode = 'N'
+    if IObjectDirectory.isImplementedBy(adapter):
+        request = FSAddRequest()
+        view = queryView(adapter, newobjecttype, request)
+        if view is not None:
+            newobjectpath = os.path.abspath(os.path.join(fspath, newobjectname))
+            if not os.path.exists(os.path.dirname(newobjectpath)):
+                return 'Nothing known about : %s'%(newobjectpath)
+            newobject = view.create()
+            objpath = objpath+'/'+newobjectname
+            objectname = os.path.basename(newobjectpath)
+            newobjectpath = os.path.dirname(newobjectpath)
+            dir_list = createAdminFolder(newobjectpath, objpath)
+            keys = dir_list.keys()
+            keys.sort()
+            for sl_no in keys:
+                ob = Folder()
+                toFS(ob, dir_list[sl_no][2], dir_list[sl_no][0], mode, dir_list[sl_no][1])
+            toFS(newobject, objectname, newobjectpath, mode, objpath)
+        else:
+            newobjectpath = os.path.abspath(os.path.join(fspath, newobjectname))
+            if not os.path.exists(newobjectpath):
+                return 'Nothing known about : %s'%(newobjectpath)
+            view = getView(adapter, '.', request)
+            newobject = view.create(newobjectpath)
+            objpath = os.path.abspath(objpath+'/'+newobjectname)
+            objectname = os.path.basename(newobjectpath)
+            newobjectpath = os.path.dirname(newobjectpath)
+            path_list = string.split(newobjectname, os.sep)
+            if len(path_list) > 1:
+                if path_list[-1] != objectname:
+                    return 'Nothing known about : %s'%(path_list[-1])
+
+                dir_list = createAdminFolder(newobjectpath, objpath)
+                keys = dir_list.keys()
+                keys.sort()
+                for sl_no in keys:
+                    ob = Folder()
+                    toFS(ob, dir_list[sl_no][2], dir_list[sl_no][0], mode, dir_list[sl_no][1])
+            toFS(newobject, objectname, newobjectpath, mode, objpath)
+
+    else:
+        return 'Not a container type : %s' %(os.path.basename(fspath))
+    return None
+
+def createAdminFolder(fspath, objpath, name=None, data={}):
+    if name is not None:
+        data[len(string.split(objpath, '/'))] = (fspath, objpath, name)
+    if not os.path.exists(os.path.join(fspath, '@@Zope')):
+        return createAdminFolder(os.path.dirname(fspath), os.path.dirname(objpath), os.path.basename(fspath))
+    return data
+
+def addTypes(dbpath
+             , siteconfpath):
+    root = getApplicationRoot(dbpath, siteconfpath)
+    f = Folder()
+    adapter = getObjectAdapter(f)
+    request = FSAddRequest()
+    allviews = viewService.all()['default']
+    setPrint("\nALL AVAILABLE TYPES")
+    setPrint("====================================================\n")
+    for view in allviews:
+        try:
+            if len(view)>1 and view[0] == '.':
+                doc = getView(adapter, view, request).__doc__
+                setPrint(' %s  \n %s \n\n' % (view, doc))
+        except:
+            pass


=== Zope3/utilities/fssync/checkout.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/checkout.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import string, os
+
+from zope.app.fssync.syncer import toFS
+
+from common import getObject, getApplicationRoot
+from common import makeNewEntry, getObjectAdapter
+
+def checkout(fspath
+             , dbpath
+             , siteconfpath
+             , objpath):
+    """Checks out objects from ZODB to the file system
+
+    Downloads ZODB objects in file system to the specified path
+    specified but -f option.
+    """
+    sandbox_path = fspath
+    if not os.path.isabs(objpath):
+        objpath = '/'+objpath
+    objpath = os.path.abspath(objpath)
+    root = getApplicationRoot(dbpath, siteconfpath)
+    main_ob = getObject(objpath, root)
+    ob_name = os.path.basename(objpath)
+    if main_ob is not None:
+        path = ''
+        for dir in string.split(objpath[:string.rfind(objpath,ob_name)], '/')[1:-1]:
+            path = os.path.join(path,dir)
+            sandbox_path = os.path.join(fspath, path)
+            admin_dir = os.path.join(os.path.dirname(sandbox_path), '@@Zope')
+            entries_path = os.path.join(os.path.dirname(sandbox_path),
+                                        '@@Zope'
+                                        , 'Entries.xml')
+            if not os.path.exists(sandbox_path):
+                os.mkdir(sandbox_path)
+            if not os.path.exists(admin_dir):
+                os.mkdir(admin_dir)
+            if not os.path.exists(entries_path):
+                makeNewEntry(admin_dir)
+
+            o_path = '/'+path
+            ob = getObject(o_path, root)
+            adapter = getObjectAdapter(ob)
+            type = adapter.typeIdentifier()
+            factory = adapter.factory()
+            name = os.path.basename(o_path)
+            makeNewEntry(admin_dir
+                         , name
+                         , type
+                         , factory
+                         , o_path)
+
+        fspath = sandbox_path
+        toFS(main_ob, ob_name, fspath)
+        return None
+    else:
+        return "Invalid object path"


=== Zope3/utilities/fssync/commit.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/commit.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,155 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import os, string, commands
+
+from zope.app.fssync.syncer import fromFS
+from common import getZODBPath, createTempfile, getObject
+from common import getApplicationRoot, traverseFS, checkConflictData
+from common import isNewObject, setPrint
+from transaction import get_transaction
+
+env = os.environ
+
+def commit(fspath
+           , dbpath
+           , siteconfpath
+           , mode=None):
+    """Checks in from file system to ZODB
+
+    Saves the unconflict files in ZODB as Zope objects from the
+    file system.
+    """
+    fspath = os.path.abspath(fspath)
+    vpath = '<>'
+    if os.path.isdir(fspath):
+        admin_dir = os.path.join(fspath,'@@Zope')
+    else:
+        admin_dir = os.path.join(os.path.dirname(fspath),'@@Zope')
+    if not os.path.exists(admin_dir):
+        return 'sync [commit aborted] : @@Zope administrative folder not found'
+
+    root = getApplicationRoot(dbpath, siteconfpath)
+    if mode == 'F':
+        err = doCommit(fspath, root, mode)
+        if err is not None:
+            return err
+    else:
+        mapping_paths = traverseFS(fspath, {})
+        for sandbox_path in mapping_paths.keys():
+            original_path = string.strip(mapping_paths[sandbox_path][0])
+            zopedb_path = string.strip(mapping_paths[sandbox_path][1])
+            if isNewObject(sandbox_path):
+                fsroot = os.path.abspath(sandbox_path[:string.find(sandbox_path
+                                                                   , zopedb_path)])
+                path = ''
+                for object in string.split(zopedb_path,'/')[1:]:
+                    path = os.path.join(path,object)
+                    newobjpath = os.path.join(fsroot,path)
+                    if isNewObject(newobjpath):
+                        err = doCommit(newobjpath, root, 'F')
+                        if err is not None:
+                            return err
+                        if os.path.isdir(newobjpath):
+                            vpath = newobjpath
+                            break
+            else:
+                if string.find(sandbox_path,vpath)==-1:
+                    fmt_sandbox_path = ''
+                    fmt_original_path = ''
+                    for dir in string.split(sandbox_path,os.sep):
+                        if string.find(dir, ' ')<>-1:
+                            fmt_sandbox_path = os.path.join(fmt_sandbox_path
+                                                            , '\''+dir+'\'')
+                        else:
+                            fmt_sandbox_path = os.path.join(fmt_sandbox_path
+                                                            , dir)
+
+                    for dir in string.split(original_path,os.sep):
+                        if string.find(dir, ' ')<>-1:
+                            fmt_original_path = os.path.join(fmt_original_path
+                                                             , '\''+dir+'\'')
+                        else:
+                            fmt_original_path = os.path.join(fmt_original_path
+                                                             , dir)
+                    fmt_sandbox_path = os.sep + fmt_sandbox_path
+                    fmt_original_path = os.sep + fmt_original_path
+
+                    ob = getObject(zopedb_path, root)
+                    zopedb_temp_file = createTempfile(ob, zopedb_path)
+                    diff_cmd1 = """diff -q -b %s %s;echo $?""" \
+                                %(fmt_original_path, zopedb_temp_file)
+                    diff_res1 = commands.getoutput(diff_cmd1)
+                    isConflict = int(diff_res1[-1])
+                    diff_cmd2 = """diff -q -b %s %s;echo $?""" \
+                                %(fmt_sandbox_path, fmt_original_path)
+                    diff_res2 = commands.getoutput(diff_cmd2)
+                    isCommitRequired = int(diff_res2[-1])
+
+                    if checkConflictData(sandbox_path, zopedb_path):
+                        isConflict = 1
+                    if isConflict:
+                        msg = "%s Conflict, Uptodate checkin failed" \
+                              %(zopedb_path)
+                        setPrint(msg)
+                    else:
+                        if not (isCommitRequired == isConflict == 0):
+                            msg = "%s  <--  %s" \
+                                  %(zopedb_path, string.split(zopedb_path,'/')[-1])
+                            err = doCommit(sandbox_path, root)
+                            if err is not None:
+                                return err
+                            setPrint(msg)
+
+                    if os.path.exists(zopedb_temp_file):
+                        os.remove(zopedb_temp_file)
+
+    return None
+
+
+def doCommit(fspath, root, mode=None):
+    container = ''
+    objpath = getZODBPath(fspath)
+    objname = string.split(objpath, '/')[-1]
+    path = string.split(objpath, '/')[:-1]
+
+    for item in path:
+        if item:
+            container = container +'[\''+item+'\']'
+    try:
+        if container:
+            container=eval('root'+container)
+        else:
+            container=root
+    except:
+        return 'sync [commit aborted] : invalid object path ---  %s' \
+               %(objpath)
+
+    #copying to ZODB
+    fromFS(container, objname , os.path.dirname(fspath), mode)
+    get_transaction().commit()
+
+    if mode is None:
+        #copying to original
+        f = open(fspath, 'r')
+        data = f.read()
+        f.close()
+        original_path = os.path.join(os.path.dirname(fspath)
+                                     ,'@@Zope'
+                                     ,'Original'
+                                     ,os.path.basename(fspath))
+        f = open(original_path, 'w')
+        f.write(string.strip(data))
+        f.close()
+    return None


=== Zope3/utilities/fssync/common.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/common.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,287 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import os, tempfile, string
+
+from zope.app.fssync.fsregistry import getSynchronizer
+from zope.app.fssync.syncer import toFS
+from zope.app import Application
+from zope.app.interfaces.dublincore import IZopeDublinCore
+from zope.app.interfaces.fssync import IObjectEntry
+from zope.app.interfaces.fssync import IObjectFile, IObjectDirectory
+from zope.app.traversing import traverse, getPath
+from zope.component import queryAdapter, getService
+from zope.exceptions import NotFoundError
+from zope.xmlpickle.xmlpickle import dumps, loads
+
+seperator = os.sep
+
+def getObjectAdapter(ob):
+    """Returns the object adapter.
+    """
+    syncService = getService(ob, 'FSRegistryService')
+    adapter = syncService.getSynchronizer(ob)
+    return adapter
+
+def getApplicationRoot(dbpath
+                       , siteconfpath):
+    """Returns the application root.
+    """
+    app = Application(dbpath, siteconfpath)
+    root = app()
+    return root
+
+def getObject(objpath
+              , root
+              , prev=None
+              , name=None):
+    """Gets the object from ZODB.
+    """
+    if prev is None:
+        try:
+            ob = traverse(root,objpath)
+            return ob
+        except:
+            return None
+    else:
+        try:
+            ob = traverse(root,objpath)
+            return ob , name, objpath
+        except:
+            return (getObject(os.path.dirname(objpath)
+                              , root
+                              , 'Y'
+                              , os.path.basename(objpath)), name, objpath)[0]
+
+def getNewObject(ob
+                 , folders
+                 , files):
+    """Returns the entire tree of a ZODB object.
+    """
+    adapter = getObjectAdapter(ob)
+    path = ''
+    try:
+        path = str(getPath(ob))
+    except TypeError:
+        pass
+
+    if IObjectFile.isImplementedBy(adapter):
+        files.append(path)
+    else:
+        folders.append(path)
+        for cname, cob in  adapter.contents():
+            getNewObject(cob, folders, files)
+    return folders, files
+
+def getZODBPath(targetfile
+                , key=None):
+    """Returns the physical path of an object in the ZODB
+    of a filesysten representation.
+    """
+    targetfile = os.path.abspath(targetfile)
+    entries_path = os.path.join(os.path.dirname(targetfile)
+                                ,'@@Zope'
+                                ,'Entries.xml')
+    entries = loads(open(entries_path).read())
+    if key is None:
+        objectpath = entries[os.path.basename(targetfile)]['path']
+    else:
+        try:
+            objectpath = entries[os.path.basename(targetfile)][key]
+        except:
+            return None
+    return objectpath
+
+def isNewObject(targetfile):
+    """Determines if the object in the File-system is new.
+    """
+    targetfile = os.path.abspath(targetfile)
+    entries_path = os.path.join(os.path.dirname(targetfile)
+                                ,'@@Zope'
+                                ,'Entries.xml')
+    entries = loads(open(entries_path).read())
+    if entries[os.path.basename(targetfile)].has_key('isNew'):
+        return 1
+    else:
+        return 0
+
+def getObjectData(ob):
+    """Returns the data of a ZODB object.
+    """
+    adapter = adapter = getObjectAdapter(ob)
+    objectdata = adapter.getBody()
+    return objectdata
+
+def getObjectDataTempfile(targetfile
+                          , objpath
+                          , dbpath
+                          , siteconfpath):
+    """Returns the data of a particular object in ZODB.
+    """
+    root = getApplicationRoot(dbpath, siteconfpath)
+    objectpath = getZODBPath(targetfile)
+    ob = getObject(objectpath, root)
+    adapter = adapter = getObjectAdapter(ob)
+    dublincore_adapter = queryAdapter(ob, IZopeDublinCore)
+    modification_date = dublincore_adapter.ModificationDate()
+    object_data = adapter.getBody()
+    temp_file = tempfile.mktemp('tmp')
+    fo = open(temp_file,'w')
+    fo.write(string.strip(object_data))
+    fo.close()
+    return temp_file, objectpath, modification_date
+
+
+def createTempfile(ob
+                   , objectpath):
+    """Creates a temporaty file in the File-system.
+    """
+    objectdata = getObjectData(ob)
+    temp_file = tempfile.mktemp('tmp')
+    fo = open(temp_file,'w')
+    fo.write(string.strip(objectdata))
+    fo.close()
+    return temp_file
+
+def checkFSPath(pathlist):
+    """Checks the file system path.
+    """
+    for path in pathlist:
+        if not os.path.exists(path):
+            err = "Invalid file system path --- "+str(path)
+        elif not os.access(path,2):
+            err = "Permission denied on --- "+str(path)
+        else:
+            err = None
+        if err is not None:
+            return err
+
+def mapFS(mappings
+          , root
+          , objectroot
+          , fsroot):
+    """Returns the new object list in the zopedb which
+    are not available in the File-system.
+    """
+    ob = getObject(objectroot, root)
+    folders, files = getNewObject(ob, [], [])
+    for folder in folders:
+        path = fsroot
+        for part in string.split(folder, '/'):
+            path = os.path.join(path, part)
+        if not os.path.exists(path):
+            location = os.path.dirname(path)
+            ob = getObject(folder, root)
+            ob_name = string.split(folder, '/')[-1]
+            toFS(ob, ob_name, location)
+    for file in files:
+        path = fsroot
+        for part in string.split(file, '/'):
+            path = os.path.join(path, part)
+        if not os.path.exists(path):
+            location = os.path.dirname(path)
+            ob = getObject(file, root)
+            ob_name = string.split(file, '/')[-1]
+            toFS(ob, ob_name, location)
+
+def traverseFS(fspath
+               , mapping_paths):
+    """Traverse through the File-system.
+    """
+    if os.path.isdir(fspath):
+        root=fspath
+        dirlist=os.listdir(root)
+        for item in dirlist:
+            if item!='@@Zope':
+                fspath=os.path.join(root,item)
+                if os.path.isdir(fspath):
+                    traverseFS(fspath, mapping_paths)
+                else:
+                    sandbox_path = fspath
+                    original_path = os.path.join(os.path.dirname(fspath)
+                                                 , '@@Zope'
+                                                 , 'Original'
+                                                 , os.path.basename(fspath))
+                    if os.path.exists(original_path):
+                        zopedb_path = getZODBPath(fspath)
+                        mapping_paths[sandbox_path] = [original_path
+                                                       , zopedb_path]
+    else:
+        sandbox_path = fspath
+        original_path = os.path.join(os.path.dirname(fspath)
+                                     , '@@Zope'
+                                     , 'Original'
+                                     , os.path.basename(fspath))
+        if os.path.exists(original_path):
+            zopedb_path = getZODBPath(fspath)
+            mapping_paths[sandbox_path] = [original_path
+                                           , zopedb_path]
+
+    return mapping_paths
+
+def checkConflictData(sandbox_path
+                      , zopedb_path):
+    """Checks for conflict data in the File-system.
+    """
+    isConflict = 0
+    f = open(sandbox_path,'r')
+    data = f.read()
+    f.close()
+    filter1 = '<<<<<<< %s' % (sandbox_path)
+    filter2 = '>>>>>>> %s' % (zopedb_path)
+    if string.find(data, filter1)<>-1 and string.find(data, filter2)<>-1:
+        isConflict = 1
+    else:
+        isConflict = 0
+
+    return isConflict
+
+
+def makeNewEntry(admin_dir
+                 , name=None
+                 , type=None
+                 , factory=None
+                 , objpath=None
+                 , isNew=None):
+    """Edits the Entries.xml file.
+    """
+    entries = {}
+    entries_path = os.path.join(admin_dir, 'Entries.xml')
+    if os.path.exists(entries_path):
+        entries = loads(open(entries_path).read())
+    if not entries.has_key(name) and name is not None:
+        if isNew:
+            entries[name] = {'type': type
+                             , 'factory': factory
+                             , 'isNew': 'Y'
+                             , 'path': objpath}
+        else:
+            entries[name] = {'type': type
+                             , 'factory': factory
+                             , 'path': objpath}
+    open(entries_path, 'w').write(dumps(entries))
+
+def getFSRoot(fspath
+              , next=None):
+    """Returns the sandbox root.
+    """
+    fspath = os.path.abspath(fspath)
+    if not os.path.exists(os.path.join(fspath,'@@Zope')):
+        return os.path.join(fspath,next)
+    else:
+        return getFSRoot(os.path.dirname(fspath)
+                         , os.path.basename(fspath))
+
+def setPrint(output_string):
+    print output_string


=== Zope3/utilities/fssync/diff.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/diff.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,141 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from common import getObjectDataTempfile, setPrint
+import os, commands, calendar, string
+
+def getdiff(targetfile
+            , objpath
+            , dbpath
+            , siteconfpath
+            , diffoption=None):
+    """Returns the difference between two files
+
+    Gets the diff between :
+        -- Current in Sandbox and Original of last sync
+        -- Current in Sandbox and Current in ZODB
+        -- Current in ZODB and Original of last sync.
+    """
+    temp_file = ''
+    objectpath = ''
+    modification_date = None
+    zodbtargetfile = targetfile
+    if not os.path.isabs(targetfile):
+        targetfile=os.path.join(os.path.abspath(os.curdir)
+                                ,targetfile)
+    if not os.path.exists(targetfile):
+        return "sync [diff aborted] : Target file does not exist --- %s" \
+               % (str(targetfile))
+    if os.path.isdir(targetfile):
+        return "sync [diff aborted] : Target file found to be a directory --- %s" \
+               % (str(targetfile))
+    if not os.path.exists(os.path.join(os.path.abspath(os.path.dirname(targetfile))
+                                       ,'@@Zope')):
+        return 'sync [diff aborted] : @@Zope administrative folder not found'
+
+    if string.find(os.path.basename(targetfile), ' ')<>-1:
+        targetfile = os.path.join(os.path.dirname(targetfile)
+                                  , '\''+os.path.basename(targetfile)+'\'')
+
+    if diffoption == '-1':
+        from_file = os.path.join(os.path.dirname(targetfile)
+                                 ,'@@Zope'
+                                 ,'Original')
+        to_file = targetfile
+    elif diffoption == '-2':
+        temp_file, objectpath, modification_date = getObjectDataTempfile(zodbtargetfile
+                                                                         , objpath
+                                                                         , dbpath
+                                                                         , siteconfpath)
+        from_file = targetfile
+        to_file = temp_file
+    elif diffoption == '-3':
+        temp_file, objectpath, modification_date = getObjectDataTempfile(zodbtargetfile
+                                                                         , objpath
+                                                                         , dbpath
+                                                                         , siteconfpath)
+        from_file = os.path.join(os.path.dirname(targetfile)
+                                 ,'@@Zope'
+                                 ,'Original'
+                                 ,os.path.basename(targetfile))
+        to_file = temp_file
+
+    diff_cmd ="""diff -a -b -B -c %s %s""" \
+               % (from_file,to_file)
+    diff_res = commands.getoutput(diff_cmd)
+    diff_res = setOutput(diff_res
+                         , temp_file
+                         , objectpath
+                         , modification_date)
+    setPrint(diff_res)
+
+    if temp_file:
+        os.remove(temp_file)
+
+    return None
+
+def getDiffDate(strdt):
+    """Returns date in Day Mon DD hh:mm:ss YYYY format.
+    """
+    fmt_date=''
+    if strdt:
+        strdt = str(strdt)
+        weekdays={0:'Mon'
+                  ,1:'Tue'
+                  ,2:'Wed'
+                  ,3:'Thu'
+                  ,4:'Fri'
+                  ,5:'Sat'
+                  ,6:'Sun'}
+        months={1:'Jan'
+                , 2:'Feb'
+                , 3:'Mar'
+                , 4:'Apr'
+                , 5:'May'
+                , 6:'Jun'
+                , 7:'Jul'
+                , 8:'Aug'
+                , 9:'Sep'
+                , 10:'Oct'
+                , 11:'Nov'
+                , 12:'Dec'}
+        date=string.split(string.split(strdt,'T')[0],'-')
+        time=string.split(string.split(strdt,'T')[1],'.')[0]
+        day=weekdays[calendar.weekday(int(date[0])
+                                      ,int(date[1])
+                                      ,int(date[2]))]
+        fmt_date=day+' '+months[int(date[1])]+' '+date[2]+' '+time+' '+date[0]
+
+    return fmt_date
+
+def setOutput(diff_res
+              , temp_file
+              , objectpath
+              , modification_date):
+    """Sets the diff output replacing it with original object
+    path and modification datetime.
+    """
+    changed_line = ''
+    modification_date = getDiffDate(modification_date)
+    if temp_file:
+        for line in string.split(diff_res,'\n'):
+            if string.find(line,temp_file)<>-1:
+                changed_line = line
+                break
+        if changed_line:
+            newline = changed_line[:string.find(changed_line,temp_file)]
+            newline = newline + objectpath+'\t\t'+modification_date
+            diff_res = string.replace(diff_res, changed_line, newline)
+
+    return "\n\n"+diff_res+"\n\n"


=== Zope3/utilities/fssync/sync.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/sync.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import sys, string, getopt, os, commands
+
+# Hack to fix the module search path
+try:
+    import zope.app
+    # All is well
+except ImportError:
+    # Fix the path, assuming this script is <root>/utilities/fssync/sync.py
+    # and the zope module is <root>/src/zope/.
+    _script = sys.argv[0]
+    _scriptdir = os.path.abspath(os.path.dirname(_script))
+    _rootdir = os.path.dirname(os.path.dirname(_scriptdir))
+    _srcdir = os.path.join(_rootdir, "src")
+    sys.path.append(_srcdir)
+
+from diff import getdiff
+from common import checkFSPath, setPrint
+from checkout import checkout
+from commit import commit
+from update import update
+from usage import USAGE
+from add import add, addTypes
+
+def main(argv):
+    short_options = ':f:o:d:s:1:2:3:t:'
+    long_options = ['fspath='
+                   , 'objpath='
+                   , 'dbpath='
+                   , 'siteconfpath=']
+
+    operations = ['commit'
+                 , 'checkout'
+                 , 'update'
+                 , 'diff'
+                 , 'fcommit'
+                 , 'add'
+                 , 'addtypes']
+
+    err = ""
+
+    usage = USAGE % argv[0]
+
+    try:
+        optlist, args = getopt.getopt(sys.argv[1:]
+                                      , short_options
+                                      , long_options)
+
+        env=os.environ
+
+        objpath = ''
+        operation = ''
+        targetfile = ''
+        diffoption = '-1'
+        newobjectname = ''
+        newobjecttype = ''
+
+        if env.has_key('SYNCROOT'): fspath = env['SYNCROOT']
+        else: fspath = '.'
+        if env.has_key('ZODBPATH'): dbpath = env['ZODBPATH']
+        else: dbpath = '../../../Data.fs'
+        if env.has_key('SITECONFPATH'): siteconfpath = env['SITECONFPATH']
+        else: siteconfpath = '../../../site.zcml'
+
+        if len(optlist) > 0  or len(args) > 0:
+            for opt in optlist:
+                if (opt[0] == '-f') or (opt[0] == '--fspath'):
+                    fspath = opt[1]
+                elif (opt[0] == '-o') or (opt[0] == '--objpath'):
+                    objpath = opt[1]
+                elif (opt[0] == '-d') or (opt[0] == '--dbpath'):
+                    dbpath = opt[1]
+                elif (opt[0] == '-s') or (opt[0] == '--siteconfpath'):
+                    siteconfpath = opt[1]
+                elif (opt[0] == '-1' or opt[0] == '-2' or opt[0] == '-3'):
+                    diffoption = opt[0]
+                    targetfile = opt[1]
+                elif opt[0] == '-t':
+                    newobjecttype = opt[1]
+
+            newobjectname = args[1:]
+
+            if len(args) <1:
+                err = "No operation has been specified"
+                raise err
+            elif args[0] != 'add' and len(args) >1:
+                err = "CommandlineError"
+                raise err
+            elif args[0] not in operations:
+                err = "Invalid operation---"+str(args[0])
+                raise err
+            else:
+                operation = args[0]
+
+            fspath, dbpath, siteconfpath = (os.path.abspath(fspath)
+                                            , os.path.abspath(dbpath)
+                                            , os.path.abspath(siteconfpath))
+            path=[fspath, dbpath, siteconfpath]
+            err=checkFSPath(path)
+            if err is not None:
+                raise err
+
+        else:
+            if len(args)>1:
+                if args[1]=='diff':
+                    targetfile = args[0]
+                    operation = args[1]
+                else:
+                    setPrint(usage)
+                    sys.exit(1)
+            else:
+                setPrint(usage)
+                sys.exit(1)
+
+        #Calls the specified operation
+        err = operate(operation
+                      , fspath
+                      , dbpath
+                      , siteconfpath
+                      , objpath
+                      , targetfile
+                      , diffoption
+                      , newobjecttype
+                      , newobjectname)
+        if err is not None:
+            raise err
+
+    except err:
+        setPrint(err)
+        sys.exit(1)
+
+
+
+
+def operate(operation
+            , fspath
+            , dbpath
+            , siteconfpath
+            , objpath
+            , targetfile
+            , diffoption
+            , newobjecttype
+            , newobjectname):
+    """Operates based on the operations passed
+    """
+    err=""
+    if operation == 'checkout':
+        err = checkout(fspath
+                       , dbpath
+                       , siteconfpath
+                       , objpath)
+    elif operation == 'commit':
+        err = commit(fspath
+                     , dbpath
+                     , siteconfpath)
+    elif operation == 'update':
+        err = update(fspath
+                     , dbpath
+                     , siteconfpath)
+    elif operation == 'diff':
+        err = getdiff(targetfile
+                      , objpath
+                      , dbpath
+                      , siteconfpath
+                      , diffoption)
+    elif operation == 'fcommit':
+        err = commit(fspath
+                     , dbpath
+                     , siteconfpath
+                     , 'F')
+    elif operation == 'add':
+        err = add(fspath
+                  , dbpath
+                  , siteconfpath
+                  , newobjecttype
+                  , newobjectname)
+    elif operation == 'addtypes':
+        err = addTypes(dbpath
+                       , siteconfpath)
+
+    return err
+
+
+# If called from the command line
+if __name__=='__main__': main(sys.argv)


=== Zope3/utilities/fssync/update.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/update.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,156 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import string, os, commands
+
+from common import getZODBPath, createTempfile, getObject
+from common import mapFS, traverseFS, checkConflictData, getApplicationRoot
+from common import isNewObject, getFSRoot, setPrint
+
+from zope.app.fssync.syncer import toFS
+
+env = os.environ
+
+def update(fspath
+           , dbpath
+           , siteconfpath):
+    """Updates the checked out objects in the file system from a ZODB
+
+    updates the files in the sandbox based on the file system path given
+    by -f option.
+    """
+    root = getApplicationRoot(dbpath, siteconfpath)
+    if env.has_key('SYNCROOT'):
+        if os.path.abspath(fspath) == os.path.abspath(env['SYNCROOT']):
+            if os.path.isdir(os.path.abspath(fspath)):
+                module_list = os.listdir(os.path.abspath(fspath))
+                if '@@Zope' in module_list:
+                    module_list.remove('@@Zope')
+                    for module in module_list:
+                        fspath = os.path.join(fspath, module)
+                        updateSettings(fspath, root)
+                else:
+                    return 'sync [update aborted] : @@Zope administrative folder not found in %s' \
+                           %(fspath)
+        else:
+            updateSettings(fspath, root)
+    else:
+        updateSettings(fspath, root)
+
+def updateSettings(fspath, root):
+    """does the settings for update
+    """
+    fspath = os.path.abspath(fspath)
+    if os.path.isdir(fspath):
+        admin_dir = os.path.join(fspath,'@@Zope')
+    else:
+        admin_dir = os.path.join(os.path.dirname(fspath),'@@Zope')
+    if not os.path.exists(admin_dir):
+        return 'sync [update aborted] : @@Zope administrative folder not found in %s'\
+               %(fspath)
+
+    mappings = {}
+    mapping_paths = {}
+    mapping_paths.update(traverseFS(fspath, mapping_paths))
+
+    for sandbox_path in mapping_paths.keys():
+        original_path = string.strip(mapping_paths[sandbox_path][0])
+        zopedb_path = string.strip(mapping_paths[sandbox_path][1])
+        if checkConflictData(sandbox_path, zopedb_path):
+            setPrint('C %s'%(zopedb_path[1:]))
+        else:
+            if not isNewObject(sandbox_path):
+                mappings[zopedb_path] = sandbox_path
+
+                fmt_sandbox_path = ''
+                fmt_original_path = ''
+                for dir in string.split(sandbox_path,os.sep):
+                    if string.find(dir, ' ')<>-1:
+                        fmt_sandbox_path = os.path.join(fmt_sandbox_path, '\''+dir+'\'')
+                    else:
+                        fmt_sandbox_path = os.path.join(fmt_sandbox_path, dir)
+
+                for dir in string.split(original_path,os.sep):
+                    if string.find(dir, ' ')<>-1:
+                        fmt_original_path = os.path.join(fmt_original_path, '\''+dir+'\'')
+                    else:
+                        fmt_original_path = os.path.join(fmt_original_path, dir)
+                fmt_sandbox_path = os.sep + fmt_sandbox_path
+                fmt_original_path = os.sep + fmt_original_path
+
+                ob = getObject(zopedb_path, root)
+                zopedb_temp_file = createTempfile(ob, zopedb_path)
+                diff3_cmd = """diff3 -a %s %s %s""" %(fmt_sandbox_path
+                                                      , fmt_original_path
+                                                      , zopedb_temp_file)
+                diff3_res = commands.getoutput(diff3_cmd)
+                if len(string.strip(diff3_res))>1:
+                    diffverify=string.strip(diff3_res[0:5])
+                    if diffverify=='====1':
+                        setPrint('M %s'%(zopedb_path[1:]))
+                    elif diffverify=='====2':
+                        doUpdate('C', ob, zopedb_path, sandbox_path)
+                        setPrint('M %s'%(zopedb_path[1:]))
+                    elif diffverify=='====3':
+                        doUpdate('U', ob, zopedb_path, sandbox_path)
+                    elif diffverify=='====':
+                        diff3_cmd = """diff3 -a -m %s %s %s;echo $?""" %(fmt_sandbox_path
+                                                                         , fmt_original_path
+                                                                         , zopedb_temp_file)
+                        diff3_res = commands.getoutput(diff3_cmd)
+                        diff3_res = string.replace(diff3_res
+                                                   , zopedb_temp_file
+                                                   , zopedb_path)
+                        if diff3_res[-1]=='0':
+                            setPrint('Merging changes in %s' \
+                                     %(zopedb_path[1:]))
+                        else:
+                            setPrint('C Merging changes in %s' \
+                                     %(zopedb_path[1:]))
+
+                        f = open(sandbox_path, 'w')
+                        f.write(string.strip(diff3_res[:-1]))
+                        f.close()
+                        doUpdate('C'
+                                 , ob
+                                 , zopedb_path
+                                 , sandbox_path)
+
+                if os.path.exists(zopedb_temp_file):
+                    os.remove(zopedb_temp_file)
+
+    if os.path.isdir(fspath):
+        objectroot = getZODBPath(fspath)
+        fsroot = getFSRoot(fspath)
+        mapFS(mappings
+              , root
+              , objectroot
+              , fsroot)
+
+
+
+def doUpdate(mode
+             , ob
+             , zopedb_path
+             , sandbox_path):
+    """Updates data
+    """
+    sandbox_path = os.path.dirname(sandbox_path)
+    ob_name = string.split(zopedb_path,'/')[-1]
+    if mode=='U':
+        if ob is not None:
+            toFS(ob, ob_name, sandbox_path)
+    elif mode=='C':
+        if ob is not None:
+            toFS(ob, ob_name, sandbox_path, mode)


=== Zope3/utilities/fssync/usage.py 1.1 => 1.2 ===
--- /dev/null	Mon May  5 14:01:04 2003
+++ Zope3/utilities/fssync/usage.py	Mon May  5 14:01:03 2003
@@ -0,0 +1,231 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+USAGE="""
+
+Usage: %s [options] operation
+
+The available options are:
+
+-f / --fspath=
+Set the file system path where the object is to be dumped.
+Is used with all the operation.
+
+-o / --objpath=
+Looks up for the Object in the specified path in the ZODB.
+Is used with checkout operation.
+
+-d / --dbpath=
+The path of ZODB.
+Is used with all the operation.
+
+-s / --siteconfpath=
+The path for site.zcml.
+Is used with all the operation.
+
+-t / --type=
+The type of object to be added to the file system.
+Is used with add operation.
+
+OPERATION
+----------------------------------------------------------------------------
+checkout --- checks out ZODB object in File-system
+             example:
+                $python sync.py -f /home/user/sandbox
+                                -d /zope3/data.fs
+                                -s /zope3/site.zcml
+                                -o /foo/bar
+                                checkout
+                  'or'
+
+                $python sync.py --fspath=/home/user/sandbox
+                                   --dbpath=/zope3/data.fs
+                                   --siteconfpath=/zope3/site.zcml
+                                   --objpath=/foo/bar
+                                   checkout
+
+                This will download the "bar" folder along with it's contents
+                into the /home/user/sandbox folder. In case if the "bar" module
+                already exist in the sandbox it will be overwritten.
+                Checkout generates the following output:
+                UPDATING foldername
+                U foldername/filename
+
+
+update   --- updates the sandbox
+             example:
+                $python sync.py -f /home/user/sandbox/bar
+                                -d /zope3/data.fs
+                                -s /zope3/site.zcml
+                                update
+                  'or'
+
+                $python sync.py --fspath=/home/user/sandbox/bar
+                                --dbpath=/zope3/data.fs
+                                --siteconfpath=/zope3/site.zcml
+                                update
+
+                This will update the contents of "bar" directory in
+                the sandbox.
+
+                An update can undergo various cases like :
+
+                Case1 : When the contents of all the three Sandbox, Original
+                        and ZODB for an object is same an update command won't
+                        do any changes.
+
+                Case2 : When the contents of the Sandbox and Original are same
+                        but ZODB is different, an update command will overwrite
+                        Sandbox and Original from ZODB and print the following:
+                        U /path/filename.
+
+                Case3 : When the contents of the Original and ZODB are same and
+                        the Sandbox is different an update command won't do any
+                        changes and print the following:
+                        M /path/filename.
+                        If the Sandbox contains conflict data the following is
+                        printed:
+                        C /path/filename.
+
+                Case4 : This is a very unlikely case. When the contents of the
+                        Sandbox and ZODB are same but the Original is different
+                        an update command will overwrite the Original with the
+                        ZODB and print the following:
+                        U /path/filename.
+
+                Case5 : When the contents of all the three Sandbox, Original
+                        and ZODB are different, an update command will mearge
+                        all the changes into the Sandbox and the Original is
+                        overwitten by the ZODB and the following is printed:
+                        Merging changes in /path/filename
+                        In case of a conflict the conflict data is copied into
+                        the Sandbox and the Original is overwitten by the ZODB
+                        and the following is printed:
+                        C Merging changes in /path/filename
+
+                Conventionaly an update has to be done on the sandbox before
+                running commit.
+
+commit   --- A commit command copies data from the File-system samdbox
+             into the ZODB
+             example:
+                $python sync.py -f /home/user/sandbox/bar
+                                -d /zope3/data.fs
+                                -s /zope3/site.zcml
+                                commit
+                  'or'
+
+                $python sync.py --fspath=/home/user/sandbox/bar
+                                --dbpath=/zope3/data.fs
+                                --siteconfpath=/zope3/site.zcml
+                                commit
+
+             Commit copies the Sandbox into Original and ZODB, if the ZODB
+             and Original are same or there is no conflict data in the Sandbox
+             and prints the following:
+             /path/filename  <-- filename
+             If the ZODB and Original are not same or the Sandbox
+             contains conflict data a commit command won't do anything
+             and will print the following:
+             /path/filename Conflict, Uptodate checkin failed.
+
+
+fcommit  --- This is a force commit. A fcommit command will forcefully
+             copy Sandbox
+             into Original and ZODB regardless of any constraints.
+             example:
+                $python sync.py -f /home/user/sandbox/bar
+                                -d /zope3/data.fs
+                                -s /zope3/site.zcml
+                                fcommit
+                  'or'
+
+                $python sync.py --fspath=/home/user/sandbox/bar
+                                --dbpath=/zope3/data.fs
+                                --siteconfpath=/zope3/site.zcml
+                                fcommit
+
+
+diff     --- Difference between Three versions of an object
+
+            -1 -- Sandbox and Original
+            -2 -- Sandbox and ZODB
+            -3 -- ZODB and Original
+
+            A diff command will produce the difference of two objects
+            in context output format.
+            example:
+                $python sync.py -2 /home/user/sandbox/bar
+                                -d /zope3/data.fs
+                                -s /zope3/site.zcml
+                                diff
+                  'or'
+
+                $python sync.py -2 /home/user/sandbox/bar
+                                --dbpath=/zope3/data.fs
+                                --siteconfpath=/zope3/site.zcml
+                                diff
+            Default option is -1
+
+
+addtypes --- Displays all the list of types that can be added to the ZODB
+                 from the filesystem.
+                 example:
+                 $python sync.py addtypes
+
+
+add      --- Adds objects to file system and saves it to the ZODB on
+             commit.
+             This command will give a list of all the available types
+             that can be added.
+             example:
+                 $python sync.py -f /home/user/sandbox/bar
+                                 -d /zope3/data.fs
+                                 -s /zope3/site.zcml
+                                 -t file
+                                 add file1.html file2.txt file3.xyz
+                    'or'
+
+                $python sync.py --fspath=/home/user/sandbox/bar
+                                --dbpath=/zope3/data.fs
+                                --siteconfpath=/zope3/site.zcml
+                                --type=file
+                                add file1.html file2.txt file3.xyz
+
+            This command will add file1.html, file2.txt, file3.xyz in
+            the bar folder of the sandbox and on commit this will be
+            checked in as file type objects in ZODB.
+            If type is not specified with -t option then the types will
+            be checked based on file extensions and only the valid type
+            will be added to the sandbox.
+            File/Folder names with spaces has to be enclosed withing quotes.
+
+
+ENVIRONMENT VARIABLES
+----------------------------------------------------------------------------
+
+SYNCROOT     --- Path for the File-system folder where the ZODB object
+                 has to be checked out.If not set it takes the default
+                 directory. Or can be specified with the --fspath or -f
+                 option
+
+ZODBPATH     --- Path where the Data.fs file exist in the File-system.
+                 if not set it takes the default is ../../Data.fs.
+                 Or can be specified with the --dbpath or -d option.
+
+SITECONFPATH --- Path for the site.zcml file.if not set it takes the
+                 default is ../../site.zcml. Or can be specified with
+                 the --siteconfpath or -s option.
+
+"""