# HG changeset patch # User Marcin Kuzminski # Date 2012-06-15 00:08:06 # Node ID 1f9c467e01ebc42e04fbfea054a6f61947e90d79 # Parent 4753a3445ff739fa895806a96f3b64dc4078eb8b # Parent 015a42e970a69c7439c32f7f165cb5b66553a0a8 merge with beta diff --git a/docs/changelog.rst b/docs/changelog.rst --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -50,6 +50,7 @@ fixes - fixed issue #459. Changed the way of obtaining logger in reindex task. - fixed #453 added ID field in whoosh SCHEMA that solves the issue of reindexing modified files +- fixes #481 rhodecode emails are sent without Date header 1.3.6 (**2012-05-17**) ---------------------- diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py --- a/rhodecode/controllers/admin/repos.py +++ b/rhodecode/controllers/admin/repos.py @@ -70,6 +70,8 @@ class ReposController(BaseController): repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() + choices, c.landing_revs = ScmModel().get_repo_landing_revs() + c.landing_revs_choices = choices def __load_data(self, repo_name=None): """ @@ -91,6 +93,9 @@ class ReposController(BaseController): return redirect(url('repos')) + choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info) + c.landing_revs_choices = choices + c.default_user_id = User.get_by_username('default').user_id c.in_public_journal = UserFollowing.query()\ .filter(UserFollowing.user_id == c.default_user_id)\ @@ -116,6 +121,7 @@ class ReposController(BaseController): c.repos_list = [('', _('--REMOVE FORK--'))] c.repos_list += [(x.repo_id, x.repo_name) for x in Repository.query().order_by(Repository.repo_name).all()] + return defaults @HasPermissionAllDecorator('hg.admin') @@ -137,7 +143,8 @@ class ReposController(BaseController): self.__load_defaults() form_result = {} try: - form_result = RepoForm(repo_groups=c.repo_groups_choices)()\ + form_result = RepoForm(repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)()\ .to_python(dict(request.POST)) RepoModel().create(form_result, self.rhodecode_user) if form_result['clone_uri']: @@ -205,7 +212,8 @@ class ReposController(BaseController): repo_model = RepoModel() changed_name = repo_name _form = RepoForm(edit=True, old_data={'repo_name': repo_name}, - repo_groups=c.repo_groups_choices)() + repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)() try: form_result = _form.to_python(dict(request.POST)) repo = repo_model.update(repo_name, form_result) diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -397,6 +397,7 @@ class SettingsController(BaseController) c.repo_groups = RepoGroup.groups_choices() c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) + c.landing_revs = ScmModel().get_repo_landing_revs() new_repo = request.GET.get('repo', '') c.new_repo = repo_name_slug(new_repo) diff --git a/rhodecode/controllers/files.py b/rhodecode/controllers/files.py --- a/rhodecode/controllers/files.py +++ b/rhodecode/controllers/files.py @@ -61,7 +61,7 @@ log = logging.getLogger(__name__) class FilesController(BaseRepoController): - @LoginRequired() + def __before__(self): super(FilesController, self).__before__() c.cut_off_limit = self.cut_off_limit @@ -113,6 +113,7 @@ class FilesController(BaseRepoController return file_node + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def index(self, repo_name, revision, f_path, annotate=False): @@ -154,9 +155,14 @@ class FilesController(BaseRepoController c.file = c.changeset.get_node(f_path) if c.file.is_file(): - c.file_history = self._get_node_history(c.changeset, f_path) + _hist = c.changeset.get_file_history(f_path) + c.file_history = self._get_node_history(c.changeset, f_path, + _hist) + c.authors = [] + for a in set([x.author for x in _hist]): + c.authors.append((h.email(a), h.person(a))) else: - c.file_history = [] + c.authors = c.file_history = [] except RepositoryError, e: h.flash(str(e), category='warning') redirect(h.url('files_home', repo_name=repo_name, @@ -164,6 +170,7 @@ class FilesController(BaseRepoController return render('files/files.html') + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def rawfile(self, repo_name, revision, f_path): @@ -176,6 +183,7 @@ class FilesController(BaseRepoController response.content_type = file_node.mimetype return file_node.content + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def raw(self, repo_name, revision, f_path): @@ -222,6 +230,7 @@ class FilesController(BaseRepoController response.content_type = mimetype return file_node.content + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') def edit(self, repo_name, revision, f_path): r_post = request.POST @@ -271,6 +280,7 @@ class FilesController(BaseRepoController return render('files/files_edit.html') + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') def add(self, repo_name, revision, f_path): r_post = request.POST @@ -325,6 +335,7 @@ class FilesController(BaseRepoController return render('files/files_add.html') + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def archivefile(self, repo_name, fname): @@ -382,6 +393,7 @@ class FilesController(BaseRepoController response.content_type = str(content_type) return get_chunked_archive(archive) + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def diff(self, repo_name, f_path): @@ -454,8 +466,9 @@ class FilesController(BaseRepoController return render('files/file_diff.html') - def _get_node_history(self, cs, f_path): - changesets = cs.get_file_history(f_path) + def _get_node_history(self, cs, f_path, changesets=None): + if changesets is None: + changesets = cs.get_file_history(f_path) hist_l = [] changesets_group = ([], _("Changesets")) @@ -479,9 +492,10 @@ class FilesController(BaseRepoController return hist_l - @jsonify + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') + @jsonify def nodelist(self, repo_name, revision, f_path): if request.environ.get('HTTP_X_PARTIAL_XHR'): cs = self.__get_cs_or_redirect(revision, repo_name) diff --git a/rhodecode/controllers/settings.py b/rhodecode/controllers/settings.py --- a/rhodecode/controllers/settings.py +++ b/rhodecode/controllers/settings.py @@ -43,6 +43,7 @@ from rhodecode.model.forms import RepoSe from rhodecode.model.repo import RepoModel from rhodecode.model.db import RepoGroup from rhodecode.model.meta import Session +from rhodecode.model.scm import ScmModel log = logging.getLogger(__name__) @@ -60,6 +61,8 @@ class SettingsController(BaseRepoControl repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() + choices, c.landing_revs = ScmModel().get_repo_landing_revs() + c.landing_revs_choices = choices @HasRepoPermissionAllDecorator('repository.admin') def index(self, repo_name): @@ -94,7 +97,8 @@ class SettingsController(BaseRepoControl _form = RepoSettingsForm(edit=True, old_data={'repo_name': repo_name}, - repo_groups=c.repo_groups_choices)() + repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)() try: form_result = _form.to_python(dict(request.POST)) diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -460,8 +460,9 @@ class LoginRequired(object): loc = "%s:%s" % (cls.__class__.__name__, func.__name__) log.debug('Checking if %s is authenticated @ %s' % (user.username, loc)) if user.is_authenticated or api_access_ok: - log.info('user %s is authenticated and granted access to %s' % ( - user.username, loc) + reason = 'RegularAuth' if user.is_authenticated else 'APIAuth' + log.info('user %s is authenticated and granted access to %s ' + 'using %s' % (user.username, loc, reason) ) return func(*fargs, **fkwargs) else: diff --git a/rhodecode/lib/rcmail/message.py b/rhodecode/lib/rcmail/message.py --- a/rhodecode/lib/rcmail/message.py +++ b/rhodecode/lib/rcmail/message.py @@ -3,6 +3,7 @@ from rhodecode.lib.rcmail.response impor from rhodecode.lib.rcmail.exceptions import BadHeaders from rhodecode.lib.rcmail.exceptions import InvalidMessage + class Attachment(object): """ Encapsulates file attachment information. @@ -134,13 +135,13 @@ class Message(object): """ if not self.recipients: - raise InvalidMessage, "No recipients have been added" + raise InvalidMessage("No recipients have been added") if not self.body and not self.html: - raise InvalidMessage, "No body has been set" + raise InvalidMessage("No body has been set") if not self.sender: - raise InvalidMessage, "No sender address has been set" + raise InvalidMessage("No sender address has been set") if self.is_bad_headers(): raise BadHeaders diff --git a/rhodecode/lib/rcmail/response.py b/rhodecode/lib/rcmail/response.py --- a/rhodecode/lib/rcmail/response.py +++ b/rhodecode/lib/rcmail/response.py @@ -364,6 +364,7 @@ def to_message(mail, separator="; "): return out + class MIMEPart(MIMEBase): """ A reimplementation of nearly everything in email.mime to be more useful @@ -387,7 +388,8 @@ class MIMEPart(MIMEBase): self.set_payload(encoded, charset=charset) def extract_payload(self, mail): - if mail.body == None: return # only None, '' is still ok + if mail.body == None: + return # only None, '' is still ok ctype, ctype_params = mail.content_encoding['Content-Type'] cdisp, cdisp_params = mail.content_encoding['Content-Disposition'] @@ -415,7 +417,8 @@ class MIMEPart(MIMEBase): def header_to_mime_encoding(value, not_email=False, separator=", "): - if not value: return "" + if not value: + return "" encoder = Charset(DEFAULT_ENCODING) if type(value) == list: @@ -424,6 +427,7 @@ def header_to_mime_encoding(value, not_e else: return properly_encode_header(value, encoder, not_email) + def properly_encode_header(value, encoder, not_email): """ The only thing special (weird) about this function is that it tries diff --git a/rhodecode/lib/rcmail/smtp_mailer.py b/rhodecode/lib/rcmail/smtp_mailer.py --- a/rhodecode/lib/rcmail/smtp_mailer.py +++ b/rhodecode/lib/rcmail/smtp_mailer.py @@ -21,10 +21,11 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - +import time import logging import smtplib from socket import sslerror +from email.utils import formatdate from rhodecode.lib.rcmail.message import Message @@ -59,8 +60,11 @@ class SmtpMailer(object): if isinstance(recipients, basestring): recipients = [recipients] + headers = { + 'Date': formatdate(time.time()) + } msg = Message(subject, recipients, body, html, self.mail_from, - recipients_separator=", ") + recipients_separator=", ", extra_headers=headers) raw_msg = msg.to_message() if self.ssl: diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py --- a/rhodecode/lib/utils.py +++ b/rhodecode/lib/utils.py @@ -448,7 +448,8 @@ def repo2db_mapper(initial_repo_list, re 'description': repo.description \ if repo.description != 'unknown' else '%s repository' % name, 'private': False, - 'group_id': getattr(group, 'group_id', None) + 'group_id': getattr(group, 'group_id', None), + 'landing_rev': repo.DEFAULT_BRANCH_NAME } rm.create(form_data, user, just_db=True) sa.commit() @@ -558,7 +559,7 @@ def create_test_env(repos_test_path, con install test repository into tmp dir """ from rhodecode.lib.db_manage import DbManage - from rhodecode.tests import HG_REPO, TESTS_TMP_PATH + from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH # PART ONE create db dbconf = config['sqlalchemy.db1.url'] @@ -593,12 +594,21 @@ def create_test_env(repos_test_path, con log.debug('remove %s' % data_path) shutil.rmtree(data_path) - #CREATE DEFAULT HG REPOSITORY + #CREATE DEFAULT TEST REPOS cur_dir = dn(dn(abspath(__file__))) tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz")) tar.extractall(jn(TESTS_TMP_PATH, HG_REPO)) tar.close() + cur_dir = dn(dn(abspath(__file__))) + tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz")) + tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO)) + tar.close() + + #LOAD VCS test stuff + from rhodecode.tests.vcs import setup_package + setup_package() + #============================================================================== # PASTER COMMANDS diff --git a/rhodecode/lib/vcs/backends/git/changeset.py b/rhodecode/lib/vcs/backends/git/changeset.py --- a/rhodecode/lib/vcs/backends/git/changeset.py +++ b/rhodecode/lib/vcs/backends/git/changeset.py @@ -259,10 +259,11 @@ class GitChangeset(BaseChangeset): # --root ==> doesn't put '^' character for bounderies # -r sha ==> blames for the given revision so, se = self.repository.run_git_command(cmd) + annotate = [] for i, blame_line in enumerate(so.split('\n')[:-1]): ln_no = i + 1 - id, line = re.split(r' \(.+?\) ', blame_line, 1) + id, line = re.split(r' ', blame_line, 1) annotate.append((ln_no, self.repository.get_changeset(id), line)) return annotate diff --git a/rhodecode/lib/vcs/backends/git/inmemory.py b/rhodecode/lib/vcs/backends/git/inmemory.py --- a/rhodecode/lib/vcs/backends/git/inmemory.py +++ b/rhodecode/lib/vcs/backends/git/inmemory.py @@ -83,7 +83,8 @@ class GitInMemoryChangeset(BaseInMemoryC curtree = newtree parent[reversed_dirnames[-1]] = DIRMOD, curtree.id else: - parent.add(node.mode, node_path, blob.id) + parent.add(name=node_path, mode=node.mode, hexsha=blob.id) + new_trees.append(parent) # Update ancestors for parent, tree, path in reversed([(a[1], b[1], b[0]) for a, b in @@ -123,7 +124,7 @@ class GitInMemoryChangeset(BaseInMemoryC commit.parents = [p._commit.id for p in self.parents if p] commit.author = commit.committer = safe_str(author) commit.encoding = ENCODING - commit.message = safe_str(message) + ' ' + commit.message = safe_str(message) # Compute date if date is None: diff --git a/rhodecode/lib/vcs/backends/git/repository.py b/rhodecode/lib/vcs/backends/git/repository.py --- a/rhodecode/lib/vcs/backends/git/repository.py +++ b/rhodecode/lib/vcs/backends/git/repository.py @@ -192,7 +192,11 @@ class GitRepository(BaseRepository): "for this repository %s" % (revision, self)) elif is_bstr(revision): - if not pattern.match(revision) or revision not in self.revisions: + _ref_revision = self._parsed_refs.get(revision) + if _ref_revision: # and _ref_revision[1] in ['H', 'RH', 'T']: + return _ref_revision[0] + + elif not pattern.match(revision) or revision not in self.revisions: raise ChangesetDoesNotExistError("Revision %r does not exist " "for this repository %s" % (revision, self)) @@ -267,18 +271,9 @@ class GitRepository(BaseRepository): if ref.startswith('refs/heads/') and not ref.endswith('/HEAD')] return OrderedDict(sorted(_branches, key=sortkey, reverse=False)) - def _heads(self, reverse=False): - refs = self._repo.get_refs() - heads = {} - - for key, val in refs.items(): - for ref_key in ['refs/heads/', 'refs/remotes/origin/']: - if key.startswith(ref_key): - n = key[len(ref_key):] - if n not in ['HEAD']: - heads[n] = val - - return heads if reverse else dict((y,x) for x,y in heads.iteritems()) + @LazyProperty + def tags(self): + return self._get_tags() def _get_tags(self): if not self.revisions: @@ -288,10 +283,6 @@ class GitRepository(BaseRepository): self._repo.get_refs().items() if ref.startswith('refs/tags/')] return OrderedDict(sorted(_tags, key=sortkey, reverse=True)) - @LazyProperty - def tags(self): - return self._get_tags() - def tag(self, name, user, revision=None, message=None, date=None, **kwargs): """ @@ -335,6 +326,34 @@ class GitRepository(BaseRepository): except OSError, e: raise RepositoryError(e.strerror) + @LazyProperty + def _parsed_refs(self): + refs = self._repo.get_refs() + keys = [('refs/heads/', 'H'), + ('refs/remotes/origin/', 'RH'), + ('refs/tags/', 'T')] + _refs = {} + for ref, sha in refs.iteritems(): + for k, type_ in keys: + if ref.startswith(k): + _key = ref[len(k):] + _refs[_key] = [sha, type_] + break + return _refs + + def _heads(self, reverse=False): + refs = self._repo.get_refs() + heads = {} + + for key, val in refs.items(): + for ref_key in ['refs/heads/', 'refs/remotes/origin/']: + if key.startswith(ref_key): + n = key[len(ref_key):] + if n not in ['HEAD']: + heads[n] = val + + return heads if reverse else dict((y, x) for x, y in heads.iteritems()) + def get_changeset(self, revision=None): """ Returns ``GitChangeset`` object representing commit from git repository diff --git a/rhodecode/lib/vcs/backends/hg/inmemory.py b/rhodecode/lib/vcs/backends/hg/inmemory.py --- a/rhodecode/lib/vcs/backends/hg/inmemory.py +++ b/rhodecode/lib/vcs/backends/hg/inmemory.py @@ -32,7 +32,8 @@ class MercurialInMemoryChangeset(BaseInM from .repository import MercurialRepository if not isinstance(message, unicode) or not isinstance(author, unicode): raise RepositoryError('Given message and author needs to be ' - 'an instance') + 'an instance got %r & %r instead' + % (type(message), type(author))) if branch is None: branch = MercurialRepository.DEFAULT_BRANCH_NAME diff --git a/rhodecode/lib/vcs/nodes.py b/rhodecode/lib/vcs/nodes.py --- a/rhodecode/lib/vcs/nodes.py +++ b/rhodecode/lib/vcs/nodes.py @@ -422,7 +422,7 @@ class FileNode(Node): def __repr__(self): return '<%s %r @ %s>' % (self.__class__.__name__, self.path, - self.changeset.short_id) + getattr(self.changeset, 'short_id', '')) class RemovedFileNode(FileNode): @@ -559,7 +559,7 @@ class DirNode(Node): def __repr__(self): return '<%s %r @ %s>' % (self.__class__.__name__, self.path, - self.changeset.short_id) + getattr(self.changeset, 'short_id', '')) class RootNode(DirNode): @@ -593,7 +593,7 @@ class SubModuleNode(Node): def __repr__(self): return '<%s %r @ %s>' % (self.__class__.__name__, self.path, - self.changeset.short_id) + getattr(self.changeset, 'short_id', '')) def _extract_submodule_url(self): if self.alias == 'git': diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -299,7 +299,7 @@ class User(Base, BaseModel): password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) active = Column("active", Boolean(), nullable=True, unique=None, default=None) admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) - name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + name = Column("firstname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) @@ -551,13 +551,14 @@ class Repository(Base, BaseModel): repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None) - repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg') + repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None) user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) private = Column("private", Boolean(), nullable=True, unique=None, default=None) enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True) description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now) + landing_rev = Column("landing_revision", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None) fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None) diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py --- a/rhodecode/model/forms.py +++ b/rhodecode/model/forms.py @@ -653,7 +653,7 @@ def PasswordResetForm(): def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(), - repo_groups=[]): + repo_groups=[], landing_revs=[]): class _RepoForm(formencode.Schema): allow_extra_fields = True filter_extra_fields = False @@ -662,10 +662,11 @@ def RepoForm(edit=False, old_data={}, su clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False)) repo_group = OneOf(repo_groups, hideList=True) repo_type = OneOf(supported_backends) - description = UnicodeString(strip=True, min=1, not_empty=True) + description = UnicodeString(strip=True, min=1, not_empty=False) private = StringBoolean(if_missing=False) enable_statistics = StringBoolean(if_missing=False) enable_downloads = StringBoolean(if_missing=False) + landing_rev = OneOf(landing_revs, hideList=True) if edit: #this is repo owner @@ -697,7 +698,7 @@ def RepoForkForm(edit=False, old_data={} def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(), - repo_groups=[]): + repo_groups=[], landing_revs=[]): class _RepoForm(formencode.Schema): allow_extra_fields = True filter_extra_fields = False @@ -706,7 +707,7 @@ def RepoSettingsForm(edit=False, old_dat description = UnicodeString(strip=True, min=1, not_empty=True) repo_group = OneOf(repo_groups, hideList=True) private = StringBoolean(if_missing=False) - + landing_rev = OneOf(landing_revs, hideList=True) chained_validators = [ValidRepoName(edit, old_data), ValidPerms(), ValidSettings] return _RepoForm diff --git a/rhodecode/model/scm.py b/rhodecode/model/scm.py --- a/rhodecode/model/scm.py +++ b/rhodecode/model/scm.py @@ -29,6 +29,7 @@ import logging import cStringIO from sqlalchemy import func +from pylons.i18n.translation import _ from rhodecode.lib.vcs import get_backend from rhodecode.lib.vcs.exceptions import RepositoryError @@ -474,3 +475,40 @@ class ScmModel(BaseModel): def get_unread_journal(self): return self.sa.query(UserLog).count() + + def get_repo_landing_revs(self, repo=None): + """ + Generates select option with tags branches and bookmarks (for hg only) + grouped by type + + :param repo: + :type repo: + """ + + hist_l = [] + choices = [] + repo = self.__get_repo(repo) + hist_l.append(['tip', _('latest tip')]) + choices.append('tip') + if not repo: + return choices, hist_l + + repo = repo.scm_instance + + branches_group = ([(k, k) for k, v in + repo.branches.iteritems()], _("Branches")) + hist_l.append(branches_group) + choices.extend([x[0] for x in branches_group[0]]) + + if repo.alias == 'hg': + bookmarks_group = ([(k, k) for k, v in + repo.bookmarks.iteritems()], _("Bookmarks")) + hist_l.append(bookmarks_group) + choices.extend([x[0] for x in bookmarks_group[0]]) + + tags_group = ([(k, k) for k, v in + repo.tags.iteritems()], _("Tags")) + hist_l.append(tags_group) + choices.extend([x[0] for x in tags_group[0]]) + + return choices, hist_l diff --git a/rhodecode/public/css/style.css b/rhodecode/public/css/style.css --- a/rhodecode/public/css/style.css +++ b/rhodecode/public/css/style.css @@ -2252,6 +2252,20 @@ h3.files_location { padding: 5px !important; } +.file_history{ + padding-top:10px; + font-size:16px; +} +.file_author{ + float: left; +} + +.file_author .item{ + float:left; + padding:5px; + color: #888; +} + .tablerow0 { background-color: #F8F8F8; } diff --git a/rhodecode/templates/admin/repos/repo_add_base.html b/rhodecode/templates/admin/repos/repo_add_base.html --- a/rhodecode/templates/admin/repos/repo_add_base.html +++ b/rhodecode/templates/admin/repos/repo_add_base.html @@ -42,6 +42,15 @@ ${h.form(url('repos'))} ${_('Type of repository to create.')} +
+
+ +
+
+ ${h.select('landing_rev','',c.landing_revs,class_="medium")} + ${_('Default revision for files page, downloads, whoosh and readme')} +
+
diff --git a/rhodecode/templates/admin/repos/repo_edit.html b/rhodecode/templates/admin/repos/repo_edit.html --- a/rhodecode/templates/admin/repos/repo_edit.html +++ b/rhodecode/templates/admin/repos/repo_edit.html @@ -62,6 +62,15 @@
+
+ +
+
+ ${h.select('landing_rev','',c.landing_revs,class_="medium")} + ${_('Default revision for files page, downloads, whoosh and readme')} +
+
+
@@ -210,7 +219,7 @@
${h.end_form()} -

${_('Set as fork')}

+

${_('Set as fork of')}

${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
@@ -219,7 +228,7 @@
    -
  • ${_('''Manually set this repository as a fork of another''')}
  • +
  • ${_('''Manually set this repository as a fork of another from the list''')}
diff --git a/rhodecode/templates/admin/users/user_edit.html b/rhodecode/templates/admin/users/user_edit.html --- a/rhodecode/templates/admin/users/user_edit.html +++ b/rhodecode/templates/admin/users/user_edit.html @@ -162,7 +162,7 @@
%for section in sorted(c.perm_user.permissions.keys()):
${section.replace("_"," ").capitalize()}
- +
@@ -202,7 +202,7 @@
%endfor -
+
diff --git a/rhodecode/templates/base/root.html b/rhodecode/templates/base/root.html --- a/rhodecode/templates/base/root.html +++ b/rhodecode/templates/base/root.html @@ -45,7 +45,7 @@ 'Group':"${_('Group')}", 'members':"${_('members')}", 'search truncated': "${_('search truncated')}", - 'no matching files': "${_('no matching files')}" + 'no matching files': "${_('no matching files')}" }; var _TM = TRANSLATION_MAP; diff --git a/rhodecode/templates/changeset/changeset_range.html b/rhodecode/templates/changeset/changeset_range.html --- a/rhodecode/templates/changeset/changeset_range.html +++ b/rhodecode/templates/changeset/changeset_range.html @@ -69,7 +69,7 @@ ##${comment.comment_inline_form(cs)} ## diff block

${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))}

- + ${diff_block.diff_block(c.changes[cs.raw_id])} ##${comment.comments(cs)} diff --git a/rhodecode/templates/files/files_source.html b/rhodecode/templates/files/files_source.html --- a/rhodecode/templates/files/files_source.html +++ b/rhodecode/templates/files/files_source.html @@ -1,15 +1,27 @@
-
${_('History')}
+
${_('History')}
-
- ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} - ${h.hidden('diff2',c.file.changeset.raw_id)} - ${h.select('diff1',c.file.changeset.raw_id,c.file_history)} - ${h.submit('diff','diff to revision',class_="ui-btn")} - ${h.submit('show_rev','show at revision',class_="ui-btn")} - ${h.end_form()} -
+
+
+ ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} + ${h.hidden('diff2',c.file.changeset.raw_id)} + ${h.select('diff1',c.file.changeset.raw_id,c.file_history)} + ${h.submit('diff',_('diff to revision'),class_="ui-btn")} + ${h.submit('show_rev',_('show at revision'),class_="ui-btn")} + ${h.end_form()} +
+
+
${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('%s' % len(c.authors))) }
+ %for email, user in c.authors: +
+
gravatar
+
+ %endfor +
+
+
+
diff --git a/rhodecode/templates/index_base.html b/rhodecode/templates/index_base.html --- a/rhodecode/templates/index_base.html +++ b/rhodecode/templates/index_base.html @@ -119,7 +119,7 @@