3
migration from moin 1.3 < patch-305 to moin 1.3 >= patch-305
4
Here we fix 2 errors that crept in by use of mig1(?) and mig5:
5
* the edit-log misses 1 field (missing TAB) on faked "missing editlog
7
* we accidently gave ATTNEW/DRW/DEL an incremented revno (although
8
attaching a file doesn't change page content and revision), so we need
9
to convert those entries to use revno == 99999999 and renumber the
10
normal entries so we have no missing numbers in between
11
* edit-log's action field sometimes was empty (default: SAVE)
13
Steps for a successful migration:
15
1. Stop your wiki and make a backup of old data and code
17
2. Make a copy of the wiki's "data" directory to your working dir
19
3. Run this script from your working dir
21
4. If there was no error, you will find:
22
data.pre-mig8 - the script renames your data directory copy to that name
23
data - converted data dir
25
5. Verify conversion results (number of pages, size of logs, attachments,
26
number of backup copies) - everything should be reasonable before
29
6. Copy additional files from data.pre-mig8 to data (maybe intermaps, logs,
30
etc.). Be aware that the file contents AND file names of wiki content
31
may have changed, so DO NOT copy the files inside the cache/ directory,
32
let the wiki refill it.
34
7. Replace the data directory your wiki uses with the data directory
35
you created by previous steps. DO NOT simply copy the converted stuff
36
into the original or you will duplicate pages and create chaos!
38
8. Test it - if something has gone wrong, you still have your backup.
41
@copyright: 2004 Thomas Waldmann
42
@license: GPL, see COPYING for details
46
import os.path, sys, urllib
48
# Insert THIS moin dir first into sys path, or you would run another
50
sys.path.insert(0, '../../..')
51
from MoinMoin import wikiutil
53
from migutil import opj, listdir, copy_file, move_file, copy_dir
55
# info[pagename][timestamp_usecs] = [revno_new, [...]]
56
# if revno_new is 99999999, we haven't assigned a new revno to this entry
59
def gather_editlog(el_from, forcepagename=None):
60
""" this gathers everything that is in edit-log into internal
61
data structures, converting to the future format
63
if not os.path.exists(el_from):
65
for l in open(el_from):
66
data = l.rstrip('\n').rstrip('\r').split('\t')
69
(timestampstr,revstr,action,pagename,ip,host,id,extra,comment) = data
71
if forcepagename: # we use this for edit-log in pagedirs (for renamed pages!)
72
pagename = forcepagename
74
if not action: # FIX: sometimes action is empty ...
77
if action in ['ATTNEW','ATTDRW','ATTDEL',]:
78
revstr = '99999999' # FIXES revno
79
# use reserved value, ATT action doesn't create new rev of anything
81
if (comment == '' and extra == '' and id == 'missing editlog entry for this page version') or \
82
(extra == '' and id == '' and comment == 'missing editlog entry for this page version'):
83
# FIX omitted field bug on fake entries
84
comment = 'missing edit-log entry for this revision' # more precise
89
data = [timestampstr,rev,action,pagename,ip,host,id,extra,comment]
91
entry = info.get(pagename, {})
92
timestamp = long(timestampstr) # must be long for py 2.2.x
93
entry[timestamp] = [99999999, data] # new revno, data
94
info[pagename] = entry
96
def gather_pagedirs(dir_from):
97
""" this gathers edit-log information from the pagedirs, just to make sure
99
pagedir = opj(dir_from, 'pages')
100
pagelist = listdir(pagedir)
101
for pagename in pagelist:
102
editlog_from = opj(pagedir, pagename, 'edit-log')
103
gather_editlog(editlog_from, pagename)
106
def generate_pages(dir_from, dir_to):
107
revactions = ['SAVE','SAVENEW','SAVE/REVERT',] # these actions create revisions
109
entry = info.get(pn, {})
110
tslist = entry.keys()
112
pagedir = opj(dir_to, 'pages', pn)
113
revdir = opj(pagedir, 'revisions')
115
editlog_file = opj(pagedir, 'edit-log')
116
f = open(editlog_file, 'w')
122
(timestamp,rev,action,pagename,ip,host,id,extra,comment) = data
123
revstr = '%08d' % rev
124
if action in revactions:
126
revnewstr = '%08d' % revnew
127
entry[ts][0] = revnew # remember what new revno we chose
128
else: # ATTNEW,ATTDRW,ATTDEL
129
revnewstr = '99999999'
130
if action.endswith('/REVERT'):
131
# replace the old revno with the correct new revno
132
revertrevold = int(extra)
135
data2 = entry[ts2][1]
136
(timestamp2,rev2,action2,pagename2,ip2,host2,id2,extra2,comment2) = data2
137
if rev2 == revertrevold:
138
revertrevnew = entry[ts2][0]
139
datanew[7] = '%08d' % revertrevnew
141
datanew[1] = revnewstr
142
f.write('\t'.join(datanew)+'\n') # does make a CRLF on win32 in the file
144
if action in revactions: # we DO have a page rev for this one
145
file_from = opj(dir_from, 'pages', pn, 'revisions', revstr)
146
file_to = opj(revdir, revnewstr)
147
copy_file(file_from, file_to)
150
# check if page exists or is deleted in orig dir
151
pagedir_from = opj(dir_from, 'pages', pn)
152
revdir_from = opj(pagedir_from, 'revisions')
154
curr_file_from = opj(pagedir_from, 'current')
155
currentfrom = open(curr_file_from).read().strip() # try to access it
160
# re-make correct DELETED status!
162
curr_file = opj(pagedir, 'current')
163
f = open(curr_file, 'w')
164
f.write("%08d\n" % revnew) # we add a \n, so it is easier to hack in there manually
167
att_from = opj(dir_from, 'pages', pn, 'attachments')
168
if os.path.exists(att_from):
169
att_to = opj(pagedir, 'attachments')
170
copy_dir(att_from, att_to)
173
def generate_editlog(dir_from, dir_to):
175
for pagename in info:
176
entry = info.get(pagename, {})
178
file_from, data = entry[ts]
181
tslist = editlog.keys()
184
editlog_file = opj(dir_to, 'edit-log')
185
f = open(editlog_file, 'w')
187
datatmp = editlog[ts][:]
189
datatmp[1] = '%08d' % rev
190
f.write('\t'.join(datatmp)+'\n')
194
origdir = 'data.pre-mig8'
196
# Backup original dir and create new empty dir
198
os.rename('data', origdir)
201
print "You need to be in the directory where your copy of the 'data' directory is located."
204
#gather_editlog(opj(origdir, 'edit-log'))
205
gather_pagedirs(origdir)
207
generate_editlog(origdir, 'data')
208
generate_pages(origdir, 'data')
210
copy_dir(opj(origdir, 'plugin'), opj('data', 'plugin'))
212
copy_dir(opj(origdir, 'user'), opj('data', 'user'))
214
copy_file(opj(origdir, 'event-log'), opj('data', 'event-log'))
216
copy_file(opj(origdir, 'intermap.txt'), opj('data', 'intermap.txt'))