Ticket #2041: trac-0.9b2-intertrac-r2308.patch
| File trac-0.9b2-intertrac-r2308.patch, 132.6 KB (added by cboos, 6 years ago) |
|---|
-
htdocs/css/browser.css
diff -ruN -x .svn trac-0.9b2/htdocs/css/browser.css intertrac-branch/htdocs/css/browser.css
old new  45 45 #dirlist td.name a, #dirlist td.rev a { border-bottom: none; display: block } 46 46 #dirlist td.change * { font-size: 9px } 47 47   48 /* Log */  49 tr.diff input {   50 padding: 0 1em 0 1em;  51 margin: 0;   52 }  53   54 div.buttons {  55 clear: left;  56 }  57   58 #anydiff {  59 margin: 0 0 1em;  60 float: left;  61 }  62 #anydiff form, #anydiff div, #anydiff h2 {  63 display: inline;  64 }  65 #anydiff input {   66 vertical-align: baseline;  67 margin: 0 -0.5em 0 1em;  68 }  69   70  48 71 /* Styles for the revision log table 49 72 (extends the styles for "table.listing") */ 50 73 #chglist { margin-top: 0 } -
htdocs/css/changeset.css
diff -ruN -x .svn trac-0.9b2/htdocs/css/changeset.css intertrac-branch/htdocs/css/changeset.css
old new  26 26  27 27 .diff ul.props { font-size: 90%; list-style: disc; margin: .5em 0 0; padding: 0 .5em 1em 2em } 28 28 .diff ul.props li { margin: 0; padding: 0 }  29   30   31 #title dl {  32 display: inline;  33 font-size: 110%  34 }  35 #title dt {   36 font-size: 110%;  37 font-weight: bold;  38 display: inline;   39 margin-left: 3em;  40 }  41 #title dd {   42 display: inline;  43 margin-left: 0.4em;  44 } -
templates/anydiff.cs
diff -ruN -x .svn trac-0.9b2/templates/anydiff.cs intertrac-branch/templates/anydiff.cs
old new   1 <?cs include "header.cs"?>  2   3 <div id="ctxtnav" class="nav">  4 <h2>Navigation</h2><?cs  5 with:links = chrome.links ?>  6 <ul>  7 </ul><?cs  8 /with ?>  9 </div>  10   11 <div id="content" class="changeset">  12 <div id="title">  13 <h1>Select Base and Target for Diff:</h1>  14 </div>  15   16 <div id="anydiff">  17 <form action="<?cs var:anydiff.diff_href ?>" method="post">  18 <table>  19 <tr>  20 <th><label for="old_path">From:</label></th>  21 <td>  22 <input type="text" id="old_path" name="old_path" value="<?cs  23 var:anydiff.old_path ?>" size="44" />  24 <label for="old_rev">at Revision:</label>  25 <input type="text" id="old_rev" name="old" value="<?cs  26 var:anydiff.old_rev ?>" size="4" />  27 </td>  28 </tr>  29 <tr>  30 <th><label for="new_path">To:</label></th>  31 <td>  32 <input type="text" id="new_path" name="path" value="<?cs  33 var:anydiff.new_path ?>" size="44" />  34 <label for="new_rev">at Revision:</label>  35 <input type="text" id="new_rev" name="new" value="<?cs  36 var:anydiff.new_rev ?>" size="4" />  37 </td>  38 </tr>  39 </table>  40 <div class="buttons">  41 <input type="submit" value="View changes" />  42 </div>  43 </form>  44 </div>  45 </div>  46   47 <?cs include "footer.cs"?> -
templates/browser.cs
diff -ruN -x .svn trac-0.9b2/templates/browser.cs intertrac-branch/templates/browser.cs
old new  3 3  4 4 <div id="ctxtnav" class="nav"> 5 5 <ul> 6  <li class="last"><a href="<?cs var:browser.log_href ?>">Revision Log</a></li>  6 <li class="first"><a href="<?cs var:browser.restr_changeset_href ?>">  7 Last Change</a></li>  8 <li class="last"><a href="<?cs var:browser.log_href ?>">  9 Revision Log</a></li> 7 10 </ul> 8 11 </div> 9 12   13  10 14 <div id="content" class="browser"> 11 15 <h1><?cs call:browser_path_links(browser.path, browser) ?></h1> 12 16  13 17 <div id="jumprev"> 14  <form action="" method="get"><div> 15  <label for="rev">View revision:</label> 16  <input type="text" id="rev" name="rev" value="<?cs 17  var:browser.revision ?>" size="4" /> 18  </div></form>  18 <form action="" method="get">  19 <div>  20 <label for="rev">View revision:</label>  21 <input type="text" id="rev" name="rev" value="<?cs  22 var:browser.revision ?>" size="4" />  23 </div>  24 </form> 19 25 </div> 20 26  21 27 <?cs if:browser.is_dir ?> … …  114 120 ?>/TracBrowser">TracBrowser</a> for help on using the browser. 115 121 </div> 116 122   123 <div id="anydiff"><?cs  124 if len(browser.path) > #1 ?>  125 <form action="<?cs var:browser.anydiff_href ?>" method="get">  126 <input type="hidden" name="new_path" value="<?cs var:browser.path ?>" />  127 <input type="hidden" name="old_path" value="<?cs var:browser.path ?>" />  128 <input type="hidden" name="new_rev" value="<?cs var:browser.revision ?>" />  129 <input type="hidden" name="old_rev" value="<?cs var:browser.revision ?>" />  130 <div class="buttons">  131 <input type="submit" value="View changes..." title="Prepare an Arbitrary Diff" />  132 </div>  133 </form><?cs  134 /if ?>  135 </div>  136  117 137 </div> 118 138 <?cs include:"footer.cs"?> -
templates/changeset.cs
diff -ruN -x .svn trac-0.9b2/templates/changeset.cs intertrac-branch/templates/changeset.cs
old new  1  <?cs include "header.cs"?>Â2  <?cs include "macros.cs"?>Â3  Â4  <div id="ctxtnav" class="nav">Â5  <h2>Changeset Navigation</h2><?csÂ6  with:links = chrome.links ?>Â7  <ul><?csÂ8  if:len(links.prev) ?>Â9  <li class="first<?cs if:!len(links.next) ?> last<?cs /if ?>">Â10  <a class="prev" href="<?cs var:links.prev.0.href ?>" title="<?csÂ11  var:links.prev.0.title ?>">Previous Changeset</a>Â12  </li><?csÂ13  /if ?><?csÂ14  if:len(links.next) ?>Â15  <li class="<?cs if:len(links.prev) ?>first <?cs /if ?>last">Â16  <a class="next" href="<?cs var:links.next.0.href ?>" title="<?csÂ17  var:links.next.0.title ?>">Next Changeset</a>Â18  </li><?csÂ19  /if ?>Â20  </ul><?csÂ21  /with ?>Â22  </div>Â23  Â24  <div id="content" class="changeset">Â25  <h1>Changeset <?cs var:changeset.revision ?></h1>Â26  Â27  <?cs each:change = changeset.changes ?><?csÂ28  if:len(change.diff) ?><?csÂ29  set:has_diffs = 1 ?><?csÂ30  /if ?><?csÂ31  /each ?><?cs if:has_diffs || diff.options.ignoreblanklinesÂ32  || diff.options.ignorecase || diff.options.ignorewhitespace ?>Â33  <form method="post" id="prefs" action="">Â34  <div>Â35  <label for="style">View differences</label>Â36  <select id="style" name="style">Â37  <option value="inline"<?csÂ38  if:diff.style == 'inline' ?> selected="selected"<?csÂ39  /if ?>>inline</option>Â40  <option value="sidebyside"<?csÂ41  if:diff.style == 'sidebyside' ?> selected="selected"<?csÂ42  /if ?>>side by side</option>Â43  </select>Â44  <div class="field">Â45  Show <input type="text" name="contextlines" id="contextlines" size="2"Â46  maxlength="2" value="<?cs var:diff.options.contextlines ?>" />Â47  <label for="contextlines">lines around each change</label>Â48  </div>Â49  <fieldset id="ignore">Â50  <legend>Ignore:</legend>Â51  <div class="field">Â52  <input type="checkbox" id="blanklines" name="ignoreblanklines"<?csÂ53  if:diff.options.ignoreblanklines ?> checked="checked"<?cs /if ?> />Â54  <label for="blanklines">Blank lines</label>Â55  </div>Â56  <div class="field">Â57  <input type="checkbox" id="case" name="ignorecase"<?csÂ58  if:diff.options.ignorecase ?> checked="checked"<?cs /if ?> />Â59  <label for="case">Case changes</label>Â60  </div>Â61  <div class="field">Â62  <input type="checkbox" id="whitespace" name="ignorewhitespace"<?csÂ63  if:diff.options.ignorewhitespace ?> checked="checked"<?cs /if ?> />Â64  <label for="whitespace">White space changes</label>Â65  </div>Â66  </fieldset>Â67  <div class="buttons">Â68  <input type="submit" name="update" value="Update" />Â69  </div>Â70  </div>Â71  </form><?cs /if ?>Â72  Â73  <?cs def:node_change(item,cl,kind) ?><?csÂ74  set:ndiffs = len(item.diff) ?><?csÂ75  set:nprops = len(item.props) ?>Â76  <div class="<?cs var:cl ?>"></div><?csÂ77  if:cl == "rem" ?>Â78  <a title="Show what was removed (rev. <?cs var:item.rev.old ?>)" href="<?csÂ79  var:item.browser_href.old ?>"><?cs var:item.path.old ?></a><?csÂ80  else ?>Â81  <a title="Show entry in browser" href="<?csÂ82  var:item.browser_href.new ?>"><?cs var:item.path.new ?></a><?csÂ83  /if ?>Â84  <span class="comment">(<?cs var:kind ?>)</span><?csÂ85  if:item.path.old && item.change == 'copy' || item.change == 'move' ?>Â86  <small><em>(<?cs var:kind ?> from <a href="<?csÂ87  var:item.browser_href.old ?>" title="Show original file (rev. <?csÂ88  var:item.rev.old ?>)"><?cs var:item.path.old ?></a>)</em></small><?csÂ89  /if ?><?csÂ90  if:$ndiffs + $nprops > #0 ?>Â91  (<a href="#file<?cs var:name(item) ?>" title="Show differences"><?csÂ92  if:$ndiffs > #0 ?><?cs var:ndiffs ?> diff<?cs if:$ndiffs > #1 ?>s<?cs /if ?><?csÂ93  /if ?><?csÂ94  if:$ndiffs && $nprops ?>, <?cs /if ?><?csÂ95  if:$nprops > #0 ?><?cs var:nprops ?> prop<?cs if:$nprops > #1 ?>s<?cs /if ?><?csÂ96  /if ?></a>)<?csÂ97  elif:cl == "mod" ?>Â98  (<a href="<?cs var:item.browser_href.old ?>"Â99  title="Show previous version in browser">previous</a>)<?csÂ100  /if ?>Â101  <?cs /def ?>Â102  Â103  <dl id="overview">Â104  <dt class="time">Timestamp:</dt>Â105  <dd class="time"><?cs var:changeset.time ?></dd>Â106  <dt class="author">Author:</dt>Â107  <dd class="author"><?cs var:changeset.author ?></dd>Â108  <dt class="message">Message:</dt>Â109  <dd class="message" id="searchable"><?cs var:changeset.message ?></dd>Â110  <dt class="files">Files:</dt>Â111  <dd class="files">Â112  <ul><?cs each:item = changeset.changes ?>Â113  <li><?csÂ114  if:item.change == 'add' ?><?csÂ115  call:node_change(item, 'add', 'added') ?><?csÂ116  elif:item.change == 'delete' ?><?csÂ117  call:node_change(item, 'rem', 'deleted') ?><?csÂ118  elif:item.change == 'copy' ?><?csÂ119  call:node_change(item, 'cp', 'copied') ?><?csÂ120  elif:item.change == 'move' ?><?csÂ121  call:node_change(item, 'mv', 'moved') ?><?csÂ122  elif:item.change == 'edit' ?><?csÂ123  call:node_change(item, 'mod', 'modified') ?><?csÂ124  /if ?>Â125  </li>Â126  <?cs /each ?></ul>Â127  </dd>Â128  </dl>Â129  Â130  <div class="diff">Â131  <div id="legend">Â132  <h3>Legend:</h3>Â133  <dl>Â134  <dt class="unmod"></dt><dd>Unmodified</dd>Â135  <dt class="add"></dt><dd>Added</dd>Â136  <dt class="rem"></dt><dd>Removed</dd>Â137  <dt class="mod"></dt><dd>Modified</dd>Â138  <dt class="cp"></dt><dd>Copied</dd>Â139  <dt class="mv"></dt><dd>Moved</dd>Â140  </dl>Â141  </div>Â142  <ul class="entries"><?csÂ143  each:item = changeset.changes ?><?csÂ144  if:len(item.diff) || len(item.props) ?><li class="entry" id="file<?csÂ145  var:name(item) ?>"><h2><a href="<?csÂ146  var:item.browser_href.new ?>" title="Show new revision <?csÂ147  var:item.rev.new ?> of this file in browser"><?csÂ148  var:item.path.new ?></a></h2><?csÂ149  if:len(item.props) ?><ul class="props"><?csÂ150  each:prop = item.props ?><li>Property <strong><?csÂ151  var:name(prop) ?></strong> <?csÂ152  if:prop.old && prop.new ?>changed from <?csÂ153  elif:!prop.old ?>set<?csÂ154  else ?>deleted<?csÂ155  /if ?><?csÂ156  if:prop.old && prop.new ?><em><tt><?cs var:prop.old ?></tt></em><?cs /if ?><?csÂ157  if:prop.new ?> to <em><tt><?cs var:prop.new ?></tt></em><?cs /if ?></li><?csÂ158  /each ?></ul><?csÂ159  /if ?><?csÂ160  if:len(item.diff) ?><table class="<?csÂ161  var:diff.style ?>" summary="Differences" cellspacing="0"><?csÂ162  if:diff.style == 'sidebyside' ?>Â163  <colgroup class="l"><col class="lineno" /><col class="content" /></colgroup>Â164  <colgroup class="r"><col class="lineno" /><col class="content" /></colgroup>Â165  <thead><tr>Â166  <th colspan="2"><a href="<?csÂ167  var:item.browser_href.old ?>" title="Show old rev. <?csÂ168  var:item.rev.old ?> of <?cs var:item.path.old ?>">Revision <?csÂ169  var:item.rev.old ?></a></th>Â170  <th colspan="2"><a href="<?csÂ171  var:item.browser_href.new ?>" title="Show new rev. <?csÂ172  var:item.rev.new ?> of <?cs var:item.path.new ?>">Revision <?csÂ173  var:item.rev.new ?></a></th>Â174  </tr>Â175  </thead><?csÂ176  each:change = item.diff ?><tbody><?csÂ177  call:diff_display(change, diff.style) ?></tbody><?csÂ178  if:name(change) < len(item.diff) - 1 ?><tbody class="skipped"><tr>Â179  <th>…</th><td> </td><th>…</th><td> </td>Â180  </tr></tbody><?cs /if ?><?csÂ181  /each ?><?csÂ182  else ?>Â183  <colgroup><col class="lineno" /><col class="lineno" /><col class="content" /></colgroup>Â184  <thead><tr>Â185  <th title="Revision <?cs var:item.rev.old ?>"><a href="<?csÂ186  var:item.browser_href.old ?>" title="Show old version of <?csÂ187  var:item.path.old ?>">r<?cs var:item.rev.old ?></a></th>Â188  <th title="Revision <?cs var:item.rev.new ?>"><a href="<?csÂ189  var:item.browser_href.new ?>" title="Show new version of <?csÂ190  var:item.path.new ?>">r<?cs var:item.rev.new ?></a></th>Â191  <th> </th></tr>Â192  </thead><?csÂ193  each:change = item.diff ?><?csÂ194  call:diff_display(change, diff.style) ?><?csÂ195  if:name(change) < len(item.diff) - 1 ?><tbody class="skipped"><tr>Â196  <th>…</th><th>…</th><td> </td>Â197  </tr></tbody><?cs /if ?><?csÂ198  /each ?><?csÂ199  /if ?></table><?csÂ200  /if ?></li><?csÂ201  /if ?><?csÂ202  /each ?></ul>Â203  </div>Â204  Â205  </div>Â206  <?cs include "footer.cs"?> -
templates/diff.cs
diff -ruN -x .svn trac-0.9b2/templates/diff.cs intertrac-branch/templates/diff.cs
old new   1 <?cs include "header.cs"?>  2 <?cs include "macros.cs"?>  3   4 <div id="ctxtnav" class="nav">  5 <h2>Navigation</h2><?cs  6 with:links = chrome.links ?>  7 <ul><?cs  8 if:diff.chgset ?><?cs  9 if:len(links.prev) ?>  10 <li class="first<?cs if:!len(links.next) ?> last<?cs /if ?>">  11 <a class="prev" href="<?cs var:links.prev.0.href ?>" title="<?cs  12 var:links.prev.0.title ?>">Previous <?cs   13 if:diff.restricted ?>Change<?cs else ?>Changeset<?cs /if ?></a>  14 </li><?cs  15 /if ?><?cs  16 if:len(links.next) ?>  17 <li class="<?cs if:len(links.prev) ?>first <?cs /if ?>last">  18 <a class="next" href="<?cs var:links.next.0.href ?>" title="<?cs  19 var:links.next.0.title ?>">Next <?cs   20 if:diff.restricted ?>Change<?cs else ?>Changeset<?cs /if ?></a>  21 </li><?cs  22 /if ?><?cs  23 else ?>  24 <li class="first"><a href="<?cs var:diff.reverse_href ?>">Reverse Diff</a></li><?cs  25 /if ?>  26 </ul><?cs  27 /with ?>  28 </div>  29   30 <div id="content" class="changeset">  31 <div id="title"><?cs  32 if:diff.chgset ?><?cs  33 if:diff.restricted ?>  34 <h1>Changeset <a title="Show full changeset" href="<?cs var:diff.href.new_rev ?>">  35 <?cs var:diff.new_rev ?></a>   36 for <a title="Show entry in browser" href="<?cs var:diff.href.new_path ?>">  37 <?cs var:diff.new_path ?></a>   38 </h1><?cs  39 else ?>  40 <h1>Changeset <?cs var:diff.new_rev ?></h1><?cs  41 /if ?><?cs  42 else ?><?cs  43 if:diff.restricted ?>  44 <h1>Changes in <a title="Show entry in browser" href="<?cs var:diff.href.new_path ?>">  45 <?cs var:diff.new_path ?></a>  46 from revision <a title="Show full changeset" href="<?cs var:diff.href.old_rev ?>">  47 <?cs var:diff.old_rev ?></a>  48 to <a title="Show full changeset" href="<?cs var:diff.href.new_rev ?>">  49 <?cs var:diff.new_rev ?></a>  50 </h1><?cs  51 else ?>  52 <h1>Changes from <a title="Show entry in browser" href="<?cs var:diff.href.old_path ?>">  53 <?cs var:diff.old_path ?></a>   54 at revision <a title="Show full changeset" href="<?cs var:diff.href.old_rev ?>">  55 <?cs var:diff.old_rev ?></a>  56 to <a title="Show entry in browser" href="<?cs var:diff.href.new_path ?>">  57 <?cs var:diff.new_path ?></a>   58 at revision <a title="Show full changeset" href="<?cs var:diff.href.new_rev ?>">  59 <?cs var:diff.new_rev ?></a>  60 </h1><?cs  61 /if ?><?cs  62 /if ?>  63 </div>  64   65 <?cs each:change = diff.changes ?><?cs  66 if:len(change.diff) ?><?cs  67 set:has_diffs = 1 ?><?cs  68 /if ?><?cs  69 /each ?><?cs if:has_diffs || diff.options.ignoreblanklines   70 || diff.options.ignorecase || diff.options.ignorewhitespace ?>  71 <form method="post" id="prefs" action="">  72 <div><?cs   73 if:!diff.chgset ?>  74 <input type="hidden" name="old_path" value="<?cs var:diff.old_path ?>" />  75 <input type="hidden" name="path" value="<?cs var:diff.new_path ?>" />  76 <input type="hidden" name="old" value="<?cs var:diff.old_rev ?>" />  77 <input type="hidden" name="new" value="<?cs var:diff.new_rev ?>" /><?cs  78 /if ?>  79 <label for="style">View differences</label>  80 <select id="style" name="style">  81 <option value="inline"<?cs  82 if:diff.style == 'inline' ?> selected="selected"<?cs  83 /if ?>>inline</option>  84 <option value="sidebyside"<?cs  85 if:diff.style == 'sidebyside' ?> selected="selected"<?cs  86 /if ?>>side by side</option>  87 </select>  88 <div class="field">  89 Show <input type="text" name="contextlines" id="contextlines" size="2"  90 maxlength="2" value="<?cs var:diff.options.contextlines ?>" />  91 <label for="contextlines">lines around each change</label>  92 </div>  93 <fieldset id="ignore">  94 <legend>Ignore:</legend>  95 <div class="field">  96 <input type="checkbox" id="blanklines" name="ignoreblanklines"<?cs  97 if:diff.options.ignoreblanklines ?> checked="checked"<?cs /if ?> />  98 <label for="blanklines">Blank lines</label>  99 </div>  100 <div class="field">  101 <input type="checkbox" id="case" name="ignorecase"<?cs  102 if:diff.options.ignorecase ?> checked="checked"<?cs /if ?> />  103 <label for="case">Case changes</label>  104 </div>  105 <div class="field">  106 <input type="checkbox" id="whitespace" name="ignorewhitespace"<?cs  107 if:diff.options.ignorewhitespace ?> checked="checked"<?cs /if ?> />  108 <label for="whitespace">White space changes</label>  109 </div>  110 </fieldset>  111 <div class="buttons">  112 <input type="submit" name="update" value="Update" />  113 </div>  114 </div>  115 </form><?cs /if ?>  116   117 <?cs def:node_change(item,cl,kind) ?><?cs   118 set:ndiffs = len(item.diff) ?><?cs  119 set:nprops = len(item.props) ?>  120 <div class="<?cs var:cl ?>"></div><?cs   121 if:cl == "rem" ?>  122 <a title="Show what was removed (rev. <?cs var:item.rev.old ?>)" href="<?cs  123 var:item.browser_href.old ?>"><?cs var:item.path.old ?></a><?cs  124 else ?>  125 <a title="Show entry in browser" href="<?cs  126 var:item.browser_href.new ?>"><?cs var:item.path.new ?></a><?cs  127 /if ?>  128 <span class="comment">(<?cs var:kind ?>)</span><?cs  129 if:item.path.old && item.change == 'copy' || item.change == 'move' ?>  130 <small><em>(<?cs var:kind ?> from <a href="<?cs  131 var:item.browser_href.old ?>" title="Show original file (rev. <?cs  132 var:item.rev.old ?>)"><?cs var:item.path.old ?></a>)</em></small><?cs  133 /if ?><?cs  134 if:$ndiffs + $nprops > #0 ?>  135 (<a href="#file<?cs var:name(item) ?>" title="Show differences"><?cs  136 if:$ndiffs > #0 ?><?cs var:ndiffs ?> diff<?cs if:$ndiffs > #1 ?>s<?cs /if ?><?cs   137 /if ?><?cs  138 if:$ndiffs && $nprops ?>, <?cs /if ?><?cs   139 if:$nprops > #0 ?><?cs var:nprops ?> prop<?cs if:$nprops > #1 ?>s<?cs /if ?><?cs  140 /if ?></a>)<?cs  141 elif:cl == "mod" ?>  142 (<a href="<?cs var:item.browser_href.old ?>"  143 title="Show previous version in browser">previous</a>)<?cs  144 /if ?>  145 <?cs /def ?>  146   147 <dl id="overview"><?cs  148 if:diff.chgset ?>  149 <dt class="time">Timestamp:</dt>  150 <dd class="time"><?cs var:changeset.time ?></dd>  151 <dt class="author">Author:</dt>  152 <dd class="author"><?cs var:changeset.author ?></dd>  153 <dt class="message">Message:</dt>  154 <dd class="message" id="searchable"><?cs var:changeset.message ?></dd><?cs  155 /if ?>  156 <dt class="files"><?cs   157 if:len(diff.changes) > #0 ?>  158 Files:<?cs  159 else ?>  160 (None)<?cs  161 /if ?>  162 </dt>  163 <dd class="files">  164 <ul><?cs each:item = diff.changes ?>  165 <li><?cs  166 if:item.change == 'add' ?><?cs  167 call:node_change(item, 'add', 'added') ?><?cs  168 elif:item.change == 'delete' ?><?cs  169 call:node_change(item, 'rem', 'deleted') ?><?cs  170 elif:item.change == 'copy' ?><?cs  171 call:node_change(item, 'cp', 'copied') ?><?cs  172 elif:item.change == 'move' ?><?cs  173 call:node_change(item, 'mv', 'moved') ?><?cs  174 elif:item.change == 'edit' ?><?cs  175 call:node_change(item, 'mod', 'modified') ?><?cs  176 /if ?>  177 </li>  178 <?cs /each ?></ul>  179 </dd>  180 </dl>  181   182 <div class="diff">  183 <div id="legend">  184 <h3>Legend:</h3>  185 <dl>  186 <dt class="unmod"></dt><dd>Unmodified</dd>  187 <dt class="add"></dt><dd>Added</dd>  188 <dt class="rem"></dt><dd>Removed</dd>  189 <dt class="mod"></dt><dd>Modified</dd>  190 <dt class="cp"></dt><dd>Copied</dd>  191 <dt class="mv"></dt><dd>Moved</dd>  192 </dl>  193 </div>  194 <ul class="entries"><?cs  195 each:item = diff.changes ?><?cs  196 if:len(item.diff) || len(item.props) ?><li class="entry" id="file<?cs  197 var:name(item) ?>"><h2><a href="<?cs  198 var:item.browser_href.new ?>" title="Show new revision <?cs  199 var:item.rev.new ?> of this file in browser"><?cs  200 var:item.path.new ?></a></h2><?cs  201 if:len(item.props) ?><ul class="props"><?cs  202 each:prop = item.props ?><li>Property <strong><?cs  203 var:name(prop) ?></strong> <?cs  204 if:prop.old && prop.new ?>changed from <?cs  205 elif:!prop.old ?>set<?cs  206 else ?>deleted<?cs  207 /if ?><?cs  208 if:prop.old && prop.new ?><em><tt><?cs var:prop.old ?></tt></em><?cs /if ?><?cs  209 if:prop.new ?> to <em><tt><?cs var:prop.new ?></tt></em><?cs /if ?></li><?cs  210 /each ?></ul><?cs  211 /if ?><?cs  212 if:len(item.diff) ?><table class="<?cs  213 var:diff.style ?>" summary="Differences" cellspacing="0"><?cs  214 if:diff.style == 'sidebyside' ?>  215 <colgroup class="l"><col class="lineno" /><col class="content" /></colgroup>  216 <colgroup class="r"><col class="lineno" /><col class="content" /></colgroup>  217 <thead><tr>  218 <th colspan="2"><a href="<?cs  219 var:item.browser_href.old ?>" title="Show old rev. <?cs  220 var:item.rev.old ?> of <?cs var:item.path.old ?>">Revision <?cs  221 var:item.rev.old ?></a></th>  222 <th colspan="2"><a href="<?cs  223 var:item.browser_href.new ?>" title="Show new rev. <?cs  224 var:item.rev.new ?> of <?cs var:item.path.new ?>">Revision <?cs  225 var:item.rev.new ?></a></th>  226 </tr>  227 </thead><?cs  228 each:change = item.diff ?><tbody><?cs  229 call:diff_display(change, diff.style) ?></tbody><?cs  230 if:name(change) < len(item.diff) - 1 ?><tbody class="skipped"><tr>  231 <th>…</th><td> </td><th>…</th><td> </td>  232 </tr></tbody><?cs /if ?><?cs  233 /each ?><?cs  234 else ?>  235 <colgroup><col class="lineno" /><col class="lineno" /><col class="content" /></colgroup>  236 <thead><tr>  237 <th title="Revision <?cs var:item.rev.old ?>"><a href="<?cs  238 var:item.browser_href.old ?>" title="Show old version of <?cs  239 var:item.path.old ?>">r<?cs var:item.rev.old ?></a></th>  240 <th title="Revision <?cs var:item.rev.new ?>"><a href="<?cs  241 var:item.browser_href.new ?>" title="Show new version of <?cs  242 var:item.path.new ?>">r<?cs var:item.rev.new ?></a></th>  243 <th> </th></tr>  244 </thead><?cs  245 each:change = item.diff ?><?cs  246 call:diff_display(change, diff.style) ?><?cs  247 if:name(change) < len(item.diff) - 1 ?><tbody class="skipped"><tr>  248 <th>…</th><th>…</th><td> </td>  249 </tr></tbody><?cs /if ?><?cs  250 /each ?><?cs  251 /if ?></table><?cs  252 /if ?></li><?cs  253 /if ?><?cs  254 /each ?></ul>  255 </div>  256   257 </div>  258 <?cs include "footer.cs"?> -
templates/log.cs
diff -ruN -x .svn trac-0.9b2/templates/log.cs intertrac-branch/templates/log.cs
old new  3 3  4 4 <div id="ctxtnav" class="nav"> 5 5 <ul> 6  <li class="last"><a href="<?cs 7  var:log.browser_href ?>">View Latest Revision</a></li><?cs  6 <li class="last">  7 <a href="<?cs var:log.browser_href ?>">View Latest Revision</a>  8 </li><?cs 8 9 if:len(chrome.links.prev) ?> 9 10 <li class="first<?cs if:!len(chrome.links.next) ?> last<?cs /if ?>"> 10 11 ← <a href="<?cs var:chrome.links.prev.0.href ?>" title="<?cs … …  61 62 title="Warning: by updating, you will clear the page history" /> 62 63 </div> 63 64 </form>  65  64 66 <div class="diff"> 65 67 <div id="legend"> 66 68 <h3>Legend:</h3> … …  74 76 </dl> 75 77 </div> 76 78 </div>  79   80 <form action="<?cs var:log.href ?>" method="post">  81 <div class="buttons"><input type="submit" value="View changes"   82 title="Diff from Old Revision to New Revision (select them below)" />  83 </div> 77 84 <table id="chglist" class="listing"> 78 85 <thead> 79 86 <tr>  87 <th>Old</th>  88 <th>New</th> 80 89 <th class="change"></th> 81 90 <th class="data">Date</th> 82 91 <th class="rev">Rev</th> … …  87 96 </thead> 88 97 <tbody><?cs 89 98 set:indent = #1 ?><?cs  99 set:idx = #0 ?><?cs 90 100 each:item = log.items ?><?cs 91 101 if:item.copyfrom_path ?> 92 102 <tr class="<?cs if:name(item) % #2 ?>even<?cs else ?>odd<?cs /if ?>"> 93  <td class="copyfrom_path" colspan=" 6" style="padding-left: <?cs var:indent ?>em"> 103 <td class="copyfrom_path" colspan="8" style="padding-left: <?cs var:indent ?>em"> 94 104 copied from <a href="<?cs var:item.browser_href ?>"?><?cs var:item.copyfrom_path ?></a>: 95 105 </td> 96 106 </tr><?cs … …  99 109 set:indent = #1 ?><?cs 100 110 /if ?> 101 111 <tr class="<?cs if:name(item) % #2 ?>even<?cs else ?>odd<?cs /if ?>">  112 <td><input type="radio" name="old"   113 value="<?cs var:item.path ?>#<?cs var:item.rev ?>" <?cs  114 if:idx == #1 ?> checked="checked" <?cs /if ?> /></td>  115 <td><input type="radio" name="new"   116 value="<?cs var:item.path ?>#<?cs var:item.rev ?>" <?cs  117 if:idx == #0 ?> checked="checked" <?cs /if ?> /></td> 102 118 <td class="change" style="padding-left:<?cs var:indent ?>em"> 103 119 <a title="View log starting at this revision" href="<?cs var:item.log_href ?>"> 104 120 <span class="<?cs var:item.change ?>"></span> … …  117 133 <td class="author"><?cs var:log.changes[item.rev].author ?></td> 118 134 <td class="summary"><?cs var:log.changes[item.rev].message ?></td> 119 135 </tr><?cs  136 set:idx = idx + 1 ?><?cs 120 137 /each ?> 121 138 </tbody> 122  </table><?cs  139 </table>  140 <div class="buttons"><input type="submit" value="View changes"   141 title="Diff from Old Revision to New Revision (select them above)" />  142 </div>  143 </form><?cs 123 144 if:len(links.prev) || len(links.next) ?><div id="paging" class="nav"><ul><?cs 124 145 if:len(links.prev) ?><li class="first<?cs 125 146 if:!len(links.next) ?> last<?cs /if ?>">← <a href="<?cs -
templates/wiki.cs
diff -ruN -x .svn trac-0.9b2/templates/wiki.cs intertrac-branch/templates/wiki.cs
old new  154 154 var:wiki.page_name ?></a></h1> 155 155 <?cs if:len(wiki.history) ?><form method="get" action=""> 156 156 <input type="hidden" name="action" value="diff" />  157 <div class="buttons">  158 <input type="submit" value="View changes" />  159 </div> 157 160 <table id="wikihist" class="listing" summary="Change history"> 158 161 <thead><tr> 159 162 <th class="diff"></th> -
trac/db_default.py
diff -ruN -x .svn trac-0.9b2/trac/db_default.py intertrac-branch/trac/db_default.py
old new  432 432 ('timeline', 'default_daysback', '30'), 433 433 ('browser', 'hide_properties', 'svk:merge'), 434 434 ('wiki', 'ignore_missing_pages', 'false'),  435 ('disabled_components', 'trac.wiki.api.StandardWikiPageNames', 'no'),  436 ('disabled_components', 'trac.wiki.api.FlexibleWikiPageNames', 'yes'),  437 ('disabled_components', 'trac.wiki.api.SubWikiPageNames', 'yes'), 435 438 ) 436 439  437 440 default_components = ('trac.About', 'trac.attachment',  -
trac/env.py
diff -ruN -x .svn trac-0.9b2/trac/env.py intertrac-branch/trac/env.py
old new  66 66 ComponentManager.__init__(self) 67 67  68 68 self.path = path  69 self.siblings = {} 69 70 self.__cnx_pool = None 70 71 if create: 71 72 self.create(db_str) -
trac/__init__.py
diff -ruN -x .svn trac-0.9b2/trac/__init__.py intertrac-branch/trac/__init__.py
old new  10 10 """ 11 11 __docformat__ = 'epytext en' 12 12  13  __version__ = '0.9b2 ' 13 __version__ = '0.9b2-intertrac' 14 14 __url__ = 'http://trac.edgewall.com/' 15 15 __copyright__ = '(C) 2003-2005 Edgewall Software' 16 16 __license__ = 'BSD' -
trac/siteconfig.py
diff -ruN -x .svn trac-0.9b2/trac/siteconfig.py intertrac-branch/trac/siteconfig.py
old new   1   2 # PLEASE DO NOT EDIT THIS FILE!  3 # This file was autogenerated when installing Trac 0.9b1-intertrac.  4 #  5 __default_templates_dir__ = '/opt/trac/stable-bct-trac/share/trac/templates'  6 __default_htdocs_dir__ = '/opt/trac/stable-bct-trac/share/trac/htdocs'  7 __default_wiki_dir__ = '/opt/trac/stable-bct-trac/share/trac/wiki-default'  8 __default_macros_dir__ = '/opt/trac/stable-bct-trac/share/trac/wiki-macros'  9  -
trac/ticket/api.py
diff -ruN -x .svn trac-0.9b2/trac/ticket/api.py intertrac-branch/trac/ticket/api.py
old new  19 19 from trac import util 20 20 from trac.core import * 21 21 from trac.perm import IPermissionRequestor 22  from trac.wiki import IWikiSyntaxProvider  22 from trac.wiki import IWikiSyntaxProvider, INTERTRAC_SCHEME 23 23 from trac.Search import ISearchSource, query_to_sql, shorten_result 24 24  25 25  … …  149 149 ('ticket', self._format_link)] 150 150  151 151 def get_wiki_syntax(self): 152  yield (r"!?# \d+",Â153  lambda x, y, z: self._format_link(x, 'ticket', y[1:], y )) 152 yield (r"!?#(?P<it_ticket>%s)?\d+" % INTERTRAC_SCHEME,  153 lambda x, y, z: self._format_link(x, 'ticket', y[1:], y, z)) 154 154  155  def _format_link(self, formatter, ns, target, label):  155 def _format_link(self, formatter, ns, target, label, fullmatch=None):  156 intertrac = formatter.shorthand_intertrac_helper(ns, target, label,  157 fullmatch)  158 if intertrac:  159 return intertrac 156 160 cursor = formatter.db.cursor() 157 161 cursor.execute("SELECT summary,status FROM ticket WHERE id=%s", 158 162 (target,)) -
trac/ticket/report.py
diff -ruN -x .svn trac-0.9b2/trac/ticket/report.py intertrac-branch/trac/ticket/report.py
old new  24 24 from trac.perm import IPermissionRequestor 25 25 from trac.web import IRequestHandler 26 26 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 27  from trac.wiki import wiki_to_html, IWikiSyntaxProvider  27 from trac.wiki import wiki_to_html, IWikiSyntaxProvider, INTERTRAC_SCHEME 28 28  29 29  30 30 dynvars_re = re.compile('\$([A-Z]+)') … …  510 510 yield ('report', self._format_link) 511 511  512 512 def get_wiki_syntax(self): 513  yield (r"!?\{\d+\}", lambda x, y, z: self._format_link(x, 'report', y[1:-1], y))  513 yield (r"!?\{(?P<it_report>%s\s*)?\d+\}" % INTERTRAC_SCHEME,  514 lambda x, y, z: self._format_link(x, 'report', y[1:-1], y, z)) 514 515  515  def _format_link(self, formatter, ns, target, label):  516 def _format_link(self, formatter, ns, target, label, fullmatch=None):  517 intertrac = formatter.shorthand_intertrac_helper(ns, target, label,  518 fullmatch)  519 if intertrac:  520 return intertrac 516 521 return '<a class="report" href="%s">%s</a>' % (formatter.href.report(target), label) 517 522  -
trac/versioncontrol/api.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/api.py intertrac-branch/trac/versioncontrol/api.py
old new  39 39 """ 40 40 raise NotImplementedError 41 41   42 def has_node(self, path, rev):  43 """  44 Tell if there's a node at the specified (path,rev) combination.  45 """  46 raise NotImplementedError  47  42 48 def get_node(self, path, rev=None): 43 49 """ 44 50 Retrieve a Node (directory or file) from the repository at the … …  111 117 'None' is a valid revision value and represents the youngest revision. 112 118 """ 113 119 return NotImplementedError 114    120   121 def get_deltas(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=1):  122 """  123 Generator that yields change tuples (old_node, new_node, kind, change)  124 for each node change between the two arbitrary (path,rev) pairs.  125   126 The old_node is assumed to be None when the change is an ADD,  127 the new_node is assumed to be None when the change is a DELETE.  128 """  129 raise NotImplementedError  130  115 131  116 132 class Node(object): 117 133 """ … …  149 165 node (if the underlying version control system supports that), which 150 166 will be indicated by the first element of the tuple (i.e. the path) 151 167 changing.  168 Starts with an entry for the current revision. 152 169 """ 153 170 raise NotImplementedError 154 171   172 def get_previous(self):  173 """  174 Return the (path, rev, chg) tuple corresponding to the previous  175 revision for that node.  176 """  177 skip = True  178 for p in self.get_history(2):  179 if skip:  180 skip = False  181 else:  182 return p  183  155 184 def get_properties(self): 156 185 """ 157 186 Returns a dictionary containing the properties (meta-data) of the node. -
trac/versioncontrol/cache.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/cache.py intertrac-branch/trac/versioncontrol/cache.py
old new  84 84 def get_node(self, path, rev=None): 85 85 return self.repos.get_node(path, rev) 86 86   87 def has_node(self, path, rev):  88 return self.repos.has_node(path, rev)  89  87 90 def get_oldest_rev(self): 88 91 return self.repos.oldest_rev 89 92  … …  108 111 def normalize_rev(self, rev): 109 112 return self.repos.normalize_rev(rev) 110 113   114 def get_deltas(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=1):  115 return self.repos.get_deltas(old_path, old_rev, new_path, new_rev, ignore_ancestry)  116  111 117  112 118 class CachedChangeset(Changeset): 113 119  -
trac/versioncontrol/diff.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/diff.py intertrac-branch/trac/versioncontrol/diff.py
old new  218 218 ignore_space_changes) 219 219 for group in _group_opcodes(opcodes, context): 220 220 i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4]  221 if i1 == 0 and i2 == 0:  222 i1, i2 = -1, -1 # support for 'A'dd changes 221 223 yield '@@ -%d,%d +%d,%d @@' % (i1 + 1, i2 - i1, j1 + 1, j2 - j1) 222 224 for tag, i1, i2, j1, j2 in group: 223 225 if tag == 'equal': -
trac/versioncontrol/svn_fs.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/svn_fs.py intertrac-branch/trac/versioncontrol/svn_fs.py
old new  207 207 def __del__(self): 208 208 self.close() 209 209   210 def has_node(self, path, rev):  211 rev_root = fs.revision_root(self.fs_ptr, rev, self.pool())  212 node_type = fs.check_path(rev_root, path, self.pool())  213 return node_type in _kindmap  214  210 215 def normalize_path(self, path): 211 216 return (not path or path == '/') and '/' or path.strip('/') 212 217  … …  298 303 subpool = Pool(self.pool) 299 304 while rev: 300 305 subpool.clear() 301  rev_root = fs.revision_root(self.fs_ptr, rev, subpool()) 302  node_type = fs.check_path(rev_root, path, subpool()) 303  if node_type in _kindmap: # then path exists at that rev  306 if self.has_node(path, rev): 304 307 if expect_deletion: 305 308 # it was missing, now it's there again: 306 309 # rev+1 must be a delete … …  330 333 expect_deletion = True 331 334 rev = self.previous_rev(rev) 332 335   336 def get_deltas(self, old_path, old_rev, new_path, new_rev,  337 ignore_ancestry=0):  338 old_node = new_node = None  339 old_rev = self.normalize_rev(old_rev)  340 new_rev = self.normalize_rev(new_rev)  341 if self.has_node(old_path, old_rev):  342 old_node = self.get_node(old_path, old_rev)  343 else:  344 raise TracError, ('The Base for Diff is invalid: path %s'  345 ' doesn\'t exist in revision %s' \  346 % (old_path, old_rev))  347 if self.has_node(new_path, new_rev):  348 new_node = self.get_node(new_path, new_rev)  349 else:  350 raise TracError, ('The Target for Diff is invalid: path %s'  351 ' doesn\'t exist in revision %s' \  352 % (new_path, new_rev))  353 if new_node.kind != old_node.kind:  354 raise TracError, ('Diff mismatch: Base is a %s (%s in revision %s) '  355 'and Target is a %s (%s in revision %s).' \  356 % (old_node.kind, old_path, old_rev,  357 new_node.kind, new_path, new_rev))  358 subpool = Pool(self.pool)  359 if new_node.isdir:  360 editor = DiffChangeEditor()  361 e_ptr, e_baton = delta.make_editor(editor, subpool())  362 old_root = fs.revision_root(self.fs_ptr, old_rev, subpool())  363 new_root = fs.revision_root(self.fs_ptr, new_rev, subpool())  364 def authz_cb(root, path, pool): return 1  365 text_deltas = 0 # as this is anyway re-done in Diff.py...  366 entry_props = 0 # "... typically used only for working copy updates"  367 repos.svn_repos_dir_delta(old_root, old_path, '',  368 new_root, new_path,  369 e_ptr, e_baton, authz_cb,  370 text_deltas,  371 1, # directory  372 entry_props,  373 ignore_ancestry,  374 subpool())  375 for path, kind, change in editor.deltas:  376 old_node = new_node = None  377 if change != Changeset.ADD:  378 old_node = self.get_node(posixpath.join(old_path, path),  379 old_rev)  380 if change != Changeset.DELETE:  381 new_node = self.get_node(posixpath.join(new_path, path),  382 new_rev)  383 else:  384 kind = _kindmap[fs.check_path(old_root, old_node.path,  385 subpool())]  386 yield (old_node, new_node, kind, change)  387 else:  388 old_root = fs.revision_root(self.fs_ptr, old_rev, subpool())  389 new_root = fs.revision_root(self.fs_ptr, new_rev, subpool())  390 if fs.contents_changed(old_root, old_path, new_root, new_path,  391 subpool()):  392 yield (old_node, new_node, Node.FILE, Changeset.EDIT)  393  333 394  334 395 class SubversionNode(Node): 335 396  … …  352 413 self.pool()) 353 414 self.created_path = fs.node_created_path(self.root, self.scoped_path, 354 415 self.pool()) 355  # 'created_path' differs from 'path' if the last operation is a copy, 356  # and furthermore, 'path' might not exist at 'create_rev'  416 # Note: 'created_path' differs from 'path' if the last change was a copy,  417 # and furthermore, 'path' might not exist at 'create_rev'.  418 # The only guarantees are:  419 # * this node exists at (path,rev)  420 # * the node existed at (created_path,created_rev)  421 # TODO: check node id 357 422 self.rev = self.created_rev 358 423  359 424 Node.__init__(self, path, self.rev, _kindmap[node_type]) … …  393 458 if newer: 394 459 yield newer 395 460   461 # def get_previous(self):  462 # # FIXME: redo it with fs.node_history  463  396 464 def get_properties(self): 397 465 props = fs.node_proplist(self.root, self.scoped_path, self.pool()) 398 466 for name,value in props.items(): … …  487 555  488 556 def _get_prop(self, name): 489 557 return fs.revision_prop(self.fs_ptr, self.rev, name, self.pool())  558   559   560 #  561 # Delta editor for diffs between arbitrary nodes  562 #  563 # Note 1: the 'copyfrom_path' and 'copyfrom_rev' information is not used  564 # because 'repos.svn_repos_dir_delta' *doesn't* provide it.  565 #  566 # Note 2: the 'dir_baton' is the path of the parent directory  567 #  568   569 class DiffChangeEditor(delta.Editor):   570   571 def __init__(self):  572 self.deltas = []  573   574 # -- svn.delta.Editor callbacks  575   576 def open_root(self, base_revision, dir_pool):  577 return ('/', Changeset.EDIT)  578   579 def add_directory(self, path, dir_baton, copyfrom_path, copyfrom_rev,  580 dir_pool):  581 self.deltas.append((path, Node.DIRECTORY, Changeset.ADD))  582 return (path, Changeset.ADD)  583   584 def open_directory(self, path, dir_baton, base_revision, dir_pool):  585 return (path, dir_baton[1])  586   587 def change_dir_prop(self, dir_baton, name, value, pool):  588 path, change = dir_baton  589 if change != Changeset.ADD:  590 self.deltas.append((path, Node.DIRECTORY, change))  591   592 def delete_entry(self, path, revision, dir_baton, pool):  593 self.deltas.append((path, None, Changeset.DELETE))  594   595 def add_file(self, path, dir_baton, copyfrom_path, copyfrom_revision,  596 dir_pool):  597 self.deltas.append((path, Node.FILE, Changeset.ADD))  598   599 def open_file(self, path, dir_baton, dummy_rev, file_pool):  600 self.deltas.append((path, Node.FILE, Changeset.EDIT))  601  -
trac/versioncontrol/tests/svn_fs.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/tests/svn_fs.py intertrac-branch/trac/versioncontrol/tests/svn_fs.py
old new  215 215 self.assertEqual(('tags/v1', 7, 'unknown'), history.next()) 216 216 self.assertRaises(StopIteration, history.next) 217 217   218 # Diffs  219   220 def _cmp_diff(self, expected, got):  221 if expected[0]:  222 old = self.repos.get_node(*expected[0])  223 self.assertEqual((old.path, old.rev), (got[0].path, got[0].rev))  224 if expected[1]:  225 new = self.repos.get_node(*expected[1])  226 self.assertEqual((new.path, new.rev), (got[1].path, got[1].rev))  227 self.assertEqual(expected[2], (got[2], got[3]))  228   229 def test_diff_file_different_revs(self):  230 diffs = self.repos.get_deltas('trunk/README.txt', 2, 'trunk/README.txt', 3)  231 self._cmp_diff((('trunk/README.txt', 2),  232 ('trunk/README.txt', 3),  233 (Node.FILE, Changeset.EDIT)), diffs.next())  234 self.assertRaises(StopIteration, diffs.next)  235   236 def test_diff_file_different_files(self):  237 diffs = self.repos.get_deltas('branches/v1x/README.txt', 12,  238 'branches/v1x/README2.txt', 12)  239 self._cmp_diff((('branches/v1x/README.txt', 12),  240 ('branches/v1x/README2.txt', 12),  241 (Node.FILE, Changeset.EDIT)), diffs.next())  242 self.assertRaises(StopIteration, diffs.next)  243   244 def test_diff_file_no_change(self):  245 diffs = self.repos.get_deltas('trunk/README.txt', 7,  246 'tags/v1/README.txt', 7)  247 self.assertRaises(StopIteration, diffs.next)  248   249 def test_diff_dir_different_revs(self):  250 diffs = self.repos.get_deltas('trunk', 4, 'trunk', 8)  251 self._cmp_diff((None, ('trunk/dir1/dir2', 8),  252 (Node.DIRECTORY, Changeset.ADD)), diffs.next())  253 self._cmp_diff((None, ('trunk/dir1/dir3', 8),  254 (Node.DIRECTORY, Changeset.ADD)), diffs.next())  255 self._cmp_diff((None, ('trunk/README2.txt', 6),  256 (Node.FILE, Changeset.ADD)), diffs.next())  257 self._cmp_diff((('trunk/dir2', 4), None,  258 (Node.DIRECTORY, Changeset.DELETE)), diffs.next())  259 self._cmp_diff((('trunk/dir3', 4), None,  260 (Node.DIRECTORY, Changeset.DELETE)), diffs.next())  261 self.assertRaises(StopIteration, diffs.next)  262   263 def test_diff_dir_different_dirs(self):  264 diffs = self.repos.get_deltas('trunk', 1, 'branches/v1x', 12)  265 self._cmp_diff((None, ('branches/v1x/dir1', 12),  266 (Node.DIRECTORY, Changeset.ADD)), diffs.next())  267 self._cmp_diff((None, ('branches/v1x/dir1/dir2', 12),  268 (Node.DIRECTORY, Changeset.ADD)), diffs.next())  269 self._cmp_diff((None, ('branches/v1x/dir1/dir3', 12),  270 (Node.DIRECTORY, Changeset.ADD)), diffs.next())  271 self._cmp_diff((None, ('branches/v1x/README.txt', 12),  272 (Node.FILE, Changeset.ADD)), diffs.next())  273 self._cmp_diff((None, ('branches/v1x/README2.txt', 12),  274 (Node.FILE, Changeset.ADD)), diffs.next())  275 self.assertRaises(StopIteration, diffs.next)  276   277 def test_diff_dir_no_change(self):  278 diffs = self.repos.get_deltas('trunk', 7,  279 'tags/v1', 7)  280 self.assertRaises(StopIteration, diffs.next)  281   282 # Changesets  283  218 284 def test_changeset_repos_creation(self): 219 285 chgset = self.repos.get_changeset(0) 220 286 self.assertEqual(0, chgset.rev) -
trac/versioncontrol/web_ui/browser.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/web_ui/browser.py intertrac-branch/trac/versioncontrol/web_ui/browser.py
old new  88 88  89 89 repos = self.env.get_repository(req.authname) 90 90 node = repos.get_node(path, rev)  91 rev = repos.normalize_rev(rev) 91 92  92 93 hidden_properties = [p.strip() for p 93 94 in self.config.get('browser', 'hide_properties', 94 95 'svk:merge').split(',')]  96  95 97 req.hdf['title'] = path 96  req.hdf['browser']= { 98 browser_hdf = { 97 99 'path': path, 98  'revision': rev or repos.youngest_rev, 100 'revision': rev, 99 101 'props': dict([(util.escape(name), util.escape(value)) 100 102 for name, value in node.get_properties().items() 101  if not name in hidden_properties]), 102  'href': util.escape(self.env.href.browser(path, rev=rev or 103  repos.youngest_rev)), 104  'log_href': util.escape(self.env.href.log(path)) 105  }  103 if not name in hidden_properties])  104 }  105 browser_hrefs = {  106 'href': self.env.href.browser(path,rev=rev),  107 'restr_changeset_href': self.env.href.changeset(node.rev, path),  108 'anydiff_href': self.env.href.anydiff(),  109 'log_href': self.env.href.log(path)  110 }  111 browser_hdf.update(dict([(key, util.escape(href)) for key, href in  112 browser_hrefs.items()]))  113 req.hdf['browser'] = browser_hdf 106 114  107 115 path_links = get_path_links(self.env.href, path, rev) 108 116 if len(path_links) > 1: … …  162 170  163 171 req.hdf['browser.items'] = info 164 172 req.hdf['browser.changes'] = changes 165    173 if node.path != '':  174 zip_href = self.env.href.diff(node.path, new=rev, old=rev,  175 old_path='/', # special case (#238)  176 format='zip')  177 add_link(req, 'alternate', zip_href, 'Zip Archive',  178 'application/zip', 'zip')  179   180  166 181 def _render_file(self, req, repos, node, rev=None): 167 182 req.perm.assert_permission('FILE_VIEW') 168 183  -
trac/versioncontrol/web_ui/changeset.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/web_ui/changeset.py intertrac-branch/trac/versioncontrol/web_ui/changeset.py
old new  22 22  23 23 from trac import mimeview, util 24 24 from trac.core import * 25  from trac.perm import IPermissionRequestorÂ26 25 from trac.Search import ISearchSource, query_to_sql, shorten_result 27 26 from trac.Timeline import ITimelineEventProvider 28 27 from trac.versioncontrol import Changeset, Node 29 28 from trac.versioncontrol.svn_authz import SubversionAuthorizer 30  from trac.versioncontrol.diff import get_diff_options, hdf_diff, unified_diffÂ31 29 from trac.web import IRequestHandler 32  from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 33  from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider  30 from trac.web.chrome import INavigationContributor  31 from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider, \  32 INTERTRAC_SCHEME  33 from trac.versioncontrol.web_ui.diff import AbstractDiffModule 34 34   35 class ChangesetModule(AbstractDiffModule): 35 36  36  class ChangesetModule(Component): 37   38  implements(INavigationContributor, IPermissionRequestor, IRequestHandler,  37 implements(INavigationContributor,  39 38 ITimelineEventProvider, IWikiSyntaxProvider, ISearchSource) 40 39  41 40 # INavigationContributor methods … …  46 45 def get_navigation_items(self, req): 47 46 return [] 48 47  49  # IPermissionRequestor methods 50   51  def get_permission_actions(self): 52  return ['CHANGESET_VIEW'] 53   54  # IRequestHandler methods  48 # (reimplemented) IRequestHandler methods 55 49  56 50 def match_request(self, req): 57  match = re.match(r'/changeset/([0-9]+) $', req.path_info) 51 match = re.match(r'/changeset/([0-9]+)(/.*)?$', req.path_info) 58 52 if match: 59 53 req.args['rev'] = match.group(1)  54 path = match.group(2)  55 if path:  56 req.args['path'] = path 60 57 return 1 61 58  62  def process_request(self, req):Â63  req.perm.assert_permission('CHANGESET_VIEW')Â64  Â65  rev = req.args.get('rev')Â66  repos = self.env.get_repository(req.authname)Â67  authzperm = SubversionAuthorizer(self.env, req.authname)Â68  authzperm.assert_permission_for_changeset(rev)Â69  Â70  diff_options = get_diff_options(req)Â71  if req.args.has_key('update'):Â72  req.redirect(self.env.href.changeset(rev))Â73  Â74  chgset = repos.get_changeset(rev)Â75  req.check_modified(chgset.date,Â76  diff_options[0] + ''.join(diff_options[1]))Â77  Â78  format = req.args.get('format')Â79  if format == 'diff':Â80  self._render_diff(req, repos, chgset, diff_options)Â81  returnÂ82  elif format == 'zip':Â83  self._render_zip(req, repos, chgset)Â84  returnÂ85  Â86  self._render_html(req, repos, chgset, diff_options)Â87  add_link(req, 'alternate', '?format=diff', 'Unified Diff',Â88  'text/plain', 'diff')Â89  add_link(req, 'alternate', '?format=zip', 'Zip Archive',Â90  'application/zip', 'zip')Â91  add_stylesheet(req, 'common/css/changeset.css')Â92  add_stylesheet(req, 'common/css/diff.css')Â93  add_stylesheet(req, 'common/css/code.css')Â94  return 'changeset.cs', NoneÂ95  Â96 59 # ITimelineEventProvider methods 97 60  98 61 def get_timeline_filters(self, req): … …  143 106 message 144 107 rev = repos.previous_rev(rev) 145 108  146  # Internal methodsÂ147  Â148  def _render_html(self, req, repos, chgset, diff_options):Â149  """HTML version"""Â150  req.hdf['title'] = '[%s]' % chgset.revÂ151  req.hdf['changeset'] = {Â152  'revision': chgset.rev,Â153  'time': util.format_datetime(chgset.date),Â154  'author': util.escape(chgset.author or 'anonymous'),Â155  'message': wiki_to_html(chgset.message or '--', self.env, req,Â156  escape_newlines=True)Â157  }Â158  Â159  oldest_rev = repos.oldest_revÂ160  if chgset.rev != oldest_rev:Â161  add_link(req, 'first', self.env.href.changeset(oldest_rev),Â162  'Changeset %s' % oldest_rev)Â163  previous_rev = repos.previous_rev(chgset.rev)Â164  add_link(req, 'prev', self.env.href.changeset(previous_rev),Â165  'Changeset %s' % previous_rev)Â166  youngest_rev = repos.youngest_revÂ167  if str(chgset.rev) != str(youngest_rev):Â168  next_rev = repos.next_rev(chgset.rev)Â169  add_link(req, 'next', self.env.href.changeset(next_rev),Â170  'Changeset %s' % next_rev)Â171  add_link(req, 'last', self.env.href.changeset(youngest_rev),Â172  'Changeset %s' % youngest_rev)Â173  Â174  edits = []Â175  idx = 0Â176  for path, kind, change, base_path, base_rev in chgset.get_changes():Â177  info = {'change': change}Â178  if base_path:Â179  info['path.old'] = base_pathÂ180  info['rev.old'] = base_revÂ181  info['browser_href.old'] = self.env.href.browser(base_path,Â182  rev=base_rev)Â183  if path:Â184  info['path.new'] = pathÂ185  info['rev.new'] = chgset.revÂ186  info['browser_href.new'] = self.env.href.browser(path,Â187  rev=chgset.rev)Â188  if change in (Changeset.COPY, Changeset.EDIT, Changeset.MOVE):Â189  edits.append((idx, path, kind, base_path, base_rev))Â190  req.hdf['changeset.changes.%d' % idx] = infoÂ191  idx += 1Â192  Â193  hidden_properties = [p.strip() for pÂ194  in self.config.get('browser', 'hide_properties',Â195  'svk:merge').split(',')]Â196  Â197  for idx, path, kind, base_path, base_rev in edits:Â198  old_node = repos.get_node(base_path or path, base_rev)Â199  new_node = repos.get_node(path, chgset.rev)Â200  Â201  # Property changesÂ202  old_props = old_node.get_properties()Â203  new_props = new_node.get_properties()Â204  changed_props = {}Â205  if old_props != new_props:Â206  for k,v in old_props.items():Â207  if not k in new_props:Â208  changed_props[k] = {'old': v}Â209  elif v != new_props[k]:Â210  changed_props[k] = {'old': v, 'new': new_props[k]}Â211  for k,v in new_props.items():Â212  if not k in old_props:Â213  changed_props[k] = {'new': v}Â214  for k in hidden_properties:Â215  if k in changed_props:Â216  del changed_props[k]Â217  req.hdf['changeset.changes.%d.props' % idx] = changed_propsÂ218  Â219  if kind == Node.DIRECTORY:Â220  continueÂ221  Â222  # Content changesÂ223  default_charset = self.config.get('trac', 'default_charset')Â224  old_content = old_node.get_content().read()Â225  if mimeview.is_binary(old_content):Â226  continueÂ227  charset = mimeview.get_charset(old_node.content_type) or \Â228  default_charsetÂ229  old_content = util.to_utf8(old_content, charset)Â230  Â231  new_content = new_node.get_content().read()Â232  if mimeview.is_binary(new_content):Â233  continueÂ234  charset = mimeview.get_charset(new_node.content_type) or \Â235  default_charsetÂ236  new_content = util.to_utf8(new_content, charset)Â237  Â238  if old_content != new_content:Â239  context = 3Â240  for option in diff_options[1]:Â241  if option.startswith('-U'):Â242  context = int(option[2:])Â243  breakÂ244  tabwidth = int(self.config.get('diff', 'tab_width',Â245  self.config.get('mimeviewer',Â246  'tab_width')))Â247  changes = hdf_diff(old_content.splitlines(),Â248  new_content.splitlines(),Â249  context, tabwidth,Â250  ignore_blank_lines='-B' in diff_options[1],Â251  ignore_case='-i' in diff_options[1],Â252  ignore_space_changes='-b' in diff_options[1])Â253  req.hdf['changeset.changes.%d.diff' % idx] = changesÂ254  Â255  def _render_diff(self, req, repos, chgset, diff_options):Â256  """Raw Unified Diff version"""Â257  req.send_response(200)Â258  req.send_header('Content-Type', 'text/plain;charset=utf-8')Â259  req.send_header('Content-Disposition',Â260  'filename=Changeset%s.diff' % req.args.get('rev'))Â261  req.end_headers()Â262  Â263  for path, kind, change, base_path, base_rev in chgset.get_changes():Â264  if change == Changeset.ADD:Â265  old_node = NoneÂ266  else:Â267  old_node = repos.get_node(base_path or path, base_rev)Â268  if change == Changeset.DELETE:Â269  new_node = NoneÂ270  else:Â271  new_node = repos.get_node(path, chgset.rev)Â272  Â273  # TODO: Property changesÂ274  Â275  # Content changesÂ276  if kind == 'dir':Â277  continueÂ278  Â279  default_charset = self.config.get('trac', 'default_charset')Â280  new_content = old_content = ''Â281  new_node_info = old_node_info = ('','')Â282  Â283  if old_node:Â284  charset = mimeview.get_charset(old_node.content_type) or \Â285  default_charsetÂ286  old_content = util.to_utf8(old_node.get_content().read(),Â287  charset)Â288  old_node_info = (old_node.path, old_node.rev)Â289  if mimeview.is_binary(old_content):Â290  continueÂ291  Â292  if new_node:Â293  charset = mimeview.get_charset(new_node.content_type) or \Â294  default_charsetÂ295  new_content = util.to_utf8(new_node.get_content().read(),Â296  charset)Â297  new_node_info = (new_node.path, new_node.rev)Â298  if mimeview.is_binary(new_content):Â299  continueÂ300  Â301  if old_content != new_content:Â302  context = 3Â303  for option in diff_options[1]:Â304  if option.startswith('-U'):Â305  context = int(option[2:])Â306  breakÂ307  req.write('Index: ' + path + util.CRLF)Â308  req.write('=' * 67 + util.CRLF)Â309  req.write('--- %s (revision %s)' % old_node_info +Â310  util.CRLF)Â311  req.write('+++ %s (revision %s)' % new_node_info +Â312  util.CRLF)Â313  for line in unified_diff(old_content.splitlines(),Â314  new_content.splitlines(), context,Â315  ignore_blank_lines='-B' in diff_options[1],Â316  ignore_case='-i' in diff_options[1],Â317  ignore_space_changes='-b' in diff_options[1]):Â318  req.write(line + util.CRLF)Â319  Â320  def _render_zip(self, req, repos, chgset):Â321  """ZIP archive with all the added and/or modified files."""Â322  req.send_response(200)Â323  req.send_header('Content-Type', 'application/zip')Â324  req.send_header('Content-Disposition',Â325  'filename=Changeset%s.zip' % chgset.rev)Â326  req.end_headers()Â327  Â328  try:Â329  from cStringIO import StringIOÂ330  except ImportError:Â331  from StringIO import StringIOÂ332  from zipfile import ZipFile, ZipInfo, ZIP_DEFLATEDÂ333  Â334  buf = StringIO()Â335  zipfile = ZipFile(buf, 'w', ZIP_DEFLATED)Â336  for path, kind, change, base_path, base_rev in chgset.get_changes():Â337  if kind == Node.FILE and change != Changeset.DELETE:Â338  node = repos.get_node(path, chgset.rev)Â339  zipinfo = ZipInfo()Â340  zipinfo.filename = node.pathÂ341  zipinfo.date_time = time.gmtime(node.last_modified)[:6]Â342  zipinfo.compress_type = ZIP_DEFLATEDÂ343  zipfile.writestr(zipinfo, node.get_content().read())Â344  zipfile.close()Â345  req.write(buf.getvalue())Â346 109  347 110 # IWikiSyntaxProvider methods 348 111  349 112 def get_wiki_syntax(self): 350  yield (r"!?\[\d+\]|(?:\b|!)r\d+\b(?!:\d)",  113 yield (r"!?\[(?P<it_changeset>%s\s*)?\d+(?:/[^\]]*)?\]|" \  114 % INTERTRAC_SCHEME + # [1], [T1] or [trac 1]  115 r"(?:\b|!)r\d+\b(?!:\d)", # r1 but not r1:2 351 116 lambda x, y, z: self._format_link(x, 'changeset', 352 117 y[0] == 'r' and y[1:] 353  or y[1:-1], y )) 118 or y[1:-1], y, z)) 354 119  355 120 def get_link_resolvers(self): 356 121 yield ('changeset', self._format_link) 357 122  358  def _format_link(self, formatter, ns, rev, label):  123 def _format_link(self, formatter, ns, chgset, label, fullmatch=None):  124 intertrac = formatter.shorthand_intertrac_helper(ns, chgset, label,  125 fullmatch)  126 if intertrac:  127 return intertrac  128 sep = chgset.find('/')  129 if sep > 0:  130 rev, path = chgset[:sep], chgset[sep:]  131 else:  132 rev, path = chgset, None 359 133 cursor = formatter.db.cursor() 360 134 cursor.execute('SELECT message FROM revision WHERE rev=%s', (rev,)) 361 135 row = cursor.fetchone() 362 136 if row: 363 137 return '<a class="changeset" title="%s" href="%s">%s</a>' \ 364 138 % (util.escape(util.shorten_line(row[0])), 365  formatter.href.changeset(rev ), label) 139 formatter.href.changeset(rev, path), label) 366 140 else: 367  return '<a class="missing changeset" href="%s" rel="nofollow">%s</a>' \ 368  % (formatter.href.changeset(rev), label)  141 return '<a class="missing changeset" href="%s"' \  142 ' rel="nofollow">%s</a>' \  143 % (formatter.href.changeset(rev, path), label) 369 144  370 145 # ISearchProvider methods 371 146  -
trac/versioncontrol/web_ui/diff.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/web_ui/diff.py intertrac-branch/trac/versioncontrol/web_ui/diff.py
old new   1 # -*- coding: iso8859-1 -*-  2 #  3 # Copyright (C) 2003-2005 Edgewall Software  4 # Copyright (C) 2003-2005 Jonas Borgström <jonas@edgewall.com>  5 # Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>  6 # All rights reserved.  7 #  8 # This software is licensed as described in the file COPYING, which  9 # you should have received as part of this distribution. The terms  10 # are also available at http://trac.edgewall.com/license.html.  11 #  12 # This software consists of voluntary contributions made by many  13 # individuals. For the exact contribution history, see the revision  14 # history and logs, available at http://projects.edgewall.com/trac/.  15 #  16 # Author: Jonas Borgström <jonas@edgewall.com>  17 # Christopher Lenz <cmlenz@gmx.de>  18 # Christian Boos <cboos@neuf.fr>  19   20 from __future__ import generators  21 import time  22 import re  23 import posixpath  24 from urllib import urlencode  25   26 from trac import mimeview, util  27 from trac.core import *  28 from trac.perm import IPermissionRequestor  29 from trac.versioncontrol import Changeset, Node  30 from trac.versioncontrol.diff import get_diff_options, hdf_diff, unified_diff  31 from trac.versioncontrol.svn_authz import SubversionAuthorizer  32 from trac.web import IRequestHandler  33 from trac.web.chrome import add_link, add_stylesheet  34 from trac.wiki import wiki_to_html, IWikiSyntaxProvider  35   36 class DiffArgs(dict):  37 def __getattr__(self,str):  38 return self[str]  39   40   41 class ChangesPermission(Component):  42 """Simple permission provider for changes related modules."""  43   44 implements(IPermissionRequestor)  45   46 def get_permission_actions(self):  47 return ['CHANGESET_VIEW']  48   49   50 class AbstractDiffModule(Component):  51 """Provide flexible functionality for showing sets of differences.  52   53 If the differences shown are coming from a specific changeset,  54 then that changeset informations can be shown too.  55   56 In addition, it is possible to show only a subset of the changeset:  57 Only the changes affecting a given path will be shown.  58 This is called the ''restricted'' changeset.  59   60 But the differences can also be computed in a more general way,  61 between two arbitrary paths and/or between two arbitrary revisions.  62 In that case, there's no changeset information displayed.  63 """  64   65 abstract = True  66   67 implements(IRequestHandler)  68   69 # IRequestHandler methods  70   71 def match_request(self, req):  72 raise NotImplementedError  73   74 def process_request(self, req):  75 """The appropriate mode of operation is inferred from  76 the request parameters:  77 * If `old` and `new` parameters are given, it will be an  78 arbitrary set of differences: `chgset` is False.  79 * If `old_path` is given and is different from `path`,  80 it's a generalized diff, from `old_path@old`  81 to `path@new`: `restricted` is False.  82 * Otherwise those are differences between two arbitrary revisions  83 of a given path: `restricted` is True.  84 * Otherwise, we are dealing with a changeset only: `chgset` is True.  85 * If the `path` is not empty or not the root, then only  86 the changes affecting that path (i.e. itself, children or  87 ancestors) will be considered: `restricted` is True.  88 * Otherwise, it's the full changeset: `restricted` is False.  89   90 In any case, the given path@rev pair must exist.  91 """  92 req.perm.assert_permission('CHANGESET_VIEW')  93   94 # -- retrieve arguments  95 path = req.args.get('path')  96 rev = req.args.get('rev')  97 old = req.args.get('old')  98 new = req.args.get('new')  99 old_path = req.args.get('old_path')  100   101 # -- normalize and check for special case  102 repos = self.env.get_repository(req.authname)  103 path = repos.normalize_path(path)  104 rev = repos.normalize_rev(rev)  105 if old_path: # Note: normalize_path now returns '/' if given 'None'  106 old_path = repos.normalize_path(old_path)  107   108 authzperm = SubversionAuthorizer(self.env, req.authname)  109 authzperm.assert_permission_for_changeset(rev)  110   111 if old_path == path and old and old == new: # revert to Changeset  112 rev = old  113 old_path = old = new = None  114   115 diff_options = get_diff_options(req)  116   117 # -- setup the `chgset` and `restricted` flags, see docstring above.  118 chgset = not old and not new and not old_path  119 if chgset:  120 restricted = path != '' and path != '/' # (subset or not)  121 else:  122 restricted = old_path == path # (same path or not)  123   124 # -- redirect if changing the diff options  125 if req.args.has_key('update'):  126 if chgset:  127 if restricted:  128 req.redirect(self.env.href.diff(path, rev=rev))  129 else:  130 req.redirect(self.env.href.changeset(rev))  131 else:  132 req.redirect(self.env.href.diff(path, new=new,  133 old_path=old_path, old=old))  134   135 # -- preparing the diff arguments  136 if chgset:  137 prev = repos.get_node(path, rev).get_previous()  138 if prev:  139 prev_path, prev_rev = prev[:2]  140 else:  141 prev_path, prev_rev = path, repos.previous_rev(rev)  142 diff_args = DiffArgs(old_path=prev_path, old_rev=prev_rev,  143 new_path=path, new_rev=rev)  144 else:  145 if not new:  146 new = repos.youngest_rev  147 elif not old:  148 old = repos.youngest_rev  149 if not old_path:  150 old_path = path  151 diff_args = DiffArgs(old_path=old_path, old_rev=old,  152 new_path=path, new_rev=new)  153 if chgset:  154 chgset = repos.get_changeset(rev)  155 req.check_modified(chgset.date,  156 diff_options[0] + ''.join(diff_options[1]))  157 else:  158 pass # FIXME: what date should we choose for a diff?  159   160 req.hdf['diff'] = diff_args  161   162 format = req.args.get('format')  163   164 if format in ['diff', 'zip']:  165 # choosing an appropriate filename  166 rpath = path.replace('/','_')  167 if chgset:  168 if restricted:  169 filename = 'changeset_%s_r%s' % (rpath, rev)  170 else:  171 filename = 'changeset_r%s' % rev  172 else:  173 if restricted:  174 filename = 'diff-%s-from-r%s-to-r%s' \  175 % (rpath, old, new)  176 elif old_path == '/': # special case for download (#238)  177 filename = '%s-r%s' % (rpath, old)  178 else:  179 filename = 'diff-from-%s-r%s-to-%s-r%s' \  180 % (old_path.replace('/','_'), old, rpath, new)  181 if format == 'diff':  182 self._render_diff(req, filename, repos, diff_args,  183 diff_options)  184 return  185 elif format == 'zip':  186 self._render_zip(req, filename, repos, diff_args)  187 return  188   189 # -- HTML format  190 self._render_html(req, repos, chgset, restricted,  191 diff_args, diff_options)  192 if chgset:  193 diff_params = 'rev=%s' % rev  194 else:  195 diff_params = urlencode({'path': path,  196 'new': new,  197 'old_path': old_path,  198 'old': old})  199 add_link(req, 'alternate', '?format=diff&'+diff_params, 'Unified Diff',  200 'text/plain', 'diff')  201 add_link(req, 'alternate', '?format=zip&'+diff_params, 'Zip Archive',  202 'application/zip', 'zip')  203 add_stylesheet(req, 'common/css/changeset.css')  204 add_stylesheet(req, 'common/css/diff.css')  205 add_stylesheet(req, 'common/css/code.css')  206 return 'diff.cs', None  207   208   209 # Internal methods  210   211 def _render_html(self, req, repos, chgset, restricted, diff, diff_options):  212 """  213 HTML version  214 """  215 req.hdf['diff'] = {  216 'chgset': chgset and True,  217 'restricted': restricted,  218 'href': { 'new_rev': self.env.href.changeset(diff.new_rev),  219 'old_rev': self.env.href.changeset(diff.old_rev),  220 'new_path': self.env.href.browser(diff.new_path,  221 rev=diff.new_rev),  222 'old_path': self.env.href.browser(diff.old_path,  223 rev=diff.old_rev)  224 }  225 }  226   227 if chgset: # Changeset Mode (possibly restricted on a path)  228 path, rev = diff.new_path, diff.new_rev  229   230 # -- getting the deltas from the Changeset.get_changes method  231 def get_deltas():  232 old_node = new_node = None  233 for npath, kind, change, opath, orev in chgset.get_changes():  234 if restricted and \  235 not (npath.startswith(path) # npath is below  236 or path.startswith(npath)): # npath is above  237 continue  238 if change != Changeset.ADD:  239 old_node = repos.get_node(opath, orev)  240 if change != Changeset.DELETE:  241 new_node = repos.get_node(npath, rev)  242 yield old_node, new_node, kind, change  243   244 def _changeset_title(rev):  245 if restricted:  246 return 'Changeset %s for %s' % (rev, path)  247 else:  248 return 'Changeset %s' % rev  249   250 title = _changeset_title(rev)  251 req.hdf['changeset'] = {  252 'revision': chgset.rev,  253 'time': util.format_datetime(chgset.date),  254 'author': util.escape(chgset.author or 'anonymous'),  255 'message': wiki_to_html(chgset.message or '--', self.env, req,  256 escape_newlines=True)  257 }  258 oldest_rev = repos.oldest_rev  259 if chgset.rev != oldest_rev:  260 if restricted:  261 prev = repos.get_node(path, rev).get_previous()  262 if prev:  263 prev_path, prev_rev = prev[:2]  264 prev_href = self.env.href.changeset(prev_rev, prev_path)  265 else:  266 prev_path = prev_rev = None  267 else:  268 prev_path = diff.old_path  269 prev_rev = repos.previous_rev(chgset.rev)  270 add_link(req, 'first', self.env.href.changeset(oldest_rev),  271 'Changeset %s' % oldest_rev)  272 prev_href = self.env.href.changeset(prev_rev)  273 if prev_rev:  274 add_link(req, 'prev', prev_href, _changeset_title(prev_rev))  275 youngest_rev = repos.youngest_rev  276 if str(chgset.rev) != str(youngest_rev):  277 if restricted:  278 next_rev = next_href = None  279 # FIXME: find an effective way to find the next rev  280 else:  281 next_rev = repos.next_rev(chgset.rev)  282 next_href = self.env.href.changeset(next_rev)  283 add_link(req, 'last',  284 self.env.href.diff(path, rev=youngest_rev),  285 'Changeset %s' % youngest_rev)  286 if next_rev:  287 add_link(req, 'next', next_href, _changeset_title(next_rev))  288   289 else: # Diff Mode  290 # -- getting the deltas from the Repository.get_deltas method  291 def get_deltas():  292 for d in repos.get_deltas(**diff):  293 yield d  294   295 reverse_href = self.env.href.diff(diff.old_path,  296 new=diff.old_rev,  297 old_path=diff.new_path,  298 old=diff.new_rev)  299 req.hdf['diff.reverse_href'] = reverse_href  300 title = self.title_for_diff(diff)  301 req.hdf['title'] = title  302   303 def _change_info(old_node, new_node, change):  304 info = {'change': change}  305 if old_node:  306 info['path.old'] = old_node.path  307 info['rev.old'] = old_node.rev # this is the created rev.  308 old_href = self.env.href.browser(old_node.path,  309 rev=diff.old_rev)  310 # Reminder: old_node.path may not exist at old_node.rev  311 info['browser_href.old'] = old_href  312 if new_node:  313 info['path.new'] = new_node.path  314 info['rev.new'] = new_node.rev # created rev.  315 new_href = self.env.href.browser(new_node.path,  316 rev=diff.new_rev)  317 # (same remark as above)  318 info['browser_href.new'] = new_href  319 return info  320   321 hidden_properties = [p.strip() for p  322 in self.config.get('browser', 'hide_properties',  323 'svk:merge').split(',')]  324   325 def _prop_changes(old_node, new_node):  326 old_props = old_node.get_properties()  327 new_props = new_node.get_properties()  328 changed_props = {}  329 if old_props != new_props:  330 for k,v in old_props.items():  331 if not k in new_props:  332 changed_props[k] = {'old': v}  333 elif v != new_props[k]:  334 changed_props[k] = {'old': v, 'new': new_props[k]}  335 for k,v in new_props.items():  336 if not k in old_props:  337 changed_props[k] = {'new': v}  338 for k in hidden_properties:  339 if k in changed_props:  340 del changed_props[k]  341 return changed_props  342   343 def _content_changes(old_node, new_node):  344 """  345 Returns the list of differences.  346 The list is empty when no differences between comparable files  347 are detected, but the return value is None for non-comparable files.  348 """  349 default_charset = self.config.get('trac', 'default_charset')  350 old_content = old_node.get_content().read()   351 if mimeview.is_binary(old_content):  352 return None  353 charset = mimeview.get_charset(old_node.content_type) or \  354 default_charset  355 old_content = util.to_utf8(old_content, charset)  356   357 new_content = new_node.get_content().read()  358 if mimeview.is_binary(new_content):  359 return None  360 charset = mimeview.get_charset(new_node.content_type) or \  361 default_charset  362 new_content = util.to_utf8(new_content, charset)  363   364 if old_content != new_content:  365 context = 3  366 options = diff_options[1]  367 for option in options:  368 if option.startswith('-U'):  369 context = int(option[2:])  370 break  371 tabwidth = int(self.config.get('diff', 'tab_width',  372 self.config.get('mimeviewer',  373 'tab_width')))  374 return hdf_diff(old_content.splitlines(),  375 new_content.splitlines(),  376 context, tabwidth,  377 ignore_blank_lines='-B' in options,  378 ignore_case='-i' in options,  379 ignore_space_changes='-b' in options)  380 else:  381 return []  382   383 idx = 0  384 for old_node, new_node, kind, change in get_deltas():  385 if change != Changeset.EDIT:  386 show_entry = True  387 else:  388 show_entry = False  389 assert old_node and new_node  390 props = _prop_changes(old_node, new_node)  391 if props:  392 req.hdf['diff.changes.%d.props' % idx] = props  393 show_entry = True  394 if kind == Node.FILE:  395 diffs = _content_changes(old_node, new_node)  396 if diffs != []:  397 if diffs:  398 req.hdf['diff.changes.%d.diff' % idx] = diffs  399 # elif None (means: manually compare to (previous))  400 show_entry = True  401 if show_entry:  402 info = _change_info(old_node, new_node, change)  403 req.hdf['diff.changes.%d' % idx] = info  404 idx += 1 # the sequence should be immutable  405   406 def _render_diff(self, req, filename, repos, diff, diff_options):  407 """Raw Unified Diff version"""  408 req.send_response(200)  409 req.send_header('Content-Type', 'text/plain;charset=utf-8')  410 req.send_header('Content-Disposition',  411 'filename=%s.diff' % filename)  412 req.end_headers()  413   414 for old_node, new_node, kind, change in repos.get_deltas(**diff):  415 # TODO: Property changes  416   417 # Content changes  418 if kind == Node.DIRECTORY:  419 continue  420   421 default_charset = self.config.get('trac', 'default_charset')  422 new_content = old_content = ''  423 new_node_info = old_node_info = ('','')  424   425 if old_node:  426 charset = mimeview.get_charset(old_node.content_type) or \  427 default_charset  428 old_content = util.to_utf8(old_node.get_content().read(),  429 charset)  430 old_node_info = (old_node.path, old_node.rev)  431 if mimeview.is_binary(old_content):  432 continue  433   434 if new_node:  435 charset = mimeview.get_charset(new_node.content_type) or \  436 default_charset  437 new_content = util.to_utf8(new_node.get_content().read(),  438 charset)  439 new_node_info = (new_node.path, new_node.rev)  440 if mimeview.is_binary(new_content):  441 continue  442 new_path = new_node.path  443 else:  444 old_node_path = repos.normalize_path(old_node.path)  445 diff_old_path = repos.normalize_path(diff.old_path)  446 new_path = posixpath.join(diff.new_path,  447 old_node_path[len(diff_old_path)+1:])  448   449 if old_content != new_content:  450 context = 3  451 options = diff_options[1]  452 for option in options:  453 if option.startswith('-U'):  454 context = int(option[2:])  455 break  456 if not old_node_info[0]:  457 old_node_info = new_node_info # support for 'A'dd changes  458 req.write('Index: ' + new_path + util.CRLF)  459 req.write('=' * 67 + util.CRLF)  460 req.write('--- %s (revision %s)' % old_node_info +  461 util.CRLF)  462 req.write('+++ %s (revision %s)' % new_node_info +  463 util.CRLF)  464 for line in unified_diff(old_content.splitlines(),  465 new_content.splitlines(), context,  466 ignore_blank_lines='-B' in options,  467 ignore_case='-i' in options,  468 ignore_space_changes='-b' in options):  469 req.write(line + util.CRLF)  470   471 def _render_zip(self, req, filename, repos, diff):  472 """ZIP archive with all the added and/or modified files."""  473 new_rev = diff.new_rev  474 req.send_response(200)  475 req.send_header('Content-Type', 'application/zip')  476 req.send_header('Content-Disposition',  477 'filename=%s.zip' % filename)  478   479 try:  480 from cStringIO import StringIO  481 except ImportError:  482 from StringIO import StringIO  483 from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED  484   485 buf = StringIO()  486 zipfile = ZipFile(buf, 'w', ZIP_DEFLATED)  487 for old_node, new_node, kind, change in repos.get_deltas(**diff):  488 if kind == Node.FILE and change != Changeset.DELETE:  489 assert new_node  490 zipinfo = ZipInfo()  491 zipinfo.filename = new_node.path  492 zipinfo.date_time = time.gmtime(new_node.last_modified)[:6]  493 zipinfo.compress_type = ZIP_DEFLATED  494 zipfile.writestr(zipinfo, new_node.get_content().read())  495 zipfile.close()  496   497 buf.seek(0, 2) # be sure to be at the end  498 req.send_header("Content-Length", buf.tell())  499 req.end_headers()  500   501 req.write(buf.getvalue())  502   503 def title_for_diff(self, diff):  504 if diff.new_path == diff.old_path: # ''diff between 2 revisions'' mode  505 return 'Diff r%s:%s for %s' \  506 % (diff.old_rev or 'latest', diff.new_rev or 'latest',  507 diff.new_path or '/')  508 else: # ''arbitrary diff'' mode  509 return 'Diff from %s@%s to %s@%s' \  510 % (diff.old_path or '/', diff.old_rev or 'latest',  511 diff.new_path or '/', diff.new_rev or 'latest')  512   513   514   515 class DiffModule(AbstractDiffModule):  516   517 implements(IWikiSyntaxProvider)  518   519 # (reimplemented) IRequestHandler methods  520   521 def match_request(self, req):  522 match = re.match(r'/diff(?:(/.*)|$)', req.path_info)  523 if match:  524 if match.group(1):  525 req.args['path'] = match.group(1)  526 return 1  527   528 # IWikiSyntaxProvider methods  529   530 def get_wiki_syntax(self):  531 return []  532   533 def get_link_resolvers(self):  534 yield ('diff', self._format_link)  535   536 def _format_link(self, formatter, ns, params, label):  537 def pathrev(path):  538 if '@' in path:  539 return path.split('@', 1)  540 else:  541 return (path, None)  542 if '//' in params:  543 p1, p2 = params.split('//', 1)  544 old, new = pathrev(p1), pathrev(p2)  545 diff = DiffArgs(old_path=old[0], old_rev=old[1],  546 new_path=new[0], new_rev=new[1])  547 else:   548 old_path, old_rev = pathrev(params)  549 new_rev = None  550 if old_rev and ':' in old_rev:  551 old_rev, new_rev = old_rev.split(':', 1)  552 diff = DiffArgs(old_path=old_path, old_rev=old_rev,  553 new_path=old_path, new_rev=new_rev)  554 title = self.title_for_diff(diff)  555 href = formatter.href.diff(diff.new_path, new=diff.new_rev,  556 old_path=diff.old_path, old=diff.old_rev)  557 return '<a class="changeset" title="%s" href="%s">%s</a>' \  558 % (title, href, label)  559   560   561 class AnyDiffModule(Component):  562   563 implements(IRequestHandler)  564   565 # IRequestHandler methods  566   567 def match_request(self, req):  568 return re.match(r'/anydiff$', req.path_info)  569   570 def process_request(self, req):  571 # -- retrieve arguments  572 new_path = req.args.get('new_path')  573 new_rev = req.args.get('new_rev')  574 old_path = req.args.get('old_path')  575 old_rev = req.args.get('old_rev')  576   577 # -- normalize   578 repos = self.env.get_repository(req.authname)  579 new_path = repos.normalize_path(new_path)  580 new_rev = repos.normalize_rev(new_rev)  581 old_path = repos.normalize_path(old_path)  582 old_rev = repos.normalize_rev(old_rev)  583   584 authzperm = SubversionAuthorizer(self.env, req.authname)  585 authzperm.assert_permission_for_changeset(new_rev)  586 authzperm.assert_permission_for_changeset(old_rev)  587   588 # -- prepare rendering  589 req.hdf['anydiff'] = {  590 'new_path': new_path,  591 'new_rev': new_rev,  592 'old_path': old_path,  593 'old_rev': old_rev,  594 'diff_href': self.env.href.diff(),  595 }  596   597 return 'anydiff.cs', None -
trac/versioncontrol/web_ui/__init__.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/web_ui/__init__.py intertrac-branch/trac/versioncontrol/web_ui/__init__.py
old new  1 1 from trac.versioncontrol.web_ui.browser import * 2 2 from trac.versioncontrol.web_ui.changeset import * 3 3 from trac.versioncontrol.web_ui.log import *  4 from trac.versioncontrol.web_ui.diff import * -
trac/versioncontrol/web_ui/log.py
diff -ruN -x .svn trac-0.9b2/trac/versioncontrol/web_ui/log.py intertrac-branch/trac/versioncontrol/web_ui/log.py
old new  67 67 stop_rev = req.args.get('stop_rev') 68 68 verbose = req.args.get('verbose') 69 69 limit = LOG_LIMIT  70 old = req.args.get('old')  71 new = req.args.get('new')  72   73 repos = self.env.get_repository(req.authname)  74 normpath = repos.normalize_path(path)  75 rev = str(repos.normalize_rev(rev))  76   77 if old and new:  78 osep = util.unescape(old).rindex('#')  79 nsep = util.unescape(new).rindex('#')  80 old_path, old_rev = old[:osep], old[osep+1:]  81 new_path, new_rev = new[:nsep], new[nsep+1:]  82 req.redirect(self.env.href.diff(new_path, new=new_rev,  83 old_path=old_path, old=old_rev)) 70 84  71 85 req.hdf['title'] = path + ' (log)' 72 86 req.hdf['log'] = { … …  83 97 if path_links: 84 98 add_link(req, 'up', path_links[-1]['href'], 'Parent directory') 85 99  86  repos = self.env.get_repository(req.authname)Â87  normpath = repos.normalize_path(path)Â88  rev = str(repos.normalize_rev(rev))Â89 100  90 101 # ''Node'' history uses `get_node()`, 91 102 # ''Path'' history uses `get_path_history()` -
trac/web/standalone.py
diff -ruN -x .svn trac-0.9b2/trac/web/standalone.py intertrac-branch/trac/web/standalone.py
old new  139 139 self.auths = auths 140 140  141 141 self.projects = {}  142 siblings = {} 142 143 for env_path in env_paths: 143 144 # Remove trailing slashes 144 145 while env_path and not os.path.split(env_path)[1]: 145 146 env_path = os.path.split(env_path)[0] 146 147 project = os.path.split(env_path)[1] 147 148 self.projects[project] = env_path  149 env = get_environment(None, self.get_env_opts(project))  150 siblings[project] = env  151 for p in siblings.values():  152 p.siblings = siblings 148 153  149 154 def get_env_opts(self, project=None): 150 155 if self.env_parent_dir: 151 156 opts = self.env_parent_dir.items() 152 157 else: 153 158 opts = [('TRAC_ENV', self.projects[project])] 154  return dict(o pts + os.environ.items()) 159 return dict(os.environ.items() + opts) # TODO: backport 155 160  156 161 def send_project_index(self, req): 157 162 if self.env_parent_dir: -
trac/wiki/api.py
diff -ruN -x .svn trac-0.9b2/trac/wiki/api.py intertrac-branch/trac/wiki/api.py
old new  23 23 import dummy_threading as threading 24 24 import time 25 25 import urllib  26 import re 26 27  27 28 from trac.core import * 28 29 from trac.util import to_utf8, TRUE … …  65 66 def get_link_resolvers(): 66 67 """Return an iterable over (namespace, formatter) tuples.""" 67 68   69 class IWikiPageNameSyntaxProvider(Interface):  70   71 def get_wiki_page_names_syntax():  72 """  73 Return an iterable that provides a regular expression for  74 matching wiki page names (see WikiPageNames)  75   76 Be careful to only allow __one__ implementation  77 (others should be listed in the ![disabled_components]  78 section of the TracIni)  79 """  80  68 81  69 82 class WikiSystem(Component): 70 83 """Represents the wiki system.""" … …  74 87 change_listeners = ExtensionPoint(IWikiChangeListener) 75 88 macro_providers = ExtensionPoint(IWikiMacroProvider) 76 89 syntax_providers = ExtensionPoint(IWikiSyntaxProvider)  90 wikipagenames_providers = ExtensionPoint(IWikiPageNameSyntaxProvider) 77 91  78 92 INDEX_UPDATE_INTERVAL = 5 # seconds 79 93  … …  81 95 self._index = None 82 96 self._last_index_update = 0 83 97 self._index_lock = threading.RLock()  98 self._compiled_rules = None  99 self._link_resolvers = None  100 self._helper_patterns = None  101 self._external_handlers = None 84 102  85 103 def _update_index(self): 86 104 self._index_lock.acquire() … …  116 134 self._update_index() 117 135 return self._index.has_key(pagename) 118 136   137 def _get_rules(self):  138 self._prepare_rules()  139 return self._compiled_rules  140 rules = property(_get_rules)  141   142 def _get_helper_patterns(self):  143 self._prepare_rules()  144 return self._helper_patterns  145 helper_patterns = property(_get_helper_patterns)  146   147 def _get_external_handlers(self):  148 self._prepare_rules()  149 return self._external_handlers  150 external_handlers = property(_get_external_handlers)  151   152 def _prepare_rules(self):  153 from trac.wiki.formatter import Formatter  154 if not self._compiled_rules:  155 helpers = []  156 handlers = {}  157 syntax = Formatter._pre_rules[:]  158 i = 0  159 for resolver in self.syntax_providers:  160 for regexp, handler in resolver.get_wiki_syntax():  161 handlers['i'+str(i)] = handler  162 syntax.append('(?P<i%d>%s)' % (i, regexp))  163 i += 1  164 syntax += Formatter._post_rules[:]  165 helper_re = re.compile(r'\?P<([a-z\d_]+)>')  166 for rule in syntax:  167 helpers += helper_re.findall(rule)[1:]  168 rules = re.compile('(?:' + '|'.join(syntax) + ')')  169 self._external_handlers = handlers  170 self._helper_patterns = helpers  171 self._compiled_rules = rules  172   173 def _get_link_resolvers(self):  174 if not self._link_resolvers:  175 resolvers = {}  176 for resolver in self.syntax_providers:  177 for namespace, handler in resolver.get_link_resolvers():  178 resolvers[namespace] = handler  179 self._link_resolvers = resolvers  180 return self._link_resolvers  181 link_resolvers = property(_get_link_resolvers)  182  119 183 # IWikiChangeListener methods 120 184  121 185 def wiki_page_added(self, page): … …  136 200 def get_wiki_syntax(self): 137 201 ignore_missing = self.config.get('wiki', 'ignore_missing_pages') 138 202 ignore_missing = ignore_missing in TRUE 139  yield (r"!?(?<!/)\b[A-Z][a-z]+(?:[A-Z][a-z]*[a-z/])+" 140  "(?:#[A-Za-z0-9]+)?(?=\Z|\s|[.,;:!?\)}\]])", 141  lambda x, y, z: self._format_link(x, 'wiki', y, y, 142  ignore_missing))  203 providers = []  204 for p in self.wikipagenames_providers:  205 if not providers:  206 yield (p.get_wiki_page_names_syntax(),  207 lambda x, y, z: self._format_link(x, 'wiki', y, y,  208 ignore_missing))  209 pc = p.__class__  210 providers.append('# %s\n%s.%s = yes' % (pc.__doc__.split('\n')[0],  211 pc.__module__, pc.__name__)  212 )  213 if len(providers) > 1:  214 self.log.warning('More than one IWikiPageNameSyntaxProvider '  215 'implementation available:\n'  216 'You should set one of the following to "no" '  217 'in your trac.ini:\n\n'  218 '[disabled_components]\n' +  219 '\n'.join(providers) +'\n') 143 220  144 221 def get_link_resolvers(self): 145 222 yield ('wiki', self._format_fancy_link) … …  163 240 else: 164 241 return '<a class="wiki" href="%s">%s</a>' \ 165 242 % (formatter.href.wiki(page) + anchor, label)  243   244   245 WIKI_START = r"!?(?<!/)\b"  246 WIKI_TARGET = r"(?:#[A-Za-z0-9]+)?"  247 WIKI_END = r"(?=\Z|\s|[.,;:!?\)}\]])"  248 WIKI_INTERWIKI = r"(?!:\S)"  249   250 class StandardWikiPageNames(Component):  251 """Standard Trac WikiPageNames rule"""  252   253 implements(IWikiPageNameSyntaxProvider)  254   255 def get_wiki_page_names_syntax(self):  256 return (WIKI_START + # where to start  257 r"[A-Z][a-z]+" # initial WikiPageNames word  258 r"(?:[A-Z][a-z]*[a-z/])+" + # additional WikiPageNames word  259 WIKI_TARGET + # optional trailing section link  260 WIKI_END + # where to end  261 WIKI_INTERWIKI) # InterWiki support  262   263 class FlexibleWikiPageNames(Component):  264 """Standard Trac WikiPageNames rule, plus digits  265 and consecutive upper-case characters allowed.  266   267 More precisely, WikiPageNames are:  268 * either 2 or more starting upper case letter or digits,  269 followed by lower case letters  270 * either 1 or more starting upper case letter or digits,  271 followed by lower case letters, repeated at least 2 times  272 (with optionally '/' between repetitions)  273 """  274   275 implements(IWikiPageNameSyntaxProvider)  276   277 def get_wiki_page_names_syntax(self):  278 return (WIKI_START +  279 r"(?:[A-Z\d]{2,}[a-z]+" # 1st way  280 r"|[A-Z\d]+[a-z]+(?:/?[A-Z\d]+[a-z]*)+)" + # 2nd way  281 WIKI_TARGET + WIKI_END + WIKI_INTERWIKI)  282   283 class SubWikiPageNames(Component):  284 """SubWiki-like rules for WikiPageNames.  285   286 See http://www.webdav.org/wiki/projects/TextFormattingRules  287   288 Note that '/' in this style of WikiPageNames are not supported.  289 """  290   291 implements(IWikiPageNameSyntaxProvider)  292   293 def get_wiki_page_names_syntax(self):  294 return (WIKI_START +  295 r"(?:[A-Z][A-Z]+[a-z\d]+[A-Z]*" # 1st and 3rd way  296 r"|[A-Z][a-z]+(?:[A-Z][a-z]+)+)" + # 2nd way  297 WIKI_TARGET + WIKI_END + WIKI_INTERWIKI)  298  -
trac/wiki/formatter.py
diff -ruN -x .svn trac-0.9b2/trac/wiki/formatter.py intertrac-branch/trac/wiki/formatter.py
old new  19 19 from __future__ import generators 20 20 import re 21 21 import os 22  import stringÂ23 22 import urllib 24 23  25 24 try: … …  28 27 from StringIO import StringIO 29 28  30 29 from trac import util  30 from trac.core import * 31 31 from trac.mimeview import * 32  from trac.wiki.api import WikiSystem  32 from trac.wiki.api import WikiSystem, IWikiChangeListener, IWikiMacroProvider 33 33  34  __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline']  34 __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline',  35 'INTERTRAC_SCHEME' ] 35 36  36 37 # 37 38 # Customization of the Wiki syntax ***use with care*** … …  45 46 SUPERSCRIPT_TOKEN = r"\^" 46 47 INLINE_TOKEN = "`" 47 48  48  LINK_SCHEME = r"[\w.+-]+" # as per RFC 2396  49 LINK_SCHEME = r"[\w.+-]+?" # as per RFC 2396  50 INTERTRAC_SCHEME = r"[a-zA-Z.+-]+?" # no digits (support for shorthand links) 49 51  50 52 def system_message(msg, text): 51 53 return """<div class="system-message"> … …  136 138 class Formatter(object): 137 139 flavor = 'default' 138 140  139  _link_resolvers = NoneÂ140 141 # Rules provided by IWikiSyntaxProviders are inserted between pre_rules and post_rules 141 142 _pre_rules = [r"(?P<bolditalic>%s)" % BOLDITALIC_TOKEN, 142 143 r"(?P<bold>%s)" % BOLD_TOKEN, … …  165 166 r"(?P<last_table_cell>\|\|\s*$)", 166 167 r"(?P<table_cell>\|\|)"] 167 168  168  _compiled_rules = NoneÂ169  _helper_patterns = NoneÂ170  _external_handlers = NoneÂ171 169 _processor_re = re.compile('#\!([\w+-][\w+-/]*)') 172 170 _anchor_re = re.compile('[^\w\d\.-:]+', re.UNICODE) 173 171  … …  194 192 db = property(fget=_get_db) 195 193  196 194 def _get_rules(self): 197  if not Formatter._compiled_rules: 198  helpers = [] 199  handlers = {} 200  syntax = Formatter._pre_rules[:] 201  wiki = WikiSystem(self.env) 202  i = 0 203  for resolver in wiki.syntax_providers: 204  for regexp, handler in resolver.get_wiki_syntax(): 205  handlers['i'+str(i)] = handler 206  syntax.append('(?P<i%d>%s)' % (i, regexp)) 207  i += 1 208  syntax += Formatter._post_rules[:] 209  helper_re = re.compile(r'\?P<([a-z\d]+)>') 210  for rule in syntax: 211  helpers += helper_re.findall(rule)[1:] 212  rules = re.compile('(?:' + string.join(syntax, '|') + ')') 213  Formatter._external_handlers = handlers 214  Formatter._helper_patterns = helpers 215  Formatter._compiled_rules = rules 216  return Formatter._compiled_rules  195 return WikiSystem(self.env).rules 217 196 rules = property(_get_rules) 218 197  219 198 def _get_link_resolvers(self): 220  if not self._link_resolvers: 221  resolvers = {} 222  wiki = WikiSystem(self.env) 223  for resolver in wiki.syntax_providers: 224  for namespace, handler in resolver.get_link_resolvers(): 225  resolvers[namespace] = handler 226  self._link_resolvers = resolvers 227  return self._link_resolvers  199 return WikiSystem(self.env).link_resolvers 228 200 link_resolvers = property(_get_link_resolvers) 229 201  230 202 def replace(self, fullmatch):  203 wiki = WikiSystem(self.env)  231 204 for itype, match in fullmatch.groupdict().items(): 232  if match and not itype in Formatter._helper_patterns: 205 if match and not itype in wiki.helper_patterns: 233 206 # Check for preceding escape character '!' 234 207 if match[0] == '!': 235 208 return match[1:] 236  if itype in self._external_handlers:Â237  return self._external_handlers[itype](self, match, fullmatch) 209 if itype in wiki.external_handlers:  210 return wiki.external_handlers[itype](self, match, fullmatch) 238 211 else: 239 212 return getattr(self, '_' + itype + '_formatter')(match, fullmatch) 240 213  … …  307 280 return self._make_link(ns, target, match, label) 308 281  309 282 def _make_link(self, ns, target, match, label):  283 # check first for an alias defined in trac.ini  284 ns = self.env.config.get('intertrac', ns.upper(), ns) 310 285 if ns in self.link_resolvers: 311  return self. _link_resolvers[ns](self, ns, target, label) 286 return self.link_resolvers[ns](self, ns, target, label) 312 287 elif target.startswith('//') or ns == "mailto": 313 288 return self._make_ext_link(ns+':'+target, label) 314 289 else: 315  return match  290 intertrac = self._make_intertrac_link(ns, target, label)  291 if intertrac:  292 return intertrac  293 else:  294 interwiki = self._make_interwiki_link(ns, target, label)  295 if interwiki:  296 return interwiki  297 else:  298 return match  299   300 def _make_intertrac_link(self, ns, target, label):  301 if self.env.siblings.has_key(ns):  302 sibling = self.env.siblings[ns]  303 if not hasattr(sibling, 'href'):  304 from trac.web.href import Href  305 def xchg_base(base):  306 return '/'.join(base.split('/')[:-1] + [ns])  307 sibling.href = Href(xchg_base(self.env.href.base))  308 sibling.abs_href = Href(xchg_base(self.env.abs_href.base))  309 ref = wiki_to_oneliner(target, sibling)  310 return ref.replace('>%s' % target, '>%s' % label)  311 url = self.env.config.get('intertrac', ns.upper()+'.url')  312 if url:  313 name = self.env.config.get('intertrac', ns.upper()+'.title',  314 'Trac project %s' % ns)  315 sep = target.find(':')  316 if sep != -1:  317 url = '%s/%s/%s' % (url, target[:sep], target[sep+1:])  318 else:   319 url = '%s/search?q=%s' % (url, urllib.quote_plus(target))  320 return self._make_ext_link(url, label, '%s in %s' % (target, name))  321 else:  322 return None  323   324 def shorthand_intertrac_helper(self, ns, target, label, fullmatch):  325 if fullmatch: # short form  326 it_grp = fullmatch.group('it_%s' % ns)  327 if it_grp:  328 alias = it_grp.strip()  329 intertrac = self.env.config.get('intertrac', alias.upper(),  330 alias)  331 target = '%s:%s' % (ns, target[len(it_grp):])  332 it = self._make_intertrac_link(intertrac, target, label)  333 return it or label  334 return None  335   336 def _make_interwiki_link(self, ns, target, label):  337 interwiki = InterWikiMap(self.env)  338 if interwiki.has_key(ns):  339 url, title = interwiki.url(ns, target)  340 return self._make_ext_link(url, label, '%s in %s' % (target, title))  341 else:  342 return None 316 343  317 344 def _make_ext_link(self, url, text, title=''): 318 345 title_attr = title and ' title="%s"' % title or '' … …  342 369 if match[0] == '!': 343 370 return match[1:] 344 371 else: 345  return self.simple_tag_handler('<span class="underline">', '</span>')  372 return self.simple_tag_handler('<span class="underline">',  373 '</span>') 346 374  347 375 def _strike_formatter(self, match, fullmatch): 348 376 if match[0] == '!': … …  730 758 OutlineFormatter(env, absurls, db).format(wikitext, out, max_depth, 731 759 min_depth) 732 760 return out.getvalue()  761   762   763 # -- InterWiki support  764   765 class InterWikiMap(Component):  766   767 implements(IWikiChangeListener, IWikiMacroProvider)  768   769 _page_name = 'InterMapTxt'  770 _interwiki_re = re.compile(r"(\w+)[ \t]+([^ \t]+)(?:[ \t]+#(.*))?",  771 re.UNICODE)  772 _argspec_re = re.compile(r"\$\d")  773   774 def __init__(self):  775 self._interwiki_map = None  776 # This dictionary maps upper-cased namespaces  777 # to (namespace, prefix, title) values  778   779 def has_key(self, ns):  780 if not self._interwiki_map:  781 self._update()  782 return self._interwiki_map.has_key(ns.upper())  783   784 def url(self, ns, target):  785 ns, url, title = self._interwiki_map[ns.upper()]  786 args = target.split(':')  787 def setarg(match):  788 num = int(match.group()[1:])  789 return 0 < num <= len(args) and args[num-1] or ''  790 url_with_args = re.sub(InterWikiMap._argspec_re, setarg, url)  791 if url_with_args == url:   792 return url + target, title  793 else:  794 return url_with_args, title  795   796 # IWikiChangeListener methods  797   798 def wiki_page_added(self, page):  799 if page.name == InterWikiMap._page_name:  800 self._update()  801   802 def wiki_page_changed(self, page, version, t, comment, author, ipnr):  803 if page.name == InterWikiMap._page_name:  804 self._update()  805   806 def wiki_page_deleted(self, page):  807 if page.name == InterWikiMap._page_name:  808 self._interwiki_map.clear()  809   810 def _update(self):  811 from trac.wiki.model import WikiPage  812 self._interwiki_map = {}  813 content = WikiPage(self.env, InterWikiMap._page_name).text  814 in_map = False  815 for line in content.split('\n'):  816 if in_map:  817 if line.startswith('----'):  818 in_map = False  819 else:  820 m = re.match(InterWikiMap._interwiki_re, line)  821 if m:  822 prefix, url, title = m.groups()  823 url = url.strip()  824 title = title and title.strip() or prefix  825 self._interwiki_map[prefix.upper()] = (prefix, url,  826 title)  827 elif line.startswith('----'):  828 in_map = True  829   830 # IWikiMacroProvider  831   832 def get_macros(self):  833 yield 'InterWiki'  834   835 def get_macro_description(self, name):   836 return "Provide a description list for the known InterWiki prefixes."  837   838 def render_macro(self, req, name, content):  839 if not self._interwiki_map:  840 self._update()  841 keys = self._interwiki_map.keys()  842 keys.sort()  843 buf = StringIO()  844 buf.write('<table><tr><th>Prefix</th><td>Site</td></tr>\n')  845 for k in keys:  846 prefix, url, title = self._interwiki_map[k]  847 shortened_url = url and url[:-1]  848 description = title == prefix and shortened_url or title  849 buf.write('<tr>\n' +  850 ('<td><a href="%sRecentChanges">%s</a></td>'  851 '<td><a href="%s">%s</a></td>\n') \  852 % (url, prefix, shortened_url, description) +  853 '</tr>\n')  854 buf.write('</table>\n')  855 return buf.getvalue() -
trac/wiki/tests/formatter.py
diff -ruN -x .svn trac-0.9b2/trac/wiki/tests/formatter.py intertrac-branch/trac/wiki/tests/formatter.py
old new  53 53 self.config = Configuration(None) 54 54 self.href = Href('/') 55 55 self.abs_href = Href('http://www.example.com/') 56  self._wiki_pages = {}Â57 56 self.path = ''  57 # -- intertrac support  58 self.siblings = {}  59 self.config.set('intertrac', 'trac.title', "Trac's Trac")  60 self.config.set('intertrac', 'trac.url',  61 "http://projects.edgewall.com/trac")  62 self.config.set('intertrac', 't', 'trac') 58 63 def component_activated(self, component): 59 64 component.env = self 60 65 component.config = self.config -
trac/wiki/tests/wiki-tests.txt
diff -ruN -x .svn trac-0.9b2/trac/wiki/tests/wiki-tests.txt intertrac-branch/trac/wiki/tests/wiki-tests.txt
old new  36 36 <a class="ext-link" href="http://www.edgewall.com/"><span class="icon"></span>http://www.edgewall.com/</a> 37 37 </p> 38 38 ============================== 39  #1, [1], r1, {1}  39 #1, {1}  40 [1], r1  41 [1/README.txt]  42 #12, [12], r12, {12} 40 43 ------------------------------ 41 44 <p> 42  <a class="missing ticket" href="/ticket/1" rel="nofollow">#1</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">[1]</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">r1</a>, <a class="report" href="/report/1">{1}</a>  45 <a class="missing ticket" href="/ticket/1" rel="nofollow">#1</a>, <a class="report" href="/report/1">{1}</a>  46 <a class="missing changeset" href="/changeset/1" rel="nofollow">[1]</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">r1</a>  47 <a class="missing changeset" href="/changeset/1/README.txt" rel="nofollow">[1/README.txt]</a>  48 <a class="missing ticket" href="/ticket/12" rel="nofollow">#12</a>, <a class="missing changeset" href="/changeset/12" rel="nofollow">[12]</a>, <a class="missing changeset" href="/changeset/12" rel="nofollow">r12</a>, <a class="report" href="/report/12">{12}</a> 43 49 </p> 44 50 ============================== 45 51 !#1, ![1], !r1, !{1} … …  60 66 [1:2], r1:2, [12:23], r12:23 61 67 </p> 62 68 ============================== 63  ticket:1, changeset:1, report:1, source:foo/bar  69 ticket:1, report:1, source:foo/bar  70 changeset:1, changeset:1/README.txt 64 71  65 72 Issue [ticket:1], CS[changeset:1], Listing [report:1], File [source:foo/bar] 66 73 ------------------------------ 67 74 <p> 68  <a class="missing ticket" href="/ticket/1" rel="nofollow">ticket:1</a>, <a class="missing changeset" href="/changeset/1" rel="nofollow">changeset:1</a>, <a class="report" href="/report/1">report:1</a>, <a class="source" href="/browser/foo/bar">source:foo/bar</a>  75 <a class="missing ticket" href="/ticket/1" rel="nofollow">ticket:1</a>, <a class="report" href="/report/1">report:1</a>, <a class="source" href="/browser/foo/bar">source:foo/bar</a>  76 <a class="missing changeset" href="/changeset/1" rel="nofollow">changeset:1</a>, <a class="missing changeset" href="/changeset/1/README.txt" rel="nofollow">changeset:1/README.txt</a> 69 77 </p> 70 78 <p> 71 79 Issue <a class="missing ticket" href="/ticket/1" rel="nofollow">1</a>, CS<a class="missing changeset" href="/changeset/1" rel="nofollow">1</a>, Listing <a class="report" href="/report/1">1</a>, File <a class="source" href="/browser/foo/bar">foo/bar</a> … …  79 87 <a class="source" href="/browser/foo/bar">source foo/bar</a>, <a class="ext-link" href="http://www.edgewall.com/"><span class="icon"></span>edgewall</a> 80 88 </p> 81 89 ==============================  90 diff:trunk//branch  91 diff:trunk@12//branch@23  92 diff:trunk@12:23  93 diff:@12:23  94 ------------------------------  95 <p>  96 <a class="changeset" title="Diff from trunk@latest to branch@latest" href="/diff/branch?old_path=trunk">diff:trunk//branch</a>  97 <a class="changeset" title="Diff from trunk@12 to branch@23" href="/diff/branch?new=23&old=12&old_path=trunk">diff:trunk@12//branch@23</a>  98 <a class="changeset" title="Diff r12:23 for trunk" href="/diff/trunk?new=23&old=12&old_path=trunk">diff:trunk@12:23</a>  99 <a class="changeset" title="Diff r12:23 for /" href="/diff/?new=23&old=12&old_path=">diff:@12:23</a>  100 </p>  101 ============================== 82 102 CamelCase AlabamA ABc AlaBamA FooBar 83 103 ------------------------------ 84 104 <p> 85 105 <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a> AlabamA ABc AlaBamA <a class="missing wiki" href="/wiki/FooBar" rel="nofollow">FooBar?</a> 86 106 </p> 87 107 ============================== 88  CamelCase,CamelCase.CamelCase: CamelCase 108 CamelCase,CamelCase.CamelCase: CamelCase 89 109 ------------------------------ 90 110 <p> 91  <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>,<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>. CamelCase:CamelCase 111 <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>,<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>.<a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a>: <a class="missing wiki" href="/wiki/CamelCase" rel="nofollow">CamelCase?</a> 92 112 </p> 93 113 ============================== 94 114 !CamelCase … …  605 625 <tr><td> a  606 626 </td></tr><tr><td> b  607 627 </td></tr></table>  628 ==============================  629 t:wiki:InterTrac  630 trac:wiki:InterTrac  631 [t:wiki:InterTrac intertrac]  632 [trac:wiki:InterTrac intertrac]  633 ------------------------------  634 <p> Â
