##// END OF EJS Templates
fixed unicode problems with file paths....
marcink -
r1087:51076a2a beta
parent child Browse files
Show More
@@ -1,593 +1,602
1 1 """Helper functions
2 2
3 3 Consists of functions to typically be used within templates, but also
4 4 available to Controllers. This module is available to both as 'h'.
5 5 """
6 6 import random
7 7 import hashlib
8 8 import StringIO
9 9 from pygments.formatters import HtmlFormatter
10 10 from pygments import highlight as code_highlight
11 11 from pylons import url
12 12 from pylons.i18n.translation import _, ungettext
13 13 from vcs.utils.annotate import annotate_highlight
14 14 from rhodecode.lib.utils import repo_name_slug
15 15
16 16 from webhelpers.html import literal, HTML, escape
17 17 from webhelpers.html.tools import *
18 18 from webhelpers.html.builder import make_tag
19 19 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
20 20 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
21 21 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
22 22 password, textarea, title, ul, xml_declaration, radio
23 23 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
24 24 mail_to, strip_links, strip_tags, tag_re
25 25 from webhelpers.number import format_byte_size, format_bit_size
26 26 from webhelpers.pylonslib import Flash as _Flash
27 27 from webhelpers.pylonslib.secure_form import secure_form
28 28 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
29 29 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
30 30 replace_whitespace, urlify, truncate, wrap_paragraphs
31 31 from webhelpers.date import time_ago_in_words
32 32
33 33 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
34 34 convert_boolean_attrs, NotGiven
35 35
36 36 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
37 37 """Reset button
38 38 """
39 39 _set_input_attrs(attrs, type, name, value)
40 40 _set_id_attr(attrs, id, name)
41 41 convert_boolean_attrs(attrs, ["disabled"])
42 42 return HTML.input(**attrs)
43 43
44 44 reset = _reset
45 45
46 46
47 47 def get_token():
48 48 """Return the current authentication token, creating one if one doesn't
49 49 already exist.
50 50 """
51 51 token_key = "_authentication_token"
52 52 from pylons import session
53 53 if not token_key in session:
54 54 try:
55 55 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
56 56 except AttributeError: # Python < 2.4
57 57 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
58 58 session[token_key] = token
59 59 if hasattr(session, 'save'):
60 60 session.save()
61 61 return session[token_key]
62 62
63 63 class _GetError(object):
64 64 """Get error from form_errors, and represent it as span wrapped error
65 65 message
66 66
67 67 :param field_name: field to fetch errors for
68 68 :param form_errors: form errors dict
69 69 """
70 70
71 71 def __call__(self, field_name, form_errors):
72 72 tmpl = """<span class="error_msg">%s</span>"""
73 73 if form_errors and form_errors.has_key(field_name):
74 74 return literal(tmpl % form_errors.get(field_name))
75 75
76 76 get_error = _GetError()
77 77
78 78 class _ToolTip(object):
79 79
80 80 def __call__(self, tooltip_title, trim_at=50):
81 81 """Special function just to wrap our text into nice formatted
82 82 autowrapped text
83 83
84 84 :param tooltip_title:
85 85 """
86 86
87 87 return wrap_paragraphs(escape(tooltip_title), trim_at)\
88 88 .replace('\n', '<br/>')
89 89
90 90 def activate(self):
91 91 """Adds tooltip mechanism to the given Html all tooltips have to have
92 92 set class `tooltip` and set attribute `tooltip_title`.
93 93 Then a tooltip will be generated based on that. All with yui js tooltip
94 94 """
95 95
96 96 js = '''
97 97 YAHOO.util.Event.onDOMReady(function(){
98 98 function toolTipsId(){
99 99 var ids = [];
100 100 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
101 101
102 102 for (var i = 0; i < tts.length; i++) {
103 103 //if element doesn't not have and id autogenerate one for tooltip
104 104
105 105 if (!tts[i].id){
106 106 tts[i].id='tt'+i*100;
107 107 }
108 108 ids.push(tts[i].id);
109 109 }
110 110 return ids
111 111 };
112 112 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
113 113 context: toolTipsId(),
114 114 monitorresize:false,
115 115 xyoffset :[0,0],
116 116 autodismissdelay:300000,
117 117 hidedelay:5,
118 118 showdelay:20,
119 119 });
120 120
121 121 // Set the text for the tooltip just before we display it. Lazy method
122 122 myToolTips.contextTriggerEvent.subscribe(
123 123 function(type, args) {
124 124
125 125 var context = args[0];
126 126
127 127 //positioning of tooltip
128 128 var tt_w = this.element.clientWidth;//tooltip width
129 129 var tt_h = this.element.clientHeight;//tooltip height
130 130
131 131 var context_w = context.offsetWidth;
132 132 var context_h = context.offsetHeight;
133 133
134 134 var pos_x = YAHOO.util.Dom.getX(context);
135 135 var pos_y = YAHOO.util.Dom.getY(context);
136 136
137 137 var display_strategy = 'right';
138 138 var xy_pos = [0,0];
139 139 switch (display_strategy){
140 140
141 141 case 'top':
142 142 var cur_x = (pos_x+context_w/2)-(tt_w/2);
143 143 var cur_y = (pos_y-tt_h-4);
144 144 xy_pos = [cur_x,cur_y];
145 145 break;
146 146 case 'bottom':
147 147 var cur_x = (pos_x+context_w/2)-(tt_w/2);
148 148 var cur_y = pos_y+context_h+4;
149 149 xy_pos = [cur_x,cur_y];
150 150 break;
151 151 case 'left':
152 152 var cur_x = (pos_x-tt_w-4);
153 153 var cur_y = pos_y-((tt_h/2)-context_h/2);
154 154 xy_pos = [cur_x,cur_y];
155 155 break;
156 156 case 'right':
157 157 var cur_x = (pos_x+context_w+4);
158 158 var cur_y = pos_y-((tt_h/2)-context_h/2);
159 159 xy_pos = [cur_x,cur_y];
160 160 break;
161 161 default:
162 162 var cur_x = (pos_x+context_w/2)-(tt_w/2);
163 163 var cur_y = pos_y-tt_h-4;
164 164 xy_pos = [cur_x,cur_y];
165 165 break;
166 166
167 167 }
168 168
169 169 this.cfg.setProperty("xy",xy_pos);
170 170
171 171 });
172 172
173 173 //Mouse out
174 174 myToolTips.contextMouseOutEvent.subscribe(
175 175 function(type, args) {
176 176 var context = args[0];
177 177
178 178 });
179 179 });
180 180 '''
181 181 return literal(js)
182 182
183 183 tooltip = _ToolTip()
184 184
185 185 class _FilesBreadCrumbs(object):
186 186
187 187 def __call__(self, repo_name, rev, paths):
188 188 if isinstance(paths, str):
189 189 paths = paths.decode('utf-8')
190 190 url_l = [link_to(repo_name, url('files_home',
191 191 repo_name=repo_name,
192 192 revision=rev, f_path=''))]
193 193 paths_l = paths.split('/')
194 194 for cnt, p in enumerate(paths_l):
195 195 if p != '':
196 196 url_l.append(link_to(p, url('files_home',
197 197 repo_name=repo_name,
198 198 revision=rev,
199 199 f_path='/'.join(paths_l[:cnt + 1]))))
200 200
201 201 return literal('/'.join(url_l))
202 202
203 203 files_breadcrumbs = _FilesBreadCrumbs()
204 204
205 205 class CodeHtmlFormatter(HtmlFormatter):
206 206 """My code Html Formatter for source codes
207 207 """
208 208
209 209 def wrap(self, source, outfile):
210 210 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
211 211
212 212 def _wrap_code(self, source):
213 213 for cnt, it in enumerate(source):
214 214 i, t = it
215 215 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
216 216 yield i, t
217 217
218 218 def _wrap_tablelinenos(self, inner):
219 219 dummyoutfile = StringIO.StringIO()
220 220 lncount = 0
221 221 for t, line in inner:
222 222 if t:
223 223 lncount += 1
224 224 dummyoutfile.write(line)
225 225
226 226 fl = self.linenostart
227 227 mw = len(str(lncount + fl - 1))
228 228 sp = self.linenospecial
229 229 st = self.linenostep
230 230 la = self.lineanchors
231 231 aln = self.anchorlinenos
232 232 nocls = self.noclasses
233 233 if sp:
234 234 lines = []
235 235
236 236 for i in range(fl, fl + lncount):
237 237 if i % st == 0:
238 238 if i % sp == 0:
239 239 if aln:
240 240 lines.append('<a href="#%s%d" class="special">%*d</a>' %
241 241 (la, i, mw, i))
242 242 else:
243 243 lines.append('<span class="special">%*d</span>' % (mw, i))
244 244 else:
245 245 if aln:
246 246 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
247 247 else:
248 248 lines.append('%*d' % (mw, i))
249 249 else:
250 250 lines.append('')
251 251 ls = '\n'.join(lines)
252 252 else:
253 253 lines = []
254 254 for i in range(fl, fl + lncount):
255 255 if i % st == 0:
256 256 if aln:
257 257 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
258 258 else:
259 259 lines.append('%*d' % (mw, i))
260 260 else:
261 261 lines.append('')
262 262 ls = '\n'.join(lines)
263 263
264 264 # in case you wonder about the seemingly redundant <div> here: since the
265 265 # content in the other cell also is wrapped in a div, some browsers in
266 266 # some configurations seem to mess up the formatting...
267 267 if nocls:
268 268 yield 0, ('<table class="%stable">' % self.cssclass +
269 269 '<tr><td><div class="linenodiv" '
270 270 'style="background-color: #f0f0f0; padding-right: 10px">'
271 271 '<pre style="line-height: 125%">' +
272 272 ls + '</pre></div></td><td class="code">')
273 273 else:
274 274 yield 0, ('<table class="%stable">' % self.cssclass +
275 275 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
276 276 ls + '</pre></div></td><td class="code">')
277 277 yield 0, dummyoutfile.getvalue()
278 278 yield 0, '</td></tr></table>'
279 279
280 280
281 281 def pygmentize(filenode, **kwargs):
282 282 """pygmentize function using pygments
283 283
284 284 :param filenode:
285 285 """
286 286
287 287 return literal(code_highlight(filenode.content,
288 288 filenode.lexer, CodeHtmlFormatter(**kwargs)))
289 289
290 290 def pygmentize_annotation(filenode, **kwargs):
291 291 """pygmentize function for annotation
292 292
293 293 :param filenode:
294 294 """
295 295
296 296 color_dict = {}
297 297 def gen_color(n=10000):
298 298 """generator for getting n of evenly distributed colors using
299 299 hsv color and golden ratio. It always return same order of colors
300 300
301 301 :returns: RGB tuple
302 302 """
303 303 import colorsys
304 304 golden_ratio = 0.618033988749895
305 305 h = 0.22717784590367374
306 306
307 307 for c in xrange(n):
308 308 h += golden_ratio
309 309 h %= 1
310 310 HSV_tuple = [h, 0.95, 0.95]
311 311 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
312 312 yield map(lambda x:str(int(x * 256)), RGB_tuple)
313 313
314 314 cgenerator = gen_color()
315 315
316 316 def get_color_string(cs):
317 317 if color_dict.has_key(cs):
318 318 col = color_dict[cs]
319 319 else:
320 320 col = color_dict[cs] = cgenerator.next()
321 321 return "color: rgb(%s)! important;" % (', '.join(col))
322 322
323 323 def url_func(changeset):
324 324 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
325 325 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
326 326
327 327 tooltip_html = tooltip_html % (changeset.author,
328 328 changeset.date,
329 329 tooltip(changeset.message))
330 330 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
331 331 short_id(changeset.raw_id))
332 332 uri = link_to(
333 333 lnk_format,
334 334 url('changeset_home', repo_name=changeset.repository.name,
335 335 revision=changeset.raw_id),
336 336 style=get_color_string(changeset.raw_id),
337 337 class_='tooltip',
338 338 title=tooltip_html
339 339 )
340 340
341 341 uri += '\n'
342 342 return uri
343 343 return literal(annotate_highlight(filenode, url_func, **kwargs))
344 344
345 345 def get_changeset_safe(repo, rev):
346 346 from vcs.backends.base import BaseRepository
347 347 from vcs.exceptions import RepositoryError
348 348 if not isinstance(repo, BaseRepository):
349 349 raise Exception('You must pass an Repository '
350 350 'object as first argument got %s', type(repo))
351 351
352 352 try:
353 353 cs = repo.get_changeset(rev)
354 354 except RepositoryError:
355 355 from rhodecode.lib.utils import EmptyChangeset
356 356 cs = EmptyChangeset()
357 357 return cs
358 358
359 359
360 360 def is_following_repo(repo_name, user_id):
361 361 from rhodecode.model.scm import ScmModel
362 362 return ScmModel().is_following_repo(repo_name, user_id)
363 363
364 364 flash = _Flash()
365 365
366 366
367 367 #==============================================================================
368 368 # MERCURIAL FILTERS available via h.
369 369 #==============================================================================
370 370 from mercurial import util
371 371 from mercurial.templatefilters import person as _person
372 372
373 373 def _age(curdate):
374 374 """turns a datetime into an age string."""
375 375
376 376 if not curdate:
377 377 return ''
378 378
379 379 from datetime import timedelta, datetime
380 380
381 381 agescales = [("year", 3600 * 24 * 365),
382 382 ("month", 3600 * 24 * 30),
383 383 ("day", 3600 * 24),
384 384 ("hour", 3600),
385 385 ("minute", 60),
386 386 ("second", 1), ]
387 387
388 388 age = datetime.now() - curdate
389 389 age_seconds = (age.days * agescales[2][1]) + age.seconds
390 390 pos = 1
391 391 for scale in agescales:
392 392 if scale[1] <= age_seconds:
393 393 if pos == 6:pos = 5
394 394 return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
395 395 pos += 1
396 396
397 397 return _('just now')
398 398
399 399 age = lambda x:_age(x)
400 400 capitalize = lambda x: x.capitalize()
401 401 email = util.email
402 402 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
403 403 person = lambda x: _person(x)
404 404 short_id = lambda x: x[:12]
405 405
406 406
407 407 def bool2icon(value):
408 408 """Returns True/False values represented as small html image of true/false
409 409 icons
410 410
411 411 :param value: bool value
412 412 """
413 413
414 414 if value is True:
415 415 return HTML.tag('img', src=url("/images/icons/accept.png"),
416 416 alt=_('True'))
417 417
418 418 if value is False:
419 419 return HTML.tag('img', src=url("/images/icons/cancel.png"),
420 420 alt=_('False'))
421 421
422 422 return value
423 423
424 424
425 def action_parser(user_log):
426 """This helper will map the specified string action into translated
425 def action_parser(user_log, feed=False):
426 """This helper will action_map the specified string action into translated
427 427 fancy names with icons and links
428 428
429 429 :param user_log: user log instance
430 :param feed: use output for feeds (no html and fancy icons)
430 431 """
431 432
432 433 action = user_log.action
433 434 action_params = ' '
434 435
435 436 x = action.split(':')
436 437
437 438 if len(x) > 1:
438 439 action, action_params = x
439 440
440 441 def get_cs_links():
441 442 revs_limit = 5 #display this amount always
442 443 revs_top_limit = 50 #show upto this amount of changesets hidden
443 444 revs = action_params.split(',')
444 445 repo_name = user_log.repository.repo_name
445 446
446 447 from rhodecode.model.scm import ScmModel
447 448 repo, dbrepo = ScmModel().get(repo_name, retval='repo',
448 449 invalidation_list=[])
449 450
450 451 message = lambda rev: get_changeset_safe(repo, rev).message
451 452
452 453 cs_links = " " + ', '.join ([link_to(rev,
453 454 url('changeset_home',
454 455 repo_name=repo_name,
455 456 revision=rev), title=tooltip(message(rev)),
456 457 class_='tooltip') for rev in revs[:revs_limit] ])
457 458
458 459 compare_view = (' <div class="compare_view tooltip" title="%s">'
459 460 '<a href="%s">%s</a> '
460 461 '</div>' % (_('Show all combined changesets %s->%s' \
461 462 % (revs[0], revs[-1])),
462 463 url('changeset_home', repo_name=repo_name,
463 464 revision='%s...%s' % (revs[0], revs[-1])
464 465 ),
465 466 _('compare view'))
466 467 )
467 468
468 469 if len(revs) > revs_limit:
469 470 uniq_id = revs[0]
470 471 html_tmpl = ('<span> %s '
471 472 '<a class="show_more" id="_%s" href="#more">%s</a> '
472 473 '%s</span>')
474 if not feed:
473 475 cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
474 476 % (len(revs) - revs_limit),
475 477 _('revisions'))
476 478
479 if not feed:
477 480 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
481 else:
482 html_tmpl = '<span id="%s"> %s </span>'
483
478 484 cs_links += html_tmpl % (uniq_id, ', '.join([link_to(rev,
479 485 url('changeset_home',
480 486 repo_name=repo_name, revision=rev),
481 487 title=message(rev), class_='tooltip')
482 488 for rev in revs[revs_limit:revs_top_limit]]))
483 489 if len(revs) > 1:
484 490 cs_links += compare_view
485 491 return cs_links
486 492
487 493 def get_fork_name():
488 494 repo_name = action_params
489 495 return _('fork name ') + str(link_to(action_params, url('summary_home',
490 496 repo_name=repo_name,)))
491 497
492 map = {'user_deleted_repo':(_('[deleted] repository'), None),
498 action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
493 499 'user_created_repo':(_('[created] repository'), None),
494 500 'user_forked_repo':(_('[forked] repository'), get_fork_name),
495 501 'user_updated_repo':(_('[updated] repository'), None),
496 502 'admin_deleted_repo':(_('[delete] repository'), None),
497 503 'admin_created_repo':(_('[created] repository'), None),
498 504 'admin_forked_repo':(_('[forked] repository'), None),
499 505 'admin_updated_repo':(_('[updated] repository'), None),
500 506 'push':(_('[pushed] into'), get_cs_links),
501 507 'pull':(_('[pulled] from'), None),
502 508 'started_following_repo':(_('[started following] repository'), None),
503 509 'stopped_following_repo':(_('[stopped following] repository'), None),
504 510 }
505 511
506 action_str = map.get(action, action)
512 action_str = action_map.get(action, action)
513 if feed:
514 action = action_str[0].replace('[', '').replace(']', '')
515 else:
507 516 action = action_str[0].replace('[', '<span class="journal_highlight">')\
508 517 .replace(']', '</span>')
509 518 action_params_func = lambda :""
510 519
511 520 if action_str[1] is not None:
512 521 action_params_func = action_str[1]
513 522
514 523 return [literal(action), action_params_func]
515 524
516 525 def action_parser_icon(user_log):
517 526 action = user_log.action
518 527 action_params = None
519 528 x = action.split(':')
520 529
521 530 if len(x) > 1:
522 531 action, action_params = x
523 532
524 533 tmpl = """<img src="%s/%s" alt="%s"/>"""
525 534 map = {'user_deleted_repo':'database_delete.png',
526 535 'user_created_repo':'database_add.png',
527 536 'user_forked_repo':'arrow_divide.png',
528 537 'user_updated_repo':'database_edit.png',
529 538 'admin_deleted_repo':'database_delete.png',
530 539 'admin_created_repo':'database_add.png',
531 540 'admin_forked_repo':'arrow_divide.png',
532 541 'admin_updated_repo':'database_edit.png',
533 542 'push':'script_add.png',
534 543 'pull':'down_16.png',
535 544 'started_following_repo':'heart_add.png',
536 545 'stopped_following_repo':'heart_delete.png',
537 546 }
538 547 return literal(tmpl % ((url('/images/icons/')),
539 548 map.get(action, action), action))
540 549
541 550
542 551 #==============================================================================
543 552 # PERMS
544 553 #==============================================================================
545 554 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
546 555 HasRepoPermissionAny, HasRepoPermissionAll
547 556
548 557 #==============================================================================
549 558 # GRAVATAR URL
550 559 #==============================================================================
551 560 import hashlib
552 561 import urllib
553 562 from pylons import request
554 563
555 564 def gravatar_url(email_address, size=30):
556 565 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
557 566 default = 'identicon'
558 567 baseurl_nossl = "http://www.gravatar.com/avatar/"
559 568 baseurl_ssl = "https://secure.gravatar.com/avatar/"
560 569 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
561 570
562 571
563 572 # construct the url
564 573 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
565 574 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
566 575
567 576 return gravatar_url
568 577
569 578 def safe_unicode(str):
570 579 """safe unicode function. In case of UnicodeDecode error we try to return
571 580 unicode with errors replace, if this failes we return unicode with
572 581 string_escape decoding """
573 582
574 583 try:
575 584 u_str = unicode(str)
576 585 except UnicodeDecodeError:
577 586 try:
578 587 u_str = unicode(str, 'utf-8', 'replace')
579 588 except UnicodeDecodeError:
580 589 #incase we have a decode error just represent as byte string
581 590 u_str = unicode(str(str).encode('string_escape'))
582 591
583 592 return u_str
584 593
585 594 def changed_tooltip(nodes):
586 595 if nodes:
587 596 pref = ': <br/> '
588 597 suf = ''
589 598 if len(nodes) > 30:
590 599 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
591 return literal(pref + '<br/> '.join([x.path for x in nodes[:30]]) + suf)
600 return literal(pref + '<br/> '.join([x.path.decode('utf-8') for x in nodes[:30]]) + suf)
592 601 else:
593 602 return ': ' + _('No Files')
@@ -1,122 +1,122
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(u'Home',h.url('/'))}
9 9 &raquo;
10 10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 11 &raquo;
12 12 ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('changelog')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <div class="box">
21 21 <!-- box / title -->
22 22 <div class="title">
23 23 ${self.breadcrumbs()}
24 24 </div>
25 25 <div class="table">
26 26 <div class="diffblock">
27 27 <div class="code-header">
28 28 <div>
29 29 ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
30 30 &raquo; <span>${h.link_to(_('raw diff'),
31 31 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span>
32 32 &raquo; <span>${h.link_to(_('download diff'),
33 33 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span>
34 34 </div>
35 35 </div>
36 36 </div>
37 37 <div id="changeset_content">
38 38 <div class="container">
39 39 <div class="left">
40 40 <div class="date">${_('commit')} ${c.changeset.revision}: ${h.short_id(c.changeset.raw_id)}@${c.changeset.date}</div>
41 41 <div class="author">
42 42 <div class="gravatar">
43 43 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
44 44 </div>
45 45 <span>${h.person(c.changeset.author)}</span><br/>
46 46 <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
47 47 </div>
48 48 <div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</div>
49 49 </div>
50 50 <div class="right">
51 51 <div class="changes">
52 52 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
53 53 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
54 54 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
55 55 </div>
56 56 %if len(c.changeset.parents)>1:
57 57 <div class="merge">
58 58 ${_('merge')}<img alt="merge" src="${h.url("/images/icons/arrow_join.png")}"/>
59 59 </div>
60 60 %endif
61 61
62 62 %if c.changeset.parents:
63 63 %for p_cs in reversed(c.changeset.parents):
64 64 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(h.short_id(p_cs.raw_id),
65 65 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
66 66 </div>
67 67 %endfor
68 68 %else:
69 69 <div class="parent">${_('No parents')}</div>
70 70 %endif
71 71 <span class="logtags">
72 72 <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
73 73 ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
74 74 %for tag in c.changeset.tags:
75 75 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
76 76 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
77 77 %endfor
78 78 </span>
79 79 </div>
80 80 </div>
81 81 <span style="font-size:1.1em;font-weight: bold">${_('Files affected')}</span>
82 82 <div class="cs_files">
83 83 %for change,filenode,diff,cs1,cs2 in c.changes:
84 <div class="cs_${change}">${h.link_to(filenode.path,h.url.current(anchor=h.repo_name_slug('C%s' % filenode.path)))}</div>
84 <div class="cs_${change}">${h.link_to(filenode.path.decode('utf-8'),h.url.current(anchor=h.repo_name_slug('C%s' % filenode.path.decode('utf-8'))))}</div>
85 85 %endfor
86 86 </div>
87 87 </div>
88 88
89 89 </div>
90 90
91 91 %for change,filenode,diff,cs1,cs2 in c.changes:
92 92 %if change !='removed':
93 93 <div style="clear:both;height:10px"></div>
94 94 <div class="diffblock">
95 <div id="${h.repo_name_slug('C%s' % filenode.path)}" class="code-header">
95 <div id="${h.repo_name_slug('C%s' % filenode.path.decode('utf-8'))}" class="code-header">
96 96 <div class="changeset_header">
97 97 <span class="changeset_file">
98 ${h.link_to_if(change!='removed',filenode.path,h.url('files_home',repo_name=c.repo_name,
99 revision=filenode.changeset.raw_id,f_path=filenode.path))}
98 ${h.link_to_if(change!='removed',filenode.path.decode('utf-8'),h.url('files_home',repo_name=c.repo_name,
99 revision=filenode.changeset.raw_id,f_path=filenode.path.decode('utf-8')))}
100 100 </span>
101 101 %if 1:
102 102 &raquo; <span>${h.link_to(_('diff'),
103 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='diff'))}</span>
103 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path.decode('utf-8'),diff2=cs2,diff1=cs1,diff='diff'))}</span>
104 104 &raquo; <span>${h.link_to(_('raw diff'),
105 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='raw'))}</span>
105 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path.decode('utf-8'),diff2=cs2,diff1=cs1,diff='raw'))}</span>
106 106 &raquo; <span>${h.link_to(_('download diff'),
107 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='download'))}</span>
107 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path.decode('utf-8'),diff2=cs2,diff1=cs1,diff='download'))}</span>
108 108 %endif
109 109 </div>
110 110 </div>
111 111 <div class="code-body">
112 112 %if diff:
113 113 ${diff|n}
114 114 %else:
115 115 ${_('No changes in this file')}
116 116 %endif
117 117 </div>
118 118 </div>
119 119 %endif
120 120 %endfor
121 121 </div>
122 122 </%def> No newline at end of file
@@ -1,97 +1,97
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(u'Home',h.url('/'))}
9 9 &raquo;
10 10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 11 &raquo;
12 12 ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('changelog')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <div class="box">
21 21 <!-- box / title -->
22 22 <div class="title">
23 23 ${self.breadcrumbs()}
24 24 </div>
25 25 <div class="table">
26 26 <div id="body" class="diffblock">
27 27 <div class="code-header">
28 28 <div>
29 29 ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
30 30 <h3>${_('Compare View')}</h3>
31 31 ##&raquo; <span>${h.link_to(_('raw diff'),
32 32 ##h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span>
33 33 ##&raquo; <span>${h.link_to(_('download diff'),
34 34 ##h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span>
35 35 </div>
36 36 </div>
37 37 </div>
38 38 <div id="changeset_compare_view_content">
39 39 <div class="container">
40 40 <table class="compare_view_commits">
41 41 %for cs in c.cs_ranges:
42 42 <tr>
43 43 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),14)}"/></div></td>
44 44 <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td>
45 45 <td><div class="author">${h.person(cs.author)}</div></td>
46 46 <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td>
47 47 <td><div class="message">${h.link_to(h.wrap_paragraphs(cs.message),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div></td>
48 48 </tr>
49 49 %endfor
50 50 </table>
51 51 </div>
52 52 <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
53 53 <div class="cs_files">
54 54 %for cs in c.cs_ranges:
55 55 <div class="cur_cs">r${cs}</div>
56 56 %for change,filenode,diff,cs1,cs2 in c.changes[cs.raw_id]:
57 <div class="cs_${change}">${h.link_to(filenode.path,h.url.current(anchor=h.repo_name_slug('C%s-%s' % (cs.short_id,filenode.path))))}</div>
57 <div class="cs_${change}">${h.link_to(filenode.path.decode('utf-8'),h.url.current(anchor=h.repo_name_slug('C%s-%s' % (cs.short_id,filenode.path.decode('utf-8')))))}</div>
58 58 %endfor
59 59 %endfor
60 60 </div>
61 61 </div>
62 62
63 63 </div>
64 64 %for cs in c.cs_ranges:
65 65 %for change,filenode,diff,cs1,cs2 in c.changes[cs.raw_id]:
66 66 %if change !='removed':
67 67 <div style="clear:both;height:10px"></div>
68 68 <div class="diffblock">
69 <div id="${h.repo_name_slug('C%s-%s' % (cs.short_id,filenode.path))}" class="code-header">
69 <div id="${h.repo_name_slug('C%s-%s' % (cs.short_id,filenode.path.decode('utf-8')))}" class="code-header">
70 70 <div class="changeset_header">
71 71 <span class="changeset_file">
72 ${h.link_to_if(change!='removed',filenode.path,h.url('files_home',repo_name=c.repo_name,
73 revision=filenode.changeset.raw_id,f_path=filenode.path))}
72 ${h.link_to_if(change!='removed',filenode.path.decode('utf-8'),h.url('files_home',repo_name=c.repo_name,
73 revision=filenode.changeset.raw_id,f_path=filenode.path.decode('utf-8')))}
74 74 </span>
75 75 %if 1:
76 76 &raquo; <span>${h.link_to(_('diff'),
77 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='diff'))}</span>
77 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path.decode('utf-8'),diff2=cs2,diff1=cs1,diff='diff'))}</span>
78 78 &raquo; <span>${h.link_to(_('raw diff'),
79 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='raw'))}</span>
79 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path.decode('utf-8'),diff2=cs2,diff1=cs1,diff='raw'))}</span>
80 80 &raquo; <span>${h.link_to(_('download diff'),
81 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='download'))}</span>
81 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path.decode('utf-8'),diff2=cs2,diff1=cs1,diff='download'))}</span>
82 82 %endif
83 83 </div>
84 84 </div>
85 85 <div class="code-body">
86 86 %if diff:
87 87 ${diff|n}
88 88 %else:
89 89 ${_('No changes in this file')}
90 90 %endif
91 91 </div>
92 92 </div>
93 93 %endif
94 94 %endfor
95 95 %endfor
96 96 </div>
97 97 </%def> No newline at end of file
@@ -1,31 +1,41
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3 <%def name="title()">
4 4 ${_('Journal')} - ${c.rhodecode_name}
5 5 </%def>
6 6 <%def name="breadcrumbs()">
7 7 ${c.rhodecode_name}
8 8 </%def>
9 9 <%def name="page_nav()">
10 10 ${self.menu('home')}
11 11 </%def>
12 12 <%def name="main()">
13 13
14 14 <div class="box">
15 15 <!-- box / title -->
16 16 <div class="title">
17 17 <h5>${_('Public Journal')}</h5>
18 <ul class="links">
19 <li>
20 <span>${h.link_to(_('RSS'),h.url('public_journal_rss'),class_='rss_icon')}</span>
21 </li>
22 <li>
23 <span>${h.link_to(_('Atom'),h.url('public_journal_atom'),class_='atom_icon')}</span>
24 </li>
25
26 </ul>
27
18 28 </div>
19 29 <script type="text/javascript">
20 30 function show_more_event(){
21 31 YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
22 32 var el = e.target;
23 33 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
24 34 YUD.setStyle(el.parentNode,'display','none');
25 35 });
26 36 }
27 37 </script>
28 38 <div id="journal">${c.journal_data}</div>
29 39 </div>
30 40
31 41 </%def>
@@ -1,332 +1,332
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.tests.test_hg_operations
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Test suite for making push/pull operations
7 7
8 8 :created_on: Dec 30, 2010
9 9 :copyright: (c) 2010 by marcink.
10 10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
11 11 """
12 12
13 13 import os
14 14 import shutil
15 15 import logging
16 16 from os.path import join as jn
17 17
18 18 from tempfile import _RandomNameSequence
19 19 from subprocess import Popen, PIPE
20 20
21 21 from paste.deploy import appconfig
22 22 from pylons import config
23 23 from sqlalchemy import engine_from_config
24 24
25 25 from rhodecode.lib.utils import add_cache
26 26 from rhodecode.model import init_model
27 27 from rhodecode.model import meta
28 28 from rhodecode.model.db import User, Repository
29 29 from rhodecode.lib.auth import get_crypt_password
30 30
31 31 from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO
32 32 from rhodecode.config.environment import load_environment
33 33
34 34 conf = appconfig('config:development.ini', relative_to='./../../')
35 35 load_environment(conf.global_conf, conf.local_conf)
36 36
37 37 add_cache(conf)
38 38
39 39 USER = 'test_admin'
40 40 PASS = 'test12'
41 41 HOST = '127.0.0.1:5000'
42 42 DEBUG = True
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 class Command(object):
47 47
48 48 def __init__(self, cwd):
49 49 self.cwd = cwd
50 50
51 51 def execute(self, cmd, *args):
52 52 """Runs command on the system with given ``args``.
53 53 """
54 54
55 55 command = cmd + ' ' + ' '.join(args)
56 56 log.debug('Executing %s' % command)
57 57 if DEBUG:
58 58 print command
59 59 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
60 60 stdout, stderr = p.communicate()
61 61 if DEBUG:
62 62 print stdout, stderr
63 63 return stdout, stderr
64 64
65 65 def get_session():
66 66 engine = engine_from_config(conf, 'sqlalchemy.db1.')
67 67 init_model(engine)
68 68 sa = meta.Session()
69 69 return sa
70 70
71 71
72 72 def create_test_user(force=True):
73 73 print 'creating test user'
74 74 sa = get_session()
75 75
76 76 user = sa.query(User).filter(User.username == USER).scalar()
77 77
78 78 if force and user is not None:
79 79 print 'removing current user'
80 80 for repo in sa.query(Repository).filter(Repository.user == user).all():
81 81 sa.delete(repo)
82 82 sa.delete(user)
83 83 sa.commit()
84 84
85 85 if user is None or force:
86 86 print 'creating new one'
87 87 new_usr = User()
88 88 new_usr.username = USER
89 89 new_usr.password = get_crypt_password(PASS)
90 90 new_usr.email = 'mail@mail.com'
91 91 new_usr.name = 'test'
92 92 new_usr.lastname = 'lasttestname'
93 93 new_usr.active = True
94 94 new_usr.admin = True
95 95 sa.add(new_usr)
96 96 sa.commit()
97 97
98 98 print 'done'
99 99
100 100
101 101 def create_test_repo(force=True):
102 102 from rhodecode.model.repo import RepoModel
103 103 sa = get_session()
104 104
105 105 user = sa.query(User).filter(User.username == USER).scalar()
106 106 if user is None:
107 107 raise Exception('user not found')
108 108
109 109
110 110 repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
111 111
112 112 if repo is None:
113 113 print 'repo not found creating'
114 114
115 115 form_data = {'repo_name':HG_REPO,
116 116 'repo_type':'hg',
117 117 'private':False, }
118 118 rm = RepoModel(sa)
119 119 rm.base_path = '/home/hg'
120 120 rm.create(form_data, user)
121 121
122 122
123 123 def set_anonymous_access(enable=True):
124 124 sa = get_session()
125 125 user = sa.query(User).filter(User.username == 'default').one()
126 126 user.active = enable
127 127 sa.add(user)
128 128 sa.commit()
129 129
130 130 def get_anonymous_access():
131 131 sa = get_session()
132 132 return sa.query(User).filter(User.username == 'default').one().active
133 133
134 134
135 135 #==============================================================================
136 136 # TESTS
137 137 #==============================================================================
138 138 def test_clone(no_errors=False):
139 139 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
140 140
141 141 try:
142 142 shutil.rmtree(path, ignore_errors=True)
143 143 os.makedirs(path)
144 144 #print 'made dirs %s' % jn(path)
145 145 except OSError:
146 146 raise
147 147
148 148
149 149 clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \
150 150 {'user':USER,
151 151 'pass':PASS,
152 152 'host':HOST,
153 153 'cloned_repo':HG_REPO,
154 154 'dest':path}
155 155
156 156 stdout, stderr = Command(cwd).execute('hg clone', clone_url)
157 157
158 158 if no_errors is False:
159 159 assert """adding file changes""" in stdout, 'no messages about cloning'
160 160 assert """abort""" not in stderr , 'got error from clone'
161 161
162 162
163 163
164 164 def test_clone_anonymous_ok():
165 165 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
166 166
167 167 try:
168 168 shutil.rmtree(path, ignore_errors=True)
169 169 os.makedirs(path)
170 170 #print 'made dirs %s' % jn(path)
171 171 except OSError:
172 172 raise
173 173
174 174
175 175 print 'checking if anonymous access is enabled'
176 176 anonymous_access = get_anonymous_access()
177 177 if not anonymous_access:
178 178 print 'not enabled, enabling it '
179 179 set_anonymous_access(enable=True)
180 180
181 181 clone_url = 'http://%(host)s/%(cloned_repo)s %(dest)s' % \
182 182 {'user':USER,
183 183 'pass':PASS,
184 184 'host':HOST,
185 185 'cloned_repo':HG_REPO,
186 186 'dest':path}
187 187
188 188 stdout, stderr = Command(cwd).execute('hg clone', clone_url)
189 189 print stdout, stderr
190 190
191 191
192 192 assert """adding file changes""" in stdout, 'no messages about cloning'
193 193 assert """abort""" not in stderr , 'got error from clone'
194 194
195 195 #disable if it was enabled
196 196 if not anonymous_access:
197 197 print 'disabling anonymous access'
198 198 set_anonymous_access(enable=False)
199 199
200 200
201 201 def test_clone_wrong_credentials():
202 202 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
203 203
204 204 try:
205 205 shutil.rmtree(path, ignore_errors=True)
206 206 os.makedirs(path)
207 207 #print 'made dirs %s' % jn(path)
208 208 except OSError:
209 209 raise
210 210
211 211
212 212 clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \
213 213 {'user':USER + 'error',
214 214 'pass':PASS,
215 215 'host':HOST,
216 216 'cloned_repo':HG_REPO,
217 217 'dest':path}
218 218
219 219 stdout, stderr = Command(cwd).execute('hg clone', clone_url)
220 220
221 221 assert """abort: authorization failed""" in stderr , 'no error from wrong credentials'
222 222
223 223
224 224 def test_pull():
225 225 pass
226 226
227 227 def test_push_modify_file(f_name='setup.py'):
228 228 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
229 229 modified_file = jn(TESTS_TMP_PATH, HG_REPO, f_name)
230 230 for i in xrange(5):
231 231 cmd = """echo 'added_line%s' >> %s""" % (i, modified_file)
232 232 Command(cwd).execute(cmd)
233 233
234 234 cmd = """hg ci -m 'changed file %s' %s """ % (i, modified_file)
235 235 Command(cwd).execute(cmd)
236 236
237 237 Command(cwd).execute('hg push %s' % jn(TESTS_TMP_PATH, HG_REPO))
238 238
239 239 def test_push_new_file(commits=15):
240 240
241 241 test_clone(no_errors=True)
242 242
243 243 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
244 added_file = jn(path, '%ssetup.py' % _RandomNameSequence().next())
244 added_file = jn(path, '%ssetupΔ…ΕΌΕΊΔ‡.py' % _RandomNameSequence().next())
245 245
246 246 Command(cwd).execute('touch %s' % added_file)
247 247
248 248 Command(cwd).execute('hg add %s' % added_file)
249 249
250 250 for i in xrange(commits):
251 251 cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
252 252 Command(cwd).execute(cmd)
253 253
254 254 cmd = """hg ci -m 'commited new %s' %s """ % (i, added_file)
255 255 Command(cwd).execute(cmd)
256 256
257 257 push_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
258 258 {'user':USER,
259 259 'pass':PASS,
260 260 'host':HOST,
261 261 'cloned_repo':HG_REPO,
262 262 'dest':jn(TESTS_TMP_PATH, HG_REPO)}
263 263
264 264 Command(cwd).execute('hg push --verbose --debug %s' % push_url)
265 265
266 266 def test_push_wrong_credentials():
267 267 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
268 268 clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
269 269 {'user':USER + 'xxx',
270 270 'pass':PASS,
271 271 'host':HOST,
272 272 'cloned_repo':HG_REPO,
273 273 'dest':jn(TESTS_TMP_PATH, HG_REPO)}
274 274
275 275 modified_file = jn(TESTS_TMP_PATH, HG_REPO, 'setup.py')
276 276 for i in xrange(5):
277 277 cmd = """echo 'added_line%s' >> %s""" % (i, modified_file)
278 278 Command(cwd).execute(cmd)
279 279
280 280 cmd = """hg ci -m 'commited %s' %s """ % (i, modified_file)
281 281 Command(cwd).execute(cmd)
282 282
283 283 Command(cwd).execute('hg push %s' % clone_url)
284 284
285 285 def test_push_wrong_path():
286 286 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
287 287 added_file = jn(path, 'somefile.py')
288 288
289 289 try:
290 290 shutil.rmtree(path, ignore_errors=True)
291 291 os.makedirs(path)
292 292 print 'made dirs %s' % jn(path)
293 293 except OSError:
294 294 raise
295 295
296 296 Command(cwd).execute("""echo '' > %s""" % added_file)
297 297 Command(cwd).execute("""hg init %s""" % path)
298 298 Command(cwd).execute("""hg add %s""" % added_file)
299 299
300 300 for i in xrange(2):
301 301 cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
302 302 Command(cwd).execute(cmd)
303 303
304 304 cmd = """hg ci -m 'commited new %s' %s """ % (i, added_file)
305 305 Command(cwd).execute(cmd)
306 306
307 307 clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
308 308 {'user':USER,
309 309 'pass':PASS,
310 310 'host':HOST,
311 311 'cloned_repo':HG_REPO + '_error',
312 312 'dest':jn(TESTS_TMP_PATH, HG_REPO)}
313 313
314 314 stdout, stderr = Command(cwd).execute('hg push %s' % clone_url)
315 315 assert """abort: HTTP Error 403: Forbidden""" in stderr
316 316
317 317
318 318 if __name__ == '__main__':
319 319 create_test_user(force=False)
320 320 create_test_repo()
321 321 #test_push_modify_file()
322 322 #test_clone()
323 323 #test_clone_anonymous_ok()
324 324
325 325 #test_clone_wrong_credentials()
326 326
327 327 #test_pull()
328 test_push_new_file(commits=2)
328 test_push_new_file(commits=15)
329 329 #test_push_wrong_path()
330 330 #test_push_wrong_credentials()
331 331
332 332
General Comments 0
You need to be logged in to leave comments. Login now