Merge lp:~chipaca/ubuntuone-client/improv-v2-upgrade into lp:ubuntuone-client

Proposed by John Lenton
Status: Merged
Approved by: Guillermo Gonzalez
Approved revision: 188
Merged at revision: not available
Proposed branch: lp:~chipaca/ubuntuone-client/improv-v2-upgrade
Merge into: lp:ubuntuone-client
Diff against target: None lines
To merge this branch: bzr merge lp:~chipaca/ubuntuone-client/improv-v2-upgrade
Reviewer Review Type Date Requested Status
Guillermo Gonzalez Approve
Eric Casteleijn (community) Approve
Review via email: mp+10805@code.launchpad.net

Commit message

fixes #405688

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) wrote :

This fixes #405688, by being a lot more cautious in moving around conflicts and partials. If anybody can think of more cases for the tests, please let me know :)

Revision history for this message
Eric Casteleijn (thisfred) wrote :

Indeed it does! +1

review: Approve
Revision history for this message
Guillermo Gonzalez (verterok) wrote :

yessir

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/syncdaemon/test_vm.py'
2--- tests/syncdaemon/test_vm.py 2009-08-25 18:26:17 +0000
3+++ tests/syncdaemon/test_vm.py 2009-08-27 16:41:47 +0000
4@@ -562,6 +562,162 @@
5 self.assertTrue(os.path.exists(self.shares_dir + '/.u1partial.bar'))
6 self.assertTrue(os.path.exists(self.shares_dir + '/baz/baz.u1conflict'))
7
8+ def test_2_to_3_more(self):
9+ """ Test the upgrade from v.2 of the metadata to v.3 some more"""
10+ vm_data_dir = os.path.join(self.data_dir, 'vm')
11+ os.makedirs(vm_data_dir)
12+ with open(os.path.join(vm_data_dir, '.version'), 'w') as fd:
13+ fd.write('2')
14+
15+ expected = []
16+
17+ for dirname in self.root_dir, self.shares_dir:
18+ # a plain .conflict...
19+ # ...on a file
20+ open(dirname + '/1a.conflict', 'w').close()
21+ expected.append(dirname + '/1a.u1conflict')
22+ # ...on an empty directory
23+ os.mkdir(dirname + '/1b.conflict')
24+ expected.append(dirname + '/1b.u1conflict')
25+ # ...on a directory with content
26+ os.mkdir(dirname + '/1c.conflict')
27+ os.mkdir(dirname + '/1c.conflict/1c')
28+ expected.append(dirname + '/1c.u1conflict/1c')
29+ # ...in a readonly directory
30+ os.mkdir(dirname + '/1d')
31+ os.mkdir(dirname + '/1d/1d.conflict')
32+ os.chmod(dirname + '/1d', 0500)
33+ expected.append(dirname + '/1d/1d.u1conflict')
34+ # ...in a directory that is also a .conflict
35+ os.mkdir(dirname + '/1e.conflict')
36+ os.mkdir(dirname + '/1e.conflict/1e.conflict')
37+ expected.append(dirname + '/1e.u1conflict/1e.u1conflict')
38+
39+ # a numbered .conflict...
40+ # ...on a file
41+ open(dirname + '/2a.conflict.2', 'w').close()
42+ expected.append(dirname + '/2a.u1conflict.2')
43+ # ...on an empty directory
44+ os.mkdir(dirname + '/2b.conflict.3')
45+ expected.append(dirname + '/2b.u1conflict.3')
46+ # ...on a directory with content
47+ os.mkdir(dirname + '/2c.conflict.4')
48+ os.mkdir(dirname + '/2c.conflict.4/2c')
49+ expected.append(dirname + '/2c.u1conflict.4/2c')
50+ # ...in a readonly directory
51+ os.mkdir(dirname + '/2d')
52+ os.mkdir(dirname + '/2d/2d.conflict.5')
53+ os.chmod(dirname + '/2d', 0500)
54+ expected.append(dirname + '/2d/2d.u1conflict.5')
55+ # ...in a directory that is also a .conflict
56+ os.mkdir(dirname + '/2e.conflict')
57+ os.mkdir(dirname + '/2e.conflict/2e.conflict.6')
58+ expected.append(dirname + '/2e.u1conflict/2e.u1conflict.6')
59+
60+ # a plain .conflict of which there already exists a .u1conflict...
61+ # ...on a file
62+ open(dirname + '/3a.conflict', 'w').close()
63+ open(dirname + '/3a.u1conflict', 'w').close()
64+ expected.append(dirname + '/3a.u1conflict')
65+ expected.append(dirname + '/3a.u1conflict.1')
66+ # ...on an empty directory
67+ os.mkdir(dirname + '/3b.conflict')
68+ os.mkdir(dirname + '/3b.u1conflict')
69+ expected.append(dirname + '/3b.u1conflict')
70+ expected.append(dirname + '/3b.u1conflict.1')
71+ # ...on a directory with content
72+ os.mkdir(dirname + '/3c.conflict')
73+ os.mkdir(dirname + '/3c.conflict/3c')
74+ os.mkdir(dirname + '/3c.u1conflict')
75+ os.mkdir(dirname + '/3c.u1conflict/3c2')
76+ expected.append(dirname + '/3c.u1conflict.1/3c')
77+ expected.append(dirname + '/3c.u1conflict/3c2')
78+ # ...in a readonly directory
79+ os.mkdir(dirname + '/3d')
80+ os.mkdir(dirname + '/3d/3d.conflict')
81+ os.mkdir(dirname + '/3d/3d.u1conflict')
82+ os.mkdir(dirname + '/3d/3d.u1conflict/3d')
83+ os.chmod(dirname + '/3d', 0500)
84+ expected.append(dirname + '/3d/3d.u1conflict/3d')
85+ expected.append(dirname + '/3d/3d.u1conflict.1')
86+ # ...in a directory that is also a .conflict
87+ os.mkdir(dirname + '/3e.conflict')
88+ os.mkdir(dirname + '/3e.conflict/3e.conflict')
89+ os.mkdir(dirname + '/3e.conflict/3e.u1conflict')
90+ os.mkdir(dirname + '/3e.conflict/3e.u1conflict/3e')
91+ expected.append(dirname + '/3e.u1conflict/3e.u1conflict/3e')
92+ expected.append(dirname + '/3e.u1conflict/3e.u1conflict.1')
93+
94+ # a numbered .conflict of which there already exists a .u1conflict...
95+ # ...on a file
96+ open(dirname + '/4a.conflict.1', 'w').close()
97+ open(dirname + '/4a.u1conflict.1', 'w').close()
98+ expected.append(dirname + '/4a.u1conflict.1')
99+ expected.append(dirname + '/4a.u1conflict.2')
100+ # ...on an empty directory
101+ os.mkdir(dirname + '/4b.conflict.2')
102+ os.mkdir(dirname + '/4b.u1conflict.2')
103+ expected.append(dirname + '/4b.u1conflict.2')
104+ expected.append(dirname + '/4b.u1conflict.3')
105+ # ...on a directory with content
106+ os.mkdir(dirname + '/4c.conflict.3')
107+ os.mkdir(dirname + '/4c.conflict.3/4c')
108+ os.mkdir(dirname + '/4c.u1conflict.3')
109+ expected.append(dirname + '/4c.u1conflict.4/4c')
110+ expected.append(dirname + '/4c.u1conflict.3')
111+ # ...in a readonly directory
112+ os.mkdir(dirname + '/4d')
113+ os.mkdir(dirname + '/4d/4d.conflict.4')
114+ os.mkdir(dirname + '/4d/4d.u1conflict.4')
115+ os.chmod(dirname + '/4d', 0500)
116+ expected.append(dirname + '/4d/4d.u1conflict.4')
117+ expected.append(dirname + '/4d/4d.u1conflict.5')
118+ # ...in a directory that is also a .conflict
119+ os.mkdir(dirname + '/4e.conflict')
120+ os.mkdir(dirname + '/4e.conflict/4e.conflict.5')
121+ os.mkdir(dirname + '/4e.conflict/4e.u1conflict.5')
122+ expected.append(dirname + '/4e.u1conflict/4e.u1conflict.5')
123+ expected.append(dirname + '/4e.u1conflict/4e.u1conflict.6')
124+
125+ # a plain .partial...
126+ # ...of a file
127+ open(dirname + '/5a.partial', 'w').close()
128+ expected.append(dirname + '/.u1partial.5a')
129+ # ...of a directory
130+ os.mkdir(dirname + '/5b')
131+ open(dirname + '/5b/.partial', 'w').close()
132+ expected.append(dirname + '/5b/.u1partial')
133+ # ...of a readonly directory
134+ os.mkdir(dirname + '/5c')
135+ open(dirname + '/5c/.partial', 'w').close()
136+ os.chmod(dirname + '/5c', 0500)
137+ expected.append(dirname + '/5c/.u1partial')
138+
139+ # a plain .partial of which there already exists a .u1partial...
140+ # ...of a file
141+ open(dirname + '/6a.partial', 'w').close()
142+ open(dirname + '/.u1partial.6a', 'w').close()
143+ expected.append(dirname + '/.u1partial.6a')
144+ expected.append(dirname + '/.u1partial.6a.1')
145+ # ...of a directory
146+ os.mkdir(dirname + '/6b')
147+ open(dirname + '/6b/.partial', 'w').close()
148+ open(dirname + '/6b/.u1partial', 'w').close()
149+ expected.append(dirname + '/6b/.u1partial')
150+ expected.append(dirname + '/6b/.u1partial.1')
151+ # ...of a readonly directory
152+ os.mkdir(dirname + '/6c')
153+ open(dirname + '/6c/.partial', 'w').close()
154+ open(dirname + '/6c/.u1partial', 'w').close()
155+ os.chmod(dirname + '/6c', 0500)
156+ expected.append(dirname + '/6c/.u1partial')
157+ expected.append(dirname + '/6c/.u1partial.1')
158+
159+ self.main = FakeMain(self.root_dir, self.shares_dir, self.data_dir)
160+
161+ for path in expected:
162+ self.assertTrue(os.path.exists(path), 'missing ' + path)
163+
164 def test_missing_version_file_with_version_non_0(self):
165 """ Test the upgrade from the first shelf layout version to v3
166 while the metadata sould be in v3 format
167
168=== modified file 'ubuntuone/syncdaemon/volume_manager.py'
169--- ubuntuone/syncdaemon/volume_manager.py 2009-08-26 13:33:23 +0000
170+++ ubuntuone/syncdaemon/volume_manager.py 2009-08-27 16:41:47 +0000
171@@ -508,24 +508,48 @@
172 for dirpath, dirnames, filenames in os.walk(top):
173 with allow_writes(dirpath):
174 for names in filenames, dirnames:
175- for pos, name in enumerate(names):
176- if name == '.partial':
177- new_name = '.u1partial'
178- else:
179- new_name = re.sub(r'^(.+)\.partial$',
180- r'.u1partial.\1', name)
181- conflict_re = r'^(.+)\.conflict((?:\.\d+)?)$'
182- new_name = re.sub(conflict_re,
183- r'\1.u1conflict\2', new_name)
184- if new_name != name:
185- self.log.debug('renaming %r to %r',
186- name, new_name)
187- os.rename(os.path.join(dirpath, name),
188- os.path.join(dirpath, new_name))
189- names[pos] = new_name
190+ self._upgrade_names(dirpath, names)
191 self._upgrade_metadata_3(md_version)
192 self._update_metadata_version()
193
194+ def _upgrade_names(self, dirpath, names):
195+ """
196+ Do the actual renaming for _upgrade_metadata_2
197+ """
198+ for pos, name in enumerate(names):
199+ new_name = name
200+ if re.match(r'.*\.partial$|\.u1partial(?:\..+)?', name):
201+ if name == '.partial':
202+ new_name = '.u1partial'
203+ else:
204+ new_name = re.sub(r'^(.+)\.partial$',
205+ r'.u1partial.\1', name)
206+ if new_name != name:
207+ while os.path.lexists(os.path.join(dirpath, new_name)):
208+ # very, very strange
209+ self.log.warning('Found a .partial and .u1partial'
210+ ' for the same file: %s!' % new_name)
211+ new_name += '.1'
212+ elif re.search(r'\.(?:u1)?conflict(?:\.\d+)?$', name):
213+ new_name = re.sub(r'^(.+)\.conflict((?:\.\d+)?)$',
214+ r'\1.u1conflict\2', name)
215+ if new_name != name:
216+ while os.path.lexists(os.path.join(dirpath, new_name)):
217+ m = re.match(r'(.*\.u1conflict)((?:\.\d+)?)$', new_name)
218+ base, num = m.groups()
219+ if not num:
220+ num = '.1'
221+ else:
222+ num = '.' + str(int(num[1:])+1)
223+ new_name = base + num
224+ if new_name != name:
225+ old_path = os.path.join(dirpath, name)
226+ new_path = os.path.join(dirpath, new_name)
227+ self.log.debug('renaming %r to %r' % (old_path, new_path))
228+ os.rename(old_path, new_path)
229+ names[pos] = new_name
230+
231+
232 def _upgrade_metadata_3(self, md_version):
233 """
234 Upgrade to version 4 (new layout!)

Subscribers

People subscribed via source and target branches