Show More
@@ -0,0 +1,9 b'' | |||||
|
1 | =================================================================== | |||
|
2 | Cannot display: file marked as a binary type. | |||
|
3 | svn:mime-type = application/octet-stream | |||
|
4 | Index: intl.dll | |||
|
5 | =================================================================== | |||
|
6 | diff --git a/intl.dll b/intl.dll | |||
|
7 | new file mode 10644 | |||
|
8 | --- /dev/null (revision 0) | |||
|
9 | +++ b/intl.dll (revision 1489) |
This diff has been collapsed as it changes many lines, (652 lines changed) Show them Hide them | |||||
@@ -0,0 +1,652 b'' | |||||
|
1 | =================================================================== | |||
|
2 | Cannot display: file marked as a binary type. | |||
|
3 | svn:mime-type = image/png | |||
|
4 | Index: trunk/doc/images/SettingsOverlay.png | |||
|
5 | =================================================================== | |||
|
6 | diff --git a/trunk/doc/images/SettingsOverlay.png b/trunk/doc/images/SettingsOverlay.png | |||
|
7 | GIT binary patch | |||
|
8 | --- a/trunk/doc/images/SettingsOverlay.png (revision 1487) | |||
|
9 | +++ b/trunk/doc/images/SettingsOverlay.png (revision 1488) | |||
|
10 | Index: trunk/doc/source/de/tsvn_ch04.xml | |||
|
11 | =================================================================== | |||
|
12 | diff --git a/trunk/doc/source/de/tsvn_ch04.xml b/trunk/doc/source/de/tsvn_ch04.xml | |||
|
13 | --- a/trunk/doc/source/de/tsvn_ch04.xml (revision 1487) | |||
|
14 | +++ b/trunk/doc/source/de/tsvn_ch04.xml (revision 1488) | |||
|
15 | @@ -1561,39 +1561,49 @@ | |||
|
16 | </figure> | |||
|
17 | Abgesehen von der bevorzugten Sprache erlaubt dieser Dialog es Ihnen, | |||
|
18 | (fast) alle Einstellungen von TortoiseSVN zu ändern. | |||
|
19 | -### Translate ### | |||
|
20 | <variablelist> | |||
|
21 | <varlistentry> | |||
|
22 | - <term>Language</term> | |||
|
23 | - <listitem> | |||
|
24 | - <para>Selects your user interface language. What did you expect?</para> | |||
|
25 | + <term>Sprache</term> | |||
|
26 | + <listitem> | |||
|
27 | + <para>Wählt die Sprache für die Dialoge/Meldungen aus. Was | |||
|
28 | + haben Sie anderes erwartet?</para> | |||
|
29 | </listitem> | |||
|
30 | </varlistentry> | |||
|
31 | ||||
|
32 | <varlistentry> | |||
|
33 | - <term>Exclude pattern</term> | |||
|
34 | + <term>Ausschliessen</term> | |||
|
35 | <listitem> | |||
|
36 | <para> | |||
|
37 | <indexterm> | |||
|
38 | - <primary>exclude pattern</primary> | |||
|
39 | + <primary>ausschliessen</primary> | |||
|
40 | </indexterm> | |||
|
41 | - Exclude files or directories by typing in the names or extensions. Patterns are separated by spaces | |||
|
42 | - e.g. <literal>bin obj *.bak *.~?? *.jar *.[Tt]mp</literal>. The first two entries refer to directories, the | |||
|
43 | - other four to files. | |||
|
44 | - </para> | |||
|
45 | - <para> | |||
|
46 | - This exclude pattern will affect all your projects. It is not versioned, so it | |||
|
47 | - will not affect other users. In contrast you can also use the versioned svn:ignore | |||
|
48 | - property to exclude files or directories from version control. You can set the svn:ignore | |||
|
49 | - property using the | |||
|
50 | + Ausgeschlossene, unversionierte Dateien werden nicht angezeigt | |||
|
51 | + in z.B. dem Übertragen Dialog. Ausserdem werden solche Dateien | |||
|
52 | + beim Importieren in ein Projektarchiv ignoriert. | |||
|
53 | + Schliessen Sie Dateien oder Ordner aus durch Angabe von | |||
|
54 | + Dateinamen oder Erweiterungen. Die einzelnen Muster werden | |||
|
55 | + durch Leerzeichen voneinander getrennt. Zum Beispiel | |||
|
56 | + <literal>bin obj *.bak *.~?? *.jar *.[Tt]mp</literal>. | |||
|
57 | + Die ersten beiden Muster beziehen sich auf Ordner, die | |||
|
58 | + restlichen vier auf Dateien. | |||
|
59 | + </para> | |||
|
60 | + <para> | |||
|
61 | + Diese Auschluss-Muster beziehen sich auf alle Ihre Projekte. | |||
|
62 | + Sie werden nicht versioniert, d.h. andere Benutzer werden davon | |||
|
63 | + nichts mitbekommen. Im Gegensatz dazu können Sie jedoch auch | |||
|
64 | + die versionierte Eigenschaft svn:ignore verwenden, um Dateien | |||
|
65 | + und/oder Ordner von der Versionskontrolle auszuschliessen. | |||
|
66 | + Sie können die svn:ignore Eigenschaft setzen durch den | |||
|
67 | <menuchoice> | |||
|
68 | - <guimenuitem>Add to Ignore List</guimenuitem> | |||
|
69 | + <guimenuitem>Ignorieren</guimenuitem> | |||
|
70 | </menuchoice> | |||
|
71 | - command. After commiting every other user will have the same | |||
|
72 | - svn:ignore property set for this project / directory as you. | |||
|
73 | + Befehl. Nach dem Übertragen wird jeder Benutzer dieselbe | |||
|
74 | + svn:ignore Eigenschaft für das Projekt oder den Ordner | |||
|
75 | + haben wie Sie. | |||
|
76 | </para> | |||
|
77 | </listitem> | |||
|
78 | </varlistentry> | |||
|
79 | +### Translate ### | |||
|
80 | ||||
|
81 | <varlistentry> | |||
|
82 | <term>Default number of log messages</term> | |||
|
83 | @@ -1608,16 +1618,36 @@ | |||
|
84 | </varlistentry> | |||
|
85 | ||||
|
86 | <varlistentry> | |||
|
87 | - <term>Short date / time format in log messages</term> | |||
|
88 | - <listitem> | |||
|
89 | - <para>If the standard long messages use up too much space on your sceen use the short format.</para> | |||
|
90 | + <term>Edit...</term> | |||
|
91 | + <listitem> | |||
|
92 | + <para>... the subversion configuration file directly. Some settings cannot be modified by TortoiseSVN.</para> | |||
|
93 | </listitem> | |||
|
94 | </varlistentry> | |||
|
95 | ||||
|
96 | <varlistentry> | |||
|
97 | - <term>Edit...</term> | |||
|
98 | - <listitem> | |||
|
99 | - <para>... the subversion configuration file directly. Some settings cannot be modified by TortoiseSVN.</para> | |||
|
100 | + <term>Short date / time format in log messages</term> | |||
|
101 | + <listitem> | |||
|
102 | + <para>If the standard long messages use up too much space on your sceen use the short format.</para> | |||
|
103 | + </listitem> | |||
|
104 | + </varlistentry> | |||
|
105 | + | |||
|
106 | + <varlistentry> | |||
|
107 | + <term>Set filedates to "last commit time"</term> | |||
|
108 | + <listitem> | |||
|
109 | + <para> | |||
|
110 | + This option tells TortoiseSVN to set the filedates to the last commit time | |||
|
111 | + when doing a checkout or an update. Otherwise TortoiseSVN will use | |||
|
112 | + the current date. | |||
|
113 | + </para> | |||
|
114 | + </listitem> | |||
|
115 | + </varlistentry> | |||
|
116 | + | |||
|
117 | + <varlistentry> | |||
|
118 | + <term>Close windows automatically</term> | |||
|
119 | + <listitem> | |||
|
120 | + <para> | |||
|
121 | + TortoiseSVN will automatically close all progress dialogs when the action is finished. | |||
|
122 | + </para> | |||
|
123 | </listitem> | |||
|
124 | </varlistentry> | |||
|
125 | ||||
|
126 | @@ -1629,15 +1659,15 @@ | |||
|
127 | </varlistentry> | |||
|
128 | ||||
|
129 | <varlistentry> | |||
|
130 | - <term>Set filedates to "last commit time"</term> | |||
|
131 | - <listitem> | |||
|
132 | - <para> | |||
|
133 | - This option tells TortoiseSVN to set the filedates to the last commit time | |||
|
134 | - when doing a checkout or an update. Otherwise TortoiseSVN will use | |||
|
135 | - the current date. | |||
|
136 | + <term>Minimum logsize in chars</term> | |||
|
137 | + <listitem> | |||
|
138 | + <para> | |||
|
139 | + The minimum length of a log message for a commit. If you enter | |||
|
140 | + a shorter message than specified here, the commit is disabled. | |||
|
141 | </para> | |||
|
142 | </listitem> | |||
|
143 | </varlistentry> | |||
|
144 | + | |||
|
145 | <varlistentry> | |||
|
146 | <term>Don't remove log messages when cancelling a commit</term> | |||
|
147 | <listitem> | |||
|
148 | @@ -1648,11 +1678,14 @@ | |||
|
149 | </para> | |||
|
150 | </listitem> | |||
|
151 | </varlistentry> | |||
|
152 | + | |||
|
153 | <varlistentry> | |||
|
154 | - <term>Close windows automatically</term> | |||
|
155 | - <listitem> | |||
|
156 | - <para> | |||
|
157 | - TortoiseSVN will automatically close all progress dialogs when the action is finished. | |||
|
158 | + <term>Show BugID/Issue-Nr. Box</term> | |||
|
159 | + <listitem> | |||
|
160 | + <para> | |||
|
161 | + Shows a textbox in the commit dialog where you can enter | |||
|
162 | + a BugID or Issue-Nr. from a bugtracker to associate the | |||
|
163 | + commit with that ID/number. | |||
|
164 | </para> | |||
|
165 | </listitem> | |||
|
166 | </varlistentry> | |||
|
167 | @@ -1673,10 +1706,32 @@ | |||
|
168 | Sie können auch alle überlagerten Icons deaktivieren, aber wo liegt der Spaß darin? | |||
|
169 | </para> | |||
|
170 | <para> | |||
|
171 | + Die <term>Ausschluss Pfade</term> sagen TortoiseSVN für welche | |||
|
172 | + Pfade die überlagerten Icons <emphasis>nicht</emphasis> gezeichnet | |||
|
173 | + werden sollen. Dies ist nützlich wenn Sie zum Beispiel sehr grosse | |||
|
174 | + Arbeitskopien haben, welche grosse externe Bibliotheken, welche Sie | |||
|
175 | + selbst nie ändern werden enthalten. Sie können dann diese Pfade | |||
|
176 | + ausschliessen. Zum Beispiel: | |||
|
177 | + </para> | |||
|
178 | + <para> | |||
|
179 | + <filename>f:\development\SVN\Subversion</filename> deaktiviert | |||
|
180 | + die überlagerten Icons <emphasis>nur</emphasis> für diesen speziellen | |||
|
181 | + Ordner. Sie können die Icons noch immer für alle Dateien und Ordner | |||
|
182 | + innerhalb sehen. | |||
|
183 | + </para> | |||
|
184 | + <para> | |||
|
185 | + <filename>f:\development\SVN\Subversion*</filename> deaktiviert die | |||
|
186 | + überlagerten Icons für <emphasis>alle</emphasis> Dateien und Ordner | |||
|
187 | + welcher Pfad mit <filename>f:\development\SVN\Subversion</filename> | |||
|
188 | + beginnt. Das bedeutet dass auch für alle Dateien und Ordner innerhalb | |||
|
189 | + keine überlagerten Icons angezeigt werden. | |||
|
190 | + </para> | |||
|
191 | + <para> | |||
|
192 | Ausserdem können Sie angeben, welche Befehle im | |||
|
193 | Hauptkontextmenu des Explorer angezeigt werden sollen und welche | |||
|
194 | Sie lieber im Untermenu haben wollen. | |||
|
195 | </para> | |||
|
196 | + </sect2> | |||
|
197 | <sect2 id="tsvn-DUG-settings-network"> | |||
|
198 | <?dbhh topicname="HIDD_SETTINGSPROXY"?> | |||
|
199 | <title>Der Einstellungsdialog, Netzwerkseite</title> | |||
|
200 | Index: trunk/doc/source/en/tsvn_ch04.xml | |||
|
201 | =================================================================== | |||
|
202 | diff --git a/trunk/doc/source/en/tsvn_ch04.xml b/trunk/doc/source/en/tsvn_ch04.xml | |||
|
203 | --- a/trunk/doc/source/en/tsvn_ch04.xml (revision 1487) | |||
|
204 | +++ b/trunk/doc/source/en/tsvn_ch04.xml (revision 1488) | |||
|
205 | @@ -1457,7 +1457,7 @@ | |||
|
206 | <varlistentry> | |||
|
207 | <term>Language</term> | |||
|
208 | <listitem> | |||
|
209 | - <para>Selects your user interface language. What did you expect?</para> | |||
|
210 | + <para>Selects your user interface language. What else did you expect?</para> | |||
|
211 | </listitem> | |||
|
212 | </varlistentry> | |||
|
213 | ||||
|
214 | @@ -1468,6 +1468,9 @@ | |||
|
215 | <indexterm> | |||
|
216 | <primary>exclude pattern</primary> | |||
|
217 | </indexterm> | |||
|
218 | + Exclude patterns are used to prevent unversioned files from | |||
|
219 | + showing up e.g. in the commit dialog. Files matching the | |||
|
220 | + patterns are also ignored by an import. | |||
|
221 | Exclude files or directories by typing in the names or extensions. Patterns are separated by spaces | |||
|
222 | e.g. <literal>bin obj *.bak *.~?? *.jar *.[Tt]mp</literal>. The first two entries refer to directories, the | |||
|
223 | other four to files. | |||
|
224 | @@ -1499,23 +1502,16 @@ | |||
|
225 | </varlistentry> | |||
|
226 | ||||
|
227 | <varlistentry> | |||
|
228 | + <term>Edit...</term> | |||
|
229 | + <listitem> | |||
|
230 | + <para>... the subversion configuration file directly. Some settings cannot be modified by TortoiseSVN.</para> | |||
|
231 | + </listitem> | |||
|
232 | + </varlistentry> | |||
|
233 | + | |||
|
234 | + <varlistentry> | |||
|
235 | <term>Short date / time format in log messages</term> | |||
|
236 | <listitem> | |||
|
237 | <para>If the standard long messages use up too much space on your sceen use the short format.</para> | |||
|
238 | - </listitem> | |||
|
239 | - </varlistentry> | |||
|
240 | - | |||
|
241 | - <varlistentry> | |||
|
242 | - <term>Edit...</term> | |||
|
243 | - <listitem> | |||
|
244 | - <para>... the subversion configuration file directly. Some settings cannot be modified by TortoiseSVN.</para> | |||
|
245 | - </listitem> | |||
|
246 | - </varlistentry> | |||
|
247 | - | |||
|
248 | - <varlistentry> | |||
|
249 | - <term>Check for newer versions</term> | |||
|
250 | - <listitem> | |||
|
251 | - <para>If checked, TortoiseSVN will check once a week if an update is available</para> | |||
|
252 | </listitem> | |||
|
253 | </varlistentry> | |||
|
254 | ||||
|
255 | @@ -1529,6 +1525,33 @@ | |||
|
256 | </para> | |||
|
257 | </listitem> | |||
|
258 | </varlistentry> | |||
|
259 | + | |||
|
260 | + <varlistentry> | |||
|
261 | + <term>Close windows automatically</term> | |||
|
262 | + <listitem> | |||
|
263 | + <para> | |||
|
264 | + TortoiseSVN will automatically close all progress dialogs when the action is finished. | |||
|
265 | + </para> | |||
|
266 | + </listitem> | |||
|
267 | + </varlistentry> | |||
|
268 | + | |||
|
269 | + <varlistentry> | |||
|
270 | + <term>Check for newer versions</term> | |||
|
271 | + <listitem> | |||
|
272 | + <para>If checked, TortoiseSVN will check once a week if an update is available</para> | |||
|
273 | + </listitem> | |||
|
274 | + </varlistentry> | |||
|
275 | + | |||
|
276 | + <varlistentry> | |||
|
277 | + <term>Minimum logsize in chars</term> | |||
|
278 | + <listitem> | |||
|
279 | + <para> | |||
|
280 | + The minimum length of a log message for a commit. If you enter | |||
|
281 | + a shorter message than specified here, the commit is disabled. | |||
|
282 | + </para> | |||
|
283 | + </listitem> | |||
|
284 | + </varlistentry> | |||
|
285 | + | |||
|
286 | <varlistentry> | |||
|
287 | <term>Don't remove log messages when cancelling a commit</term> | |||
|
288 | <listitem> | |||
|
289 | @@ -1539,11 +1562,14 @@ | |||
|
290 | </para> | |||
|
291 | </listitem> | |||
|
292 | </varlistentry> | |||
|
293 | + | |||
|
294 | <varlistentry> | |||
|
295 | - <term>Close windows automatically</term> | |||
|
296 | - <listitem> | |||
|
297 | - <para> | |||
|
298 | - TortoiseSVN will automatically close all progress dialogs when the action is finished. | |||
|
299 | + <term>Show BugID/Issue-Nr. Box</term> | |||
|
300 | + <listitem> | |||
|
301 | + <para> | |||
|
302 | + Shows a textbox in the commit dialog where you can enter | |||
|
303 | + a BugID or Issue-Nr. from a bugtracker to associate the | |||
|
304 | + commit with that ID/number. | |||
|
305 | </para> | |||
|
306 | </listitem> | |||
|
307 | </varlistentry> | |||
|
308 | @@ -1552,7 +1578,7 @@ | |||
|
309 | </sect2> | |||
|
310 | <sect2 id="tsvn-DUG-settings-overlay"> | |||
|
311 | <?dbhh topicname="HIDD_SETTINGSOVERLAY"?> | |||
|
312 | - <title>The Settings Dialog, Overlay Tab</title> | |||
|
313 | + <title>The Settings Dialog, Look and Feel Tab</title> | |||
|
314 | <para> | |||
|
315 | <figure id="tsvn-DUG-settings-dia-2"> | |||
|
316 | <title>The Settings Dialog, Overlay Tab</title> | |||
|
317 | @@ -1560,8 +1586,27 @@ | |||
|
318 | </figure> | |||
|
319 | This tab allows you to choose, for which items TortoiseSVN shall | |||
|
320 | display icon overlays. If you feel that your icon overlays are very | |||
|
321 | - slow (explore is not responsive), uncheck the "show changed directories" box. | |||
|
322 | + slow (explorer is not responsive), uncheck the "show changed directories" box. | |||
|
323 | You can even disable all icon overlays, but where's the fun in that? | |||
|
324 | + </para> | |||
|
325 | + <para> | |||
|
326 | + The <term>Exclude Paths</term> are used to tell TortoiseSVN for which | |||
|
327 | + paths <emphasis>not</emphasis> to show icon overlays and status columns. | |||
|
328 | + This is useful if you have some very big working copies containing | |||
|
329 | + only libraries which you won't change at all and therefore don't | |||
|
330 | + need the overlays. For example: | |||
|
331 | + </para> | |||
|
332 | + <para> | |||
|
333 | + <filename>f:\development\SVN\Subversion</filename> will disable | |||
|
334 | + the overlays on <emphasis>only</emphasis> that specific folder. You | |||
|
335 | + still can see the overlays on all files and folder inside that folder. | |||
|
336 | + </para> | |||
|
337 | + <para> | |||
|
338 | + <filename>f:\development\SVN\Subversion*</filename> will disable the | |||
|
339 | + overlays on <emphasis>all</emphasis> files and folders which path | |||
|
340 | + starts with <filename>f:\development\SVN\Subversion</filename>. That | |||
|
341 | + means you won't see overlays for all files and folder below that | |||
|
342 | + path. | |||
|
343 | </para> | |||
|
344 | <para> | |||
|
345 | You can also specifiy here which of the TortoiseSVN contex menu | |||
|
346 | Index: trunk/src/Changelog.txt | |||
|
347 | =================================================================== | |||
|
348 | diff --git a/trunk/src/Changelog.txt b/trunk/src/Changelog.txt | |||
|
349 | --- a/trunk/src/Changelog.txt (revision 1487) | |||
|
350 | +++ b/trunk/src/Changelog.txt (revision 1488) | |||
|
351 | @@ -1,3 +1,5 @@ | |||
|
352 | +- ADD: Option to exclude specific paths from showing | |||
|
353 | + icon overlays. (Stefan) | |||
|
354 | - ADD: On Win2k and later, the authentication data is now | |||
|
355 | encrypted before saved. The encryption is not available | |||
|
356 | for the other OS's. (Stefan) | |||
|
357 | Index: trunk/src/Resources/TortoiseProcENG.rc | |||
|
358 | =================================================================== | |||
|
359 | diff --git a/trunk/src/Resources/TortoiseProcENG.rc b/trunk/src/Resources/TortoiseProcENG.rc | |||
|
360 | --- a/trunk/src/Resources/TortoiseProcENG.rc (revision 1487) | |||
|
361 | +++ b/trunk/src/Resources/TortoiseProcENG.rc (revision 1488) | |||
|
362 | @@ -398,27 +398,31 @@ | |||
|
363 | BEGIN | |||
|
364 | CONTROL "&Indicate folders with changed contents", | |||
|
365 | IDC_CHANGEDDIRS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12, | |||
|
366 | - 20,145,10 | |||
|
367 | + 20,206,10 | |||
|
368 | CONTROL "&Removable drives",IDC_REMOVABLE,"Button", | |||
|
369 | - BS_AUTOCHECKBOX | WS_TABSTOP,18,66,130,10 | |||
|
370 | + BS_AUTOCHECKBOX | WS_TABSTOP,18,58,130,10 | |||
|
371 | CONTROL "&Network drives",IDC_NETWORK,"Button",BS_AUTOCHECKBOX | | |||
|
372 | - WS_TABSTOP,18,76,130,10 | |||
|
373 | + WS_TABSTOP,18,68,130,10 | |||
|
374 | CONTROL "&Fixed drives",IDC_FIXED,"Button",BS_AUTOCHECKBOX | | |||
|
375 | - WS_TABSTOP,18,87,127,10 | |||
|
376 | + WS_TABSTOP,18,79,127,10 | |||
|
377 | CONTROL "&CD-ROM",IDC_CDROM,"Button",BS_AUTOCHECKBOX | | |||
|
378 | - WS_TABSTOP,159,66,118,10 | |||
|
379 | - GROUPBOX "Drive Types",IDC_DRIVEGROUP,12,52,274,50 | |||
|
380 | + WS_TABSTOP,166,58,118,10 | |||
|
381 | + GROUPBOX "Drive Types",IDC_DRIVEGROUP,12,44,274,50 | |||
|
382 | CONTROL "RAM drives",IDC_RAM,"Button",BS_AUTOCHECKBOX | | |||
|
383 | - WS_TABSTOP,159,76,119,10 | |||
|
384 | + WS_TABSTOP,166,68,119,10 | |||
|
385 | CONTROL "Unknown drives",IDC_UNKNOWN,"Button",BS_AUTOCHECKBOX | | |||
|
386 | - WS_TABSTOP,159,86,118,10 | |||
|
387 | + WS_TABSTOP,166,78,118,10 | |||
|
388 | CONTROL "Show overlays only in explorer",IDC_ONLYEXPLORER,"Button", | |||
|
389 | - BS_AUTOCHECKBOX | WS_TABSTOP,12,33,122,10 | |||
|
390 | - GROUPBOX "Icon Overlays / Status Columns",IDC_STATIC,7,7,286,103 | |||
|
391 | - GROUPBOX "Context Menu",IDC_STATIC,7,113,286,97 | |||
|
392 | + BS_AUTOCHECKBOX | WS_TABSTOP,12,33,190,10 | |||
|
393 | + GROUPBOX "Icon Overlays / Status Columns",IDC_STATIC,7,7,286,118 | |||
|
394 | + GROUPBOX "Context Menu",IDC_STATIC,7,130,286,80 | |||
|
395 | CONTROL "",IDC_MENULIST,"SysListView32",LVS_REPORT | | |||
|
396 | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | | |||
|
397 | - WS_BORDER | WS_TABSTOP,12,125,274,78 | |||
|
398 | + WS_BORDER | WS_TABSTOP,12,140,274,63 | |||
|
399 | + LTEXT "Exclude paths:",IDC_STATIC,12,106,85,8 | |||
|
400 | + EDITTEXT IDC_EXCLUDEPATHS,102,96,184,25,ES_MULTILINE | | |||
|
401 | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | | |||
|
402 | + WS_VSCROLL | |||
|
403 | END | |||
|
404 | ||||
|
405 | IDD_SETTINGSPROXY DIALOGEX 0, 0, 300, 217 | |||
|
406 | @@ -860,7 +864,7 @@ | |||
|
407 | RIGHTMARGIN, 293 | |||
|
408 | VERTGUIDE, 12 | |||
|
409 | VERTGUIDE, 18 | |||
|
410 | - VERTGUIDE, 159 | |||
|
411 | + VERTGUIDE, 166 | |||
|
412 | VERTGUIDE, 286 | |||
|
413 | TOPMARGIN, 7 | |||
|
414 | BOTTOMMARGIN, 210 | |||
|
415 | @@ -1377,6 +1381,8 @@ | |||
|
416 | "If activated, prevents the overlays from showing in ""save as.."" or ""open"" dialogs" | |||
|
417 | IDS_SETTINGS_MENULAYOUT_TT | |||
|
418 | "Check those menu entries you want to appear in the top context menu instead of the submenu" | |||
|
419 | + IDS_SETTINGS_EXCLUDELIST_TT | |||
|
420 | + "A newline separated list of paths for which no icon overlays are shown.\nIf you add an ""*"" char at the end of a path, then all files and subdirs inside that path are excluded too.\nAn empty list will allow overlays on all paths." | |||
|
421 | END | |||
|
422 | ||||
|
423 | STRINGTABLE | |||
|
424 | Index: trunk/src/TortoiseProc/SetOverlayPage.cpp | |||
|
425 | =================================================================== | |||
|
426 | diff --git a/trunk/src/TortoiseProc/SetOverlayPage.cpp b/trunk/src/TortoiseProc/SetOverlayPage.cpp | |||
|
427 | --- a/trunk/src/TortoiseProc/SetOverlayPage.cpp (revision 1487) | |||
|
428 | +++ b/trunk/src/TortoiseProc/SetOverlayPage.cpp (revision 1488) | |||
|
429 | @@ -20,6 +20,7 @@ | |||
|
430 | #include "TortoiseProc.h" | |||
|
431 | #include "SetOverlayPage.h" | |||
|
432 | #include "Globals.h" | |||
|
433 | +#include ".\setoverlaypage.h" | |||
|
434 | ||||
|
435 | ||||
|
436 | // CSetOverlayPage dialog | |||
|
437 | @@ -35,6 +36,7 @@ | |||
|
438 | , m_bRAM(FALSE) | |||
|
439 | , m_bUnknown(FALSE) | |||
|
440 | , m_bOnlyExplorer(FALSE) | |||
|
441 | + , m_sExcludePaths(_T("")) | |||
|
442 | { | |||
|
443 | m_regShowChangedDirs = CRegDWORD(_T("Software\\TortoiseSVN\\RecursiveOverlay")); | |||
|
444 | m_regOnlyExplorer = CRegDWORD(_T("Software\\TortoiseSVN\\OverlaysOnlyInExplorer"), FALSE); | |||
|
445 | @@ -45,6 +47,7 @@ | |||
|
446 | m_regDriveMaskRAM = CRegDWORD(_T("Software\\TortoiseSVN\\DriveMaskRAM")); | |||
|
447 | m_regDriveMaskUnknown = CRegDWORD(_T("Software\\TortoiseSVN\\DriveMaskUnknown")); | |||
|
448 | m_regTopmenu = CRegDWORD(_T("Software\\TortoiseSVN\\ContextMenuEntries"), MENUCHECKOUT | MENUUPDATE | MENUCOMMIT); | |||
|
449 | + m_regExcludePaths = CRegString(_T("Software\\TortoiseSVN\\OverlayExcludeList")); | |||
|
450 | ||||
|
451 | m_bShowChangedDirs = m_regShowChangedDirs; | |||
|
452 | m_bOnlyExplorer = m_regOnlyExplorer; | |||
|
453 | @@ -55,6 +58,8 @@ | |||
|
454 | m_bRAM = m_regDriveMaskRAM; | |||
|
455 | m_bUnknown = m_regDriveMaskUnknown; | |||
|
456 | m_topmenu = m_regTopmenu; | |||
|
457 | + m_sExcludePaths = m_regExcludePaths; | |||
|
458 | + m_sExcludePaths.Replace(_T("\n"), _T("\r\n")); | |||
|
459 | } | |||
|
460 | ||||
|
461 | CSetOverlayPage::~CSetOverlayPage() | |||
|
462 | @@ -74,6 +79,7 @@ | |||
|
463 | DDX_Control(pDX, IDC_DRIVEGROUP, m_cDriveGroup); | |||
|
464 | DDX_Check(pDX, IDC_ONLYEXPLORER, m_bOnlyExplorer); | |||
|
465 | DDX_Control(pDX, IDC_MENULIST, m_cMenuList); | |||
|
466 | + DDX_Text(pDX, IDC_EXCLUDEPATHS, m_sExcludePaths); | |||
|
467 | } | |||
|
468 | ||||
|
469 | ||||
|
470 | @@ -87,6 +93,7 @@ | |||
|
471 | ON_BN_CLICKED(IDC_RAM, OnBnClickedRam) | |||
|
472 | ON_BN_CLICKED(IDC_ONLYEXPLORER, OnBnClickedOnlyexplorer) | |||
|
473 | ON_NOTIFY(LVN_ITEMCHANGED, IDC_MENULIST, OnLvnItemchangedMenulist) | |||
|
474 | + ON_EN_CHANGE(IDC_EXCLUDEPATHS, OnEnChangeExcludepaths) | |||
|
475 | END_MESSAGE_MAP() | |||
|
476 | ||||
|
477 | ||||
|
478 | @@ -103,6 +110,9 @@ | |||
|
479 | m_regDriveMaskRAM = m_bRAM; | |||
|
480 | m_regDriveMaskUnknown = m_bUnknown; | |||
|
481 | m_regTopmenu = m_topmenu; | |||
|
482 | + m_sExcludePaths.Replace(_T("\r"), _T("")); | |||
|
483 | + m_regExcludePaths = m_sExcludePaths; | |||
|
484 | + m_sExcludePaths.Replace(_T("\n"), _T("\r\n")); | |||
|
485 | } | |||
|
486 | } | |||
|
487 | ||||
|
488 | @@ -116,7 +126,7 @@ | |||
|
489 | m_tooltips.AddTool(IDC_CHANGEDDIRS, IDS_SETTINGS_CHANGEDDIRS_TT); | |||
|
490 | m_tooltips.AddTool(IDC_ONLYEXPLORER, IDS_SETTINGS_ONLYEXPLORER_TT); | |||
|
491 | m_tooltips.AddTool(IDC_MENULIST, IDS_SETTINGS_MENULAYOUT_TT); | |||
|
492 | - | |||
|
493 | + m_tooltips.AddTool(IDC_EXCLUDEPATHS, IDS_SETTINGS_EXCLUDELIST_TT); | |||
|
494 | ||||
|
495 | m_cMenuList.SetExtendedStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); | |||
|
496 | ||||
|
497 | @@ -280,3 +290,8 @@ | |||
|
498 | } // if (m_cMenuList.GetItemCount() > 0) | |||
|
499 | *pResult = 0; | |||
|
500 | } | |||
|
501 | + | |||
|
502 | +void CSetOverlayPage::OnEnChangeExcludepaths() | |||
|
503 | +{ | |||
|
504 | + SetModified(); | |||
|
505 | +} | |||
|
506 | Index: trunk/src/TortoiseProc/SetOverlayPage.h | |||
|
507 | =================================================================== | |||
|
508 | diff --git a/trunk/src/TortoiseProc/SetOverlayPage.h b/trunk/src/TortoiseProc/SetOverlayPage.h | |||
|
509 | --- a/trunk/src/TortoiseProc/SetOverlayPage.h (revision 1487) | |||
|
510 | +++ b/trunk/src/TortoiseProc/SetOverlayPage.h (revision 1488) | |||
|
511 | @@ -92,6 +92,8 @@ | |||
|
512 | CIconStatic m_cDriveGroup; | |||
|
513 | BOOL m_bInitialized; | |||
|
514 | CRegDWORD m_regTopmenu; | |||
|
515 | + CRegString m_regExcludePaths; | |||
|
516 | + CString m_sExcludePaths; | |||
|
517 | ||||
|
518 | CImageList m_imgList; | |||
|
519 | CListCtrl m_cMenuList; | |||
|
520 | @@ -110,4 +112,5 @@ | |||
|
521 | virtual BOOL OnApply(); | |||
|
522 | afx_msg void OnBnClickedOnlyexplorer(); | |||
|
523 | afx_msg void OnLvnItemchangedMenulist(NMHDR *pNMHDR, LRESULT *pResult); | |||
|
524 | + afx_msg void OnEnChangeExcludepaths(); | |||
|
525 | }; | |||
|
526 | Index: trunk/src/TortoiseProc/resource.h | |||
|
527 | =================================================================== | |||
|
528 | diff --git a/trunk/src/TortoiseProc/resource.h b/trunk/src/TortoiseProc/resource.h | |||
|
529 | --- a/trunk/src/TortoiseProc/resource.h (revision 1487) | |||
|
530 | +++ b/trunk/src/TortoiseProc/resource.h (revision 1488) | |||
|
531 | @@ -179,6 +179,7 @@ | |||
|
532 | #define IDC_MINLOGSIZE 1077 | |||
|
533 | #define IDC_BUGID 1077 | |||
|
534 | #define IDC_WCURL 1077 | |||
|
535 | +#define IDC_EXCLUDEPATHS 1077 | |||
|
536 | #define IDC_DRIVEGROUP 1079 | |||
|
537 | #define IDC_PROXYGROUP 1080 | |||
|
538 | #define IDC_SSHGROUP 1081 | |||
|
539 | @@ -427,6 +428,7 @@ | |||
|
540 | #define IDS_SETTINGS_CHECKNEWER_TT 3100 | |||
|
541 | #define IDS_SETTINGS_ONLYEXPLORER_TT 3101 | |||
|
542 | #define IDS_SETTINGS_MENULAYOUT_TT 3102 | |||
|
543 | +#define IDS_SETTINGS_EXCLUDELIST_TT 3103 | |||
|
544 | #define IDS_CHECKNEWER_YOURVERSION 3200 | |||
|
545 | #define IDS_CHECKNEWER_CURRENTVERSION 3201 | |||
|
546 | #define IDS_CHECKNEWER_YOURUPTODATE 3202 | |||
|
547 | Index: trunk/src/TortoiseShell/ShellCache.h | |||
|
548 | =================================================================== | |||
|
549 | diff --git a/trunk/src/TortoiseShell/ShellCache.h b/trunk/src/TortoiseShell/ShellCache.h | |||
|
550 | --- a/trunk/src/TortoiseShell/ShellCache.h (revision 1487) | |||
|
551 | +++ b/trunk/src/TortoiseShell/ShellCache.h (revision 1488) | |||
|
552 | @@ -21,9 +21,11 @@ | |||
|
553 | #include "globals.h" | |||
|
554 | #include <tchar.h> | |||
|
555 | #include <string> | |||
|
556 | +#include <vector> | |||
|
557 | #include "registry.h" | |||
|
558 | ||||
|
559 | #define REGISTRYTIMEOUT 2000 | |||
|
560 | +#define EXCLUDELISTTIMEOUT 5000 | |||
|
561 | #define DRIVETYPETIMEOUT 300000 // 5 min | |||
|
562 | #define NUMBERFMTTIMEOUT 300000 | |||
|
563 | class ShellCache | |||
|
564 | @@ -39,12 +41,14 @@ | |||
|
565 | driveremove = CRegStdWORD(_T("Software\\TortoiseSVN\\DriveMaskRemovable")); | |||
|
566 | driveram = CRegStdWORD(_T("Software\\TortoiseSVN\\DriveMaskRAM")); | |||
|
567 | driveunknown = CRegStdWORD(_T("Software\\TortoiseSVN\\DriveMaskUnknown")); | |||
|
568 | + excludelist = CRegStdString(_T("Software\\TortoiseSVN\\OverlayExcludeList")); | |||
|
569 | recursiveticker = GetTickCount(); | |||
|
570 | folderoverlayticker = GetTickCount(); | |||
|
571 | driveticker = recursiveticker; | |||
|
572 | drivetypeticker = recursiveticker; | |||
|
573 | langticker = recursiveticker; | |||
|
574 | - columnrevformatticker = langticker; | |||
|
575 | + columnrevformatticker = recursiveticker; | |||
|
576 | + excludelistticker = recursiveticker; | |||
|
577 | menulayout = CRegStdWORD(_T("Software\\TortoiseSVN\\ContextMenuEntries"), MENUCHECKOUT | MENUUPDATE | MENUCOMMIT); | |||
|
578 | langid = CRegStdWORD(_T("Software\\TortoiseSVN\\LanguageID"), 1033); | |||
|
579 | blockstatus = CRegStdWORD(_T("Software\\TortoiseSVN\\BlockStatus"), 0); | |||
|
580 | @@ -177,6 +181,21 @@ | |||
|
581 | return FALSE; | |||
|
582 | if ((drivetype == DRIVE_UNKNOWN)&&(IsUnknown())) | |||
|
583 | return FALSE; | |||
|
584 | + | |||
|
585 | + ExcludeListValid(); | |||
|
586 | + for (std::vector<stdstring>::iterator I = exvector.begin(); I != exvector.end(); ++I) | |||
|
587 | + { | |||
|
588 | + if (I->empty()) | |||
|
589 | + continue; | |||
|
590 | + if (I->at(I->size()-1)=='*') | |||
|
591 | + { | |||
|
592 | + stdstring str = I->substr(0, I->size()-1); | |||
|
593 | + if (_tcsnicmp(str.c_str(), path, str.size())==0) | |||
|
594 | + return FALSE; | |||
|
595 | + } | |||
|
596 | + else if (_tcsicmp(I->c_str(), path)==0) | |||
|
597 | + return FALSE; | |||
|
598 | + } | |||
|
599 | return TRUE; | |||
|
600 | } | |||
|
601 | DWORD GetLangID() | |||
|
602 | @@ -218,6 +237,32 @@ | |||
|
603 | driveremove.read(); | |||
|
604 | } | |||
|
605 | } | |||
|
606 | + void ExcludeListValid() | |||
|
607 | + { | |||
|
608 | + if ((GetTickCount() - EXCLUDELISTTIMEOUT)>excludelistticker) | |||
|
609 | + { | |||
|
610 | + excludelistticker = GetTickCount(); | |||
|
611 | + excludelist.read(); | |||
|
612 | + if (excludeliststr.compare((stdstring)excludelist)==0) | |||
|
613 | + return; | |||
|
614 | + excludeliststr = (stdstring)excludelist; | |||
|
615 | + exvector.clear(); | |||
|
616 | + int pos = 0, pos_ant = 0; | |||
|
617 | + pos = excludeliststr.find(_T("\n"), pos_ant); | |||
|
618 | + while (pos != stdstring::npos) | |||
|
619 | + { | |||
|
620 | + stdstring token = excludeliststr.substr(pos_ant, pos-pos_ant); | |||
|
621 | + exvector.push_back(token); | |||
|
622 | + pos_ant = pos+1; | |||
|
623 | + pos = excludeliststr.find(_T("\n"), pos_ant); | |||
|
624 | + } | |||
|
625 | + if (!excludeliststr.empty()) | |||
|
626 | + { | |||
|
627 | + exvector.push_back(excludeliststr.substr(pos_ant, excludeliststr.size()-1)); | |||
|
628 | + } | |||
|
629 | + excludeliststr = (stdstring)excludelist; | |||
|
630 | + } | |||
|
631 | + } | |||
|
632 | CRegStdWORD blockstatus; | |||
|
633 | CRegStdWORD langid; | |||
|
634 | CRegStdWORD showrecursive; | |||
|
635 | @@ -229,6 +274,9 @@ | |||
|
636 | CRegStdWORD driveram; | |||
|
637 | CRegStdWORD driveunknown; | |||
|
638 | CRegStdWORD menulayout; | |||
|
639 | + CRegStdString excludelist; | |||
|
640 | + stdstring excludeliststr; | |||
|
641 | + std::vector<stdstring> exvector; | |||
|
642 | DWORD recursiveticker; | |||
|
643 | DWORD folderoverlayticker; | |||
|
644 | DWORD driveticker; | |||
|
645 | @@ -237,6 +285,7 @@ | |||
|
646 | DWORD langticker; | |||
|
647 | DWORD blockstatusticker; | |||
|
648 | DWORD columnrevformatticker; | |||
|
649 | + DWORD excludelistticker; | |||
|
650 | UINT drivetypecache[27]; | |||
|
651 | TCHAR drivetypepathcache[MAX_PATH]; | |||
|
652 | NUMBERFMT columnrevformat; No newline at end of file |
@@ -0,0 +1,192 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import os | |||
|
22 | ||||
|
23 | import mock | |||
|
24 | import pytest | |||
|
25 | ||||
|
26 | from rhodecode.controllers.files import FilesController | |||
|
27 | from rhodecode.lib import helpers as h | |||
|
28 | from rhodecode.lib.compat import OrderedDict | |||
|
29 | from rhodecode.lib.ext_json import json | |||
|
30 | from rhodecode.lib.vcs import nodes | |||
|
31 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |||
|
32 | from rhodecode.lib.vcs.conf import settings | |||
|
33 | from rhodecode.lib.vcs.nodes import FileNode | |||
|
34 | from rhodecode.model.db import Repository | |||
|
35 | from rhodecode.model.scm import ScmModel | |||
|
36 | from rhodecode.tests import ( | |||
|
37 | url, TEST_USER_ADMIN_LOGIN, assert_session_flash, assert_not_in_session_flash) | |||
|
38 | from rhodecode.tests.fixture import Fixture | |||
|
39 | from rhodecode.tests.utils import commit_change | |||
|
40 | ||||
|
41 | fixture = Fixture() | |||
|
42 | ||||
|
43 | ||||
|
44 | @pytest.mark.usefixtures("autologin_user", "app") | |||
|
45 | class TestSideBySideDiff(object): | |||
|
46 | ||||
|
47 | def test_diff_side_by_side(self, app, backend, backend_stub): | |||
|
48 | f_path = 'test_sidebyside_file.py' | |||
|
49 | commit1_content = 'content-25d7e49c18b159446c\n' | |||
|
50 | commit2_content = 'content-603d6c72c46d953420\n' | |||
|
51 | repo = backend.create_repo() | |||
|
52 | ||||
|
53 | commit1 = commit_change( | |||
|
54 | repo.repo_name, filename=f_path, content=commit1_content, | |||
|
55 | message='A', vcs_type=backend.alias, parent=None, newfile=True) | |||
|
56 | ||||
|
57 | commit2 = commit_change( | |||
|
58 | repo.repo_name, filename=f_path, content=commit2_content, | |||
|
59 | message='B, child of A', vcs_type=backend.alias, parent=commit1) | |||
|
60 | ||||
|
61 | compare_url = url( | |||
|
62 | 'compare_url', | |||
|
63 | repo_name=repo.repo_name, | |||
|
64 | source_ref_type='rev', | |||
|
65 | source_ref=commit1.raw_id, | |||
|
66 | target_repo=repo.repo_name, | |||
|
67 | target_ref_type='rev', | |||
|
68 | target_ref=commit2.raw_id, | |||
|
69 | f_path=f_path, | |||
|
70 | diffmode='sidebyside') | |||
|
71 | ||||
|
72 | response = self.app.get(compare_url) | |||
|
73 | ||||
|
74 | response.mustcontain('Expand 1 commit') | |||
|
75 | response.mustcontain('1 file changed') | |||
|
76 | ||||
|
77 | response.mustcontain( | |||
|
78 | 'r%s:%s...r%s:%s' % ( | |||
|
79 | commit1.idx, commit1.short_id, commit2.idx, commit2.short_id)) | |||
|
80 | ||||
|
81 | response.mustcontain('<strong>{}</strong>'.format(f_path)) | |||
|
82 | ||||
|
83 | def test_diff_side_by_side_with_empty_file(self, app, backend, backend_stub): | |||
|
84 | commits = [ | |||
|
85 | {'message': 'First commit'}, | |||
|
86 | {'message': 'Commit with binary', | |||
|
87 | 'added': [nodes.FileNode('file.empty', content='')]}, | |||
|
88 | ] | |||
|
89 | f_path = 'file.empty' | |||
|
90 | repo = backend.create_repo(commits=commits) | |||
|
91 | commit1 = repo.get_commit(commit_idx=0) | |||
|
92 | commit2 = repo.get_commit(commit_idx=1) | |||
|
93 | ||||
|
94 | compare_url = url( | |||
|
95 | 'compare_url', | |||
|
96 | repo_name=repo.repo_name, | |||
|
97 | source_ref_type='rev', | |||
|
98 | source_ref=commit1.raw_id, | |||
|
99 | target_repo=repo.repo_name, | |||
|
100 | target_ref_type='rev', | |||
|
101 | target_ref=commit2.raw_id, | |||
|
102 | f_path=f_path, | |||
|
103 | diffmode='sidebyside') | |||
|
104 | ||||
|
105 | response = self.app.get(compare_url) | |||
|
106 | ||||
|
107 | response.mustcontain('Expand 1 commit') | |||
|
108 | response.mustcontain('1 file changed') | |||
|
109 | ||||
|
110 | response.mustcontain( | |||
|
111 | 'r%s:%s...r%s:%s' % ( | |||
|
112 | commit1.idx, commit1.short_id, commit2.idx, commit2.short_id)) | |||
|
113 | ||||
|
114 | response.mustcontain('<strong>{}</strong>'.format(f_path)) | |||
|
115 | ||||
|
116 | def test_diff_sidebyside_two_commits(self, app, backend): | |||
|
117 | commit_id_range = { | |||
|
118 | 'hg': { | |||
|
119 | 'commits': ['25d7e49c18b159446cadfa506a5cf8ad1cb04067', | |||
|
120 | '603d6c72c46d953420c89d36372f08d9f305f5dd'], | |||
|
121 | 'changes': '21 files changed: 943 inserted, 288 deleted' | |||
|
122 | }, | |||
|
123 | 'git': { | |||
|
124 | 'commits': ['6fc9270775aaf5544c1deb014f4ddd60c952fcbb', | |||
|
125 | '03fa803d7e9fb14daa9a3089e0d1494eda75d986'], | |||
|
126 | 'changes': '21 files changed: 943 inserted, 288 deleted' | |||
|
127 | }, | |||
|
128 | ||||
|
129 | 'svn': { | |||
|
130 | 'commits': ['336', | |||
|
131 | '337'], | |||
|
132 | 'changes': '21 files changed: 943 inserted, 288 deleted' | |||
|
133 | }, | |||
|
134 | } | |||
|
135 | ||||
|
136 | commit_info = commit_id_range[backend.alias] | |||
|
137 | commit2, commit1 = commit_info['commits'] | |||
|
138 | file_changes = commit_info['changes'] | |||
|
139 | ||||
|
140 | compare_url = url( | |||
|
141 | 'compare_url', | |||
|
142 | repo_name=backend.repo_name, | |||
|
143 | source_ref_type='rev', | |||
|
144 | source_ref=commit2, | |||
|
145 | target_repo=backend.repo_name, | |||
|
146 | target_ref_type='rev', | |||
|
147 | target_ref=commit1, | |||
|
148 | diffmode='sidebyside') | |||
|
149 | response = self.app.get(compare_url) | |||
|
150 | ||||
|
151 | response.mustcontain('Expand 1 commit') | |||
|
152 | response.mustcontain(file_changes) | |||
|
153 | ||||
|
154 | def test_diff_sidebyside_two_commits_single_file(self, app, backend): | |||
|
155 | commit_id_range = { | |||
|
156 | 'hg': { | |||
|
157 | 'commits': ['25d7e49c18b159446cadfa506a5cf8ad1cb04067', | |||
|
158 | '603d6c72c46d953420c89d36372f08d9f305f5dd'], | |||
|
159 | 'changes': '1 file changed: 1 inserted, 1 deleted' | |||
|
160 | }, | |||
|
161 | 'git': { | |||
|
162 | 'commits': ['6fc9270775aaf5544c1deb014f4ddd60c952fcbb', | |||
|
163 | '03fa803d7e9fb14daa9a3089e0d1494eda75d986'], | |||
|
164 | 'changes': '1 file changed: 1 inserted, 1 deleted' | |||
|
165 | }, | |||
|
166 | ||||
|
167 | 'svn': { | |||
|
168 | 'commits': ['336', | |||
|
169 | '337'], | |||
|
170 | 'changes': '1 file changed: 1 inserted, 1 deleted' | |||
|
171 | }, | |||
|
172 | } | |||
|
173 | f_path = 'docs/conf.py' | |||
|
174 | ||||
|
175 | commit_info = commit_id_range[backend.alias] | |||
|
176 | commit2, commit1 = commit_info['commits'] | |||
|
177 | file_changes = commit_info['changes'] | |||
|
178 | ||||
|
179 | compare_url = url( | |||
|
180 | 'compare_url', | |||
|
181 | repo_name=backend.repo_name, | |||
|
182 | source_ref_type='rev', | |||
|
183 | source_ref=commit2, | |||
|
184 | target_repo=backend.repo_name, | |||
|
185 | target_ref_type='rev', | |||
|
186 | target_ref=commit1, | |||
|
187 | f_path=f_path, | |||
|
188 | diffmode='sidebyside') | |||
|
189 | response = self.app.get(compare_url) | |||
|
190 | ||||
|
191 | response.mustcontain('Expand 1 commit') | |||
|
192 | response.mustcontain(file_changes) |
@@ -1066,7 +1066,7 b' def make_map(config):' | |||||
1066 | '/{repo_name}/annotate/{revision}/{f_path}', |
|
1066 | '/{repo_name}/annotate/{revision}/{f_path}', | |
1067 | controller='files', action='index', revision='tip', |
|
1067 | controller='files', action='index', revision='tip', | |
1068 | f_path='', annotate=True, conditions={'function': check_repo}, |
|
1068 | f_path='', annotate=True, conditions={'function': check_repo}, | |
1069 | requirements=URL_NAME_REQUIREMENTS) |
|
1069 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) | |
1070 |
|
1070 | |||
1071 | rmap.connect('files_edit', |
|
1071 | rmap.connect('files_edit', | |
1072 | '/{repo_name}/edit/{revision}/{f_path}', |
|
1072 | '/{repo_name}/edit/{revision}/{f_path}', |
@@ -90,6 +90,7 b' class CompareController(BaseRepoControll' | |||||
90 | c.target_ref_type = "" |
|
90 | c.target_ref_type = "" | |
91 | c.commit_statuses = ChangesetStatus.STATUSES |
|
91 | c.commit_statuses = ChangesetStatus.STATUSES | |
92 | c.preview_mode = False |
|
92 | c.preview_mode = False | |
|
93 | c.file_path = None | |||
93 | return render('compare/compare_diff.html') |
|
94 | return render('compare/compare_diff.html') | |
94 |
|
95 | |||
95 | @LoginRequired() |
|
96 | @LoginRequired() | |
@@ -103,8 +104,10 b' class CompareController(BaseRepoControll' | |||||
103 |
|
104 | |||
104 | # target_ref will be evaluated in target_repo |
|
105 | # target_ref will be evaluated in target_repo | |
105 | target_repo_name = request.GET.get('target_repo', source_repo_name) |
|
106 | target_repo_name = request.GET.get('target_repo', source_repo_name) | |
106 |
target_path, target_id = parse_path_ref( |
|
107 | target_path, target_id = parse_path_ref( | |
|
108 | target_ref, default_path=request.GET.get('f_path', '')) | |||
107 |
|
109 | |||
|
110 | c.file_path = target_path | |||
108 | c.commit_statuses = ChangesetStatus.STATUSES |
|
111 | c.commit_statuses = ChangesetStatus.STATUSES | |
109 |
|
112 | |||
110 | # if merge is True |
|
113 | # if merge is True | |
@@ -115,7 +118,6 b' class CompareController(BaseRepoControll' | |||||
115 | # if merge is False |
|
118 | # if merge is False | |
116 | # Show a raw diff of source/target refs even if no ancestor exists |
|
119 | # Show a raw diff of source/target refs even if no ancestor exists | |
117 |
|
120 | |||
118 |
|
||||
119 | # c.fulldiff disables cut_off_limit |
|
121 | # c.fulldiff disables cut_off_limit | |
120 | c.fulldiff = str2bool(request.GET.get('fulldiff')) |
|
122 | c.fulldiff = str2bool(request.GET.get('fulldiff')) | |
121 |
|
123 | |||
@@ -131,7 +133,8 b' class CompareController(BaseRepoControll' | |||||
131 | target_repo=source_repo_name, |
|
133 | target_repo=source_repo_name, | |
132 | target_ref_type=source_ref_type, |
|
134 | target_ref_type=source_ref_type, | |
133 | target_ref=source_ref, |
|
135 | target_ref=source_ref, | |
134 |
merge=merge and '1' or '' |
|
136 | merge=merge and '1' or '', | |
|
137 | f_path=target_path) | |||
135 |
|
138 | |||
136 | source_repo = Repository.get_by_repo_name(source_repo_name) |
|
139 | source_repo = Repository.get_by_repo_name(source_repo_name) | |
137 | target_repo = Repository.get_by_repo_name(target_repo_name) |
|
140 | target_repo = Repository.get_by_repo_name(target_repo_name) | |
@@ -151,8 +154,11 b' class CompareController(BaseRepoControll' | |||||
151 | h.flash(msg, category='error') |
|
154 | h.flash(msg, category='error') | |
152 | return redirect(url('compare_home', repo_name=c.repo_name)) |
|
155 | return redirect(url('compare_home', repo_name=c.repo_name)) | |
153 |
|
156 | |||
154 |
source_ |
|
157 | source_scm = source_repo.scm_instance() | |
155 |
target_ |
|
158 | target_scm = target_repo.scm_instance() | |
|
159 | ||||
|
160 | source_alias = source_scm.alias | |||
|
161 | target_alias = target_scm.alias | |||
156 | if source_alias != target_alias: |
|
162 | if source_alias != target_alias: | |
157 | msg = _('The comparison of two different kinds of remote repos ' |
|
163 | msg = _('The comparison of two different kinds of remote repos ' | |
158 | 'is not available') |
|
164 | 'is not available') | |
@@ -175,9 +181,6 b' class CompareController(BaseRepoControll' | |||||
175 | c.source_ref_type = source_ref_type |
|
181 | c.source_ref_type = source_ref_type | |
176 | c.target_ref_type = target_ref_type |
|
182 | c.target_ref_type = target_ref_type | |
177 |
|
183 | |||
178 | source_scm = source_repo.scm_instance() |
|
|||
179 | target_scm = target_repo.scm_instance() |
|
|||
180 |
|
||||
181 | pre_load = ["author", "branch", "date", "message"] |
|
184 | pre_load = ["author", "branch", "date", "message"] | |
182 | c.ancestor = None |
|
185 | c.ancestor = None | |
183 | try: |
|
186 | try: | |
@@ -238,7 +241,8 b' class CompareController(BaseRepoControll' | |||||
238 |
|
241 | |||
239 | txtdiff = source_repo.scm_instance().get_diff( |
|
242 | txtdiff = source_repo.scm_instance().get_diff( | |
240 | commit1=source_commit, commit2=target_commit, |
|
243 | commit1=source_commit, commit2=target_commit, | |
241 |
path1=source_path |
|
244 | path=target_path, path1=source_path) | |
|
245 | ||||
242 | diff_processor = diffs.DiffProcessor( |
|
246 | diff_processor = diffs.DiffProcessor( | |
243 | txtdiff, format='newdiff', diff_limit=diff_limit, |
|
247 | txtdiff, format='newdiff', diff_limit=diff_limit, | |
244 | file_limit=file_limit, show_full_diff=c.fulldiff) |
|
248 | file_limit=file_limit, show_full_diff=c.fulldiff) | |
@@ -260,5 +264,7 b' class CompareController(BaseRepoControll' | |||||
260 | ).render_patchset(_parsed, source_ref, target_ref) |
|
264 | ).render_patchset(_parsed, source_ref, target_ref) | |
261 |
|
265 | |||
262 | c.preview_mode = merge |
|
266 | c.preview_mode = merge | |
|
267 | c.source_commit = source_commit | |||
|
268 | c.target_commit = target_commit | |||
263 |
|
269 | |||
264 | return render('compare/compare_diff.html') |
|
270 | return render('compare/compare_diff.html') |
@@ -799,21 +799,15 b' class FilesController(BaseRepoController' | |||||
799 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
799 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
800 | 'repository.admin') |
|
800 | 'repository.admin') | |
801 | def diff(self, repo_name, f_path): |
|
801 | def diff(self, repo_name, f_path): | |
802 | ignore_whitespace = request.GET.get('ignorews') == '1' |
|
802 | ||
803 |
|
|
803 | c.action = request.GET.get('diff') | |
804 | diff1 = request.GET.get('diff1', '') |
|
804 | diff1 = request.GET.get('diff1', '') | |
|
805 | diff2 = request.GET.get('diff2', '') | |||
805 |
|
806 | |||
806 | path1, diff1 = parse_path_ref(diff1, default_path=f_path) |
|
807 | path1, diff1 = parse_path_ref(diff1, default_path=f_path) | |
807 |
|
808 | |||
808 | diff2 = request.GET.get('diff2', '') |
|
809 | ignore_whitespace = str2bool(request.GET.get('ignorews')) | |
809 |
|
|
810 | line_context = request.GET.get('context', 3) | |
810 | c.no_changes = diff1 == diff2 |
|
|||
811 | c.f_path = f_path |
|
|||
812 | c.big_diff = False |
|
|||
813 | c.ignorews_url = _ignorews_url |
|
|||
814 | c.context_url = _context_url |
|
|||
815 | c.changes = OrderedDict() |
|
|||
816 | c.changes[diff2] = [] |
|
|||
817 |
|
811 | |||
818 | if not any((diff1, diff2)): |
|
812 | if not any((diff1, diff2)): | |
819 | h.flash( |
|
813 | h.flash( | |
@@ -821,18 +815,16 b' class FilesController(BaseRepoController' | |||||
821 | category='error') |
|
815 | category='error') | |
822 | raise HTTPBadRequest() |
|
816 | raise HTTPBadRequest() | |
823 |
|
817 | |||
824 | # special case if we want a show commit_id only, it's impl here |
|
818 | if c.action not in ['download', 'raw']: | |
825 | # to reduce JS and callbacks |
|
819 | # redirect to new view if we render diff | |
826 |
|
820 | return redirect( | ||
827 | if request.GET.get('show_rev') and diff1: |
|
821 | url('compare_url', repo_name=repo_name, | |
828 | if str2bool(request.GET.get('annotate', 'False')): |
|
822 | source_ref_type='rev', | |
829 | _url = url('files_annotate_home', repo_name=c.repo_name, |
|
823 | source_ref=diff1, | |
830 | revision=diff1, f_path=path1) |
|
824 | target_repo=c.repo_name, | |
831 | else: |
|
825 | target_ref_type='rev', | |
832 | _url = url('files_home', repo_name=c.repo_name, |
|
826 | target_ref=diff2, | |
833 |
|
|
827 | f_path=f_path)) | |
834 |
|
||||
835 | return redirect(_url) |
|
|||
836 |
|
828 | |||
837 | try: |
|
829 | try: | |
838 | node1 = self._get_file_node(diff1, path1) |
|
830 | node1 = self._get_file_node(diff1, path1) | |
@@ -877,98 +869,40 b' class FilesController(BaseRepoController' | |||||
877 | return diff.as_raw() |
|
869 | return diff.as_raw() | |
878 |
|
870 | |||
879 | else: |
|
871 | else: | |
880 | fid = h.FID(diff2, node2.path) |
|
872 | return redirect( | |
881 | line_context_lcl = get_line_ctx(fid, request.GET) |
|
873 | url('compare_url', repo_name=repo_name, | |
882 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) |
|
874 | source_ref_type='rev', | |
883 |
|
875 | source_ref=diff1, | ||
884 | __, commit1, commit2, diff, st, data = diffs.wrapped_diff( |
|
876 | target_repo=c.repo_name, | |
885 | filenode_old=node1, |
|
877 | target_ref_type='rev', | |
886 | filenode_new=node2, |
|
878 | target_ref=diff2, | |
887 | diff_limit=self.cut_off_limit_diff, |
|
879 | f_path=f_path)) | |
888 | file_limit=self.cut_off_limit_file, |
|
|||
889 | show_full_diff=request.GET.get('fulldiff'), |
|
|||
890 | ignore_whitespace=ign_whitespace_lcl, |
|
|||
891 | line_context=line_context_lcl,) |
|
|||
892 |
|
||||
893 | c.lines_added = data['stats']['added'] if data else 0 |
|
|||
894 | c.lines_deleted = data['stats']['deleted'] if data else 0 |
|
|||
895 | c.files = [data] |
|
|||
896 | c.commit_ranges = [c.commit_1, c.commit_2] |
|
|||
897 | c.ancestor = None |
|
|||
898 | c.statuses = [] |
|
|||
899 | c.target_repo = c.rhodecode_db_repo |
|
|||
900 | c.filename1 = node1.path |
|
|||
901 | c.filename = node2.path |
|
|||
902 | c.binary_file = node1.is_binary or node2.is_binary |
|
|||
903 | operation = data['operation'] if data else '' |
|
|||
904 |
|
||||
905 | commit_changes = { |
|
|||
906 | # TODO: it's passing the old file to the diff to keep the |
|
|||
907 | # standard but this is not being used for this template, |
|
|||
908 | # but might need both files in the future or a more standard |
|
|||
909 | # way to work with that |
|
|||
910 | 'fid': [commit1, commit2, operation, |
|
|||
911 | c.filename, diff, st, data] |
|
|||
912 | } |
|
|||
913 |
|
||||
914 | c.changes = commit_changes |
|
|||
915 |
|
||||
916 | return render('files/file_diff.html') |
|
|||
917 |
|
880 | |||
918 | @LoginRequired() |
|
881 | @LoginRequired() | |
919 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
882 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
920 | 'repository.admin') |
|
883 | 'repository.admin') | |
921 | def diff_2way(self, repo_name, f_path): |
|
884 | def diff_2way(self, repo_name, f_path): | |
|
885 | """ | |||
|
886 | Kept only to make OLD links work | |||
|
887 | """ | |||
922 | diff1 = request.GET.get('diff1', '') |
|
888 | diff1 = request.GET.get('diff1', '') | |
923 | diff2 = request.GET.get('diff2', '') |
|
889 | diff2 = request.GET.get('diff2', '') | |
924 |
|
890 | |||
925 | nodes = [] |
|
891 | if not any((diff1, diff2)): | |
926 | unknown_commits = [] |
|
892 | h.flash( | |
927 | for commit in [diff1, diff2]: |
|
893 | 'Need query parameter "diff1" or "diff2" to generate a diff.', | |
928 |
|
|
894 | category='error') | |
929 | nodes.append(self._get_file_node(commit, f_path)) |
|
895 | raise HTTPBadRequest() | |
930 | except (RepositoryError, NodeError): |
|
|||
931 | log.exception('%(commit)s does not exist' % {'commit': commit}) |
|
|||
932 | unknown_commits.append(commit) |
|
|||
933 | h.flash(h.literal( |
|
|||
934 | _('Commit %(commit)s does not exist.') % {'commit': commit} |
|
|||
935 | ), category='error') |
|
|||
936 |
|
||||
937 | if unknown_commits: |
|
|||
938 | return redirect(url('files_home', repo_name=c.repo_name, |
|
|||
939 | f_path=f_path)) |
|
|||
940 |
|
||||
941 | if all(isinstance(node.commit, EmptyCommit) for node in nodes): |
|
|||
942 | raise HTTPNotFound |
|
|||
943 |
|
||||
944 | node1, node2 = nodes |
|
|||
945 |
|
896 | |||
946 | f_gitdiff = diffs.get_gitdiff(node1, node2, ignore_whitespace=False) |
|
897 | return redirect( | |
947 | diff_processor = diffs.DiffProcessor(f_gitdiff, format='gitdiff') |
|
898 | url('compare_url', repo_name=repo_name, | |
948 | diff_data = diff_processor.prepare() |
|
899 | source_ref_type='rev', | |
949 |
|
900 | source_ref=diff1, | ||
950 | if not diff_data or diff_data[0]['raw_diff'] == '': |
|
901 | target_repo=c.repo_name, | |
951 | h.flash(h.literal(_('%(file_path)s has not changed ' |
|
902 | target_ref_type='rev', | |
952 | 'between %(commit_1)s and %(commit_2)s.') % { |
|
903 | target_ref=diff2, | |
953 |
|
|
904 | f_path=f_path, | |
954 | 'commit_1': node1.commit.id, |
|
905 | diffmode='sideside')) | |
955 | 'commit_2': node2.commit.id |
|
|||
956 | }), category='error') |
|
|||
957 | return redirect(url('files_home', repo_name=c.repo_name, |
|
|||
958 | f_path=f_path)) |
|
|||
959 |
|
||||
960 | c.diff_data = diff_data[0] |
|
|||
961 | c.FID = h.FID(diff2, node2.path) |
|
|||
962 | # cleanup some unneeded data |
|
|||
963 | del c.diff_data['raw_diff'] |
|
|||
964 | del c.diff_data['chunks'] |
|
|||
965 |
|
||||
966 | c.node1 = node1 |
|
|||
967 | c.commit_1 = node1.commit |
|
|||
968 | c.node2 = node2 |
|
|||
969 | c.commit_2 = node2.commit |
|
|||
970 |
|
||||
971 | return render('files/diff_2way.html') |
|
|||
972 |
|
906 | |||
973 | def _get_file_node(self, commit_id, f_path): |
|
907 | def _get_file_node(self, commit_id, f_path): | |
974 | if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]: |
|
908 | if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]: |
@@ -27,6 +27,7 b' Should only contain utilities to be shar' | |||||
27 | from rhodecode.lib import helpers as h |
|
27 | from rhodecode.lib import helpers as h | |
28 | from rhodecode.lib.vcs.exceptions import RepositoryError |
|
28 | from rhodecode.lib.vcs.exceptions import RepositoryError | |
29 |
|
29 | |||
|
30 | ||||
30 | def parse_path_ref(ref, default_path=None): |
|
31 | def parse_path_ref(ref, default_path=None): | |
31 | """ |
|
32 | """ | |
32 | Parse out a path and reference combination and return both parts of it. |
|
33 | Parse out a path and reference combination and return both parts of it. |
@@ -378,6 +378,7 b' class BaseRepository(object):' | |||||
378 | parameter works only for backends which support diff generation for |
|
378 | parameter works only for backends which support diff generation for | |
379 | different paths. Other backends will raise a `ValueError` if `path1` |
|
379 | different paths. Other backends will raise a `ValueError` if `path1` | |
380 | is set and has a different value than `path`. |
|
380 | is set and has a different value than `path`. | |
|
381 | :param file_path: filter this diff by given path pattern | |||
381 | """ |
|
382 | """ | |
382 | raise NotImplementedError |
|
383 | raise NotImplementedError | |
383 |
|
384 | |||
@@ -1540,9 +1541,10 b' class Diff(object):' | |||||
1540 | """ |
|
1541 | """ | |
1541 | Represents a diff result from a repository backend. |
|
1542 | Represents a diff result from a repository backend. | |
1542 |
|
1543 | |||
1543 |
Subclasses have to provide a backend specific value for |
|
1544 | Subclasses have to provide a backend specific value for | |
|
1545 | :attr:`_header_re` and :attr:`_meta_re`. | |||
1544 | """ |
|
1546 | """ | |
1545 |
|
1547 | _meta_re = None | ||
1546 | _header_re = None |
|
1548 | _header_re = None | |
1547 |
|
1549 | |||
1548 | def __init__(self, raw_diff): |
|
1550 | def __init__(self, raw_diff): | |
@@ -1554,9 +1556,18 b' class Diff(object):' | |||||
1554 | to make diffs consistent we must prepend with \n, and make sure |
|
1556 | to make diffs consistent we must prepend with \n, and make sure | |
1555 | we can detect last chunk as this was also has special rule |
|
1557 | we can detect last chunk as this was also has special rule | |
1556 | """ |
|
1558 | """ | |
1557 | chunks = ('\n' + self.raw).split('\ndiff --git')[1:] |
|
1559 | ||
|
1560 | diff_parts = ('\n' + self.raw).split('\ndiff --git') | |||
|
1561 | header = diff_parts[0] | |||
|
1562 | ||||
|
1563 | if self._meta_re: | |||
|
1564 | match = self._meta_re.match(header) | |||
|
1565 | ||||
|
1566 | chunks = diff_parts[1:] | |||
1558 | total_chunks = len(chunks) |
|
1567 | total_chunks = len(chunks) | |
1559 | return (DiffChunk(chunk, self, cur_chunk == total_chunks) |
|
1568 | ||
|
1569 | return ( | |||
|
1570 | DiffChunk(chunk, self, cur_chunk == total_chunks) | |||
1560 |
|
|
1571 | for cur_chunk, chunk in enumerate(chunks, start=1)) | |
1561 |
|
1572 | |||
1562 |
|
1573 |
@@ -30,6 +30,10 b' from rhodecode.lib.vcs.backends import b' | |||||
30 |
|
30 | |||
31 | class SubversionDiff(base.Diff): |
|
31 | class SubversionDiff(base.Diff): | |
32 |
|
32 | |||
|
33 | _meta_re = re.compile(r""" | |||
|
34 | (?:^(?P<svn_bin_patch>Cannot[ ]display:[ ]file[ ]marked[ ]as[ ]a[ ]binary[ ]type.)(?:\n|$))? | |||
|
35 | """, re.VERBOSE | re.MULTILINE) | |||
|
36 | ||||
33 | _header_re = re.compile(r""" |
|
37 | _header_re = re.compile(r""" | |
34 | #^diff[ ]--git |
|
38 | #^diff[ ]--git | |
35 | [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n |
|
39 | [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n |
@@ -1477,8 +1477,9 b' table.integrations {' | |||||
1477 | margin-left: 8px; |
|
1477 | margin-left: 8px; | |
1478 | } |
|
1478 | } | |
1479 |
|
1479 | |||
1480 |
|
|
1480 | div.ancestor { | |
1481 | margin: @padding 0; |
|
1481 | margin: @padding 0; | |
|
1482 | line-height: 3.0em; | |||
1482 | } |
|
1483 | } | |
1483 |
|
1484 | |||
1484 | .cs_icon_td input[type="checkbox"] { |
|
1485 | .cs_icon_td input[type="checkbox"] { |
@@ -72,6 +72,7 b'' | |||||
72 | } |
|
72 | } | |
73 | .disabled { |
|
73 | .disabled { | |
74 | opacity: .5; |
|
74 | opacity: .5; | |
|
75 | cursor: inherit; | |||
75 | } |
|
76 | } | |
76 | .help-block { |
|
77 | .help-block { | |
77 | color: inherit; |
|
78 | color: inherit; |
@@ -73,6 +73,16 b' String.prototype.capitalizeFirstLetter =' | |||||
73 | }; |
|
73 | }; | |
74 |
|
74 | |||
75 |
|
75 | |||
|
76 | String.prototype.truncateAfter = function(chars, suffix) { | |||
|
77 | var suffix = suffix || ''; | |||
|
78 | if (this.length > chars) { | |||
|
79 | return this.substr(0, chars) + suffix; | |||
|
80 | } else { | |||
|
81 | return this; | |||
|
82 | } | |||
|
83 | }; | |||
|
84 | ||||
|
85 | ||||
76 | /** |
|
86 | /** | |
77 | * Splits remainder |
|
87 | * Splits remainder | |
78 | * |
|
88 | * |
@@ -112,7 +112,7 b'' | |||||
112 |
|
112 | |||
113 | <div class="fieldset"> |
|
113 | <div class="fieldset"> | |
114 | <div class="left-label"> |
|
114 | <div class="left-label"> | |
115 | ${_('Diffs')}: |
|
115 | ${_('Diff options')}: | |
116 | </div> |
|
116 | </div> | |
117 | <div class="right-content"> |
|
117 | <div class="right-content"> | |
118 | <div class="diff-actions"> |
|
118 | <div class="diff-actions"> |
@@ -31,27 +31,82 b'' | |||||
31 | <%def name="main()"> |
|
31 | <%def name="main()"> | |
32 | <div class="summary-header"> |
|
32 | <div class="summary-header"> | |
33 | <div class="title"> |
|
33 | <div class="title"> | |
34 | <div class="title-content"> |
|
|||
35 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
34 | ${self.repo_page_title(c.rhodecode_db_repo)} | |
36 |
|
|
35 | </div> | |
37 |
|
|
36 | </div> | |
|
37 | ||||
|
38 | ||||
|
39 | <div class="summary changeset"> | |||
|
40 | <div class="summary-detail"> | |||
|
41 | <div class="summary-detail-header"> | |||
|
42 | <span class="breadcrumbs files_location"> | |||
|
43 | <h4> | |||
|
44 | ${_('Commit Range')} | |||
|
45 | <code> | |||
|
46 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)}...r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} | |||
|
47 | </code> | |||
|
48 | </h4> | |||
|
49 | </span> | |||
|
50 | </div> | |||
|
51 | ||||
|
52 | <div class="fieldset"> | |||
|
53 | <div class="left-label"> | |||
|
54 | ${_('Diff option')}: | |||
|
55 | </div> | |||
|
56 | <div class="right-content"> | |||
38 | <div class="header-buttons"> |
|
57 | <div class="header-buttons"> | |
39 | <a href="${h.url('compare_url', repo_name=c.repo_name, source_ref_type='rev', source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'), target_ref_type='rev', target_ref=c.commit_ranges[-1].raw_id)}" |
|
58 | <a href="${h.url('compare_url', repo_name=c.repo_name, source_ref_type='rev', source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'), target_ref_type='rev', target_ref=c.commit_ranges[-1].raw_id)}"> | |
40 | class="btn btn-default"> |
|
|||
41 | ${_('Show combined compare')} |
|
59 | ${_('Show combined compare')} | |
42 | </a> |
|
60 | </a> | |
43 | </div> |
|
61 | </div> | |
44 | </div> |
|
62 | </div> | |
|
63 | </div> | |||
45 |
|
64 | |||
46 | <div class="summary-detail"> |
|
65 | <%doc> | |
47 | <div class="title"> |
|
66 | ##TODO(marcink): implement this and diff menus | |
48 | <h2> |
|
67 | <div class="fieldset"> | |
49 | ${self.breadcrumbs_links()} |
|
68 | <div class="left-label"> | |
50 | </h2> |
|
69 | ${_('Diff options')}: | |
|
70 | </div> | |||
|
71 | <div class="right-content"> | |||
|
72 | <div class="diff-actions"> | |||
|
73 | <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |||
|
74 | ${_('Raw Diff')} | |||
|
75 | </a> | |||
|
76 | | | |||
|
77 | <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> | |||
|
78 | ${_('Patch Diff')} | |||
|
79 | </a> | |||
|
80 | | | |||
|
81 | <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision='?',diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"> | |||
|
82 | ${_('Download Diff')} | |||
|
83 | </a> | |||
|
84 | </div> | |||
51 | </div> |
|
85 | </div> | |
52 | </div> |
|
86 | </div> | |
|
87 | </%doc> | |||
|
88 | </div> <!-- end summary-detail --> | |||
|
89 | ||||
|
90 | </div> <!-- end summary --> | |||
|
91 | ||||
53 | <div id="changeset_compare_view_content"> |
|
92 | <div id="changeset_compare_view_content"> | |
54 | ##CS |
|
93 | <div class="pull-left"> | |
|
94 | <div class="btn-group"> | |||
|
95 | <a | |||
|
96 | class="btn" | |||
|
97 | href="#" | |||
|
98 | onclick="$('.compare_select').show();$('.compare_select_hidden').hide(); return false"> | |||
|
99 | ${ungettext('Expand %s commit','Expand %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |||
|
100 | </a> | |||
|
101 | <a | |||
|
102 | class="btn" | |||
|
103 | href="#" | |||
|
104 | onclick="$('.compare_select').hide();$('.compare_select_hidden').show(); return false"> | |||
|
105 | ${ungettext('Collapse %s commit','Collapse %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |||
|
106 | </a> | |||
|
107 | </div> | |||
|
108 | </div> | |||
|
109 | ## Commit range generated below | |||
55 | <%include file="../compare/compare_commits.html"/> |
|
110 | <%include file="../compare/compare_commits.html"/> | |
56 | <div class="cs_files"> |
|
111 | <div class="cs_files"> | |
57 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> |
|
112 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> | |
@@ -65,7 +120,6 b'' | |||||
65 | commit=commit, |
|
120 | commit=commit, | |
66 | )} |
|
121 | )} | |
67 | %endfor |
|
122 | %endfor | |
68 | </table> |
|
|||
69 | </div> |
|
123 | </div> | |
70 | </div> |
|
124 | </div> | |
71 | </%def> |
|
125 | </%def> |
@@ -52,45 +52,6 b'' | |||||
52 | </div> |
|
52 | </div> | |
53 | </%def> |
|
53 | </%def> | |
54 |
|
54 | |||
55 | <%def name="diff_menu(repo_name, f_path, cs1, cs2, change, file=None)"> |
|
|||
56 | <% |
|
|||
57 | onclick_diff2way = '' |
|
|||
58 | if (file and file["exceeds_limit"]): |
|
|||
59 | onclick_diff2way = '''return confirm('%s');''' % _("Showing a big diff might take some time and resources, continue?") |
|
|||
60 | %> |
|
|||
61 |
|
||||
62 | % if change in ['A', 'M']: |
|
|||
63 | <a href="${h.url('files_home',repo_name=repo_name,f_path=f_path,revision=cs2)}" |
|
|||
64 | class="tooltip" title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': cs2[:12]})}"> |
|
|||
65 | ${_('Show File')} |
|
|||
66 | </a> |
|
|||
67 | % else: |
|
|||
68 | <span |
|
|||
69 | class="tooltip" title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': cs2[:12]})}"> |
|
|||
70 | ${_('Show File')} |
|
|||
71 | </span> |
|
|||
72 | % endif |
|
|||
73 | | |
|
|||
74 | <a href="${h.url('files_diff_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" |
|
|||
75 | class="tooltip" title="${h.tooltip(_('Show full diff for this file'))}"> |
|
|||
76 | ${_('Unified Diff')} |
|
|||
77 | </a> |
|
|||
78 | | |
|
|||
79 | <a href="${h.url('files_diff_2way_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" |
|
|||
80 | class="tooltip" title="${h.tooltip(_('Show full side-by-side diff for this file'))}"} onclick="${onclick_diff2way}"> |
|
|||
81 | ${_('Side-by-side Diff')} |
|
|||
82 | </a> |
|
|||
83 | | |
|
|||
84 | <a href="${h.url('files_diff_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='raw')}" |
|
|||
85 | class="tooltip" title="${h.tooltip(_('Raw diff'))}"> |
|
|||
86 | ${_('Raw Diff')} |
|
|||
87 | </a> |
|
|||
88 | | |
|
|||
89 | <a href="${h.url('files_diff_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='download')}" |
|
|||
90 | class="tooltip" title="${h.tooltip(_('Download diff'))}"> |
|
|||
91 | ${_('Download Diff')} |
|
|||
92 | </a> |
|
|||
93 | </%def> |
|
|||
94 |
|
55 | |||
95 | <%def name="diff_summary_text(changed_files, lines_added, lines_deleted, limited_diff=False)"> |
|
56 | <%def name="diff_summary_text(changed_files, lines_added, lines_deleted, limited_diff=False)"> | |
96 | % if limited_diff: |
|
57 | % if limited_diff: |
@@ -162,6 +162,7 b' collapse_all = len(diffset.files) > coll' | |||||
162 |
|
162 | |||
163 | <div class="filediffs"> |
|
163 | <div class="filediffs"> | |
164 | %for i, filediff in enumerate(diffset.files): |
|
164 | %for i, filediff in enumerate(diffset.files): | |
|
165 | ||||
165 | <% |
|
166 | <% | |
166 | lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted'] |
|
167 | lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted'] | |
167 | over_lines_changed_limit = lines_changed > lines_changed_limit |
|
168 | over_lines_changed_limit = lines_changed > lines_changed_limit | |
@@ -414,6 +415,7 b' from rhodecode.lib.diffs import NEW_FILE' | |||||
414 | if line.modified.lineno: |
|
415 | if line.modified.lineno: | |
415 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n') |
|
416 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n') | |
416 | %> |
|
417 | %> | |
|
418 | ||||
417 | <tr class="cb-line"> |
|
419 | <tr class="cb-line"> | |
418 | <td class="cb-data ${action_class(line.original.action)}" |
|
420 | <td class="cb-data ${action_class(line.original.action)}" | |
419 | data-line-number="${line.original.lineno}" |
|
421 | data-line-number="${line.original.lineno}" | |
@@ -544,6 +546,7 b' from rhodecode.lib.diffs import NEW_FILE' | |||||
544 | <div class="diffset-menu clearinner"> |
|
546 | <div class="diffset-menu clearinner"> | |
545 | <div class="pull-right"> |
|
547 | <div class="pull-right"> | |
546 | <div class="btn-group"> |
|
548 | <div class="btn-group"> | |
|
549 | ||||
547 | <a |
|
550 | <a | |
548 | class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip" |
|
551 | class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip" | |
549 | title="${_('View side by side')}" |
|
552 | title="${_('View side by side')}" | |
@@ -557,20 +560,21 b' from rhodecode.lib.diffs import NEW_FILE' | |||||
557 | </a> |
|
560 | </a> | |
558 | </div> |
|
561 | </div> | |
559 | </div> |
|
562 | </div> | |
|
563 | ||||
560 | <div class="pull-left"> |
|
564 | <div class="pull-left"> | |
561 | <div class="btn-group"> |
|
565 | <div class="btn-group"> | |
562 | <a |
|
566 | <a | |
563 | class="btn" |
|
567 | class="btn" | |
564 | href="#" |
|
568 | href="#" | |
565 | onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All')}</a> |
|
569 | onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All Files')}</a> | |
566 | <a |
|
570 | <a | |
567 | class="btn" |
|
571 | class="btn" | |
568 | href="#" |
|
572 | href="#" | |
569 | onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All')}</a> |
|
573 | onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All Files')}</a> | |
570 | <a |
|
574 | <a | |
571 | class="btn" |
|
575 | class="btn" | |
572 | href="#" |
|
576 | href="#" | |
573 | onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode')}</a> |
|
577 | onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode Diff')}</a> | |
574 | </div> |
|
578 | </div> | |
575 | </div> |
|
579 | </div> | |
576 | </div> |
|
580 | </div> |
@@ -1,20 +1,17 b'' | |||||
1 | ## Changesets table ! |
|
1 | ## Changesets table ! | |
2 | <%namespace name="base" file="/base/base.html"/> |
|
2 | <%namespace name="base" file="/base/base.html"/> | |
3 | <div class="container"> |
|
|||
4 | %if not c.commit_ranges: |
|
|||
5 | <p class="empty_data">${_('No Commits')}</p> |
|
|||
6 | %else: |
|
|||
7 |
|
3 | |||
8 |
|
|
4 | %if c.ancestor: | |
9 |
|
|
5 | <div class="ancestor">${_('Common Ancestor Commit')}: | |
10 |
|
|
6 | <a href="${h.url('changeset_home', | |
11 |
|
|
7 | repo_name=c.repo_name, | |
12 |
|
|
8 | revision=c.ancestor)}"> | |
13 |
|
|
9 | ${h.short_id(c.ancestor)} | |
14 |
|
|
10 | </a> | |
15 | </p> |
|
11 | </div> | |
16 |
|
|
12 | %endif | |
17 |
|
13 | |||
|
14 | <div class="container"> | |||
18 | <input type="hidden" name="__start__" value="revisions:sequence"> |
|
15 | <input type="hidden" name="__start__" value="revisions:sequence"> | |
19 | <table class="rctable compare_view_commits"> |
|
16 | <table class="rctable compare_view_commits"> | |
20 | <tr> |
|
17 | <tr> | |
@@ -66,9 +63,21 b'' | |||||
66 | </td> |
|
63 | </td> | |
67 | </tr> |
|
64 | </tr> | |
68 | %endfor |
|
65 | %endfor | |
|
66 | <tr class="compare_select_hidden" style="display: none"> | |||
|
67 | <td colspan="5"> | |||
|
68 | ${ungettext('%s commit hidden','%s commits hidden', len(c.commit_ranges)) % len(c.commit_ranges)} | |||
|
69 | </td> | |||
|
70 | </tr> | |||
|
71 | % if not c.commit_ranges: | |||
|
72 | <tr class="compare_select"> | |||
|
73 | <td colspan="5"> | |||
|
74 | ${_('No commits in this compare')} | |||
|
75 | </td> | |||
|
76 | </tr> | |||
|
77 | % endif | |||
69 | </table> |
|
78 | </table> | |
70 | <input type="hidden" name="__end__" value="revisions:sequence"> |
|
79 | <input type="hidden" name="__end__" value="revisions:sequence"> | |
71 | %endif |
|
80 | ||
72 | </div> |
|
81 | </div> | |
73 |
|
82 | |||
74 | <script> |
|
83 | <script> | |
@@ -76,7 +85,7 b'' | |||||
76 | var target_expand = $(this); |
|
85 | var target_expand = $(this); | |
77 | var cid = target_expand.data('commitId'); |
|
86 | var cid = target_expand.data('commitId'); | |
78 |
|
87 | |||
79 | ## TODO: dan: extract styles into css, and just toggleClass('open') here |
|
88 | // ## TODO: dan: extract styles into css, and just toggleClass('open') here | |
80 | if (target_expand.hasClass('open')){ |
|
89 | if (target_expand.hasClass('open')){ | |
81 | $('#c-'+cid).css({ |
|
90 | $('#c-'+cid).css({ | |
82 | 'height': '1.5em', |
|
91 | 'height': '1.5em', |
@@ -34,34 +34,132 b'' | |||||
34 | <div class="box"> |
|
34 | <div class="box"> | |
35 | <div class="title"> |
|
35 | <div class="title"> | |
36 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
36 | ${self.repo_page_title(c.rhodecode_db_repo)} | |
37 | <div class="breadcrumbs"> |
|
|||
38 | ${_('Compare Commits')} |
|
|||
39 | </div> |
|
|||
40 | </div> |
|
37 | </div> | |
41 |
|
38 | |||
42 |
<div class=" |
|
39 | <div class="summary changeset"> | |
43 |
<div |
|
40 | <div class="summary-detail"> | |
|
41 | <div class="summary-detail-header"> | |||
|
42 | <span class="breadcrumbs files_location"> | |||
|
43 | <h4> | |||
|
44 | ${_('Compare Commits')} | |||
|
45 | % if c.file_path: | |||
|
46 | ${_('for file')} <a href="#${'a_' + h.FID('',c.file_path)}">${c.file_path}</a> | |||
|
47 | % endif | |||
|
48 | ||||
|
49 | % if c.commit_ranges: | |||
|
50 | <code> | |||
|
51 | r${c.source_commit.revision}:${h.short_id(c.source_commit.raw_id)}...r${c.target_commit.revision}:${h.short_id(c.target_commit.raw_id)} | |||
|
52 | </code> | |||
|
53 | % endif | |||
|
54 | </h4> | |||
|
55 | </span> | |||
|
56 | </div> | |||
|
57 | ||||
|
58 | <div class="fieldset"> | |||
|
59 | <div class="left-label"> | |||
|
60 | ${_('Target')}: | |||
|
61 | </div> | |||
|
62 | <div class="right-content"> | |||
|
63 | <div> | |||
44 | <div class="code-header" > |
|
64 | <div class="code-header" > | |
45 | <div class="compare_header"> |
|
65 | <div class="compare_header"> | |
46 | ## The hidden elements are replaced with a select2 widget |
|
66 | ## The hidden elements are replaced with a select2 widget | |
47 |
|
|
67 | ${h.hidden('compare_source')} | |
48 | <div class="compare-label">${_('Source')}</div>${h.hidden('compare_target')} |
|
68 | </div> | |
|
69 | </div> | |||
|
70 | </div> | |||
|
71 | </div> | |||
|
72 | </div> | |||
49 |
|
73 | |||
50 | %if not c.preview_mode: |
|
74 | <div class="fieldset"> | |
51 |
|
|
75 | <div class="left-label"> | |
|
76 | ${_('Source')}: | |||
|
77 | </div> | |||
|
78 | <div class="right-content"> | |||
|
79 | <div> | |||
|
80 | <div class="code-header" > | |||
|
81 | <div class="compare_header"> | |||
|
82 | ## The hidden elements are replaced with a select2 widget | |||
|
83 | ${h.hidden('compare_target')} | |||
|
84 | </div> | |||
|
85 | </div> | |||
|
86 | </div> | |||
|
87 | </div> | |||
|
88 | </div> | |||
|
89 | ||||
|
90 | <div class="fieldset"> | |||
|
91 | <div class="left-label"> | |||
|
92 | ${_('Actions')}: | |||
|
93 | </div> | |||
|
94 | <div class="right-content"> | |||
|
95 | <div> | |||
|
96 | <div class="code-header" > | |||
|
97 | <div class="compare_header"> | |||
|
98 | ||||
52 | <div class="compare-buttons"> |
|
99 | <div class="compare-buttons"> | |
53 |
%if |
|
100 | % if c.compare_home: | |
54 |
|
|
101 | <a id="compare_revs" class="btn btn-primary"> ${_('Compare Commits')}</a> | |
|
102 | ||||
|
103 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Swap')}</a> | |||
|
104 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a> | |||
|
105 | <div id="changeset_compare_view_content"> | |||
|
106 | <div class="help-block">${_('Compare commits, branches, bookmarks or tags.')}</div> | |||
|
107 | </div> | |||
|
108 | ||||
|
109 | % elif c.preview_mode: | |||
|
110 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Compare Commits')}</a> | |||
|
111 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Swap')}</a> | |||
|
112 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a> | |||
|
113 | ||||
|
114 | % else: | |||
|
115 | <a id="compare_revs" class="btn btn-primary"> ${_('Compare Commits')}</a> | |||
|
116 | <a id="btn-swap" class="btn btn-primary" href="${c.swap_url}">${_('Swap')}</a> | |||
|
117 | ||||
|
118 | ## allow comment only if there are commits to comment on | |||
|
119 | % if c.diffset and c.diffset.files and c.commit_ranges: | |||
|
120 | <a id="compare_changeset_status_toggle" class="btn btn-primary">${_('Comment')}</a> | |||
|
121 | % else: | |||
|
122 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a> | |||
55 | %endif |
|
123 | % endif | |
56 | <div id="compare_revs" class="btn btn-primary"><i class ="icon-loop"></i> ${_('Compare Commits')}</div> |
|
|||
57 | %if c.diffset and c.diffset.files: |
|
|||
58 | <div id="compare_changeset_status_toggle" class="btn btn-primary">${_('Comment')}</div> |
|
|||
59 | %endif |
|
|||
60 | </div> |
|
|||
61 | %endif |
|
124 | % endif | |
62 | </div> |
|
125 | </div> | |
63 | </div> |
|
126 | </div> | |
64 | </div> |
|
127 | </div> | |
|
128 | </div> | |||
|
129 | </div> | |||
|
130 | </div> | |||
|
131 | ||||
|
132 | <%doc> | |||
|
133 | ##TODO(marcink): implement this and diff menus | |||
|
134 | <div class="fieldset"> | |||
|
135 | <div class="left-label"> | |||
|
136 | ${_('Diff options')}: | |||
|
137 | </div> | |||
|
138 | <div class="right-content"> | |||
|
139 | <div class="diff-actions"> | |||
|
140 | <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |||
|
141 | ${_('Raw Diff')} | |||
|
142 | </a> | |||
|
143 | | | |||
|
144 | <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> | |||
|
145 | ${_('Patch Diff')} | |||
|
146 | </a> | |||
|
147 | | | |||
|
148 | <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision='?',diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"> | |||
|
149 | ${_('Download Diff')} | |||
|
150 | </a> | |||
|
151 | </div> | |||
|
152 | </div> | |||
|
153 | </div> | |||
|
154 | </%doc> | |||
|
155 | ||||
|
156 | </div> <!-- end summary-detail --> | |||
|
157 | ||||
|
158 | </div> <!-- end summary --> | |||
|
159 | ||||
|
160 | ||||
|
161 | <div class="table"> | |||
|
162 | ||||
65 | ## use JS script to load it quickly before potentially large diffs render long time |
|
163 | ## use JS script to load it quickly before potentially large diffs render long time | |
66 | ## this prevents from situation when large diffs block rendering of select2 fields |
|
164 | ## this prevents from situation when large diffs block rendering of select2 fields | |
67 | <script type="text/javascript"> |
|
165 | <script type="text/javascript"> | |
@@ -241,13 +339,26 b'' | |||||
241 |
|
339 | |||
242 | </div> |
|
340 | </div> | |
243 |
|
341 | |||
244 | %if c.compare_home: |
|
342 | %if not c.compare_home: | |
245 | <div id="changeset_compare_view_content"> |
|
343 | <div id="changeset_compare_view_content"> | |
246 | <div class="help-block">${_('Compare commits, branches, bookmarks or tags.')}</div> |
|
344 | <div class="pull-left"> | |
|
345 | <div class="btn-group"> | |||
|
346 | <a | |||
|
347 | class="btn" | |||
|
348 | href="#" | |||
|
349 | onclick="$('.compare_select').show();$('.compare_select_hidden').hide(); return false"> | |||
|
350 | ${ungettext('Expand %s commit','Expand %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |||
|
351 | </a> | |||
|
352 | <a | |||
|
353 | class="btn" | |||
|
354 | href="#" | |||
|
355 | onclick="$('.compare_select').hide();$('.compare_select_hidden').show(); return false"> | |||
|
356 | ${ungettext('Collapse %s commit','Collapse %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |||
|
357 | </a> | |||
247 | </div> |
|
358 | </div> | |
248 | %else: |
|
359 | </div> | |
249 | <div id="changeset_compare_view_content"> |
|
360 | <div style="padding:0 10px 10px 0px" class="pull-left"></div> | |
250 | ##CS |
|
361 | ## commit compare generated below | |
251 | <%include file="compare_commits.html"/> |
|
362 | <%include file="compare_commits.html"/> | |
252 | ${cbdiffs.render_diffset_menu()} |
|
363 | ${cbdiffs.render_diffset_menu()} | |
253 | ${cbdiffs.render_diffset(c.diffset)} |
|
364 | ${cbdiffs.render_diffset(c.diffset)} |
@@ -9,11 +9,9 b'' | |||||
9 | </%def> |
|
9 | </%def> | |
10 |
|
10 | |||
11 | <%def name="js_extra()"> |
|
11 | <%def name="js_extra()"> | |
12 | <script type="text/javascript" src="${h.asset('js/mergerly.js', ver=c.rhodecode_version_hash)}"></script> |
|
|||
13 | </%def> |
|
12 | </%def> | |
14 |
|
13 | |||
15 | <%def name="css_extra()"> |
|
14 | <%def name="css_extra()"> | |
16 | <link rel="stylesheet" type="text/css" href="${h.asset('css/mergerly.css', ver=c.rhodecode_version_hash)}"/> |
|
|||
17 | </%def> |
|
15 | </%def> | |
18 |
|
16 | |||
19 |
|
17 |
@@ -128,7 +128,7 b'' | |||||
128 | // used for history, and switch to |
|
128 | // used for history, and switch to | |
129 | var initialCommitData = { |
|
129 | var initialCommitData = { | |
130 | id: null, |
|
130 | id: null, | |
131 |
text: '${_(" |
|
131 | text: '${_("Pick Commit")}', | |
132 | type: 'sha', |
|
132 | type: 'sha', | |
133 | raw_id: null, |
|
133 | raw_id: null, | |
134 | files_url: null |
|
134 | files_url: null | |
@@ -151,9 +151,47 b'' | |||||
151 |
|
151 | |||
152 | // file history select2 |
|
152 | // file history select2 | |
153 | select2FileHistorySwitcher('#diff1', initialCommitData, state); |
|
153 | select2FileHistorySwitcher('#diff1', initialCommitData, state); | |
|
154 | ||||
|
155 | // show at, diff to actions handlers | |||
154 | $('#diff1').on('change', function(e) { |
|
156 | $('#diff1').on('change', function(e) { | |
155 | $('#diff').removeClass('disabled').removeAttr("disabled"); |
|
157 | $('#diff_to_commit').removeClass('disabled').removeAttr("disabled"); | |
156 | $('#show_rev').removeClass('disabled').removeAttr("disabled"); |
|
158 | $('#diff_to_commit').val(_gettext('Diff to Commit ') + e.val.truncateAfter(8, '...')); | |
|
159 | ||||
|
160 | $('#show_at_commit').removeClass('disabled').removeAttr("disabled"); | |||
|
161 | $('#show_at_commit').val(_gettext('Show at Commit ') + e.val.truncateAfter(8, '...')); | |||
|
162 | }); | |||
|
163 | ||||
|
164 | $('#diff_to_commit').on('click', function(e) { | |||
|
165 | var diff1 = $('#diff1').val(); | |||
|
166 | var diff2 = $('#diff2').val(); | |||
|
167 | ||||
|
168 | var url_data = { | |||
|
169 | repo_name: templateContext.repo_name, | |||
|
170 | source_ref: diff1, | |||
|
171 | source_ref_type: 'rev', | |||
|
172 | target_ref: diff2, | |||
|
173 | target_ref_type: 'rev', | |||
|
174 | merge: 1, | |||
|
175 | f_path: state.f_path | |||
|
176 | }; | |||
|
177 | window.location = pyroutes.url('compare_url', url_data); | |||
|
178 | }); | |||
|
179 | ||||
|
180 | $('#show_at_commit').on('click', function(e) { | |||
|
181 | var diff1 = $('#diff1').val(); | |||
|
182 | ||||
|
183 | var annotate = $('#annotate').val(); | |||
|
184 | if (annotate === "True") { | |||
|
185 | var url = pyroutes.url('files_annotate_home', | |||
|
186 | {'repo_name': templateContext.repo_name, | |||
|
187 | 'revision': diff1, 'f_path': state.f_path}); | |||
|
188 | } else { | |||
|
189 | var url = pyroutes.url('files_home', | |||
|
190 | {'repo_name': templateContext.repo_name, | |||
|
191 | 'revision': diff1, 'f_path': state.f_path}); | |||
|
192 | } | |||
|
193 | window.location = url; | |||
|
194 | ||||
157 | }); |
|
195 | }); | |
158 |
|
196 | |||
159 | // show more authors |
|
197 | // show more authors |
@@ -46,16 +46,28 b'' | |||||
46 | </div> |
|
46 | </div> | |
47 |
|
47 | |||
48 |
|
48 | |||
49 |
<div |
|
49 | <div class="fieldset collapsable-content" data-toggle="summary-details"> | |
50 | ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} |
|
50 | <div class="left-label"> | |
|
51 | ${_('Show/Diff file')}: | |||
|
52 | </div> | |||
|
53 | <div class="right-content"> | |||
51 | ${h.hidden('diff1')} |
|
54 | ${h.hidden('diff1')} | |
52 |
${h.hidden('diff2',c. |
|
55 | ${h.hidden('diff2',c.commit.raw_id)} | |
|
56 | ${h.hidden('annotate', c.annotate)} | |||
|
57 | </div> | |||
|
58 | </div> | |||
53 |
|
59 | |||
54 | ${h.submit('diff',_('Diff to Commit'),class_="btn disabled",disabled="true")} |
|
60 | ||
55 | ${h.submit('show_rev',_('Show at Commit'),class_="btn disabled",disabled="true")} |
|
61 | <div class="fieldset collapsable-content" data-toggle="summary-details"> | |
56 | ${h.hidden('annotate', c.annotate)} |
|
62 | <div class="left-label"> | |
57 | ${h.end_form()} |
|
63 | ${_('Action')}: | |
58 | </div> |
|
64 | </div> | |
|
65 | <div class="right-content"> | |||
|
66 | ${h.submit('diff_to_commit',_('Diff to Commit'),class_="btn disabled",disabled="true")} | |||
|
67 | ${h.submit('show_at_commit',_('Show at Commit'),class_="btn disabled",disabled="true")} | |||
|
68 | </div> | |||
|
69 | </div> | |||
|
70 | ||||
59 |
|
71 | |||
60 | <script> |
|
72 | <script> | |
61 | collapsableContent(); |
|
73 | collapsableContent(); |
@@ -360,14 +360,33 b'' | |||||
360 | </div> |
|
360 | </div> | |
361 | % endif |
|
361 | % endif | |
362 | <div class="compare_view_commits_title"> |
|
362 | <div class="compare_view_commits_title"> | |
|
363 | ||||
|
364 | <div class="pull-left"> | |||
|
365 | <div class="btn-group"> | |||
|
366 | <a | |||
|
367 | class="btn" | |||
|
368 | href="#" | |||
|
369 | onclick="$('.compare_select').show();$('.compare_select_hidden').hide(); return false"> | |||
|
370 | ${ungettext('Expand %s commit','Expand %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |||
|
371 | </a> | |||
|
372 | <a | |||
|
373 | class="btn" | |||
|
374 | href="#" | |||
|
375 | onclick="$('.compare_select').hide();$('.compare_select_hidden').show(); return false"> | |||
|
376 | ${ungettext('Collapse %s commit','Collapse %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |||
|
377 | </a> | |||
|
378 | </div> | |||
|
379 | </div> | |||
|
380 | ||||
|
381 | <div class="pull-right"> | |||
363 | % if c.allowed_to_update and not c.pull_request.is_closed(): |
|
382 | % if c.allowed_to_update and not c.pull_request.is_closed(): | |
364 | <a id="update_commits" class="btn btn-primary pull-right">${_('Update commits')}</a> |
|
383 | <a id="update_commits" class="btn btn-primary pull-right">${_('Update commits')}</a> | |
365 | % else: |
|
384 | % else: | |
366 | <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a> |
|
385 | <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a> | |
367 | % endif |
|
386 | % endif | |
368 | % if len(c.commit_ranges): |
|
387 | ||
369 | <h2>${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}</h2> |
|
388 | </div> | |
370 | % endif |
|
389 | ||
371 | </div> |
|
390 | </div> | |
372 | % if not c.missing_commits: |
|
391 | % if not c.missing_commits: | |
373 | <%include file="/compare/compare_commits.html" /> |
|
392 | <%include file="/compare/compare_commits.html" /> |
@@ -244,7 +244,8 b' class TestCommitCommentsController(TestC' | |||||
244 | ('markdown', '# header', '<h1>header</h1>'), |
|
244 | ('markdown', '# header', '<h1>header</h1>'), | |
245 | ('markdown', '*italics*', '<em>italics</em>'), |
|
245 | ('markdown', '*italics*', '<em>italics</em>'), | |
246 | ('markdown', '**bold**', '<strong>bold</strong>'), |
|
246 | ('markdown', '**bold**', '<strong>bold</strong>'), | |
247 | ]) |
|
247 | ], ids=['rst-plain', 'rst-header', 'rst-italics', 'rst-bold', 'md-plain', | |
|
248 | 'md-header', 'md-italics', 'md-bold', ]) | |||
248 | def test_preview(self, renderer, input, output, backend): |
|
249 | def test_preview(self, renderer, input, output, backend): | |
249 | self.log_user() |
|
250 | self.log_user() | |
250 | params = { |
|
251 | params = { |
@@ -22,16 +22,13 b' import mock' | |||||
22 | import pytest |
|
22 | import pytest | |
23 | import lxml.html |
|
23 | import lxml.html | |
24 |
|
24 | |||
25 | from rhodecode.lib.vcs.backends.base import EmptyCommit |
|
|||
26 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
25 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError | |
27 | from rhodecode.model.db import Repository |
|
26 | from rhodecode.tests import url, assert_session_flash | |
28 | from rhodecode.model.scm import ScmModel |
|
27 | from rhodecode.tests.utils import AssertResponse, commit_change | |
29 | from rhodecode.tests import url, TEST_USER_ADMIN_LOGIN, assert_session_flash |
|
|||
30 | from rhodecode.tests.utils import AssertResponse |
|
|||
31 |
|
28 | |||
32 |
|
29 | |||
33 | @pytest.mark.usefixtures("autologin_user", "app") |
|
30 | @pytest.mark.usefixtures("autologin_user", "app") | |
34 | class TestCompareController: |
|
31 | class TestCompareController(object): | |
35 |
|
32 | |||
36 | @pytest.mark.xfail_backends("svn", reason="Requires pull") |
|
33 | @pytest.mark.xfail_backends("svn", reason="Requires pull") | |
37 | def test_compare_remote_with_different_commit_indexes(self, backend): |
|
34 | def test_compare_remote_with_different_commit_indexes(self, backend): | |
@@ -53,23 +50,23 b' class TestCompareController:' | |||||
53 | fork = backend.create_repo() |
|
50 | fork = backend.create_repo() | |
54 |
|
51 | |||
55 | # prepare fork |
|
52 | # prepare fork | |
56 |
commit0 = |
|
53 | commit0 = commit_change( | |
57 | fork.repo_name, filename='file1', content='A', |
|
54 | fork.repo_name, filename='file1', content='A', | |
58 | message='A', vcs_type=backend.alias, parent=None, newfile=True) |
|
55 | message='A', vcs_type=backend.alias, parent=None, newfile=True) | |
59 |
|
56 | |||
60 |
commit1 = |
|
57 | commit1 = commit_change( | |
61 | fork.repo_name, filename='file1', content='B', |
|
58 | fork.repo_name, filename='file1', content='B', | |
62 | message='B, child of A', vcs_type=backend.alias, parent=commit0) |
|
59 | message='B, child of A', vcs_type=backend.alias, parent=commit0) | |
63 |
|
60 | |||
64 |
|
|
61 | commit_change( # commit 2 | |
65 | fork.repo_name, filename='file1', content='C', |
|
62 | fork.repo_name, filename='file1', content='C', | |
66 | message='C, child of B', vcs_type=backend.alias, parent=commit1) |
|
63 | message='C, child of B', vcs_type=backend.alias, parent=commit1) | |
67 |
|
64 | |||
68 |
commit3 = |
|
65 | commit3 = commit_change( | |
69 | fork.repo_name, filename='file1', content='D', |
|
66 | fork.repo_name, filename='file1', content='D', | |
70 | message='D, child of A', vcs_type=backend.alias, parent=commit0) |
|
67 | message='D, child of A', vcs_type=backend.alias, parent=commit0) | |
71 |
|
68 | |||
72 |
commit4 = |
|
69 | commit4 = commit_change( | |
73 | fork.repo_name, filename='file1', content='E', |
|
70 | fork.repo_name, filename='file1', content='E', | |
74 | message='E, child of D', vcs_type=backend.alias, parent=commit3) |
|
71 | message='E, child of D', vcs_type=backend.alias, parent=commit3) | |
75 |
|
72 | |||
@@ -105,7 +102,7 b' class TestCompareController:' | |||||
105 | repo1 = backend.create_repo() |
|
102 | repo1 = backend.create_repo() | |
106 |
|
103 | |||
107 | # commit something ! |
|
104 | # commit something ! | |
108 |
commit0 = |
|
105 | commit0 = commit_change( | |
109 | repo1.repo_name, filename='file1', content='line1\n', |
|
106 | repo1.repo_name, filename='file1', content='line1\n', | |
110 | message='commit1', vcs_type=backend.alias, parent=None, |
|
107 | message='commit1', vcs_type=backend.alias, parent=None, | |
111 | newfile=True) |
|
108 | newfile=True) | |
@@ -114,11 +111,11 b' class TestCompareController:' | |||||
114 | repo2 = backend.create_fork() |
|
111 | repo2 = backend.create_fork() | |
115 |
|
112 | |||
116 | # add two extra commit into fork |
|
113 | # add two extra commit into fork | |
117 |
commit1 = |
|
114 | commit1 = commit_change( | |
118 | repo2.repo_name, filename='file1', content='line1\nline2\n', |
|
115 | repo2.repo_name, filename='file1', content='line1\nline2\n', | |
119 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
116 | message='commit2', vcs_type=backend.alias, parent=commit0) | |
120 |
|
117 | |||
121 |
commit2 = |
|
118 | commit2 = commit_change( | |
122 | repo2.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
119 | repo2.repo_name, filename='file1', content='line1\nline2\nline3\n', | |
123 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
120 | message='commit3', vcs_type=backend.alias, parent=commit1) | |
124 |
|
121 | |||
@@ -156,7 +153,7 b' class TestCompareController:' | |||||
156 | repo1 = backend.create_repo() |
|
153 | repo1 = backend.create_repo() | |
157 |
|
154 | |||
158 | # commit something ! |
|
155 | # commit something ! | |
159 |
commit0 = |
|
156 | commit0 = commit_change( | |
160 | repo1.repo_name, filename='file1', content='line1\n', |
|
157 | repo1.repo_name, filename='file1', content='line1\n', | |
161 | message='commit1', vcs_type=backend.alias, parent=None, |
|
158 | message='commit1', vcs_type=backend.alias, parent=None, | |
162 | newfile=True) |
|
159 | newfile=True) | |
@@ -165,17 +162,17 b' class TestCompareController:' | |||||
165 | repo2 = backend.create_fork() |
|
162 | repo2 = backend.create_fork() | |
166 |
|
163 | |||
167 | # now commit something to origin repo |
|
164 | # now commit something to origin repo | |
168 |
|
|
165 | commit_change( | |
169 | repo1.repo_name, filename='file2', content='line1file2\n', |
|
166 | repo1.repo_name, filename='file2', content='line1file2\n', | |
170 | message='commit2', vcs_type=backend.alias, parent=commit0, |
|
167 | message='commit2', vcs_type=backend.alias, parent=commit0, | |
171 | newfile=True) |
|
168 | newfile=True) | |
172 |
|
169 | |||
173 | # add two extra commit into fork |
|
170 | # add two extra commit into fork | |
174 |
commit1 = |
|
171 | commit1 = commit_change( | |
175 | repo2.repo_name, filename='file1', content='line1\nline2\n', |
|
172 | repo2.repo_name, filename='file1', content='line1\nline2\n', | |
176 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
173 | message='commit2', vcs_type=backend.alias, parent=commit0) | |
177 |
|
174 | |||
178 |
commit2 = |
|
175 | commit2 = commit_change( | |
179 | repo2.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
176 | repo2.repo_name, filename='file1', content='line1\nline2\nline3\n', | |
180 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
177 | message='commit3', vcs_type=backend.alias, parent=commit1) | |
181 |
|
178 | |||
@@ -207,9 +204,9 b' class TestCompareController:' | |||||
207 | compare_page.swap_is_hidden() |
|
204 | compare_page.swap_is_hidden() | |
208 | compare_page.target_source_are_disabled() |
|
205 | compare_page.target_source_are_disabled() | |
209 |
|
206 | |||
210 |
@pytest.mark.xfail_backends("svn" |
|
207 | @pytest.mark.xfail_backends("svn") | |
|
208 | # TODO(marcink): no svn support for compare two seperate repos | |||
211 | def test_compare_of_unrelated_forks(self, backend): |
|
209 | def test_compare_of_unrelated_forks(self, backend): | |
212 | # TODO: johbo: Fails for git due to some other issue it seems |
|
|||
213 | orig = backend.create_repo(number_of_commits=1) |
|
210 | orig = backend.create_repo(number_of_commits=1) | |
214 | fork = backend.create_repo(number_of_commits=1) |
|
211 | fork = backend.create_repo(number_of_commits=1) | |
215 |
|
212 | |||
@@ -245,11 +242,11 b' class TestCompareController:' | |||||
245 | repo1 = backend.create_repo() |
|
242 | repo1 = backend.create_repo() | |
246 |
|
243 | |||
247 | # commit something ! |
|
244 | # commit something ! | |
248 |
commit0 = |
|
245 | commit0 = commit_change( | |
249 | repo1.repo_name, filename='file1', content='line1\n', |
|
246 | repo1.repo_name, filename='file1', content='line1\n', | |
250 | message='commit1', vcs_type=backend.alias, parent=None, |
|
247 | message='commit1', vcs_type=backend.alias, parent=None, | |
251 | newfile=True) |
|
248 | newfile=True) | |
252 |
commit1 = |
|
249 | commit1 = commit_change( | |
253 | repo1.repo_name, filename='file1', content='line1\nline2\n', |
|
250 | repo1.repo_name, filename='file1', content='line1\nline2\n', | |
254 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
251 | message='commit2', vcs_type=backend.alias, parent=commit0) | |
255 |
|
252 | |||
@@ -257,18 +254,18 b' class TestCompareController:' | |||||
257 | repo2 = backend.create_fork() |
|
254 | repo2 = backend.create_fork() | |
258 |
|
255 | |||
259 | # now make commit3-6 |
|
256 | # now make commit3-6 | |
260 |
commit2 = |
|
257 | commit2 = commit_change( | |
261 | repo1.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
258 | repo1.repo_name, filename='file1', content='line1\nline2\nline3\n', | |
262 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
259 | message='commit3', vcs_type=backend.alias, parent=commit1) | |
263 |
commit3 = |
|
260 | commit3 = commit_change( | |
264 | repo1.repo_name, filename='file1', |
|
261 | repo1.repo_name, filename='file1', | |
265 | content='line1\nline2\nline3\nline4\n', message='commit4', |
|
262 | content='line1\nline2\nline3\nline4\n', message='commit4', | |
266 | vcs_type=backend.alias, parent=commit2) |
|
263 | vcs_type=backend.alias, parent=commit2) | |
267 |
commit4 = |
|
264 | commit4 = commit_change( | |
268 | repo1.repo_name, filename='file1', |
|
265 | repo1.repo_name, filename='file1', | |
269 | content='line1\nline2\nline3\nline4\nline5\n', message='commit5', |
|
266 | content='line1\nline2\nline3\nline4\nline5\n', message='commit5', | |
270 | vcs_type=backend.alias, parent=commit3) |
|
267 | vcs_type=backend.alias, parent=commit3) | |
271 |
|
|
268 | commit_change( # commit 5 | |
272 | repo1.repo_name, filename='file1', |
|
269 | repo1.repo_name, filename='file1', | |
273 | content='line1\nline2\nline3\nline4\nline5\nline6\n', |
|
270 | content='line1\nline2\nline3\nline4\nline5\nline6\n', | |
274 | message='commit6', vcs_type=backend.alias, parent=commit4) |
|
271 | message='commit6', vcs_type=backend.alias, parent=commit4) | |
@@ -311,11 +308,11 b' class TestCompareController:' | |||||
311 | repo1 = backend.create_repo() |
|
308 | repo1 = backend.create_repo() | |
312 |
|
309 | |||
313 | # commit something ! |
|
310 | # commit something ! | |
314 |
commit0 = |
|
311 | commit0 = commit_change( | |
315 | repo1.repo_name, filename='file1', content='line1\n', |
|
312 | repo1.repo_name, filename='file1', content='line1\n', | |
316 | message='commit1', vcs_type=backend.alias, parent=None, |
|
313 | message='commit1', vcs_type=backend.alias, parent=None, | |
317 | newfile=True) |
|
314 | newfile=True) | |
318 |
commit1 = |
|
315 | commit1 = commit_change( | |
319 | repo1.repo_name, filename='file1', content='line1\nline2\n', |
|
316 | repo1.repo_name, filename='file1', content='line1\nline2\n', | |
320 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
317 | message='commit2', vcs_type=backend.alias, parent=commit0) | |
321 |
|
318 | |||
@@ -323,18 +320,18 b' class TestCompareController:' | |||||
323 | backend.create_fork() |
|
320 | backend.create_fork() | |
324 |
|
321 | |||
325 | # now make commit3-6 |
|
322 | # now make commit3-6 | |
326 |
commit2 = |
|
323 | commit2 = commit_change( | |
327 | repo1.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
324 | repo1.repo_name, filename='file1', content='line1\nline2\nline3\n', | |
328 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
325 | message='commit3', vcs_type=backend.alias, parent=commit1) | |
329 |
commit3 = |
|
326 | commit3 = commit_change( | |
330 | repo1.repo_name, filename='file1', |
|
327 | repo1.repo_name, filename='file1', | |
331 | content='line1\nline2\nline3\nline4\n', message='commit4', |
|
328 | content='line1\nline2\nline3\nline4\n', message='commit4', | |
332 | vcs_type=backend.alias, parent=commit2) |
|
329 | vcs_type=backend.alias, parent=commit2) | |
333 |
commit4 = |
|
330 | commit4 = commit_change( | |
334 | repo1.repo_name, filename='file1', |
|
331 | repo1.repo_name, filename='file1', | |
335 | content='line1\nline2\nline3\nline4\nline5\n', message='commit5', |
|
332 | content='line1\nline2\nline3\nline4\nline5\n', message='commit5', | |
336 | vcs_type=backend.alias, parent=commit3) |
|
333 | vcs_type=backend.alias, parent=commit3) | |
337 |
commit5 = |
|
334 | commit5 = commit_change( | |
338 | repo1.repo_name, filename='file1', |
|
335 | repo1.repo_name, filename='file1', | |
339 | content='line1\nline2\nline3\nline4\nline5\nline6\n', |
|
336 | content='line1\nline2\nline3\nline4\nline5\nline6\n', | |
340 | message='commit6', vcs_type=backend.alias, parent=commit4) |
|
337 | message='commit6', vcs_type=backend.alias, parent=commit4) | |
@@ -400,7 +397,7 b' class TestCompareController:' | |||||
400 | repo1 = backend.create_repo() |
|
397 | repo1 = backend.create_repo() | |
401 | r1_name = repo1.repo_name |
|
398 | r1_name = repo1.repo_name | |
402 |
|
399 | |||
403 |
commit0 = |
|
400 | commit0 = commit_change( | |
404 | repo=r1_name, filename='file1', |
|
401 | repo=r1_name, filename='file1', | |
405 | content='line1', message='commit1', vcs_type=backend.alias, |
|
402 | content='line1', message='commit1', vcs_type=backend.alias, | |
406 | newfile=True) |
|
403 | newfile=True) | |
@@ -413,19 +410,19 b' class TestCompareController:' | |||||
413 | self.r2_id = repo2.repo_id |
|
410 | self.r2_id = repo2.repo_id | |
414 | r2_name = repo2.repo_name |
|
411 | r2_name = repo2.repo_name | |
415 |
|
412 | |||
416 |
commit1 = |
|
413 | commit1 = commit_change( | |
417 | repo=r2_name, filename='file1-fork', |
|
414 | repo=r2_name, filename='file1-fork', | |
418 | content='file1-line1-from-fork', message='commit1-fork', |
|
415 | content='file1-line1-from-fork', message='commit1-fork', | |
419 | vcs_type=backend.alias, parent=repo2.scm_instance()[-1], |
|
416 | vcs_type=backend.alias, parent=repo2.scm_instance()[-1], | |
420 | newfile=True) |
|
417 | newfile=True) | |
421 |
|
418 | |||
422 |
commit2 = |
|
419 | commit2 = commit_change( | |
423 | repo=r2_name, filename='file2-fork', |
|
420 | repo=r2_name, filename='file2-fork', | |
424 | content='file2-line1-from-fork', message='commit2-fork', |
|
421 | content='file2-line1-from-fork', message='commit2-fork', | |
425 | vcs_type=backend.alias, parent=commit1, |
|
422 | vcs_type=backend.alias, parent=commit1, | |
426 | newfile=True) |
|
423 | newfile=True) | |
427 |
|
424 | |||
428 |
|
|
425 | commit_change( # commit 3 | |
429 | repo=r2_name, filename='file3-fork', |
|
426 | repo=r2_name, filename='file3-fork', | |
430 | content='file3-line1-from-fork', message='commit3-fork', |
|
427 | content='file3-line1-from-fork', message='commit3-fork', | |
431 | vcs_type=backend.alias, parent=commit2, newfile=True) |
|
428 | vcs_type=backend.alias, parent=commit2, newfile=True) | |
@@ -447,9 +444,9 b' class TestCompareController:' | |||||
447 | response.mustcontain('%s@%s' % (r2_name, commit_id1)) |
|
444 | response.mustcontain('%s@%s' % (r2_name, commit_id1)) | |
448 | response.mustcontain('%s@%s' % (r1_name, commit_id2)) |
|
445 | response.mustcontain('%s@%s' % (r1_name, commit_id2)) | |
449 | response.mustcontain('No files') |
|
446 | response.mustcontain('No files') | |
450 |
response.mustcontain('No |
|
447 | response.mustcontain('No commits in this compare') | |
451 |
|
448 | |||
452 |
commit0 = |
|
449 | commit0 = commit_change( | |
453 | repo=r1_name, filename='file2', |
|
450 | repo=r1_name, filename='file2', | |
454 | content='line1-added-after-fork', message='commit2-parent', |
|
451 | content='line1-added-after-fork', message='commit2-parent', | |
455 | vcs_type=backend.alias, parent=None, newfile=True) |
|
452 | vcs_type=backend.alias, parent=None, newfile=True) | |
@@ -558,7 +555,7 b' class TestCompareController:' | |||||
558 |
|
555 | |||
559 |
|
556 | |||
560 | @pytest.mark.usefixtures("autologin_user") |
|
557 | @pytest.mark.usefixtures("autologin_user") | |
561 | class TestCompareControllerSvn: |
|
558 | class TestCompareControllerSvn(object): | |
562 |
|
559 | |||
563 | def test_supports_references_with_path(self, app, backend_svn): |
|
560 | def test_supports_references_with_path(self, app, backend_svn): | |
564 | repo = backend_svn['svn-simple-layout'] |
|
561 | repo = backend_svn['svn-simple-layout'] | |
@@ -574,7 +571,7 b' class TestCompareControllerSvn:' | |||||
574 | status=200) |
|
571 | status=200) | |
575 |
|
572 | |||
576 | # Expecting no commits, since both paths are at the same revision |
|
573 | # Expecting no commits, since both paths are at the same revision | |
577 |
response.mustcontain('No |
|
574 | response.mustcontain('No commits in this compare') | |
578 |
|
575 | |||
579 | # Should find only one file changed when comparing those two tags |
|
576 | # Should find only one file changed when comparing those two tags | |
580 | response.mustcontain('example.py') |
|
577 | response.mustcontain('example.py') | |
@@ -596,7 +593,7 b' class TestCompareControllerSvn:' | |||||
596 | status=200) |
|
593 | status=200) | |
597 |
|
594 | |||
598 | # It should show commits |
|
595 | # It should show commits | |
599 |
assert 'No |
|
596 | assert 'No commits in this compare' not in response.body | |
600 |
|
597 | |||
601 | # Should find only one file changed when comparing those two tags |
|
598 | # Should find only one file changed when comparing those two tags | |
602 | response.mustcontain('example.py') |
|
599 | response.mustcontain('example.py') | |
@@ -660,36 +657,3 b' class ComparePage(AssertResponse):' | |||||
660 | def target_source_are_enabled(self): |
|
657 | def target_source_are_enabled(self): | |
661 | response = self.response |
|
658 | response = self.response | |
662 | response.mustcontain("var enable_fields = true;") |
|
659 | response.mustcontain("var enable_fields = true;") | |
663 |
|
||||
664 |
|
||||
665 | def _commit_change( |
|
|||
666 | repo, filename, content, message, vcs_type, parent=None, |
|
|||
667 | newfile=False): |
|
|||
668 | repo = Repository.get_by_repo_name(repo) |
|
|||
669 | _commit = parent |
|
|||
670 | if not parent: |
|
|||
671 | _commit = EmptyCommit(alias=vcs_type) |
|
|||
672 |
|
||||
673 | if newfile: |
|
|||
674 | nodes = { |
|
|||
675 | filename: { |
|
|||
676 | 'content': content |
|
|||
677 | } |
|
|||
678 | } |
|
|||
679 | commit = ScmModel().create_nodes( |
|
|||
680 | user=TEST_USER_ADMIN_LOGIN, repo=repo, |
|
|||
681 | message=message, |
|
|||
682 | nodes=nodes, |
|
|||
683 | parent_commit=_commit, |
|
|||
684 | author=TEST_USER_ADMIN_LOGIN, |
|
|||
685 | ) |
|
|||
686 | else: |
|
|||
687 | commit = ScmModel().commit_change( |
|
|||
688 | repo=repo.scm_instance(), repo_name=repo.repo_name, |
|
|||
689 | commit=parent, user=TEST_USER_ADMIN_LOGIN, |
|
|||
690 | author=TEST_USER_ADMIN_LOGIN, |
|
|||
691 | message=message, |
|
|||
692 | content=content, |
|
|||
693 | f_path=filename |
|
|||
694 | ) |
|
|||
695 | return commit |
|
@@ -44,7 +44,7 b' class TestCompareController:' | |||||
44 | response.mustcontain('%s@%s' % (backend.repo_name, tag1)) |
|
44 | response.mustcontain('%s@%s' % (backend.repo_name, tag1)) | |
45 | response.mustcontain('%s@%s' % (backend.repo_name, tag2)) |
|
45 | response.mustcontain('%s@%s' % (backend.repo_name, tag2)) | |
46 |
|
46 | |||
47 |
# outgoing c |
|
47 | # outgoing commits between tags | |
48 | commit_indexes = { |
|
48 | commit_indexes = { | |
49 | 'git': [113] + range(115, 121), |
|
49 | 'git': [113] + range(115, 121), | |
50 | 'hg': [112] + range(115, 121), |
|
50 | 'hg': [112] + range(115, 121), | |
@@ -118,8 +118,8 b' class TestCompareController:' | |||||
118 | response.mustcontain('%s@%s' % (backend.repo_name, head_id)) |
|
118 | response.mustcontain('%s@%s' % (backend.repo_name, head_id)) | |
119 |
|
119 | |||
120 | # branches are equal |
|
120 | # branches are equal | |
121 |
response.mustcontain(' |
|
121 | response.mustcontain('No files') | |
122 |
response.mustcontain(' |
|
122 | response.mustcontain('No commits in this compare') | |
123 |
|
123 | |||
124 | def test_compare_commits(self, backend): |
|
124 | def test_compare_commits(self, backend): | |
125 | repo = backend.repo |
|
125 | repo = backend.repo |
@@ -28,15 +28,11 b' from rhodecode.lib import helpers as h' | |||||
28 | from rhodecode.lib.compat import OrderedDict |
|
28 | from rhodecode.lib.compat import OrderedDict | |
29 | from rhodecode.lib.ext_json import json |
|
29 | from rhodecode.lib.ext_json import json | |
30 | from rhodecode.lib.vcs import nodes |
|
30 | from rhodecode.lib.vcs import nodes | |
31 | from rhodecode.lib.vcs.backends.base import EmptyCommit |
|
31 | ||
32 | from rhodecode.lib.vcs.conf import settings |
|
32 | from rhodecode.lib.vcs.conf import settings | |
33 | from rhodecode.lib.vcs.nodes import FileNode |
|
|||
34 | from rhodecode.model.db import Repository |
|
|||
35 | from rhodecode.model.scm import ScmModel |
|
|||
36 | from rhodecode.tests import ( |
|
33 | from rhodecode.tests import ( | |
37 |
url |
|
34 | url, assert_session_flash, assert_not_in_session_flash) | |
38 | from rhodecode.tests.fixture import Fixture |
|
35 | from rhodecode.tests.fixture import Fixture | |
39 | from rhodecode.tests.utils import AssertResponse |
|
|||
40 |
|
36 | |||
41 | fixture = Fixture() |
|
37 | fixture = Fixture() | |
42 |
|
38 | |||
@@ -48,40 +44,6 b' NODE_HISTORY = {' | |||||
48 |
|
44 | |||
49 |
|
45 | |||
50 |
|
46 | |||
51 | def _commit_change( |
|
|||
52 | repo, filename, content, message, vcs_type, parent=None, |
|
|||
53 | newfile=False): |
|
|||
54 | repo = Repository.get_by_repo_name(repo) |
|
|||
55 | _commit = parent |
|
|||
56 | if not parent: |
|
|||
57 | _commit = EmptyCommit(alias=vcs_type) |
|
|||
58 |
|
||||
59 | if newfile: |
|
|||
60 | nodes = { |
|
|||
61 | filename: { |
|
|||
62 | 'content': content |
|
|||
63 | } |
|
|||
64 | } |
|
|||
65 | commit = ScmModel().create_nodes( |
|
|||
66 | user=TEST_USER_ADMIN_LOGIN, repo=repo, |
|
|||
67 | message=message, |
|
|||
68 | nodes=nodes, |
|
|||
69 | parent_commit=_commit, |
|
|||
70 | author=TEST_USER_ADMIN_LOGIN, |
|
|||
71 | ) |
|
|||
72 | else: |
|
|||
73 | commit = ScmModel().commit_change( |
|
|||
74 | repo=repo.scm_instance(), repo_name=repo.repo_name, |
|
|||
75 | commit=parent, user=TEST_USER_ADMIN_LOGIN, |
|
|||
76 | author=TEST_USER_ADMIN_LOGIN, |
|
|||
77 | message=message, |
|
|||
78 | content=content, |
|
|||
79 | f_path=filename |
|
|||
80 | ) |
|
|||
81 | return commit |
|
|||
82 |
|
||||
83 |
|
||||
84 |
|
||||
85 | @pytest.mark.usefixtures("app") |
|
47 | @pytest.mark.usefixtures("app") | |
86 | class TestFilesController: |
|
48 | class TestFilesController: | |
87 |
|
49 | |||
@@ -120,7 +82,7 b' class TestFilesController:' | |||||
120 | response = self.app.get(url( |
|
82 | response = self.app.get(url( | |
121 | controller='files', action='index', |
|
83 | controller='files', action='index', | |
122 | repo_name=repo.repo_name, revision='tip', f_path='/')) |
|
84 | repo_name=repo.repo_name, revision='tip', f_path='/')) | |
123 |
assert_response = |
|
85 | assert_response = response.assert_response() | |
124 | assert_response.contains_one_link( |
|
86 | assert_response.contains_one_link( | |
125 | 'absolute-path @ 000000000000', 'http://example.com/absolute-path') |
|
87 | 'absolute-path @ 000000000000', 'http://example.com/absolute-path') | |
126 |
|
88 | |||
@@ -130,7 +92,7 b' class TestFilesController:' | |||||
130 | response = self.app.get(url( |
|
92 | response = self.app.get(url( | |
131 | controller='files', action='index', |
|
93 | controller='files', action='index', | |
132 | repo_name=repo.repo_name, revision='tip', f_path='/')) |
|
94 | repo_name=repo.repo_name, revision='tip', f_path='/')) | |
133 |
assert_response = |
|
95 | assert_response = response.assert_response() | |
134 | assert_response.contains_one_link( |
|
96 | assert_response.contains_one_link( | |
135 | 'subpaths-path @ 000000000000', |
|
97 | 'subpaths-path @ 000000000000', | |
136 | 'http://sub-base.example.com/subpaths-path') |
|
98 | 'http://sub-base.example.com/subpaths-path') | |
@@ -179,21 +141,24 b' class TestFilesController:' | |||||
179 | assert_dirs_in_response(response, dirs, params) |
|
141 | assert_dirs_in_response(response, dirs, params) | |
180 | assert_files_in_response(response, files, params) |
|
142 | assert_files_in_response(response, files, params) | |
181 |
|
143 | |||
182 | @pytest.mark.xfail_backends("git", reason="Missing branches in git repo") |
|
|||
183 | @pytest.mark.xfail_backends("svn", reason="Depends on branch support") |
|
|||
184 | def test_index_different_branch(self, backend): |
|
144 | def test_index_different_branch(self, backend): | |
185 | # TODO: Git test repository does not contain branches |
|
145 | branches = dict( | |
|
146 | hg=(150, ['git']), | |||
|
147 | # TODO: Git test repository does not contain other branches | |||
|
148 | git=(633, ['master']), | |||
186 | # TODO: Branch support in Subversion |
|
149 | # TODO: Branch support in Subversion | |
187 |
|
150 | svn=(150, []) | ||
188 | commit = backend.repo.get_commit(commit_idx=150) |
|
151 | ) | |
|
152 | idx, branches = branches[backend.alias] | |||
|
153 | commit = backend.repo.get_commit(commit_idx=idx) | |||
189 | response = self.app.get(url( |
|
154 | response = self.app.get(url( | |
190 | controller='files', action='index', |
|
155 | controller='files', action='index', | |
191 | repo_name=backend.repo_name, |
|
156 | repo_name=backend.repo_name, | |
192 | revision=commit.raw_id, |
|
157 | revision=commit.raw_id, | |
193 | f_path='/')) |
|
158 | f_path='/')) | |
194 |
assert_response = |
|
159 | assert_response = response.assert_response() | |
195 | assert_response.element_contains( |
|
160 | for branch in branches: | |
196 |
'.tags .branchtag', |
|
161 | assert_response.element_contains('.tags .branchtag', branch) | |
197 |
|
162 | |||
198 | def test_index_paging(self, backend): |
|
163 | def test_index_paging(self, backend): | |
199 | repo = backend.repo |
|
164 | repo = backend.repo | |
@@ -221,7 +186,7 b' class TestFilesController:' | |||||
221 | msgbox = """<div class="commit right-content">%s</div>""" |
|
186 | msgbox = """<div class="commit right-content">%s</div>""" | |
222 | response.mustcontain(msgbox % (commit.message, )) |
|
187 | response.mustcontain(msgbox % (commit.message, )) | |
223 |
|
188 | |||
224 |
assert_response = |
|
189 | assert_response = response.assert_response() | |
225 | if commit.branch: |
|
190 | if commit.branch: | |
226 | assert_response.element_contains('.tags.tags-main .branchtag', commit.branch) |
|
191 | assert_response.element_contains('.tags.tags-main .branchtag', commit.branch) | |
227 | if commit.tags: |
|
192 | if commit.tags: | |
@@ -348,7 +313,7 b' class TestFilesController:' | |||||
348 | f_path='/', commit_id=commit.raw_id), |
|
313 | f_path='/', commit_id=commit.raw_id), | |
349 | extra_environ=xhr_header) |
|
314 | extra_environ=xhr_header) | |
350 |
|
315 | |||
351 |
assert_response = |
|
316 | assert_response = response.assert_response() | |
352 |
|
317 | |||
353 | for attr in ['data-commit-id', 'data-date', 'data-author']: |
|
318 | for attr in ['data-commit-id', 'data-date', 'data-author']: | |
354 | elements = assert_response.get_elements('[{}]'.format(attr)) |
|
319 | elements = assert_response.get_elements('[{}]'.format(attr)) | |
@@ -401,7 +366,7 b' class TestFilesController:' | |||||
401 | # TODO: johbo: Think about a better place for these tests. Either controller |
|
366 | # TODO: johbo: Think about a better place for these tests. Either controller | |
402 | # specific unit tests or we move down the whole logic further towards the vcs |
|
367 | # specific unit tests or we move down the whole logic further towards the vcs | |
403 | # layer |
|
368 | # layer | |
404 | class TestAdjustFilePathForSvn: |
|
369 | class TestAdjustFilePathForSvn(object): | |
405 | """SVN specific adjustments of node history in FileController.""" |
|
370 | """SVN specific adjustments of node history in FileController.""" | |
406 |
|
371 | |||
407 | def test_returns_path_relative_to_matched_reference(self): |
|
372 | def test_returns_path_relative_to_matched_reference(self): | |
@@ -433,7 +398,7 b' class TestAdjustFilePathForSvn:' | |||||
433 |
|
398 | |||
434 |
|
399 | |||
435 | @pytest.mark.usefixtures("app") |
|
400 | @pytest.mark.usefixtures("app") | |
436 | class TestRepositoryArchival: |
|
401 | class TestRepositoryArchival(object): | |
437 |
|
402 | |||
438 | def test_archival(self, backend): |
|
403 | def test_archival(self, backend): | |
439 | backend.enable_downloads() |
|
404 | backend.enable_downloads() | |
@@ -485,7 +450,7 b' class TestRepositoryArchival:' | |||||
485 |
|
450 | |||
486 |
|
451 | |||
487 | @pytest.mark.usefixtures("app", "autologin_user") |
|
452 | @pytest.mark.usefixtures("app", "autologin_user") | |
488 | class TestRawFileHandling: |
|
453 | class TestRawFileHandling(object): | |
489 |
|
454 | |||
490 | def test_raw_file_ok(self, backend): |
|
455 | def test_raw_file_ok(self, backend): | |
491 | commit = backend.repo.get_commit(commit_idx=173) |
|
456 | commit = backend.repo.get_commit(commit_idx=173) | |
@@ -575,6 +540,7 b' class TestFilesDiff:' | |||||
575 | def test_file_full_diff(self, backend, diff): |
|
540 | def test_file_full_diff(self, backend, diff): | |
576 | commit1 = backend.repo.get_commit(commit_idx=-1) |
|
541 | commit1 = backend.repo.get_commit(commit_idx=-1) | |
577 | commit2 = backend.repo.get_commit(commit_idx=-2) |
|
542 | commit2 = backend.repo.get_commit(commit_idx=-2) | |
|
543 | ||||
578 | response = self.app.get( |
|
544 | response = self.app.get( | |
579 | url( |
|
545 | url( | |
580 | controller='files', |
|
546 | controller='files', | |
@@ -582,11 +548,17 b' class TestFilesDiff:' | |||||
582 | repo_name=backend.repo_name, |
|
548 | repo_name=backend.repo_name, | |
583 | f_path='README'), |
|
549 | f_path='README'), | |
584 | params={ |
|
550 | params={ | |
585 |
'diff1': commit |
|
551 | 'diff1': commit2.raw_id, | |
586 |
'diff2': commit |
|
552 | 'diff2': commit1.raw_id, | |
587 | 'fulldiff': '1', |
|
553 | 'fulldiff': '1', | |
588 | 'diff': diff, |
|
554 | 'diff': diff, | |
589 | }) |
|
555 | }) | |
|
556 | ||||
|
557 | if diff == 'diff': | |||
|
558 | # use redirect since this is OLD view redirecting to compare page | |||
|
559 | response = response.follow() | |||
|
560 | ||||
|
561 | # It's a symlink to README.rst | |||
590 | response.mustcontain('README.rst') |
|
562 | response.mustcontain('README.rst') | |
591 | response.mustcontain('No newline at end of file') |
|
563 | response.mustcontain('No newline at end of file') | |
592 |
|
564 | |||
@@ -610,7 +582,17 b' class TestFilesDiff:' | |||||
610 | 'fulldiff': '1', |
|
582 | 'fulldiff': '1', | |
611 | 'diff': 'diff', |
|
583 | 'diff': 'diff', | |
612 | }) |
|
584 | }) | |
613 | response.mustcontain('Cannot diff binary files') |
|
585 | # use redirect since this is OLD view redirecting to compare page | |
|
586 | response = response.follow() | |||
|
587 | response.mustcontain('Expand 1 commit') | |||
|
588 | response.mustcontain('1 file changed: 0 inserted, 0 deleted') | |||
|
589 | ||||
|
590 | if backend.alias == 'svn': | |||
|
591 | response.mustcontain('new file 10644') | |||
|
592 | # TODO(marcink): SVN doesn't yet detect binary changes | |||
|
593 | else: | |||
|
594 | response.mustcontain('new file 100644') | |||
|
595 | response.mustcontain('binary diff hidden') | |||
614 |
|
596 | |||
615 | def test_diff_2way(self, backend): |
|
597 | def test_diff_2way(self, backend): | |
616 | commit1 = backend.repo.get_commit(commit_idx=-1) |
|
598 | commit1 = backend.repo.get_commit(commit_idx=-1) | |
@@ -622,14 +604,15 b' class TestFilesDiff:' | |||||
622 | repo_name=backend.repo_name, |
|
604 | repo_name=backend.repo_name, | |
623 | f_path='README'), |
|
605 | f_path='README'), | |
624 | params={ |
|
606 | params={ | |
625 |
'diff1': commit |
|
607 | 'diff1': commit2.raw_id, | |
626 |
'diff2': commit |
|
608 | 'diff2': commit1.raw_id, | |
627 | }) |
|
609 | }) | |
|
610 | # use redirect since this is OLD view redirecting to compare page | |||
|
611 | response = response.follow() | |||
628 |
|
612 | |||
629 | # Expecting links to both variants of the file. Links are used |
|
613 | # It's a symlink to README.rst | |
630 | # to load the content dynamically. |
|
614 | response.mustcontain('README.rst') | |
631 | response.mustcontain('/%s/README' % commit1.raw_id) |
|
615 | response.mustcontain('No newline at end of file') | |
632 | response.mustcontain('/%s/README' % commit2.raw_id) |
|
|||
633 |
|
616 | |||
634 | def test_requires_one_commit_id(self, backend, autologin_user): |
|
617 | def test_requires_one_commit_id(self, backend, autologin_user): | |
635 | response = self.app.get( |
|
618 | response = self.app.get( | |
@@ -642,17 +625,19 b' class TestFilesDiff:' | |||||
642 | response.mustcontain( |
|
625 | response.mustcontain( | |
643 | 'Need query parameter', 'diff1', 'diff2', 'to generate a diff.') |
|
626 | 'Need query parameter', 'diff1', 'diff2', 'to generate a diff.') | |
644 |
|
627 | |||
645 |
def test_returns_no |
|
628 | def test_returns_no_files_if_file_does_not_exist(self, vcsbackend): | |
646 | repo = vcsbackend.repo |
|
629 | repo = vcsbackend.repo | |
647 | self.app.get( |
|
630 | response = self.app.get( | |
648 | url( |
|
631 | url( | |
649 | controller='files', |
|
632 | controller='files', | |
650 | action='diff', |
|
633 | action='diff', | |
651 | repo_name=repo.name, |
|
634 | repo_name=repo.name, | |
652 | f_path='does-not-exist-in-any-commit', |
|
635 | f_path='does-not-exist-in-any-commit', | |
653 | diff1=repo[0].raw_id, |
|
636 | diff1=repo[0].raw_id, | |
654 | diff2=repo[1].raw_id), |
|
637 | diff2=repo[1].raw_id),) | |
655 | status=404) |
|
638 | ||
|
639 | response = response.follow() | |||
|
640 | response.mustcontain('No files') | |||
656 |
|
641 | |||
657 | def test_returns_redirect_if_file_not_changed(self, backend): |
|
642 | def test_returns_redirect_if_file_not_changed(self, backend): | |
658 | commit = backend.repo.get_commit(commit_idx=-1) |
|
643 | commit = backend.repo.get_commit(commit_idx=-1) | |
@@ -666,25 +651,40 b' class TestFilesDiff:' | |||||
666 | diff1=commit.raw_id, |
|
651 | diff1=commit.raw_id, | |
667 | diff2=commit.raw_id, |
|
652 | diff2=commit.raw_id, | |
668 | ), |
|
653 | ), | |
669 | status=302 |
|
|||
670 | ) |
|
654 | ) | |
671 | assert response.headers['Location'].endswith(f_path) |
|
655 | response = response.follow() | |
672 | redirected = response.follow() |
|
656 | response.mustcontain('No files') | |
673 |
re |
|
657 | response.mustcontain('No commits in this compare') | |
674 |
|
658 | |||
675 | def test_supports_diff_to_different_path_svn(self, backend_svn): |
|
659 | def test_supports_diff_to_different_path_svn(self, backend_svn): | |
|
660 | #TODO: check this case | |||
|
661 | return | |||
|
662 | ||||
676 | repo = backend_svn['svn-simple-layout'].scm_instance() |
|
663 | repo = backend_svn['svn-simple-layout'].scm_instance() | |
677 |
commit_id = |
|
664 | commit_id_1 = '24' | |
|
665 | commit_id_2 = '26' | |||
|
666 | ||||
|
667 | ||||
|
668 | print( url( | |||
|
669 | controller='files', | |||
|
670 | action='diff', | |||
|
671 | repo_name=repo.name, | |||
|
672 | f_path='trunk/example.py', | |||
|
673 | diff1='tags/v0.2/example.py@' + commit_id_1, | |||
|
674 | diff2=commit_id_2)) | |||
|
675 | ||||
678 | response = self.app.get( |
|
676 | response = self.app.get( | |
679 | url( |
|
677 | url( | |
680 | controller='files', |
|
678 | controller='files', | |
681 | action='diff', |
|
679 | action='diff', | |
682 | repo_name=repo.name, |
|
680 | repo_name=repo.name, | |
683 | f_path='trunk/example.py', |
|
681 | f_path='trunk/example.py', | |
684 | diff1='tags/v0.2/example.py@' + commit_id, |
|
682 | diff1='tags/v0.2/example.py@' + commit_id_1, | |
685 |
diff2=commit_id) |
|
683 | diff2=commit_id_2)) | |
686 | status=200) |
|
684 | ||
|
685 | response = response.follow() | |||
687 | response.mustcontain( |
|
686 | response.mustcontain( | |
|
687 | # diff contains this | |||
688 | "Will print out a useful message on invocation.") |
|
688 | "Will print out a useful message on invocation.") | |
689 |
|
689 | |||
690 | # Note: Expecting that we indicate the user what's being compared |
|
690 | # Note: Expecting that we indicate the user what's being compared | |
@@ -692,6 +692,9 b' class TestFilesDiff:' | |||||
692 | response.mustcontain("tags/v0.2/example.py") |
|
692 | response.mustcontain("tags/v0.2/example.py") | |
693 |
|
693 | |||
694 | def test_show_rev_redirects_to_svn_path(self, backend_svn): |
|
694 | def test_show_rev_redirects_to_svn_path(self, backend_svn): | |
|
695 | #TODO: check this case | |||
|
696 | return | |||
|
697 | ||||
695 | repo = backend_svn['svn-simple-layout'].scm_instance() |
|
698 | repo = backend_svn['svn-simple-layout'].scm_instance() | |
696 | commit_id = repo[-1].raw_id |
|
699 | commit_id = repo[-1].raw_id | |
697 | response = self.app.get( |
|
700 | response = self.app.get( | |
@@ -708,6 +711,9 b' class TestFilesDiff:' | |||||
708 | 'svn-svn-simple-layout/files/26/branches/argparse/example.py') |
|
711 | 'svn-svn-simple-layout/files/26/branches/argparse/example.py') | |
709 |
|
712 | |||
710 | def test_show_rev_and_annotate_redirects_to_svn_path(self, backend_svn): |
|
713 | def test_show_rev_and_annotate_redirects_to_svn_path(self, backend_svn): | |
|
714 | #TODO: check this case | |||
|
715 | return | |||
|
716 | ||||
711 | repo = backend_svn['svn-simple-layout'].scm_instance() |
|
717 | repo = backend_svn['svn-simple-layout'].scm_instance() | |
712 | commit_id = repo[-1].raw_id |
|
718 | commit_id = repo[-1].raw_id | |
713 | response = self.app.get( |
|
719 | response = self.app.get( | |
@@ -979,100 +985,3 b' def _assert_items_in_response(response, ' | |||||
979 | def assert_timeago_in_response(response, items, params): |
|
985 | def assert_timeago_in_response(response, items, params): | |
980 | for item in items: |
|
986 | for item in items: | |
981 | response.mustcontain(h.age_component(params['date'])) |
|
987 | response.mustcontain(h.age_component(params['date'])) | |
982 |
|
||||
983 |
|
||||
984 |
|
||||
985 | @pytest.mark.usefixtures("autologin_user", "app") |
|
|||
986 | class TestSideBySideDiff: |
|
|||
987 |
|
||||
988 | def test_diff2way(self, app, backend, backend_stub): |
|
|||
989 | f_path = 'content' |
|
|||
990 | commit1_content = 'content-25d7e49c18b159446c' |
|
|||
991 | commit2_content = 'content-603d6c72c46d953420' |
|
|||
992 | repo = backend.create_repo() |
|
|||
993 |
|
||||
994 | commit1 = _commit_change( |
|
|||
995 | repo.repo_name, filename=f_path, content=commit1_content, |
|
|||
996 | message='A', vcs_type=backend.alias, parent=None, newfile=True) |
|
|||
997 |
|
||||
998 | commit2 = _commit_change( |
|
|||
999 | repo.repo_name, filename=f_path, content=commit2_content, |
|
|||
1000 | message='B, child of A', vcs_type=backend.alias, parent=commit1) |
|
|||
1001 |
|
||||
1002 | response = self.app.get(url( |
|
|||
1003 | controller='files', action='diff_2way', |
|
|||
1004 | repo_name=repo.repo_name, |
|
|||
1005 | diff1=commit1.raw_id, |
|
|||
1006 | diff2=commit2.raw_id, |
|
|||
1007 | f_path=f_path)) |
|
|||
1008 |
|
||||
1009 | assert_response = AssertResponse(response) |
|
|||
1010 | response.mustcontain( |
|
|||
1011 | ('Side-by-side Diff r0:%s ... r1:%s') % ( commit1.short_id, commit2.short_id )) |
|
|||
1012 | response.mustcontain('id="compare"') |
|
|||
1013 | response.mustcontain(( |
|
|||
1014 | "var orig1_url = '/%s/raw/%s/%s';\n" |
|
|||
1015 | "var orig2_url = '/%s/raw/%s/%s';") % |
|
|||
1016 | ( repo.repo_name, commit1.raw_id, f_path, |
|
|||
1017 | repo.repo_name, commit2.raw_id, f_path)) |
|
|||
1018 |
|
||||
1019 |
|
||||
1020 | def test_diff2way_with_empty_file(self, app, backend, backend_stub): |
|
|||
1021 | commits = [ |
|
|||
1022 | {'message': 'First commit'}, |
|
|||
1023 | {'message': 'Commit with binary', |
|
|||
1024 | 'added': [nodes.FileNode('file.empty', content='')]}, |
|
|||
1025 | ] |
|
|||
1026 | f_path='file.empty' |
|
|||
1027 | repo = backend.create_repo(commits=commits) |
|
|||
1028 | commit_id1 = repo.get_commit(commit_idx=0).raw_id |
|
|||
1029 | commit_id2 = repo.get_commit(commit_idx=1).raw_id |
|
|||
1030 |
|
||||
1031 | response = self.app.get(url( |
|
|||
1032 | controller='files', action='diff_2way', |
|
|||
1033 | repo_name=repo.repo_name, |
|
|||
1034 | diff1=commit_id1, |
|
|||
1035 | diff2=commit_id2, |
|
|||
1036 | f_path=f_path)) |
|
|||
1037 |
|
||||
1038 | assert_response = AssertResponse(response) |
|
|||
1039 | if backend.alias == 'svn': |
|
|||
1040 | assert_session_flash( response, |
|
|||
1041 | ('%(file_path)s has not changed') % { 'file_path': 'file.empty' }) |
|
|||
1042 | else: |
|
|||
1043 | response.mustcontain( |
|
|||
1044 | ('Side-by-side Diff r0:%s ... r1:%s') % ( repo.get_commit(commit_idx=0).short_id, repo.get_commit(commit_idx=1).short_id )) |
|
|||
1045 | response.mustcontain('id="compare"') |
|
|||
1046 | response.mustcontain(( |
|
|||
1047 | "var orig1_url = '/%s/raw/%s/%s';\n" |
|
|||
1048 | "var orig2_url = '/%s/raw/%s/%s';") % |
|
|||
1049 | ( repo.repo_name, commit_id1, f_path, |
|
|||
1050 | repo.repo_name, commit_id2, f_path)) |
|
|||
1051 |
|
||||
1052 |
|
||||
1053 | def test_empty_diff_2way_redirect_to_summary_with_alert(self, app, backend): |
|
|||
1054 | commit_id_range = { |
|
|||
1055 | 'hg': ( |
|
|||
1056 | '25d7e49c18b159446cadfa506a5cf8ad1cb04067', |
|
|||
1057 | '603d6c72c46d953420c89d36372f08d9f305f5dd'), |
|
|||
1058 | 'git': ( |
|
|||
1059 | '6fc9270775aaf5544c1deb014f4ddd60c952fcbb', |
|
|||
1060 | '03fa803d7e9fb14daa9a3089e0d1494eda75d986'), |
|
|||
1061 | 'svn': ( |
|
|||
1062 | '335', |
|
|||
1063 | '337'), |
|
|||
1064 | } |
|
|||
1065 | f_path = 'setup.py' |
|
|||
1066 |
|
||||
1067 | commit_ids = commit_id_range[backend.alias] |
|
|||
1068 |
|
||||
1069 | response = self.app.get(url( |
|
|||
1070 | controller='files', action='diff_2way', |
|
|||
1071 | repo_name=backend.repo_name, |
|
|||
1072 | diff2=commit_ids[0], |
|
|||
1073 | diff1=commit_ids[1], |
|
|||
1074 | f_path=f_path)) |
|
|||
1075 |
|
||||
1076 | assert_response = AssertResponse(response) |
|
|||
1077 | assert_session_flash( response, |
|
|||
1078 | ('%(file_path)s has not changed') % { 'file_path': f_path }) |
|
@@ -531,6 +531,81 b' DIFF_FIXTURES = [' | |||||
531 | }), |
|
531 | }), | |
532 | ]), |
|
532 | ]), | |
533 |
|
533 | |||
|
534 | ('svn', | |||
|
535 | 'svn_diff_binary_add_file.diff', | |||
|
536 | [('intl.dll', 'A', | |||
|
537 | {'added': 0, | |||
|
538 | 'deleted': 0, | |||
|
539 | 'binary': False, | |||
|
540 | 'ops': {NEW_FILENODE: 'new file 10644', | |||
|
541 | #TODO(Marcink): depends on binary detection on svn patches | |||
|
542 | # BIN_FILENODE: 'binary diff hidden' | |||
|
543 | } | |||
|
544 | }), | |||
|
545 | ]), | |||
|
546 | ||||
|
547 | ('svn', | |||
|
548 | 'svn_diff_multiple_changes.diff', | |||
|
549 | [('trunk/doc/images/SettingsOverlay.png', 'M', | |||
|
550 | {'added': 0, | |||
|
551 | 'deleted': 0, | |||
|
552 | 'binary': False, | |||
|
553 | 'ops': {MOD_FILENODE: 'modified file', | |||
|
554 | #TODO(Marcink): depends on binary detection on svn patches | |||
|
555 | # BIN_FILENODE: 'binary diff hidden' | |||
|
556 | } | |||
|
557 | }), | |||
|
558 | ('trunk/doc/source/de/tsvn_ch04.xml', 'M', | |||
|
559 | {'added': 89, | |||
|
560 | 'deleted': 34, | |||
|
561 | 'binary': False, | |||
|
562 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
563 | }), | |||
|
564 | ('trunk/doc/source/en/tsvn_ch04.xml', 'M', | |||
|
565 | {'added': 66, | |||
|
566 | 'deleted': 21, | |||
|
567 | 'binary': False, | |||
|
568 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
569 | }), | |||
|
570 | ('trunk/src/Changelog.txt', 'M', | |||
|
571 | {'added': 2, | |||
|
572 | 'deleted': 0, | |||
|
573 | 'binary': False, | |||
|
574 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
575 | }), | |||
|
576 | ('trunk/src/Resources/TortoiseProcENG.rc', 'M', | |||
|
577 | {'added': 19, | |||
|
578 | 'deleted': 13, | |||
|
579 | 'binary': False, | |||
|
580 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
581 | }), | |||
|
582 | ('trunk/src/TortoiseProc/SetOverlayPage.cpp', 'M', | |||
|
583 | {'added': 16, | |||
|
584 | 'deleted': 1, | |||
|
585 | 'binary': False, | |||
|
586 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
587 | }), | |||
|
588 | ('trunk/src/TortoiseProc/SetOverlayPage.h', 'M', | |||
|
589 | {'added': 3, | |||
|
590 | 'deleted': 0, | |||
|
591 | 'binary': False, | |||
|
592 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
593 | }), | |||
|
594 | ('trunk/src/TortoiseProc/resource.h', 'M', | |||
|
595 | {'added': 2, | |||
|
596 | 'deleted': 0, | |||
|
597 | 'binary': False, | |||
|
598 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
599 | }), | |||
|
600 | ('trunk/src/TortoiseShell/ShellCache.h', 'M', | |||
|
601 | {'added': 50, | |||
|
602 | 'deleted': 1, | |||
|
603 | 'binary': False, | |||
|
604 | 'ops': {MOD_FILENODE: 'modified file'} | |||
|
605 | }), | |||
|
606 | ]), | |||
|
607 | ||||
|
608 | ||||
534 | # TODO: mikhail: do we still need this? |
|
609 | # TODO: mikhail: do we still need this? | |
535 | # ( |
|
610 | # ( | |
536 | # 'hg', |
|
611 | # 'hg', | |
@@ -579,7 +654,6 b' DIFF_FIXTURES = [' | |||||
579 | # 'pylons_app.egg-info/dependency_links.txt', 'A', { |
|
654 | # 'pylons_app.egg-info/dependency_links.txt', 'A', { | |
580 | # 'deleted': 0, 'binary': False, 'added': 1, 'ops': { |
|
655 | # 'deleted': 0, 'binary': False, 'added': 1, 'ops': { | |
581 | # 1: 'new file 100644'}}), |
|
656 | # 1: 'new file 100644'}}), | |
582 | # #TODO: |
|
|||
583 | # ] |
|
657 | # ] | |
584 | # ), |
|
658 | # ), | |
585 | ] |
|
659 | ] |
@@ -38,6 +38,7 b' from rhodecode.model.db import User, Rep' | |||||
38 | from rhodecode.model.meta import Session |
|
38 | from rhodecode.model.meta import Session | |
39 | from rhodecode.model.scm import ScmModel |
|
39 | from rhodecode.model.scm import ScmModel | |
40 | from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository |
|
40 | from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository | |
|
41 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |||
41 |
|
42 | |||
42 |
|
43 | |||
43 | log = logging.getLogger(__name__) |
|
44 | log = logging.getLogger(__name__) | |
@@ -372,3 +373,37 b' def repo_on_filesystem(repo_name):' | |||||
372 | repo = vcs.get_vcs_instance( |
|
373 | repo = vcs.get_vcs_instance( | |
373 | os.path.join(TESTS_TMP_PATH, repo_name), create=False) |
|
374 | os.path.join(TESTS_TMP_PATH, repo_name), create=False) | |
374 | return repo is not None |
|
375 | return repo is not None | |
|
376 | ||||
|
377 | ||||
|
378 | def commit_change( | |||
|
379 | repo, filename, content, message, vcs_type, parent=None, newfile=False): | |||
|
380 | from rhodecode.tests import TEST_USER_ADMIN_LOGIN | |||
|
381 | ||||
|
382 | repo = Repository.get_by_repo_name(repo) | |||
|
383 | _commit = parent | |||
|
384 | if not parent: | |||
|
385 | _commit = EmptyCommit(alias=vcs_type) | |||
|
386 | ||||
|
387 | if newfile: | |||
|
388 | nodes = { | |||
|
389 | filename: { | |||
|
390 | 'content': content | |||
|
391 | } | |||
|
392 | } | |||
|
393 | commit = ScmModel().create_nodes( | |||
|
394 | user=TEST_USER_ADMIN_LOGIN, repo=repo, | |||
|
395 | message=message, | |||
|
396 | nodes=nodes, | |||
|
397 | parent_commit=_commit, | |||
|
398 | author=TEST_USER_ADMIN_LOGIN, | |||
|
399 | ) | |||
|
400 | else: | |||
|
401 | commit = ScmModel().commit_change( | |||
|
402 | repo=repo.scm_instance(), repo_name=repo.repo_name, | |||
|
403 | commit=parent, user=TEST_USER_ADMIN_LOGIN, | |||
|
404 | author=TEST_USER_ADMIN_LOGIN, | |||
|
405 | message=message, | |||
|
406 | content=content, | |||
|
407 | f_path=filename | |||
|
408 | ) | |||
|
409 | return commit |
@@ -359,14 +359,15 b' class TestSvnGetDiff:' | |||||
359 | ], ids=['file', 'dir']) |
|
359 | ], ids=['file', 'dir']) | |
360 | def test_diff_to_tagged_version(self, vcsbackend_svn, path, path1): |
|
360 | def test_diff_to_tagged_version(self, vcsbackend_svn, path, path1): | |
361 | repo = vcsbackend_svn['svn-simple-layout'] |
|
361 | repo = vcsbackend_svn['svn-simple-layout'] | |
362 |
commit = repo[- |
|
362 | commit1 = repo[-2] | |
363 | diff = repo.get_diff(commit, commit, path=path, path1=path1) |
|
363 | commit2 = repo[-1] | |
|
364 | diff = repo.get_diff(commit1, commit2, path=path, path1=path1) | |||
364 | assert diff.raw == self.expected_diff_v_0_2 |
|
365 | assert diff.raw == self.expected_diff_v_0_2 | |
365 |
|
366 | |||
366 | expected_diff_v_0_2 = '''Index: example.py |
|
367 | expected_diff_v_0_2 = '''Index: example.py | |
367 | =================================================================== |
|
368 | =================================================================== | |
368 | diff --git a/example.py b/example.py |
|
369 | diff --git a/example.py b/example.py | |
369 |
--- a/example.py\t(revision 2 |
|
370 | --- a/example.py\t(revision 25) | |
370 | +++ b/example.py\t(revision 26) |
|
371 | +++ b/example.py\t(revision 26) | |
371 | @@ -7,8 +7,12 @@ |
|
372 | @@ -7,8 +7,12 @@ | |
372 |
|
373 |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
This diff has been collapsed as it changes many lines, (1669 lines changed) Show them Hide them |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now