Merge lp:~savoirfairelinux-openerp/openupgrade-addons/7.0 into lp:openupgrade-addons

Status: Merged
Merged at revision: 8143
Proposed branch: lp:~savoirfairelinux-openerp/openupgrade-addons/7.0
Merge into: lp:openupgrade-addons
Diff against target: 394 lines (+380/-0)
3 files modified
document_page/migrations/7.0.1.0.1/post-migration.py (+306/-0)
document_page/migrations/7.0.1.0.1/pre-migration.py (+60/-0)
document_page/migrations/7.0.1.0.1/user_notes.txt (+14/-0)
To merge this branch: bzr merge lp:~savoirfairelinux-openerp/openupgrade-addons/7.0
Reviewer Review Type Date Requested Status
Holger Brunn (Therp) code review Approve
Maxime Chambreuil (http://www.savoirfairelinux.com) (community) code review Approve
Sandy Carter (http://www.savoirfairelinux.com) (community) Approve
Stefan Rijnhart (Opener) Approve
Review via email: mp+190413@code.launchpad.net

Description of the change

Handling migration of wiki to document_page.

Groups turned into parent pages with type 'category'
Wiky syntax converted to html using specifically made python port of Wiky.js

Leftover from 6.1 after Upgrade:
 - Dashboards
 - OpenERP Web mobile
 - Process
 - web Dashboard

Missing from 7.0 after Upgrade:
 - Enterprise Process
 - View Editor

Lost data:
 - wiki_wiki.tags
 - wiki_wiki.minor_edit
 - wiki_wiki.review
 - wiki_wiki.summary
 - wiki_wiki.toc
 - wiki_wiki.section
 - wiki_wiki_history.minor_edit
 - wiki_groups.summary
 - wiki_make_index
 - wiki_wiki_page_open

Known issues:
  Views are messed up after upgrade, this is resolved by installing 'Enterprise Process' after the upgrade.

To post a comment you must log in.
Revision history for this message
Sylvain LE GAL (GRAP) (sylvain-legal) wrote :

I don't use neither know the 'wiki' module.
Sorry.

review: Abstain
Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

Looks great! But this should be a migration script of the wiki module, not of the document_page module. So I'd advise to create an empty wiki addon that simply contains the script you developed. (and appropriate __openerp__.py, __init__.py of course)

Then on #343, #349, #408f, I think you need to copy data between the tables and not rename them

Please put the information about lost data into a file called user_notes.txt, the loang term goal is to present the information there to the user, giving a summary what points should be given attention.

When setting up your fake wiki module for 7.0, simply let it depend on Enterprise Process, then this addon will be installed automatically on upgrade.

review: Needs Fixing
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thanks for your contribution! I think the idea of rendering the wiki in Python is very elegant.

Holger, I think putting this script in the document_page module is very defendable. Looking at the code, it is clear that the document_page module is not only conceptually the replacement of the wiki module, but also a direct rewrite of it. This is actually already encoded in the base module's pre script that triggers the module renames.

The renaming of the tables and models (ll.343..352) goes together with this idea. Small fixes here: I think you do still need to rename the history model. You do not need to rename the create_menu table as this is a transient model.

I do not see why you would make such an effort to precreate and fill columns in the pre-script. Typically, this is done in the post-script. If it is to allow the orm to set a database constraint 'not null', remember that if you fill them properly in the post-script, the orm will set the constraint at the next, regular upgrade. Can you say if that was your main concern?

l.364: I am guessing the comment 'Put wiki_wiki content into wiki_groups' should be the other way around.

This module aggressively drops deprecated columns. I am generally in favour of prefixing them with the generated openupgrade prefix instead, to prevent unintentional loss of information. But pending the creation of the ephemeral service module to drop deprecated columns in a controlled fashion, I will not block this proposal for it.

review: Needs Fixing
Revision history for this message
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) wrote :

Looking at the base migration script, I came to the conclusion that document_page was the simplified continuation of wiki_wiki. There is also the fact that modules that depened on wiki_wiki in 6.* now depend on document_page.

The issue with the views that was resolved by Enterprise process seems to be fixed.

I wasn't sure whether to put my precreate functions in pre, or post. That's fixed now.

What is the generated prefix? Is it version? How would you name it?

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Hi Sandy, to retrieve the legacy name for columns or tables, you can use

    openupgrade.get_legacy_name(existing_table_or_column_name)

In rename_columns, you can specify (existing_column_name, None). That will call get_legacy_name internally.

Revision history for this message
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) wrote :

This should address all your issues, Stefan.
Holger, I hope this works too.

review: Needs Resubmitting
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thanks for updating this branch! Code approved, but I think your comments in user_notes.txt about leftover modules, missing modules and known issues are a little off. For instance, the Process module in 6.1 is the same module as the Enterprice process in 7.0, and it will always be installed. Could you perhaps just remove these three comments and keep the first two lines of the file and the lost data stanza?

I think the issue you are experiencing with the views after the upgrade may be similar to https://bugs.launchpad.net/openupgrade-server/+bug/1226086, which fixed itself after the next (regular) module upgrade.

review: Needs Fixing
Revision history for this message
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) wrote :

Done

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Approved. Thanks again!

review: Approve
Revision history for this message
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) :
review: Approve
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote :

lgtm

review: Approve (code review)
Revision history for this message
Holger Brunn (Therp) (hbrunn) :
review: Approve (code review)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'document_page/migrations/7.0.1.0.1/post-migration.py'
2--- document_page/migrations/7.0.1.0.1/post-migration.py 1970-01-01 00:00:00 +0000
3+++ document_page/migrations/7.0.1.0.1/post-migration.py 2013-10-15 19:37:17 +0000
4@@ -0,0 +1,306 @@
5+# -*- coding: utf-8 -*-
6+##############################################################################
7+#
8+# OpenERP, Open Source Management Solution
9+# This module copyright (C) 2013 Savoir-faire Linux
10+# (<http://www.savoirfairelinux.com>).
11+#
12+# This program is free software: you can redistribute it and/or modify
13+# it under the terms of the GNU Affero General Public License as
14+# published by the Free Software Foundation, either version 3 of the
15+# License, or (at your option) any later version.
16+#
17+# This program is distributed in the hope that it will be useful,
18+# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+# GNU Affero General Public License for more details.
21+#
22+# You should have received a copy of the GNU Affero General Public License
23+# along with this program. If not, see <http://www.gnu.org/licenses/>.
24+#
25+##############################################################################
26+
27+from openerp.openupgrade import openupgrade
28+from openerp import pooler, SUPERUSER_ID
29+from openerp.openupgrade.openupgrade import logged_query
30+
31+
32+def combine_wiki_groups_document_page(cr):
33+ """Put wiki_groups content into wiki_wiki, then delete wiki_groups, conserve parent_id"""
34+ logged_query(cr, """ALTER TABLE document_page ADD COLUMN old_id integer;""")
35+ logged_query(cr, """\
36+INSERT INTO document_page(create_uid, create_date, write_date, name, content, type, old_id)
37+SELECT create_uid, create_date, write_date, name, content, 'category' AS type, id
38+FROM wiki_groups
39+ORDER BY id ASC;""")
40+ logged_query(cr, """\
41+UPDATE document_page w
42+SET parent_id = (SELECT id FROM document_page WHERE old_id = w.group_id LIMIT 1)
43+WHERE group_id IS NOT null;\
44+""")
45+ openupgrade.drop_columns(cr, [('document_page', 'group_id'), ('document_page', 'old_id')])
46+
47+
48+def migrate_wiki_to_html(cr, pool):
49+ document_page_obj = pool.get('document.page')
50+ wiky = Wiky()
51+ logged_query(cr, """\
52+SELECT id, content
53+FROM document_page
54+WHERE content is not NULL;
55+""")
56+ for page_line_id, content in cr.fetchall():
57+ document_page_obj.write(
58+ cr, SUPERUSER_ID, [page_line_id],
59+ {'content': wiky.process(content)}
60+ )
61+
62+
63+@openupgrade.migrate()
64+def migrate(cr, version):
65+ pool = pooler.get_pool(cr.dbname)
66+ combine_wiki_groups_document_page(cr)
67+ migrate_wiki_to_html(cr, pool)
68+ logged_query(cr, """DROP TABLE wiki_wiki_page_open;""")
69+ logged_query(cr, """DROP TABLE wiki_make_index;""")
70+ logged_query(cr, """DROP TABLE wiki_create_menu""")
71+ logged_query(cr, """DROP TABLE wiki_groups""")
72+
73+
74+##############################################################################
75+#
76+# Wiky.py - Python library to converts Wiki MarkUp language to HTML.
77+# Based on Wiki.js by Tanin Na Nakorn
78+#
79+# Copyright © 2013 Sandy Carter <bwrsandman@gmail.com>
80+# This work is free. You can redistribute it and/or modify it under the
81+# terms of the Creative Commons Attribution 3.0 Unported License.
82+# (http://creativecommons.org/licenses/by/3.0/legalcode)
83+#
84+##############################################################################
85+
86+import re
87+
88+re_h3 = re.compile("^===[^=]+===$")
89+re_h2 = re.compile("^==[^=]+==$")
90+re_h1 = re.compile("^=[^=]+=$")
91+re_indent = re.compile("^:+")
92+re_hr = re.compile("^-{4}")
93+re_ul = re.compile("^\*+ ")
94+re_ol = re.compile("^#+ ")
95+re_ul_ol = re.compile("^(\*+|#+) ")
96+re_ul_li = re.compile("^(\*+|##+):? ")
97+re_ol_li = re.compile("^(\*\*+|#+):? ")
98+re_ul_ol_li = re.compile("^(\*+|#+):? ")
99+re_youtube = re.compile("^(https?://)?(www\.)?youtube.com/(watch\?(.*)v=|embed/)([^&]+)")
100+re_b_i = re.compile("'''''(([^']|([^']('{1,4})?[^']))+)'''''")
101+re_b = re.compile("'''(([^']|([^'](''?)?[^']))+)'''")
102+re_i = re.compile("''(([^']|([^']'?[^']))+)''")
103+
104+
105+class Wiky:
106+ def __init__(self, link_image=None):
107+ self.link_image = link_image
108+
109+ def process(self, wikitext):
110+ lines = wikitext.split("\n")
111+ html = ""
112+ i = 0
113+ while i < len(lines):
114+ line = lines[i]
115+ if re_h3.match(line):
116+ html += "<h3>%s</h3>" % line[3:-3]
117+ elif re_h2.match(line):
118+ html += "<h2>%s</h2>" % line[2:-2]
119+ elif re_h1.match(line):
120+ html += "<h1>%s</h1>" % line[1:-1]
121+ elif re_hr.match(line):
122+ html += "<hr/>"
123+ elif re_indent.match(line):
124+ start = i
125+ while i < len(lines) and re_indent.match(lines[i]):
126+ i += 1
127+ i -= 1
128+ html += self.process_indent(lines[start: i + 1])
129+ elif re_ul.match(line):
130+ start = i
131+ while i < len(lines) and re_ul_li.match(lines[i]):
132+ i += 1
133+ i -= 1
134+ html += self.process_bullet_point(lines[start: i + 1])
135+ elif re_ol.match(line):
136+ start = i
137+ while i < len(lines) and re_ol_li.match(lines[i]):
138+ i += 1
139+ i -= 1
140+ html += self.process_bullet_point(lines[start: i + 1])
141+ else:
142+ html += self.process_normal(line)
143+ html += "<br/>\n"
144+ i += 1
145+ return html
146+
147+ def process_indent(self, lines):
148+ html = "\n<dl>\n"
149+ i = 0
150+ while i < len(lines):
151+ line = lines[i]
152+ html += "<dd>"
153+ this_count = len(re_indent.match(line).group(0))
154+ html += self.process_normal(line[this_count:])
155+
156+ nested_end = i
157+ j = i + 1
158+ while j < len(lines):
159+ nested_count = len(re_indent.match(lines[j]).group(0))
160+ if nested_count <= this_count:
161+ break
162+ else:
163+ nested_end = j
164+ j += 1
165+
166+ if nested_end > i:
167+ html += self.process_indent(lines[i + 1: nested_end + 1])
168+ i = nested_end
169+
170+ html += "</dd>\n"
171+ i += 1
172+ html += "</dl>\n"
173+ return html
174+
175+ def process_bullet_point(self, lines):
176+ if not len(lines):
177+ return ""
178+ html = "<ul>" if lines[0][0] == "*" else "<ol>"
179+ html += '\n'
180+ i = 0
181+ while i < len(lines):
182+ line = lines[i]
183+ html += "<li>"
184+ this_count = len(re_ul_ol.match(line).group(1))
185+ html += self.process_normal(line[this_count+1:])
186+
187+ # continue previous with #:
188+ nested_end = i
189+ j = i + 1
190+ while j < len(lines):
191+ nested_count = len(re_ul_ol_li.match(lines[j]).group(1))
192+ if nested_count < this_count:
193+ break
194+ elif lines[j][nested_count] == ':':
195+ html += "<br/>" + self.process_normal(lines[j][nested_count + 2:])
196+ nested_end = j
197+ else:
198+ break
199+ j += 1
200+ i = nested_end
201+
202+ # nested bullet point
203+ nested_end = i
204+ j = i + 1
205+ while j < len(lines):
206+ nested_count = len(re_ul_ol_li.match(lines[j]).group(1))
207+ if nested_count <= this_count:
208+ break
209+ else:
210+ nested_end = j
211+ j += 1
212+
213+ if nested_end > i:
214+ html += self.process_bullet_point(lines[i + 1: nested_end + 1])
215+ i = nested_end
216+
217+ # continue previous with #:
218+ nested_end = i
219+ j = i + 1
220+ while j < len(lines):
221+ nested_count = len(re_ul_ol_li.match(lines[j]).group(1))
222+ if nested_count < this_count:
223+ break
224+ elif lines[j][nested_count] == ':':
225+ html += self.process_normal(lines[j][nested_count + 2:])
226+ nested_end = j
227+ else:
228+ break
229+ j += 1
230+ i = nested_end
231+ html += "</li>\n"
232+ i += 1
233+ html += "</ul>" if lines[0][0] == "*" else "</ol>"
234+ html += '\n'
235+ return html
236+
237+ def process_url(self, txt):
238+ css = ('style="background: url(\"%s\") no-repeat scroll '
239+ 'right center transparent;padding-right: 13px;"'
240+ % self.link_image) if self.link_image else ''
241+ try:
242+ index = txt.index(" ")
243+ url = txt[:index]
244+ label = txt[index + 1:]
245+ except ValueError:
246+ label = url = txt
247+ return """<a href="%s" %s>%s</a>""" % (url, css, label)
248+
249+ @staticmethod
250+ def process_image(txt):
251+ try:
252+ index = txt.index(" ")
253+ url = txt[:index]
254+ label = txt[index + 1:]
255+ except ValueError:
256+ url = txt
257+ label = ""
258+ return '<img src="%s" alt="%s" />' % (url, label)
259+
260+ @staticmethod
261+ def process_video(url):
262+ m = re_youtube.match(url)
263+ if not m:
264+ return "<b>%s is an invalid YouTube URL</b>" % url
265+ url = "http://www.youtube.com/embed/" + m.group(5)
266+ return '<iframe width="480" height="390" src="%s" frameborder="0" allowfullscreen=""></iframe>' % url
267+
268+ def process_normal(self, wikitext):
269+ # Image
270+ while True:
271+ try:
272+ index = wikitext.index("[[File:")
273+ end_index = wikitext.index("]]", index + 7)
274+ wikitext = (wikitext[:index] +
275+ self.process_image(wikitext[index + 7:end_index]) +
276+ wikitext[end_index + 2:])
277+ except ValueError:
278+ break
279+
280+ # Video
281+ while True:
282+ try:
283+ index = wikitext.index("[[Video:")
284+ end_index = wikitext.index("]]", index + 8)
285+ wikitext = (wikitext[:index] +
286+ self.process_video(wikitext[index+8:end_index]) +
287+ wikitext[end_index + 2:])
288+ except ValueError:
289+ break
290+
291+ # URL
292+ for protocol in ["http", "ftp", "news"]:
293+ end_index = -1
294+ while True:
295+ try:
296+ index = wikitext.index("[%s://" % protocol, end_index + 1)
297+ end_index = wikitext.index("]", index + len(protocol) + 4)
298+ wikitext = (wikitext[:index] +
299+ self.process_url(wikitext[index+1:end_index]) +
300+ wikitext[end_index+1:])
301+ except ValueError:
302+ break
303+
304+ # Bold, Italics, Emphasis
305+ wikitext = re_b_i.sub("<b><i>\1</i></b>", wikitext)
306+ wikitext = re_b.sub("<b>\1</b>", wikitext)
307+ wikitext = re_i.sub("<i>\1</i>", wikitext)
308+
309+ return wikitext
310+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
311
312=== added file 'document_page/migrations/7.0.1.0.1/pre-migration.py'
313--- document_page/migrations/7.0.1.0.1/pre-migration.py 1970-01-01 00:00:00 +0000
314+++ document_page/migrations/7.0.1.0.1/pre-migration.py 2013-10-15 19:37:17 +0000
315@@ -0,0 +1,60 @@
316+# -*- coding: utf-8 -*-
317+##############################################################################
318+#
319+# OpenERP, Open Source Management Solution
320+# This module copyright (C) 2013 Savoir-faire Linux
321+# (<http://www.savoirfairelinux.com>).
322+#
323+# This program is free software: you can redistribute it and/or modify
324+# it under the terms of the GNU Affero General Public License as
325+# published by the Free Software Foundation, either version 3 of the
326+# License, or (at your option) any later version.
327+#
328+# This program is distributed in the hope that it will be useful,
329+# but WITHOUT ANY WARRANTY; without even the implied warranty of
330+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
331+# GNU Affero General Public License for more details.
332+#
333+# You should have received a copy of the GNU Affero General Public License
334+# along with this program. If not, see <http://www.gnu.org/licenses/>.
335+#
336+##############################################################################
337+
338+from openerp.openupgrade import openupgrade
339+
340+column_renames = {
341+ 'wiki_wiki': [
342+ ('text_area', 'content'),
343+ ('tags', None),
344+ ('minor_edit', None),
345+ ('review', None),
346+ ('summary', None),
347+ ('toc', None),
348+ ('section', None),
349+ ],
350+ 'wiki_groups': [
351+ ('template', 'content'),
352+ ],
353+ 'wiki_wiki_history': [
354+ ('text_area', 'content'),
355+ ('wiki_id', 'page_id'),
356+ ('minor_edit', None),
357+ ],
358+}
359+
360+table_renames = [
361+ ('wiki_wiki', 'document_page'),
362+ ('wiki_wiki_history', 'document_page_history'),
363+]
364+
365+model_renames = [
366+ ('wiki.wiki', 'document.page'),
367+ ('wiki.wiki.history', 'document.page.history'),
368+]
369+
370+
371+@openupgrade.migrate()
372+def migrate(cr, version):
373+ openupgrade.rename_columns(cr, column_renames)
374+ openupgrade.rename_tables(cr, table_renames)
375+ openupgrade.rename_models(cr, model_renames)
376
377=== added file 'document_page/migrations/7.0.1.0.1/user_notes.txt'
378--- document_page/migrations/7.0.1.0.1/user_notes.txt 1970-01-01 00:00:00 +0000
379+++ document_page/migrations/7.0.1.0.1/user_notes.txt 2013-10-15 19:37:17 +0000
380@@ -0,0 +1,14 @@
381+Groups turned into parent pages with type 'category'
382+Wiky syntax converted to html using specifically made python port of Wiky.js
383+
384+Lost data:
385+ - wiki_wiki.tags
386+ - wiki_wiki.minor_edit
387+ - wiki_wiki.review
388+ - wiki_wiki.summary
389+ - wiki_wiki.toc
390+ - wiki_wiki.section
391+ - wiki_wiki_history.minor_edit
392+ - wiki_groups.summary
393+ - wiki_make_index
394+ - wiki_wiki_page_open

Subscribers

People subscribed via source and target branches