##// END OF EJS Templates
fixes few bugs...
marcink -
r671:bee56f20 rhodecode-0.0.1.0.1 default
parent child Browse files
Show More
@@ -3,6 +3,16 b''
3 3 Changelog
4 4 =========
5 5
6
7 1.0.1 (**2010-11-10**)
8 ----------------------
9
10 - fixed #53 python2.5 incompatible enumerate calls
11 - fixed #52 disable mercurial extension for web
12 - fixed #51 deleting repositories don't delete it's dependent objects
13 - small css updated
14
15
6 16 1.0.0 (**2010-11-02**)
7 17 ----------------------
8 18
@@ -5,12 +5,12 b' Installation'
5 5
6 6 ``RhodeCode`` is written entirely in Python, but in order to use it's full
7 7 potential there are some third-party requirements. When RhodeCode is used
8 together with celery You have to install some kind of message broker,
8 together with celery_ You have to install some kind of message broker,
9 9 recommended one is rabbitmq_ to make the async tasks work.
10 10
11 11 Of course RhodeCode works in sync mode also, then You don't have to install
12 12 any third party apps. Celery_ will give You large speed improvement when using
13 many big repositories. If You plan to use it for 2 or 3 small repositories, it
13 many big repositories. If You plan to use it for 5 or 10 small repositories, it
14 14 will work just fine without celery running.
15 15
16 16 After You decide to Run it with celery make sure You run celeryd and
@@ -33,7 +33,7 b' Install from Cheese Shop'
33 33
34 34 Easiest way to install ``rhodecode`` is to run::
35 35
36 easy_install rhodecode
36 easy_install rhodecode
37 37
38 38 Or::
39 39
@@ -42,15 +42,16 b' Or::'
42 42 If you prefer to install manually simply grab latest release from
43 43 http://pypi.python.org/pypi/rhodecode, decompres archive and run::
44 44
45 python setup.py install
45 python setup.py install
46 46
47 47
48 48 Step by step installation example
49 49 ---------------------------------
50 50
51 51
52 - Assuming You have installed virtualenv_ create one using. The `--no-site-packages`
53 will make sure non of Your system libs are linked with this virtualenv_
52 - Assuming You have installed virtualenv_ create one using.
53 The `--no-site-packages` will make sure non of Your system libs are linked
54 with this virtualenv_
54 55
55 56 ::
56 57
@@ -40,6 +40,18 b' Setting up the application'
40 40 - Default permissions on each repository is read, and owner is admin. So
41 41 remember to update these if needed.
42 42
43 Note
44 ----
45
46 RhodeCode when running without the celery it's running all it's task in sync
47 mode, for first few times when visiting summary page You can notice few
48 slow downs, this is due the statistics building it's cache. After all changesets
49 are parsed it'll take the stats from cache and run much faster. Each summary
50 page display parse at most 250 changesets in order to not stress the cpu, so
51 the full stats are going to be loaded after total_number_of_changesets/250
52 summary page visits.
53
54
43 55
44 56 Setting up Whoosh
45 57 -----------------
@@ -53,9 +65,9 b' Setting up Whoosh'
53 65 When using incremental mode whoosh will check last modification date of each file
54 66 and add it to reindex if newer file is available. Also indexing daemon checks
55 67 for removed files and removes them from index. Sometime You might want to rebuild
56 index from scrach, in admin pannel You can check `build from scratch` flag
68 index from scratch, in admin panel You can check `build from scratch` flag
57 69 and in standalone daemon You can pass `full` instead on incremental to build
58 remove previos index and build new one.
70 remove previous index and build new one.
59 71
60 72 Nginx virtual host example
61 73 --------------------------
@@ -24,7 +24,7 b' versioning implementation: http://semver'
24 24 @author: marcink
25 25 """
26 26
27 VERSION = (1, 0, 0,)
27 VERSION = (1, 0, 1,)
28 28
29 29 __version__ = '.'.join((str(each) for each in VERSION[:4]))
30 30
@@ -64,20 +64,20 b" def recursive_replace(str, replace=' '):"
64 64 return str
65 65 else:
66 66 str = str.replace(replace * 2, replace)
67 return recursive_replace(str, replace)
67 return recursive_replace(str, replace)
68 68
69 69 class _ToolTip(object):
70
70
71 71 def __call__(self, tooltip_title, trim_at=50):
72 72 """
73 73 Special function just to wrap our text into nice formatted autowrapped
74 74 text
75 75 :param tooltip_title:
76 76 """
77
77
78 78 return wrap_paragraphs(escape(tooltip_title), trim_at)\
79 79 .replace('\n', '<br/>')
80
80
81 81 def activate(self):
82 82 """
83 83 Adds tooltip mechanism to the given Html all tooltips have to have
@@ -85,7 +85,7 b' class _ToolTip(object):'
85 85 Then a tooltip will be generated based on that
86 86 All with yui js tooltip
87 87 """
88
88
89 89 js = '''
90 90 YAHOO.util.Event.onDOMReady(function(){
91 91 function toolTipsId(){
@@ -190,25 +190,25 b' class _ToolTip(object):'
190 190
191 191 });
192 192 });
193 '''
193 '''
194 194 return literal(js)
195 195
196 196 tooltip = _ToolTip()
197 197
198 198 class _FilesBreadCrumbs(object):
199
199
200 200 def __call__(self, repo_name, rev, paths):
201 201 url_l = [link_to(repo_name, url('files_home',
202 202 repo_name=repo_name,
203 203 revision=rev, f_path=''))]
204 204 paths_l = paths.split('/')
205
206 for cnt, p in enumerate(paths_l, 1):
205
206 for cnt, p in enumerate(paths_l):
207 207 if p != '':
208 208 url_l.append(link_to(p, url('files_home',
209 209 repo_name=repo_name,
210 210 revision=rev,
211 f_path='/'.join(paths_l[:cnt]))))
211 f_path='/'.join(paths_l[:cnt + 1]))))
212 212
213 213 return literal('/'.join(url_l))
214 214
@@ -219,9 +219,9 b' class CodeHtmlFormatter(HtmlFormatter):'
219 219 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
220 220
221 221 def _wrap_code(self, source):
222 for cnt, it in enumerate(source, 1):
222 for cnt, it in enumerate(source):
223 223 i, t = it
224 t = '<div id="#S-%s">%s</div>' % (cnt, t)
224 t = '<div id="#S-%s">%s</div>' % (cnt + 1, t)
225 225 yield i, t
226 226 def pygmentize(filenode, **kwargs):
227 227 """
@@ -236,12 +236,12 b' def pygmentize_annotation(filenode, **kw'
236 236 pygmentize function for annotation
237 237 :param filenode:
238 238 """
239
239
240 240 color_dict = {}
241 241 def gen_color():
242 242 """generator for getting 10k of evenly distibuted colors using hsv color
243 243 and golden ratio.
244 """
244 """
245 245 import colorsys
246 246 n = 10000
247 247 golden_ratio = 0.618033988749895
@@ -252,21 +252,21 b' def pygmentize_annotation(filenode, **kw'
252 252 h %= 1
253 253 HSV_tuple = [h, 0.95, 0.95]
254 254 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
255 yield map(lambda x:str(int(x * 256)), RGB_tuple)
255 yield map(lambda x:str(int(x * 256)), RGB_tuple)
256 256
257 257 cgenerator = gen_color()
258
258
259 259 def get_color_string(cs):
260 260 if color_dict.has_key(cs):
261 261 col = color_dict[cs]
262 262 else:
263 263 col = color_dict[cs] = cgenerator.next()
264 264 return "color: rgb(%s)! important;" % (', '.join(col))
265
265
266 266 def url_func(changeset):
267 267 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
268 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
269
268 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
269
270 270 tooltip_html = tooltip_html % (changeset.author,
271 271 changeset.date,
272 272 tooltip(changeset.message))
@@ -280,11 +280,11 b' def pygmentize_annotation(filenode, **kw'
280 280 class_='tooltip',
281 281 tooltip_title=tooltip_html
282 282 )
283
283
284 284 uri += '\n'
285 return uri
285 return uri
286 286 return literal(annotate_highlight(filenode, url_func, **kwargs))
287
287
288 288 def repo_name_slug(value):
289 289 """Return slug of name of repository
290 290 This function is called on each creation/modification
@@ -292,7 +292,7 b' def repo_name_slug(value):'
292 292 """
293 293 slug = remove_formatting(value)
294 294 slug = strip_tags(slug)
295
295
296 296 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
297 297 slug = slug.replace(c, '-')
298 298 slug = recursive_replace(slug, '-')
@@ -305,7 +305,7 b' def get_changeset_safe(repo, rev):'
305 305 if not isinstance(repo, BaseRepository):
306 306 raise Exception('You must pass an Repository '
307 307 'object as first argument got %s', type(repo))
308
308
309 309 try:
310 310 cs = repo.get_changeset(rev)
311 311 except RepositoryError:
@@ -358,8 +358,8 b' def gravatar_url(email_address, size=30)'
358 358 baseurl_nossl = "http://www.gravatar.com/avatar/"
359 359 baseurl_ssl = "https://secure.gravatar.com/avatar/"
360 360 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
361
362
361
362
363 363 # construct the url
364 364 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
365 365 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
@@ -370,7 +370,7 b' def safe_unicode(str):'
370 370 """safe unicode function. In case of UnicodeDecode error we try to return
371 371 unicode with errors replace, if this failes we return unicode with
372 372 string_escape decoding """
373
373
374 374 try:
375 375 u_str = unicode(str)
376 376 except UnicodeDecodeError:
@@ -379,5 +379,5 b' def safe_unicode(str):'
379 379 except UnicodeDecodeError:
380 380 #incase we have a decode error just represent as byte string
381 381 u_str = unicode(str(str).encode('string_escape'))
382
382
383 383 return u_str
@@ -221,6 +221,11 b" def make_ui(read_from='file', path=None,"
221 221 for k, v in cfg.items(section):
222 222 baseui.setconfig(section, k, v)
223 223 log.debug('settings ui from file[%s]%s:%s', section, k, v)
224
225 for k, v in baseui.configitems('extensions'):
226 baseui.setconfig('extensions', k, '0')
227 #just enable mq
228 baseui.setconfig('extensions', 'mq', '1')
224 229 if checkpaths:check_repo_dir(cfg.items('paths'))
225 230
226 231
@@ -22,9 +22,9 b' class RhodeCodeUi(Base):'
22 22 ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
23 23 ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
24 24 ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
25
26
27 class User(Base):
25
26
27 class User(Base):
28 28 __tablename__ = 'users'
29 29 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
30 30 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
@@ -36,21 +36,21 b' class User(Base):'
36 36 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
37 37 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
38 38 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
39
39
40 40 user_log = relation('UserLog')
41 41 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
42
42
43 43 @LazyProperty
44 44 def full_contact(self):
45 45 return '%s %s <%s>' % (self.name, self.lastname, self.email)
46
46
47 47 def __repr__(self):
48 48 return "<User('id:%s:%s')>" % (self.user_id, self.username)
49
49
50 50 def update_lastlogin(self):
51 51 """Update user lastlogin"""
52 52 import datetime
53
53
54 54 try:
55 55 session = Session.object_session(self)
56 56 self.last_login = datetime.datetime.now()
@@ -58,24 +58,24 b' class User(Base):'
58 58 session.commit()
59 59 log.debug('updated user %s lastlogin', self.username)
60 60 except Exception:
61 session.rollback()
62
63
64 class UserLog(Base):
61 session.rollback()
62
63
64 class UserLog(Base):
65 65 __tablename__ = 'user_logs'
66 66 __table_args__ = {'useexisting':True}
67 67 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
68 68 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
69 69 repository_id = Column("repository_id", INTEGER(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
70 70 repository_name = Column("repository_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
71 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
71 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
72 72 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
73 73 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
74 74 revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
75
75
76 76 user = relation('User')
77 77 repository = relation('Repository')
78
78
79 79 class Repository(Base):
80 80 __tablename__ = 'repositories'
81 81 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
@@ -85,21 +85,23 b' class Repository(Base):'
85 85 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
86 86 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
87 87 fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
88
88
89 89 user = relation('User')
90 90 fork = relation('Repository', remote_side=repo_id)
91 91 repo_to_perm = relation('RepoToPerm', cascade='all')
92
92 stats = relation('Statistics', cascade='all')
93
94
93 95 def __repr__(self):
94 96 return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
95
97
96 98 class Permission(Base):
97 99 __tablename__ = 'permissions'
98 100 __table_args__ = {'useexisting':True}
99 101 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
100 102 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 103 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102
104
103 105 def __repr__(self):
104 106 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
105 107
@@ -109,8 +111,8 b' class RepoToPerm(Base):'
109 111 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
110 112 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
111 113 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
112 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
113
114 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
115
114 116 user = relation('User')
115 117 permission = relation('Permission')
116 118 repository = relation('Repository')
@@ -121,7 +123,7 b' class UserToPerm(Base):'
121 123 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
122 124 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
123 125 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
124
126
125 127 user = relation('User')
126 128 permission = relation('Permission')
127 129
@@ -134,6 +136,6 b' class Statistics(Base):'
134 136 commit_activity = Column("commit_activity", BLOB(), nullable=False)#JSON data
135 137 commit_activity_combined = Column("commit_activity_combined", BLOB(), nullable=False)#JSON data
136 138 languages = Column("languages", BLOB(), nullable=False)#JSON data
137
138 repository = relation('Repository')
139 139
140 repository = relation('Repository', single_parent=True)
141
@@ -270,7 +270,7 b' text-decoration:none;'
270 270 }
271 271
272 272 #header #header-inner #logo a:hover {
273 color:#dabf29;
273 color:#bfe3ff;
274 274 }
275 275
276 276 #header #header-inner #quick,#header #header-inner #quick ul {
@@ -419,7 +419,7 b' padding:12px 9px 7px 24px;'
419 419 }
420 420
421 421 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
422 background:url("../images/icons/folder_edit.png") no-repeat scroll 4px 9px #FFF;
422 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
423 423 width:167px;
424 424 margin:0;
425 425 padding:12px 9px 7px 24px;
@@ -1010,7 +1010,7 b' padding:0;'
1010 1010 #content div.box table th {
1011 1011 background:#eee;
1012 1012 border-bottom:1px solid #ddd;
1013 padding:10px;
1013 padding:5px 0px 5px 5px;
1014 1014 }
1015 1015
1016 1016 #content div.box table th.left {
@@ -1393,7 +1393,6 b' background-color:#003367;'
1393 1393 color:#FFF;
1394 1394 display:block;
1395 1395 min-width:20px;
1396 max-width:400px;
1397 1396 text-decoration:none;
1398 1397 height:12px;
1399 1398 margin-bottom:4px;
@@ -1542,7 +1541,7 b' background:#F88;'
1542 1541
1543 1542 .right .merge {
1544 1543 vertical-align:top;
1545 font-size:60%;
1544 font-size:0.75em;
1546 1545 font-weight:700;
1547 1546 }
1548 1547
@@ -1554,13 +1553,15 b' font-family:monospace;'
1554 1553 .right .logtags .branchtag {
1555 1554 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1556 1555 display:block;
1557 padding:8px 16px 0 0;
1556 font-size:0.8em;
1557 padding:11px 16px 0 0;
1558 1558 }
1559 1559
1560 1560 .right .logtags .tagtag {
1561 1561 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1562 1562 display:block;
1563 padding:6px 18px 0 0;
1563 font-size:0.8em;
1564 padding:11px 16px 0 0;
1564 1565 }
1565 1566
1566 1567 div.browserblock {
@@ -1701,6 +1702,7 b' font:100% sans-serif;'
1701 1702 width:auto;
1702 1703 opacity:1px;
1703 1704 padding:8px;
1705 white-space: pre;
1704 1706 }
1705 1707
1706 1708 .ac {
@@ -2024,7 +2026,6 b' display:block;'
2024 2026 }
2025 2027
2026 2028 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2027 background:url("../../images/title_tab_selected.png") no-repeat bottom center;
2028 2029 color:#bfe3ff;
2029 2030 }
2030 2031
@@ -43,8 +43,8 b''
43 43 </tr>
44 44 %endif
45 45
46 %for cnt,node in enumerate(c.files_list,1):
47 <tr class="parity${cnt%2}">
46 %for cnt,node in enumerate(c.files_list):
47 <tr class="parity${(cnt+1)%2}">
48 48 <td>
49 49 ${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=node.path),class_=file_class(node))}
50 50 </td>
@@ -59,19 +59,19 b''
59 59 %endif
60 60 </td>
61 61 <td>
62 %if node.is_file():
63 ${node.last_changeset.revision}
64 %endif
62 %if node.is_file():
63 ${node.last_changeset.revision}
64 %endif
65 65 </td>
66 66 <td>
67 %if node.is_file():
68 ${h.age(node.last_changeset._ctx.date())} - ${node.last_changeset.date}
69 %endif
67 %if node.is_file():
68 ${h.age(node.last_changeset._ctx.date())} - ${node.last_changeset.date}
69 %endif
70 70 </td>
71 71 <td>
72 %if node.is_file():
73 ${node.last_changeset.author}
74 %endif
72 %if node.is_file():
73 ${node.last_changeset.author}
74 %endif
75 75 </td>
76 76 </tr>
77 77 %endfor
@@ -131,11 +131,13 b' E.onDOMReady(function(e){'
131 131 var value = data[k];
132 132 var td1 = document.createElement('td');
133 133 td1.width=150;
134
134 135 var trending_language_label = document.createElement('div');
135 136 trending_language_label.innerHTML = k;
136 137 td1.appendChild(trending_language_label);
137 138
138 139 var td2 = document.createElement('td');
140 td2.setAttribute('style','padding-right: 12px ! important;');
139 141 var trending_language = document.createElement('div');
140 142 trending_language.title = k;
141 143 trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>";
General Comments 0
You need to be logged in to leave comments. Login now