##// END OF EJS Templates
merged bugfixes for rhodecode 1.1.2 release
marcink -
r939:c165349f default
parent child Browse files
Show More
@@ -1,136 +1,151 b''
1 .. _changelog:
1 .. _changelog:
2
2
3 Changelog
3 Changelog
4 =========
4 =========
5
5
6 1.1.1 (**2011-01-06**)
6 1.1.1 (**2011-01-06**)
7 ======================
7 ======================
8
8
9 news
9 news
10 ----
10 ----
11
11
12 - added force https option into ini files for easier https usage (no need to
12 - added force https option into ini files for easier https usage (no need to
13 set server headers with this options)
13 set server headers with this options)
14 - small css updates
14 - small css updates
15
15
16 fixes
16 fixes
17 -----
17 -----
18
18
19 - fixed #96 redirect loop on files view on repositories without changesets
19 - fixed #96 redirect loop on files view on repositories without changesets
20 - fixed #97 unicode string passed into server header in special cases (mod_wsgi)
20 - fixed #97 unicode string passed into server header in special cases (mod_wsgi)
21 and server crashed with errors
21 and server crashed with errors
22 - fixed large tooltips problems on main page
22 - fixed large tooltips problems on main page
23 - fixed #92 whoosh indexer is more error proof
23 - fixed #92 whoosh indexer is more error proof
24
24
25 1.1.2 (**2011-01-12**)
26 ======================
27
28 news
29 ----
30
31
32 fixes
33 -----
34
35 - fixes #98 protection against float division of percentage stats
36 - fixed graph bug
37 - forced webhelpers version since it was making troubles during installation
38
39
25 1.1.0 (**2010-12-18**)
40 1.1.0 (**2010-12-18**)
26 ======================
41 ======================
27
42
28 news
43 news
29 ----
44 ----
30
45
31 - rewrite of internals for vcs >=0.1.10
46 - rewrite of internals for vcs >=0.1.10
32 - uses mercurial 1.7 with dotencode disabled for maintaining compatibility
47 - uses mercurial 1.7 with dotencode disabled for maintaining compatibility
33 with older clients
48 with older clients
34 - anonymous access, authentication via ldap
49 - anonymous access, authentication via ldap
35 - performance upgrade for cached repos list - each repository has it's own
50 - performance upgrade for cached repos list - each repository has it's own
36 cache that's invalidated when needed.
51 cache that's invalidated when needed.
37 - performance upgrades on repositories with large amount of commits (20K+)
52 - performance upgrades on repositories with large amount of commits (20K+)
38 - main page quick filter for filtering repositories
53 - main page quick filter for filtering repositories
39 - user dashboards with ability to follow chosen repositories actions
54 - user dashboards with ability to follow chosen repositories actions
40 - sends email to admin on new user registration
55 - sends email to admin on new user registration
41 - added cache/statistics reset options into repository settings
56 - added cache/statistics reset options into repository settings
42 - more detailed action logger (based on hooks) with pushed changesets lists
57 - more detailed action logger (based on hooks) with pushed changesets lists
43 and options to disable those hooks from admin panel
58 and options to disable those hooks from admin panel
44 - introduced new enhanced changelog for merges that shows more accurate results
59 - introduced new enhanced changelog for merges that shows more accurate results
45 - new improved and faster code stats (based on pygments lexers mapping tables,
60 - new improved and faster code stats (based on pygments lexers mapping tables,
46 showing up to 10 trending sources for each repository. Additionally stats
61 showing up to 10 trending sources for each repository. Additionally stats
47 can be disabled in repository settings.
62 can be disabled in repository settings.
48 - gui optimizations, fixed application width to 1024px
63 - gui optimizations, fixed application width to 1024px
49 - added cut off (for large files/changesets) limit into config files
64 - added cut off (for large files/changesets) limit into config files
50 - whoosh, celeryd, upgrade moved to paster command
65 - whoosh, celeryd, upgrade moved to paster command
51 - other than sqlite database backends can be used
66 - other than sqlite database backends can be used
52
67
53 fixes
68 fixes
54 -----
69 -----
55
70
56 - fixes #61 forked repo was showing only after cache expired
71 - fixes #61 forked repo was showing only after cache expired
57 - fixes #76 no confirmation on user deletes
72 - fixes #76 no confirmation on user deletes
58 - fixes #66 Name field misspelled
73 - fixes #66 Name field misspelled
59 - fixes #72 block user removal when he owns repositories
74 - fixes #72 block user removal when he owns repositories
60 - fixes #69 added password confirmation fields
75 - fixes #69 added password confirmation fields
61 - fixes #87 RhodeCode crashes occasionally on updating repository owner
76 - fixes #87 RhodeCode crashes occasionally on updating repository owner
62 - fixes #82 broken annotations on files with more than 1 blank line at the end
77 - fixes #82 broken annotations on files with more than 1 blank line at the end
63 - a lot of fixes and tweaks for file browser
78 - a lot of fixes and tweaks for file browser
64 - fixed detached session issues
79 - fixed detached session issues
65 - fixed when user had no repos he would see all repos listed in my account
80 - fixed when user had no repos he would see all repos listed in my account
66 - fixed ui() instance bug when global hgrc settings was loaded for server
81 - fixed ui() instance bug when global hgrc settings was loaded for server
67 instance and all hgrc options were merged with our db ui() object
82 instance and all hgrc options were merged with our db ui() object
68 - numerous small bugfixes
83 - numerous small bugfixes
69
84
70 (special thanks for TkSoh for detailed feedback)
85 (special thanks for TkSoh for detailed feedback)
71
86
72
87
73 1.0.2 (**2010-11-12**)
88 1.0.2 (**2010-11-12**)
74 ======================
89 ======================
75
90
76 news
91 news
77 ----
92 ----
78
93
79 - tested under python2.7
94 - tested under python2.7
80 - bumped sqlalchemy and celery versions
95 - bumped sqlalchemy and celery versions
81
96
82 fixes
97 fixes
83 -----
98 -----
84
99
85 - fixed #59 missing graph.js
100 - fixed #59 missing graph.js
86 - fixed repo_size crash when repository had broken symlinks
101 - fixed repo_size crash when repository had broken symlinks
87 - fixed python2.5 crashes.
102 - fixed python2.5 crashes.
88
103
89
104
90 1.0.1 (**2010-11-10**)
105 1.0.1 (**2010-11-10**)
91 ======================
106 ======================
92
107
93 news
108 news
94 ----
109 ----
95
110
96 - small css updated
111 - small css updated
97
112
98 fixes
113 fixes
99 -----
114 -----
100
115
101 - fixed #53 python2.5 incompatible enumerate calls
116 - fixed #53 python2.5 incompatible enumerate calls
102 - fixed #52 disable mercurial extension for web
117 - fixed #52 disable mercurial extension for web
103 - fixed #51 deleting repositories don't delete it's dependent objects
118 - fixed #51 deleting repositories don't delete it's dependent objects
104
119
105
120
106 1.0.0 (**2010-11-02**)
121 1.0.0 (**2010-11-02**)
107 ======================
122 ======================
108
123
109 - security bugfix simplehg wasn't checking for permissions on commands
124 - security bugfix simplehg wasn't checking for permissions on commands
110 other than pull or push.
125 other than pull or push.
111 - fixed doubled messages after push or pull in admin journal
126 - fixed doubled messages after push or pull in admin journal
112 - templating and css corrections, fixed repo switcher on chrome, updated titles
127 - templating and css corrections, fixed repo switcher on chrome, updated titles
113 - admin menu accessible from options menu on repository view
128 - admin menu accessible from options menu on repository view
114 - permissions cached queries
129 - permissions cached queries
115
130
116 1.0.0rc4 (**2010-10-12**)
131 1.0.0rc4 (**2010-10-12**)
117 ==========================
132 ==========================
118
133
119 - fixed python2.5 missing simplejson imports (thanks to Jens BΓ€ckman)
134 - fixed python2.5 missing simplejson imports (thanks to Jens BΓ€ckman)
120 - removed cache_manager settings from sqlalchemy meta
135 - removed cache_manager settings from sqlalchemy meta
121 - added sqlalchemy cache settings to ini files
136 - added sqlalchemy cache settings to ini files
122 - validated password length and added second try of failure on paster setup-app
137 - validated password length and added second try of failure on paster setup-app
123 - fixed setup database destroy prompt even when there was no db
138 - fixed setup database destroy prompt even when there was no db
124
139
125
140
126 1.0.0rc3 (**2010-10-11**)
141 1.0.0rc3 (**2010-10-11**)
127 =========================
142 =========================
128
143
129 - fixed i18n during installation.
144 - fixed i18n during installation.
130
145
131 1.0.0rc2 (**2010-10-11**)
146 1.0.0rc2 (**2010-10-11**)
132 =========================
147 =========================
133
148
134 - Disabled dirsize in file browser, it's causing nasty bug when dir renames
149 - Disabled dirsize in file browser, it's causing nasty bug when dir renames
135 occure. After vcs is fixed it'll be put back again.
150 occure. After vcs is fixed it'll be put back again.
136 - templating/css rewrites, optimized css. No newline at end of file
151 - templating/css rewrites, optimized css.
@@ -1,99 +1,99 b''
1 .. _installation:
1 .. _installation:
2
2
3 Installation
3 Installation
4 ============
4 ============
5
5
6 ``RhodeCode`` is written entirely in Python, but in order to use it's full
6 ``RhodeCode`` is written entirely in Python, but in order to use it's full
7 potential there are some third-party requirements. When RhodeCode is used
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 recommended one is rabbitmq_ to make the async tasks work.
9 recommended one is rabbitmq_ to make the async tasks work.
10
10
11 Of course RhodeCode works in sync mode also, then You don't have to install
11 Of course RhodeCode works in sync mode also, then You don't have to install
12 any third party apps. Celery_ will give You large speed improvement when using
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 7 or 10 small repositories, it
13 many big repositories. If You plan to use it for 7 or 10 small repositories, it
14 will work just fine without celery running.
14 will work just fine without celery running.
15
15
16 After You decide to Run it with celery make sure You run celeryd using paster
16 After You decide to Run it with celery make sure You run celeryd using paster
17 and message broker together with the application.
17 and message broker together with the application.
18
18
19 Install from Cheese Shop
19 Install from Cheese Shop
20 ------------------------
20 ------------------------
21 Rhodecode requires python 2.x greater than version 2.5
21 Rhodecode requires python 2.x greater than version 2.5
22
22
23 Easiest way to install ``rhodecode`` is to run::
23 Easiest way to install ``rhodecode`` is to run::
24
24
25 easy_install rhodecode
25 easy_install rhodecode
26
26
27 Or::
27 Or::
28
28
29 pip install rhodecode
29 pip install rhodecode
30
30
31 If you prefer to install manually simply grab latest release from
31 If you prefer to install manually simply grab latest release from
32 http://pypi.python.org/pypi/rhodecode, decompres archive and run::
32 http://pypi.python.org/pypi/RhodeCode, decompres archive and run::
33
33
34 python setup.py install
34 python setup.py install
35
35
36
36
37 Step by step installation example
37 Step by step installation example
38 ---------------------------------
38 ---------------------------------
39
39
40
40
41 - Assuming You have installed virtualenv_ create one using.
41 - Assuming You have installed virtualenv_ create one using.
42 The `--no-site-packages` will make sure non of Your system libs are linked
42 The `--no-site-packages` will make sure non of Your system libs are linked
43 with this virtualenv_
43 with this virtualenv_
44
44
45 ::
45 ::
46
46
47 virtualenv --no-site-packages /var/www/rhodecode-venv
47 virtualenv --no-site-packages /var/www/rhodecode-venv
48
48
49 - this will install new virtualenv_ into `/var/www/rhodecode-venv`.
49 - this will install new virtualenv_ into `/var/www/rhodecode-venv`.
50 - Activate the virtualenv_ by running
50 - Activate the virtualenv_ by running
51
51
52 ::
52 ::
53
53
54 source /var/www/rhodecode-venv/bin/activate
54 source /var/www/rhodecode-venv/bin/activate
55
55
56 - Make a folder for rhodecode somewhere on the filesystem for example
56 - Make a folder for rhodecode somewhere on the filesystem for example
57
57
58 ::
58 ::
59
59
60 mkdir /var/www/rhodecode
60 mkdir /var/www/rhodecode
61
61
62
62
63 - Run this command to install rhodecode
63 - Run this command to install rhodecode
64
64
65 ::
65 ::
66
66
67 easy_install rhodecode
67 easy_install rhodecode
68
68
69 - this will install rhodecode together with pylons
69 - this will install rhodecode together with pylons
70 and all other required python libraries
70 and all other required python libraries
71
71
72 Requirements for Celery (optional)
72 Requirements for Celery (optional)
73 ----------------------------------
73 ----------------------------------
74
74
75 .. note::
75 .. note::
76 Installing message broker and using celery is optional, RhodeCode will
76 Installing message broker and using celery is optional, RhodeCode will
77 work without them perfectly fine.
77 work without them perfectly fine.
78
78
79
79
80 **Message Broker**
80 **Message Broker**
81
81
82 - preferred is `RabbitMq <http://www.rabbitmq.com/>`_
82 - preferred is `RabbitMq <http://www.rabbitmq.com/>`_
83 - possible other is `Redis <http://code.google.com/p/redis/>`_
83 - possible other is `Redis <http://code.google.com/p/redis/>`_
84
84
85 For installation instructions You can visit:
85 For installation instructions You can visit:
86 http://ask.github.com/celery/getting-started/index.html
86 http://ask.github.com/celery/getting-started/index.html
87 It's very nice tutorial how to start celery_ with rabbitmq_
87 It's very nice tutorial how to start celery_ with rabbitmq_
88
88
89
89
90 You can now proceed to :ref:`setup`
90 You can now proceed to :ref:`setup`
91 -----------------------------------
91 -----------------------------------
92
92
93
93
94
94
95 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
95 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
96 .. _python: http://www.python.org/
96 .. _python: http://www.python.org/
97 .. _mercurial: http://mercurial.selenic.com/
97 .. _mercurial: http://mercurial.selenic.com/
98 .. _celery: http://celeryproject.org/
98 .. _celery: http://celeryproject.org/
99 .. _rabbitmq: http://www.rabbitmq.com/ No newline at end of file
99 .. _rabbitmq: http://www.rabbitmq.com/
@@ -1,299 +1,302 b''
1 .. _setup:
1 .. _setup:
2
2
3 Setup
3 Setup
4 =====
4 =====
5
5
6
6
7 Setting up the application
7 Setting up the application
8 --------------------------
8 --------------------------
9
9
10 First You'll ned to create RhodeCode config file. Run the following command
10 First You'll ned to create RhodeCode config file. Run the following command
11 to do this
11 to do this
12
12
13 ::
13 ::
14
14
15 paster make-config RhodeCode production.ini
15 paster make-config RhodeCode production.ini
16
16
17 - This will create `production.ini` config inside the directory
17 - This will create `production.ini` config inside the directory
18 this config contains various settings for RhodeCode, e.g proxy port,
18 this config contains various settings for RhodeCode, e.g proxy port,
19 email settings, usage of static files, cache, celery settings and logging.
19 email settings, usage of static files, cache, celery settings and logging.
20
20
21
21
22
22
23 Next we need to create the database.
23 Next we need to create the database.
24
24
25 ::
25 ::
26
26
27 paster setup-app production.ini
27 paster setup-app production.ini
28
28
29 - This command will create all needed tables and an admin account.
29 - This command will create all needed tables and an admin account.
30 When asked for a path You can either use a new location of one with already
30 When asked for a path You can either use a new location of one with already
31 existing ones. RhodeCode will simply add all new found repositories to
31 existing ones. RhodeCode will simply add all new found repositories to
32 it's database. Also make sure You specify correct path to repositories.
32 it's database. Also make sure You specify correct path to repositories.
33 - Remember that the given path for mercurial_ repositories must be write
33 - Remember that the given path for mercurial_ repositories must be write
34 accessible for the application. It's very important since RhodeCode web
34 accessible for the application. It's very important since RhodeCode web
35 interface will work even without such an access but, when trying to do a
35 interface will work even without such an access but, when trying to do a
36 push it'll eventually fail with permission denied errors.
36 push it'll eventually fail with permission denied errors.
37
37
38 You are ready to use rhodecode, to run it simply execute
38 You are ready to use rhodecode, to run it simply execute
39
39
40 ::
40 ::
41
41
42 paster serve production.ini
42 paster serve production.ini
43
43
44 - This command runs the RhodeCode server the app should be available at the
44 - This command runs the RhodeCode server the app should be available at the
45 127.0.0.1:5000. This ip and port is configurable via the production.ini
45 127.0.0.1:5000. This ip and port is configurable via the production.ini
46 file created in previous step
46 file created in previous step
47 - Use admin account you created to login.
47 - Use admin account you created to login.
48 - Default permissions on each repository is read, and owner is admin. So
48 - Default permissions on each repository is read, and owner is admin. So
49 remember to update these if needed. In the admin panel You can toggle ldap,
49 remember to update these if needed. In the admin panel You can toggle ldap,
50 anonymous, permissions settings. As well as edit more advanced options on
50 anonymous, permissions settings. As well as edit more advanced options on
51 users and repositories
51 users and repositories
52
52
53
53
54 Setting up Whoosh full text search
54 Setting up Whoosh full text search
55 ----------------------------------
55 ----------------------------------
56
56
57 Index for whoosh can be build starting from version 1.1 using paster command
57 Index for whoosh can be build starting from version 1.1 using paster command
58 passing repo locations to index, as well as Your config file that stores
58 passing repo locations to index, as well as Your config file that stores
59 whoosh index files locations. There is possible to pass `-f` to the options
59 whoosh index files locations. There is possible to pass `-f` to the options
60 to enable full index rebuild. Without that indexing will run always in in
60 to enable full index rebuild. Without that indexing will run always in in
61 incremental mode.
61 incremental mode.
62
62
63 ::
63 ::
64
64
65 paster make-index production.ini --repo-location=<location for repos>
65 paster make-index production.ini --repo-location=<location for repos>
66
66
67 for full index rebuild You can use
67 for full index rebuild You can use
68
68
69 ::
69 ::
70
70
71 paster make-index production.ini -f --repo-location=<location for repos>
71 paster make-index production.ini -f --repo-location=<location for repos>
72
72
73 - For full text search You can either put crontab entry for
73 - For full text search You can either put crontab entry for
74
74
75 This command can be run even from crontab in order to do periodical
75 This command can be run even from crontab in order to do periodical
76 index builds and keep Your index always up to date. An example entry might
76 index builds and keep Your index always up to date. An example entry might
77 look like this
77 look like this
78
78
79 ::
79 ::
80
80
81 /path/to/python/bin/paster /path/to/rhodecode/production.ini --repo-location=<location for repos>
81 /path/to/python/bin/paster /path/to/rhodecode/production.ini --repo-location=<location for repos>
82
82
83 When using incremental(default) mode whoosh will check last modification date
83 When using incremental(default) mode whoosh will check last modification date
84 of each file and add it to reindex if newer file is available. Also indexing
84 of each file and add it to reindex if newer file is available. Also indexing
85 daemon checks for removed files and removes them from index.
85 daemon checks for removed files and removes them from index.
86
86
87 Sometime You might want to rebuild index from scratch. You can do that using
87 Sometime You might want to rebuild index from scratch. You can do that using
88 the `-f` flag passed to paster command or, in admin panel You can check
88 the `-f` flag passed to paster command or, in admin panel You can check
89 `build from scratch` flag.
89 `build from scratch` flag.
90
90
91
91
92 Setting up LDAP support
92 Setting up LDAP support
93 -----------------------
93 -----------------------
94
94
95 RhodeCode starting from version 1.1 supports ldap authentication. In order
95 RhodeCode starting from version 1.1 supports ldap authentication. In order
96 to use ldap, You have to install python-ldap package. This package is available
96 to use ldap, You have to install python-ldap package. This package is available
97 via pypi, so You can install it by running
97 via pypi, so You can install it by running
98
98
99 ::
99 ::
100
100
101 easy_install python-ldap
101 easy_install python-ldap
102
102
103 ::
103 ::
104
104
105 pip install python-ldap
105 pip install python-ldap
106
106
107 .. note::
107 .. note::
108 python-ldap requires some certain libs on Your system, so before installing
108 python-ldap requires some certain libs on Your system, so before installing
109 it check that You have at least `openldap`, and `sasl` libraries.
109 it check that You have at least `openldap`, and `sasl` libraries.
110
110
111 ldap settings are located in admin->ldap section,
111 ldap settings are located in admin->ldap section,
112
112
113 Here's a typical ldap setup::
113 Here's a typical ldap setup::
114
114
115 Enable ldap = checked #controls if ldap access is enabled
115 Enable ldap = checked #controls if ldap access is enabled
116 Host = host.domain.org #actual ldap server to connect
116 Host = host.domain.org #actual ldap server to connect
117 Port = 389 or 689 for ldaps #ldap server ports
117 Port = 389 or 689 for ldaps #ldap server ports
118 Enable LDAPS = unchecked #enable disable ldaps
118 Enable LDAPS = unchecked #enable disable ldaps
119 Account = <account> #access for ldap server(if required)
119 Account = <account> #access for ldap server(if required)
120 Password = <password> #password for ldap server(if required)
120 Password = <password> #password for ldap server(if required)
121 Base DN = uid=%(user)s,CN=users,DC=host,DC=domain,DC=org
121 Base DN = uid=%(user)s,CN=users,DC=host,DC=domain,DC=org
122
122
123
123
124 `Account` and `Password` are optional, and used for two-phase ldap
124 `Account` and `Password` are optional, and used for two-phase ldap
125 authentication so those are credentials to access Your ldap, if it doesn't
125 authentication so those are credentials to access Your ldap, if it doesn't
126 support anonymous search/user lookups.
126 support anonymous search/user lookups.
127
127
128 Base DN must have %(user)s template inside, it's a placer where Your uid used
128 Base DN must have %(user)s template inside, it's a placer where Your uid used
129 to login would go, it allows admins to specify not standard schema for uid
129 to login would go, it allows admins to specify not standard schema for uid
130 variable
130 variable
131
131
132 If all data are entered correctly, and `python-ldap` is properly installed
132 If all data are entered correctly, and `python-ldap` is properly installed
133 Users should be granted to access RhodeCode wit ldap accounts. When
133 Users should be granted to access RhodeCode wit ldap accounts. When
134 logging at the first time an special ldap account is created inside RhodeCode,
134 logging at the first time an special ldap account is created inside RhodeCode,
135 so You can control over permissions even on ldap users. If such user exists
135 so You can control over permissions even on ldap users. If such user exists
136 already in RhodeCode database ldap user with the same username would be not
136 already in RhodeCode database ldap user with the same username would be not
137 able to access RhodeCode.
137 able to access RhodeCode.
138
138
139 If You have problems with ldap access and believe You entered correct
139 If You have problems with ldap access and believe You entered correct
140 information check out the RhodeCode logs,any error messages sent from
140 information check out the RhodeCode logs,any error messages sent from
141 ldap will be saved there.
141 ldap will be saved there.
142
142
143
143
144
144
145 Setting Up Celery
145 Setting Up Celery
146 -----------------
146 -----------------
147
147
148 Since version 1.1 celery is configured by the rhodecode ini configuration files
148 Since version 1.1 celery is configured by the rhodecode ini configuration files
149 simply set use_celery=true in the ini file then add / change the configuration
149 simply set use_celery=true in the ini file then add / change the configuration
150 variables inside the ini file.
150 variables inside the ini file.
151
151
152 Remember that the ini files uses format with '.' not with '_' like celery
152 Remember that the ini files uses format with '.' not with '_' like celery
153 so for example setting `BROKER_HOST` in celery means setting `broker.host` in
153 so for example setting `BROKER_HOST` in celery means setting `broker.host` in
154 the config file.
154 the config file.
155
155
156 In order to make start using celery run::
156 In order to make start using celery run::
157
157 paster celeryd <configfile.ini>
158 paster celeryd <configfile.ini>
158
159
159
160 .. note::
161 Make sure You run this command from same virtualenv, and with the same user
162 that rhodecode runs.
163
160 HTTPS support
164 HTTPS support
161 -------------
165 -------------
162
166
163 There are two ways to enable https, first is to set HTTP_X_URL_SCHEME in
167 There are two ways to enable https, first is to set HTTP_X_URL_SCHEME in
164 Your http server headers, than rhodecode will recognise this headers and make
168 Your http server headers, than rhodecode will recognise this headers and make
165 proper https redirections, another way is to set `force_https = true`
169 proper https redirections, another way is to set `force_https = true`
166 in the ini cofiguration to force using https, no headers are needed than to
170 in the ini cofiguration to force using https, no headers are needed than to
167 enable https
171 enable https
168
172
169
173
170 Nginx virtual host example
174 Nginx virtual host example
171 --------------------------
175 --------------------------
172
176
173 Sample config for nginx using proxy::
177 Sample config for nginx using proxy::
174
178
175 server {
179 server {
176 listen 80;
180 listen 80;
177 server_name hg.myserver.com;
181 server_name hg.myserver.com;
178 access_log /var/log/nginx/rhodecode.access.log;
182 access_log /var/log/nginx/rhodecode.access.log;
179 error_log /var/log/nginx/rhodecode.error.log;
183 error_log /var/log/nginx/rhodecode.error.log;
180 location / {
184 location / {
181 root /var/www/rhodecode/rhodecode/public/;
185 root /var/www/rhodecode/rhodecode/public/;
182 if (!-f $request_filename){
186 if (!-f $request_filename){
183 proxy_pass http://127.0.0.1:5000;
187 proxy_pass http://127.0.0.1:5000;
184 }
188 }
185 #this is important for https !!!
189 #this is important if You want to use https !!!
186 proxy_set_header X-Url-Scheme $scheme;
190 proxy_set_header X-Url-Scheme $scheme;
187 include /etc/nginx/proxy.conf;
191 include /etc/nginx/proxy.conf;
188 }
192 }
189 }
193 }
190
194
191 Here's the proxy.conf. It's tuned so it'll not timeout on long
195 Here's the proxy.conf. It's tuned so it'll not timeout on long
192 pushes and also on large pushes::
196 pushes and also on large pushes::
193
197
194 proxy_redirect off;
198 proxy_redirect off;
195 proxy_set_header Host $host;
199 proxy_set_header Host $host;
196 proxy_set_header X-Host $http_host;
200 proxy_set_header X-Host $http_host;
197 proxy_set_header X-Real-IP $remote_addr;
201 proxy_set_header X-Real-IP $remote_addr;
198 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
202 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
199 proxy_set_header Proxy-host $proxy_host;
203 proxy_set_header Proxy-host $proxy_host;
200 client_max_body_size 400m;
204 client_max_body_size 400m;
201 client_body_buffer_size 128k;
205 client_body_buffer_size 128k;
202 proxy_buffering off;
206 proxy_buffering off;
203 proxy_connect_timeout 3600;
207 proxy_connect_timeout 3600;
204 proxy_send_timeout 3600;
208 proxy_send_timeout 3600;
205 proxy_read_timeout 3600;
209 proxy_read_timeout 3600;
206 proxy_buffer_size 8k;
210 proxy_buffer_size 8k;
207 proxy_buffers 8 32k;
211 proxy_buffers 8 32k;
208 proxy_busy_buffers_size 64k;
212 proxy_busy_buffers_size 64k;
209 proxy_temp_file_write_size 64k;
213 proxy_temp_file_write_size 64k;
210
214
211 Also when using root path with nginx You might set the static files to false
215 Also when using root path with nginx You might set the static files to false
212 in production.ini file::
216 in production.ini file::
213
217
214 [app:main]
218 [app:main]
215 use = egg:rhodecode
219 use = egg:rhodecode
216 full_stack = true
220 full_stack = true
217 static_files = false
221 static_files = false
218 lang=en
222 lang=en
219 cache_dir = %(here)s/data
223 cache_dir = %(here)s/data
220
224
221 To not have the statics served by the application. And improve speed.
225 To not have the statics served by the application. And improve speed.
222
226
223
227
224 Apache virtual host example
228 Apache virtual host example
225 ---------------------------
229 ---------------------------
226
230
227 Sample config for apache using proxy::
231 Sample config for apache using proxy::
228
232
229 <VirtualHost *:80>
233 <VirtualHost *:80>
230 ServerName hg.myserver.com
234 ServerName hg.myserver.com
231 ServerAlias hg.myserver.com
235 ServerAlias hg.myserver.com
232
236
233 <Proxy *>
237 <Proxy *>
234 Order allow,deny
238 Order allow,deny
235 Allow from all
239 Allow from all
236 </Proxy>
240 </Proxy>
237
241
238 #important !
242 #important !
239 #Directive to properly generate url (clone url) for pylons
243 #Directive to properly generate url (clone url) for pylons
240 ProxyPreserveHost On
244 ProxyPreserveHost On
241
245
242 #rhodecode instance
246 #rhodecode instance
243 ProxyPass / http://127.0.0.1:5000/
247 ProxyPass / http://127.0.0.1:5000/
244 ProxyPassReverse / http://127.0.0.1:5000/
248 ProxyPassReverse / http://127.0.0.1:5000/
245
249
246 #to enable https use line below
250 #to enable https use line below
247 #SetEnvIf X-Url-Scheme https HTTPS=1
251 #SetEnvIf X-Url-Scheme https HTTPS=1
248
252
249 </VirtualHost>
253 </VirtualHost>
250
254
251
255
252 Additional tutorial
256 Additional tutorial
253 http://wiki.pylonshq.com/display/pylonscookbook/Apache+as+a+reverse+proxy+for+Pylons
257 http://wiki.pylonshq.com/display/pylonscookbook/Apache+as+a+reverse+proxy+for+Pylons
254
258
255
259
256 Apache's example FCGI config
260 Apache's example FCGI config
257 ----------------------------
261 ----------------------------
258
262
259 TODO !
263 TODO !
260
264
261 Other configuration files
265 Other configuration files
262 -------------------------
266 -------------------------
263
267
264 Some extra configuration files and examples can be found here:
268 Some example init.d script can be found here, for debian and gentoo:
265 http://hg.python-works.com/rhodecode/files/tip/init.d
266
269
267 and also an celeryconfig file can be use from here:
270 https://rhodeocode.org/rhodecode/files/tip/init.d
268 http://hg.python-works.com/rhodecode/files/tip/celeryconfig.py
271
269
272
270 Troubleshooting
273 Troubleshooting
271 ---------------
274 ---------------
272
275
273 - missing static files ?
276 - missing static files ?
274
277
275 - make sure either to set the `static_files = true` in the .ini file or
278 - make sure either to set the `static_files = true` in the .ini file or
276 double check the root path for Your http setup. It should point to
279 double check the root path for Your http setup. It should point to
277 for example:
280 for example:
278 /home/my-virtual-python/lib/python2.6/site-packages/rhodecode/public
281 /home/my-virtual-python/lib/python2.6/site-packages/rhodecode/public
279
282
280 - can't install celery/rabbitmq
283 - can't install celery/rabbitmq
281
284
282 - don't worry RhodeCode works without them too. No extra setup required
285 - don't worry RhodeCode works without them too. No extra setup required
283
286
284 - long lasting push timeouts ?
287 - long lasting push timeouts ?
285
288
286 - make sure You set a longer timeouts in Your proxy/fcgi settings, timeouts
289 - make sure You set a longer timeouts in Your proxy/fcgi settings, timeouts
287 are caused by https server and not RhodeCode
290 are caused by https server and not RhodeCode
288
291
289 - large pushes timeouts ?
292 - large pushes timeouts ?
290
293
291 - make sure You set a proper max_body_size for the http server
294 - make sure You set a proper max_body_size for the http server
292
295
293
296
294
297
295 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
298 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
296 .. _python: http://www.python.org/
299 .. _python: http://www.python.org/
297 .. _mercurial: http://mercurial.selenic.com/
300 .. _mercurial: http://mercurial.selenic.com/
298 .. _celery: http://celeryproject.org/
301 .. _celery: http://celeryproject.org/
299 .. _rabbitmq: http://www.rabbitmq.com/ No newline at end of file
302 .. _rabbitmq: http://www.rabbitmq.com/
@@ -1,313 +1,313 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Admin controller for RhodeCode
6 Admin controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import formencode
30 import formencode
31 from operator import itemgetter
31 from operator import itemgetter
32 from formencode import htmlfill
32 from formencode import htmlfill
33
33
34 from paste.httpexceptions import HTTPInternalServerError
34 from paste.httpexceptions import HTTPInternalServerError
35 from pylons import request, response, session, tmpl_context as c, url
35 from pylons import request, response, session, tmpl_context as c, url
36 from pylons.controllers.util import abort, redirect
36 from pylons.controllers.util import abort, redirect
37 from pylons.i18n.translation import _
37 from pylons.i18n.translation import _
38
38
39 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
41 HasPermissionAnyDecorator
41 HasPermissionAnyDecorator
42 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.utils import invalidate_cache, action_logger
43 from rhodecode.lib.utils import invalidate_cache, action_logger
44 from rhodecode.model.db import User
44 from rhodecode.model.db import User
45 from rhodecode.model.forms import RepoForm
45 from rhodecode.model.forms import RepoForm
46 from rhodecode.model.scm import ScmModel
46 from rhodecode.model.scm import ScmModel
47 from rhodecode.model.repo import RepoModel
47 from rhodecode.model.repo import RepoModel
48
48
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52 class ReposController(BaseController):
52 class ReposController(BaseController):
53 """REST Controller styled on the Atom Publishing Protocol"""
53 """REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
54 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
55 # file has a resource setup:
56 # map.resource('repo', 'repos')
56 # map.resource('repo', 'repos')
57
57
58 @LoginRequired()
58 @LoginRequired()
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
60 def __before__(self):
60 def __before__(self):
61 c.admin_user = session.get('admin_user')
61 c.admin_user = session.get('admin_user')
62 c.admin_username = session.get('admin_username')
62 c.admin_username = session.get('admin_username')
63 super(ReposController, self).__before__()
63 super(ReposController, self).__before__()
64
64
65 @HasPermissionAllDecorator('hg.admin')
65 @HasPermissionAllDecorator('hg.admin')
66 def index(self, format='html'):
66 def index(self, format='html'):
67 """GET /repos: All items in the collection"""
67 """GET /repos: All items in the collection"""
68 # url('repos')
68 # url('repos')
69 cached_repo_list = ScmModel().get_repos()
69 cached_repo_list = ScmModel().get_repos()
70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
71 return render('admin/repos/repos.html')
71 return render('admin/repos/repos.html')
72
72
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
74 def create(self):
74 def create(self):
75 """POST /repos: Create a new item"""
75 """POST /repos: Create a new item"""
76 # url('repos')
76 # url('repos')
77 repo_model = RepoModel()
77 repo_model = RepoModel()
78 _form = RepoForm()()
78 _form = RepoForm()()
79 form_result = {}
79 form_result = {}
80 try:
80 try:
81 form_result = _form.to_python(dict(request.POST))
81 form_result = _form.to_python(dict(request.POST))
82 repo_model.create(form_result, c.rhodecode_user)
82 repo_model.create(form_result, c.rhodecode_user)
83 h.flash(_('created repository %s') % form_result['repo_name'],
83 h.flash(_('created repository %s') % form_result['repo_name'],
84 category='success')
84 category='success')
85
85
86 if request.POST.get('user_created'):
86 if request.POST.get('user_created'):
87 action_logger(self.rhodecode_user, 'user_created_repo',
87 action_logger(self.rhodecode_user, 'user_created_repo',
88 form_result['repo_name'], '', self.sa)
88 form_result['repo_name'], '', self.sa)
89 else:
89 else:
90 action_logger(self.rhodecode_user, 'admin_created_repo',
90 action_logger(self.rhodecode_user, 'admin_created_repo',
91 form_result['repo_name'], '', self.sa)
91 form_result['repo_name'], '', self.sa)
92
92
93 except formencode.Invalid, errors:
93 except formencode.Invalid, errors:
94 c.new_repo = errors.value['repo_name']
94 c.new_repo = errors.value['repo_name']
95
95
96 if request.POST.get('user_created'):
96 if request.POST.get('user_created'):
97 r = render('admin/repos/repo_add_create_repository.html')
97 r = render('admin/repos/repo_add_create_repository.html')
98 else:
98 else:
99 r = render('admin/repos/repo_add.html')
99 r = render('admin/repos/repo_add.html')
100
100
101 return htmlfill.render(
101 return htmlfill.render(
102 r,
102 r,
103 defaults=errors.value,
103 defaults=errors.value,
104 errors=errors.error_dict or {},
104 errors=errors.error_dict or {},
105 prefix_error=False,
105 prefix_error=False,
106 encoding="UTF-8")
106 encoding="UTF-8")
107
107
108 except Exception:
108 except Exception:
109 log.error(traceback.format_exc())
109 log.error(traceback.format_exc())
110 msg = _('error occurred during creation of repository %s') \
110 msg = _('error occurred during creation of repository %s') \
111 % form_result.get('repo_name')
111 % form_result.get('repo_name')
112 h.flash(msg, category='error')
112 h.flash(msg, category='error')
113 if request.POST.get('user_created'):
113 if request.POST.get('user_created'):
114 return redirect(url('home'))
114 return redirect(url('home'))
115 return redirect(url('repos'))
115 return redirect(url('repos'))
116
116
117 @HasPermissionAllDecorator('hg.admin')
117 @HasPermissionAllDecorator('hg.admin')
118 def new(self, format='html'):
118 def new(self, format='html'):
119 """GET /repos/new: Form to create a new item"""
119 """GET /repos/new: Form to create a new item"""
120 new_repo = request.GET.get('repo', '')
120 new_repo = request.GET.get('repo', '')
121 c.new_repo = h.repo_name_slug(new_repo)
121 c.new_repo = h.repo_name_slug(new_repo)
122
122
123 return render('admin/repos/repo_add.html')
123 return render('admin/repos/repo_add.html')
124
124
125 @HasPermissionAllDecorator('hg.admin')
125 @HasPermissionAllDecorator('hg.admin')
126 def update(self, repo_name):
126 def update(self, repo_name):
127 """PUT /repos/repo_name: Update an existing item"""
127 """PUT /repos/repo_name: Update an existing item"""
128 # Forms posted to this method should contain a hidden field:
128 # Forms posted to this method should contain a hidden field:
129 # <input type="hidden" name="_method" value="PUT" />
129 # <input type="hidden" name="_method" value="PUT" />
130 # Or using helpers:
130 # Or using helpers:
131 # h.form(url('repo', repo_name=ID),
131 # h.form(url('repo', repo_name=ID),
132 # method='put')
132 # method='put')
133 # url('repo', repo_name=ID)
133 # url('repo', repo_name=ID)
134 repo_model = RepoModel()
134 repo_model = RepoModel()
135 changed_name = repo_name
135 changed_name = repo_name
136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
137
137
138 try:
138 try:
139 form_result = _form.to_python(dict(request.POST))
139 form_result = _form.to_python(dict(request.POST))
140 repo_model.update(repo_name, form_result)
140 repo_model.update(repo_name, form_result)
141 invalidate_cache('get_repo_cached_%s' % repo_name)
141 invalidate_cache('get_repo_cached_%s' % repo_name)
142 h.flash(_('Repository %s updated successfully' % repo_name),
142 h.flash(_('Repository %s updated successfully' % repo_name),
143 category='success')
143 category='success')
144 changed_name = form_result['repo_name']
144 changed_name = form_result['repo_name']
145 action_logger(self.rhodecode_user, 'admin_updated_repo',
145 action_logger(self.rhodecode_user, 'admin_updated_repo',
146 changed_name, '', self.sa)
146 changed_name, '', self.sa)
147
147
148 except formencode.Invalid, errors:
148 except formencode.Invalid, errors:
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
150 if c.repo_info.stats:
150 if c.repo_info.stats:
151 last_rev = c.repo_info.stats.stat_on_revision
151 last_rev = c.repo_info.stats.stat_on_revision
152 else:
152 else:
153 last_rev = 0
153 last_rev = 0
154 c.stats_revision = last_rev
154 c.stats_revision = last_rev
155 r = ScmModel().get(repo_name)
155 r = ScmModel().get(repo_name)
156 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
156 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
157
157
158 if last_rev == 0:
158 if last_rev == 0:
159 c.stats_percentage = 0
159 c.stats_percentage = 0
160 else:
160 else:
161 c.stats_percentage = '%.2f' % ((float((last_rev)) /
161 c.stats_percentage = '%.2f' % ((float((last_rev)) /
162 c.repo_last_rev) * 100)
162 c.repo_last_rev) * 100)
163
163
164 c.users_array = repo_model.get_users_js()
164 c.users_array = repo_model.get_users_js()
165 errors.value.update({'user':c.repo_info.user.username})
165 errors.value.update({'user':c.repo_info.user.username})
166 return htmlfill.render(
166 return htmlfill.render(
167 render('admin/repos/repo_edit.html'),
167 render('admin/repos/repo_edit.html'),
168 defaults=errors.value,
168 defaults=errors.value,
169 errors=errors.error_dict or {},
169 errors=errors.error_dict or {},
170 prefix_error=False,
170 prefix_error=False,
171 encoding="UTF-8")
171 encoding="UTF-8")
172
172
173 except Exception:
173 except Exception:
174 log.error(traceback.format_exc())
174 log.error(traceback.format_exc())
175 h.flash(_('error occurred during update of repository %s') \
175 h.flash(_('error occurred during update of repository %s') \
176 % repo_name, category='error')
176 % repo_name, category='error')
177
177
178 return redirect(url('edit_repo', repo_name=changed_name))
178 return redirect(url('edit_repo', repo_name=changed_name))
179
179
180 @HasPermissionAllDecorator('hg.admin')
180 @HasPermissionAllDecorator('hg.admin')
181 def delete(self, repo_name):
181 def delete(self, repo_name):
182 """DELETE /repos/repo_name: Delete an existing item"""
182 """DELETE /repos/repo_name: Delete an existing item"""
183 # Forms posted to this method should contain a hidden field:
183 # Forms posted to this method should contain a hidden field:
184 # <input type="hidden" name="_method" value="DELETE" />
184 # <input type="hidden" name="_method" value="DELETE" />
185 # Or using helpers:
185 # Or using helpers:
186 # h.form(url('repo', repo_name=ID),
186 # h.form(url('repo', repo_name=ID),
187 # method='delete')
187 # method='delete')
188 # url('repo', repo_name=ID)
188 # url('repo', repo_name=ID)
189
189
190 repo_model = RepoModel()
190 repo_model = RepoModel()
191 repo = repo_model.get_by_repo_name(repo_name)
191 repo = repo_model.get_by_repo_name(repo_name)
192 if not repo:
192 if not repo:
193 h.flash(_('%s repository is not mapped to db perhaps'
193 h.flash(_('%s repository is not mapped to db perhaps'
194 ' it was moved or renamed from the filesystem'
194 ' it was moved or renamed from the filesystem'
195 ' please run the application again'
195 ' please run the application again'
196 ' in order to rescan repositories') % repo_name,
196 ' in order to rescan repositories') % repo_name,
197 category='error')
197 category='error')
198
198
199 return redirect(url('repos'))
199 return redirect(url('repos'))
200 try:
200 try:
201 action_logger(self.rhodecode_user, 'admin_deleted_repo',
201 action_logger(self.rhodecode_user, 'admin_deleted_repo',
202 repo_name, '', self.sa)
202 repo_name, '', self.sa)
203 repo_model.delete(repo)
203 repo_model.delete(repo)
204 invalidate_cache('get_repo_cached_%s' % repo_name)
204 invalidate_cache('get_repo_cached_%s' % repo_name)
205 h.flash(_('deleted repository %s') % repo_name, category='success')
205 h.flash(_('deleted repository %s') % repo_name, category='success')
206
206
207 except Exception, e:
207 except Exception, e:
208 log.error(traceback.format_exc())
208 log.error(traceback.format_exc())
209 h.flash(_('An error occurred during deletion of %s') % repo_name,
209 h.flash(_('An error occurred during deletion of %s') % repo_name,
210 category='error')
210 category='error')
211
211
212 return redirect(url('repos'))
212 return redirect(url('repos'))
213
213
214 @HasPermissionAllDecorator('hg.admin')
214 @HasPermissionAllDecorator('hg.admin')
215 def delete_perm_user(self, repo_name):
215 def delete_perm_user(self, repo_name):
216 """
216 """
217 DELETE an existing repository permission user
217 DELETE an existing repository permission user
218 :param repo_name:
218 :param repo_name:
219 """
219 """
220
220
221 try:
221 try:
222 repo_model = RepoModel()
222 repo_model = RepoModel()
223 repo_model.delete_perm_user(request.POST, repo_name)
223 repo_model.delete_perm_user(request.POST, repo_name)
224 except Exception, e:
224 except Exception, e:
225 h.flash(_('An error occurred during deletion of repository user'),
225 h.flash(_('An error occurred during deletion of repository user'),
226 category='error')
226 category='error')
227 raise HTTPInternalServerError()
227 raise HTTPInternalServerError()
228
228
229 @HasPermissionAllDecorator('hg.admin')
229 @HasPermissionAllDecorator('hg.admin')
230 def repo_stats(self, repo_name):
230 def repo_stats(self, repo_name):
231 """
231 """
232 DELETE an existing repository statistics
232 DELETE an existing repository statistics
233 :param repo_name:
233 :param repo_name:
234 """
234 """
235
235
236 try:
236 try:
237 repo_model = RepoModel()
237 repo_model = RepoModel()
238 repo_model.delete_stats(repo_name)
238 repo_model.delete_stats(repo_name)
239 except Exception, e:
239 except Exception, e:
240 h.flash(_('An error occurred during deletion of repository stats'),
240 h.flash(_('An error occurred during deletion of repository stats'),
241 category='error')
241 category='error')
242 return redirect(url('edit_repo', repo_name=repo_name))
242 return redirect(url('edit_repo', repo_name=repo_name))
243
243
244 @HasPermissionAllDecorator('hg.admin')
244 @HasPermissionAllDecorator('hg.admin')
245 def repo_cache(self, repo_name):
245 def repo_cache(self, repo_name):
246 """
246 """
247 INVALIDATE existing repository cache
247 INVALIDATE existing repository cache
248 :param repo_name:
248 :param repo_name:
249 """
249 """
250
250
251 try:
251 try:
252 ScmModel().mark_for_invalidation(repo_name)
252 ScmModel().mark_for_invalidation(repo_name)
253 except Exception, e:
253 except Exception, e:
254 h.flash(_('An error occurred during cache invalidation'),
254 h.flash(_('An error occurred during cache invalidation'),
255 category='error')
255 category='error')
256 return redirect(url('edit_repo', repo_name=repo_name))
256 return redirect(url('edit_repo', repo_name=repo_name))
257
257
258 @HasPermissionAllDecorator('hg.admin')
258 @HasPermissionAllDecorator('hg.admin')
259 def show(self, repo_name, format='html'):
259 def show(self, repo_name, format='html'):
260 """GET /repos/repo_name: Show a specific item"""
260 """GET /repos/repo_name: Show a specific item"""
261 # url('repo', repo_name=ID)
261 # url('repo', repo_name=ID)
262
262
263 @HasPermissionAllDecorator('hg.admin')
263 @HasPermissionAllDecorator('hg.admin')
264 def edit(self, repo_name, format='html'):
264 def edit(self, repo_name, format='html'):
265 """GET /repos/repo_name/edit: Form to edit an existing item"""
265 """GET /repos/repo_name/edit: Form to edit an existing item"""
266 # url('edit_repo', repo_name=ID)
266 # url('edit_repo', repo_name=ID)
267 repo_model = RepoModel()
267 repo_model = RepoModel()
268 r = ScmModel().get(repo_name)
268 r = ScmModel().get(repo_name)
269 c.repo_info = repo_model.get_by_repo_name(repo_name)
269 c.repo_info = repo_model.get_by_repo_name(repo_name)
270
270
271 if c.repo_info is None:
271 if c.repo_info is None:
272 h.flash(_('%s repository is not mapped to db perhaps'
272 h.flash(_('%s repository is not mapped to db perhaps'
273 ' it was created or renamed from the filesystem'
273 ' it was created or renamed from the filesystem'
274 ' please run the application again'
274 ' please run the application again'
275 ' in order to rescan repositories') % repo_name,
275 ' in order to rescan repositories') % repo_name,
276 category='error')
276 category='error')
277
277
278 return redirect(url('repos'))
278 return redirect(url('repos'))
279
279
280 if c.repo_info.stats:
280 if c.repo_info.stats:
281 last_rev = c.repo_info.stats.stat_on_revision
281 last_rev = c.repo_info.stats.stat_on_revision
282 else:
282 else:
283 last_rev = 0
283 last_rev = 0
284 c.stats_revision = last_rev
284 c.stats_revision = last_rev
285
285
286 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
286 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
287
287
288 if last_rev == 0:
288 if last_rev == 0 or c.repo_last_rev == 0:
289 c.stats_percentage = 0
289 c.stats_percentage = 0
290 else:
290 else:
291 c.stats_percentage = '%.2f' % ((float((last_rev)) /
291 c.stats_percentage = '%.2f' % ((float((last_rev)) /
292 c.repo_last_rev) * 100)
292 c.repo_last_rev) * 100)
293
293
294 defaults = c.repo_info.get_dict()
294 defaults = c.repo_info.get_dict()
295 if c.repo_info.user:
295 if c.repo_info.user:
296 defaults.update({'user':c.repo_info.user.username})
296 defaults.update({'user':c.repo_info.user.username})
297 else:
297 else:
298 replacement_user = self.sa.query(User)\
298 replacement_user = self.sa.query(User)\
299 .filter(User.admin == True).first().username
299 .filter(User.admin == True).first().username
300 defaults.update({'user':replacement_user})
300 defaults.update({'user':replacement_user})
301
301
302 c.users_array = repo_model.get_users_js()
302 c.users_array = repo_model.get_users_js()
303
303
304 for p in c.repo_info.repo_to_perm:
304 for p in c.repo_info.repo_to_perm:
305 defaults.update({'perm_%s' % p.user.username:
305 defaults.update({'perm_%s' % p.user.username:
306 p.permission.permission_name})
306 p.permission.permission_name})
307
307
308 return htmlfill.render(
308 return htmlfill.render(
309 render('admin/repos/repo_edit.html'),
309 render('admin/repos/repo_edit.html'),
310 defaults=defaults,
310 defaults=defaults,
311 encoding="UTF-8",
311 encoding="UTF-8",
312 force_defaults=False
312 force_defaults=False
313 )
313 )
@@ -1,144 +1,143 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.summary
3 rhodecode.controllers.summary
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Summary controller for Rhodecode
6 Summary controller for Rhodecode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import calendar
28 import calendar
29 import logging
29 import logging
30 from time import mktime
30 from time import mktime
31 from datetime import datetime, timedelta
31 from datetime import datetime, timedelta, date
32
32
33 from vcs.exceptions import ChangesetError
33 from vcs.exceptions import ChangesetError
34
34
35 from pylons import tmpl_context as c, request, url
35 from pylons import tmpl_context as c, request, url
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 from rhodecode.model.scm import ScmModel
38 from rhodecode.model.scm import ScmModel
39 from rhodecode.model.db import Statistics
39 from rhodecode.model.db import Statistics
40
40
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
43 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
44
44
45 from rhodecode.lib.celerylib import run_task
45 from rhodecode.lib.celerylib import run_task
46 from rhodecode.lib.celerylib.tasks import get_commits_stats
46 from rhodecode.lib.celerylib.tasks import get_commits_stats
47
47
48 from webhelpers.paginate import Page
48 from webhelpers.paginate import Page
49
49
50 try:
50 try:
51 import json
51 import json
52 except ImportError:
52 except ImportError:
53 #python 2.5 compatibility
53 #python 2.5 compatibility
54 import simplejson as json
54 import simplejson as json
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57 class SummaryController(BaseController):
57 class SummaryController(BaseController):
58
58
59 @LoginRequired()
59 @LoginRequired()
60 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
60 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
61 'repository.admin')
61 'repository.admin')
62 def __before__(self):
62 def __before__(self):
63 super(SummaryController, self).__before__()
63 super(SummaryController, self).__before__()
64
64
65 def index(self):
65 def index(self):
66 scm_model = ScmModel()
66 scm_model = ScmModel()
67 c.repo_info = scm_model.get_repo(c.repo_name)
67 c.repo_info = scm_model.get_repo(c.repo_name)
68 c.following = scm_model.is_following_repo(c.repo_name,
68 c.following = scm_model.is_following_repo(c.repo_name,
69 c.rhodecode_user.user_id)
69 c.rhodecode_user.user_id)
70 def url_generator(**kw):
70 def url_generator(**kw):
71 return url('shortlog_home', repo_name=c.repo_name, **kw)
71 return url('shortlog_home', repo_name=c.repo_name, **kw)
72
72
73 c.repo_changesets = Page(c.repo_info, page=1, items_per_page=10,
73 c.repo_changesets = Page(c.repo_info, page=1, items_per_page=10,
74 url=url_generator)
74 url=url_generator)
75
75
76 e = request.environ
76 e = request.environ
77
77
78 if self.rhodecode_user.username == 'default':
78 if self.rhodecode_user.username == 'default':
79 password = ':default'
79 password = ':default'
80 else:
80 else:
81 password = ''
81 password = ''
82
82
83 uri = u'%(protocol)s://%(user)s%(password)s@%(host)s%(prefix)s/%(repo_name)s' % {
83 uri = u'%(protocol)s://%(user)s%(password)s@%(host)s%(prefix)s/%(repo_name)s' % {
84 'protocol': e.get('wsgi.url_scheme'),
84 'protocol': e.get('wsgi.url_scheme'),
85 'user':str(c.rhodecode_user.username),
85 'user':str(c.rhodecode_user.username),
86 'password':password,
86 'password':password,
87 'host':e.get('HTTP_HOST'),
87 'host':e.get('HTTP_HOST'),
88 'prefix':e.get('SCRIPT_NAME'),
88 'prefix':e.get('SCRIPT_NAME'),
89 'repo_name':c.repo_name, }
89 'repo_name':c.repo_name, }
90 c.clone_repo_url = uri
90 c.clone_repo_url = uri
91 c.repo_tags = OrderedDict()
91 c.repo_tags = OrderedDict()
92 for name, hash in c.repo_info.tags.items()[:10]:
92 for name, hash in c.repo_info.tags.items()[:10]:
93 try:
93 try:
94 c.repo_tags[name] = c.repo_info.get_changeset(hash)
94 c.repo_tags[name] = c.repo_info.get_changeset(hash)
95 except ChangesetError:
95 except ChangesetError:
96 c.repo_tags[name] = EmptyChangeset(hash)
96 c.repo_tags[name] = EmptyChangeset(hash)
97
97
98 c.repo_branches = OrderedDict()
98 c.repo_branches = OrderedDict()
99 for name, hash in c.repo_info.branches.items()[:10]:
99 for name, hash in c.repo_info.branches.items()[:10]:
100 try:
100 try:
101 c.repo_branches[name] = c.repo_info.get_changeset(hash)
101 c.repo_branches[name] = c.repo_info.get_changeset(hash)
102 except ChangesetError:
102 except ChangesetError:
103 c.repo_branches[name] = EmptyChangeset(hash)
103 c.repo_branches[name] = EmptyChangeset(hash)
104
104
105 td = datetime.today() + timedelta(days=1)
105 td = date.today() + timedelta(days=1)
106 y, m, d = td.year, td.month, td.day
106 td_1m = td - timedelta(days=calendar.mdays[td.month])
107 td_1y = td - timedelta(days=365)
107
108
108 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
109 ts_min_m = mktime(td_1m.timetuple())
109 d, 0, 0, 0, 0, 0, 0,))
110 ts_min_y = mktime(td_1y.timetuple())
110 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
111 ts_max_y = mktime(td.timetuple())
111 d, 0, 0, 0, 0, 0, 0,))
112
112
113 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
114 if c.repo_info.dbrepo.enable_statistics:
113 if c.repo_info.dbrepo.enable_statistics:
115 c.no_data_msg = _('No data loaded yet')
114 c.no_data_msg = _('No data loaded yet')
116 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
115 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
117 else:
116 else:
118 c.no_data_msg = _('Statistics update are disabled for this repository')
117 c.no_data_msg = _('Statistics update are disabled for this repository')
119 c.ts_min = ts_min_m
118 c.ts_min = ts_min_m
120 c.ts_max = ts_max_y
119 c.ts_max = ts_max_y
121
120
122 stats = self.sa.query(Statistics)\
121 stats = self.sa.query(Statistics)\
123 .filter(Statistics.repository == c.repo_info.dbrepo)\
122 .filter(Statistics.repository == c.repo_info.dbrepo)\
124 .scalar()
123 .scalar()
125
124
126
125
127 if stats and stats.languages:
126 if stats and stats.languages:
128 c.no_data = False is c.repo_info.dbrepo.enable_statistics
127 c.no_data = False is c.repo_info.dbrepo.enable_statistics
129 lang_stats = json.loads(stats.languages)
128 lang_stats = json.loads(stats.languages)
130 c.commit_data = stats.commit_activity
129 c.commit_data = stats.commit_activity
131 c.overview_data = stats.commit_activity_combined
130 c.overview_data = stats.commit_activity_combined
132 c.trending_languages = json.dumps(OrderedDict(
131 c.trending_languages = json.dumps(OrderedDict(
133 sorted(lang_stats.items(), reverse=True,
132 sorted(lang_stats.items(), reverse=True,
134 key=lambda k: k[1])[:10]
133 key=lambda k: k[1])[:10]
135 )
134 )
136 )
135 )
137 else:
136 else:
138 c.commit_data = json.dumps({})
137 c.commit_data = json.dumps({})
139 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10] ])
138 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10] ])
140 c.trending_languages = json.dumps({})
139 c.trending_languages = json.dumps({})
141 c.no_data = True
140 c.no_data = True
142
141
143 return render('summary/summary.html')
142 return render('summary/summary.html')
144
143
@@ -1,103 +1,104 b''
1 import sys
1 import sys
2 py_version = sys.version_info
2 py_version = sys.version_info
3
3
4 from rhodecode import get_version
4 from rhodecode import get_version
5
5
6 requirements = [
6 requirements = [
7 "Pylons==1.0.0",
7 "Pylons==1.0.0",
8 "WebHelpers>=1.2",
8 "SQLAlchemy==0.6.5",
9 "SQLAlchemy==0.6.5",
9 "Mako==0.3.6",
10 "Mako==0.3.6",
10 "vcs==0.1.10",
11 "vcs==0.1.10",
11 "pygments==1.3.1",
12 "pygments==1.3.1",
12 "mercurial==1.7.2",
13 "mercurial==1.7.2",
13 "whoosh==1.3.4",
14 "whoosh==1.3.4",
14 "celery==2.1.4",
15 "celery==2.1.4",
15 "py-bcrypt",
16 "py-bcrypt",
16 "babel",
17 "babel",
17 ]
18 ]
18
19
19 classifiers = ['Development Status :: 5 - Production/Stable',
20 classifiers = ['Development Status :: 5 - Production/Stable',
20 'Environment :: Web Environment',
21 'Environment :: Web Environment',
21 'Framework :: Pylons',
22 'Framework :: Pylons',
22 'Intended Audience :: Developers',
23 'Intended Audience :: Developers',
23 'License :: OSI Approved :: BSD License',
24 'License :: OSI Approved :: BSD License',
24 'Operating System :: OS Independent',
25 'Operating System :: OS Independent',
25 'Programming Language :: Python', ]
26 'Programming Language :: Python', ]
26
27
27 if sys.version_info < (2, 6):
28 if sys.version_info < (2, 6):
28 requirements.append("simplejson")
29 requirements.append("simplejson")
29 requirements.append("pysqlite")
30 requirements.append("pysqlite")
30
31
31 #additional files from project that goes somewhere in the filesystem
32 #additional files from project that goes somewhere in the filesystem
32 #relative to sys.prefix
33 #relative to sys.prefix
33 data_files = []
34 data_files = []
34
35
35 #additional files that goes into package itself
36 #additional files that goes into package itself
36 package_data = {'rhodecode': ['i18n/*/LC_MESSAGES/*.mo', ], }
37 package_data = {'rhodecode': ['i18n/*/LC_MESSAGES/*.mo', ], }
37
38
38 description = ('Mercurial repository browser/management with '
39 description = ('Mercurial repository browser/management with '
39 'build in push/pull server and full text search')
40 'build in push/pull server and full text search')
40 #long description
41 #long description
41 try:
42 try:
42 readme_file = 'README.rst'
43 readme_file = 'README.rst'
43 changelog_file = 'docs/changelog.rst'
44 changelog_file = 'docs/changelog.rst'
44 long_description = open(readme_file).read() + '\n\n' + \
45 long_description = open(readme_file).read() + '\n\n' + \
45 open(changelog_file).read()
46 open(changelog_file).read()
46
47
47 except IOError, err:
48 except IOError, err:
48 sys.stderr.write("[WARNING] Cannot find file specified as "
49 sys.stderr.write("[WARNING] Cannot find file specified as "
49 "long_description (%s)\n or changelog (%s) skipping that file" \
50 "long_description (%s)\n or changelog (%s) skipping that file" \
50 % (readme_file, changelog_file))
51 % (readme_file, changelog_file))
51 long_description = description
52 long_description = description
52
53
53
54
54 try:
55 try:
55 from setuptools import setup, find_packages
56 from setuptools import setup, find_packages
56 except ImportError:
57 except ImportError:
57 from ez_setup import use_setuptools
58 from ez_setup import use_setuptools
58 use_setuptools()
59 use_setuptools()
59 from setuptools import setup, find_packages
60 from setuptools import setup, find_packages
60 #packages
61 #packages
61 packages = find_packages(exclude=['ez_setup'])
62 packages = find_packages(exclude=['ez_setup'])
62
63
63 setup(
64 setup(
64 name='RhodeCode',
65 name='RhodeCode',
65 version=get_version(),
66 version=get_version(),
66 description=description,
67 description=description,
67 long_description=long_description,
68 long_description=long_description,
68 keywords='rhodiumcode mercurial web hgwebdir gitweb git replacement serving hgweb rhodecode',
69 keywords='rhodiumcode mercurial web hgwebdir gitweb git replacement serving hgweb rhodecode',
69 license='BSD',
70 license='BSD',
70 author='Marcin Kuzminski',
71 author='Marcin Kuzminski',
71 author_email='marcin@python-works.com',
72 author_email='marcin@python-works.com',
72 url='http://hg.python-works.com',
73 url='http://hg.python-works.com',
73 install_requires=requirements,
74 install_requires=requirements,
74 classifiers=classifiers,
75 classifiers=classifiers,
75 setup_requires=["PasteScript>=1.6.3"],
76 setup_requires=["PasteScript>=1.6.3"],
76 data_files=data_files,
77 data_files=data_files,
77 packages=packages,
78 packages=packages,
78 include_package_data=True,
79 include_package_data=True,
79 test_suite='nose.collector',
80 test_suite='nose.collector',
80 package_data=package_data,
81 package_data=package_data,
81 message_extractors={'rhodecode': [
82 message_extractors={'rhodecode': [
82 ('**.py', 'python', None),
83 ('**.py', 'python', None),
83 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
84 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
84 ('public/**', 'ignore', None)]},
85 ('public/**', 'ignore', None)]},
85 zip_safe=False,
86 zip_safe=False,
86 paster_plugins=['PasteScript', 'Pylons'],
87 paster_plugins=['PasteScript', 'Pylons'],
87 entry_points="""
88 entry_points="""
88 [paste.app_factory]
89 [paste.app_factory]
89 main = rhodecode.config.middleware:make_app
90 main = rhodecode.config.middleware:make_app
90
91
91 [paste.app_install]
92 [paste.app_install]
92 main = pylons.util:PylonsInstaller
93 main = pylons.util:PylonsInstaller
93
94
94 [paste.global_paster_command]
95 [paste.global_paster_command]
95 make-index = rhodecode.lib.indexers:MakeIndex
96 make-index = rhodecode.lib.indexers:MakeIndex
96 upgrade-db = rhodecode.lib.dbmigrate:UpgradeDb
97 upgrade-db = rhodecode.lib.dbmigrate:UpgradeDb
97 celeryd=rhodecode.lib.celerypylons.commands:CeleryDaemonCommand
98 celeryd=rhodecode.lib.celerypylons.commands:CeleryDaemonCommand
98 celerybeat=rhodecode.lib.celerypylons.commands:CeleryBeatCommand
99 celerybeat=rhodecode.lib.celerypylons.commands:CeleryBeatCommand
99 camqadm=rhodecode.lib.celerypylons.commands:CAMQPAdminCommand
100 camqadm=rhodecode.lib.celerypylons.commands:CAMQPAdminCommand
100 celeryev=rhodecode.lib.celerypylons.commands:CeleryEventCommand
101 celeryev=rhodecode.lib.celerypylons.commands:CeleryEventCommand
101
102
102 """,
103 """,
103 )
104 )
General Comments 0
You need to be logged in to leave comments. Login now