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
alecs_myu
erp5
Commits
8d08790c
Commit
8d08790c
authored
Apr 11, 2017
by
Ayush Tiwari
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bt5_config: Save BM as zexp rather than a folder
parent
0d067945
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
32 additions
and
385 deletions
+32
-385
product/ERP5/Document/BusinessManager.py
product/ERP5/Document/BusinessManager.py
+25
-384
product/ERP5/Tool/TemplateTool.py
product/ERP5/Tool/TemplateTool.py
+7
-1
No files found.
product/ERP5/Document/BusinessManager.py
View file @
8d08790c
...
...
@@ -246,76 +246,39 @@ class BusinessManager(XMLObject):
"""
if
not
self
.
getStatus
()
==
'built'
:
raise
ValueError
,
'Manager not built properly'
return
self
.
_export
(
path
,
local
,
bma
,
**
kw
)
f
=
StringIO
()
self
.
_p_jar
.
exportFile
(
self
.
_p_oid
,
f
)
def
_export
(
self
,
path
=
None
,
local
=
0
,
bma
=
None
,
**
kw
):
# XXX: Improve naming
name
=
self
.
getTitle
()
name
=
posixpath
.
join
(
path
,
name
)
# XXX required due to overuse of os.path
name
=
name
.
replace
(
'
\
\
'
,
'/'
).
replace
(
':'
,
'/'
)
name
=
quote
(
name
+
'.zexp'
)
obj_path
=
name
.
replace
(
'/'
,
os
.
sep
)
if
bma
is
None
:
if
local
:
# we export into a folder tree
bma
=
BusinessManagerFolder
(
path
,
creation
=
1
)
else
:
# We export bm into a tarball file
if
path
is
None
:
path
=
self
.
getTitle
()
bma
=
BusinessManagerTarball
(
path
,
creation
=
1
)
# export bt
for
prop
in
self
.
propertyMap
():
prop_type
=
prop
[
'type'
]
id
=
prop
[
'id'
]
if
id
in
(
'id'
,
'uid'
,
'rid'
,
'sid'
,
'id_group'
,
'last_id'
,
'revision'
,
'install_object_list_list'
,
'id_generator'
,
'bm_for_diff'
):
continue
value
=
self
.
getProperty
(
id
)
if
not
value
:
continue
if
prop_type
in
(
'text'
,
'string'
,
'int'
,
'boolean'
):
bma
.
addObject
(
str
(
value
),
name
=
id
,
path
=
'bm'
,
ext
=
''
)
elif
prop_type
in
(
'lines'
,
'tokens'
):
bma
.
addObject
(
'
\
n
'
.
join
(
value
),
name
=
id
,
path
=
'bm'
,
ext
=
''
)
# Export each part
for
item
in
self
.
_path_item_list
:
item
.
export
(
context
=
self
,
bma
=
bma
,
**
kw
)
f
.
seek
(
0
)
obj
=
f
.
read
()
return
bma
.
finishCreation
()
object_path
=
os
.
path
.
join
(
path
,
obj_path
)
path
=
os
.
path
.
dirname
(
object_path
)
os
.
path
.
exists
(
path
)
or
os
.
makedirs
(
path
)
f
=
open
(
object_path
,
'wb'
)
try
:
f
.
write
(
obj
)
finally
:
f
.
close
()
security
.
declareProtected
(
Permissions
.
ManagePortal
,
'importFile'
)
def
importFile
(
self
,
path
):
"""
Import
all xml files in Business Manager
Import
Business Manager object and all attribute to current BM itself
"""
bma
=
(
BusinessManagerFolder
if
os
.
path
.
isdir
(
path
)
else
BusinessManagerTarball
)(
path
,
importing
=
1
)
bm_item
=
bm
()
bma
.
importFiles
(
bm_item
,
parent
=
self
)
prop_dict
=
{}
for
prop
in
self
.
propertyMap
():
pid
=
prop
[
'id'
]
if
pid
!=
'id'
:
prop_type
=
prop
[
'type'
]
value
=
bm_item
.
get
(
pid
)
if
prop_type
in
(
'text'
,
'string'
):
prop_dict
[
pid
]
=
value
or
''
elif
prop_type
in
(
'int'
,
'boolean'
):
prop_dict
[
pid
]
=
value
or
0
elif
prop_type
in
(
'lines'
,
'tokens'
):
# XXX: Do add pid[:-5] after we switch to proper getters and setters
prop_dict
[
pid
]
=
(
value
or
''
).
splitlines
()
# XXX: This is not working, needs to be fixed so as it copies all the
# properties from BMA to the newly created Business Manager
self
.
_edit
(
**
prop_dict
)
self
.
storeTemplateData
()
#workflow_tool = self.getPortalObject().portal_workflow
#workflow_tool.business_package_building_workflow.notifyWorkflowMethod(
# self, 'edit', kw={'comment': 'Downloaded'})
for
item_object
in
self
.
_path_item_list
:
item_object
.
importFile
(
bma
,
parent
=
self
)
# Set the status to uninstalled
self
.
setStatus
(
'uninstalled'
)
connection
=
self
.
aq_parent
.
_p_jar
file
=
open
(
path
,
'rb'
)
obj
=
connection
.
importFile
(
file
)
self
.
_path_item_list
=
obj
.
_path_item_list
self
.
_setTemplatePathList
(
obj
.
getTemplatePathList
())
def
__add__
(
self
,
other
):
"""
...
...
@@ -1078,190 +1041,6 @@ class BusinessItem(Implicit, Persistent):
obj
.
deletePdfContent
()
return
obj
def
export
(
self
,
context
,
bma
,
**
kw
):
"""
Export the business item object : fill the BusinessManagerArchive with
objects exported as XML, hierarchicaly organised.
"""
if
not
self
.
_value
:
return
path
=
self
.
__class__
.
__name__
+
'/'
# We now will add the XML object and its sha hash while exporting the object
# to Business Manager itself
# Back compatibility with filesystem Documents
key
=
self
.
_path
obj
=
self
.
_value
if
isinstance
(
obj
,
str
):
if
not
key
.
startswith
(
path
):
key
=
path
+
key
bma
.
addObject
(
obj
,
name
=
key
,
ext
=
'.py'
)
else
:
try
:
extension
,
unicode_data
,
record_id
=
\
SEPARATELY_EXPORTED_PROPERTY_DICT
[
obj
.
__class__
.
__name__
]
except
KeyError
:
pass
else
:
while
1
:
# not a loop
obj
=
obj
.
_getCopy
(
context
)
data
=
getattr
(
aq_base
(
obj
),
record_id
,
None
)
if
unicode_data
:
if
type
(
data
)
is
not
unicode
:
break
try
:
data
=
data
.
encode
(
aq_base
(
obj
).
output_encoding
)
except
(
AttributeError
,
UnicodeEncodeError
):
break
elif
type
(
data
)
is
not
bytes
:
if
not
isinstance
(
data
,
Pdata
):
break
data
=
bytes
(
data
)
try
:
# Delete this attribute from the object.
# in case the related Portal Type does not exist, the object may be broken.
# So we cannot delattr, but we can delete the key of its its broken state
if
isinstance
(
obj
,
ERP5BaseBroken
):
del
obj
.
__Broken_state__
[
record_id
]
obj
.
_p_changed
=
1
else
:
delattr
(
obj
,
record_id
)
except
(
AttributeError
,
KeyError
):
# property was acquired on a class,
# do nothing, only .xml metadata will be exported
break
# export a separate file with the data
if
not
extension
:
extension
=
self
.
guessExtensionOfDocument
(
obj
,
key
,
data
if
record_id
==
'data'
else
None
)
bma
.
addObject
(
StringIO
(
data
),
key
,
path
=
path
,
ext
=
'._xml'
if
extension
==
'xml'
else
'.'
+
extension
)
break
# since we get the obj from context we should
# again remove useless properties
obj
=
self
.
removeProperties
(
obj
,
1
,
keep_workflow_history
=
True
)
transaction
.
savepoint
(
optimistic
=
True
)
f
=
StringIO
()
obj
.
_p_jar
.
exportFile
(
obj
.
_p_oid
,
f
)
bma
.
addObject
(
f
,
key
,
path
=
path
)
def
importFile
(
self
,
bma
,
parent
,
**
kw
):
bma
.
importFiles
(
self
,
parent
)
def
_importFile
(
self
,
file_name
,
file_obj
,
parent
):
obj_key
,
file_ext
=
os
.
path
.
splitext
(
file_name
)
# id() for installing several bt5 in the same transaction
transactional_variable_obj_key
=
"%s-%s"
%
(
id
(
self
),
obj_key
)
if
file_ext
==
'.zexp'
:
connection
=
self
.
getConnection
(
parent
)
__traceback_info__
=
'Importing %s'
%
file_name
obj
=
connection
.
importFile
(
file_obj
,
customImporters
=
customImporters
)
self
.
_value
=
obj
data
=
getTransactionalVariable
().
get
(
transactional_variable_obj_key
)
if
data
is
not
None
:
self
.
_restoreSeparatelyExportedProperty
(
obj
,
data
)
elif
file_ext
!=
'.xml'
:
# For ZODB Components: if .xml have been processed before, set the
# source code property, otherwise store it in a transactional variable
# so that it can be set once the .xml has been processed
data
=
file_obj
.
read
()
item
=
parent
.
getBusinessItemByPath
(
obj_key
)
obj
=
item
.
_value
if
obj
is
None
:
getTransactionalVariable
()[
transactional_variable_obj_key
]
=
data
else
:
self
.
_restoreSeparatelyExportedProperty
(
obj
,
data
)
def
_restoreSeparatelyExportedProperty
(
self
,
obj
,
data
):
unicode_data
,
property_name
=
SEPARATELY_EXPORTED_PROPERTY_DICT
[
obj
.
__class__
.
__name__
][
1
:]
if
unicode_data
:
data
=
data
.
decode
(
obj
.
output_encoding
)
try
:
setattr
(
obj
,
property_name
,
data
)
except
BrokenModified
:
obj
.
__Broken_state__
[
property_name
]
=
data
obj
.
_p_changed
=
1
else
:
# Revert any work done by __setstate__.
# XXX: This is enough for all objects we currently split in 2 files,
# but __setstate__ could behave badly with the missing attribute
# and newly added types may require more than this.
self
.
removeProperties
(
obj
,
1
,
keep_workflow_history
=
True
)
def
getConnection
(
self
,
obj
):
while
True
:
connection
=
obj
.
_p_jar
if
connection
is
not
None
:
return
connection
obj
=
obj
.
aq_parent
def
_compileXML
(
self
,
file
):
# This method converts XML to ZEXP. Because the conversion
# is quite heavy, a persistent cache database is used to
# store ZEXP, so the second run wouldn't have to re-generate
# identical data again.
#
# For now, a pair of the path to an XML file and its modification time
# are used as a unique key. In theory, a checksum of the content could
# be used instead, and it could be more reliable, as modification time
# might not be updated in some insane filesystems correctly. However,
# in practice, checksums consume a lot of CPU time, so when the cache
# does not hit, the increased overhead is significant. In addition, it
# does rarely happen that two XML files in Business Manager contain
# the same data, so it may not be expected to have more cache hits
# with this approach.
#
# The disadvantage is that this wouldn't work with the archive format,
# because each entry in an archive does not have a mtime in itself.
# However, the plan is to have an archive to retain ZEXP directly
# instead of XML, so the idea of caching would be completely useless
# with the archive format.
name
=
file
.
name
mtime
=
os
.
path
.
getmtime
(
file
.
name
)
key
=
'%s:%s'
%
(
name
,
mtime
)
try
:
return
StringIO
(
cache_database
.
db
[
key
])
except
:
pass
from
Shared.DC.xml
import
ppml
from
OFS.XMLExportImport
import
start_zopedata
,
save_record
,
save_zopedata
import
xml.parsers.expat
outfile
=
StringIO
()
try
:
data
=
file
.
read
()
F
=
ppml
.
xmlPickler
()
F
.
end_handlers
[
'record'
]
=
save_record
F
.
end_handlers
[
'ZopeData'
]
=
save_zopedata
F
.
start_handlers
[
'ZopeData'
]
=
start_zopedata
F
.
binary
=
1
F
.
file
=
outfile
p
=
xml
.
parsers
.
expat
.
ParserCreate
(
'utf-8'
)
p
.
returns_unicode
=
False
p
.
CharacterDataHandler
=
F
.
handle_data
p
.
StartElementHandler
=
F
.
unknown_starttag
p
.
EndElementHandler
=
F
.
unknown_endtag
p
.
Parse
(
data
)
try
:
cache_database
.
db
[
key
]
=
outfile
.
getvalue
()
except
:
pass
outfile
.
seek
(
0
)
return
outfile
except
:
outfile
.
close
()
raise
def
getBusinessPath
(
self
):
return
self
.
_path
...
...
@@ -1283,144 +1062,6 @@ class BusinessItem(Implicit, Persistent):
def
getParentBusinessManager
(
self
):
return
self
.
aq_parent
class
BusinessManagerArchive
(
object
):
"""
This is the base class for all Business Manager archives
"""
def
__init__
(
self
,
path
,
**
kw
):
self
.
path
=
path
def
addObject
(
self
,
obj
,
name
,
path
=
None
,
ext
=
'.zexp'
):
if
path
:
name
=
posixpath
.
join
(
path
,
name
)
# XXX required due to overuse of os.path
name
=
name
.
replace
(
'
\
\
'
,
'/'
).
replace
(
':'
,
'/'
)
name
=
quote
(
name
+
ext
)
path
=
name
.
replace
(
'/'
,
os
.
sep
)
try
:
write
=
self
.
_writeFile
except
AttributeError
:
if
not
isinstance
(
obj
,
str
):
obj
.
seek
(
0
)
obj
=
obj
.
read
()
self
.
_writeString
(
obj
,
path
)
else
:
if
isinstance
(
obj
,
str
):
obj
=
StringIO
(
obj
)
else
:
obj
.
seek
(
0
)
write
(
obj
,
path
)
def
finishCreation
(
self
):
pass
class
BusinessManagerFolder
(
BusinessManagerArchive
):
"""
Class archiving business manager into a folder tree
"""
def
_writeString
(
self
,
obj
,
path
):
object_path
=
os
.
path
.
join
(
self
.
path
,
path
)
path
=
os
.
path
.
dirname
(
object_path
)
os
.
path
.
exists
(
path
)
or
os
.
makedirs
(
path
)
f
=
open
(
object_path
,
'wb'
)
try
:
f
.
write
(
obj
)
finally
:
f
.
close
()
def
importFiles
(
self
,
item
,
parent
):
"""
Import file from a local folder
"""
join
=
os
.
path
.
join
item_name
=
item
.
__class__
.
__name__
root
=
join
(
os
.
path
.
normpath
(
self
.
path
),
item_name
,
''
)
root_path_len
=
len
(
root
)
if
CACHE_DATABASE_PATH
:
try
:
cache_database
.
db
=
gdbm
.
open
(
CACHE_DATABASE_PATH
,
'cf'
)
except
gdbm
.
error
:
cache_database
.
db
=
gdbm
.
open
(
CACHE_DATABASE_PATH
,
'nf'
)
try
:
for
root
,
dirs
,
files
in
os
.
walk
(
root
):
for
file_name
in
files
:
# If the item name is Business Item, then only import the files which
# mattter for this Business Item
if
item_name
==
'BusinessItem'
:
if
not
fnmatch
.
fnmatch
(
file_name
,
'%s.*'
%
item
.
_path
.
split
(
'/'
)[
-
1
]):
continue
file_name
=
join
(
root
,
file_name
)
with
open
(
file_name
,
'rb'
)
as
f
:
file_name
=
posixpath
.
normpath
(
file_name
[
root_path_len
:])
if
'%'
in
file_name
:
file_name
=
unquote
(
file_name
)
elif
item_name
==
'bm'
and
file_name
==
'revision'
:
continue
# self.revision.hash(item_name + '/' + file_name, f.read())
f
.
seek
(
0
)
item
.
_importFile
(
file_name
,
f
,
parent
)
finally
:
if
hasattr
(
cache_database
,
'db'
):
cache_database
.
db
.
close
()
del
cache_database
.
db
class
BusinessManagerTarball
(
BusinessManagerArchive
):
"""
Class archiving business manager into a tarball file
"""
def
__init__
(
self
,
path
,
creation
=
0
,
importing
=
0
,
**
kw
):
super
(
BusinessManagerTarball
,
self
).
__init__
(
path
,
**
kw
)
if
creation
:
self
.
fobj
=
StringIO
()
self
.
tar
=
tarfile
.
open
(
''
,
'w:gz'
,
self
.
fobj
)
self
.
time
=
time
.
time
()
elif
importing
:
self
.
tar
=
tarfile
.
open
(
path
,
'r:gz'
)
self
.
item_dict
=
item_dict
=
defaultdict
(
list
)
for
info
in
self
.
tar
.
getmembers
():
if
info
.
isreg
():
path
=
info
.
name
.
split
(
'/'
)
if
path
[
0
]
==
'.'
:
del
path
[
0
]
item_dict
[
path
[
1
]].
append
((
'/'
.
join
(
path
[
2
:]),
info
))
def
_writeFile
(
self
,
obj
,
path
):
if
self
.
path
:
path
=
posixpath
.
join
(
self
.
path
,
path
)
info
=
tarfile
.
TarInfo
(
path
)
info
.
mtime
=
self
.
time
obj
.
seek
(
0
,
2
)
info
.
size
=
obj
.
tell
()
obj
.
seek
(
0
)
self
.
tar
.
addfile
(
info
,
obj
)
def
finishCreation
(
self
):
self
.
tar
.
close
()
return
self
.
fobj
def
importFiles
(
self
,
item
,
parent
):
"""
Import all file from the archive to the site
"""
extractfile
=
self
.
tar
.
extractfile
item_name
=
item
.
__class__
.
__name__
for
file_name
,
info
in
self
.
item_dict
.
get
(
item_name
,
()):
if
'%'
in
file_name
:
file_name
=
unquote
(
file_name
)
elif
item_name
==
'bm'
and
file_name
==
'revision'
:
continue
f
=
extractfile
(
info
)
self
.
revision
.
hash
(
item_name
+
'/'
+
file_name
,
f
.
read
())
f
.
seek
(
0
)
item
.
_importFile
(
file_name
,
f
,
parent
)
class
bm
(
dict
):
"""
Fake 'bm' item to read bm/* files through BusinessManagerArchive
...
...
product/ERP5/Tool/TemplateTool.py
View file @
8d08790c
...
...
@@ -387,6 +387,9 @@ class TemplateTool (BaseTool):
id = self.generateNewId()
urltype, name = splittype(url)
# Create a zexp path which would be used for Business Manager files
zexp_path = name + '
/
' + name.split('
/
')[-1] + '
.
zexp
'
if WIN and urltype and '
\\
' in name:
urltype = None
name = url
...
...
@@ -398,10 +401,13 @@ class TemplateTool (BaseTool):
del bt.uid
return self[self._setObject(id, bt)]
bt = self._download_url(url, id)
elif os.path.exists(zexp_path):
# If the path exists, we create a Business Manager object after
# downloading it from zexp path
bt = self._download_local(os.path.normpath(zexp_path), id, format_version=3)
else:
template_version_path_list = [
name+'
/
bp
/
template_format_version
',
name+'
/
bm
/
template_format_version
',
]
for path in template_version_path_list:
...
...
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