Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Hugo Ricateau
erp5
Commits
86ea1af6
Commit
86ea1af6
authored
Nov 24, 2017
by
Ayush Tiwari
Committed by
Ayush Tiwari
Apr 17, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
CommitTool: Intoduction of CommitTool, BusinessCommit and BusinessSnapshot classes
parent
d49d0c52
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
453 additions
and
7 deletions
+453
-7
product/ERP5/Document/BusinessCommit.py
product/ERP5/Document/BusinessCommit.py
+162
-0
product/ERP5/Document/BusinessManager.py
product/ERP5/Document/BusinessManager.py
+11
-4
product/ERP5/Document/BusinessSnapshot.py
product/ERP5/Document/BusinessSnapshot.py
+221
-0
product/ERP5/Tool/CommitTool.py
product/ERP5/Tool/CommitTool.py
+56
-1
product/ERP5/__init__.py
product/ERP5/__init__.py
+3
-2
No files found.
product/ERP5/Document/BusinessCommit.py
0 → 100644
View file @
86ea1af6
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2017 Nexedi SARL and Contributors. All Rights Reserved.
# Ayush-Tiwari <ayush.tiwari@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.
#
##############################################################################
import
gc
import
os
import
posixpath
import
transaction
import
imghdr
import
tarfile
import
time
import
hashlib
import
fnmatch
import
re
import
threading
import
pprint
import
uuid
from
copy
import
deepcopy
from
collections
import
defaultdict
from
cStringIO
import
StringIO
from
OFS.Image
import
Pdata
from
lxml.etree
import
parse
from
urllib
import
quote
,
unquote
from
OFS
import
SimpleItem
,
XMLExportImport
from
datetime
import
datetime
from
itertools
import
chain
from
operator
import
attrgetter
from
persistent.list
import
PersistentList
from
AccessControl
import
ClassSecurityInfo
,
Unauthorized
,
getSecurityManager
from
Acquisition
import
Implicit
,
aq_base
,
aq_inner
,
aq_parent
from
zLOG
import
LOG
,
INFO
,
WARNING
from
Products.ERP5Type.XMLObject
import
XMLObject
from
Products.ERP5Type.Core.Folder
import
Folder
from
Products.CMFCore.utils
import
getToolByName
from
Products.PythonScripts.PythonScript
import
PythonScript
from
Products.ERP5Type.dynamic.lazy_class
import
ERP5BaseBroken
from
Products.ERP5Type.Globals
import
Persistent
,
PersistentMapping
from
Products.ERP5Type
import
Permissions
,
PropertySheet
,
interfaces
from
Products.ERP5Type.Globals
import
InitializeClass
from
Products.ERP5Type.TransactionalVariable
import
getTransactionalVariable
from
Products.ERP5Type.patches.ppml
import
importXML
from
Products.ERP5Type.Accessor.Constant
import
PropertyGetter
as
ConstantGetter
class
BusinessCommit
(
Folder
):
meta_type
=
'ERP5 Business Commit'
portal_type
=
'Business Commit'
add_permission
=
Permissions
.
AddPortalContent
allowed_types
=
(
'Business Item'
,
'Business Property Item'
,
'Business Patch item'
,)
template_format_version
=
3
# Factory Type Information
factory_type_information
=
\
{
'id'
:
portal_type
,
'meta_type'
:
meta_type
,
'icon'
:
'file_icon.gif'
,
'product'
:
'ERP5Type'
,
'factory'
:
''
,
'type_class'
:
'BusinessCommit'
,
'immediate_view'
:
'BusinessCommit_view'
,
'allow_discussion'
:
1
,
'allowed_content_types'
:
(
'Business Item'
,
'Business Property Item'
,
'Business Patch Item'
,
)
,
'filter_content_types'
:
1
}
# Declarative security
security
=
ClassSecurityInfo
()
security
.
declareObjectProtected
(
Permissions
.
AccessContentsInformation
)
# Declarative properties
property_sheets
=
(
PropertySheet
.
Base
,
PropertySheet
.
XMLObject
,
PropertySheet
.
SimpleItem
,
PropertySheet
.
CategoryCore
,
PropertySheet
.
Version
,
)
security
.
declarePublic
(
'newContent'
)
def
newContent
(
self
,
id
=
None
,
**
kw
):
"""
Override newContent so as to use 'id' generated like hash.
Also, copy the objects in the Business Commit after creating new object
"""
if
id
is
None
:
id
=
uuid
.
uuid1
()
return
super
(
BusinessCommit
,
self
).
newContent
(
id
,
**
kw
)
def
createEquivalentSnapshot
(
self
):
"""
This function uses the current commit to create a new snapshot
"""
portal_commit
=
self
.
aq_parent
# Create empty snapshot
snapshot
=
portal_commit
.
newContent
(
portal_type
=
'Business Snapshot'
)
# Add the current commit as predecessor. This way we can have the BI
# BPI in that commit to the Business Snapshot also.
snapshot
.
setSimilarValue
(
self
)
self
.
setSimilarValue
(
snapshot
)
# Build the snapshot
snapshot
.
buildSnapshot
()
return
snapshot
def
install
(
self
):
"""
Installation:
- check if there is already an equivalent snapshot
- if not, create one and install it
"""
successor_list
=
self
.
getPredecessorRelatedValueList
()
# Check if the successor list has a snapshot in it
try
:
eqv_snapshot
=
[
l
for
l
in
successor_list
if
l
.
getPortalType
()
==
'Business Snapshot'
][
0
]
except
IndexError
:
# Create a new equivalent snapshot
eqv_snapshot
=
self
.
createEquivalentSnapshot
()
for
item
in
eqv_snapshot
.
objectValues
():
item
.
install
(
self
)
def
getItemPathList
(
self
):
return
[
l
.
getProperty
(
'item_path'
)
for
l
in
self
.
objectValues
()]
product/ERP5/Document/BusinessManager.py
View file @
86ea1af6
...
...
@@ -719,10 +719,17 @@ class BusinessItem(XMLObject):
"""
Overriden function so that we can update attributes for BusinessItem objects
"""
return
super
(
BusinessItem
,
self
).
_edit
(
item_path
=
item_path
,
item_sign
=
item_sign
,
item_layer
=
item_layer
,
**
kw
)
super
(
BusinessItem
,
self
).
_edit
(
item_path
=
item_path
,
item_sign
=
item_sign
,
item_layer
=
item_layer
,
**
kw
)
# Build the object here, if the item_path has been added/updated
# XXX: We also need to add attribute to ensure that this doesn't happen
# while in tests or while creating them on the fly
if
'item_path'
in
self
.
_v_modified_property_dict
:
self
.
build
(
self
.
aq_parent
)
def
build
(
self
,
context
,
**
kw
):
"""
...
...
product/ERP5/Document/BusinessSnapshot.py
0 → 100644
View file @
86ea1af6
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2017 Nexedi SARL and Contributors. All Rights Reserved.
# Ayush-Tiwari <ayush.tiwari@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.
#
##############################################################################
import
gc
import
os
import
posixpath
import
transaction
import
imghdr
import
tarfile
import
time
import
hashlib
import
fnmatch
import
re
import
threading
import
pprint
from
copy
import
deepcopy
from
collections
import
defaultdict
from
cStringIO
import
StringIO
from
OFS.Image
import
Pdata
from
lxml.etree
import
parse
from
urllib
import
quote
,
unquote
from
OFS
import
SimpleItem
,
XMLExportImport
from
datetime
import
datetime
from
itertools
import
chain
from
operator
import
attrgetter
from
persistent.list
import
PersistentList
from
AccessControl
import
ClassSecurityInfo
,
Unauthorized
,
getSecurityManager
from
Acquisition
import
Implicit
,
aq_base
,
aq_inner
,
aq_parent
from
zLOG
import
LOG
,
INFO
,
WARNING
from
Products.ERP5Type.XMLObject
import
XMLObject
from
Products.ERP5Type.Core.Folder
import
Folder
from
Products.CMFCore.utils
import
getToolByName
from
Products.PythonScripts.PythonScript
import
PythonScript
from
Products.ERP5Type.dynamic.lazy_class
import
ERP5BaseBroken
from
Products.ERP5Type.Globals
import
Persistent
,
PersistentMapping
from
Products.ERP5Type
import
Permissions
,
PropertySheet
,
interfaces
from
Products.ERP5Type.Globals
import
InitializeClass
from
Products.ERP5Type.TransactionalVariable
import
getTransactionalVariable
from
Products.ERP5Type.patches.ppml
import
importXML
from
Products.ERP5Type.Accessor.Constant
import
PropertyGetter
as
ConstantGetter
class
BusinessSnapshot
(
Folder
):
meta_type
=
'ERP5 Business Snashot'
portal_type
=
'Business Snapshot'
add_permission
=
Permissions
.
AddPortalContent
allowed_types
=
(
'Business Item'
,
'Business Property Item'
,
'Business Patch item'
,)
# Declarative security
security
=
ClassSecurityInfo
()
security
.
declareObjectProtected
(
Permissions
.
AccessContentsInformation
)
template_format_version
=
3
# Factory Type Information
factory_type_information
=
\
{
'id'
:
portal_type
,
'meta_type'
:
meta_type
,
'icon'
:
'file_icon.gif'
,
'product'
:
'ERP5Type'
,
'factory'
:
''
,
'type_class'
:
'BusinessSnapshot'
,
'immediate_view'
:
'BusinessSnapshot_view'
,
'allow_discussion'
:
1
,
'allowed_content_types'
:
(
'Business Item'
,
'Business Property Item'
,
'Business Patch Item'
,
)
,
'filter_content_types'
:
1
}
# Declarative security
security
=
ClassSecurityInfo
()
security
.
declareObjectProtected
(
Permissions
.
AccessContentsInformation
)
# Declarative properties
property_sheets
=
(
PropertySheet
.
Base
,
PropertySheet
.
XMLObject
,
PropertySheet
.
SimpleItem
,
PropertySheet
.
CategoryCore
,
PropertySheet
.
Version
,
)
def
getLastSnapshot
(
self
):
portal
=
self
.
getPortalObject
()
commit_tool
=
portal
.
portal_commits
# Get the snapshot list except the current snapshot
snapshot_list
=
[
l
for
l
in
commit_tool
.
objectValues
(
portal_type
=
'Business Snapshot'
)
if
l
!=
self
]
if
snapshot_list
:
# Get the last created/installed snapshot comparing creation_date
return
max
(
snapshot_list
,
key
=
(
lambda
x
:
x
.
getCreationDate
()))
return
None
def
getItemList
(
self
):
"""
Returns the collection of all Business Item, Business Property Item and
Business Patch item at the given snapshot.
"""
return
self
.
objectValues
()
def
getItemPathList
(
self
):
"""
Returns the path of all Business Item, Business Property Item and
Business Patch item at the given snapshot.
"""
return
[
l
.
getProperty
(
'item_path'
)
for
l
in
self
.
getItemList
()]
def
buildSnapshot
(
self
):
"""
Using equivalent commit, create a snapshot of ZODB state
"""
new_item_list
=
[]
new_item_path_list
=
[]
# Get the equivalent commit for the snapshot
eqv_commit
=
self
.
getSimilarValue
()
# Get last created snapshot
last_snapshot
=
self
.
getLastSnapshot
()
# Commit list of all commits between the last snapshot/first commit and the
# current snapshot
successor_commit_list
=
[]
# If there is last snapshot, then combine all the commit afterwards to create
# new snapshot
if
last_snapshot
:
# [1]: Extend the item_list with list of items from last snapshot
new_item_list
.
extend
(
last_snapshot
.
getItemList
())
new_item_path_list
.
extend
(
last_snapshot
.
getItemPathList
())
# Get next predecessor commit for this snapshot using the equivalent commit
# Notice that we don't use the snapshot to get the next commit as the
# snapshot is mere a state which uses `predecessor` just for mentioning the
# equivalent commit.
# Here the first next commit should be the commit created after last snapshot
# which we can get using the equivalent commit of last snapshot and then
# finding the next commit for it
next_commit
=
last_snapshot
.
getSimilarValue
().
getPredecessorRelatedValue
()
# If there is no last snapshot, create a new one by combining all the commits
else
:
# Get the oldest commit and start from there to find the next commit
oldest_commit
=
min
(
self
.
aq_parent
.
objectValues
(
portal_type
=
'Business Commit'
),
key
=
(
lambda
x
:
x
.
getCreationDate
()))
new_item_list
.
extend
(
oldest_commit
.
objectValues
())
new_item_path_list
.
extend
(
oldest_commit
.
getItemPathList
())
next_commit
=
oldest_commit
.
getPredecessorRelatedValue
()
# Fill sucessor commit list
while
(
next_commit
.
getId
()
!=
eqv_commit
.
getId
()):
successor_commit_list
.
append
(
next_commit
)
next_commit
=
next_commit
.
getPredecessorRelatedValue
()
# Append the equivalent commit to successor commits
successor_commit_list
.
append
(
eqv_commit
)
for
commit
in
successor_commit_list
:
for
item
in
commit
.
objectValues
():
item_path
=
item
.
getProperty
(
'item_path'
)
if
item_path
in
new_item_path_list
:
# Replace the old item with same path with new item
new_item_list
=
[
l
if
l
.
getProperty
(
'item_path'
)
!=
item_path
else
item
for
l
in
new_item_list
]
else
:
# Add the item to list if there is no existing item at that path
new_item_list
.
append
(
item
)
new_item_path_list
.
append
(
item_path
)
# Create hardlinks for the objects
for
item
in
new_item_list
:
self
.
_setObject
(
item
.
id
,
item
,
suppress_events
=
True
)
def
install
(
self
):
"""
Install the sub-objects in the commit
"""
for
item
in
self
.
objectValues
():
item
.
install
(
self
)
product/ERP5/Tool/CommitTool.py
View file @
86ea1af6
...
...
@@ -31,11 +31,13 @@ from webdav.client import Resource
from
App.config
import
getConfiguration
import
os
import
time
import
shutil
import
sys
import
hashlib
import
pprint
import
transaction
import
uuid
from
Acquisition
import
Implicit
,
Explicit
from
AccessControl
import
ClassSecurityInfo
...
...
@@ -131,6 +133,26 @@ class CommitTool (BaseTool):
- portal_commits/387897938794876-9 (Snapshort of erp5_trade)
- portal_commits/387897938794876-10 (Snapshot of erp5_base)
Draft -> Commited -> Pushed (to repo) |Commit]
Draft -> Installed <-> Uninstalled |Snapshot]
Developer mode: make commits and push them (nothing else)
Developer mode: make snapshots and push them (nothing else)
Installation:
- create an empty snapshot that that's similar to a Commit
- fill it with hard links to commits and snapshots
- install it
Only Draft can be modified
3 types
- Commit - partial state (pushed)
- Save Point - complete state with copies of a single bt (only for
optimisation) (really needed ?) (pushed)
- Snapshort - complete state with hard link for all bt (installed)
We should try first with Commit and Snapshot
"""
id
=
'portal_commits'
title
=
'Commit Tool'
...
...
@@ -148,6 +170,39 @@ class CommitTool (BaseTool):
security
=
ClassSecurityInfo
()
security
.
declareProtected
(
Permissions
.
ManagePortal
,
'manage_overview'
)
manage_overview
=
DTMLFile
(
'explainCommitTool'
,
_dtmldir
)
#manage_overview = DTMLFile('explainCommitTool', _dtmldir)
def
getCommitList
(
self
):
return
self
.
objectValues
(
portal_type
=
'Business Commit'
)
def
getSnapshotList
(
self
):
return
self
.
objectValues
(
portal_type
=
'Business Snapshot'
)
security
.
declarePublic
(
'newContent'
)
def
newContent
(
self
,
id
=
None
,
**
kw
):
"""
Override newContent so as to use 'id' generated like hash
"""
if
id
is
None
:
id
=
uuid
.
uuid1
()
new_obj
=
super
(
CommitTool
,
self
).
newContent
(
id
,
**
kw
)
# Add the last commit as its predecessor
commit_list
=
[
l
for
l
in
self
.
objectValues
(
portal_type
=
'Business Commit'
)
if
l
!=
new_obj
]
latest_commit
=
max
(
commit_list
,
key
=
(
lambda
x
:
x
.
getCreationDate
()))
if
new_obj
.
getPortalType
()
==
'Business Commit'
:
# TODO: Add check for no latest_commit. Usable especially for 1st BM
new_obj
.
setPredecessorValue
(
latest_commit
)
else
:
# If the new_obj is Business Snapshot, create a similar value for the
# latest commit
new_obj
.
setSimilarValue
(
latest_commit
)
latest_commit
.
setSimilarValue
(
new_obj
)
return
new_obj
InitializeClass
(
CommitTool
)
product/ERP5/__init__.py
View file @
86ea1af6
...
...
@@ -52,7 +52,7 @@ from Tool import CategoryTool, SimulationTool, RuleTool, IdTool, TemplateTool,\
AcknowledgementTool
,
SolverTool
,
SolverProcessTool
,
\
ConversionTool
,
RoundingTool
,
UrlRegistryTool
,
InterfaceTool
,
\
CertificateAuthorityTool
,
InotifyTool
,
TaskDistributionTool
,
\
DiffTool
DiffTool
,
CommitTool
import
ERP5Site
from
Document
import
PythonScript
,
BusinessManager
object_classes
=
(
ERP5Site
.
ERP5Site
,
...
...
@@ -88,7 +88,8 @@ portal_tools = ( CategoryTool.CategoryTool,
InotifyTool
.
InotifyTool
,
TaskDistributionTool
.
TaskDistributionTool
,
InterfaceTool
.
InterfaceTool
,
DiffTool
.
DiffTool
DiffTool
.
DiffTool
,
CommitTool
.
CommitTool
,
)
content_classes
=
()
content_constructors
=
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment