##// END OF EJS Templates
diffs: compare overhaul....
marcink -
r1259:8e9f93ec default
parent child Browse files
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(target_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_alias = source_repo.scm_instance().alias
155 target_alias = target_repo.scm_instance().alias
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:
@@ -199,9 +202,9 b' class CompareController(BaseRepoControll'
199 202 c.statuses = c.rhodecode_db_repo.statuses(
200 203 [x.raw_id for x in c.commit_ranges])
201 204
202 if partial: # for PR ajax commits loader
205 if partial: # for PR ajax commits loader
203 206 if not c.ancestor:
204 return '' # cannot merge if there is no ancestor
207 return '' # cannot merge if there is no ancestor
205 208 return render('compare/compare_commits.html')
206 209
207 210 if c.ancestor:
@@ -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, path=target_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 line_context = request.GET.get('context', 3)
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 c.action = request.GET.get('diff')
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 revision=diff1, f_path=path1)
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 try:
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 'file_path': f_path,
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.
@@ -76,8 +77,8 b' def get_commit_from_ref_name(repo, ref_n'
76 77 }
77 78
78 79 commit_id = ref_name
79 if repo_scm.alias != 'svn': # pass svn refs straight to backend until
80 # the branch issue with svn is fixed
80 if repo_scm.alias != 'svn': # pass svn refs straight to backend until
81 # the branch issue with svn is fixed
81 82 if ref_type and ref_type in ref_type_mapping:
82 83 try:
83 84 commit_id = ref_type_mapping[ref_type][ref_name]
@@ -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 :attr:`_header_re`.
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,10 +1556,19 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)
1560 for cur_chunk, chunk in enumerate(chunks, start=1))
1568
1569 return (
1570 DiffChunk(chunk, self, cur_chunk == total_chunks)
1571 for cur_chunk, chunk in enumerate(chunks, start=1))
1561 1572
1562 1573
1563 1574 class DiffChunk(object):
@@ -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 p.ancestor {
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">
@@ -29,29 +29,84 b''
29 29 </%def>
30 30
31 31 <%def name="main()">
32 <div class="summary-header">
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 </div>
37 </div>
38 <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">
41 ${_('Show combined compare')}
42 </a>
43 35 </div>
44 </div>
36 </div>
37
38
39 <div class="summary changeset">
40 <div class="summary-detail">
41 <div class="summary-detail-header">
42 <span class="breadcrumbs files_location">
43 <h4>
44 ${_('Commit Range')}
45 <code>
46 r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)}...r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)}
47 </code>
48 </h4>
49 </span>
50 </div>
51
52 <div class="fieldset">
53 <div class="left-label">
54 ${_('Diff option')}:
55 </div>
56 <div class="right-content">
57 <div class="header-buttons">
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)}">
59 ${_('Show combined compare')}
60 </a>
61 </div>
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>
85 </div>
86 </div>
87 </%doc>
88 </div> <!-- end summary-detail -->
89
90 </div> <!-- end summary -->
91
92 <div id="changeset_compare_view_content">
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>
51 108 </div>
52 </div>
53 <div id="changeset_compare_view_content">
54 ##CS
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,10 +162,11 b' collapse_all = len(diffset.files) > coll'
162 162
163 163 <div class="filediffs">
164 164 %for i, filediff in enumerate(diffset.files):
165 <%
166 lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted']
167 over_lines_changed_limit = lines_changed > lines_changed_limit
168 %>
165
166 <%
167 lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted']
168 over_lines_changed_limit = lines_changed > lines_changed_limit
169 %>
169 170 <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox">
170 171 <div
171 172 class="filediff"
@@ -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 %if c.ancestor:
9 <p class="ancestor">${_('Common Ancestor Commit')}:
10 <a href="${h.url('changeset_home',
11 repo_name=c.repo_name,
12 revision=c.ancestor)}">
13 ${h.short_id(c.ancestor)}
14 </a>
15 </p>
16 %endif
4 %if c.ancestor:
5 <div class="ancestor">${_('Common Ancestor Commit')}:
6 <a href="${h.url('changeset_home',
7 repo_name=c.repo_name,
8 revision=c.ancestor)}">
9 ${h.short_id(c.ancestor)}
10 </a>
11 </div>
12 %endif
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
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>
64 <div class="code-header" >
65 <div class="compare_header">
66 ## The hidden elements are replaced with a select2 widget
67 ${h.hidden('compare_source')}
68 </div>
69 </div>
70 </div>
71 </div>
72 </div>
73
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
99 <div class="compare-buttons">
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>
123 % endif
124 % endif
125 </div>
126 </div>
127 </div>
128 </div>
129 </div>
130 </div>
131
132 <%doc>
133 ##TODO(marcink): implement this and diff menus
134 <div class="fieldset">
135 <div class="left-label">
136 ${_('Diff options')}:
137 </div>
138 <div class="right-content">
139 <div class="diff-actions">
140 <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
141 ${_('Raw Diff')}
142 </a>
143 |
144 <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
145 ${_('Patch Diff')}
146 </a>
147 |
148 <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision='?',diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
149 ${_('Download Diff')}
150 </a>
151 </div>
152 </div>
153 </div>
154 </%doc>
155
156 </div> <!-- end summary-detail -->
157
158 </div> <!-- end summary -->
159
160
42 161 <div class="table">
43 <div id="codeblock" class="diffblock">
44 <div class="code-header" >
45 <div class="compare_header">
46 ## The hidden elements are replaced with a select2 widget
47 <div class="compare-label">${_('Target')}</div>${h.hidden('compare_source')}
48 <div class="compare-label">${_('Source')}</div>${h.hidden('compare_target')}
49 162
50 %if not c.preview_mode:
51 <div class="compare-label"></div>
52 <div class="compare-buttons">
53 %if not c.compare_home:
54 <a id="btn-swap" class="btn btn-primary" href="${c.swap_url}"><i class="icon-refresh"></i> ${_('Swap')}</a>
55 %endif
56 <div id="compare_revs" class="btn btn-primary"><i class ="icon-loop"></i> ${_('Compare Commits')}</div>
57 %if c.diffset and c.diffset.files:
58 <div id="compare_changeset_status_toggle" class="btn btn-primary">${_('Comment')}</div>
59 %endif
60 </div>
61 %endif
62 </div>
63 </div>
64 </div>
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>
247 </div>
248 %else:
249 <div id="changeset_compare_view_content">
250 ##CS
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>
358 </div>
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: '${_("Switch To Commit")}',
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,17 +46,29 b''
46 46 </div>
47 47
48 48
49 <div id="node_history" class="file_diff_buttons collapsable-content" data-toggle="summary-details">
50 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
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.file_last_commit.raw_id)}
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')}:
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>
58 69 </div>
59 70
71
60 72 <script>
61 73 collapsableContent();
62 74 </script> No newline at end of file
@@ -360,14 +360,33 b''
360 360 </div>
361 361 % endif
362 362 <div class="compare_view_commits_title">
363 % if c.allowed_to_update and not c.pull_request.is_closed():
364 <a id="update_commits" class="btn btn-primary pull-right">${_('Update commits')}</a>
365 % else:
366 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
367 % 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
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">
382 % if c.allowed_to_update and not c.pull_request.is_closed():
383 <a id="update_commits" class="btn btn-primary pull-right">${_('Update commits')}</a>
384 % else:
385 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
386 % 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 = _commit_change(
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 = _commit_change(
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 _commit_change( # commit 2
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 _commit_change(
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 = _commit_change(
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 = _commit_change(
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", "git")
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 _commit_change( # commit 5
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 = _commit_change(
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 _commit_change( # commit 3
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 Commits')
447 response.mustcontain('No commits in this compare')
451 448
452 commit0 = _commit_change(
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 Commits')
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 Commits' not in response.body
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 changesets between tags
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('<p class="empty_data">No files</p>')
122 response.mustcontain('<p class="empty_data">No Commits</p>')
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, TEST_USER_ADMIN_LOGIN, assert_session_flash, assert_not_in_session_flash)
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 = AssertResponse(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 = AssertResponse(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
186 # TODO: Branch support in Subversion
187
188 commit = backend.repo.get_commit(commit_idx=150)
145 branches = dict(
146 hg=(150, ['git']),
147 # TODO: Git test repository does not contain other branches
148 git=(633, ['master']),
149 # TODO: Branch support in Subversion
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 = AssertResponse(response)
195 assert_response.element_contains(
196 '.tags .branchtag', 'git')
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 = AssertResponse(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 = AssertResponse(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': commit1.raw_id,
586 'diff2': commit2.raw_id,
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': commit1.raw_id,
626 'diff2': commit2.raw_id,
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,21 +625,23 b' class TestFilesDiff:'
642 625 response.mustcontain(
643 626 'Need query parameter', 'diff1', 'diff2', 'to generate a diff.')
644 627
645 def test_returns_not_found_if_file_does_not_exist(self, vcsbackend):
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)
659 f_path= 'README'
644 f_path = 'README'
660 645 response = self.app.get(
661 646 url(
662 647 controller='files',
@@ -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 redirected.mustcontain('has not changed between')
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 = repo[-1].raw_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[-1]
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 26)
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