Show More
@@ -1,33 +1,33 b'' | |||||
1 |
------------------------------------------------ |
|
1 | ------------------------------------------------ | |
2 |
Pylons based repository management for mercurial |
|
2 | Pylons based repository management for mercurial | |
3 |
------------------------------------------------ |
|
3 | ------------------------------------------------ | |
4 |
|
||||
5 | Fully customizable, with authentication, permissions. Based on vcs library. |
|
|||
6 |
|
4 | |||
7 | **Overview** |
|
5 | **Overview** | |
8 |
|
6 | |||
9 |
- |
|
7 | - Has it's own middleware to handle mercurial protocol request. Each request can | |
10 |
be logged and authenticated |
|
8 | be logged and authenticated. Runs on threads unlikely to hgweb You can make | |
11 | - full permissions per project read/write/admin access even on mercurial request |
|
9 | multiple pulls/pushes simultaneous | |
12 | - mako templates let's you customize look and feel of application. |
|
10 | - Full permissions and authentication per project private/read/write/admin. | |
13 | - diffs annotations and source code all colored by pygments. |
|
11 | One account for web interface and mercurial push/pull/clone. | |
14 | - mercurial branch graph and yui-flot powered graphs with zooming and statistics |
|
12 | - Mako templates let's you customize look and feel of application. | |
15 | - admin interface for performing user/permission managements as well as repository |
|
13 | - Beautiful diffs, annotations and source codes all colored by pygments. | |
16 | management. |
|
14 | - Mercurial branch graph and yui-flot powered graphs with zooming and statistics | |
17 | - server side forks, it's possible to fork a project and hack it free without |
|
15 | - Admin interface with user/permission management. User activity journal logs | |
|
16 | pulls, pushes, forks,registrations. Possible to disable built in hooks | |||
|
17 | - Server side forks, it's possible to fork a project and hack it free without | |||
18 | breaking the main. |
|
18 | breaking the main. | |
19 |
- |
|
19 | - Full text search on source codes, search on file names. All powered by whoosh | |
|
20 | and build in indexing daemons | |||
20 | (no external search servers required all in one application) |
|
21 | (no external search servers required all in one application) | |
21 | - async tasks for speed and performance using celery (works without them too) |
|
22 | - Rss / atom feeds, gravatar support, download sources as zip/tarballs | |
22 | - Additional settings for mercurial web, (hooks editable from admin |
|
23 | - Async tasks for speed and performance using celery (works without them too) | |
23 | panel !) also manage paths, archive, remote messages |
|
24 | - Backup scripts can do backup of whole app and send it over scp to desired | |
24 | - backup scripts can do backup of whole app and send it over scp to desired location |
|
25 | location | |
25 |
- |
|
26 | - Setup project descriptions and info inside built in db for easy, non | |
26 | file-system operations |
|
27 | file-system operations | |
27 |
- |
|
28 | - Added cache with invalidation on push/repo management for high performance and | |
28 | always up to date data. |
|
29 | always up to date data. | |
29 | - rss / atom feeds, gravatar support |
|
30 | - Based on pylons 1.0 / sqlalchemy 0.6 / sqlite | |
30 | - based on pylons 1.0 / sqlalchemy 0.6 |
|
|||
31 |
|
31 | |||
32 | **Incoming** |
|
32 | **Incoming** | |
33 |
|
33 | |||
@@ -37,18 +37,13 b' Fully customizable, with authentication,' | |||||
37 | - clonning from remote repositories into rhodecode (git/mercurial) |
|
37 | - clonning from remote repositories into rhodecode (git/mercurial) | |
38 | - other cools stuff that i can figure out (or You can help me figure out) |
|
38 | - other cools stuff that i can figure out (or You can help me figure out) | |
39 |
|
39 | |||
40 | .. note:: |
|
40 | ------------ | |
41 | This software is still in beta mode. |
|
41 | Installation | |
42 | I don't guarantee that it'll work correctly. |
|
42 | ------------ | |
43 |
|
||||
44 |
|
43 | |||
45 | ------------- |
|
44 | **quick setup** | |
46 | Installation |
|
|||
47 | ------------- |
|
|||
48 |
|
45 | |||
49 | quick setup |
|
46 | - pip install -E rhodecode-venv rhodecode | |
50 |
|
||||
51 | - pip install -E rhodecode-venv http://bitbucket.org/marcinkuzminski/rhodecode/get/tip.zip |
|
|||
52 | - activate virtualenv |
|
47 | - activate virtualenv | |
53 | - run `paster make-config RhodeCode production.ini` |
|
48 | - run `paster make-config RhodeCode production.ini` | |
54 | - run `paster setup-app production.ini` |
|
49 | - run `paster setup-app production.ini` | |
@@ -56,8 +51,7 b' quick setup' | |||||
56 |
|
51 | |||
57 | You're ready to go. |
|
52 | You're ready to go. | |
58 |
|
53 | |||
59 |
|
54 | **MORE DETAILED INSTRUCTIONS** | ||
60 | MORE DETAILED INSTRUCTIONS |
|
|||
61 |
|
55 | |||
62 | - I highly recommend to install new virtualenv for rhodecode see |
|
56 | - I highly recommend to install new virtualenv for rhodecode see | |
63 | http://pypi.python.org/pypi/virtualenv for more details. |
|
57 | http://pypi.python.org/pypi/virtualenv for more details. | |
@@ -66,7 +60,7 b' MORE DETAILED INSTRUCTIONS' | |||||
66 | Activate the virtualenv by running |
|
60 | Activate the virtualenv by running | |
67 | `source activate /var/www/rhodecode-venv/bin/activate` |
|
61 | `source activate /var/www/rhodecode-venv/bin/activate` | |
68 | - Make a folder for rhodecode somewhere on the filesystem for example /var/www/rhodecode |
|
62 | - Make a folder for rhodecode somewhere on the filesystem for example /var/www/rhodecode | |
69 | - Run easy_install http://bitbucket.org/marcinkuzminski/rhodecode/get/tip.zip. |
|
63 | - Run easy_install rhodecode | |
70 | - Run `paster make-config RhodeCode production.inii` in order to install |
|
64 | - Run `paster make-config RhodeCode production.inii` in order to install | |
71 | the application config. You can play with the app settings later |
|
65 | the application config. You can play with the app settings later | |
72 | - Run `paster setup-app production.ini` it should create all needed tables |
|
66 | - Run `paster setup-app production.ini` it should create all needed tables | |
@@ -83,12 +77,11 b' MORE DETAILED INSTRUCTIONS' | |||||
83 | The app should gain a lot of speed and become much more responsible. |
|
77 | The app should gain a lot of speed and become much more responsible. | |
84 | For installation instructions You can visit: |
|
78 | For installation instructions You can visit: | |
85 | http://ask.github.com/celery/getting-started/index.html. |
|
79 | http://ask.github.com/celery/getting-started/index.html. | |
86 |
- All needed configs are inside rhodecode ie. celeryconfig.py |
|
80 | - All needed configs are inside rhodecode sources ie. celeryconfig.py, | |
87 |
You can configure the email, ports, loggers, |
|
81 | development.ini, production.ini You can configure the email, ports, loggers, | |
|
82 | workers from there. | |||
88 | - For full text search You can either put crontab entry for |
|
83 | - For full text search You can either put crontab entry for | |
89 | `python /var/www/rhodecode/rhodecode/lib/indexers/daemon.py incremental <path_to_repos>` |
|
84 | `python /var/www/rhodecode/rhodecode/lib/indexers/daemon.py incremental <path_to_repos>` | |
90 | or run indexer from admin panel. This will scann the repos given in the |
|
85 | or run indexer from admin panel. This will scann the repos given in the | |
91 | application setup or given path for daemon.py and each scann in incremental |
|
86 | application setup or given path for daemon.py and each scann in incremental | |
92 |
mode will scann only changed files |
|
87 | mode will scann only changed files. No newline at end of file | |
93 | Hg Update hook must be activated to index the content it's enabled by default |
|
|||
94 | after setup No newline at end of file |
|
@@ -102,7 +102,7 b' class PermissionsController(BaseControll' | |||||
102 | h.flash(_('Default permissions updated succesfully'), |
|
102 | h.flash(_('Default permissions updated succesfully'), | |
103 | category='success') |
|
103 | category='success') | |
104 |
|
104 | |||
105 |
except formencode.Invalid |
|
105 | except formencode.Invalid, errors: | |
106 | c.perms_choices = self.perms_choices |
|
106 | c.perms_choices = self.perms_choices | |
107 | c.register_choices = self.register_choices |
|
107 | c.register_choices = self.register_choices | |
108 | c.create_choices = self.create_choices |
|
108 | c.create_choices = self.create_choices |
@@ -85,7 +85,7 b' class ReposController(BaseController):' | |||||
85 |
action_logger(self.rhodecode_user, 'admin_created_repo', |
|
85 | action_logger(self.rhodecode_user, 'admin_created_repo', | |
86 | form_result['repo_name'], '', self.sa) |
|
86 | form_result['repo_name'], '', self.sa) | |
87 |
|
87 | |||
88 |
except formencode.Invalid |
|
88 | except formencode.Invalid, errors: | |
89 | c.new_repo = errors.value['repo_name'] |
|
89 | c.new_repo = errors.value['repo_name'] | |
90 |
|
90 | |||
91 | if request.POST.get('user_created'): |
|
91 | if request.POST.get('user_created'): | |
@@ -137,7 +137,7 b' class ReposController(BaseController):' | |||||
137 | h.flash(_('Repository %s updated succesfully' % repo_name), |
|
137 | h.flash(_('Repository %s updated succesfully' % repo_name), | |
138 | category='success') |
|
138 | category='success') | |
139 | changed_name = form_result['repo_name'] |
|
139 | changed_name = form_result['repo_name'] | |
140 |
except formencode.Invalid |
|
140 | except formencode.Invalid, errors: | |
141 | c.repo_info = repo_model.get(repo_name) |
|
141 | c.repo_info = repo_model.get(repo_name) | |
142 | c.users_array = repo_model.get_users_js() |
|
142 | c.users_array = repo_model.get_users_js() | |
143 | errors.value.update({'user':c.repo_info.user.username}) |
|
143 | errors.value.update({'user':c.repo_info.user.username}) | |
@@ -199,7 +199,7 b' class ReposController(BaseController):' | |||||
199 | try: |
|
199 | try: | |
200 | repo_model = RepoModel() |
|
200 | repo_model = RepoModel() | |
201 | repo_model.delete_perm_user(request.POST, repo_name) |
|
201 | repo_model.delete_perm_user(request.POST, repo_name) | |
202 |
except Exception |
|
202 | except Exception, e: | |
203 | h.flash(_('An error occured during deletion of repository user'), |
|
203 | h.flash(_('An error occured during deletion of repository user'), | |
204 | category='error') |
|
204 | category='error') | |
205 | raise HTTPInternalServerError() |
|
205 | raise HTTPInternalServerError() |
@@ -140,7 +140,7 b' class SettingsController(BaseController)' | |||||
140 | self.sa.rollback() |
|
140 | self.sa.rollback() | |
141 |
|
141 | |||
142 |
|
142 | |||
143 |
except formencode.Invalid |
|
143 | except formencode.Invalid, errors: | |
144 | return htmlfill.render( |
|
144 | return htmlfill.render( | |
145 | render('admin/settings/settings.html'), |
|
145 | render('admin/settings/settings.html'), | |
146 | defaults=errors.value, |
|
146 | defaults=errors.value, | |
@@ -193,7 +193,7 b' class SettingsController(BaseController)' | |||||
193 | self.sa.rollback() |
|
193 | self.sa.rollback() | |
194 |
|
194 | |||
195 |
|
195 | |||
196 |
except formencode.Invalid |
|
196 | except formencode.Invalid, errors: | |
197 | return htmlfill.render( |
|
197 | return htmlfill.render( | |
198 | render('admin/settings/settings.html'), |
|
198 | render('admin/settings/settings.html'), | |
199 | defaults=errors.value, |
|
199 | defaults=errors.value, | |
@@ -269,7 +269,7 b' class SettingsController(BaseController)' | |||||
269 | h.flash(_('Your account was updated succesfully'), |
|
269 | h.flash(_('Your account was updated succesfully'), | |
270 | category='success') |
|
270 | category='success') | |
271 |
|
271 | |||
272 |
except formencode.Invalid |
|
272 | except formencode.Invalid, errors: | |
273 | c.user = self.sa.query(User).get(c.rhodecode_user.user_id) |
|
273 | c.user = self.sa.query(User).get(c.rhodecode_user.user_id) | |
274 | c.user_repos = [] |
|
274 | c.user_repos = [] | |
275 | for repo in c.cached_repo_list.values(): |
|
275 | for repo in c.cached_repo_list.values(): |
@@ -73,7 +73,7 b' class UsersController(BaseController):' | |||||
73 | h.flash(_('created user %s') % form_result['username'], |
|
73 | h.flash(_('created user %s') % form_result['username'], | |
74 | category='success') |
|
74 | category='success') | |
75 | #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa) |
|
75 | #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa) | |
76 |
except formencode.Invalid |
|
76 | except formencode.Invalid, errors: | |
77 | return htmlfill.render( |
|
77 | return htmlfill.render( | |
78 | render('admin/users/user_add.html'), |
|
78 | render('admin/users/user_add.html'), | |
79 | defaults=errors.value, |
|
79 | defaults=errors.value, | |
@@ -110,7 +110,7 b' class UsersController(BaseController):' | |||||
110 | user_model.update(id, form_result) |
|
110 | user_model.update(id, form_result) | |
111 | h.flash(_('User updated succesfully'), category='success') |
|
111 | h.flash(_('User updated succesfully'), category='success') | |
112 |
|
112 | |||
113 |
except formencode.Invalid |
|
113 | except formencode.Invalid, errors: | |
114 | return htmlfill.render( |
|
114 | return htmlfill.render( | |
115 | render('admin/users/user_edit.html'), |
|
115 | render('admin/users/user_edit.html'), | |
116 | defaults=errors.value, |
|
116 | defaults=errors.value, | |
@@ -136,7 +136,7 b' class UsersController(BaseController):' | |||||
136 | try: |
|
136 | try: | |
137 | user_model.delete(id) |
|
137 | user_model.delete(id) | |
138 | h.flash(_('sucessfully deleted user'), category='success') |
|
138 | h.flash(_('sucessfully deleted user'), category='success') | |
139 |
except DefaultUserException |
|
139 | except DefaultUserException, e: | |
140 | h.flash(str(e), category='warning') |
|
140 | h.flash(str(e), category='warning') | |
141 | except Exception: |
|
141 | except Exception: | |
142 | h.flash(_('An error occured during deletion of user'), |
|
142 | h.flash(_('An error occured during deletion of user'), |
@@ -74,7 +74,7 b' class LoginController(BaseController):' | |||||
74 | else: |
|
74 | else: | |
75 | return redirect(url('hg_home')) |
|
75 | return redirect(url('hg_home')) | |
76 |
|
76 | |||
77 |
except formencode.Invalid |
|
77 | except formencode.Invalid, errors: | |
78 | return htmlfill.render( |
|
78 | return htmlfill.render( | |
79 | render('/login.html'), |
|
79 | render('/login.html'), | |
80 | defaults=errors.value, |
|
80 | defaults=errors.value, | |
@@ -105,7 +105,7 b' class LoginController(BaseController):' | |||||
105 | category='success') |
|
105 | category='success') | |
106 | return redirect(url('login_home')) |
|
106 | return redirect(url('login_home')) | |
107 |
|
107 | |||
108 |
except formencode.Invalid |
|
108 | except formencode.Invalid, errors: | |
109 | return htmlfill.render( |
|
109 | return htmlfill.render( | |
110 | render('/register.html'), |
|
110 | render('/register.html'), | |
111 | defaults=errors.value, |
|
111 | defaults=errors.value, | |
@@ -127,7 +127,7 b' class LoginController(BaseController):' | |||||
127 | category='success') |
|
127 | category='success') | |
128 | return redirect(url('login_home')) |
|
128 | return redirect(url('login_home')) | |
129 |
|
129 | |||
130 |
except formencode.Invalid |
|
130 | except formencode.Invalid, errors: | |
131 | return htmlfill.render( |
|
131 | return htmlfill.render( | |
132 | render('/password_reset.html'), |
|
132 | render('/password_reset.html'), | |
133 | defaults=errors.value, |
|
133 | defaults=errors.value, |
@@ -82,7 +82,7 b' class SettingsController(BaseController)' | |||||
82 | h.flash(_('Repository %s updated successfully' % repo_name), |
|
82 | h.flash(_('Repository %s updated successfully' % repo_name), | |
83 | category='success') |
|
83 | category='success') | |
84 | changed_name = form_result['repo_name'] |
|
84 | changed_name = form_result['repo_name'] | |
85 |
except formencode.Invalid |
|
85 | except formencode.Invalid, errors: | |
86 | c.repo_info = repo_model.get(repo_name) |
|
86 | c.repo_info = repo_model.get(repo_name) | |
87 | c.users_array = repo_model.get_users_js() |
|
87 | c.users_array = repo_model.get_users_js() | |
88 | errors.value.update({'user':c.repo_info.user.username}) |
|
88 | errors.value.update({'user':c.repo_info.user.username}) | |
@@ -162,7 +162,7 b' class SettingsController(BaseController)' | |||||
162 | category='success') |
|
162 | category='success') | |
163 | action_logger(self.rhodecode_user, 'user_forked_repo', |
|
163 | action_logger(self.rhodecode_user, 'user_forked_repo', | |
164 | repo_name, '', self.sa) |
|
164 | repo_name, '', self.sa) | |
165 |
except formencode.Invalid |
|
165 | except formencode.Invalid, errors: | |
166 | c.new_repo = errors.value['fork_name'] |
|
166 | c.new_repo = errors.value['fork_name'] | |
167 | r = render('settings/repo_fork.html') |
|
167 | r = render('settings/repo_fork.html') | |
168 |
|
168 |
@@ -85,7 +85,7 b' def get_user_cached(username):' | |||||
85 | def authfunc(environ, username, password): |
|
85 | def authfunc(environ, username, password): | |
86 | try: |
|
86 | try: | |
87 | user = get_user_cached(username) |
|
87 | user = get_user_cached(username) | |
88 |
except (NoResultFound, MultipleResultsFound, OperationalError) |
|
88 | except (NoResultFound, MultipleResultsFound, OperationalError), e: | |
89 | log.error(e) |
|
89 | log.error(e) | |
90 | user = None |
|
90 | user = None | |
91 |
|
91 |
@@ -8,8 +8,13 b' from rhodecode.lib.smtp_mailer import Sm' | |||||
8 | from rhodecode.lib.utils import OrderedDict |
|
8 | from rhodecode.lib.utils import OrderedDict | |
9 | from time import mktime |
|
9 | from time import mktime | |
10 | from vcs.backends.hg import MercurialRepository |
|
10 | from vcs.backends.hg import MercurialRepository | |
|
11 | import traceback | |||
|
12 | ||||
|
13 | try: | |||
11 | import json |
|
14 | import json | |
12 | import traceback |
|
15 | except ImportError: | |
|
16 | #python 2.5 compatibility | |||
|
17 | import simplejson as json | |||
13 |
|
18 | |||
14 | try: |
|
19 | try: | |
15 | from celeryconfig import PYLONS_CONFIG as config |
|
20 | from celeryconfig import PYLONS_CONFIG as config |
@@ -1,5 +1,6 b'' | |||||
1 | from rhodecode import get_version |
|
1 | from rhodecode import get_version | |
2 | import sys |
|
2 | import sys | |
|
3 | py_version = sys.version_info | |||
3 |
|
4 | |||
4 | requirements = [ |
|
5 | requirements = [ | |
5 | "Pylons>=1.0.0", |
|
6 | "Pylons>=1.0.0", | |
@@ -9,12 +10,15 b' requirements = [' | |||||
9 | "vcs>=0.1.7", |
|
10 | "vcs>=0.1.7", | |
10 | "pygments>=1.3.0", |
|
11 | "pygments>=1.3.0", | |
11 | "mercurial>=1.6", |
|
12 | "mercurial>=1.6", | |
12 | "pysqlite", |
|
|||
13 | "whoosh==1.0.0", |
|
13 | "whoosh==1.0.0", | |
14 | "py-bcrypt", |
|
14 | "py-bcrypt", | |
15 | "celery", |
|
15 | "celery", | |
16 | ] |
|
16 | ] | |
17 |
|
17 | |||
|
18 | if sys.version_info < (2, 6): | |||
|
19 | requirements.append("simplejson") | |||
|
20 | requirements.append("pysqlite") | |||
|
21 | ||||
18 | #additional files from project that goes somewhere in the filesystem |
|
22 | #additional files from project that goes somewhere in the filesystem | |
19 | #relative to sys.prefix |
|
23 | #relative to sys.prefix | |
20 | data_files = [] |
|
24 | data_files = [] |
General Comments 0
You need to be logged in to leave comments.
Login now