@@ -13,13 +13,13 @@ news
----
- implemented #89 Can setup google analytics code from settings menu
- implemented #91 added nicer looking archive urls with more download options
like tags, branches
- implemented #44 into file browsing, and added follow branch option
- implemented #84 downloads can be enabled/disabled for each repository
- anonymous repository can be cloned without having to pass default:default
into clone url
- fixed #90 whoosh indexer can index chooses repositories passed in command
line
- extended journal with day aggregates and paging
- implemented #107 source code lines highlight ranges
@@ -47,12 +47,13 @@ fixes
- fixed #99 Unicode errors, on file node paths with non utf-8 characters
- journal fork fixes
- removed issue with space inside renamed repository after deletion
- fixed strange issue on formencode imports
- fixed #126 Deleting repository on Windows, rename used incompatible chars.
- windows fixes for os.kill and path spliting, issues #148 and #133
- #150 fixes for errors on repositories mapped in db but corrupted in filesystem
1.1.7 (**2011-03-23**)
======================
news
@@ -58,19 +58,21 @@ class UserTemp(object):
def __init__(self, user_id):
self.user_id = user_id
def __repr__(self):
return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
class RepoTemp(object):
def __init__(self, repo_id):
self.repo_id = repo_id
return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
class ScmModel(BaseModel):
"""Generic Scm Model
"""
@LazyProperty
def repos_path(self):
@@ -95,13 +97,13 @@ class ScmModel(BaseModel):
baseui = make_ui('db')
repos_list = {}
for name, path in get_filesystem_repos(repos_path, recursive=True):
try:
if repos_list.has_key(name):
if name in repos_list:
raise RepositoryError('Duplicate repository name %s '
'found in %s' % (name, path))
else:
klass = get_backend(path[0])
@@ -113,14 +115,14 @@ class ScmModel(BaseModel):
except OSError:
continue
return repos_list
def get_repos(self, all_repos=None):
"""Get all repos from db and for each repo create it's backend instance.
and fill that backed with information from database
"""Get all repos from db and for each repo create it's
backend instance and fill that backed with information from database
:param all_repos: give specific repositories list, good for filtering
this have to be a list of just the repository names
if all_repos is None:
repos = self.sa.query(Repository)\
@@ -134,33 +136,38 @@ class ScmModel(BaseModel):
.all()]
for r_name in all_repos:
r_dbr = self.get(r_name, invalidation_list)
if r_dbr is not None:
repo, dbrepo = r_dbr
if not repo and dbrepo:
log.error('Repository %s looks somehow corrupted', r_name)
last_change = repo.last_change
tip = h.get_changeset_safe(repo, 'tip')
tmp_d = {}
tmp_d['name'] = dbrepo.repo_name
tmp_d['name_sort'] = tmp_d['name'].lower()
tmp_d['description'] = dbrepo.description
tmp_d['description_sort'] = tmp_d['description']
tmp_d['last_change'] = last_change
tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
tmp_d['last_change_sort'] = time.mktime(last_change \
.timetuple())
tmp_d['tip'] = tip.raw_id
tmp_d['tip_sort'] = tip.revision
tmp_d['rev'] = tip.revision
tmp_d['contact'] = dbrepo.user.full_contact
tmp_d['contact_sort'] = tmp_d['contact']
tmp_d['owner_sort'] = tmp_d['contact']
tmp_d['repo_archives'] = list(repo._get_archives())
tmp_d['last_msg'] = tip.message
tmp_d['repo'] = repo
tmp_d['dbrepo'] = dbrepo.get_dict()
tmp_d['dbrepo_fork'] = dbrepo.fork.get_dict() if dbrepo.fork else {}
tmp_d['dbrepo_fork'] = dbrepo.fork.get_dict() if dbrepo.fork \
else {}
yield tmp_d
def get(self, repo_name, invalidation_list=None, retval='all'):
"""Returns a tuple of Repository,DbRepository,
Get's repository from given name, creates BackendInstance and
propagates it's data from database with all additional information
@@ -225,13 +232,12 @@ class ScmModel(BaseModel):
if retval == 'repo' or 'all':
r = _get_repo(repo_name)
if retval == 'dbrepo' or 'all':
dbr = RepoModel().get_full(repo_name, cache=True,
invalidate=dbinvalidate)
return r, dbr
def mark_for_invalidation(self, repo_name):
"""Puts cache invalidation task into db for
further global cache invalidation
@@ -253,13 +259,12 @@ class ScmModel(BaseModel):
self.sa.add(cache)
self.sa.commit()
except (DatabaseError,):
log.error(traceback.format_exc())
self.sa.rollback()
def toggle_following_repo(self, follow_repo_id, user_id):
f = self.sa.query(UserFollowing)\
.filter(UserFollowing.follows_repo_id == follow_repo_id)\
.filter(UserFollowing.user_id == user_id).scalar()
@@ -274,13 +279,12 @@ class ScmModel(BaseModel):
return
except:
raise
f = UserFollowing()
f.user_id = user_id
f.follows_repo_id = follow_repo_id
self.sa.add(f)
@@ -289,13 +293,13 @@ class ScmModel(BaseModel):
RepoTemp(follow_repo_id))
def toggle_following_user(self, follow_user_id , user_id):
def toggle_following_user(self, follow_user_id, user_id):
.filter(UserFollowing.follows_user_id == follow_user_id)\
if f is not None:
@@ -352,21 +356,20 @@ class ScmModel(BaseModel):
.filter(Repository.fork_id == repo_id).count()
return self.sa.query(Repository)\
.filter(Repository.fork \
== RepoModel().get_by_repo_name(repo_id)).count()
def pull_changes(self, repo_name, username):
repo, dbrepo = self.get(repo_name, retval='all')
extras = {'ip':'',
'username':username,
'action':'push_remote',
'repository':repo_name}
extras = {'ip': '',
'username': username,
'action': 'push_remote',
'repository': repo_name}
#inject ui extra param to log this action via push logger
for k, v in extras.items():
repo._repo.ui.setconfig('rhodecode_extras', k, v)
repo.pull(dbrepo.clone_uri)
@@ -375,13 +378,12 @@ class ScmModel(BaseModel):
def get_unread_journal(self):
return self.sa.query(UserLog).count()
def _should_invalidate(self, repo_name):
"""Looks up database for invalidation signals for this repo_name
:param repo_name:
Status change: