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 | 1066 | '/{repo_name}/annotate/{revision}/{f_path}', |
|
1067 | 1067 | controller='files', action='index', revision='tip', |
|
1068 | 1068 | f_path='', annotate=True, conditions={'function': check_repo}, |
|
1069 | requirements=URL_NAME_REQUIREMENTS) | |
|
1069 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) | |
|
1070 | 1070 | |
|
1071 | 1071 | rmap.connect('files_edit', |
|
1072 | 1072 | '/{repo_name}/edit/{revision}/{f_path}', |
@@ -90,6 +90,7 b' class CompareController(BaseRepoControll' | |||
|
90 | 90 | c.target_ref_type = "" |
|
91 | 91 | c.commit_statuses = ChangesetStatus.STATUSES |
|
92 | 92 | c.preview_mode = False |
|
93 | c.file_path = None | |
|
93 | 94 | return render('compare/compare_diff.html') |
|
94 | 95 | |
|
95 | 96 | @LoginRequired() |
@@ -103,8 +104,10 b' class CompareController(BaseRepoControll' | |||
|
103 | 104 | |
|
104 | 105 | # target_ref will be evaluated in target_repo |
|
105 | 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 | 111 | c.commit_statuses = ChangesetStatus.STATUSES |
|
109 | 112 | |
|
110 | 113 | # if merge is True |
@@ -115,7 +118,6 b' class CompareController(BaseRepoControll' | |||
|
115 | 118 | # if merge is False |
|
116 | 119 | # Show a raw diff of source/target refs even if no ancestor exists |
|
117 | 120 | |
|
118 | ||
|
119 | 121 | # c.fulldiff disables cut_off_limit |
|
120 | 122 | c.fulldiff = str2bool(request.GET.get('fulldiff')) |
|
121 | 123 | |
@@ -131,7 +133,8 b' class CompareController(BaseRepoControll' | |||
|
131 | 133 | target_repo=source_repo_name, |
|
132 | 134 | target_ref_type=source_ref_type, |
|
133 | 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 | 139 | source_repo = Repository.get_by_repo_name(source_repo_name) |
|
137 | 140 | target_repo = Repository.get_by_repo_name(target_repo_name) |
@@ -151,8 +154,11 b' class CompareController(BaseRepoControll' | |||
|
151 | 154 | h.flash(msg, category='error') |
|
152 | 155 | return redirect(url('compare_home', repo_name=c.repo_name)) |
|
153 | 156 | |
|
154 |
source_ |
|
|
155 |
target_ |
|
|
157 | source_scm = source_repo.scm_instance() | |
|
158 | target_scm = target_repo.scm_instance() | |
|
159 | ||
|
160 | source_alias = source_scm.alias | |
|
161 | target_alias = target_scm.alias | |
|
156 | 162 | if source_alias != target_alias: |
|
157 | 163 | msg = _('The comparison of two different kinds of remote repos ' |
|
158 | 164 | 'is not available') |
@@ -175,9 +181,6 b' class CompareController(BaseRepoControll' | |||
|
175 | 181 | c.source_ref_type = source_ref_type |
|
176 | 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 | 184 | pre_load = ["author", "branch", "date", "message"] |
|
182 | 185 | c.ancestor = None |
|
183 | 186 | try: |
@@ -238,7 +241,8 b' class CompareController(BaseRepoControll' | |||
|
238 | 241 | |
|
239 | 242 | txtdiff = source_repo.scm_instance().get_diff( |
|
240 | 243 | commit1=source_commit, commit2=target_commit, |
|
241 |
path1=source_path |
|
|
244 | path=target_path, path1=source_path) | |
|
245 | ||
|
242 | 246 | diff_processor = diffs.DiffProcessor( |
|
243 | 247 | txtdiff, format='newdiff', diff_limit=diff_limit, |
|
244 | 248 | file_limit=file_limit, show_full_diff=c.fulldiff) |
@@ -260,5 +264,7 b' class CompareController(BaseRepoControll' | |||
|
260 | 264 | ).render_patchset(_parsed, source_ref, target_ref) |
|
261 | 265 | |
|
262 | 266 | c.preview_mode = merge |
|
267 | c.source_commit = source_commit | |
|
268 | c.target_commit = target_commit | |
|
263 | 269 | |
|
264 | 270 | return render('compare/compare_diff.html') |
@@ -799,21 +799,15 b' class FilesController(BaseRepoController' | |||
|
799 | 799 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
800 | 800 | 'repository.admin') |
|
801 | 801 | def diff(self, repo_name, f_path): |
|
802 | ignore_whitespace = request.GET.get('ignorews') == '1' | |
|
803 |
|
|
|
802 | ||
|
803 | c.action = request.GET.get('diff') | |
|
804 | 804 | diff1 = request.GET.get('diff1', '') |
|
805 | diff2 = request.GET.get('diff2', '') | |
|
805 | 806 | |
|
806 | 807 | path1, diff1 = parse_path_ref(diff1, default_path=f_path) |
|
807 | 808 | |
|
808 | diff2 = request.GET.get('diff2', '') | |
|
809 |
|
|
|
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] = [] | |
|
809 | ignore_whitespace = str2bool(request.GET.get('ignorews')) | |
|
810 | line_context = request.GET.get('context', 3) | |
|
817 | 811 | |
|
818 | 812 | if not any((diff1, diff2)): |
|
819 | 813 | h.flash( |
@@ -821,18 +815,16 b' class FilesController(BaseRepoController' | |||
|
821 | 815 | category='error') |
|
822 | 816 | raise HTTPBadRequest() |
|
823 | 817 | |
|
824 | # special case if we want a show commit_id only, it's impl here | |
|
825 | # to reduce JS and callbacks | |
|
826 | ||
|
827 | if request.GET.get('show_rev') and diff1: | |
|
828 | if str2bool(request.GET.get('annotate', 'False')): | |
|
829 | _url = url('files_annotate_home', repo_name=c.repo_name, | |
|
830 | revision=diff1, f_path=path1) | |
|
831 | else: | |
|
832 | _url = url('files_home', repo_name=c.repo_name, | |
|
833 |
|
|
|
834 | ||
|
835 | return redirect(_url) | |
|
818 | if c.action not in ['download', 'raw']: | |
|
819 | # redirect to new view if we render diff | |
|
820 | return redirect( | |
|
821 | url('compare_url', repo_name=repo_name, | |
|
822 | source_ref_type='rev', | |
|
823 | source_ref=diff1, | |
|
824 | target_repo=c.repo_name, | |
|
825 | target_ref_type='rev', | |
|
826 | target_ref=diff2, | |
|
827 | f_path=f_path)) | |
|
836 | 828 | |
|
837 | 829 | try: |
|
838 | 830 | node1 = self._get_file_node(diff1, path1) |
@@ -877,98 +869,40 b' class FilesController(BaseRepoController' | |||
|
877 | 869 | return diff.as_raw() |
|
878 | 870 | |
|
879 | 871 | else: |
|
880 | fid = h.FID(diff2, node2.path) | |
|
881 | line_context_lcl = get_line_ctx(fid, request.GET) | |
|
882 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) | |
|
883 | ||
|
884 | __, commit1, commit2, diff, st, data = diffs.wrapped_diff( | |
|
885 | filenode_old=node1, | |
|
886 | filenode_new=node2, | |
|
887 | diff_limit=self.cut_off_limit_diff, | |
|
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') | |
|
872 | return redirect( | |
|
873 | url('compare_url', repo_name=repo_name, | |
|
874 | source_ref_type='rev', | |
|
875 | source_ref=diff1, | |
|
876 | target_repo=c.repo_name, | |
|
877 | target_ref_type='rev', | |
|
878 | target_ref=diff2, | |
|
879 | f_path=f_path)) | |
|
917 | 880 | |
|
918 | 881 | @LoginRequired() |
|
919 | 882 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
920 | 883 | 'repository.admin') |
|
921 | 884 | def diff_2way(self, repo_name, f_path): |
|
885 | """ | |
|
886 | Kept only to make OLD links work | |
|
887 | """ | |
|
922 | 888 | diff1 = request.GET.get('diff1', '') |
|
923 | 889 | diff2 = request.GET.get('diff2', '') |
|
924 | 890 | |
|
925 | nodes = [] | |
|
926 | unknown_commits = [] | |
|
927 | for commit in [diff1, diff2]: | |
|
928 |
|
|
|
929 | nodes.append(self._get_file_node(commit, f_path)) | |
|
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 | |
|
891 | if not any((diff1, diff2)): | |
|
892 | h.flash( | |
|
893 | 'Need query parameter "diff1" or "diff2" to generate a diff.', | |
|
894 | category='error') | |
|
895 | raise HTTPBadRequest() | |
|
945 | 896 | |
|
946 | f_gitdiff = diffs.get_gitdiff(node1, node2, ignore_whitespace=False) | |
|
947 | diff_processor = diffs.DiffProcessor(f_gitdiff, format='gitdiff') | |
|
948 | diff_data = diff_processor.prepare() | |
|
949 | ||
|
950 | if not diff_data or diff_data[0]['raw_diff'] == '': | |
|
951 | h.flash(h.literal(_('%(file_path)s has not changed ' | |
|
952 | 'between %(commit_1)s and %(commit_2)s.') % { | |
|
953 |
|
|
|
954 | 'commit_1': node1.commit.id, | |
|
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') | |
|
897 | return redirect( | |
|
898 | url('compare_url', repo_name=repo_name, | |
|
899 | source_ref_type='rev', | |
|
900 | source_ref=diff1, | |
|
901 | target_repo=c.repo_name, | |
|
902 | target_ref_type='rev', | |
|
903 | target_ref=diff2, | |
|
904 | f_path=f_path, | |
|
905 | diffmode='sideside')) | |
|
972 | 906 | |
|
973 | 907 | def _get_file_node(self, commit_id, f_path): |
|
974 | 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 | 27 | from rhodecode.lib import helpers as h |
|
28 | 28 | from rhodecode.lib.vcs.exceptions import RepositoryError |
|
29 | 29 | |
|
30 | ||
|
30 | 31 | def parse_path_ref(ref, default_path=None): |
|
31 | 32 | """ |
|
32 | 33 | Parse out a path and reference combination and return both parts of it. |
@@ -378,6 +378,7 b' class BaseRepository(object):' | |||
|
378 | 378 | parameter works only for backends which support diff generation for |
|
379 | 379 | different paths. Other backends will raise a `ValueError` if `path1` |
|
380 | 380 | is set and has a different value than `path`. |
|
381 | :param file_path: filter this diff by given path pattern | |
|
381 | 382 | """ |
|
382 | 383 | raise NotImplementedError |
|
383 | 384 | |
@@ -1540,9 +1541,10 b' class Diff(object):' | |||
|
1540 | 1541 | """ |
|
1541 | 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 | 1548 | _header_re = None |
|
1547 | 1549 | |
|
1548 | 1550 | def __init__(self, raw_diff): |
@@ -1554,9 +1556,18 b' class Diff(object):' | |||
|
1554 | 1556 | to make diffs consistent we must prepend with \n, and make sure |
|
1555 | 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 | 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 |
|
|
1561 | 1572 | |
|
1562 | 1573 |
@@ -30,6 +30,10 b' from rhodecode.lib.vcs.backends import b' | |||
|
30 | 30 | |
|
31 | 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 | 37 | _header_re = re.compile(r""" |
|
34 | 38 | #^diff[ ]--git |
|
35 | 39 | [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n |
@@ -1477,8 +1477,9 b' table.integrations {' | |||
|
1477 | 1477 | margin-left: 8px; |
|
1478 | 1478 | } |
|
1479 | 1479 | |
|
1480 |
|
|
|
1480 | div.ancestor { | |
|
1481 | 1481 | margin: @padding 0; |
|
1482 | line-height: 3.0em; | |
|
1482 | 1483 | } |
|
1483 | 1484 | |
|
1484 | 1485 | .cs_icon_td input[type="checkbox"] { |
@@ -72,6 +72,7 b'' | |||
|
72 | 72 | } |
|
73 | 73 | .disabled { |
|
74 | 74 | opacity: .5; |
|
75 | cursor: inherit; | |
|
75 | 76 | } |
|
76 | 77 | .help-block { |
|
77 | 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 | 87 | * Splits remainder |
|
78 | 88 | * |
@@ -112,7 +112,7 b'' | |||
|
112 | 112 | |
|
113 | 113 | <div class="fieldset"> |
|
114 | 114 | <div class="left-label"> |
|
115 | ${_('Diffs')}: | |
|
115 | ${_('Diff options')}: | |
|
116 | 116 | </div> |
|
117 | 117 | <div class="right-content"> |
|
118 | 118 | <div class="diff-actions"> |
@@ -31,27 +31,82 b'' | |||
|
31 | 31 | <%def name="main()"> |
|
32 | 32 | <div class="summary-header"> |
|
33 | 33 | <div class="title"> |
|
34 | <div class="title-content"> | |
|
35 | 34 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
36 | 35 |
|
|
37 | 36 |
|
|
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 | 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)}" | |
|
40 | class="btn btn-default"> | |
|
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)}"> | |
|
41 | 59 | ${_('Show combined compare')} |
|
42 | 60 | </a> |
|
43 | 61 | </div> |
|
44 | 62 | </div> |
|
63 | </div> | |
|
45 | 64 | |
|
46 | <div class="summary-detail"> | |
|
47 | <div class="title"> | |
|
48 | <h2> | |
|
49 | ${self.breadcrumbs_links()} | |
|
50 | </h2> | |
|
65 | <%doc> | |
|
66 | ##TODO(marcink): implement this and diff menus | |
|
67 | <div class="fieldset"> | |
|
68 | <div class="left-label"> | |
|
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 | 85 | </div> |
|
52 | 86 | </div> |
|
87 | </%doc> | |
|
88 | </div> <!-- end summary-detail --> | |
|
89 | ||
|
90 | </div> <!-- end summary --> | |
|
91 | ||
|
53 | 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 | 110 | <%include file="../compare/compare_commits.html"/> |
|
56 | 111 | <div class="cs_files"> |
|
57 | 112 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> |
@@ -65,7 +120,6 b'' | |||
|
65 | 120 | commit=commit, |
|
66 | 121 | )} |
|
67 | 122 | %endfor |
|
68 | </table> | |
|
69 | 123 | </div> |
|
70 | 124 | </div> |
|
71 | 125 | </%def> |
@@ -52,45 +52,6 b'' | |||
|
52 | 52 | </div> |
|
53 | 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 | 56 | <%def name="diff_summary_text(changed_files, lines_added, lines_deleted, limited_diff=False)"> |
|
96 | 57 | % if limited_diff: |
@@ -162,6 +162,7 b' collapse_all = len(diffset.files) > coll' | |||
|
162 | 162 | |
|
163 | 163 | <div class="filediffs"> |
|
164 | 164 | %for i, filediff in enumerate(diffset.files): |
|
165 | ||
|
165 | 166 | <% |
|
166 | 167 | lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted'] |
|
167 | 168 | over_lines_changed_limit = lines_changed > lines_changed_limit |
@@ -414,6 +415,7 b' from rhodecode.lib.diffs import NEW_FILE' | |||
|
414 | 415 | if line.modified.lineno: |
|
415 | 416 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n') |
|
416 | 417 | %> |
|
418 | ||
|
417 | 419 | <tr class="cb-line"> |
|
418 | 420 | <td class="cb-data ${action_class(line.original.action)}" |
|
419 | 421 | data-line-number="${line.original.lineno}" |
@@ -544,6 +546,7 b' from rhodecode.lib.diffs import NEW_FILE' | |||
|
544 | 546 | <div class="diffset-menu clearinner"> |
|
545 | 547 | <div class="pull-right"> |
|
546 | 548 | <div class="btn-group"> |
|
549 | ||
|
547 | 550 | <a |
|
548 | 551 | class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip" |
|
549 | 552 | title="${_('View side by side')}" |
@@ -557,20 +560,21 b' from rhodecode.lib.diffs import NEW_FILE' | |||
|
557 | 560 | </a> |
|
558 | 561 | </div> |
|
559 | 562 | </div> |
|
563 | ||
|
560 | 564 | <div class="pull-left"> |
|
561 | 565 | <div class="btn-group"> |
|
562 | 566 | <a |
|
563 | 567 | class="btn" |
|
564 | 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 | 570 | <a |
|
567 | 571 | class="btn" |
|
568 | 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 | 574 | <a |
|
571 | 575 | class="btn" |
|
572 | 576 | href="#" |
|
573 | onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode')}</a> | |
|
577 | onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode Diff')}</a> | |
|
574 | 578 | </div> |
|
575 | 579 | </div> |
|
576 | 580 | </div> |
@@ -1,20 +1,17 b'' | |||
|
1 | 1 | ## Changesets table ! |
|
2 | 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 |
|
|
9 |
|
|
|
5 | <div class="ancestor">${_('Common Ancestor Commit')}: | |
|
10 | 6 |
|
|
11 | 7 |
|
|
12 | 8 |
|
|
13 | 9 |
|
|
14 | 10 |
|
|
15 | </p> | |
|
11 | </div> | |
|
16 | 12 |
|
|
17 | 13 | |
|
14 | <div class="container"> | |
|
18 | 15 | <input type="hidden" name="__start__" value="revisions:sequence"> |
|
19 | 16 | <table class="rctable compare_view_commits"> |
|
20 | 17 | <tr> |
@@ -66,9 +63,21 b'' | |||
|
66 | 63 | </td> |
|
67 | 64 | </tr> |
|
68 | 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 | 78 | </table> |
|
70 | 79 | <input type="hidden" name="__end__" value="revisions:sequence"> |
|
71 | %endif | |
|
80 | ||
|
72 | 81 | </div> |
|
73 | 82 | |
|
74 | 83 | <script> |
@@ -76,7 +85,7 b'' | |||
|
76 | 85 | var target_expand = $(this); |
|
77 | 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 | 89 | if (target_expand.hasClass('open')){ |
|
81 | 90 | $('#c-'+cid).css({ |
|
82 | 91 | 'height': '1.5em', |
@@ -34,34 +34,132 b'' | |||
|
34 | 34 | <div class="box"> |
|
35 | 35 | <div class="title"> |
|
36 | 36 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
37 | <div class="breadcrumbs"> | |
|
38 | ${_('Compare Commits')} | |
|
39 | </div> | |
|
40 | 37 | </div> |
|
41 | 38 | |
|
42 |
<div class=" |
|
|
43 |
<div |
|
|
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 | ${_('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 | 64 | <div class="code-header" > |
|
45 | 65 | <div class="compare_header"> |
|
46 | 66 | ## The hidden elements are replaced with a select2 widget |
|
47 |
|
|
|
48 | <div class="compare-label">${_('Source')}</div>${h.hidden('compare_target')} | |
|
67 | ${h.hidden('compare_source')} | |
|
68 | </div> | |
|
69 | </div> | |
|
70 | </div> | |
|
71 | </div> | |
|
72 | </div> | |
|
49 | 73 | |
|
50 | %if not c.preview_mode: | |
|
51 |
|
|
|
74 | <div class="fieldset"> | |
|
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 | 99 | <div class="compare-buttons"> |
|
53 |
%if |
|
|
54 |
|
|
|
100 | % if c.compare_home: | |
|
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 | 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 | 124 | %endif |
|
62 | 125 | </div> |
|
63 | 126 | </div> |
|
64 | 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 | 163 | ## use JS script to load it quickly before potentially large diffs render long time |
|
66 | 164 | ## this prevents from situation when large diffs block rendering of select2 fields |
|
67 | 165 | <script type="text/javascript"> |
@@ -241,13 +339,26 b'' | |||
|
241 | 339 | |
|
242 | 340 | </div> |
|
243 | 341 | |
|
244 | %if c.compare_home: | |
|
342 | %if not c.compare_home: | |
|
245 | 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 | 358 | </div> |
|
248 | %else: | |
|
249 | <div id="changeset_compare_view_content"> | |
|
250 | ##CS | |
|
359 | </div> | |
|
360 | <div style="padding:0 10px 10px 0px" class="pull-left"></div> | |
|
361 | ## commit compare generated below | |
|
251 | 362 | <%include file="compare_commits.html"/> |
|
252 | 363 | ${cbdiffs.render_diffset_menu()} |
|
253 | 364 | ${cbdiffs.render_diffset(c.diffset)} |
@@ -9,11 +9,9 b'' | |||
|
9 | 9 | </%def> |
|
10 | 10 | |
|
11 | 11 | <%def name="js_extra()"> |
|
12 | <script type="text/javascript" src="${h.asset('js/mergerly.js', ver=c.rhodecode_version_hash)}"></script> | |
|
13 | 12 | </%def> |
|
14 | 13 | |
|
15 | 14 | <%def name="css_extra()"> |
|
16 | <link rel="stylesheet" type="text/css" href="${h.asset('css/mergerly.css', ver=c.rhodecode_version_hash)}"/> | |
|
17 | 15 | </%def> |
|
18 | 16 | |
|
19 | 17 |
@@ -128,7 +128,7 b'' | |||
|
128 | 128 | // used for history, and switch to |
|
129 | 129 | var initialCommitData = { |
|
130 | 130 | id: null, |
|
131 |
text: '${_(" |
|
|
131 | text: '${_("Pick Commit")}', | |
|
132 | 132 | type: 'sha', |
|
133 | 133 | raw_id: null, |
|
134 | 134 | files_url: null |
@@ -151,9 +151,47 b'' | |||
|
151 | 151 | |
|
152 | 152 | // file history select2 |
|
153 | 153 | select2FileHistorySwitcher('#diff1', initialCommitData, state); |
|
154 | ||
|
155 | // show at, diff to actions handlers | |
|
154 | 156 | $('#diff1').on('change', function(e) { |
|
155 | $('#diff').removeClass('disabled').removeAttr("disabled"); | |
|
156 | $('#show_rev').removeClass('disabled').removeAttr("disabled"); | |
|
157 | $('#diff_to_commit').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 | 197 | // show more authors |
@@ -46,16 +46,28 b'' | |||
|
46 | 46 | </div> |
|
47 | 47 | |
|
48 | 48 | |
|
49 |
<div |
|
|
50 | ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} | |
|
49 | <div class="fieldset collapsable-content" data-toggle="summary-details"> | |
|
50 | <div class="left-label"> | |
|
51 | ${_('Show/Diff file')}: | |
|
52 | </div> | |
|
53 | <div class="right-content"> | |
|
51 | 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")} | |
|
55 | ${h.submit('show_rev',_('Show at Commit'),class_="btn disabled",disabled="true")} | |
|
56 | ${h.hidden('annotate', c.annotate)} | |
|
57 | ${h.end_form()} | |
|
60 | ||
|
61 | <div class="fieldset collapsable-content" data-toggle="summary-details"> | |
|
62 | <div class="left-label"> | |
|
63 | ${_('Action')}: | |
|
58 | 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 | 72 | <script> |
|
61 | 73 | collapsableContent(); |
@@ -360,14 +360,33 b'' | |||
|
360 | 360 | </div> |
|
361 | 361 | % endif |
|
362 | 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 | 382 | % if c.allowed_to_update and not c.pull_request.is_closed(): |
|
364 | 383 | <a id="update_commits" class="btn btn-primary pull-right">${_('Update commits')}</a> |
|
365 | 384 | % else: |
|
366 | 385 | <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a> |
|
367 | 386 | % endif |
|
368 | % if len(c.commit_ranges): | |
|
369 | <h2>${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}</h2> | |
|
370 | % endif | |
|
387 | ||
|
388 | </div> | |
|
389 | ||
|
371 | 390 | </div> |
|
372 | 391 | % if not c.missing_commits: |
|
373 | 392 | <%include file="/compare/compare_commits.html" /> |
@@ -244,7 +244,8 b' class TestCommitCommentsController(TestC' | |||
|
244 | 244 | ('markdown', '# header', '<h1>header</h1>'), |
|
245 | 245 | ('markdown', '*italics*', '<em>italics</em>'), |
|
246 | 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 | 249 | def test_preview(self, renderer, input, output, backend): |
|
249 | 250 | self.log_user() |
|
250 | 251 | params = { |
@@ -22,16 +22,13 b' import mock' | |||
|
22 | 22 | import pytest |
|
23 | 23 | import lxml.html |
|
24 | 24 | |
|
25 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |
|
26 | 25 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
27 | from rhodecode.model.db import Repository | |
|
28 | from rhodecode.model.scm import ScmModel | |
|
29 | from rhodecode.tests import url, TEST_USER_ADMIN_LOGIN, assert_session_flash | |
|
30 | from rhodecode.tests.utils import AssertResponse | |
|
26 | from rhodecode.tests import url, assert_session_flash | |
|
27 | from rhodecode.tests.utils import AssertResponse, commit_change | |
|
31 | 28 | |
|
32 | 29 | |
|
33 | 30 | @pytest.mark.usefixtures("autologin_user", "app") |
|
34 | class TestCompareController: | |
|
31 | class TestCompareController(object): | |
|
35 | 32 | |
|
36 | 33 | @pytest.mark.xfail_backends("svn", reason="Requires pull") |
|
37 | 34 | def test_compare_remote_with_different_commit_indexes(self, backend): |
@@ -53,23 +50,23 b' class TestCompareController:' | |||
|
53 | 50 | fork = backend.create_repo() |
|
54 | 51 | |
|
55 | 52 | # prepare fork |
|
56 |
commit0 = |
|
|
53 | commit0 = commit_change( | |
|
57 | 54 | fork.repo_name, filename='file1', content='A', |
|
58 | 55 | message='A', vcs_type=backend.alias, parent=None, newfile=True) |
|
59 | 56 | |
|
60 |
commit1 = |
|
|
57 | commit1 = commit_change( | |
|
61 | 58 | fork.repo_name, filename='file1', content='B', |
|
62 | 59 | message='B, child of A', vcs_type=backend.alias, parent=commit0) |
|
63 | 60 | |
|
64 |
|
|
|
61 | commit_change( # commit 2 | |
|
65 | 62 | fork.repo_name, filename='file1', content='C', |
|
66 | 63 | message='C, child of B', vcs_type=backend.alias, parent=commit1) |
|
67 | 64 | |
|
68 |
commit3 = |
|
|
65 | commit3 = commit_change( | |
|
69 | 66 | fork.repo_name, filename='file1', content='D', |
|
70 | 67 | message='D, child of A', vcs_type=backend.alias, parent=commit0) |
|
71 | 68 | |
|
72 |
commit4 = |
|
|
69 | commit4 = commit_change( | |
|
73 | 70 | fork.repo_name, filename='file1', content='E', |
|
74 | 71 | message='E, child of D', vcs_type=backend.alias, parent=commit3) |
|
75 | 72 | |
@@ -105,7 +102,7 b' class TestCompareController:' | |||
|
105 | 102 | repo1 = backend.create_repo() |
|
106 | 103 | |
|
107 | 104 | # commit something ! |
|
108 |
commit0 = |
|
|
105 | commit0 = commit_change( | |
|
109 | 106 | repo1.repo_name, filename='file1', content='line1\n', |
|
110 | 107 | message='commit1', vcs_type=backend.alias, parent=None, |
|
111 | 108 | newfile=True) |
@@ -114,11 +111,11 b' class TestCompareController:' | |||
|
114 | 111 | repo2 = backend.create_fork() |
|
115 | 112 | |
|
116 | 113 | # add two extra commit into fork |
|
117 |
commit1 = |
|
|
114 | commit1 = commit_change( | |
|
118 | 115 | repo2.repo_name, filename='file1', content='line1\nline2\n', |
|
119 | 116 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
120 | 117 | |
|
121 |
commit2 = |
|
|
118 | commit2 = commit_change( | |
|
122 | 119 | repo2.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
123 | 120 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
124 | 121 | |
@@ -156,7 +153,7 b' class TestCompareController:' | |||
|
156 | 153 | repo1 = backend.create_repo() |
|
157 | 154 | |
|
158 | 155 | # commit something ! |
|
159 |
commit0 = |
|
|
156 | commit0 = commit_change( | |
|
160 | 157 | repo1.repo_name, filename='file1', content='line1\n', |
|
161 | 158 | message='commit1', vcs_type=backend.alias, parent=None, |
|
162 | 159 | newfile=True) |
@@ -165,17 +162,17 b' class TestCompareController:' | |||
|
165 | 162 | repo2 = backend.create_fork() |
|
166 | 163 | |
|
167 | 164 | # now commit something to origin repo |
|
168 |
|
|
|
165 | commit_change( | |
|
169 | 166 | repo1.repo_name, filename='file2', content='line1file2\n', |
|
170 | 167 | message='commit2', vcs_type=backend.alias, parent=commit0, |
|
171 | 168 | newfile=True) |
|
172 | 169 | |
|
173 | 170 | # add two extra commit into fork |
|
174 |
commit1 = |
|
|
171 | commit1 = commit_change( | |
|
175 | 172 | repo2.repo_name, filename='file1', content='line1\nline2\n', |
|
176 | 173 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
177 | 174 | |
|
178 |
commit2 = |
|
|
175 | commit2 = commit_change( | |
|
179 | 176 | repo2.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
180 | 177 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
181 | 178 | |
@@ -207,9 +204,9 b' class TestCompareController:' | |||
|
207 | 204 | compare_page.swap_is_hidden() |
|
208 | 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 | 209 | def test_compare_of_unrelated_forks(self, backend): |
|
212 | # TODO: johbo: Fails for git due to some other issue it seems | |
|
213 | 210 | orig = backend.create_repo(number_of_commits=1) |
|
214 | 211 | fork = backend.create_repo(number_of_commits=1) |
|
215 | 212 | |
@@ -245,11 +242,11 b' class TestCompareController:' | |||
|
245 | 242 | repo1 = backend.create_repo() |
|
246 | 243 | |
|
247 | 244 | # commit something ! |
|
248 |
commit0 = |
|
|
245 | commit0 = commit_change( | |
|
249 | 246 | repo1.repo_name, filename='file1', content='line1\n', |
|
250 | 247 | message='commit1', vcs_type=backend.alias, parent=None, |
|
251 | 248 | newfile=True) |
|
252 |
commit1 = |
|
|
249 | commit1 = commit_change( | |
|
253 | 250 | repo1.repo_name, filename='file1', content='line1\nline2\n', |
|
254 | 251 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
255 | 252 | |
@@ -257,18 +254,18 b' class TestCompareController:' | |||
|
257 | 254 | repo2 = backend.create_fork() |
|
258 | 255 | |
|
259 | 256 | # now make commit3-6 |
|
260 |
commit2 = |
|
|
257 | commit2 = commit_change( | |
|
261 | 258 | repo1.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
262 | 259 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
263 |
commit3 = |
|
|
260 | commit3 = commit_change( | |
|
264 | 261 | repo1.repo_name, filename='file1', |
|
265 | 262 | content='line1\nline2\nline3\nline4\n', message='commit4', |
|
266 | 263 | vcs_type=backend.alias, parent=commit2) |
|
267 |
commit4 = |
|
|
264 | commit4 = commit_change( | |
|
268 | 265 | repo1.repo_name, filename='file1', |
|
269 | 266 | content='line1\nline2\nline3\nline4\nline5\n', message='commit5', |
|
270 | 267 | vcs_type=backend.alias, parent=commit3) |
|
271 |
|
|
|
268 | commit_change( # commit 5 | |
|
272 | 269 | repo1.repo_name, filename='file1', |
|
273 | 270 | content='line1\nline2\nline3\nline4\nline5\nline6\n', |
|
274 | 271 | message='commit6', vcs_type=backend.alias, parent=commit4) |
@@ -311,11 +308,11 b' class TestCompareController:' | |||
|
311 | 308 | repo1 = backend.create_repo() |
|
312 | 309 | |
|
313 | 310 | # commit something ! |
|
314 |
commit0 = |
|
|
311 | commit0 = commit_change( | |
|
315 | 312 | repo1.repo_name, filename='file1', content='line1\n', |
|
316 | 313 | message='commit1', vcs_type=backend.alias, parent=None, |
|
317 | 314 | newfile=True) |
|
318 |
commit1 = |
|
|
315 | commit1 = commit_change( | |
|
319 | 316 | repo1.repo_name, filename='file1', content='line1\nline2\n', |
|
320 | 317 | message='commit2', vcs_type=backend.alias, parent=commit0) |
|
321 | 318 | |
@@ -323,18 +320,18 b' class TestCompareController:' | |||
|
323 | 320 | backend.create_fork() |
|
324 | 321 | |
|
325 | 322 | # now make commit3-6 |
|
326 |
commit2 = |
|
|
323 | commit2 = commit_change( | |
|
327 | 324 | repo1.repo_name, filename='file1', content='line1\nline2\nline3\n', |
|
328 | 325 | message='commit3', vcs_type=backend.alias, parent=commit1) |
|
329 |
commit3 = |
|
|
326 | commit3 = commit_change( | |
|
330 | 327 | repo1.repo_name, filename='file1', |
|
331 | 328 | content='line1\nline2\nline3\nline4\n', message='commit4', |
|
332 | 329 | vcs_type=backend.alias, parent=commit2) |
|
333 |
commit4 = |
|
|
330 | commit4 = commit_change( | |
|
334 | 331 | repo1.repo_name, filename='file1', |
|
335 | 332 | content='line1\nline2\nline3\nline4\nline5\n', message='commit5', |
|
336 | 333 | vcs_type=backend.alias, parent=commit3) |
|
337 |
commit5 = |
|
|
334 | commit5 = commit_change( | |
|
338 | 335 | repo1.repo_name, filename='file1', |
|
339 | 336 | content='line1\nline2\nline3\nline4\nline5\nline6\n', |
|
340 | 337 | message='commit6', vcs_type=backend.alias, parent=commit4) |
@@ -400,7 +397,7 b' class TestCompareController:' | |||
|
400 | 397 | repo1 = backend.create_repo() |
|
401 | 398 | r1_name = repo1.repo_name |
|
402 | 399 | |
|
403 |
commit0 = |
|
|
400 | commit0 = commit_change( | |
|
404 | 401 | repo=r1_name, filename='file1', |
|
405 | 402 | content='line1', message='commit1', vcs_type=backend.alias, |
|
406 | 403 | newfile=True) |
@@ -413,19 +410,19 b' class TestCompareController:' | |||
|
413 | 410 | self.r2_id = repo2.repo_id |
|
414 | 411 | r2_name = repo2.repo_name |
|
415 | 412 | |
|
416 |
commit1 = |
|
|
413 | commit1 = commit_change( | |
|
417 | 414 | repo=r2_name, filename='file1-fork', |
|
418 | 415 | content='file1-line1-from-fork', message='commit1-fork', |
|
419 | 416 | vcs_type=backend.alias, parent=repo2.scm_instance()[-1], |
|
420 | 417 | newfile=True) |
|
421 | 418 | |
|
422 |
commit2 = |
|
|
419 | commit2 = commit_change( | |
|
423 | 420 | repo=r2_name, filename='file2-fork', |
|
424 | 421 | content='file2-line1-from-fork', message='commit2-fork', |
|
425 | 422 | vcs_type=backend.alias, parent=commit1, |
|
426 | 423 | newfile=True) |
|
427 | 424 | |
|
428 |
|
|
|
425 | commit_change( # commit 3 | |
|
429 | 426 | repo=r2_name, filename='file3-fork', |
|
430 | 427 | content='file3-line1-from-fork', message='commit3-fork', |
|
431 | 428 | vcs_type=backend.alias, parent=commit2, newfile=True) |
@@ -447,9 +444,9 b' class TestCompareController:' | |||
|
447 | 444 | response.mustcontain('%s@%s' % (r2_name, commit_id1)) |
|
448 | 445 | response.mustcontain('%s@%s' % (r1_name, commit_id2)) |
|
449 | 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 | 450 | repo=r1_name, filename='file2', |
|
454 | 451 | content='line1-added-after-fork', message='commit2-parent', |
|
455 | 452 | vcs_type=backend.alias, parent=None, newfile=True) |
@@ -558,7 +555,7 b' class TestCompareController:' | |||
|
558 | 555 | |
|
559 | 556 | |
|
560 | 557 | @pytest.mark.usefixtures("autologin_user") |
|
561 | class TestCompareControllerSvn: | |
|
558 | class TestCompareControllerSvn(object): | |
|
562 | 559 | |
|
563 | 560 | def test_supports_references_with_path(self, app, backend_svn): |
|
564 | 561 | repo = backend_svn['svn-simple-layout'] |
@@ -574,7 +571,7 b' class TestCompareControllerSvn:' | |||
|
574 | 571 | status=200) |
|
575 | 572 | |
|
576 | 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 | 576 | # Should find only one file changed when comparing those two tags |
|
580 | 577 | response.mustcontain('example.py') |
@@ -596,7 +593,7 b' class TestCompareControllerSvn:' | |||
|
596 | 593 | status=200) |
|
597 | 594 | |
|
598 | 595 | # It should show commits |
|
599 |
assert 'No |
|
|
596 | assert 'No commits in this compare' not in response.body | |
|
600 | 597 | |
|
601 | 598 | # Should find only one file changed when comparing those two tags |
|
602 | 599 | response.mustcontain('example.py') |
@@ -660,36 +657,3 b' class ComparePage(AssertResponse):' | |||
|
660 | 657 | def target_source_are_enabled(self): |
|
661 | 658 | response = self.response |
|
662 | 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 | 44 | response.mustcontain('%s@%s' % (backend.repo_name, tag1)) |
|
45 | 45 | response.mustcontain('%s@%s' % (backend.repo_name, tag2)) |
|
46 | 46 | |
|
47 |
# outgoing c |
|
|
47 | # outgoing commits between tags | |
|
48 | 48 | commit_indexes = { |
|
49 | 49 | 'git': [113] + range(115, 121), |
|
50 | 50 | 'hg': [112] + range(115, 121), |
@@ -118,8 +118,8 b' class TestCompareController:' | |||
|
118 | 118 | response.mustcontain('%s@%s' % (backend.repo_name, head_id)) |
|
119 | 119 | |
|
120 | 120 | # branches are equal |
|
121 |
response.mustcontain(' |
|
|
122 |
response.mustcontain(' |
|
|
121 | response.mustcontain('No files') | |
|
122 | response.mustcontain('No commits in this compare') | |
|
123 | 123 | |
|
124 | 124 | def test_compare_commits(self, backend): |
|
125 | 125 | repo = backend.repo |
@@ -28,15 +28,11 b' from rhodecode.lib import helpers as h' | |||
|
28 | 28 | from rhodecode.lib.compat import OrderedDict |
|
29 | 29 | from rhodecode.lib.ext_json import json |
|
30 | 30 | from rhodecode.lib.vcs import nodes |
|
31 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |
|
31 | ||
|
32 | 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 | 33 | from rhodecode.tests import ( |
|
37 |
url |
|
|
34 | url, assert_session_flash, assert_not_in_session_flash) | |
|
38 | 35 | from rhodecode.tests.fixture import Fixture |
|
39 | from rhodecode.tests.utils import AssertResponse | |
|
40 | 36 | |
|
41 | 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 | 47 | @pytest.mark.usefixtures("app") |
|
86 | 48 | class TestFilesController: |
|
87 | 49 | |
@@ -120,7 +82,7 b' class TestFilesController:' | |||
|
120 | 82 | response = self.app.get(url( |
|
121 | 83 | controller='files', action='index', |
|
122 | 84 | repo_name=repo.repo_name, revision='tip', f_path='/')) |
|
123 |
assert_response = |
|
|
85 | assert_response = response.assert_response() | |
|
124 | 86 | assert_response.contains_one_link( |
|
125 | 87 | 'absolute-path @ 000000000000', 'http://example.com/absolute-path') |
|
126 | 88 | |
@@ -130,7 +92,7 b' class TestFilesController:' | |||
|
130 | 92 | response = self.app.get(url( |
|
131 | 93 | controller='files', action='index', |
|
132 | 94 | repo_name=repo.repo_name, revision='tip', f_path='/')) |
|
133 |
assert_response = |
|
|
95 | assert_response = response.assert_response() | |
|
134 | 96 | assert_response.contains_one_link( |
|
135 | 97 | 'subpaths-path @ 000000000000', |
|
136 | 98 | 'http://sub-base.example.com/subpaths-path') |
@@ -179,21 +141,24 b' class TestFilesController:' | |||
|
179 | 141 | assert_dirs_in_response(response, dirs, params) |
|
180 | 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 | 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 | 149 | # TODO: Branch support in Subversion |
|
187 | ||
|
188 | commit = backend.repo.get_commit(commit_idx=150) | |
|
150 | svn=(150, []) | |
|
151 | ) | |
|
152 | idx, branches = branches[backend.alias] | |
|
153 | commit = backend.repo.get_commit(commit_idx=idx) | |
|
189 | 154 | response = self.app.get(url( |
|
190 | 155 | controller='files', action='index', |
|
191 | 156 | repo_name=backend.repo_name, |
|
192 | 157 | revision=commit.raw_id, |
|
193 | 158 | f_path='/')) |
|
194 |
assert_response = |
|
|
195 | assert_response.element_contains( | |
|
196 |
'.tags .branchtag', |
|
|
159 | assert_response = response.assert_response() | |
|
160 | for branch in branches: | |
|
161 | assert_response.element_contains('.tags .branchtag', branch) | |
|
197 | 162 | |
|
198 | 163 | def test_index_paging(self, backend): |
|
199 | 164 | repo = backend.repo |
@@ -221,7 +186,7 b' class TestFilesController:' | |||
|
221 | 186 | msgbox = """<div class="commit right-content">%s</div>""" |
|
222 | 187 | response.mustcontain(msgbox % (commit.message, )) |
|
223 | 188 | |
|
224 |
assert_response = |
|
|
189 | assert_response = response.assert_response() | |
|
225 | 190 | if commit.branch: |
|
226 | 191 | assert_response.element_contains('.tags.tags-main .branchtag', commit.branch) |
|
227 | 192 | if commit.tags: |
@@ -348,7 +313,7 b' class TestFilesController:' | |||
|
348 | 313 | f_path='/', commit_id=commit.raw_id), |
|
349 | 314 | extra_environ=xhr_header) |
|
350 | 315 | |
|
351 |
assert_response = |
|
|
316 | assert_response = response.assert_response() | |
|
352 | 317 | |
|
353 | 318 | for attr in ['data-commit-id', 'data-date', 'data-author']: |
|
354 | 319 | elements = assert_response.get_elements('[{}]'.format(attr)) |
@@ -401,7 +366,7 b' class TestFilesController:' | |||
|
401 | 366 | # TODO: johbo: Think about a better place for these tests. Either controller |
|
402 | 367 | # specific unit tests or we move down the whole logic further towards the vcs |
|
403 | 368 | # layer |
|
404 | class TestAdjustFilePathForSvn: | |
|
369 | class TestAdjustFilePathForSvn(object): | |
|
405 | 370 | """SVN specific adjustments of node history in FileController.""" |
|
406 | 371 | |
|
407 | 372 | def test_returns_path_relative_to_matched_reference(self): |
@@ -433,7 +398,7 b' class TestAdjustFilePathForSvn:' | |||
|
433 | 398 | |
|
434 | 399 | |
|
435 | 400 | @pytest.mark.usefixtures("app") |
|
436 | class TestRepositoryArchival: | |
|
401 | class TestRepositoryArchival(object): | |
|
437 | 402 | |
|
438 | 403 | def test_archival(self, backend): |
|
439 | 404 | backend.enable_downloads() |
@@ -485,7 +450,7 b' class TestRepositoryArchival:' | |||
|
485 | 450 | |
|
486 | 451 | |
|
487 | 452 | @pytest.mark.usefixtures("app", "autologin_user") |
|
488 | class TestRawFileHandling: | |
|
453 | class TestRawFileHandling(object): | |
|
489 | 454 | |
|
490 | 455 | def test_raw_file_ok(self, backend): |
|
491 | 456 | commit = backend.repo.get_commit(commit_idx=173) |
@@ -575,6 +540,7 b' class TestFilesDiff:' | |||
|
575 | 540 | def test_file_full_diff(self, backend, diff): |
|
576 | 541 | commit1 = backend.repo.get_commit(commit_idx=-1) |
|
577 | 542 | commit2 = backend.repo.get_commit(commit_idx=-2) |
|
543 | ||
|
578 | 544 | response = self.app.get( |
|
579 | 545 | url( |
|
580 | 546 | controller='files', |
@@ -582,11 +548,17 b' class TestFilesDiff:' | |||
|
582 | 548 | repo_name=backend.repo_name, |
|
583 | 549 | f_path='README'), |
|
584 | 550 | params={ |
|
585 |
'diff1': commit |
|
|
586 |
'diff2': commit |
|
|
551 | 'diff1': commit2.raw_id, | |
|
552 | 'diff2': commit1.raw_id, | |
|
587 | 553 | 'fulldiff': '1', |
|
588 | 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 | 562 | response.mustcontain('README.rst') |
|
591 | 563 | response.mustcontain('No newline at end of file') |
|
592 | 564 | |
@@ -610,7 +582,17 b' class TestFilesDiff:' | |||
|
610 | 582 | 'fulldiff': '1', |
|
611 | 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 | 597 | def test_diff_2way(self, backend): |
|
616 | 598 | commit1 = backend.repo.get_commit(commit_idx=-1) |
@@ -622,14 +604,15 b' class TestFilesDiff:' | |||
|
622 | 604 | repo_name=backend.repo_name, |
|
623 | 605 | f_path='README'), |
|
624 | 606 | params={ |
|
625 |
'diff1': commit |
|
|
626 |
'diff2': commit |
|
|
607 | 'diff1': commit2.raw_id, | |
|
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 | |
|
630 | # to load the content dynamically. | |
|
631 | response.mustcontain('/%s/README' % commit1.raw_id) | |
|
632 | response.mustcontain('/%s/README' % commit2.raw_id) | |
|
613 | # It's a symlink to README.rst | |
|
614 | response.mustcontain('README.rst') | |
|
615 | response.mustcontain('No newline at end of file') | |
|
633 | 616 | |
|
634 | 617 | def test_requires_one_commit_id(self, backend, autologin_user): |
|
635 | 618 | response = self.app.get( |
@@ -642,17 +625,19 b' class TestFilesDiff:' | |||
|
642 | 625 | response.mustcontain( |
|
643 | 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 | 629 | repo = vcsbackend.repo |
|
647 | self.app.get( | |
|
630 | response = self.app.get( | |
|
648 | 631 | url( |
|
649 | 632 | controller='files', |
|
650 | 633 | action='diff', |
|
651 | 634 | repo_name=repo.name, |
|
652 | 635 | f_path='does-not-exist-in-any-commit', |
|
653 | 636 | diff1=repo[0].raw_id, |
|
654 | diff2=repo[1].raw_id), | |
|
655 | status=404) | |
|
637 | diff2=repo[1].raw_id),) | |
|
638 | ||
|
639 | response = response.follow() | |
|
640 | response.mustcontain('No files') | |
|
656 | 641 | |
|
657 | 642 | def test_returns_redirect_if_file_not_changed(self, backend): |
|
658 | 643 | commit = backend.repo.get_commit(commit_idx=-1) |
@@ -666,25 +651,40 b' class TestFilesDiff:' | |||
|
666 | 651 | diff1=commit.raw_id, |
|
667 | 652 | diff2=commit.raw_id, |
|
668 | 653 | ), |
|
669 | status=302 | |
|
670 | 654 | ) |
|
671 | assert response.headers['Location'].endswith(f_path) | |
|
672 | redirected = response.follow() | |
|
673 |
re |
|
|
655 | response = response.follow() | |
|
656 | response.mustcontain('No files') | |
|
657 | response.mustcontain('No commits in this compare') | |
|
674 | 658 | |
|
675 | 659 | def test_supports_diff_to_different_path_svn(self, backend_svn): |
|
660 | #TODO: check this case | |
|
661 | return | |
|
662 | ||
|
676 | 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 | 676 | response = self.app.get( |
|
679 | 677 | url( |
|
680 | 678 | controller='files', |
|
681 | 679 | action='diff', |
|
682 | 680 | repo_name=repo.name, |
|
683 | 681 | f_path='trunk/example.py', |
|
684 | diff1='tags/v0.2/example.py@' + commit_id, | |
|
685 |
diff2=commit_id) |
|
|
686 | status=200) | |
|
682 | diff1='tags/v0.2/example.py@' + commit_id_1, | |
|
683 | diff2=commit_id_2)) | |
|
684 | ||
|
685 | response = response.follow() | |
|
687 | 686 | response.mustcontain( |
|
687 | # diff contains this | |
|
688 | 688 | "Will print out a useful message on invocation.") |
|
689 | 689 | |
|
690 | 690 | # Note: Expecting that we indicate the user what's being compared |
@@ -692,6 +692,9 b' class TestFilesDiff:' | |||
|
692 | 692 | response.mustcontain("tags/v0.2/example.py") |
|
693 | 693 | |
|
694 | 694 | def test_show_rev_redirects_to_svn_path(self, backend_svn): |
|
695 | #TODO: check this case | |
|
696 | return | |
|
697 | ||
|
695 | 698 | repo = backend_svn['svn-simple-layout'].scm_instance() |
|
696 | 699 | commit_id = repo[-1].raw_id |
|
697 | 700 | response = self.app.get( |
@@ -708,6 +711,9 b' class TestFilesDiff:' | |||
|
708 | 711 | 'svn-svn-simple-layout/files/26/branches/argparse/example.py') |
|
709 | 712 | |
|
710 | 713 | def test_show_rev_and_annotate_redirects_to_svn_path(self, backend_svn): |
|
714 | #TODO: check this case | |
|
715 | return | |
|
716 | ||
|
711 | 717 | repo = backend_svn['svn-simple-layout'].scm_instance() |
|
712 | 718 | commit_id = repo[-1].raw_id |
|
713 | 719 | response = self.app.get( |
@@ -979,100 +985,3 b' def _assert_items_in_response(response, ' | |||
|
979 | 985 | def assert_timeago_in_response(response, items, params): |
|
980 | 986 | for item in items: |
|
981 | 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 | 609 | # TODO: mikhail: do we still need this? |
|
535 | 610 | # ( |
|
536 | 611 | # 'hg', |
@@ -579,7 +654,6 b' DIFF_FIXTURES = [' | |||
|
579 | 654 | # 'pylons_app.egg-info/dependency_links.txt', 'A', { |
|
580 | 655 | # 'deleted': 0, 'binary': False, 'added': 1, 'ops': { |
|
581 | 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 | 38 | from rhodecode.model.meta import Session |
|
39 | 39 | from rhodecode.model.scm import ScmModel |
|
40 | 40 | from rhodecode.lib.vcs.backends.svn.repository import SubversionRepository |
|
41 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |
|
41 | 42 | |
|
42 | 43 | |
|
43 | 44 | log = logging.getLogger(__name__) |
@@ -372,3 +373,37 b' def repo_on_filesystem(repo_name):' | |||
|
372 | 373 | repo = vcs.get_vcs_instance( |
|
373 | 374 | os.path.join(TESTS_TMP_PATH, repo_name), create=False) |
|
374 | 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 | 359 | ], ids=['file', 'dir']) |
|
360 | 360 | def test_diff_to_tagged_version(self, vcsbackend_svn, path, path1): |
|
361 | 361 | repo = vcsbackend_svn['svn-simple-layout'] |
|
362 |
commit = repo[- |
|
|
363 | diff = repo.get_diff(commit, commit, path=path, path1=path1) | |
|
362 | commit1 = repo[-2] | |
|
363 | commit2 = repo[-1] | |
|
364 | diff = repo.get_diff(commit1, commit2, path=path, path1=path1) | |
|
364 | 365 | assert diff.raw == self.expected_diff_v_0_2 |
|
365 | 366 | |
|
366 | 367 | expected_diff_v_0_2 = '''Index: example.py |
|
367 | 368 | =================================================================== |
|
368 | 369 | diff --git a/example.py b/example.py |
|
369 |
--- a/example.py\t(revision 2 |
|
|
370 | --- a/example.py\t(revision 25) | |
|
370 | 371 | +++ b/example.py\t(revision 26) |
|
371 | 372 | @@ -7,8 +7,12 @@ |
|
372 | 373 |
|
1 | NO CONTENT: file was removed |
|
1 | 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 |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now