##// END OF EJS Templates
release: Merge default into stable for release preparation
marcink -
r2693:660bcebf merge stable
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,80 b''
1 .. _svn-path-permissions:
2
3 |svn| Enabling Path Permissions
4 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5
6 Because |RCEE| uses standard svn apache mod_svn we can take advantage of the
7 authz configuration to protect paths and branches.
8
9
10 Configuring RhodeCode
11 =====================
12
13
14 1. To configure path based permissions first we need to use a customized
15 mod_dav_svn.conf.
16
17 Open :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
18 And find `svn.proxy.config_template` setting. Now set a new path to read
19 the template from. For example:
20
21 .. code-block:: ini
22
23 svn.proxy.config_template = /home/ubuntu/rhodecode/custom_mod_dav_svn.conf.mako
24
25
26 2. Create the file as in example: `/home/ubuntu/rhodecode/custom_mod_dav_svn.conf.mako`
27 You can download one from:
28
29 `<https://code.rhodecode.com/rhodecode-enterprise-ce/files/default/rhodecode/apps/svn_support/templates/mod-dav-svn.conf.mako/>`_
30
31 3. Add (if not yet exists) a section `AuthzSVNReposRelativeAccessFile` in order
32 to read the path auth file.
33
34 Example modified config section enabling reading the authz file relative
35 to repository path. Means located in `/storage_dir/repo_name/conf/authz`
36
37 .. code-block:: text
38
39
40 # snip ...
41
42 # use specific SVN conf/authz file for each repository
43 AuthzSVNReposRelativeAccessFile authz
44
45 Allow from all
46 # snip ...
47
48 .. note::
49
50 The `AuthzSVNReposRelativeAccessFile` should go above the `Allow from all`
51 directive.
52
53
54 4. Restart RhodeCode, Go to
55 the :menuselection:`Admin --> Settings --> VCS` page, and
56 click :guilabel:`Generate Apache Config`.
57 This will now generate a new configuration with enabled changes to read
58 the authz file. You can verify if changes were made by checking the generated
59 mod_dav_svn.conf file which is included in your apache configuration.
60
61 5. Specify new rules in the repository authz configuration.
62 edit a file in :file:`repo_name/conf/authz`. For example, we specify that
63 only admin is allowed to push to develop branch
64
65 .. code-block:: ini
66
67 [/branches/develop]
68 * = r
69 admin = rw
70
71
72 For more example see:
73 `<https://svn.apache.org/repos/asf/subversion/trunk/subversion/mod_authz_svn/INSTALL/>`_
74
75 Those rules also work for paths, so not only branches but all different
76 paths inside the repository can be specified.
77
78 6. Reload Apache. If all is configured correctly it should not be allowed to
79 commit according to specified rules.
80
@@ -0,0 +1,48 b''
1 .. _views-ref:
2
3 views
4 =====
5
6 push (EE only)
7 --------------
8
9 .. py:function:: push(apiuser, repoid, remote_uri=<Optional:None>)
10
11 Triggers a push on the given repository from a remote location. You
12 can use this to keep remote repositories up-to-date.
13
14 This command can only be run using an |authtoken| with admin
15 rights to the specified repository. For more information,
16 see :ref:`config-token-ref`.
17
18 This command takes the following options:
19
20 :param apiuser: This is filled automatically from the |authtoken|.
21 :type apiuser: AuthUser
22 :param repoid: The repository name or repository ID.
23 :type repoid: str or int
24 :param remote_uri: Optional remote URI to pass in for push
25 :type remote_uri: str
26
27 Example output:
28
29 .. code-block:: bash
30
31 id : <id_given_in_input>
32 result : {
33 "msg": "Pushed to url `<remote_url>` on repo `<repository name>`"
34 "repository": "<repository name>"
35 }
36 error : null
37
38 Example error output:
39
40 .. code-block:: bash
41
42 id : <id_given_in_input>
43 result : null
44 error : {
45 "Unable to push changes to `<remote_url>`"
46 }
47
48
@@ -0,0 +1,112 b''
1 .. _config-ldap-groups-ref:
2
3 LDAP/AD With User Groups Sync
4 -----------------------------
5
6 |RCM| supports LDAP (Lightweight Directory Access Protocol) or
7 AD (active Directory) authentication.
8 All LDAP versions are supported, with the following |RCM| plugins managing each:
9
10 * For LDAP/AD with user group sync use ``LDAP + User Groups (egg:rhodecode-enterprise-ee#ldap_group)``
11
12 RhodeCode reads all data defined from plugin and creates corresponding
13 accounts on local database after receiving data from LDAP. This is done on
14 every user log-in including operations like pushing/pulling/checkout.
15 In addition group membership is read from LDAP and following operations are done:
16
17 - automatic addition of user to |RCM| user group
18 - automatic removal of user from any other |RCM| user groups not specified in LDAP.
19 The removal is done *only* on groups that are marked to be synced from ldap.
20 This setting can be changed in advanced settings on user groups
21 - automatic creation of user groups if they aren't yet existing in |RCM|
22 - marking user as super-admins if he is a member of any admin group defined in plugin settings
23
24 This plugin is available only in EE Edition.
25
26 .. important::
27
28 The email used with your |RCE| super-admin account needs to match the email
29 address attached to your admin profile in LDAP. This is because
30 within |RCE| the user email needs to be unique, and multiple users
31 cannot share an email account.
32
33 Likewise, if as an admin you also have a user account, the email address
34 attached to the user account needs to be different.
35
36
37 LDAP Configuration Steps
38 ^^^^^^^^^^^^^^^^^^^^^^^^
39
40 To configure |LDAP|, use the following steps:
41
42 1. From the |RCM| interface, select
43 :menuselection:`Admin --> Authentication`
44 2. Enable the ldap+ groups plugin and select :guilabel:`Save`
45 3. Select the :guilabel:`Enabled` check box in the plugin configuration section
46 4. Add the required LDAP information and :guilabel:`Save`, for more details,
47 see :ref:`config-ldap-groups-examples`
48
49 For a more detailed description of LDAP objects, see :ref:`ldap-gloss-ref`:
50
51 .. _config-ldap-groups-examples:
52
53 Example LDAP configuration
54 ^^^^^^^^^^^^^^^^^^^^^^^^^^
55 .. code-block:: bash
56
57 # Auth Cache TTL, Defines the caching for authentication to offload LDAP server.
58 # This means that cache result will be saved for 3600 before contacting LDAP server to verify the user access
59 3600
60 # Host, comma seperated format is optionally possible to specify more than 1 server
61 https://ldap1.server.com/ldap-admin/,https://ldap2.server.com/ldap-admin/
62 # Default LDAP Port, use 689 for LDAPS
63 389
64 # Account, used for SimpleBind if LDAP server requires an authentication
65 e.g admin@server.com
66 # Password used for simple bind
67 ldap-user-password
68 # LDAP connection security
69 LDAPS
70 # Certificate checks level
71 DEMAND
72 # Base DN
73 cn=Rufus Magillacuddy,ou=users,dc=rhodecode,dc=com
74 # User Search Base
75 ou=groups,ou=users
76 # LDAP search filter to narrow the results
77 (objectClass=person)
78 # LDAP search scope
79 SUBTREE
80 # Login attribute
81 sAMAccountName
82 # First Name Attribute to read
83 givenName
84 # Last Name Attribute to read
85 sn
86 # Email Attribute to read email address from
87 mail
88 # group extraction method
89 rfc2307bis
90 # Group search base
91 ou=RC-Groups
92 # Group Name Attribute, field to read the group name from
93 sAMAAccountName
94 # User Member of Attribute, field in which groups are stored
95 memberOf
96 # LDAP Group Search Filter, allows narrowing the results
97
98 # Admin Groups. Comma separated list of groups. If user is member of
99 # any of those he will be marked as super-admin in RhodeCode
100 admins, management
101
102
103 Below is example setup that can be used with Active Directory and ldap groups.
104
105 .. image:: ../images/ldap-groups-example.png
106 :alt: LDAP/AD setup example
107 :scale: 50 %
108
109 .. toctree::
110
111 ldap-active-directory
112 ldap-authentication No newline at end of file
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,139 b''
1 |RCE| 4.12.0 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2018-04-24
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13 - Svn: added support for RhodeCode integration framework. All integrations like
14 slack, email, Jenkins now also fully work for SVN.
15 - Integrations: added new dedicated Jenkins integration with the support of
16 CSRF authentication. Available in EE edition only.
17 - Automation: added new bi-directional remote sync. RhodeCode instances can now
18 automatically push or pull from/to remote locations. This feature is powered
19 by the Scheduler of 4.11 release, and it is required to be enabled for this feature to work.
20 Available in EE edition only.
21 - Mercurial: path-based permissions. RhodeCode can now use Mercurials narrowhg
22 to implement path-based permissions. All permissions are read from .hg/hgacl.
23 Thanks to the great contribution from Sandu Turcan.
24 - VCS: added new diff caches. Available as an option under vcs settings.
25 Diff caches work on pull-request, or individual commits for greater
26 performance and reduced memory usage. This feature increases speed of large
27 pull requests significantly. In addition for pull requests it will allow
28 showing old closed pull requests even if commits from source were removed,
29 further enhancing auditing capabilities.
30 - Audit: added few new audit log entries especially around changing permissions.
31 - LDAP: added connection pinning and timeout option to ldap plugin. This should
32 prevent problems when connection to LDAP is not stable causing RhodeCode
33 instances to freeze waiting on LDAP connections.
34 - User groups: expose public user group profiles. Allows to see members of a user
35 groups by other team members, if they have proper permissions.
36 - UI: show pull request page in quick nav menu on my account for quicker access.
37 - UI: hidden/outdated comments now have visible markers next to line numbers.
38 This allows access to them without showing all hidden comments.
39
40
41 General
42 ^^^^^^^
43
44 - Ssh: show conflicting fingerprint when adding an already existing key.
45 Helps to track why adding a key failed.
46 - System info: added ulimit to system info. This is causing lots of problems
47 when we hit any of those limits, that is why it's important to show this.
48 - Repository settings: add hidden view to force re-install hooks.
49 Available under /{repo_name}/settings/advanced/hooks
50 - Integrations: Webhook now handles response errors and show response for
51 easier debugging.
52 - Cli: speed up CLI execution start by skipping auth plugin search/registry.
53 - SVN: added an example in the docs on how to enable path-based permissions.
54 - LDAP: enable connection recycling on LDAP plugin.
55 - Auth plugins: use a nicer visual display of auth plugins that would
56 highlight that order of enabled plugins does matter.
57 - Events: expose shadow repo build url.
58 - Events: expose pull request title and uid in event data.
59 - API: enable setting sync flag for user groups on create/edit.
60 - API: update pull method with a possible specification of the url
61 - Logging: improved consistency of auth plugins logs.
62 - Logging: improved log for ssl required
63 - Dependencies: bumped mercurial to 4.4 series
64 - Dependencies: bumped zope.cachedescriptors==4.3.1
65 - Dependencies: bumped zope.deprecation==4.3.0
66 - Dependencies: bumped zope.event==4.3.0
67 - Dependencies: bumped zope.interface==4.4.3
68 - Dependencies: bumped graphviz 0.8.2
69 - Dependencies: bumped to ipaddress 0.1.19
70 - Dependencies: bumped pyexpect to 4.3.1
71 - Dependencies: bumped ws4py to 0.4.3
72 - Dependencies: bumped bleach to 2.1.2
73 - Dependencies: bumped html5lib 1.0.1
74 - Dependencies: bumped greenlet to 0.4.13
75 - Dependencies: bumped markdown to 2.6.11
76 - Dependencies: bumped psutil to 5.4.3
77 - Dependencies: bumped beaker to 1.9.1
78 - Dependencies: bumped alembic to 0.6.8 release.
79 - Dependencies: bumped supervisor to 3.3.4
80 - Dependencies: bumped pyexpect to 4.4.0 and scandir to 1.7
81 - Dependencies: bumped appenlight client to 0.6.25
82 - Dependencies: don't require full mysql lib for the db driver.
83 Reduces installation package size by around 100MB.
84
85
86 Security
87 ^^^^^^^^
88
89 - My account: changing email in my account now requires providing user
90 access password. This is a case for only RhodeCode built-in accounts.
91 Prevents adding recovery email by unauthorized users who gain
92 access to logged in session of user.
93 - Logging: fix leaking of tokens to logging.
94 - General: serialize the repo name in repo checks to prevent potential
95 html injections by providing a malformed url.
96
97
98 Performance
99 ^^^^^^^^^^^
100
101 - Diffs: don't use recurred diffset attachment in diffs. This makes
102 this structure much harder to garbage collect. Reduces memory usage.
103 - Diff cache: added caching for better performance of large pull requests.
104
105
106 Fixes
107 ^^^^^
108
109 - Age helper: fix issues with proper timezone detection for certain timezones.
110 Fixes wrong age display in few cases.
111 - API: added audit logs for user group related calls that were
112 accidentally missing.
113 - Diffs: fix and improve line selections and anchor links.
114 - Pull requests: fixed cases with default expected refs are closed or unavailable.
115 For Mercurial with closed default branch a compare across forks could fail.
116 - Core: properly report 502 errors for gevent and gunicorn.
117 Gevent wtih Gunicorn doesn't raise normal pycurl errors.
118 - Auth plugins: fixed problem with cache of settings in multi-worker mode.
119 The previous implementation had a bug that cached the settings in each class,
120 caused not refreshing the update of settings in multi-worker mode.
121 Only restart of RhodeCode loaded new settings.
122 - Audit logs: properly handle query syntax in the search field.
123 - Repositories: better handling of missing requirements errors for repositories.
124 - API: fixed problems with repository fork/create using celery backend.
125 - VCS settings: added missing flash message on validation errors to prevent
126 missing out some field input validation problems.
127
128
129 Upgrade notes
130 ^^^^^^^^^^^^^
131
132 - This release adds support for SVN hook. This required lots of changes on how we
133 handle SVN protocol. We did thoughtful tests for SVN compatibility.
134 Please be advised to check the behaviour of SVN repositories during this update.
135
136 - Diff caches are turned off by default for backward compatibility. We however recommend
137 turning them on either individually for bigger repositories or globally for every repository.
138 This setting can be found in admin > settings > vcs, or repository > settings > vcs
139
@@ -0,0 +1,20 b''
1 diff -rup Beaker-1.9.1-orig/beaker/container.py Beaker-1.9.1/beaker/container.py
2 --- Beaker-1.9.1-orig/beaker/container.py 2018-04-10 10:23:04.000000000 +0200
3 +++ Beaker-1.9.1/beaker/container.py 2018-04-10 10:23:34.000000000 +0200
4 @@ -353,13 +353,13 @@ class Value(object):
5 debug("get_value returning old value while new one is created")
6 return value
7 else:
8 - debug("lock_creatfunc (didnt wait)")
9 + debug("lock_creatfunc `%s` (didnt wait)", self.createfunc.__name__)
10 has_createlock = True
11
12 if not has_createlock:
13 - debug("lock_createfunc (waiting)")
14 + debug("lock_createfunc `%s` (waiting)", self.createfunc.__name__)
15 creation_lock.acquire()
16 - debug("lock_createfunc (waited)")
17 + debug("lock_createfunc `%s` (waited)", self.createfunc.__name__)
18
19 try:
20 # see if someone created the value already
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,6 +1,6 b''
1 [bumpversion]
1 [bumpversion]
2 current_version = 4.11.6
2 current_version = 4.12.0
3 message = release: Bump version {current_version} to {new_version}
3 message = release: Bump version {current_version} to {new_version}
4
4
5 [bumpversion:file:rhodecode/VERSION]
5 [bumpversion:file:rhodecode/VERSION]
6
6
@@ -1,33 +1,28 b''
1 [DEFAULT]
1 [DEFAULT]
2 done = false
2 done = false
3
3
4 [task:bump_version]
4 [task:bump_version]
5 done = true
5 done = true
6
6
7 [task:rc_tools_pinned]
7 [task:rc_tools_pinned]
8 done = true
9
8
10 [task:fixes_on_stable]
9 [task:fixes_on_stable]
11 done = true
12
10
13 [task:pip2nix_generated]
11 [task:pip2nix_generated]
14 done = true
15
12
16 [task:changelog_updated]
13 [task:changelog_updated]
17 done = true
18
14
19 [task:generate_api_docs]
15 [task:generate_api_docs]
20 done = true
16
17 [task:updated_translation]
21
18
22 [release]
19 [release]
23 state = prepared
20 state = in_progress
24 version = 4.11.6
21 version = 4.12.0
25
26 [task:updated_translation]
27
22
28 [task:generate_js_routes]
23 [task:generate_js_routes]
29
24
30 [task:updated_trial_license]
25 [task:updated_trial_license]
31
26
32 [task:generate_oss_licenses]
27 [task:generate_oss_licenses]
33
28
@@ -1,54 +1,51 b''
1 # top level files
1 # top level files
2
2
3 include MANIFEST.in
3 include MANIFEST.in
4 include README.rst
4 include README.rst
5 include CHANGES.rst
5 include CHANGES.rst
6 include LICENSE.txt
6 include LICENSE.txt
7
7
8 include rhodecode/VERSION
8 include rhodecode/VERSION
9
9
10 # docs
10 # docs
11 recursive-include docs *
11 recursive-include docs *
12
12
13 # all config files
13 # all config files
14 recursive-include configs *
14 recursive-include configs *
15
15
16 # translations
16 # translations
17 recursive-include rhodecode/i18n *
17 recursive-include rhodecode/i18n *
18
18
19 # hook templates
20 recursive-include rhodecode/config/hook_templates *
21
22 # non-python core stuff
19 # non-python core stuff
23 recursive-include rhodecode *.cfg
20 recursive-include rhodecode *.cfg
24 recursive-include rhodecode *.json
21 recursive-include rhodecode *.json
25 recursive-include rhodecode *.ini_tmpl
22 recursive-include rhodecode *.ini_tmpl
26 recursive-include rhodecode *.sh
23 recursive-include rhodecode *.sh
27 recursive-include rhodecode *.mako
24 recursive-include rhodecode *.mako
28
25
29 # 502 page
26 # 502 page
30 include rhodecode/public/502.html
27 include rhodecode/public/502.html
31
28
32
29
33 # images, css
30 # images, css
34 include rhodecode/public/css/*.css
31 include rhodecode/public/css/*.css
35 include rhodecode/public/images/*.*
32 include rhodecode/public/images/*.*
36 include rhodecode/public/images/ee_features/*.*
33 include rhodecode/public/images/ee_features/*.*
37
34
38 # sound files
35 # sound files
39 include rhodecode/public/sounds/*.mp3
36 include rhodecode/public/sounds/*.mp3
40 include rhodecode/public/sounds/*.wav
37 include rhodecode/public/sounds/*.wav
41
38
42 # fonts
39 # fonts
43 recursive-include rhodecode/public/fonts/ProximaNova *
40 recursive-include rhodecode/public/fonts/ProximaNova *
44 recursive-include rhodecode/public/fonts/RCIcons *
41 recursive-include rhodecode/public/fonts/RCIcons *
45
42
46 # js
43 # js
47 recursive-include rhodecode/public/js *
44 recursive-include rhodecode/public/js *
48
45
49 # templates
46 # templates
50 recursive-include rhodecode/templates *
47 recursive-include rhodecode/templates *
51
48
52 # skip any tests files
49 # skip any tests files
53 recursive-exclude rhodecode/tests *
50 recursive-exclude rhodecode/tests *
54
51
@@ -1,722 +1,719 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 use = egg:waitress#main
54 use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 threads = 5
56 threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 max_request_body_size = 107374182400
58 max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 asyncore_use_poll = true
61 asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 #use = egg:gunicorn#main
69 #use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 #workers = 2
74 #workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
76 ## generally recommended to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 #proc_name = rhodecode
79 #proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 #worker_class = gevent
82 #worker_class = gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 #max_requests = 1000
87 #max_requests = 1000
88 #max_requests_jitter = 30
88 #max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 #timeout = 21600
91 #timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 # During development the we want to have the debug toolbar enabled
111 # During development the we want to have the debug toolbar enabled
112 pyramid.includes =
112 pyramid.includes =
113 pyramid_debugtoolbar
113 pyramid_debugtoolbar
114 rhodecode.lib.middleware.request_wrapper
114 rhodecode.lib.middleware.request_wrapper
115
115
116 pyramid.reload_templates = true
116 pyramid.reload_templates = true
117
117
118 debugtoolbar.hosts = 0.0.0.0/0
118 debugtoolbar.hosts = 0.0.0.0/0
119 debugtoolbar.exclude_prefixes =
119 debugtoolbar.exclude_prefixes =
120 /css
120 /css
121 /fonts
121 /fonts
122 /images
122 /images
123 /js
123 /js
124
124
125 ## RHODECODE PLUGINS ##
125 ## RHODECODE PLUGINS ##
126 rhodecode.includes =
126 rhodecode.includes =
127 rhodecode.api
127 rhodecode.api
128
128
129
129
130 # api prefix url
130 # api prefix url
131 rhodecode.api.url = /_admin/api
131 rhodecode.api.url = /_admin/api
132
132
133
133
134 ## END RHODECODE PLUGINS ##
134 ## END RHODECODE PLUGINS ##
135
135
136 ## encryption key used to encrypt social plugin tokens,
136 ## encryption key used to encrypt social plugin tokens,
137 ## remote_urls with credentials etc, if not set it defaults to
137 ## remote_urls with credentials etc, if not set it defaults to
138 ## `beaker.session.secret`
138 ## `beaker.session.secret`
139 #rhodecode.encrypted_values.secret =
139 #rhodecode.encrypted_values.secret =
140
140
141 ## decryption strict mode (enabled by default). It controls if decryption raises
141 ## decryption strict mode (enabled by default). It controls if decryption raises
142 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
142 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
143 #rhodecode.encrypted_values.strict = false
143 #rhodecode.encrypted_values.strict = false
144
144
145 ## return gzipped responses from Rhodecode (static files/application)
145 ## return gzipped responses from Rhodecode (static files/application)
146 gzip_responses = false
146 gzip_responses = false
147
147
148 ## autogenerate javascript routes file on startup
148 ## autogenerate javascript routes file on startup
149 generate_js_files = false
149 generate_js_files = false
150
150
151 ## Optional Languages
151 ## Optional Languages
152 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
152 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
153 lang = en
153 lang = en
154
154
155 ## perform a full repository scan on each server start, this should be
155 ## perform a full repository scan on each server start, this should be
156 ## set to false after first startup, to allow faster server restarts.
156 ## set to false after first startup, to allow faster server restarts.
157 startup.import_repos = false
157 startup.import_repos = false
158
158
159 ## Uncomment and set this path to use archive download cache.
159 ## Uncomment and set this path to use archive download cache.
160 ## Once enabled, generated archives will be cached at this location
160 ## Once enabled, generated archives will be cached at this location
161 ## and served from the cache during subsequent requests for the same archive of
161 ## and served from the cache during subsequent requests for the same archive of
162 ## the repository.
162 ## the repository.
163 #archive_cache_dir = /tmp/tarballcache
163 #archive_cache_dir = /tmp/tarballcache
164
164
165 ## URL at which the application is running. This is used for bootstraping
165 ## URL at which the application is running. This is used for bootstraping
166 ## requests in context when no web request is available. Used in ishell, or
166 ## requests in context when no web request is available. Used in ishell, or
167 ## SSH calls. Set this for events to receive proper url for SSH calls.
167 ## SSH calls. Set this for events to receive proper url for SSH calls.
168 app.base_url = http://rhodecode.local
168 app.base_url = http://rhodecode.local
169
169
170 ## change this to unique ID for security
170 ## change this to unique ID for security
171 app_instance_uuid = rc-production
171 app_instance_uuid = rc-production
172
172
173 ## cut off limit for large diffs (size in bytes). If overall diff size on
173 ## cut off limit for large diffs (size in bytes). If overall diff size on
174 ## commit, or pull request exceeds this limit this diff will be displayed
174 ## commit, or pull request exceeds this limit this diff will be displayed
175 ## partially. E.g 512000 == 512Kb
175 ## partially. E.g 512000 == 512Kb
176 cut_off_limit_diff = 512000
176 cut_off_limit_diff = 512000
177
177
178 ## cut off limit for large files inside diffs (size in bytes). Each individual
178 ## cut off limit for large files inside diffs (size in bytes). Each individual
179 ## file inside diff which exceeds this limit will be displayed partially.
179 ## file inside diff which exceeds this limit will be displayed partially.
180 ## E.g 128000 == 128Kb
180 ## E.g 128000 == 128Kb
181 cut_off_limit_file = 128000
181 cut_off_limit_file = 128000
182
182
183 ## use cache version of scm repo everywhere
183 ## use cache version of scm repo everywhere
184 vcs_full_cache = true
184 vcs_full_cache = true
185
185
186 ## force https in RhodeCode, fixes https redirects, assumes it's always https
186 ## force https in RhodeCode, fixes https redirects, assumes it's always https
187 ## Normally this is controlled by proper http flags sent from http server
187 ## Normally this is controlled by proper http flags sent from http server
188 force_https = false
188 force_https = false
189
189
190 ## use Strict-Transport-Security headers
190 ## use Strict-Transport-Security headers
191 use_htsts = false
191 use_htsts = false
192
192
193 ## number of commits stats will parse on each iteration
194 commit_parse_limit = 25
195
196 ## git rev filter option, --all is the default filter, if you need to
193 ## git rev filter option, --all is the default filter, if you need to
197 ## hide all refs in changelog switch this to --branches --tags
194 ## hide all refs in changelog switch this to --branches --tags
198 git_rev_filter = --branches --tags
195 git_rev_filter = --branches --tags
199
196
200 # Set to true if your repos are exposed using the dumb protocol
197 # Set to true if your repos are exposed using the dumb protocol
201 git_update_server_info = false
198 git_update_server_info = false
202
199
203 ## RSS/ATOM feed options
200 ## RSS/ATOM feed options
204 rss_cut_off_limit = 256000
201 rss_cut_off_limit = 256000
205 rss_items_per_page = 10
202 rss_items_per_page = 10
206 rss_include_diff = false
203 rss_include_diff = false
207
204
208 ## gist URL alias, used to create nicer urls for gist. This should be an
205 ## gist URL alias, used to create nicer urls for gist. This should be an
209 ## url that does rewrites to _admin/gists/{gistid}.
206 ## url that does rewrites to _admin/gists/{gistid}.
210 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
207 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
211 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
208 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
212 gist_alias_url =
209 gist_alias_url =
213
210
214 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
211 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
215 ## used for access.
212 ## used for access.
216 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
213 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
217 ## came from the the logged in user who own this authentication token.
214 ## came from the the logged in user who own this authentication token.
218 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
215 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
219 ## authentication token. Such view would be only accessible when used together
216 ## authentication token. Such view would be only accessible when used together
220 ## with this authentication token
217 ## with this authentication token
221 ##
218 ##
222 ## list of all views can be found under `/_admin/permissions/auth_token_access`
219 ## list of all views can be found under `/_admin/permissions/auth_token_access`
223 ## The list should be "," separated and on a single line.
220 ## The list should be "," separated and on a single line.
224 ##
221 ##
225 ## Most common views to enable:
222 ## Most common views to enable:
226 # RepoCommitsView:repo_commit_download
223 # RepoCommitsView:repo_commit_download
227 # RepoCommitsView:repo_commit_patch
224 # RepoCommitsView:repo_commit_patch
228 # RepoCommitsView:repo_commit_raw
225 # RepoCommitsView:repo_commit_raw
229 # RepoCommitsView:repo_commit_raw@TOKEN
226 # RepoCommitsView:repo_commit_raw@TOKEN
230 # RepoFilesView:repo_files_diff
227 # RepoFilesView:repo_files_diff
231 # RepoFilesView:repo_archivefile
228 # RepoFilesView:repo_archivefile
232 # RepoFilesView:repo_file_raw
229 # RepoFilesView:repo_file_raw
233 # GistView:*
230 # GistView:*
234 api_access_controllers_whitelist =
231 api_access_controllers_whitelist =
235
232
236 ## default encoding used to convert from and to unicode
233 ## default encoding used to convert from and to unicode
237 ## can be also a comma separated list of encoding in case of mixed encodings
234 ## can be also a comma separated list of encoding in case of mixed encodings
238 default_encoding = UTF-8
235 default_encoding = UTF-8
239
236
240 ## instance-id prefix
237 ## instance-id prefix
241 ## a prefix key for this instance used for cache invalidation when running
238 ## a prefix key for this instance used for cache invalidation when running
242 ## multiple instances of rhodecode, make sure it's globally unique for
239 ## multiple instances of rhodecode, make sure it's globally unique for
243 ## all running rhodecode instances. Leave empty if you don't use it
240 ## all running rhodecode instances. Leave empty if you don't use it
244 instance_id =
241 instance_id =
245
242
246 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
243 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
247 ## of an authentication plugin also if it is disabled by it's settings.
244 ## of an authentication plugin also if it is disabled by it's settings.
248 ## This could be useful if you are unable to log in to the system due to broken
245 ## This could be useful if you are unable to log in to the system due to broken
249 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
246 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
250 ## module to log in again and fix the settings.
247 ## module to log in again and fix the settings.
251 ##
248 ##
252 ## Available builtin plugin IDs (hash is part of the ID):
249 ## Available builtin plugin IDs (hash is part of the ID):
253 ## egg:rhodecode-enterprise-ce#rhodecode
250 ## egg:rhodecode-enterprise-ce#rhodecode
254 ## egg:rhodecode-enterprise-ce#pam
251 ## egg:rhodecode-enterprise-ce#pam
255 ## egg:rhodecode-enterprise-ce#ldap
252 ## egg:rhodecode-enterprise-ce#ldap
256 ## egg:rhodecode-enterprise-ce#jasig_cas
253 ## egg:rhodecode-enterprise-ce#jasig_cas
257 ## egg:rhodecode-enterprise-ce#headers
254 ## egg:rhodecode-enterprise-ce#headers
258 ## egg:rhodecode-enterprise-ce#crowd
255 ## egg:rhodecode-enterprise-ce#crowd
259 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
256 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
260
257
261 ## alternative return HTTP header for failed authentication. Default HTTP
258 ## alternative return HTTP header for failed authentication. Default HTTP
262 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
259 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
263 ## handling that causing a series of failed authentication calls.
260 ## handling that causing a series of failed authentication calls.
264 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
261 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
265 ## This will be served instead of default 401 on bad authnetication
262 ## This will be served instead of default 401 on bad authnetication
266 auth_ret_code =
263 auth_ret_code =
267
264
268 ## use special detection method when serving auth_ret_code, instead of serving
265 ## use special detection method when serving auth_ret_code, instead of serving
269 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
266 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
270 ## and then serve auth_ret_code to clients
267 ## and then serve auth_ret_code to clients
271 auth_ret_code_detection = false
268 auth_ret_code_detection = false
272
269
273 ## locking return code. When repository is locked return this HTTP code. 2XX
270 ## locking return code. When repository is locked return this HTTP code. 2XX
274 ## codes don't break the transactions while 4XX codes do
271 ## codes don't break the transactions while 4XX codes do
275 lock_ret_code = 423
272 lock_ret_code = 423
276
273
277 ## allows to change the repository location in settings page
274 ## allows to change the repository location in settings page
278 allow_repo_location_change = true
275 allow_repo_location_change = true
279
276
280 ## allows to setup custom hooks in settings page
277 ## allows to setup custom hooks in settings page
281 allow_custom_hooks_settings = true
278 allow_custom_hooks_settings = true
282
279
283 ## generated license token, goto license page in RhodeCode settings to obtain
280 ## generated license token, goto license page in RhodeCode settings to obtain
284 ## new token
281 ## new token
285 license_token =
282 license_token =
286
283
287 ## supervisor connection uri, for managing supervisor and logs.
284 ## supervisor connection uri, for managing supervisor and logs.
288 supervisor.uri =
285 supervisor.uri =
289 ## supervisord group name/id we only want this RC instance to handle
286 ## supervisord group name/id we only want this RC instance to handle
290 supervisor.group_id = dev
287 supervisor.group_id = dev
291
288
292 ## Display extended labs settings
289 ## Display extended labs settings
293 labs_settings_active = true
290 labs_settings_active = true
294
291
295 ####################################
292 ####################################
296 ### CELERY CONFIG ####
293 ### CELERY CONFIG ####
297 ####################################
294 ####################################
298 ## run: /path/to/celery worker \
295 ## run: /path/to/celery worker \
299 ## -E --beat --app rhodecode.lib.celerylib.loader \
296 ## -E --beat --app rhodecode.lib.celerylib.loader \
300 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
297 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
301 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
298 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
302
299
303 use_celery = false
300 use_celery = false
304
301
305 ## connection url to the message broker (default rabbitmq)
302 ## connection url to the message broker (default rabbitmq)
306 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
303 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
307
304
308 ## maximum tasks to execute before worker restart
305 ## maximum tasks to execute before worker restart
309 celery.max_tasks_per_child = 100
306 celery.max_tasks_per_child = 100
310
307
311 ## tasks will never be sent to the queue, but executed locally instead.
308 ## tasks will never be sent to the queue, but executed locally instead.
312 celery.task_always_eager = false
309 celery.task_always_eager = false
313
310
314 ####################################
311 ####################################
315 ### BEAKER CACHE ####
312 ### BEAKER CACHE ####
316 ####################################
313 ####################################
317 # default cache dir for templates. Putting this into a ramdisk
314 # default cache dir for templates. Putting this into a ramdisk
318 ## can boost performance, eg. %(here)s/data_ramdisk
315 ## can boost performance, eg. %(here)s/data_ramdisk
319 cache_dir = %(here)s/data
316 cache_dir = %(here)s/data
320
317
321 ## locking and default file storage for Beaker. Putting this into a ramdisk
318 ## locking and default file storage for Beaker. Putting this into a ramdisk
322 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
319 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
323 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
320 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
324 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
321 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
325
322
326 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
323 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
327
324
328 beaker.cache.super_short_term.type = memory
325 beaker.cache.super_short_term.type = memory
329 beaker.cache.super_short_term.expire = 10
326 beaker.cache.super_short_term.expire = 10
330 beaker.cache.super_short_term.key_length = 256
327 beaker.cache.super_short_term.key_length = 256
331
328
332 beaker.cache.short_term.type = memory
329 beaker.cache.short_term.type = memory
333 beaker.cache.short_term.expire = 60
330 beaker.cache.short_term.expire = 60
334 beaker.cache.short_term.key_length = 256
331 beaker.cache.short_term.key_length = 256
335
332
336 beaker.cache.long_term.type = memory
333 beaker.cache.long_term.type = memory
337 beaker.cache.long_term.expire = 36000
334 beaker.cache.long_term.expire = 36000
338 beaker.cache.long_term.key_length = 256
335 beaker.cache.long_term.key_length = 256
339
336
340 beaker.cache.sql_cache_short.type = memory
337 beaker.cache.sql_cache_short.type = memory
341 beaker.cache.sql_cache_short.expire = 10
338 beaker.cache.sql_cache_short.expire = 10
342 beaker.cache.sql_cache_short.key_length = 256
339 beaker.cache.sql_cache_short.key_length = 256
343
340
344 ## default is memory cache, configure only if required
341 ## default is memory cache, configure only if required
345 ## using multi-node or multi-worker setup
342 ## using multi-node or multi-worker setup
346 #beaker.cache.auth_plugins.type = ext:database
343 #beaker.cache.auth_plugins.type = ext:database
347 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
344 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
348 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
345 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
349 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
346 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
350 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
347 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
351 #beaker.cache.auth_plugins.sa.pool_size = 10
348 #beaker.cache.auth_plugins.sa.pool_size = 10
352 #beaker.cache.auth_plugins.sa.max_overflow = 0
349 #beaker.cache.auth_plugins.sa.max_overflow = 0
353
350
354 beaker.cache.repo_cache_long.type = memorylru_base
351 beaker.cache.repo_cache_long.type = memorylru_base
355 beaker.cache.repo_cache_long.max_items = 4096
352 beaker.cache.repo_cache_long.max_items = 4096
356 beaker.cache.repo_cache_long.expire = 2592000
353 beaker.cache.repo_cache_long.expire = 2592000
357
354
358 ## default is memorylru_base cache, configure only if required
355 ## default is memorylru_base cache, configure only if required
359 ## using multi-node or multi-worker setup
356 ## using multi-node or multi-worker setup
360 #beaker.cache.repo_cache_long.type = ext:memcached
357 #beaker.cache.repo_cache_long.type = ext:memcached
361 #beaker.cache.repo_cache_long.url = localhost:11211
358 #beaker.cache.repo_cache_long.url = localhost:11211
362 #beaker.cache.repo_cache_long.expire = 1209600
359 #beaker.cache.repo_cache_long.expire = 1209600
363 #beaker.cache.repo_cache_long.key_length = 256
360 #beaker.cache.repo_cache_long.key_length = 256
364
361
365 ####################################
362 ####################################
366 ### BEAKER SESSION ####
363 ### BEAKER SESSION ####
367 ####################################
364 ####################################
368
365
369 ## .session.type is type of storage options for the session, current allowed
366 ## .session.type is type of storage options for the session, current allowed
370 ## types are file, ext:memcached, ext:database, and memory (default).
367 ## types are file, ext:memcached, ext:database, and memory (default).
371 beaker.session.type = file
368 beaker.session.type = file
372 beaker.session.data_dir = %(here)s/data/sessions/data
369 beaker.session.data_dir = %(here)s/data/sessions/data
373
370
374 ## db based session, fast, and allows easy management over logged in users
371 ## db based session, fast, and allows easy management over logged in users
375 #beaker.session.type = ext:database
372 #beaker.session.type = ext:database
376 #beaker.session.table_name = db_session
373 #beaker.session.table_name = db_session
377 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
374 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
378 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
375 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
379 #beaker.session.sa.pool_recycle = 3600
376 #beaker.session.sa.pool_recycle = 3600
380 #beaker.session.sa.echo = false
377 #beaker.session.sa.echo = false
381
378
382 beaker.session.key = rhodecode
379 beaker.session.key = rhodecode
383 beaker.session.secret = develop-rc-uytcxaz
380 beaker.session.secret = develop-rc-uytcxaz
384 beaker.session.lock_dir = %(here)s/data/sessions/lock
381 beaker.session.lock_dir = %(here)s/data/sessions/lock
385
382
386 ## Secure encrypted cookie. Requires AES and AES python libraries
383 ## Secure encrypted cookie. Requires AES and AES python libraries
387 ## you must disable beaker.session.secret to use this
384 ## you must disable beaker.session.secret to use this
388 #beaker.session.encrypt_key = key_for_encryption
385 #beaker.session.encrypt_key = key_for_encryption
389 #beaker.session.validate_key = validation_key
386 #beaker.session.validate_key = validation_key
390
387
391 ## sets session as invalid(also logging out user) if it haven not been
388 ## sets session as invalid(also logging out user) if it haven not been
392 ## accessed for given amount of time in seconds
389 ## accessed for given amount of time in seconds
393 beaker.session.timeout = 2592000
390 beaker.session.timeout = 2592000
394 beaker.session.httponly = true
391 beaker.session.httponly = true
395 ## Path to use for the cookie. Set to prefix if you use prefix middleware
392 ## Path to use for the cookie. Set to prefix if you use prefix middleware
396 #beaker.session.cookie_path = /custom_prefix
393 #beaker.session.cookie_path = /custom_prefix
397
394
398 ## uncomment for https secure cookie
395 ## uncomment for https secure cookie
399 beaker.session.secure = false
396 beaker.session.secure = false
400
397
401 ## auto save the session to not to use .save()
398 ## auto save the session to not to use .save()
402 beaker.session.auto = false
399 beaker.session.auto = false
403
400
404 ## default cookie expiration time in seconds, set to `true` to set expire
401 ## default cookie expiration time in seconds, set to `true` to set expire
405 ## at browser close
402 ## at browser close
406 #beaker.session.cookie_expires = 3600
403 #beaker.session.cookie_expires = 3600
407
404
408 ###################################
405 ###################################
409 ## SEARCH INDEXING CONFIGURATION ##
406 ## SEARCH INDEXING CONFIGURATION ##
410 ###################################
407 ###################################
411 ## Full text search indexer is available in rhodecode-tools under
408 ## Full text search indexer is available in rhodecode-tools under
412 ## `rhodecode-tools index` command
409 ## `rhodecode-tools index` command
413
410
414 ## WHOOSH Backend, doesn't require additional services to run
411 ## WHOOSH Backend, doesn't require additional services to run
415 ## it works good with few dozen repos
412 ## it works good with few dozen repos
416 search.module = rhodecode.lib.index.whoosh
413 search.module = rhodecode.lib.index.whoosh
417 search.location = %(here)s/data/index
414 search.location = %(here)s/data/index
418
415
419 ########################################
416 ########################################
420 ### CHANNELSTREAM CONFIG ####
417 ### CHANNELSTREAM CONFIG ####
421 ########################################
418 ########################################
422 ## channelstream enables persistent connections and live notification
419 ## channelstream enables persistent connections and live notification
423 ## in the system. It's also used by the chat system
420 ## in the system. It's also used by the chat system
424 channelstream.enabled = false
421 channelstream.enabled = false
425
422
426 ## server address for channelstream server on the backend
423 ## server address for channelstream server on the backend
427 channelstream.server = 127.0.0.1:9800
424 channelstream.server = 127.0.0.1:9800
428
425
429 ## location of the channelstream server from outside world
426 ## location of the channelstream server from outside world
430 ## use ws:// for http or wss:// for https. This address needs to be handled
427 ## use ws:// for http or wss:// for https. This address needs to be handled
431 ## by external HTTP server such as Nginx or Apache
428 ## by external HTTP server such as Nginx or Apache
432 ## see nginx/apache configuration examples in our docs
429 ## see nginx/apache configuration examples in our docs
433 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
430 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
434 channelstream.secret = secret
431 channelstream.secret = secret
435 channelstream.history.location = %(here)s/channelstream_history
432 channelstream.history.location = %(here)s/channelstream_history
436
433
437 ## Internal application path that Javascript uses to connect into.
434 ## Internal application path that Javascript uses to connect into.
438 ## If you use proxy-prefix the prefix should be added before /_channelstream
435 ## If you use proxy-prefix the prefix should be added before /_channelstream
439 channelstream.proxy_path = /_channelstream
436 channelstream.proxy_path = /_channelstream
440
437
441
438
442 ###################################
439 ###################################
443 ## APPENLIGHT CONFIG ##
440 ## APPENLIGHT CONFIG ##
444 ###################################
441 ###################################
445
442
446 ## Appenlight is tailored to work with RhodeCode, see
443 ## Appenlight is tailored to work with RhodeCode, see
447 ## http://appenlight.com for details how to obtain an account
444 ## http://appenlight.com for details how to obtain an account
448
445
449 ## appenlight integration enabled
446 ## appenlight integration enabled
450 appenlight = false
447 appenlight = false
451
448
452 appenlight.server_url = https://api.appenlight.com
449 appenlight.server_url = https://api.appenlight.com
453 appenlight.api_key = YOUR_API_KEY
450 appenlight.api_key = YOUR_API_KEY
454 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
451 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
455
452
456 # used for JS client
453 # used for JS client
457 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
454 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
458
455
459 ## TWEAK AMOUNT OF INFO SENT HERE
456 ## TWEAK AMOUNT OF INFO SENT HERE
460
457
461 ## enables 404 error logging (default False)
458 ## enables 404 error logging (default False)
462 appenlight.report_404 = false
459 appenlight.report_404 = false
463
460
464 ## time in seconds after request is considered being slow (default 1)
461 ## time in seconds after request is considered being slow (default 1)
465 appenlight.slow_request_time = 1
462 appenlight.slow_request_time = 1
466
463
467 ## record slow requests in application
464 ## record slow requests in application
468 ## (needs to be enabled for slow datastore recording and time tracking)
465 ## (needs to be enabled for slow datastore recording and time tracking)
469 appenlight.slow_requests = true
466 appenlight.slow_requests = true
470
467
471 ## enable hooking to application loggers
468 ## enable hooking to application loggers
472 appenlight.logging = true
469 appenlight.logging = true
473
470
474 ## minimum log level for log capture
471 ## minimum log level for log capture
475 appenlight.logging.level = WARNING
472 appenlight.logging.level = WARNING
476
473
477 ## send logs only from erroneous/slow requests
474 ## send logs only from erroneous/slow requests
478 ## (saves API quota for intensive logging)
475 ## (saves API quota for intensive logging)
479 appenlight.logging_on_error = false
476 appenlight.logging_on_error = false
480
477
481 ## list of additonal keywords that should be grabbed from environ object
478 ## list of additonal keywords that should be grabbed from environ object
482 ## can be string with comma separated list of words in lowercase
479 ## can be string with comma separated list of words in lowercase
483 ## (by default client will always send following info:
480 ## (by default client will always send following info:
484 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
481 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
485 ## start with HTTP* this list be extended with additional keywords here
482 ## start with HTTP* this list be extended with additional keywords here
486 appenlight.environ_keys_whitelist =
483 appenlight.environ_keys_whitelist =
487
484
488 ## list of keywords that should be blanked from request object
485 ## list of keywords that should be blanked from request object
489 ## can be string with comma separated list of words in lowercase
486 ## can be string with comma separated list of words in lowercase
490 ## (by default client will always blank keys that contain following words
487 ## (by default client will always blank keys that contain following words
491 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
488 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
492 ## this list be extended with additional keywords set here
489 ## this list be extended with additional keywords set here
493 appenlight.request_keys_blacklist =
490 appenlight.request_keys_blacklist =
494
491
495 ## list of namespaces that should be ignores when gathering log entries
492 ## list of namespaces that should be ignores when gathering log entries
496 ## can be string with comma separated list of namespaces
493 ## can be string with comma separated list of namespaces
497 ## (by default the client ignores own entries: appenlight_client.client)
494 ## (by default the client ignores own entries: appenlight_client.client)
498 appenlight.log_namespace_blacklist =
495 appenlight.log_namespace_blacklist =
499
496
500
497
501 ################################################################################
498 ################################################################################
502 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
499 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
503 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
500 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
504 ## execute malicious code after an exception is raised. ##
501 ## execute malicious code after an exception is raised. ##
505 ################################################################################
502 ################################################################################
506 #set debug = false
503 #set debug = false
507
504
508
505
509 ##############
506 ##############
510 ## STYLING ##
507 ## STYLING ##
511 ##############
508 ##############
512 debug_style = true
509 debug_style = true
513
510
514 ###########################################
511 ###########################################
515 ### MAIN RHODECODE DATABASE CONFIG ###
512 ### MAIN RHODECODE DATABASE CONFIG ###
516 ###########################################
513 ###########################################
517 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
514 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
518 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
515 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
519 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
516 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
520 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
517 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
521
518
522 # see sqlalchemy docs for other advanced settings
519 # see sqlalchemy docs for other advanced settings
523
520
524 ## print the sql statements to output
521 ## print the sql statements to output
525 sqlalchemy.db1.echo = false
522 sqlalchemy.db1.echo = false
526 ## recycle the connections after this amount of seconds
523 ## recycle the connections after this amount of seconds
527 sqlalchemy.db1.pool_recycle = 3600
524 sqlalchemy.db1.pool_recycle = 3600
528 sqlalchemy.db1.convert_unicode = true
525 sqlalchemy.db1.convert_unicode = true
529
526
530 ## the number of connections to keep open inside the connection pool.
527 ## the number of connections to keep open inside the connection pool.
531 ## 0 indicates no limit
528 ## 0 indicates no limit
532 #sqlalchemy.db1.pool_size = 5
529 #sqlalchemy.db1.pool_size = 5
533
530
534 ## the number of connections to allow in connection pool "overflow", that is
531 ## the number of connections to allow in connection pool "overflow", that is
535 ## connections that can be opened above and beyond the pool_size setting,
532 ## connections that can be opened above and beyond the pool_size setting,
536 ## which defaults to five.
533 ## which defaults to five.
537 #sqlalchemy.db1.max_overflow = 10
534 #sqlalchemy.db1.max_overflow = 10
538
535
539
536
540 ##################
537 ##################
541 ### VCS CONFIG ###
538 ### VCS CONFIG ###
542 ##################
539 ##################
543 vcs.server.enable = true
540 vcs.server.enable = true
544 vcs.server = localhost:9900
541 vcs.server = localhost:9900
545
542
546 ## Web server connectivity protocol, responsible for web based VCS operatations
543 ## Web server connectivity protocol, responsible for web based VCS operatations
547 ## Available protocols are:
544 ## Available protocols are:
548 ## `http` - use http-rpc backend (default)
545 ## `http` - use http-rpc backend (default)
549 vcs.server.protocol = http
546 vcs.server.protocol = http
550
547
551 ## Push/Pull operations protocol, available options are:
548 ## Push/Pull operations protocol, available options are:
552 ## `http` - use http-rpc backend (default)
549 ## `http` - use http-rpc backend (default)
553 ##
550 ##
554 vcs.scm_app_implementation = http
551 vcs.scm_app_implementation = http
555
552
556 ## Push/Pull operations hooks protocol, available options are:
553 ## Push/Pull operations hooks protocol, available options are:
557 ## `http` - use http-rpc backend (default)
554 ## `http` - use http-rpc backend (default)
558 vcs.hooks.protocol = http
555 vcs.hooks.protocol = http
559
556
560 vcs.server.log_level = debug
557 vcs.server.log_level = debug
561 ## Start VCSServer with this instance as a subprocess, usefull for development
558 ## Start VCSServer with this instance as a subprocess, usefull for development
562 vcs.start_server = false
559 vcs.start_server = false
563
560
564 ## List of enabled VCS backends, available options are:
561 ## List of enabled VCS backends, available options are:
565 ## `hg` - mercurial
562 ## `hg` - mercurial
566 ## `git` - git
563 ## `git` - git
567 ## `svn` - subversion
564 ## `svn` - subversion
568 vcs.backends = hg, git, svn
565 vcs.backends = hg, git, svn
569
566
570 vcs.connection_timeout = 3600
567 vcs.connection_timeout = 3600
571 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
568 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
572 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
569 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
573 #vcs.svn.compatible_version = pre-1.8-compatible
570 #vcs.svn.compatible_version = pre-1.8-compatible
574
571
575
572
576 ############################################################
573 ############################################################
577 ### Subversion proxy support (mod_dav_svn) ###
574 ### Subversion proxy support (mod_dav_svn) ###
578 ### Maps RhodeCode repo groups into SVN paths for Apache ###
575 ### Maps RhodeCode repo groups into SVN paths for Apache ###
579 ############################################################
576 ############################################################
580 ## Enable or disable the config file generation.
577 ## Enable or disable the config file generation.
581 svn.proxy.generate_config = false
578 svn.proxy.generate_config = false
582 ## Generate config file with `SVNListParentPath` set to `On`.
579 ## Generate config file with `SVNListParentPath` set to `On`.
583 svn.proxy.list_parent_path = true
580 svn.proxy.list_parent_path = true
584 ## Set location and file name of generated config file.
581 ## Set location and file name of generated config file.
585 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
582 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
586 ## alternative mod_dav config template. This needs to be a mako template
583 ## alternative mod_dav config template. This needs to be a mako template
587 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
584 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
588 ## Used as a prefix to the `Location` block in the generated config file.
585 ## Used as a prefix to the `Location` block in the generated config file.
589 ## In most cases it should be set to `/`.
586 ## In most cases it should be set to `/`.
590 svn.proxy.location_root = /
587 svn.proxy.location_root = /
591 ## Command to reload the mod dav svn configuration on change.
588 ## Command to reload the mod dav svn configuration on change.
592 ## Example: `/etc/init.d/apache2 reload`
589 ## Example: `/etc/init.d/apache2 reload`
593 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
590 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
594 ## If the timeout expires before the reload command finishes, the command will
591 ## If the timeout expires before the reload command finishes, the command will
595 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
592 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
596 #svn.proxy.reload_timeout = 10
593 #svn.proxy.reload_timeout = 10
597
594
598 ############################################################
595 ############################################################
599 ### SSH Support Settings ###
596 ### SSH Support Settings ###
600 ############################################################
597 ############################################################
601
598
602 ## Defines if a custom authorized_keys file should be created and written on
599 ## Defines if a custom authorized_keys file should be created and written on
603 ## any change user ssh keys. Setting this to false also disables posibility
600 ## any change user ssh keys. Setting this to false also disables posibility
604 ## of adding SSH keys by users from web interface. Super admins can still
601 ## of adding SSH keys by users from web interface. Super admins can still
605 ## manage SSH Keys.
602 ## manage SSH Keys.
606 ssh.generate_authorized_keyfile = false
603 ssh.generate_authorized_keyfile = false
607
604
608 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
605 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
609 # ssh.authorized_keys_ssh_opts =
606 # ssh.authorized_keys_ssh_opts =
610
607
611 ## Path to the authrozied_keys file where the generate entries are placed.
608 ## Path to the authrozied_keys file where the generate entries are placed.
612 ## It is possible to have multiple key files specified in `sshd_config` e.g.
609 ## It is possible to have multiple key files specified in `sshd_config` e.g.
613 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
610 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
614 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
611 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
615
612
616 ## Command to execute the SSH wrapper. The binary is available in the
613 ## Command to execute the SSH wrapper. The binary is available in the
617 ## rhodecode installation directory.
614 ## rhodecode installation directory.
618 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
615 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
619 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
616 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
620
617
621 ## Allow shell when executing the ssh-wrapper command
618 ## Allow shell when executing the ssh-wrapper command
622 ssh.wrapper_cmd_allow_shell = false
619 ssh.wrapper_cmd_allow_shell = false
623
620
624 ## Enables logging, and detailed output send back to the client during SSH
621 ## Enables logging, and detailed output send back to the client during SSH
625 ## operations. Usefull for debugging, shouldn't be used in production.
622 ## operations. Usefull for debugging, shouldn't be used in production.
626 ssh.enable_debug_logging = true
623 ssh.enable_debug_logging = true
627
624
628 ## Paths to binary executable, by default they are the names, but we can
625 ## Paths to binary executable, by default they are the names, but we can
629 ## override them if we want to use a custom one
626 ## override them if we want to use a custom one
630 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
627 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
631 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
628 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
632 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
629 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
633
630
634
631
635 ## Dummy marker to add new entries after.
632 ## Dummy marker to add new entries after.
636 ## Add any custom entries below. Please don't remove.
633 ## Add any custom entries below. Please don't remove.
637 custom.conf = 1
634 custom.conf = 1
638
635
639
636
640 ################################
637 ################################
641 ### LOGGING CONFIGURATION ####
638 ### LOGGING CONFIGURATION ####
642 ################################
639 ################################
643 [loggers]
640 [loggers]
644 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
641 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
645
642
646 [handlers]
643 [handlers]
647 keys = console, console_sql
644 keys = console, console_sql
648
645
649 [formatters]
646 [formatters]
650 keys = generic, color_formatter, color_formatter_sql
647 keys = generic, color_formatter, color_formatter_sql
651
648
652 #############
649 #############
653 ## LOGGERS ##
650 ## LOGGERS ##
654 #############
651 #############
655 [logger_root]
652 [logger_root]
656 level = NOTSET
653 level = NOTSET
657 handlers = console
654 handlers = console
658
655
659 [logger_sqlalchemy]
656 [logger_sqlalchemy]
660 level = INFO
657 level = INFO
661 handlers = console_sql
658 handlers = console_sql
662 qualname = sqlalchemy.engine
659 qualname = sqlalchemy.engine
663 propagate = 0
660 propagate = 0
664
661
665 [logger_beaker]
662 [logger_beaker]
666 level = DEBUG
663 level = DEBUG
667 handlers =
664 handlers =
668 qualname = beaker.container
665 qualname = beaker.container
669 propagate = 1
666 propagate = 1
670
667
671 [logger_rhodecode]
668 [logger_rhodecode]
672 level = DEBUG
669 level = DEBUG
673 handlers =
670 handlers =
674 qualname = rhodecode
671 qualname = rhodecode
675 propagate = 1
672 propagate = 1
676
673
677 [logger_ssh_wrapper]
674 [logger_ssh_wrapper]
678 level = DEBUG
675 level = DEBUG
679 handlers =
676 handlers =
680 qualname = ssh_wrapper
677 qualname = ssh_wrapper
681 propagate = 1
678 propagate = 1
682
679
683 [logger_celery]
680 [logger_celery]
684 level = DEBUG
681 level = DEBUG
685 handlers =
682 handlers =
686 qualname = celery
683 qualname = celery
687
684
688
685
689 ##############
686 ##############
690 ## HANDLERS ##
687 ## HANDLERS ##
691 ##############
688 ##############
692
689
693 [handler_console]
690 [handler_console]
694 class = StreamHandler
691 class = StreamHandler
695 args = (sys.stderr, )
692 args = (sys.stderr, )
696 level = DEBUG
693 level = DEBUG
697 formatter = color_formatter
694 formatter = color_formatter
698
695
699 [handler_console_sql]
696 [handler_console_sql]
700 class = StreamHandler
697 class = StreamHandler
701 args = (sys.stderr, )
698 args = (sys.stderr, )
702 level = DEBUG
699 level = DEBUG
703 formatter = color_formatter_sql
700 formatter = color_formatter_sql
704
701
705 ################
702 ################
706 ## FORMATTERS ##
703 ## FORMATTERS ##
707 ################
704 ################
708
705
709 [formatter_generic]
706 [formatter_generic]
710 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
707 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
711 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
708 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
712 datefmt = %Y-%m-%d %H:%M:%S
709 datefmt = %Y-%m-%d %H:%M:%S
713
710
714 [formatter_color_formatter]
711 [formatter_color_formatter]
715 class = rhodecode.lib.logging_formatter.ColorFormatter
712 class = rhodecode.lib.logging_formatter.ColorFormatter
716 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
713 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
717 datefmt = %Y-%m-%d %H:%M:%S
714 datefmt = %Y-%m-%d %H:%M:%S
718
715
719 [formatter_color_formatter_sql]
716 [formatter_color_formatter_sql]
720 class = rhodecode.lib.logging_formatter.ColorFormatterSql
717 class = rhodecode.lib.logging_formatter.ColorFormatterSql
721 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
718 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
722 datefmt = %Y-%m-%d %H:%M:%S
719 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,151 +1,152 b''
1 """
1 """
2 gunicorn config extension and hooks. Sets additional configuration that is
2 gunicorn config extension and hooks. Sets additional configuration that is
3 available post the .ini config.
3 available post the .ini config.
4
4
5 - workers = ${cpu_number}
5 - workers = ${cpu_number}
6 - threads = 1
6 - threads = 1
7 - proc_name = ${gunicorn_proc_name}
7 - proc_name = ${gunicorn_proc_name}
8 - worker_class = sync
8 - worker_class = sync
9 - worker_connections = 10
9 - worker_connections = 10
10 - max_requests = 1000
10 - max_requests = 1000
11 - max_requests_jitter = 30
11 - max_requests_jitter = 30
12 - timeout = 21600
12 - timeout = 21600
13
13
14 """
14 """
15
15
16 import multiprocessing
16 import multiprocessing
17 import sys
17 import sys
18 import time
18 import time
19 import datetime
19 import datetime
20 import threading
20 import threading
21 import traceback
21 import traceback
22 from gunicorn.glogging import Logger
22 from gunicorn.glogging import Logger
23
23
24
24
25 # GLOBAL
25 # GLOBAL
26 errorlog = '-'
26 errorlog = '-'
27 accesslog = '-'
27 accesslog = '-'
28 loglevel = 'debug'
28 loglevel = 'debug'
29
29
30 # SECURITY
30 # SECURITY
31
31
32 # The maximum size of HTTP request line in bytes.
32 # The maximum size of HTTP request line in bytes.
33 limit_request_line = 4094
33 limit_request_line = 4094
34
34
35 # Limit the number of HTTP headers fields in a request.
35 # Limit the number of HTTP headers fields in a request.
36 limit_request_fields = 1024
36 limit_request_fields = 1024
37
37
38 # Limit the allowed size of an HTTP request header field.
38 # Limit the allowed size of an HTTP request header field.
39 # Value is a positive number or 0.
39 # Value is a positive number or 0.
40 # Setting it to 0 will allow unlimited header field sizes.
40 # Setting it to 0 will allow unlimited header field sizes.
41 limit_request_field_size = 0
41 limit_request_field_size = 0
42
42
43
43
44 # Timeout for graceful workers restart.
44 # Timeout for graceful workers restart.
45 # After receiving a restart signal, workers have this much time to finish
45 # After receiving a restart signal, workers have this much time to finish
46 # serving requests. Workers still alive after the timeout (starting from the
46 # serving requests. Workers still alive after the timeout (starting from the
47 # receipt of the restart signal) are force killed.
47 # receipt of the restart signal) are force killed.
48 graceful_timeout = 30
48 graceful_timeout = 30
49
49
50
50
51 # The number of seconds to wait for requests on a Keep-Alive connection.
51 # The number of seconds to wait for requests on a Keep-Alive connection.
52 # Generally set in the 1-5 seconds range.
52 # Generally set in the 1-5 seconds range.
53 keepalive = 2
53 keepalive = 2
54
54
55
55
56 # SERVER MECHANICS
56 # SERVER MECHANICS
57 # None == system temp dir
57 # None == system temp dir
58 # worker_tmp_dir is recommended to be set to some tmpfs
58 worker_tmp_dir = None
59 worker_tmp_dir = None
59 tmp_upload_dir = None
60 tmp_upload_dir = None
60
61
61 # Custom log format
62 # Custom log format
62 access_log_format = (
63 access_log_format = (
63 '%(t)s GNCRN %(p)-8s %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
64 '%(t)s [%(p)-8s] GNCRN %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
64
65
65 # self adjust workers based on CPU count
66 # self adjust workers based on CPU count
66 # workers = multiprocessing.cpu_count() * 2 + 1
67 # workers = multiprocessing.cpu_count() * 2 + 1
67
68
68
69
69 def post_fork(server, worker):
70 def post_fork(server, worker):
70 server.log.info("[<%-10s>] WORKER spawned", worker.pid)
71 server.log.info("[<%-10s>] WORKER spawned", worker.pid)
71
72
72
73
73 def pre_fork(server, worker):
74 def pre_fork(server, worker):
74 pass
75 pass
75
76
76
77
77 def pre_exec(server):
78 def pre_exec(server):
78 server.log.info("Forked child, re-executing.")
79 server.log.info("Forked child, re-executing.")
79
80
80
81
81 def on_starting(server):
82 def on_starting(server):
82 server.log.info("Server is starting.")
83 server.log.info("Server is starting.")
83
84
84
85
85 def when_ready(server):
86 def when_ready(server):
86 server.log.info("Server is ready. Spawning workers")
87 server.log.info("Server is ready. Spawning workers")
87
88
88
89
89 def on_reload(server):
90 def on_reload(server):
90 pass
91 pass
91
92
92
93
93 def worker_int(worker):
94 def worker_int(worker):
94 worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid)
95 worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid)
95
96
96 # get traceback info, on worker crash
97 # get traceback info, on worker crash
97 id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
98 id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
98 code = []
99 code = []
99 for thread_id, stack in sys._current_frames().items():
100 for thread_id, stack in sys._current_frames().items():
100 code.append(
101 code.append(
101 "\n# Thread: %s(%d)" % (id2name.get(thread_id, ""), thread_id))
102 "\n# Thread: %s(%d)" % (id2name.get(thread_id, ""), thread_id))
102 for fname, lineno, name, line in traceback.extract_stack(stack):
103 for fname, lineno, name, line in traceback.extract_stack(stack):
103 code.append('File: "%s", line %d, in %s' % (fname, lineno, name))
104 code.append('File: "%s", line %d, in %s' % (fname, lineno, name))
104 if line:
105 if line:
105 code.append(" %s" % (line.strip()))
106 code.append(" %s" % (line.strip()))
106 worker.log.debug("\n".join(code))
107 worker.log.debug("\n".join(code))
107
108
108
109
109 def worker_abort(worker):
110 def worker_abort(worker):
110 worker.log.info("[<%-10s>] worker received SIGABRT signal", worker.pid)
111 worker.log.info("[<%-10s>] worker received SIGABRT signal", worker.pid)
111
112
112
113
113 def worker_exit(server, worker):
114 def worker_exit(server, worker):
114 worker.log.info("[<%-10s>] worker exit", worker.pid)
115 worker.log.info("[<%-10s>] worker exit", worker.pid)
115
116
116
117
117 def child_exit(server, worker):
118 def child_exit(server, worker):
118 worker.log.info("[<%-10s>] worker child exit", worker.pid)
119 worker.log.info("[<%-10s>] worker child exit", worker.pid)
119
120
120
121
121 def pre_request(worker, req):
122 def pre_request(worker, req):
122 return
123 worker.start_time = time.time()
123 worker.log.debug("[<%-10s>] PRE WORKER: %s %s",
124 worker.log.debug(
124 worker.pid, req.method, req.path)
125 "GNCRN PRE WORKER [cnt:%s]: %s %s", worker.nr, req.method, req.path)
125
126
126
127
127 def post_request(worker, req, environ, resp):
128 def post_request(worker, req, environ, resp):
128 return
129 total_time = time.time() - worker.start_time
129 worker.log.debug("[<%-10s>] POST WORKER: %s %s resp: %s", worker.pid,
130 worker.log.debug(
130 req.method, req.path, resp.status_code)
131 "GNCRN POST WORKER [cnt:%s]: %s %s resp: %s, Load Time: %.3fs",
131
132 worker.nr, req.method, req.path, resp.status_code, total_time)
132
133
133
134
134 class RhodeCodeLogger(Logger):
135 class RhodeCodeLogger(Logger):
135 """
136 """
136 Custom Logger that allows some customization that gunicorn doesn't allow
137 Custom Logger that allows some customization that gunicorn doesn't allow
137 """
138 """
138
139
139 datefmt = r"%Y-%m-%d %H:%M:%S"
140 datefmt = r"%Y-%m-%d %H:%M:%S"
140
141
141 def __init__(self, cfg):
142 def __init__(self, cfg):
142 Logger.__init__(self, cfg)
143 Logger.__init__(self, cfg)
143
144
144 def now(self):
145 def now(self):
145 """ return date in RhodeCode Log format """
146 """ return date in RhodeCode Log format """
146 now = time.time()
147 now = time.time()
147 msecs = int((now - long(now)) * 1000)
148 msecs = int((now - long(now)) * 1000)
148 return time.strftime(self.datefmt, time.localtime(now)) + '.{0:03d}'.format(msecs)
149 return time.strftime(self.datefmt, time.localtime(now)) + '.{0:03d}'.format(msecs)
149
150
150
151
151 logger_class = RhodeCodeLogger
152 logger_class = RhodeCodeLogger
@@ -1,692 +1,689 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 #use = egg:waitress#main
54 #use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 #threads = 5
56 #threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 #max_request_body_size = 107374182400
58 #max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 #asyncore_use_poll = true
61 #asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 use = egg:gunicorn#main
69 use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 workers = 2
74 workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
76 ## generally recommended to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 proc_name = rhodecode
79 proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 worker_class = gevent
82 worker_class = gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 max_requests = 1000
87 max_requests = 1000
88 max_requests_jitter = 30
88 max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 timeout = 21600
91 timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 ## encryption key used to encrypt social plugin tokens,
111 ## encryption key used to encrypt social plugin tokens,
112 ## remote_urls with credentials etc, if not set it defaults to
112 ## remote_urls with credentials etc, if not set it defaults to
113 ## `beaker.session.secret`
113 ## `beaker.session.secret`
114 #rhodecode.encrypted_values.secret =
114 #rhodecode.encrypted_values.secret =
115
115
116 ## decryption strict mode (enabled by default). It controls if decryption raises
116 ## decryption strict mode (enabled by default). It controls if decryption raises
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
118 #rhodecode.encrypted_values.strict = false
118 #rhodecode.encrypted_values.strict = false
119
119
120 ## return gzipped responses from Rhodecode (static files/application)
120 ## return gzipped responses from Rhodecode (static files/application)
121 gzip_responses = false
121 gzip_responses = false
122
122
123 ## autogenerate javascript routes file on startup
123 ## autogenerate javascript routes file on startup
124 generate_js_files = false
124 generate_js_files = false
125
125
126 ## Optional Languages
126 ## Optional Languages
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
128 lang = en
128 lang = en
129
129
130 ## perform a full repository scan on each server start, this should be
130 ## perform a full repository scan on each server start, this should be
131 ## set to false after first startup, to allow faster server restarts.
131 ## set to false after first startup, to allow faster server restarts.
132 startup.import_repos = false
132 startup.import_repos = false
133
133
134 ## Uncomment and set this path to use archive download cache.
134 ## Uncomment and set this path to use archive download cache.
135 ## Once enabled, generated archives will be cached at this location
135 ## Once enabled, generated archives will be cached at this location
136 ## and served from the cache during subsequent requests for the same archive of
136 ## and served from the cache during subsequent requests for the same archive of
137 ## the repository.
137 ## the repository.
138 #archive_cache_dir = /tmp/tarballcache
138 #archive_cache_dir = /tmp/tarballcache
139
139
140 ## URL at which the application is running. This is used for bootstraping
140 ## URL at which the application is running. This is used for bootstraping
141 ## requests in context when no web request is available. Used in ishell, or
141 ## requests in context when no web request is available. Used in ishell, or
142 ## SSH calls. Set this for events to receive proper url for SSH calls.
142 ## SSH calls. Set this for events to receive proper url for SSH calls.
143 app.base_url = http://rhodecode.local
143 app.base_url = http://rhodecode.local
144
144
145 ## change this to unique ID for security
145 ## change this to unique ID for security
146 app_instance_uuid = rc-production
146 app_instance_uuid = rc-production
147
147
148 ## cut off limit for large diffs (size in bytes). If overall diff size on
148 ## cut off limit for large diffs (size in bytes). If overall diff size on
149 ## commit, or pull request exceeds this limit this diff will be displayed
149 ## commit, or pull request exceeds this limit this diff will be displayed
150 ## partially. E.g 512000 == 512Kb
150 ## partially. E.g 512000 == 512Kb
151 cut_off_limit_diff = 512000
151 cut_off_limit_diff = 512000
152
152
153 ## cut off limit for large files inside diffs (size in bytes). Each individual
153 ## cut off limit for large files inside diffs (size in bytes). Each individual
154 ## file inside diff which exceeds this limit will be displayed partially.
154 ## file inside diff which exceeds this limit will be displayed partially.
155 ## E.g 128000 == 128Kb
155 ## E.g 128000 == 128Kb
156 cut_off_limit_file = 128000
156 cut_off_limit_file = 128000
157
157
158 ## use cache version of scm repo everywhere
158 ## use cache version of scm repo everywhere
159 vcs_full_cache = true
159 vcs_full_cache = true
160
160
161 ## force https in RhodeCode, fixes https redirects, assumes it's always https
161 ## force https in RhodeCode, fixes https redirects, assumes it's always https
162 ## Normally this is controlled by proper http flags sent from http server
162 ## Normally this is controlled by proper http flags sent from http server
163 force_https = false
163 force_https = false
164
164
165 ## use Strict-Transport-Security headers
165 ## use Strict-Transport-Security headers
166 use_htsts = false
166 use_htsts = false
167
167
168 ## number of commits stats will parse on each iteration
169 commit_parse_limit = 25
170
171 ## git rev filter option, --all is the default filter, if you need to
168 ## git rev filter option, --all is the default filter, if you need to
172 ## hide all refs in changelog switch this to --branches --tags
169 ## hide all refs in changelog switch this to --branches --tags
173 git_rev_filter = --branches --tags
170 git_rev_filter = --branches --tags
174
171
175 # Set to true if your repos are exposed using the dumb protocol
172 # Set to true if your repos are exposed using the dumb protocol
176 git_update_server_info = false
173 git_update_server_info = false
177
174
178 ## RSS/ATOM feed options
175 ## RSS/ATOM feed options
179 rss_cut_off_limit = 256000
176 rss_cut_off_limit = 256000
180 rss_items_per_page = 10
177 rss_items_per_page = 10
181 rss_include_diff = false
178 rss_include_diff = false
182
179
183 ## gist URL alias, used to create nicer urls for gist. This should be an
180 ## gist URL alias, used to create nicer urls for gist. This should be an
184 ## url that does rewrites to _admin/gists/{gistid}.
181 ## url that does rewrites to _admin/gists/{gistid}.
185 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
182 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
186 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
183 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
187 gist_alias_url =
184 gist_alias_url =
188
185
189 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
186 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
190 ## used for access.
187 ## used for access.
191 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
188 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
192 ## came from the the logged in user who own this authentication token.
189 ## came from the the logged in user who own this authentication token.
193 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
190 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
194 ## authentication token. Such view would be only accessible when used together
191 ## authentication token. Such view would be only accessible when used together
195 ## with this authentication token
192 ## with this authentication token
196 ##
193 ##
197 ## list of all views can be found under `/_admin/permissions/auth_token_access`
194 ## list of all views can be found under `/_admin/permissions/auth_token_access`
198 ## The list should be "," separated and on a single line.
195 ## The list should be "," separated and on a single line.
199 ##
196 ##
200 ## Most common views to enable:
197 ## Most common views to enable:
201 # RepoCommitsView:repo_commit_download
198 # RepoCommitsView:repo_commit_download
202 # RepoCommitsView:repo_commit_patch
199 # RepoCommitsView:repo_commit_patch
203 # RepoCommitsView:repo_commit_raw
200 # RepoCommitsView:repo_commit_raw
204 # RepoCommitsView:repo_commit_raw@TOKEN
201 # RepoCommitsView:repo_commit_raw@TOKEN
205 # RepoFilesView:repo_files_diff
202 # RepoFilesView:repo_files_diff
206 # RepoFilesView:repo_archivefile
203 # RepoFilesView:repo_archivefile
207 # RepoFilesView:repo_file_raw
204 # RepoFilesView:repo_file_raw
208 # GistView:*
205 # GistView:*
209 api_access_controllers_whitelist =
206 api_access_controllers_whitelist =
210
207
211 ## default encoding used to convert from and to unicode
208 ## default encoding used to convert from and to unicode
212 ## can be also a comma separated list of encoding in case of mixed encodings
209 ## can be also a comma separated list of encoding in case of mixed encodings
213 default_encoding = UTF-8
210 default_encoding = UTF-8
214
211
215 ## instance-id prefix
212 ## instance-id prefix
216 ## a prefix key for this instance used for cache invalidation when running
213 ## a prefix key for this instance used for cache invalidation when running
217 ## multiple instances of rhodecode, make sure it's globally unique for
214 ## multiple instances of rhodecode, make sure it's globally unique for
218 ## all running rhodecode instances. Leave empty if you don't use it
215 ## all running rhodecode instances. Leave empty if you don't use it
219 instance_id =
216 instance_id =
220
217
221 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
218 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
222 ## of an authentication plugin also if it is disabled by it's settings.
219 ## of an authentication plugin also if it is disabled by it's settings.
223 ## This could be useful if you are unable to log in to the system due to broken
220 ## This could be useful if you are unable to log in to the system due to broken
224 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
221 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
225 ## module to log in again and fix the settings.
222 ## module to log in again and fix the settings.
226 ##
223 ##
227 ## Available builtin plugin IDs (hash is part of the ID):
224 ## Available builtin plugin IDs (hash is part of the ID):
228 ## egg:rhodecode-enterprise-ce#rhodecode
225 ## egg:rhodecode-enterprise-ce#rhodecode
229 ## egg:rhodecode-enterprise-ce#pam
226 ## egg:rhodecode-enterprise-ce#pam
230 ## egg:rhodecode-enterprise-ce#ldap
227 ## egg:rhodecode-enterprise-ce#ldap
231 ## egg:rhodecode-enterprise-ce#jasig_cas
228 ## egg:rhodecode-enterprise-ce#jasig_cas
232 ## egg:rhodecode-enterprise-ce#headers
229 ## egg:rhodecode-enterprise-ce#headers
233 ## egg:rhodecode-enterprise-ce#crowd
230 ## egg:rhodecode-enterprise-ce#crowd
234 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
231 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
235
232
236 ## alternative return HTTP header for failed authentication. Default HTTP
233 ## alternative return HTTP header for failed authentication. Default HTTP
237 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
234 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
238 ## handling that causing a series of failed authentication calls.
235 ## handling that causing a series of failed authentication calls.
239 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
236 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
240 ## This will be served instead of default 401 on bad authnetication
237 ## This will be served instead of default 401 on bad authnetication
241 auth_ret_code =
238 auth_ret_code =
242
239
243 ## use special detection method when serving auth_ret_code, instead of serving
240 ## use special detection method when serving auth_ret_code, instead of serving
244 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
241 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
245 ## and then serve auth_ret_code to clients
242 ## and then serve auth_ret_code to clients
246 auth_ret_code_detection = false
243 auth_ret_code_detection = false
247
244
248 ## locking return code. When repository is locked return this HTTP code. 2XX
245 ## locking return code. When repository is locked return this HTTP code. 2XX
249 ## codes don't break the transactions while 4XX codes do
246 ## codes don't break the transactions while 4XX codes do
250 lock_ret_code = 423
247 lock_ret_code = 423
251
248
252 ## allows to change the repository location in settings page
249 ## allows to change the repository location in settings page
253 allow_repo_location_change = true
250 allow_repo_location_change = true
254
251
255 ## allows to setup custom hooks in settings page
252 ## allows to setup custom hooks in settings page
256 allow_custom_hooks_settings = true
253 allow_custom_hooks_settings = true
257
254
258 ## generated license token, goto license page in RhodeCode settings to obtain
255 ## generated license token, goto license page in RhodeCode settings to obtain
259 ## new token
256 ## new token
260 license_token =
257 license_token =
261
258
262 ## supervisor connection uri, for managing supervisor and logs.
259 ## supervisor connection uri, for managing supervisor and logs.
263 supervisor.uri =
260 supervisor.uri =
264 ## supervisord group name/id we only want this RC instance to handle
261 ## supervisord group name/id we only want this RC instance to handle
265 supervisor.group_id = prod
262 supervisor.group_id = prod
266
263
267 ## Display extended labs settings
264 ## Display extended labs settings
268 labs_settings_active = true
265 labs_settings_active = true
269
266
270 ####################################
267 ####################################
271 ### CELERY CONFIG ####
268 ### CELERY CONFIG ####
272 ####################################
269 ####################################
273 ## run: /path/to/celery worker \
270 ## run: /path/to/celery worker \
274 ## -E --beat --app rhodecode.lib.celerylib.loader \
271 ## -E --beat --app rhodecode.lib.celerylib.loader \
275 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
272 ## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
276 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
273 ## --loglevel DEBUG --ini /path/to/rhodecode.ini
277
274
278 use_celery = false
275 use_celery = false
279
276
280 ## connection url to the message broker (default rabbitmq)
277 ## connection url to the message broker (default rabbitmq)
281 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
278 celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost
282
279
283 ## maximum tasks to execute before worker restart
280 ## maximum tasks to execute before worker restart
284 celery.max_tasks_per_child = 100
281 celery.max_tasks_per_child = 100
285
282
286 ## tasks will never be sent to the queue, but executed locally instead.
283 ## tasks will never be sent to the queue, but executed locally instead.
287 celery.task_always_eager = false
284 celery.task_always_eager = false
288
285
289 ####################################
286 ####################################
290 ### BEAKER CACHE ####
287 ### BEAKER CACHE ####
291 ####################################
288 ####################################
292 # default cache dir for templates. Putting this into a ramdisk
289 # default cache dir for templates. Putting this into a ramdisk
293 ## can boost performance, eg. %(here)s/data_ramdisk
290 ## can boost performance, eg. %(here)s/data_ramdisk
294 cache_dir = %(here)s/data
291 cache_dir = %(here)s/data
295
292
296 ## locking and default file storage for Beaker. Putting this into a ramdisk
293 ## locking and default file storage for Beaker. Putting this into a ramdisk
297 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
294 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
298 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
295 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
299 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
296 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
300
297
301 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
298 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
302
299
303 beaker.cache.super_short_term.type = memory
300 beaker.cache.super_short_term.type = memory
304 beaker.cache.super_short_term.expire = 10
301 beaker.cache.super_short_term.expire = 10
305 beaker.cache.super_short_term.key_length = 256
302 beaker.cache.super_short_term.key_length = 256
306
303
307 beaker.cache.short_term.type = memory
304 beaker.cache.short_term.type = memory
308 beaker.cache.short_term.expire = 60
305 beaker.cache.short_term.expire = 60
309 beaker.cache.short_term.key_length = 256
306 beaker.cache.short_term.key_length = 256
310
307
311 beaker.cache.long_term.type = memory
308 beaker.cache.long_term.type = memory
312 beaker.cache.long_term.expire = 36000
309 beaker.cache.long_term.expire = 36000
313 beaker.cache.long_term.key_length = 256
310 beaker.cache.long_term.key_length = 256
314
311
315 beaker.cache.sql_cache_short.type = memory
312 beaker.cache.sql_cache_short.type = memory
316 beaker.cache.sql_cache_short.expire = 10
313 beaker.cache.sql_cache_short.expire = 10
317 beaker.cache.sql_cache_short.key_length = 256
314 beaker.cache.sql_cache_short.key_length = 256
318
315
319 ## default is memory cache, configure only if required
316 ## default is memory cache, configure only if required
320 ## using multi-node or multi-worker setup
317 ## using multi-node or multi-worker setup
321 #beaker.cache.auth_plugins.type = ext:database
318 #beaker.cache.auth_plugins.type = ext:database
322 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
319 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
323 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
320 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
324 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
321 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
325 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
322 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
326 #beaker.cache.auth_plugins.sa.pool_size = 10
323 #beaker.cache.auth_plugins.sa.pool_size = 10
327 #beaker.cache.auth_plugins.sa.max_overflow = 0
324 #beaker.cache.auth_plugins.sa.max_overflow = 0
328
325
329 beaker.cache.repo_cache_long.type = memorylru_base
326 beaker.cache.repo_cache_long.type = memorylru_base
330 beaker.cache.repo_cache_long.max_items = 4096
327 beaker.cache.repo_cache_long.max_items = 4096
331 beaker.cache.repo_cache_long.expire = 2592000
328 beaker.cache.repo_cache_long.expire = 2592000
332
329
333 ## default is memorylru_base cache, configure only if required
330 ## default is memorylru_base cache, configure only if required
334 ## using multi-node or multi-worker setup
331 ## using multi-node or multi-worker setup
335 #beaker.cache.repo_cache_long.type = ext:memcached
332 #beaker.cache.repo_cache_long.type = ext:memcached
336 #beaker.cache.repo_cache_long.url = localhost:11211
333 #beaker.cache.repo_cache_long.url = localhost:11211
337 #beaker.cache.repo_cache_long.expire = 1209600
334 #beaker.cache.repo_cache_long.expire = 1209600
338 #beaker.cache.repo_cache_long.key_length = 256
335 #beaker.cache.repo_cache_long.key_length = 256
339
336
340 ####################################
337 ####################################
341 ### BEAKER SESSION ####
338 ### BEAKER SESSION ####
342 ####################################
339 ####################################
343
340
344 ## .session.type is type of storage options for the session, current allowed
341 ## .session.type is type of storage options for the session, current allowed
345 ## types are file, ext:memcached, ext:database, and memory (default).
342 ## types are file, ext:memcached, ext:database, and memory (default).
346 beaker.session.type = file
343 beaker.session.type = file
347 beaker.session.data_dir = %(here)s/data/sessions/data
344 beaker.session.data_dir = %(here)s/data/sessions/data
348
345
349 ## db based session, fast, and allows easy management over logged in users
346 ## db based session, fast, and allows easy management over logged in users
350 #beaker.session.type = ext:database
347 #beaker.session.type = ext:database
351 #beaker.session.table_name = db_session
348 #beaker.session.table_name = db_session
352 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
349 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
353 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
350 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
354 #beaker.session.sa.pool_recycle = 3600
351 #beaker.session.sa.pool_recycle = 3600
355 #beaker.session.sa.echo = false
352 #beaker.session.sa.echo = false
356
353
357 beaker.session.key = rhodecode
354 beaker.session.key = rhodecode
358 beaker.session.secret = production-rc-uytcxaz
355 beaker.session.secret = production-rc-uytcxaz
359 beaker.session.lock_dir = %(here)s/data/sessions/lock
356 beaker.session.lock_dir = %(here)s/data/sessions/lock
360
357
361 ## Secure encrypted cookie. Requires AES and AES python libraries
358 ## Secure encrypted cookie. Requires AES and AES python libraries
362 ## you must disable beaker.session.secret to use this
359 ## you must disable beaker.session.secret to use this
363 #beaker.session.encrypt_key = key_for_encryption
360 #beaker.session.encrypt_key = key_for_encryption
364 #beaker.session.validate_key = validation_key
361 #beaker.session.validate_key = validation_key
365
362
366 ## sets session as invalid(also logging out user) if it haven not been
363 ## sets session as invalid(also logging out user) if it haven not been
367 ## accessed for given amount of time in seconds
364 ## accessed for given amount of time in seconds
368 beaker.session.timeout = 2592000
365 beaker.session.timeout = 2592000
369 beaker.session.httponly = true
366 beaker.session.httponly = true
370 ## Path to use for the cookie. Set to prefix if you use prefix middleware
367 ## Path to use for the cookie. Set to prefix if you use prefix middleware
371 #beaker.session.cookie_path = /custom_prefix
368 #beaker.session.cookie_path = /custom_prefix
372
369
373 ## uncomment for https secure cookie
370 ## uncomment for https secure cookie
374 beaker.session.secure = false
371 beaker.session.secure = false
375
372
376 ## auto save the session to not to use .save()
373 ## auto save the session to not to use .save()
377 beaker.session.auto = false
374 beaker.session.auto = false
378
375
379 ## default cookie expiration time in seconds, set to `true` to set expire
376 ## default cookie expiration time in seconds, set to `true` to set expire
380 ## at browser close
377 ## at browser close
381 #beaker.session.cookie_expires = 3600
378 #beaker.session.cookie_expires = 3600
382
379
383 ###################################
380 ###################################
384 ## SEARCH INDEXING CONFIGURATION ##
381 ## SEARCH INDEXING CONFIGURATION ##
385 ###################################
382 ###################################
386 ## Full text search indexer is available in rhodecode-tools under
383 ## Full text search indexer is available in rhodecode-tools under
387 ## `rhodecode-tools index` command
384 ## `rhodecode-tools index` command
388
385
389 ## WHOOSH Backend, doesn't require additional services to run
386 ## WHOOSH Backend, doesn't require additional services to run
390 ## it works good with few dozen repos
387 ## it works good with few dozen repos
391 search.module = rhodecode.lib.index.whoosh
388 search.module = rhodecode.lib.index.whoosh
392 search.location = %(here)s/data/index
389 search.location = %(here)s/data/index
393
390
394 ########################################
391 ########################################
395 ### CHANNELSTREAM CONFIG ####
392 ### CHANNELSTREAM CONFIG ####
396 ########################################
393 ########################################
397 ## channelstream enables persistent connections and live notification
394 ## channelstream enables persistent connections and live notification
398 ## in the system. It's also used by the chat system
395 ## in the system. It's also used by the chat system
399 channelstream.enabled = false
396 channelstream.enabled = false
400
397
401 ## server address for channelstream server on the backend
398 ## server address for channelstream server on the backend
402 channelstream.server = 127.0.0.1:9800
399 channelstream.server = 127.0.0.1:9800
403
400
404 ## location of the channelstream server from outside world
401 ## location of the channelstream server from outside world
405 ## use ws:// for http or wss:// for https. This address needs to be handled
402 ## use ws:// for http or wss:// for https. This address needs to be handled
406 ## by external HTTP server such as Nginx or Apache
403 ## by external HTTP server such as Nginx or Apache
407 ## see nginx/apache configuration examples in our docs
404 ## see nginx/apache configuration examples in our docs
408 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
405 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
409 channelstream.secret = secret
406 channelstream.secret = secret
410 channelstream.history.location = %(here)s/channelstream_history
407 channelstream.history.location = %(here)s/channelstream_history
411
408
412 ## Internal application path that Javascript uses to connect into.
409 ## Internal application path that Javascript uses to connect into.
413 ## If you use proxy-prefix the prefix should be added before /_channelstream
410 ## If you use proxy-prefix the prefix should be added before /_channelstream
414 channelstream.proxy_path = /_channelstream
411 channelstream.proxy_path = /_channelstream
415
412
416
413
417 ###################################
414 ###################################
418 ## APPENLIGHT CONFIG ##
415 ## APPENLIGHT CONFIG ##
419 ###################################
416 ###################################
420
417
421 ## Appenlight is tailored to work with RhodeCode, see
418 ## Appenlight is tailored to work with RhodeCode, see
422 ## http://appenlight.com for details how to obtain an account
419 ## http://appenlight.com for details how to obtain an account
423
420
424 ## appenlight integration enabled
421 ## appenlight integration enabled
425 appenlight = false
422 appenlight = false
426
423
427 appenlight.server_url = https://api.appenlight.com
424 appenlight.server_url = https://api.appenlight.com
428 appenlight.api_key = YOUR_API_KEY
425 appenlight.api_key = YOUR_API_KEY
429 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
426 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
430
427
431 # used for JS client
428 # used for JS client
432 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
429 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
433
430
434 ## TWEAK AMOUNT OF INFO SENT HERE
431 ## TWEAK AMOUNT OF INFO SENT HERE
435
432
436 ## enables 404 error logging (default False)
433 ## enables 404 error logging (default False)
437 appenlight.report_404 = false
434 appenlight.report_404 = false
438
435
439 ## time in seconds after request is considered being slow (default 1)
436 ## time in seconds after request is considered being slow (default 1)
440 appenlight.slow_request_time = 1
437 appenlight.slow_request_time = 1
441
438
442 ## record slow requests in application
439 ## record slow requests in application
443 ## (needs to be enabled for slow datastore recording and time tracking)
440 ## (needs to be enabled for slow datastore recording and time tracking)
444 appenlight.slow_requests = true
441 appenlight.slow_requests = true
445
442
446 ## enable hooking to application loggers
443 ## enable hooking to application loggers
447 appenlight.logging = true
444 appenlight.logging = true
448
445
449 ## minimum log level for log capture
446 ## minimum log level for log capture
450 appenlight.logging.level = WARNING
447 appenlight.logging.level = WARNING
451
448
452 ## send logs only from erroneous/slow requests
449 ## send logs only from erroneous/slow requests
453 ## (saves API quota for intensive logging)
450 ## (saves API quota for intensive logging)
454 appenlight.logging_on_error = false
451 appenlight.logging_on_error = false
455
452
456 ## list of additonal keywords that should be grabbed from environ object
453 ## list of additonal keywords that should be grabbed from environ object
457 ## can be string with comma separated list of words in lowercase
454 ## can be string with comma separated list of words in lowercase
458 ## (by default client will always send following info:
455 ## (by default client will always send following info:
459 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
456 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
460 ## start with HTTP* this list be extended with additional keywords here
457 ## start with HTTP* this list be extended with additional keywords here
461 appenlight.environ_keys_whitelist =
458 appenlight.environ_keys_whitelist =
462
459
463 ## list of keywords that should be blanked from request object
460 ## list of keywords that should be blanked from request object
464 ## can be string with comma separated list of words in lowercase
461 ## can be string with comma separated list of words in lowercase
465 ## (by default client will always blank keys that contain following words
462 ## (by default client will always blank keys that contain following words
466 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
463 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
467 ## this list be extended with additional keywords set here
464 ## this list be extended with additional keywords set here
468 appenlight.request_keys_blacklist =
465 appenlight.request_keys_blacklist =
469
466
470 ## list of namespaces that should be ignores when gathering log entries
467 ## list of namespaces that should be ignores when gathering log entries
471 ## can be string with comma separated list of namespaces
468 ## can be string with comma separated list of namespaces
472 ## (by default the client ignores own entries: appenlight_client.client)
469 ## (by default the client ignores own entries: appenlight_client.client)
473 appenlight.log_namespace_blacklist =
470 appenlight.log_namespace_blacklist =
474
471
475
472
476 ################################################################################
473 ################################################################################
477 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
474 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
478 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
475 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
479 ## execute malicious code after an exception is raised. ##
476 ## execute malicious code after an exception is raised. ##
480 ################################################################################
477 ################################################################################
481 set debug = false
478 set debug = false
482
479
483
480
484 ###########################################
481 ###########################################
485 ### MAIN RHODECODE DATABASE CONFIG ###
482 ### MAIN RHODECODE DATABASE CONFIG ###
486 ###########################################
483 ###########################################
487 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
484 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
488 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
485 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
489 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
486 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
490 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
487 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
491
488
492 # see sqlalchemy docs for other advanced settings
489 # see sqlalchemy docs for other advanced settings
493
490
494 ## print the sql statements to output
491 ## print the sql statements to output
495 sqlalchemy.db1.echo = false
492 sqlalchemy.db1.echo = false
496 ## recycle the connections after this amount of seconds
493 ## recycle the connections after this amount of seconds
497 sqlalchemy.db1.pool_recycle = 3600
494 sqlalchemy.db1.pool_recycle = 3600
498 sqlalchemy.db1.convert_unicode = true
495 sqlalchemy.db1.convert_unicode = true
499
496
500 ## the number of connections to keep open inside the connection pool.
497 ## the number of connections to keep open inside the connection pool.
501 ## 0 indicates no limit
498 ## 0 indicates no limit
502 #sqlalchemy.db1.pool_size = 5
499 #sqlalchemy.db1.pool_size = 5
503
500
504 ## the number of connections to allow in connection pool "overflow", that is
501 ## the number of connections to allow in connection pool "overflow", that is
505 ## connections that can be opened above and beyond the pool_size setting,
502 ## connections that can be opened above and beyond the pool_size setting,
506 ## which defaults to five.
503 ## which defaults to five.
507 #sqlalchemy.db1.max_overflow = 10
504 #sqlalchemy.db1.max_overflow = 10
508
505
509
506
510 ##################
507 ##################
511 ### VCS CONFIG ###
508 ### VCS CONFIG ###
512 ##################
509 ##################
513 vcs.server.enable = true
510 vcs.server.enable = true
514 vcs.server = localhost:9900
511 vcs.server = localhost:9900
515
512
516 ## Web server connectivity protocol, responsible for web based VCS operatations
513 ## Web server connectivity protocol, responsible for web based VCS operatations
517 ## Available protocols are:
514 ## Available protocols are:
518 ## `http` - use http-rpc backend (default)
515 ## `http` - use http-rpc backend (default)
519 vcs.server.protocol = http
516 vcs.server.protocol = http
520
517
521 ## Push/Pull operations protocol, available options are:
518 ## Push/Pull operations protocol, available options are:
522 ## `http` - use http-rpc backend (default)
519 ## `http` - use http-rpc backend (default)
523 ##
520 ##
524 vcs.scm_app_implementation = http
521 vcs.scm_app_implementation = http
525
522
526 ## Push/Pull operations hooks protocol, available options are:
523 ## Push/Pull operations hooks protocol, available options are:
527 ## `http` - use http-rpc backend (default)
524 ## `http` - use http-rpc backend (default)
528 vcs.hooks.protocol = http
525 vcs.hooks.protocol = http
529
526
530 vcs.server.log_level = info
527 vcs.server.log_level = info
531 ## Start VCSServer with this instance as a subprocess, usefull for development
528 ## Start VCSServer with this instance as a subprocess, usefull for development
532 vcs.start_server = false
529 vcs.start_server = false
533
530
534 ## List of enabled VCS backends, available options are:
531 ## List of enabled VCS backends, available options are:
535 ## `hg` - mercurial
532 ## `hg` - mercurial
536 ## `git` - git
533 ## `git` - git
537 ## `svn` - subversion
534 ## `svn` - subversion
538 vcs.backends = hg, git, svn
535 vcs.backends = hg, git, svn
539
536
540 vcs.connection_timeout = 3600
537 vcs.connection_timeout = 3600
541 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
538 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
542 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
539 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
543 #vcs.svn.compatible_version = pre-1.8-compatible
540 #vcs.svn.compatible_version = pre-1.8-compatible
544
541
545
542
546 ############################################################
543 ############################################################
547 ### Subversion proxy support (mod_dav_svn) ###
544 ### Subversion proxy support (mod_dav_svn) ###
548 ### Maps RhodeCode repo groups into SVN paths for Apache ###
545 ### Maps RhodeCode repo groups into SVN paths for Apache ###
549 ############################################################
546 ############################################################
550 ## Enable or disable the config file generation.
547 ## Enable or disable the config file generation.
551 svn.proxy.generate_config = false
548 svn.proxy.generate_config = false
552 ## Generate config file with `SVNListParentPath` set to `On`.
549 ## Generate config file with `SVNListParentPath` set to `On`.
553 svn.proxy.list_parent_path = true
550 svn.proxy.list_parent_path = true
554 ## Set location and file name of generated config file.
551 ## Set location and file name of generated config file.
555 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
552 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
556 ## alternative mod_dav config template. This needs to be a mako template
553 ## alternative mod_dav config template. This needs to be a mako template
557 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
554 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
558 ## Used as a prefix to the `Location` block in the generated config file.
555 ## Used as a prefix to the `Location` block in the generated config file.
559 ## In most cases it should be set to `/`.
556 ## In most cases it should be set to `/`.
560 svn.proxy.location_root = /
557 svn.proxy.location_root = /
561 ## Command to reload the mod dav svn configuration on change.
558 ## Command to reload the mod dav svn configuration on change.
562 ## Example: `/etc/init.d/apache2 reload`
559 ## Example: `/etc/init.d/apache2 reload`
563 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
560 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
564 ## If the timeout expires before the reload command finishes, the command will
561 ## If the timeout expires before the reload command finishes, the command will
565 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
562 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
566 #svn.proxy.reload_timeout = 10
563 #svn.proxy.reload_timeout = 10
567
564
568 ############################################################
565 ############################################################
569 ### SSH Support Settings ###
566 ### SSH Support Settings ###
570 ############################################################
567 ############################################################
571
568
572 ## Defines if a custom authorized_keys file should be created and written on
569 ## Defines if a custom authorized_keys file should be created and written on
573 ## any change user ssh keys. Setting this to false also disables posibility
570 ## any change user ssh keys. Setting this to false also disables posibility
574 ## of adding SSH keys by users from web interface. Super admins can still
571 ## of adding SSH keys by users from web interface. Super admins can still
575 ## manage SSH Keys.
572 ## manage SSH Keys.
576 ssh.generate_authorized_keyfile = false
573 ssh.generate_authorized_keyfile = false
577
574
578 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
575 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
579 # ssh.authorized_keys_ssh_opts =
576 # ssh.authorized_keys_ssh_opts =
580
577
581 ## Path to the authrozied_keys file where the generate entries are placed.
578 ## Path to the authrozied_keys file where the generate entries are placed.
582 ## It is possible to have multiple key files specified in `sshd_config` e.g.
579 ## It is possible to have multiple key files specified in `sshd_config` e.g.
583 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
580 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
584 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
581 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
585
582
586 ## Command to execute the SSH wrapper. The binary is available in the
583 ## Command to execute the SSH wrapper. The binary is available in the
587 ## rhodecode installation directory.
584 ## rhodecode installation directory.
588 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
585 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
589 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
586 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
590
587
591 ## Allow shell when executing the ssh-wrapper command
588 ## Allow shell when executing the ssh-wrapper command
592 ssh.wrapper_cmd_allow_shell = false
589 ssh.wrapper_cmd_allow_shell = false
593
590
594 ## Enables logging, and detailed output send back to the client during SSH
591 ## Enables logging, and detailed output send back to the client during SSH
595 ## operations. Usefull for debugging, shouldn't be used in production.
592 ## operations. Usefull for debugging, shouldn't be used in production.
596 ssh.enable_debug_logging = false
593 ssh.enable_debug_logging = false
597
594
598 ## Paths to binary executable, by default they are the names, but we can
595 ## Paths to binary executable, by default they are the names, but we can
599 ## override them if we want to use a custom one
596 ## override them if we want to use a custom one
600 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
597 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
601 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
598 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
602 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
599 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
603
600
604
601
605 ## Dummy marker to add new entries after.
602 ## Dummy marker to add new entries after.
606 ## Add any custom entries below. Please don't remove.
603 ## Add any custom entries below. Please don't remove.
607 custom.conf = 1
604 custom.conf = 1
608
605
609
606
610 ################################
607 ################################
611 ### LOGGING CONFIGURATION ####
608 ### LOGGING CONFIGURATION ####
612 ################################
609 ################################
613 [loggers]
610 [loggers]
614 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
611 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
615
612
616 [handlers]
613 [handlers]
617 keys = console, console_sql
614 keys = console, console_sql
618
615
619 [formatters]
616 [formatters]
620 keys = generic, color_formatter, color_formatter_sql
617 keys = generic, color_formatter, color_formatter_sql
621
618
622 #############
619 #############
623 ## LOGGERS ##
620 ## LOGGERS ##
624 #############
621 #############
625 [logger_root]
622 [logger_root]
626 level = NOTSET
623 level = NOTSET
627 handlers = console
624 handlers = console
628
625
629 [logger_sqlalchemy]
626 [logger_sqlalchemy]
630 level = INFO
627 level = INFO
631 handlers = console_sql
628 handlers = console_sql
632 qualname = sqlalchemy.engine
629 qualname = sqlalchemy.engine
633 propagate = 0
630 propagate = 0
634
631
635 [logger_beaker]
632 [logger_beaker]
636 level = DEBUG
633 level = DEBUG
637 handlers =
634 handlers =
638 qualname = beaker.container
635 qualname = beaker.container
639 propagate = 1
636 propagate = 1
640
637
641 [logger_rhodecode]
638 [logger_rhodecode]
642 level = DEBUG
639 level = DEBUG
643 handlers =
640 handlers =
644 qualname = rhodecode
641 qualname = rhodecode
645 propagate = 1
642 propagate = 1
646
643
647 [logger_ssh_wrapper]
644 [logger_ssh_wrapper]
648 level = DEBUG
645 level = DEBUG
649 handlers =
646 handlers =
650 qualname = ssh_wrapper
647 qualname = ssh_wrapper
651 propagate = 1
648 propagate = 1
652
649
653 [logger_celery]
650 [logger_celery]
654 level = DEBUG
651 level = DEBUG
655 handlers =
652 handlers =
656 qualname = celery
653 qualname = celery
657
654
658
655
659 ##############
656 ##############
660 ## HANDLERS ##
657 ## HANDLERS ##
661 ##############
658 ##############
662
659
663 [handler_console]
660 [handler_console]
664 class = StreamHandler
661 class = StreamHandler
665 args = (sys.stderr, )
662 args = (sys.stderr, )
666 level = INFO
663 level = INFO
667 formatter = generic
664 formatter = generic
668
665
669 [handler_console_sql]
666 [handler_console_sql]
670 class = StreamHandler
667 class = StreamHandler
671 args = (sys.stderr, )
668 args = (sys.stderr, )
672 level = WARN
669 level = WARN
673 formatter = generic
670 formatter = generic
674
671
675 ################
672 ################
676 ## FORMATTERS ##
673 ## FORMATTERS ##
677 ################
674 ################
678
675
679 [formatter_generic]
676 [formatter_generic]
680 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
677 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
681 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
678 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
682 datefmt = %Y-%m-%d %H:%M:%S
679 datefmt = %Y-%m-%d %H:%M:%S
683
680
684 [formatter_color_formatter]
681 [formatter_color_formatter]
685 class = rhodecode.lib.logging_formatter.ColorFormatter
682 class = rhodecode.lib.logging_formatter.ColorFormatter
686 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
683 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
687 datefmt = %Y-%m-%d %H:%M:%S
684 datefmt = %Y-%m-%d %H:%M:%S
688
685
689 [formatter_color_formatter_sql]
686 [formatter_color_formatter_sql]
690 class = rhodecode.lib.logging_formatter.ColorFormatterSql
687 class = rhodecode.lib.logging_formatter.ColorFormatterSql
691 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
688 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
692 datefmt = %Y-%m-%d %H:%M:%S
689 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,101 +1,101 b''
1 .. _sec-your-server:
1 .. _sec-sophos-umc:
2
2
3 Securing Your Server via Sophos UTM 9
3 Securing Your Server via Sophos UTM 9
4 -------------------------------------
4 -------------------------------------
5
5
6
6
7
7
8 Below is an example configuration for Sophos UTM 9 Webserver Protection::
8 Below is an example configuration for Sophos UTM 9 Webserver Protection::
9
9
10 Sophos UTM 9 Webserver Protection
10 Sophos UTM 9 Webserver Protection
11 Web Application Firewall based on apache2 modesecurity2
11 Web Application Firewall based on apache2 modesecurity2
12 --------------------------------------------------
12 --------------------------------------------------
13 1. Firewall Profiles -> Firewall Profile
13 1. Firewall Profiles -> Firewall Profile
14 --------------------------------------------------
14 --------------------------------------------------
15 Name: RhodeCode (can be anything)
15 Name: RhodeCode (can be anything)
16 Mode: Reject
16 Mode: Reject
17 Hardening & Signing:
17 Hardening & Signing:
18 [ ] Static URL hardeninig
18 [ ] Static URL hardeninig
19 [ ] Form hardening
19 [ ] Form hardening
20 [x] Cookie Signing
20 [x] Cookie Signing
21 Filtering:
21 Filtering:
22 [x] Block clients with bad reputation
22 [x] Block clients with bad reputation
23 [x] Common Threats Filter
23 [x] Common Threats Filter
24 [ ] Rigid Filtering
24 [ ] Rigid Filtering
25 Skip Filter Rules:
25 Skip Filter Rules:
26 960015
26 960015
27 950120
27 950120
28 981173
28 981173
29 970901
29 970901
30 960010
30 960010
31 960032
31 960032
32 960035
32 960035
33 958291
33 958291
34 970903
34 970903
35 970003
35 970003
36 Common Threat Filter Categories:
36 Common Threat Filter Categories:
37 [x] Protocol violations
37 [x] Protocol violations
38 [x] Protocol anomalies
38 [x] Protocol anomalies
39 [x] Request limit
39 [x] Request limit
40 [x] HTTP policy
40 [x] HTTP policy
41 [x] Bad robots
41 [x] Bad robots
42 [x] Generic attacks
42 [x] Generic attacks
43 [x] SQL injection attacks
43 [x] SQL injection attacks
44 [x] XSS attacks
44 [x] XSS attacks
45 [x] Tight security
45 [x] Tight security
46 [x] Trojans
46 [x] Trojans
47 [x] Outbound
47 [x] Outbound
48 Scanning:
48 Scanning:
49 [ ] Enable antivirus scanning
49 [ ] Enable antivirus scanning
50 [ ] Block uploads by MIME type
50 [ ] Block uploads by MIME type
51 --------------------------------------------------
51 --------------------------------------------------
52 2. Web Application Firewall -> Real Webservers
52 2. Web Application Firewall -> Real Webservers
53 --------------------------------------------------
53 --------------------------------------------------
54 Name: RhodeCode (can be anything)
54 Name: RhodeCode (can be anything)
55 Host: Your RhodeCode-Server (UTM object)
55 Host: Your RhodeCode-Server (UTM object)
56 Type: Encrypted (HTTPS)
56 Type: Encrypted (HTTPS)
57 Port: 443
57 Port: 443
58 --------------------------------------------------
58 --------------------------------------------------
59 3. Web Application Firewall -> Virual Webservers
59 3. Web Application Firewall -> Virual Webservers
60 --------------------------------------------------
60 --------------------------------------------------
61 Name: RhodeCode (can be anything)
61 Name: RhodeCode (can be anything)
62 Interface: WAN (your WAN interface)
62 Interface: WAN (your WAN interface)
63 Type: Encrypted (HTTPS) & redirect
63 Type: Encrypted (HTTPS) & redirect
64 Certificate: Wildcard or matching domain certificate
64 Certificate: Wildcard or matching domain certificate
65 Domains (in case of Wildcard certificate):
65 Domains (in case of Wildcard certificate):
66 rhodecode.yourcompany.com (match your DNS configuration)
66 rhodecode.yourcompany.com (match your DNS configuration)
67 gist.yourcompany.com (match your DNS & RhodeCode configuration)
67 gist.yourcompany.com (match your DNS & RhodeCode configuration)
68 Real Webservers for path '/':
68 Real Webservers for path '/':
69 [x] RhodeCode (created in step 2)
69 [x] RhodeCode (created in step 2)
70 Firewall: RhodeCode (created in step 1)
70 Firewall: RhodeCode (created in step 1)
71 --------------------------------------------------
71 --------------------------------------------------
72 4. Firewall Profiles -> Exceptions
72 4. Firewall Profiles -> Exceptions
73 --------------------------------------------------
73 --------------------------------------------------
74 Name: RhodeCode exceptions (can be anything)
74 Name: RhodeCode exceptions (can be anything)
75 Skip these checks:
75 Skip these checks:
76 [ ] Cookie signing
76 [ ] Cookie signing
77 [ ] Static URL Hardening
77 [ ] Static URL Hardening
78 [ ] Form hardening
78 [ ] Form hardening
79 [x] Antivirus scanning
79 [x] Antivirus scanning
80 [x] True file type control
80 [x] True file type control
81 [ ] Block clients with bad reputation
81 [ ] Block clients with bad reputation
82 Skip these categories:
82 Skip these categories:
83 [ ] Protocol violations
83 [ ] Protocol violations
84 [x] Protocol anomalies
84 [x] Protocol anomalies
85 [x] Request limits
85 [x] Request limits
86 [ ] HTTP policy
86 [ ] HTTP policy
87 [ ] Bad robots
87 [ ] Bad robots
88 [ ] Generic attacks
88 [ ] Generic attacks
89 [ ] SQL injection attacks
89 [ ] SQL injection attacks
90 [ ] XSS attacks
90 [ ] XSS attacks
91 [ ] Tight security
91 [ ] Tight security
92 [ ] Trojans
92 [ ] Trojans
93 [x] Outbound
93 [x] Outbound
94 Virtual Webservers:
94 Virtual Webservers:
95 [x] RhodeCode (created in step 3)
95 [x] RhodeCode (created in step 3)
96 For All Requests:
96 For All Requests:
97 Web requests matching this pattern:
97 Web requests matching this pattern:
98 /_channelstream/ws
98 /_channelstream/ws
99 /Repository1/*
99 /Repository1/*
100 /Repository2/*
100 /Repository2/*
101 /Repository3/* No newline at end of file
101 /Repository3/*
@@ -1,31 +1,32 b''
1 .. _rhodecode-admin-ref:
1 .. _rhodecode-admin-ref:
2
2
3 System Administration
3 System Administration
4 =====================
4 =====================
5
5
6 The following are the most common system administration tasks.
6 The following are the most common system administration tasks.
7
7
8 .. only:: latex
8 .. only:: latex
9
9
10 * :ref:`vcs-server`
10 * :ref:`vcs-server`
11 * :ref:`apache-ws-ref`
11 * :ref:`apache-ws-ref`
12 * :ref:`nginx-ws-ref`
12 * :ref:`nginx-ws-ref`
13 * :ref:`rhodecode-tuning-ref`
13 * :ref:`rhodecode-tuning-ref`
14 * :ref:`indexing-ref`
14 * :ref:`indexing-ref`
15 * :ref:`rhodecode-reset-ref`
15 * :ref:`rhodecode-reset-ref`
16
16
17 .. toctree::
17 .. toctree::
18
18
19 config-files-overview
19 config-files-overview
20 vcs-server
20 vcs-server
21 svn-http
21 svn-http
22 svn-path-permissions
22 gunicorn-ssl-support
23 gunicorn-ssl-support
23 apache-config
24 apache-config
24 nginx-config
25 nginx-config
25 backup-restore
26 backup-restore
26 tuning-rhodecode
27 tuning-rhodecode
27 indexing
28 indexing
28 reset-information
29 reset-information
29 enable-debug
30 enable-debug
30 admin-tricks
31 admin-tricks
31 cleanup-cmds
32 cleanup-cmds
@@ -1,207 +1,208 b''
1 .. _api:
1 .. _api:
2
2
3 API Documentation
3 API Documentation
4 =================
4 =================
5
5
6 The |RCE| API uses a single scheme for calling all API methods. The API is
6 The |RCE| API uses a single scheme for calling all API methods. The API is
7 implemented with JSON protocol in both directions. To send API requests to
7 implemented with JSON protocol in both directions. To send API requests to
8 your instance of |RCE|, use the following URL format
8 your instance of |RCE|, use the following URL format
9 ``<your_server>/_admin``
9 ``<your_server>/_admin``
10
10
11 .. note::
11 .. note::
12
12
13 To use the API, you should configure the :file:`~/.rhoderc` file with
13 To use the API, you should configure the :file:`~/.rhoderc` file with
14 access details per instance. For more information, see
14 access details per instance. For more information, see
15 :ref:`config-rhoderc`.
15 :ref:`config-rhoderc`.
16
16
17
17
18 API ACCESS FOR WEB VIEWS
18 API ACCESS FOR WEB VIEWS
19 ------------------------
19 ------------------------
20
20
21 API access can also be turned on for each web view in |RCE| that is
21 API access can also be turned on for each web view in |RCE| that is
22 decorated with a `@LoginRequired` decorator. To enable API access, change
22 decorated with a `@LoginRequired` decorator. To enable API access, change
23 the standard login decorator to `@LoginRequired(api_access=True)`.
23 the standard login decorator to `@LoginRequired(api_access=True)`.
24
24
25 From |RCM| version 1.7.0 you can configure a white list
25 From |RCM| version 1.7.0 you can configure a white list
26 of views that have API access enabled by default. To enable these,
26 of views that have API access enabled by default. To enable these,
27 edit the |RCM| configuration ``.ini`` file. The default location is:
27 edit the |RCM| configuration ``.ini`` file. The default location is:
28
28
29 * |RCM| Pre-2.2.7 :file:`root/rhodecode/data/production.ini`
29 * |RCM| Pre-2.2.7 :file:`root/rhodecode/data/production.ini`
30 * |RCM| 3.0 :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini`
30 * |RCM| 3.0 :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini`
31
31
32 To configure the white list, edit this section of the file. In this
32 To configure the white list, edit this section of the file. In this
33 configuration example, API access is granted to the patch/diff raw file and
33 configuration example, API access is granted to the patch/diff raw file and
34 archive.
34 archive.
35
35
36 .. code-block:: ini
36 .. code-block:: ini
37
37
38 ## List of controllers (using glob syntax) that AUTH TOKENS could be used for access.
38 ## List of controllers (using glob syntax) that AUTH TOKENS could be used for access.
39 ## Adding ?auth_token = <token> to the url authenticates this request as if it
39 ## Adding ?auth_token = <token> to the url authenticates this request as if it
40 ## came from the the logged in user who own this authentication token.
40 ## came from the the logged in user who own this authentication token.
41 ##
41 ##
42 ## Syntax is <ControllerClass>:<function_pattern>.
42 ## Syntax is <ControllerClass>:<function_pattern>.
43 ## The list should be "," separated and on a single line.
43 ## The list should be "," separated and on a single line.
44 ##
44 ##
45 api_access_controllers_whitelist = RepoCommitsView:repo_commit_raw,RepoCommitsView:repo_commit_patch,RepoCommitsView:repo_commit_download
45 api_access_controllers_whitelist = RepoCommitsView:repo_commit_raw,RepoCommitsView:repo_commit_patch,RepoCommitsView:repo_commit_download
46
46
47 After this change, a |RCE| view can be accessed without login by adding a
47 After this change, a |RCE| view can be accessed without login by adding a
48 GET parameter ``?auth_token=<auth_token>`` to a url. For example to
48 GET parameter ``?auth_token=<auth_token>`` to a url. For example to
49 access the raw diff.
49 access the raw diff.
50
50
51 .. code-block:: html
51 .. code-block:: html
52
52
53 http://<server>/<repo>/changeset-diff/<sha>?auth_token=<auth_token>
53 http://<server>/<repo>/changeset-diff/<sha>?auth_token=<auth_token>
54
54
55 By default this is only enabled on RSS/ATOM feed views. Exposing raw diffs is a
55 By default this is only enabled on RSS/ATOM feed views. Exposing raw diffs is a
56 good way to integrate with 3rd party services like code review, or build farms
56 good way to integrate with 3rd party services like code review, or build farms
57 that could download archives.
57 that could download archives.
58
58
59 API ACCESS
59 API ACCESS
60 ----------
60 ----------
61
61
62 All clients are required to send JSON-RPC spec JSON data.
62 All clients are required to send JSON-RPC spec JSON data.
63
63
64 .. code-block:: bash
64 .. code-block:: bash
65
65
66 {
66 {
67 "id:"<id>",
67 "id:"<id>",
68 "auth_token":"<auth_token>",
68 "auth_token":"<auth_token>",
69 "method":"<method_name>",
69 "method":"<method_name>",
70 "args":{"<arg_key>":"<arg_val>"}
70 "args":{"<arg_key>":"<arg_val>"}
71 }
71 }
72
72
73 Example call for auto pulling from remote repositories using curl:
73 Example call for auto pulling from remote repositories using curl:
74
74
75 .. code-block:: bash
75 .. code-block:: bash
76
76
77 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,
77 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,
78 "auth_token":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull", "args":{"repoid":"CPython"}}'
78 "auth_token":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull", "args":{"repoid":"CPython"}}'
79
79
80 Provide those parameters:
80 Provide those parameters:
81 - **id** A value of any type, which is used to match the response with the
81 - **id** A value of any type, which is used to match the response with the
82 request that it is replying to.
82 request that it is replying to.
83 - **auth_token** for access and permission validation.
83 - **auth_token** for access and permission validation.
84 - **method** is name of method to call
84 - **method** is name of method to call
85 - **args** is an ``key:value`` list of arguments to pass to method
85 - **args** is an ``key:value`` list of arguments to pass to method
86
86
87 .. note::
87 .. note::
88
88
89 To get your |authtoken|, from the |RCE| interface,
89 To get your |authtoken|, from the |RCE| interface,
90 go to:
90 go to:
91 :menuselection:`username --> My account --> Auth tokens`
91 :menuselection:`username --> My account --> Auth tokens`
92
92
93 For security reasons you should always create a dedicated |authtoken| for
93 For security reasons you should always create a dedicated |authtoken| for
94 API use only.
94 API use only.
95
95
96
96
97 The |RCE| API will always return a JSON-RPC response:
97 The |RCE| API will always return a JSON-RPC response:
98
98
99 .. code-block:: bash
99 .. code-block:: bash
100
100
101 {
101 {
102 "id": <id>, # matching id sent by request
102 "id": <id>, # matching id sent by request
103 "result": "<result>"|null, # JSON formatted result, null if any errors
103 "result": "<result>"|null, # JSON formatted result, null if any errors
104 "error": "null"|<error_message> # JSON formatted error (if any)
104 "error": "null"|<error_message> # JSON formatted error (if any)
105 }
105 }
106
106
107 All responses from API will be with `HTTP/1.0 200 OK` status code.
107 All responses from API will be with `HTTP/1.0 200 OK` status code.
108 If there is an error when calling the API, the *error* key will contain a
108 If there is an error when calling the API, the *error* key will contain a
109 failure description and the *result* will be `null`.
109 failure description and the *result* will be `null`.
110
110
111 API CLIENT
111 API CLIENT
112 ----------
112 ----------
113
113
114 To install the |RCE| API, see :ref:`install-tools`. To configure the API per
114 To install the |RCE| API, see :ref:`install-tools`. To configure the API per
115 instance, see the :ref:`rc-tools` section as you need to configure a
115 instance, see the :ref:`rc-tools` section as you need to configure a
116 :file:`~/.rhoderc` file with your |authtokens|.
116 :file:`~/.rhoderc` file with your |authtokens|.
117
117
118 Once you have set up your instance API access, use the following examples to
118 Once you have set up your instance API access, use the following examples to
119 get started.
119 get started.
120
120
121 .. code-block:: bash
121 .. code-block:: bash
122
122
123 # Getting the 'rhodecode' repository
123 # Getting the 'rhodecode' repository
124 # from a RhodeCode Enterprise instance
124 # from a RhodeCode Enterprise instance
125 rhodecode-api --instance-name=enterprise-1 get_repo repoid:rhodecode
125 rhodecode-api --instance-name=enterprise-1 get_repo repoid:rhodecode
126
126
127 Calling method get_repo => http://127.0.0.1:5000
127 Calling method get_repo => http://127.0.0.1:5000
128 Server response
128 Server response
129 {
129 {
130 <json data>
130 <json data>
131 }
131 }
132
132
133 # Creating a new mercurial repository called 'brand-new'
133 # Creating a new mercurial repository called 'brand-new'
134 # with a description 'Repo-description'
134 # with a description 'Repo-description'
135 rhodecode-api --instance-name=enterprise-1 create_repo repo_name:brand-new repo_type:hg description:Repo-description
135 rhodecode-api --instance-name=enterprise-1 create_repo repo_name:brand-new repo_type:hg description:Repo-description
136 {
136 {
137 "error": null,
137 "error": null,
138 "id": 1110,
138 "id": 1110,
139 "result": {
139 "result": {
140 "msg": "Created new repository `brand-new`",
140 "msg": "Created new repository `brand-new`",
141 "success": true,
141 "success": true,
142 "task": null
142 "task": null
143 }
143 }
144 }
144 }
145
145
146 A broken example, what not to do.
146 A broken example, what not to do.
147
147
148 .. code-block:: bash
148 .. code-block:: bash
149
149
150 # A call missing the required arguments
150 # A call missing the required arguments
151 # and not specifying the instance
151 # and not specifying the instance
152 rhodecode-api get_repo
152 rhodecode-api get_repo
153
153
154 Calling method get_repo => http://127.0.0.1:5000
154 Calling method get_repo => http://127.0.0.1:5000
155 Server response
155 Server response
156 "Missing non optional `repoid` arg in JSON DATA"
156 "Missing non optional `repoid` arg in JSON DATA"
157
157
158 You can specify pure JSON using the ``--format`` parameter.
158 You can specify pure JSON using the ``--format`` parameter.
159
159
160 .. code-block:: bash
160 .. code-block:: bash
161
161
162 rhodecode-api --format=json get_repo repoid:rhodecode
162 rhodecode-api --format=json get_repo repoid:rhodecode
163
163
164 In such case only output that this function shows is pure JSON, we can use that
164 In such case only output that this function shows is pure JSON, we can use that
165 and pipe output to some json formatter.
165 and pipe output to some json formatter.
166
166
167 If output is in pure JSON format, you can pipe output to a JSON formatter.
167 If output is in pure JSON format, you can pipe output to a JSON formatter.
168
168
169 .. code-block:: bash
169 .. code-block:: bash
170
170
171 rhodecode-api --instance-name=enterprise-1 --format=json get_repo repoid:rhodecode | python -m json.tool
171 rhodecode-api --instance-name=enterprise-1 --format=json get_repo repoid:rhodecode | python -m json.tool
172
172
173 API METHODS
173 API METHODS
174 -----------
174 -----------
175
175
176 Each method by default required following arguments.
176 Each method by default required following arguments.
177
177
178 .. code-block:: bash
178 .. code-block:: bash
179
179
180 id : "<id_for_response>"
180 id : "<id_for_response>"
181 auth_token : "<auth_token>"
181 auth_token : "<auth_token>"
182 method : "<method name>"
182 method : "<method name>"
183 args : {}
183 args : {}
184
184
185 Use each **param** from docs and put it in args, Optional parameters
185 Use each **param** from docs and put it in args, Optional parameters
186 are not required in args.
186 are not required in args.
187
187
188 .. code-block:: bash
188 .. code-block:: bash
189
189
190 args: {"repoid": "rhodecode"}
190 args: {"repoid": "rhodecode"}
191
191
192 .. Note: From this point on things are generated by the script in
192 .. Note: From this point on things are generated by the script in
193 `scripts/fabfile.py`. To change things below, update the docstrings in the
193 `scripts/fabfile.py`. To change things below, update the docstrings in the
194 ApiController.
194 ApiController.
195
195
196 .. --- API DEFS MARKER ---
196 .. --- API DEFS MARKER ---
197 .. toctree::
197 .. toctree::
198
198
199 methods/views
199 methods/license-methods
200 methods/license-methods
200 methods/deprecated-methods
201 methods/deprecated-methods
201 methods/gist-methods
202 methods/gist-methods
202 methods/pull-request-methods
203 methods/pull-request-methods
203 methods/repo-methods
204 methods/repo-methods
204 methods/repo-group-methods
205 methods/repo-group-methods
205 methods/server-methods
206 methods/server-methods
206 methods/user-methods
207 methods/user-methods
207 methods/user-group-methods
208 methods/user-group-methods
@@ -1,1024 +1,1028 b''
1 .. _repo-methods-ref:
1 .. _repo-methods-ref:
2
2
3 repo methods
3 repo methods
4 ============
4 ============
5
5
6 add_field_to_repo
6 add_field_to_repo
7 -----------------
7 -----------------
8
8
9 .. py:function:: add_field_to_repo(apiuser, repoid, key, label=<Optional:''>, description=<Optional:''>)
9 .. py:function:: add_field_to_repo(apiuser, repoid, key, label=<Optional:''>, description=<Optional:''>)
10
10
11 Adds an extra field to a repository.
11 Adds an extra field to a repository.
12
12
13 This command can only be run using an |authtoken| with at least
13 This command can only be run using an |authtoken| with at least
14 write permissions to the |repo|.
14 write permissions to the |repo|.
15
15
16 :param apiuser: This is filled automatically from the |authtoken|.
16 :param apiuser: This is filled automatically from the |authtoken|.
17 :type apiuser: AuthUser
17 :type apiuser: AuthUser
18 :param repoid: Set the repository name or repository id.
18 :param repoid: Set the repository name or repository id.
19 :type repoid: str or int
19 :type repoid: str or int
20 :param key: Create a unique field key for this repository.
20 :param key: Create a unique field key for this repository.
21 :type key: str
21 :type key: str
22 :param label:
22 :param label:
23 :type label: Optional(str)
23 :type label: Optional(str)
24 :param description:
24 :param description:
25 :type description: Optional(str)
25 :type description: Optional(str)
26
26
27
27
28 comment_commit
28 comment_commit
29 --------------
29 --------------
30
30
31 .. py:function:: comment_commit(apiuser, repoid, commit_id, message, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
31 .. py:function:: comment_commit(apiuser, repoid, commit_id, message, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
32
32
33 Set a commit comment, and optionally change the status of the commit.
33 Set a commit comment, and optionally change the status of the commit.
34
34
35 :param apiuser: This is filled automatically from the |authtoken|.
35 :param apiuser: This is filled automatically from the |authtoken|.
36 :type apiuser: AuthUser
36 :type apiuser: AuthUser
37 :param repoid: Set the repository name or repository ID.
37 :param repoid: Set the repository name or repository ID.
38 :type repoid: str or int
38 :type repoid: str or int
39 :param commit_id: Specify the commit_id for which to set a comment.
39 :param commit_id: Specify the commit_id for which to set a comment.
40 :type commit_id: str
40 :type commit_id: str
41 :param message: The comment text.
41 :param message: The comment text.
42 :type message: str
42 :type message: str
43 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
43 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
44 'approved', 'rejected', 'under_review'
44 'approved', 'rejected', 'under_review'
45 :type status: str
45 :type status: str
46 :param comment_type: Comment type, one of: 'note', 'todo'
46 :param comment_type: Comment type, one of: 'note', 'todo'
47 :type comment_type: Optional(str), default: 'note'
47 :type comment_type: Optional(str), default: 'note'
48 :param userid: Set the user name of the comment creator.
48 :param userid: Set the user name of the comment creator.
49 :type userid: Optional(str or int)
49 :type userid: Optional(str or int)
50
50
51 Example error output:
51 Example error output:
52
52
53 .. code-block:: bash
53 .. code-block:: bash
54
54
55 {
55 {
56 "id" : <id_given_in_input>,
56 "id" : <id_given_in_input>,
57 "result" : {
57 "result" : {
58 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
58 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
59 "status_change": null or <status>,
59 "status_change": null or <status>,
60 "success": true
60 "success": true
61 },
61 },
62 "error" : null
62 "error" : null
63 }
63 }
64
64
65
65
66 create_repo
66 create_repo
67 -----------
67 -----------
68
68
69 .. py:function:: create_repo(apiuser, repo_name, repo_type, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, copy_permissions=<Optional:False>)
69 .. py:function:: create_repo(apiuser, repo_name, repo_type, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, push_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, copy_permissions=<Optional:False>)
70
70
71 Creates a repository.
71 Creates a repository.
72
72
73 * If the repository name contains "/", repository will be created inside
73 * If the repository name contains "/", repository will be created inside
74 a repository group or nested repository groups
74 a repository group or nested repository groups
75
75
76 For example "foo/bar/repo1" will create |repo| called "repo1" inside
76 For example "foo/bar/repo1" will create |repo| called "repo1" inside
77 group "foo/bar". You have to have permissions to access and write to
77 group "foo/bar". You have to have permissions to access and write to
78 the last repository group ("bar" in this example)
78 the last repository group ("bar" in this example)
79
79
80 This command can only be run using an |authtoken| with at least
80 This command can only be run using an |authtoken| with at least
81 permissions to create repositories, or write permissions to
81 permissions to create repositories, or write permissions to
82 parent repository groups.
82 parent repository groups.
83
83
84 :param apiuser: This is filled automatically from the |authtoken|.
84 :param apiuser: This is filled automatically from the |authtoken|.
85 :type apiuser: AuthUser
85 :type apiuser: AuthUser
86 :param repo_name: Set the repository name.
86 :param repo_name: Set the repository name.
87 :type repo_name: str
87 :type repo_name: str
88 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
88 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
89 :type repo_type: str
89 :type repo_type: str
90 :param owner: user_id or username
90 :param owner: user_id or username
91 :type owner: Optional(str)
91 :type owner: Optional(str)
92 :param description: Set the repository description.
92 :param description: Set the repository description.
93 :type description: Optional(str)
93 :type description: Optional(str)
94 :param private: set repository as private
94 :param private: set repository as private
95 :type private: bool
95 :type private: bool
96 :param clone_uri: set clone_uri
96 :param clone_uri: set clone_uri
97 :type clone_uri: str
97 :type clone_uri: str
98 :param push_uri: set push_uri
99 :type push_uri: str
98 :param landing_rev: <rev_type>:<rev>
100 :param landing_rev: <rev_type>:<rev>
99 :type landing_rev: str
101 :type landing_rev: str
100 :param enable_locking:
102 :param enable_locking:
101 :type enable_locking: bool
103 :type enable_locking: bool
102 :param enable_downloads:
104 :param enable_downloads:
103 :type enable_downloads: bool
105 :type enable_downloads: bool
104 :param enable_statistics:
106 :param enable_statistics:
105 :type enable_statistics: bool
107 :type enable_statistics: bool
106 :param copy_permissions: Copy permission from group in which the
108 :param copy_permissions: Copy permission from group in which the
107 repository is being created.
109 repository is being created.
108 :type copy_permissions: bool
110 :type copy_permissions: bool
109
111
110
112
111 Example output:
113 Example output:
112
114
113 .. code-block:: bash
115 .. code-block:: bash
114
116
115 id : <id_given_in_input>
117 id : <id_given_in_input>
116 result: {
118 result: {
117 "msg": "Created new repository `<reponame>`",
119 "msg": "Created new repository `<reponame>`",
118 "success": true,
120 "success": true,
119 "task": "<celery task id or None if done sync>"
121 "task": "<celery task id or None if done sync>"
120 }
122 }
121 error: null
123 error: null
122
124
123
125
124 Example error output:
126 Example error output:
125
127
126 .. code-block:: bash
128 .. code-block:: bash
127
129
128 id : <id_given_in_input>
130 id : <id_given_in_input>
129 result : null
131 result : null
130 error : {
132 error : {
131 'failed to create repository `<repo_name>`'
133 'failed to create repository `<repo_name>`'
132 }
134 }
133
135
134
136
135 delete_repo
137 delete_repo
136 -----------
138 -----------
137
139
138 .. py:function:: delete_repo(apiuser, repoid, forks=<Optional:''>)
140 .. py:function:: delete_repo(apiuser, repoid, forks=<Optional:''>)
139
141
140 Deletes a repository.
142 Deletes a repository.
141
143
142 * When the `forks` parameter is set it's possible to detach or delete
144 * When the `forks` parameter is set it's possible to detach or delete
143 forks of deleted repository.
145 forks of deleted repository.
144
146
145 This command can only be run using an |authtoken| with admin
147 This command can only be run using an |authtoken| with admin
146 permissions on the |repo|.
148 permissions on the |repo|.
147
149
148 :param apiuser: This is filled automatically from the |authtoken|.
150 :param apiuser: This is filled automatically from the |authtoken|.
149 :type apiuser: AuthUser
151 :type apiuser: AuthUser
150 :param repoid: Set the repository name or repository ID.
152 :param repoid: Set the repository name or repository ID.
151 :type repoid: str or int
153 :type repoid: str or int
152 :param forks: Set to `detach` or `delete` forks from the |repo|.
154 :param forks: Set to `detach` or `delete` forks from the |repo|.
153 :type forks: Optional(str)
155 :type forks: Optional(str)
154
156
155 Example error output:
157 Example error output:
156
158
157 .. code-block:: bash
159 .. code-block:: bash
158
160
159 id : <id_given_in_input>
161 id : <id_given_in_input>
160 result: {
162 result: {
161 "msg": "Deleted repository `<reponame>`",
163 "msg": "Deleted repository `<reponame>`",
162 "success": true
164 "success": true
163 }
165 }
164 error: null
166 error: null
165
167
166
168
167 fork_repo
169 fork_repo
168 ---------
170 ---------
169
171
170 .. py:function:: fork_repo(apiuser, repoid, fork_name, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, copy_permissions=<Optional:False>)
172 .. py:function:: fork_repo(apiuser, repoid, fork_name, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, copy_permissions=<Optional:False>)
171
173
172 Creates a fork of the specified |repo|.
174 Creates a fork of the specified |repo|.
173
175
174 * If the fork_name contains "/", fork will be created inside
176 * If the fork_name contains "/", fork will be created inside
175 a repository group or nested repository groups
177 a repository group or nested repository groups
176
178
177 For example "foo/bar/fork-repo" will create fork called "fork-repo"
179 For example "foo/bar/fork-repo" will create fork called "fork-repo"
178 inside group "foo/bar". You have to have permissions to access and
180 inside group "foo/bar". You have to have permissions to access and
179 write to the last repository group ("bar" in this example)
181 write to the last repository group ("bar" in this example)
180
182
181 This command can only be run using an |authtoken| with minimum
183 This command can only be run using an |authtoken| with minimum
182 read permissions of the forked repo, create fork permissions for an user.
184 read permissions of the forked repo, create fork permissions for an user.
183
185
184 :param apiuser: This is filled automatically from the |authtoken|.
186 :param apiuser: This is filled automatically from the |authtoken|.
185 :type apiuser: AuthUser
187 :type apiuser: AuthUser
186 :param repoid: Set repository name or repository ID.
188 :param repoid: Set repository name or repository ID.
187 :type repoid: str or int
189 :type repoid: str or int
188 :param fork_name: Set the fork name, including it's repository group membership.
190 :param fork_name: Set the fork name, including it's repository group membership.
189 :type fork_name: str
191 :type fork_name: str
190 :param owner: Set the fork owner.
192 :param owner: Set the fork owner.
191 :type owner: str
193 :type owner: str
192 :param description: Set the fork description.
194 :param description: Set the fork description.
193 :type description: str
195 :type description: str
194 :param copy_permissions: Copy permissions from parent |repo|. The
196 :param copy_permissions: Copy permissions from parent |repo|. The
195 default is False.
197 default is False.
196 :type copy_permissions: bool
198 :type copy_permissions: bool
197 :param private: Make the fork private. The default is False.
199 :param private: Make the fork private. The default is False.
198 :type private: bool
200 :type private: bool
199 :param landing_rev: Set the landing revision. The default is tip.
201 :param landing_rev: Set the landing revision. The default is tip.
200
202
201 Example output:
203 Example output:
202
204
203 .. code-block:: bash
205 .. code-block:: bash
204
206
205 id : <id_for_response>
207 id : <id_for_response>
206 api_key : "<api_key>"
208 api_key : "<api_key>"
207 args: {
209 args: {
208 "repoid" : "<reponame or repo_id>",
210 "repoid" : "<reponame or repo_id>",
209 "fork_name": "<forkname>",
211 "fork_name": "<forkname>",
210 "owner": "<username or user_id = Optional(=apiuser)>",
212 "owner": "<username or user_id = Optional(=apiuser)>",
211 "description": "<description>",
213 "description": "<description>",
212 "copy_permissions": "<bool>",
214 "copy_permissions": "<bool>",
213 "private": "<bool>",
215 "private": "<bool>",
214 "landing_rev": "<landing_rev>"
216 "landing_rev": "<landing_rev>"
215 }
217 }
216
218
217 Example error output:
219 Example error output:
218
220
219 .. code-block:: bash
221 .. code-block:: bash
220
222
221 id : <id_given_in_input>
223 id : <id_given_in_input>
222 result: {
224 result: {
223 "msg": "Created fork of `<reponame>` as `<forkname>`",
225 "msg": "Created fork of `<reponame>` as `<forkname>`",
224 "success": true,
226 "success": true,
225 "task": "<celery task id or None if done sync>"
227 "task": "<celery task id or None if done sync>"
226 }
228 }
227 error: null
229 error: null
228
230
229
231
230 get_repo
232 get_repo
231 --------
233 --------
232
234
233 .. py:function:: get_repo(apiuser, repoid, cache=<Optional:True>)
235 .. py:function:: get_repo(apiuser, repoid, cache=<Optional:True>)
234
236
235 Gets an existing repository by its name or repository_id.
237 Gets an existing repository by its name or repository_id.
236
238
237 The members section so the output returns users groups or users
239 The members section so the output returns users groups or users
238 associated with that repository.
240 associated with that repository.
239
241
240 This command can only be run using an |authtoken| with admin rights,
242 This command can only be run using an |authtoken| with admin rights,
241 or users with at least read rights to the |repo|.
243 or users with at least read rights to the |repo|.
242
244
243 :param apiuser: This is filled automatically from the |authtoken|.
245 :param apiuser: This is filled automatically from the |authtoken|.
244 :type apiuser: AuthUser
246 :type apiuser: AuthUser
245 :param repoid: The repository name or repository id.
247 :param repoid: The repository name or repository id.
246 :type repoid: str or int
248 :type repoid: str or int
247 :param cache: use the cached value for last changeset
249 :param cache: use the cached value for last changeset
248 :type: cache: Optional(bool)
250 :type: cache: Optional(bool)
249
251
250 Example output:
252 Example output:
251
253
252 .. code-block:: bash
254 .. code-block:: bash
253
255
254 {
256 {
255 "error": null,
257 "error": null,
256 "id": <repo_id>,
258 "id": <repo_id>,
257 "result": {
259 "result": {
258 "clone_uri": null,
260 "clone_uri": null,
259 "created_on": "timestamp",
261 "created_on": "timestamp",
260 "description": "repo description",
262 "description": "repo description",
261 "enable_downloads": false,
263 "enable_downloads": false,
262 "enable_locking": false,
264 "enable_locking": false,
263 "enable_statistics": false,
265 "enable_statistics": false,
264 "followers": [
266 "followers": [
265 {
267 {
266 "active": true,
268 "active": true,
267 "admin": false,
269 "admin": false,
268 "api_key": "****************************************",
270 "api_key": "****************************************",
269 "api_keys": [
271 "api_keys": [
270 "****************************************"
272 "****************************************"
271 ],
273 ],
272 "email": "user@example.com",
274 "email": "user@example.com",
273 "emails": [
275 "emails": [
274 "user@example.com"
276 "user@example.com"
275 ],
277 ],
276 "extern_name": "rhodecode",
278 "extern_name": "rhodecode",
277 "extern_type": "rhodecode",
279 "extern_type": "rhodecode",
278 "firstname": "username",
280 "firstname": "username",
279 "ip_addresses": [],
281 "ip_addresses": [],
280 "language": null,
282 "language": null,
281 "last_login": "2015-09-16T17:16:35.854",
283 "last_login": "2015-09-16T17:16:35.854",
282 "lastname": "surname",
284 "lastname": "surname",
283 "user_id": <user_id>,
285 "user_id": <user_id>,
284 "username": "name"
286 "username": "name"
285 }
287 }
286 ],
288 ],
287 "fork_of": "parent-repo",
289 "fork_of": "parent-repo",
288 "landing_rev": [
290 "landing_rev": [
289 "rev",
291 "rev",
290 "tip"
292 "tip"
291 ],
293 ],
292 "last_changeset": {
294 "last_changeset": {
293 "author": "User <user@example.com>",
295 "author": "User <user@example.com>",
294 "branch": "default",
296 "branch": "default",
295 "date": "timestamp",
297 "date": "timestamp",
296 "message": "last commit message",
298 "message": "last commit message",
297 "parents": [
299 "parents": [
298 {
300 {
299 "raw_id": "commit-id"
301 "raw_id": "commit-id"
300 }
302 }
301 ],
303 ],
302 "raw_id": "commit-id",
304 "raw_id": "commit-id",
303 "revision": <revision number>,
305 "revision": <revision number>,
304 "short_id": "short id"
306 "short_id": "short id"
305 },
307 },
306 "lock_reason": null,
308 "lock_reason": null,
307 "locked_by": null,
309 "locked_by": null,
308 "locked_date": null,
310 "locked_date": null,
309 "owner": "owner-name",
311 "owner": "owner-name",
310 "permissions": [
312 "permissions": [
311 {
313 {
312 "name": "super-admin-name",
314 "name": "super-admin-name",
313 "origin": "super-admin",
315 "origin": "super-admin",
314 "permission": "repository.admin",
316 "permission": "repository.admin",
315 "type": "user"
317 "type": "user"
316 },
318 },
317 {
319 {
318 "name": "owner-name",
320 "name": "owner-name",
319 "origin": "owner",
321 "origin": "owner",
320 "permission": "repository.admin",
322 "permission": "repository.admin",
321 "type": "user"
323 "type": "user"
322 },
324 },
323 {
325 {
324 "name": "user-group-name",
326 "name": "user-group-name",
325 "origin": "permission",
327 "origin": "permission",
326 "permission": "repository.write",
328 "permission": "repository.write",
327 "type": "user_group"
329 "type": "user_group"
328 }
330 }
329 ],
331 ],
330 "private": true,
332 "private": true,
331 "repo_id": 676,
333 "repo_id": 676,
332 "repo_name": "user-group/repo-name",
334 "repo_name": "user-group/repo-name",
333 "repo_type": "hg"
335 "repo_type": "hg"
334 }
336 }
335 }
337 }
336
338
337
339
338 get_repo_changeset
340 get_repo_changeset
339 ------------------
341 ------------------
340
342
341 .. py:function:: get_repo_changeset(apiuser, repoid, revision, details=<Optional:'basic'>)
343 .. py:function:: get_repo_changeset(apiuser, repoid, revision, details=<Optional:'basic'>)
342
344
343 Returns information about a changeset.
345 Returns information about a changeset.
344
346
345 Additionally parameters define the amount of details returned by
347 Additionally parameters define the amount of details returned by
346 this function.
348 this function.
347
349
348 This command can only be run using an |authtoken| with admin rights,
350 This command can only be run using an |authtoken| with admin rights,
349 or users with at least read rights to the |repo|.
351 or users with at least read rights to the |repo|.
350
352
351 :param apiuser: This is filled automatically from the |authtoken|.
353 :param apiuser: This is filled automatically from the |authtoken|.
352 :type apiuser: AuthUser
354 :type apiuser: AuthUser
353 :param repoid: The repository name or repository id
355 :param repoid: The repository name or repository id
354 :type repoid: str or int
356 :type repoid: str or int
355 :param revision: revision for which listing should be done
357 :param revision: revision for which listing should be done
356 :type revision: str
358 :type revision: str
357 :param details: details can be 'basic|extended|full' full gives diff
359 :param details: details can be 'basic|extended|full' full gives diff
358 info details like the diff itself, and number of changed files etc.
360 info details like the diff itself, and number of changed files etc.
359 :type details: Optional(str)
361 :type details: Optional(str)
360
362
361
363
362 get_repo_changesets
364 get_repo_changesets
363 -------------------
365 -------------------
364
366
365 .. py:function:: get_repo_changesets(apiuser, repoid, start_rev, limit, details=<Optional:'basic'>)
367 .. py:function:: get_repo_changesets(apiuser, repoid, start_rev, limit, details=<Optional:'basic'>)
366
368
367 Returns a set of commits limited by the number starting
369 Returns a set of commits limited by the number starting
368 from the `start_rev` option.
370 from the `start_rev` option.
369
371
370 Additional parameters define the amount of details returned by this
372 Additional parameters define the amount of details returned by this
371 function.
373 function.
372
374
373 This command can only be run using an |authtoken| with admin rights,
375 This command can only be run using an |authtoken| with admin rights,
374 or users with at least read rights to |repos|.
376 or users with at least read rights to |repos|.
375
377
376 :param apiuser: This is filled automatically from the |authtoken|.
378 :param apiuser: This is filled automatically from the |authtoken|.
377 :type apiuser: AuthUser
379 :type apiuser: AuthUser
378 :param repoid: The repository name or repository ID.
380 :param repoid: The repository name or repository ID.
379 :type repoid: str or int
381 :type repoid: str or int
380 :param start_rev: The starting revision from where to get changesets.
382 :param start_rev: The starting revision from where to get changesets.
381 :type start_rev: str
383 :type start_rev: str
382 :param limit: Limit the number of commits to this amount
384 :param limit: Limit the number of commits to this amount
383 :type limit: str or int
385 :type limit: str or int
384 :param details: Set the level of detail returned. Valid option are:
386 :param details: Set the level of detail returned. Valid option are:
385 ``basic``, ``extended`` and ``full``.
387 ``basic``, ``extended`` and ``full``.
386 :type details: Optional(str)
388 :type details: Optional(str)
387
389
388 .. note::
390 .. note::
389
391
390 Setting the parameter `details` to the value ``full`` is extensive
392 Setting the parameter `details` to the value ``full`` is extensive
391 and returns details like the diff itself, and the number
393 and returns details like the diff itself, and the number
392 of changed files.
394 of changed files.
393
395
394
396
395 get_repo_nodes
397 get_repo_nodes
396 --------------
398 --------------
397
399
398 .. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
400 .. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
399
401
400 Returns a list of nodes and children in a flat list for a given
402 Returns a list of nodes and children in a flat list for a given
401 path at given revision.
403 path at given revision.
402
404
403 It's possible to specify ret_type to show only `files` or `dirs`.
405 It's possible to specify ret_type to show only `files` or `dirs`.
404
406
405 This command can only be run using an |authtoken| with admin rights,
407 This command can only be run using an |authtoken| with admin rights,
406 or users with at least read rights to |repos|.
408 or users with at least read rights to |repos|.
407
409
408 :param apiuser: This is filled automatically from the |authtoken|.
410 :param apiuser: This is filled automatically from the |authtoken|.
409 :type apiuser: AuthUser
411 :type apiuser: AuthUser
410 :param repoid: The repository name or repository ID.
412 :param repoid: The repository name or repository ID.
411 :type repoid: str or int
413 :type repoid: str or int
412 :param revision: The revision for which listing should be done.
414 :param revision: The revision for which listing should be done.
413 :type revision: str
415 :type revision: str
414 :param root_path: The path from which to start displaying.
416 :param root_path: The path from which to start displaying.
415 :type root_path: str
417 :type root_path: str
416 :param ret_type: Set the return type. Valid options are
418 :param ret_type: Set the return type. Valid options are
417 ``all`` (default), ``files`` and ``dirs``.
419 ``all`` (default), ``files`` and ``dirs``.
418 :type ret_type: Optional(str)
420 :type ret_type: Optional(str)
419 :param details: Returns extended information about nodes, such as
421 :param details: Returns extended information about nodes, such as
420 md5, binary, and or content. The valid options are ``basic`` and
422 md5, binary, and or content. The valid options are ``basic`` and
421 ``full``.
423 ``full``.
422 :type details: Optional(str)
424 :type details: Optional(str)
423 :param max_file_bytes: Only return file content under this file size bytes
425 :param max_file_bytes: Only return file content under this file size bytes
424 :type details: Optional(int)
426 :type details: Optional(int)
425
427
426 Example output:
428 Example output:
427
429
428 .. code-block:: bash
430 .. code-block:: bash
429
431
430 id : <id_given_in_input>
432 id : <id_given_in_input>
431 result: [
433 result: [
432 {
434 {
433 "name" : "<name>"
435 "name" : "<name>"
434 "type" : "<type>",
436 "type" : "<type>",
435 "binary": "<true|false>" (only in extended mode)
437 "binary": "<true|false>" (only in extended mode)
436 "md5" : "<md5 of file content>" (only in extended mode)
438 "md5" : "<md5 of file content>" (only in extended mode)
437 },
439 },
438 ...
440 ...
439 ]
441 ]
440 error: null
442 error: null
441
443
442
444
443 get_repo_refs
445 get_repo_refs
444 -------------
446 -------------
445
447
446 .. py:function:: get_repo_refs(apiuser, repoid)
448 .. py:function:: get_repo_refs(apiuser, repoid)
447
449
448 Returns a dictionary of current references. It returns
450 Returns a dictionary of current references. It returns
449 bookmarks, branches, closed_branches, and tags for given repository
451 bookmarks, branches, closed_branches, and tags for given repository
450
452
451 It's possible to specify ret_type to show only `files` or `dirs`.
453 It's possible to specify ret_type to show only `files` or `dirs`.
452
454
453 This command can only be run using an |authtoken| with admin rights,
455 This command can only be run using an |authtoken| with admin rights,
454 or users with at least read rights to |repos|.
456 or users with at least read rights to |repos|.
455
457
456 :param apiuser: This is filled automatically from the |authtoken|.
458 :param apiuser: This is filled automatically from the |authtoken|.
457 :type apiuser: AuthUser
459 :type apiuser: AuthUser
458 :param repoid: The repository name or repository ID.
460 :param repoid: The repository name or repository ID.
459 :type repoid: str or int
461 :type repoid: str or int
460
462
461 Example output:
463 Example output:
462
464
463 .. code-block:: bash
465 .. code-block:: bash
464
466
465 id : <id_given_in_input>
467 id : <id_given_in_input>
466 "result": {
468 "result": {
467 "bookmarks": {
469 "bookmarks": {
468 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
470 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
469 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
471 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
470 },
472 },
471 "branches": {
473 "branches": {
472 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
474 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
473 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
475 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
474 },
476 },
475 "branches_closed": {},
477 "branches_closed": {},
476 "tags": {
478 "tags": {
477 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
479 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
478 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
480 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
479 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
481 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
480 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
482 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
481 }
483 }
482 }
484 }
483 error: null
485 error: null
484
486
485
487
486 get_repo_settings
488 get_repo_settings
487 -----------------
489 -----------------
488
490
489 .. py:function:: get_repo_settings(apiuser, repoid, key=<Optional:None>)
491 .. py:function:: get_repo_settings(apiuser, repoid, key=<Optional:None>)
490
492
491 Returns all settings for a repository. If key is given it only returns the
493 Returns all settings for a repository. If key is given it only returns the
492 setting identified by the key or null.
494 setting identified by the key or null.
493
495
494 :param apiuser: This is filled automatically from the |authtoken|.
496 :param apiuser: This is filled automatically from the |authtoken|.
495 :type apiuser: AuthUser
497 :type apiuser: AuthUser
496 :param repoid: The repository name or repository id.
498 :param repoid: The repository name or repository id.
497 :type repoid: str or int
499 :type repoid: str or int
498 :param key: Key of the setting to return.
500 :param key: Key of the setting to return.
499 :type: key: Optional(str)
501 :type: key: Optional(str)
500
502
501 Example output:
503 Example output:
502
504
503 .. code-block:: bash
505 .. code-block:: bash
504
506
505 {
507 {
506 "error": null,
508 "error": null,
507 "id": 237,
509 "id": 237,
508 "result": {
510 "result": {
509 "extensions_largefiles": true,
511 "extensions_largefiles": true,
510 "extensions_evolve": true,
512 "extensions_evolve": true,
511 "hooks_changegroup_push_logger": true,
513 "hooks_changegroup_push_logger": true,
512 "hooks_changegroup_repo_size": false,
514 "hooks_changegroup_repo_size": false,
513 "hooks_outgoing_pull_logger": true,
515 "hooks_outgoing_pull_logger": true,
514 "phases_publish": "True",
516 "phases_publish": "True",
515 "rhodecode_hg_use_rebase_for_merging": true,
517 "rhodecode_hg_use_rebase_for_merging": true,
516 "rhodecode_pr_merge_enabled": true,
518 "rhodecode_pr_merge_enabled": true,
517 "rhodecode_use_outdated_comments": true
519 "rhodecode_use_outdated_comments": true
518 }
520 }
519 }
521 }
520
522
521
523
522 get_repos
524 get_repos
523 ---------
525 ---------
524
526
525 .. py:function:: get_repos(apiuser, root=<Optional:None>, traverse=<Optional:True>)
527 .. py:function:: get_repos(apiuser, root=<Optional:None>, traverse=<Optional:True>)
526
528
527 Lists all existing repositories.
529 Lists all existing repositories.
528
530
529 This command can only be run using an |authtoken| with admin rights,
531 This command can only be run using an |authtoken| with admin rights,
530 or users with at least read rights to |repos|.
532 or users with at least read rights to |repos|.
531
533
532 :param apiuser: This is filled automatically from the |authtoken|.
534 :param apiuser: This is filled automatically from the |authtoken|.
533 :type apiuser: AuthUser
535 :type apiuser: AuthUser
534 :param root: specify root repository group to fetch repositories.
536 :param root: specify root repository group to fetch repositories.
535 filters the returned repositories to be members of given root group.
537 filters the returned repositories to be members of given root group.
536 :type root: Optional(None)
538 :type root: Optional(None)
537 :param traverse: traverse given root into subrepositories. With this flag
539 :param traverse: traverse given root into subrepositories. With this flag
538 set to False, it will only return top-level repositories from `root`.
540 set to False, it will only return top-level repositories from `root`.
539 if root is empty it will return just top-level repositories.
541 if root is empty it will return just top-level repositories.
540 :type traverse: Optional(True)
542 :type traverse: Optional(True)
541
543
542
544
543 Example output:
545 Example output:
544
546
545 .. code-block:: bash
547 .. code-block:: bash
546
548
547 id : <id_given_in_input>
549 id : <id_given_in_input>
548 result: [
550 result: [
549 {
551 {
550 "repo_id" : "<repo_id>",
552 "repo_id" : "<repo_id>",
551 "repo_name" : "<reponame>"
553 "repo_name" : "<reponame>"
552 "repo_type" : "<repo_type>",
554 "repo_type" : "<repo_type>",
553 "clone_uri" : "<clone_uri>",
555 "clone_uri" : "<clone_uri>",
554 "private": : "<bool>",
556 "private": : "<bool>",
555 "created_on" : "<datetimecreated>",
557 "created_on" : "<datetimecreated>",
556 "description" : "<description>",
558 "description" : "<description>",
557 "landing_rev": "<landing_rev>",
559 "landing_rev": "<landing_rev>",
558 "owner": "<repo_owner>",
560 "owner": "<repo_owner>",
559 "fork_of": "<name_of_fork_parent>",
561 "fork_of": "<name_of_fork_parent>",
560 "enable_downloads": "<bool>",
562 "enable_downloads": "<bool>",
561 "enable_locking": "<bool>",
563 "enable_locking": "<bool>",
562 "enable_statistics": "<bool>",
564 "enable_statistics": "<bool>",
563 },
565 },
564 ...
566 ...
565 ]
567 ]
566 error: null
568 error: null
567
569
568
570
569 grant_user_group_permission
571 grant_user_group_permission
570 ---------------------------
572 ---------------------------
571
573
572 .. py:function:: grant_user_group_permission(apiuser, repoid, usergroupid, perm)
574 .. py:function:: grant_user_group_permission(apiuser, repoid, usergroupid, perm)
573
575
574 Grant permission for a user group on the specified repository,
576 Grant permission for a user group on the specified repository,
575 or update existing permissions.
577 or update existing permissions.
576
578
577 This command can only be run using an |authtoken| with admin
579 This command can only be run using an |authtoken| with admin
578 permissions on the |repo|.
580 permissions on the |repo|.
579
581
580 :param apiuser: This is filled automatically from the |authtoken|.
582 :param apiuser: This is filled automatically from the |authtoken|.
581 :type apiuser: AuthUser
583 :type apiuser: AuthUser
582 :param repoid: Set the repository name or repository ID.
584 :param repoid: Set the repository name or repository ID.
583 :type repoid: str or int
585 :type repoid: str or int
584 :param usergroupid: Specify the ID of the user group.
586 :param usergroupid: Specify the ID of the user group.
585 :type usergroupid: str or int
587 :type usergroupid: str or int
586 :param perm: Set the user group permissions using the following
588 :param perm: Set the user group permissions using the following
587 format: (repository.(none|read|write|admin))
589 format: (repository.(none|read|write|admin))
588 :type perm: str
590 :type perm: str
589
591
590 Example output:
592 Example output:
591
593
592 .. code-block:: bash
594 .. code-block:: bash
593
595
594 id : <id_given_in_input>
596 id : <id_given_in_input>
595 result : {
597 result : {
596 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
598 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
597 "success": true
599 "success": true
598
600
599 }
601 }
600 error : null
602 error : null
601
603
602 Example error output:
604 Example error output:
603
605
604 .. code-block:: bash
606 .. code-block:: bash
605
607
606 id : <id_given_in_input>
608 id : <id_given_in_input>
607 result : null
609 result : null
608 error : {
610 error : {
609 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
611 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
610 }
612 }
611
613
612
614
613 grant_user_permission
615 grant_user_permission
614 ---------------------
616 ---------------------
615
617
616 .. py:function:: grant_user_permission(apiuser, repoid, userid, perm)
618 .. py:function:: grant_user_permission(apiuser, repoid, userid, perm)
617
619
618 Grant permissions for the specified user on the given repository,
620 Grant permissions for the specified user on the given repository,
619 or update existing permissions if found.
621 or update existing permissions if found.
620
622
621 This command can only be run using an |authtoken| with admin
623 This command can only be run using an |authtoken| with admin
622 permissions on the |repo|.
624 permissions on the |repo|.
623
625
624 :param apiuser: This is filled automatically from the |authtoken|.
626 :param apiuser: This is filled automatically from the |authtoken|.
625 :type apiuser: AuthUser
627 :type apiuser: AuthUser
626 :param repoid: Set the repository name or repository ID.
628 :param repoid: Set the repository name or repository ID.
627 :type repoid: str or int
629 :type repoid: str or int
628 :param userid: Set the user name.
630 :param userid: Set the user name.
629 :type userid: str
631 :type userid: str
630 :param perm: Set the user permissions, using the following format
632 :param perm: Set the user permissions, using the following format
631 ``(repository.(none|read|write|admin))``
633 ``(repository.(none|read|write|admin))``
632 :type perm: str
634 :type perm: str
633
635
634 Example output:
636 Example output:
635
637
636 .. code-block:: bash
638 .. code-block:: bash
637
639
638 id : <id_given_in_input>
640 id : <id_given_in_input>
639 result: {
641 result: {
640 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
642 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
641 "success": true
643 "success": true
642 }
644 }
643 error: null
645 error: null
644
646
645
647
646 invalidate_cache
648 invalidate_cache
647 ----------------
649 ----------------
648
650
649 .. py:function:: invalidate_cache(apiuser, repoid, delete_keys=<Optional:False>)
651 .. py:function:: invalidate_cache(apiuser, repoid, delete_keys=<Optional:False>)
650
652
651 Invalidates the cache for the specified repository.
653 Invalidates the cache for the specified repository.
652
654
653 This command can only be run using an |authtoken| with admin rights to
655 This command can only be run using an |authtoken| with admin rights to
654 the specified repository.
656 the specified repository.
655
657
656 This command takes the following options:
658 This command takes the following options:
657
659
658 :param apiuser: This is filled automatically from |authtoken|.
660 :param apiuser: This is filled automatically from |authtoken|.
659 :type apiuser: AuthUser
661 :type apiuser: AuthUser
660 :param repoid: Sets the repository name or repository ID.
662 :param repoid: Sets the repository name or repository ID.
661 :type repoid: str or int
663 :type repoid: str or int
662 :param delete_keys: This deletes the invalidated keys instead of
664 :param delete_keys: This deletes the invalidated keys instead of
663 just flagging them.
665 just flagging them.
664 :type delete_keys: Optional(``True`` | ``False``)
666 :type delete_keys: Optional(``True`` | ``False``)
665
667
666 Example output:
668 Example output:
667
669
668 .. code-block:: bash
670 .. code-block:: bash
669
671
670 id : <id_given_in_input>
672 id : <id_given_in_input>
671 result : {
673 result : {
672 'msg': Cache for repository `<repository name>` was invalidated,
674 'msg': Cache for repository `<repository name>` was invalidated,
673 'repository': <repository name>
675 'repository': <repository name>
674 }
676 }
675 error : null
677 error : null
676
678
677 Example error output:
679 Example error output:
678
680
679 .. code-block:: bash
681 .. code-block:: bash
680
682
681 id : <id_given_in_input>
683 id : <id_given_in_input>
682 result : null
684 result : null
683 error : {
685 error : {
684 'Error occurred during cache invalidation action'
686 'Error occurred during cache invalidation action'
685 }
687 }
686
688
687
689
688 lock
690 lock
689 ----
691 ----
690
692
691 .. py:function:: lock(apiuser, repoid, locked=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
693 .. py:function:: lock(apiuser, repoid, locked=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
692
694
693 Sets the lock state of the specified |repo| by the given user.
695 Sets the lock state of the specified |repo| by the given user.
694 From more information, see :ref:`repo-locking`.
696 From more information, see :ref:`repo-locking`.
695
697
696 * If the ``userid`` option is not set, the repository is locked to the
698 * If the ``userid`` option is not set, the repository is locked to the
697 user who called the method.
699 user who called the method.
698 * If the ``locked`` parameter is not set, the current lock state of the
700 * If the ``locked`` parameter is not set, the current lock state of the
699 repository is displayed.
701 repository is displayed.
700
702
701 This command can only be run using an |authtoken| with admin rights to
703 This command can only be run using an |authtoken| with admin rights to
702 the specified repository.
704 the specified repository.
703
705
704 This command takes the following options:
706 This command takes the following options:
705
707
706 :param apiuser: This is filled automatically from the |authtoken|.
708 :param apiuser: This is filled automatically from the |authtoken|.
707 :type apiuser: AuthUser
709 :type apiuser: AuthUser
708 :param repoid: Sets the repository name or repository ID.
710 :param repoid: Sets the repository name or repository ID.
709 :type repoid: str or int
711 :type repoid: str or int
710 :param locked: Sets the lock state.
712 :param locked: Sets the lock state.
711 :type locked: Optional(``True`` | ``False``)
713 :type locked: Optional(``True`` | ``False``)
712 :param userid: Set the repository lock to this user.
714 :param userid: Set the repository lock to this user.
713 :type userid: Optional(str or int)
715 :type userid: Optional(str or int)
714
716
715 Example error output:
717 Example error output:
716
718
717 .. code-block:: bash
719 .. code-block:: bash
718
720
719 id : <id_given_in_input>
721 id : <id_given_in_input>
720 result : {
722 result : {
721 'repo': '<reponame>',
723 'repo': '<reponame>',
722 'locked': <bool: lock state>,
724 'locked': <bool: lock state>,
723 'locked_since': <int: lock timestamp>,
725 'locked_since': <int: lock timestamp>,
724 'locked_by': <username of person who made the lock>,
726 'locked_by': <username of person who made the lock>,
725 'lock_reason': <str: reason for locking>,
727 'lock_reason': <str: reason for locking>,
726 'lock_state_changed': <bool: True if lock state has been changed in this request>,
728 'lock_state_changed': <bool: True if lock state has been changed in this request>,
727 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
729 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
728 or
730 or
729 'msg': 'Repo `<repository name>` not locked.'
731 'msg': 'Repo `<repository name>` not locked.'
730 or
732 or
731 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
733 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
732 }
734 }
733 error : null
735 error : null
734
736
735 Example error output:
737 Example error output:
736
738
737 .. code-block:: bash
739 .. code-block:: bash
738
740
739 id : <id_given_in_input>
741 id : <id_given_in_input>
740 result : null
742 result : null
741 error : {
743 error : {
742 'Error occurred locking repository `<reponame>`'
744 'Error occurred locking repository `<reponame>`'
743 }
745 }
744
746
745
747
746 maintenance
748 maintenance
747 -----------
749 -----------
748
750
749 .. py:function:: maintenance(apiuser, repoid)
751 .. py:function:: maintenance(apiuser, repoid)
750
752
751 Triggers a maintenance on the given repository.
753 Triggers a maintenance on the given repository.
752
754
753 This command can only be run using an |authtoken| with admin
755 This command can only be run using an |authtoken| with admin
754 rights to the specified repository. For more information,
756 rights to the specified repository. For more information,
755 see :ref:`config-token-ref`.
757 see :ref:`config-token-ref`.
756
758
757 This command takes the following options:
759 This command takes the following options:
758
760
759 :param apiuser: This is filled automatically from the |authtoken|.
761 :param apiuser: This is filled automatically from the |authtoken|.
760 :type apiuser: AuthUser
762 :type apiuser: AuthUser
761 :param repoid: The repository name or repository ID.
763 :param repoid: The repository name or repository ID.
762 :type repoid: str or int
764 :type repoid: str or int
763
765
764 Example output:
766 Example output:
765
767
766 .. code-block:: bash
768 .. code-block:: bash
767
769
768 id : <id_given_in_input>
770 id : <id_given_in_input>
769 result : {
771 result : {
770 "msg": "executed maintenance command",
772 "msg": "executed maintenance command",
771 "executed_actions": [
773 "executed_actions": [
772 <action_message>, <action_message2>...
774 <action_message>, <action_message2>...
773 ],
775 ],
774 "repository": "<repository name>"
776 "repository": "<repository name>"
775 }
777 }
776 error : null
778 error : null
777
779
778 Example error output:
780 Example error output:
779
781
780 .. code-block:: bash
782 .. code-block:: bash
781
783
782 id : <id_given_in_input>
784 id : <id_given_in_input>
783 result : null
785 result : null
784 error : {
786 error : {
785 "Unable to execute maintenance on `<reponame>`"
787 "Unable to execute maintenance on `<reponame>`"
786 }
788 }
787
789
788
790
789 pull
791 pull
790 ----
792 ----
791
793
792 .. py:function:: pull(apiuser, repoid)
794 .. py:function:: pull(apiuser, repoid, remote_uri=<Optional:None>)
793
795
794 Triggers a pull on the given repository from a remote location. You
796 Triggers a pull on the given repository from a remote location. You
795 can use this to keep remote repositories up-to-date.
797 can use this to keep remote repositories up-to-date.
796
798
797 This command can only be run using an |authtoken| with admin
799 This command can only be run using an |authtoken| with admin
798 rights to the specified repository. For more information,
800 rights to the specified repository. For more information,
799 see :ref:`config-token-ref`.
801 see :ref:`config-token-ref`.
800
802
801 This command takes the following options:
803 This command takes the following options:
802
804
803 :param apiuser: This is filled automatically from the |authtoken|.
805 :param apiuser: This is filled automatically from the |authtoken|.
804 :type apiuser: AuthUser
806 :type apiuser: AuthUser
805 :param repoid: The repository name or repository ID.
807 :param repoid: The repository name or repository ID.
806 :type repoid: str or int
808 :type repoid: str or int
809 :param remote_uri: Optional remote URI to pass in for pull
810 :type remote_uri: str
807
811
808 Example output:
812 Example output:
809
813
810 .. code-block:: bash
814 .. code-block:: bash
811
815
812 id : <id_given_in_input>
816 id : <id_given_in_input>
813 result : {
817 result : {
814 "msg": "Pulled from `<repository name>`"
818 "msg": "Pulled from url `<remote_url>` on repo `<repository name>`"
815 "repository": "<repository name>"
819 "repository": "<repository name>"
816 }
820 }
817 error : null
821 error : null
818
822
819 Example error output:
823 Example error output:
820
824
821 .. code-block:: bash
825 .. code-block:: bash
822
826
823 id : <id_given_in_input>
827 id : <id_given_in_input>
824 result : null
828 result : null
825 error : {
829 error : {
826 "Unable to pull changes from `<reponame>`"
830 "Unable to push changes from `<remote_url>`"
827 }
831 }
828
832
829
833
830 remove_field_from_repo
834 remove_field_from_repo
831 ----------------------
835 ----------------------
832
836
833 .. py:function:: remove_field_from_repo(apiuser, repoid, key)
837 .. py:function:: remove_field_from_repo(apiuser, repoid, key)
834
838
835 Removes an extra field from a repository.
839 Removes an extra field from a repository.
836
840
837 This command can only be run using an |authtoken| with at least
841 This command can only be run using an |authtoken| with at least
838 write permissions to the |repo|.
842 write permissions to the |repo|.
839
843
840 :param apiuser: This is filled automatically from the |authtoken|.
844 :param apiuser: This is filled automatically from the |authtoken|.
841 :type apiuser: AuthUser
845 :type apiuser: AuthUser
842 :param repoid: Set the repository name or repository ID.
846 :param repoid: Set the repository name or repository ID.
843 :type repoid: str or int
847 :type repoid: str or int
844 :param key: Set the unique field key for this repository.
848 :param key: Set the unique field key for this repository.
845 :type key: str
849 :type key: str
846
850
847
851
848 revoke_user_group_permission
852 revoke_user_group_permission
849 ----------------------------
853 ----------------------------
850
854
851 .. py:function:: revoke_user_group_permission(apiuser, repoid, usergroupid)
855 .. py:function:: revoke_user_group_permission(apiuser, repoid, usergroupid)
852
856
853 Revoke the permissions of a user group on a given repository.
857 Revoke the permissions of a user group on a given repository.
854
858
855 This command can only be run using an |authtoken| with admin
859 This command can only be run using an |authtoken| with admin
856 permissions on the |repo|.
860 permissions on the |repo|.
857
861
858 :param apiuser: This is filled automatically from the |authtoken|.
862 :param apiuser: This is filled automatically from the |authtoken|.
859 :type apiuser: AuthUser
863 :type apiuser: AuthUser
860 :param repoid: Set the repository name or repository ID.
864 :param repoid: Set the repository name or repository ID.
861 :type repoid: str or int
865 :type repoid: str or int
862 :param usergroupid: Specify the user group ID.
866 :param usergroupid: Specify the user group ID.
863 :type usergroupid: str or int
867 :type usergroupid: str or int
864
868
865 Example output:
869 Example output:
866
870
867 .. code-block:: bash
871 .. code-block:: bash
868
872
869 id : <id_given_in_input>
873 id : <id_given_in_input>
870 result: {
874 result: {
871 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
875 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
872 "success": true
876 "success": true
873 }
877 }
874 error: null
878 error: null
875
879
876
880
877 revoke_user_permission
881 revoke_user_permission
878 ----------------------
882 ----------------------
879
883
880 .. py:function:: revoke_user_permission(apiuser, repoid, userid)
884 .. py:function:: revoke_user_permission(apiuser, repoid, userid)
881
885
882 Revoke permission for a user on the specified repository.
886 Revoke permission for a user on the specified repository.
883
887
884 This command can only be run using an |authtoken| with admin
888 This command can only be run using an |authtoken| with admin
885 permissions on the |repo|.
889 permissions on the |repo|.
886
890
887 :param apiuser: This is filled automatically from the |authtoken|.
891 :param apiuser: This is filled automatically from the |authtoken|.
888 :type apiuser: AuthUser
892 :type apiuser: AuthUser
889 :param repoid: Set the repository name or repository ID.
893 :param repoid: Set the repository name or repository ID.
890 :type repoid: str or int
894 :type repoid: str or int
891 :param userid: Set the user name of revoked user.
895 :param userid: Set the user name of revoked user.
892 :type userid: str or int
896 :type userid: str or int
893
897
894 Example error output:
898 Example error output:
895
899
896 .. code-block:: bash
900 .. code-block:: bash
897
901
898 id : <id_given_in_input>
902 id : <id_given_in_input>
899 result: {
903 result: {
900 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
904 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
901 "success": true
905 "success": true
902 }
906 }
903 error: null
907 error: null
904
908
905
909
906 set_repo_settings
910 set_repo_settings
907 -----------------
911 -----------------
908
912
909 .. py:function:: set_repo_settings(apiuser, repoid, settings)
913 .. py:function:: set_repo_settings(apiuser, repoid, settings)
910
914
911 Update repository settings. Returns true on success.
915 Update repository settings. Returns true on success.
912
916
913 :param apiuser: This is filled automatically from the |authtoken|.
917 :param apiuser: This is filled automatically from the |authtoken|.
914 :type apiuser: AuthUser
918 :type apiuser: AuthUser
915 :param repoid: The repository name or repository id.
919 :param repoid: The repository name or repository id.
916 :type repoid: str or int
920 :type repoid: str or int
917 :param settings: The new settings for the repository.
921 :param settings: The new settings for the repository.
918 :type: settings: dict
922 :type: settings: dict
919
923
920 Example output:
924 Example output:
921
925
922 .. code-block:: bash
926 .. code-block:: bash
923
927
924 {
928 {
925 "error": null,
929 "error": null,
926 "id": 237,
930 "id": 237,
927 "result": true
931 "result": true
928 }
932 }
929
933
930
934
931 strip
935 strip
932 -----
936 -----
933
937
934 .. py:function:: strip(apiuser, repoid, revision, branch)
938 .. py:function:: strip(apiuser, repoid, revision, branch)
935
939
936 Strips the given revision from the specified repository.
940 Strips the given revision from the specified repository.
937
941
938 * This will remove the revision and all of its decendants.
942 * This will remove the revision and all of its decendants.
939
943
940 This command can only be run using an |authtoken| with admin rights to
944 This command can only be run using an |authtoken| with admin rights to
941 the specified repository.
945 the specified repository.
942
946
943 This command takes the following options:
947 This command takes the following options:
944
948
945 :param apiuser: This is filled automatically from the |authtoken|.
949 :param apiuser: This is filled automatically from the |authtoken|.
946 :type apiuser: AuthUser
950 :type apiuser: AuthUser
947 :param repoid: The repository name or repository ID.
951 :param repoid: The repository name or repository ID.
948 :type repoid: str or int
952 :type repoid: str or int
949 :param revision: The revision you wish to strip.
953 :param revision: The revision you wish to strip.
950 :type revision: str
954 :type revision: str
951 :param branch: The branch from which to strip the revision.
955 :param branch: The branch from which to strip the revision.
952 :type branch: str
956 :type branch: str
953
957
954 Example output:
958 Example output:
955
959
956 .. code-block:: bash
960 .. code-block:: bash
957
961
958 id : <id_given_in_input>
962 id : <id_given_in_input>
959 result : {
963 result : {
960 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
964 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
961 "repository": "<repository name>"
965 "repository": "<repository name>"
962 }
966 }
963 error : null
967 error : null
964
968
965 Example error output:
969 Example error output:
966
970
967 .. code-block:: bash
971 .. code-block:: bash
968
972
969 id : <id_given_in_input>
973 id : <id_given_in_input>
970 result : null
974 result : null
971 error : {
975 error : {
972 "Unable to strip commit <commit_hash> from repo `<repository name>`"
976 "Unable to strip commit <commit_hash> from repo `<repository name>`"
973 }
977 }
974
978
975
979
976 update_repo
980 update_repo
977 -----------
981 -----------
978
982
979 .. py:function:: update_repo(apiuser, repoid, repo_name=<Optional:None>, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, fork_of=<Optional:None>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, fields=<Optional:''>)
983 .. py:function:: update_repo(apiuser, repoid, repo_name=<Optional:None>, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, push_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, fork_of=<Optional:None>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, fields=<Optional:''>)
980
984
981 Updates a repository with the given information.
985 Updates a repository with the given information.
982
986
983 This command can only be run using an |authtoken| with at least
987 This command can only be run using an |authtoken| with at least
984 admin permissions to the |repo|.
988 admin permissions to the |repo|.
985
989
986 * If the repository name contains "/", repository will be updated
990 * If the repository name contains "/", repository will be updated
987 accordingly with a repository group or nested repository groups
991 accordingly with a repository group or nested repository groups
988
992
989 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
993 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
990 called "repo-test" and place it inside group "foo/bar".
994 called "repo-test" and place it inside group "foo/bar".
991 You have to have permissions to access and write to the last repository
995 You have to have permissions to access and write to the last repository
992 group ("bar" in this example)
996 group ("bar" in this example)
993
997
994 :param apiuser: This is filled automatically from the |authtoken|.
998 :param apiuser: This is filled automatically from the |authtoken|.
995 :type apiuser: AuthUser
999 :type apiuser: AuthUser
996 :param repoid: repository name or repository ID.
1000 :param repoid: repository name or repository ID.
997 :type repoid: str or int
1001 :type repoid: str or int
998 :param repo_name: Update the |repo| name, including the
1002 :param repo_name: Update the |repo| name, including the
999 repository group it's in.
1003 repository group it's in.
1000 :type repo_name: str
1004 :type repo_name: str
1001 :param owner: Set the |repo| owner.
1005 :param owner: Set the |repo| owner.
1002 :type owner: str
1006 :type owner: str
1003 :param fork_of: Set the |repo| as fork of another |repo|.
1007 :param fork_of: Set the |repo| as fork of another |repo|.
1004 :type fork_of: str
1008 :type fork_of: str
1005 :param description: Update the |repo| description.
1009 :param description: Update the |repo| description.
1006 :type description: str
1010 :type description: str
1007 :param private: Set the |repo| as private. (True | False)
1011 :param private: Set the |repo| as private. (True | False)
1008 :type private: bool
1012 :type private: bool
1009 :param clone_uri: Update the |repo| clone URI.
1013 :param clone_uri: Update the |repo| clone URI.
1010 :type clone_uri: str
1014 :type clone_uri: str
1011 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
1015 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
1012 :type landing_rev: str
1016 :type landing_rev: str
1013 :param enable_statistics: Enable statistics on the |repo|, (True | False).
1017 :param enable_statistics: Enable statistics on the |repo|, (True | False).
1014 :type enable_statistics: bool
1018 :type enable_statistics: bool
1015 :param enable_locking: Enable |repo| locking.
1019 :param enable_locking: Enable |repo| locking.
1016 :type enable_locking: bool
1020 :type enable_locking: bool
1017 :param enable_downloads: Enable downloads from the |repo|, (True | False).
1021 :param enable_downloads: Enable downloads from the |repo|, (True | False).
1018 :type enable_downloads: bool
1022 :type enable_downloads: bool
1019 :param fields: Add extra fields to the |repo|. Use the following
1023 :param fields: Add extra fields to the |repo|. Use the following
1020 example format: ``field_key=field_val,field_key2=fieldval2``.
1024 example format: ``field_key=field_val,field_key2=fieldval2``.
1021 Escape ', ' with \,
1025 Escape ', ' with \,
1022 :type fields: str
1026 :type fields: str
1023
1027
1024
1028
@@ -1,412 +1,418 b''
1 .. _user-group-methods-ref:
1 .. _user-group-methods-ref:
2
2
3 user_group methods
3 user_group methods
4 ==================
4 ==================
5
5
6 add_user_to_user_group
6 add_user_to_user_group
7 ----------------------
7 ----------------------
8
8
9 .. py:function:: add_user_to_user_group(apiuser, usergroupid, userid)
9 .. py:function:: add_user_to_user_group(apiuser, usergroupid, userid)
10
10
11 Adds a user to a `user group`. If the user already exists in the group
11 Adds a user to a `user group`. If the user already exists in the group
12 this command will return false.
12 this command will return false.
13
13
14 This command can only be run using an |authtoken| with admin rights to
14 This command can only be run using an |authtoken| with admin rights to
15 the specified user group.
15 the specified user group.
16
16
17 This command takes the following options:
17 This command takes the following options:
18
18
19 :param apiuser: This is filled automatically from the |authtoken|.
19 :param apiuser: This is filled automatically from the |authtoken|.
20 :type apiuser: AuthUser
20 :type apiuser: AuthUser
21 :param usergroupid: Set the name of the `user group` to which a
21 :param usergroupid: Set the name of the `user group` to which a
22 user will be added.
22 user will be added.
23 :type usergroupid: int
23 :type usergroupid: int
24 :param userid: Set the `user_id` of the user to add to the group.
24 :param userid: Set the `user_id` of the user to add to the group.
25 :type userid: int
25 :type userid: int
26
26
27 Example output:
27 Example output:
28
28
29 .. code-block:: bash
29 .. code-block:: bash
30
30
31 id : <id_given_in_input>
31 id : <id_given_in_input>
32 result : {
32 result : {
33 "success": True|False # depends on if member is in group
33 "success": True|False # depends on if member is in group
34 "msg": "added member `<username>` to user group `<groupname>` |
34 "msg": "added member `<username>` to user group `<groupname>` |
35 User is already in that group"
35 User is already in that group"
36
36
37 }
37 }
38 error : null
38 error : null
39
39
40 Example error output:
40 Example error output:
41
41
42 .. code-block:: bash
42 .. code-block:: bash
43
43
44 id : <id_given_in_input>
44 id : <id_given_in_input>
45 result : null
45 result : null
46 error : {
46 error : {
47 "failed to add member to user group `<user_group_name>`"
47 "failed to add member to user group `<user_group_name>`"
48 }
48 }
49
49
50
50
51 create_user_group
51 create_user_group
52 -----------------
52 -----------------
53
53
54 .. py:function:: create_user_group(apiuser, group_name, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, active=<Optional:True>)
54 .. py:function:: create_user_group(apiuser, group_name, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, active=<Optional:True>, sync=<Optional:None>)
55
55
56 Creates a new user group.
56 Creates a new user group.
57
57
58 This command can only be run using an |authtoken| with admin rights to
58 This command can only be run using an |authtoken| with admin rights to
59 the specified repository.
59 the specified repository.
60
60
61 This command takes the following options:
61 This command takes the following options:
62
62
63 :param apiuser: This is filled automatically from the |authtoken|.
63 :param apiuser: This is filled automatically from the |authtoken|.
64 :type apiuser: AuthUser
64 :type apiuser: AuthUser
65 :param group_name: Set the name of the new user group.
65 :param group_name: Set the name of the new user group.
66 :type group_name: str
66 :type group_name: str
67 :param description: Give a description of the new user group.
67 :param description: Give a description of the new user group.
68 :type description: str
68 :type description: str
69 :param owner: Set the owner of the new user group.
69 :param owner: Set the owner of the new user group.
70 If not set, the owner is the |authtoken| user.
70 If not set, the owner is the |authtoken| user.
71 :type owner: Optional(str or int)
71 :type owner: Optional(str or int)
72 :param active: Set this group as active.
72 :param active: Set this group as active.
73 :type active: Optional(``True`` | ``False``)
73 :type active: Optional(``True`` | ``False``)
74 :param sync: Set enabled or disabled the automatically sync from
75 external authentication types like ldap.
76 :type sync: Optional(``True`` | ``False``)
74
77
75 Example output:
78 Example output:
76
79
77 .. code-block:: bash
80 .. code-block:: bash
78
81
79 id : <id_given_in_input>
82 id : <id_given_in_input>
80 result: {
83 result: {
81 "msg": "created new user group `<groupname>`",
84 "msg": "created new user group `<groupname>`",
82 "user_group": <user_group_object>
85 "user_group": <user_group_object>
83 }
86 }
84 error: null
87 error: null
85
88
86 Example error output:
89 Example error output:
87
90
88 .. code-block:: bash
91 .. code-block:: bash
89
92
90 id : <id_given_in_input>
93 id : <id_given_in_input>
91 result : null
94 result : null
92 error : {
95 error : {
93 "user group `<group name>` already exist"
96 "user group `<group name>` already exist"
94 or
97 or
95 "failed to create group `<group name>`"
98 "failed to create group `<group name>`"
96 }
99 }
97
100
98
101
99 delete_user_group
102 delete_user_group
100 -----------------
103 -----------------
101
104
102 .. py:function:: delete_user_group(apiuser, usergroupid)
105 .. py:function:: delete_user_group(apiuser, usergroupid)
103
106
104 Deletes the specified `user group`.
107 Deletes the specified `user group`.
105
108
106 This command can only be run using an |authtoken| with admin rights to
109 This command can only be run using an |authtoken| with admin rights to
107 the specified repository.
110 the specified repository.
108
111
109 This command takes the following options:
112 This command takes the following options:
110
113
111 :param apiuser: filled automatically from apikey
114 :param apiuser: filled automatically from apikey
112 :type apiuser: AuthUser
115 :type apiuser: AuthUser
113 :param usergroupid:
116 :param usergroupid:
114 :type usergroupid: int
117 :type usergroupid: int
115
118
116 Example output:
119 Example output:
117
120
118 .. code-block:: bash
121 .. code-block:: bash
119
122
120 id : <id_given_in_input>
123 id : <id_given_in_input>
121 result : {
124 result : {
122 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
125 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
123 }
126 }
124 error : null
127 error : null
125
128
126 Example error output:
129 Example error output:
127
130
128 .. code-block:: bash
131 .. code-block:: bash
129
132
130 id : <id_given_in_input>
133 id : <id_given_in_input>
131 result : null
134 result : null
132 error : {
135 error : {
133 "failed to delete user group ID:<user_group_id> <user_group_name>"
136 "failed to delete user group ID:<user_group_id> <user_group_name>"
134 or
137 or
135 "RepoGroup assigned to <repo_groups_list>"
138 "RepoGroup assigned to <repo_groups_list>"
136 }
139 }
137
140
138
141
139 get_user_group
142 get_user_group
140 --------------
143 --------------
141
144
142 .. py:function:: get_user_group(apiuser, usergroupid)
145 .. py:function:: get_user_group(apiuser, usergroupid)
143
146
144 Returns the data of an existing user group.
147 Returns the data of an existing user group.
145
148
146 This command can only be run using an |authtoken| with admin rights to
149 This command can only be run using an |authtoken| with admin rights to
147 the specified repository.
150 the specified repository.
148
151
149 :param apiuser: This is filled automatically from the |authtoken|.
152 :param apiuser: This is filled automatically from the |authtoken|.
150 :type apiuser: AuthUser
153 :type apiuser: AuthUser
151 :param usergroupid: Set the user group from which to return data.
154 :param usergroupid: Set the user group from which to return data.
152 :type usergroupid: str or int
155 :type usergroupid: str or int
153
156
154 Example error output:
157 Example error output:
155
158
156 .. code-block:: bash
159 .. code-block:: bash
157
160
158 {
161 {
159 "error": null,
162 "error": null,
160 "id": <id>,
163 "id": <id>,
161 "result": {
164 "result": {
162 "active": true,
165 "active": true,
163 "group_description": "group description",
166 "group_description": "group description",
164 "group_name": "group name",
167 "group_name": "group name",
165 "permissions": [
168 "permissions": [
166 {
169 {
167 "name": "owner-name",
170 "name": "owner-name",
168 "origin": "owner",
171 "origin": "owner",
169 "permission": "usergroup.admin",
172 "permission": "usergroup.admin",
170 "type": "user"
173 "type": "user"
171 },
174 },
172 {
175 {
173 {
176 {
174 "name": "user name",
177 "name": "user name",
175 "origin": "permission",
178 "origin": "permission",
176 "permission": "usergroup.admin",
179 "permission": "usergroup.admin",
177 "type": "user"
180 "type": "user"
178 },
181 },
179 {
182 {
180 "name": "user group name",
183 "name": "user group name",
181 "origin": "permission",
184 "origin": "permission",
182 "permission": "usergroup.write",
185 "permission": "usergroup.write",
183 "type": "user_group"
186 "type": "user_group"
184 }
187 }
185 ],
188 ],
186 "permissions_summary": {
189 "permissions_summary": {
187 "repositories": {
190 "repositories": {
188 "aa-root-level-repo-1": "repository.admin"
191 "aa-root-level-repo-1": "repository.admin"
189 },
192 },
190 "repositories_groups": {}
193 "repositories_groups": {}
191 },
194 },
192 "owner": "owner name",
195 "owner": "owner name",
193 "users": [],
196 "users": [],
194 "users_group_id": 2
197 "users_group_id": 2
195 }
198 }
196 }
199 }
197
200
198
201
199 get_user_groups
202 get_user_groups
200 ---------------
203 ---------------
201
204
202 .. py:function:: get_user_groups(apiuser)
205 .. py:function:: get_user_groups(apiuser)
203
206
204 Lists all the existing user groups within RhodeCode.
207 Lists all the existing user groups within RhodeCode.
205
208
206 This command can only be run using an |authtoken| with admin rights to
209 This command can only be run using an |authtoken| with admin rights to
207 the specified repository.
210 the specified repository.
208
211
209 This command takes the following options:
212 This command takes the following options:
210
213
211 :param apiuser: This is filled automatically from the |authtoken|.
214 :param apiuser: This is filled automatically from the |authtoken|.
212 :type apiuser: AuthUser
215 :type apiuser: AuthUser
213
216
214 Example error output:
217 Example error output:
215
218
216 .. code-block:: bash
219 .. code-block:: bash
217
220
218 id : <id_given_in_input>
221 id : <id_given_in_input>
219 result : [<user_group_obj>,...]
222 result : [<user_group_obj>,...]
220 error : null
223 error : null
221
224
222
225
223 grant_user_group_permission_to_user_group
226 grant_user_group_permission_to_user_group
224 -----------------------------------------
227 -----------------------------------------
225
228
226 .. py:function:: grant_user_group_permission_to_user_group(apiuser, usergroupid, sourceusergroupid, perm)
229 .. py:function:: grant_user_group_permission_to_user_group(apiuser, usergroupid, sourceusergroupid, perm)
227
230
228 Give one user group permissions to another user group.
231 Give one user group permissions to another user group.
229
232
230 :param apiuser: This is filled automatically from the |authtoken|.
233 :param apiuser: This is filled automatically from the |authtoken|.
231 :type apiuser: AuthUser
234 :type apiuser: AuthUser
232 :param usergroupid: Set the user group on which to edit permissions.
235 :param usergroupid: Set the user group on which to edit permissions.
233 :type usergroupid: str or int
236 :type usergroupid: str or int
234 :param sourceusergroupid: Set the source user group to which
237 :param sourceusergroupid: Set the source user group to which
235 access/permissions will be granted.
238 access/permissions will be granted.
236 :type sourceusergroupid: str or int
239 :type sourceusergroupid: str or int
237 :param perm: (usergroup.(none|read|write|admin))
240 :param perm: (usergroup.(none|read|write|admin))
238 :type perm: str
241 :type perm: str
239
242
240 Example output:
243 Example output:
241
244
242 .. code-block:: bash
245 .. code-block:: bash
243
246
244 id : <id_given_in_input>
247 id : <id_given_in_input>
245 result : {
248 result : {
246 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
249 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
247 "success": true
250 "success": true
248 }
251 }
249 error : null
252 error : null
250
253
251
254
252 grant_user_permission_to_user_group
255 grant_user_permission_to_user_group
253 -----------------------------------
256 -----------------------------------
254
257
255 .. py:function:: grant_user_permission_to_user_group(apiuser, usergroupid, userid, perm)
258 .. py:function:: grant_user_permission_to_user_group(apiuser, usergroupid, userid, perm)
256
259
257 Set permissions for a user in a user group.
260 Set permissions for a user in a user group.
258
261
259 :param apiuser: This is filled automatically from the |authtoken|.
262 :param apiuser: This is filled automatically from the |authtoken|.
260 :type apiuser: AuthUser
263 :type apiuser: AuthUser
261 :param usergroupid: Set the user group to edit permissions on.
264 :param usergroupid: Set the user group to edit permissions on.
262 :type usergroupid: str or int
265 :type usergroupid: str or int
263 :param userid: Set the user from whom you wish to set permissions.
266 :param userid: Set the user from whom you wish to set permissions.
264 :type userid: str
267 :type userid: str
265 :param perm: (usergroup.(none|read|write|admin))
268 :param perm: (usergroup.(none|read|write|admin))
266 :type perm: str
269 :type perm: str
267
270
268 Example output:
271 Example output:
269
272
270 .. code-block:: bash
273 .. code-block:: bash
271
274
272 id : <id_given_in_input>
275 id : <id_given_in_input>
273 result : {
276 result : {
274 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
277 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
275 "success": true
278 "success": true
276 }
279 }
277 error : null
280 error : null
278
281
279
282
280 remove_user_from_user_group
283 remove_user_from_user_group
281 ---------------------------
284 ---------------------------
282
285
283 .. py:function:: remove_user_from_user_group(apiuser, usergroupid, userid)
286 .. py:function:: remove_user_from_user_group(apiuser, usergroupid, userid)
284
287
285 Removes a user from a user group.
288 Removes a user from a user group.
286
289
287 * If the specified user is not in the group, this command will return
290 * If the specified user is not in the group, this command will return
288 `false`.
291 `false`.
289
292
290 This command can only be run using an |authtoken| with admin rights to
293 This command can only be run using an |authtoken| with admin rights to
291 the specified user group.
294 the specified user group.
292
295
293 :param apiuser: This is filled automatically from the |authtoken|.
296 :param apiuser: This is filled automatically from the |authtoken|.
294 :type apiuser: AuthUser
297 :type apiuser: AuthUser
295 :param usergroupid: Sets the user group name.
298 :param usergroupid: Sets the user group name.
296 :type usergroupid: str or int
299 :type usergroupid: str or int
297 :param userid: The user you wish to remove from |RCE|.
300 :param userid: The user you wish to remove from |RCE|.
298 :type userid: str or int
301 :type userid: str or int
299
302
300 Example output:
303 Example output:
301
304
302 .. code-block:: bash
305 .. code-block:: bash
303
306
304 id : <id_given_in_input>
307 id : <id_given_in_input>
305 result: {
308 result: {
306 "success": True|False, # depends on if member is in group
309 "success": True|False, # depends on if member is in group
307 "msg": "removed member <username> from user group <groupname> |
310 "msg": "removed member <username> from user group <groupname> |
308 User wasn't in group"
311 User wasn't in group"
309 }
312 }
310 error: null
313 error: null
311
314
312
315
313 revoke_user_group_permission_from_user_group
316 revoke_user_group_permission_from_user_group
314 --------------------------------------------
317 --------------------------------------------
315
318
316 .. py:function:: revoke_user_group_permission_from_user_group(apiuser, usergroupid, sourceusergroupid)
319 .. py:function:: revoke_user_group_permission_from_user_group(apiuser, usergroupid, sourceusergroupid)
317
320
318 Revoke the permissions that one user group has to another.
321 Revoke the permissions that one user group has to another.
319
322
320 :param apiuser: This is filled automatically from the |authtoken|.
323 :param apiuser: This is filled automatically from the |authtoken|.
321 :type apiuser: AuthUser
324 :type apiuser: AuthUser
322 :param usergroupid: Set the user group on which to edit permissions.
325 :param usergroupid: Set the user group on which to edit permissions.
323 :type usergroupid: str or int
326 :type usergroupid: str or int
324 :param sourceusergroupid: Set the user group from which permissions
327 :param sourceusergroupid: Set the user group from which permissions
325 are revoked.
328 are revoked.
326 :type sourceusergroupid: str or int
329 :type sourceusergroupid: str or int
327
330
328 Example output:
331 Example output:
329
332
330 .. code-block:: bash
333 .. code-block:: bash
331
334
332 id : <id_given_in_input>
335 id : <id_given_in_input>
333 result : {
336 result : {
334 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
337 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
335 "success": true
338 "success": true
336 }
339 }
337 error : null
340 error : null
338
341
339
342
340 revoke_user_permission_from_user_group
343 revoke_user_permission_from_user_group
341 --------------------------------------
344 --------------------------------------
342
345
343 .. py:function:: revoke_user_permission_from_user_group(apiuser, usergroupid, userid)
346 .. py:function:: revoke_user_permission_from_user_group(apiuser, usergroupid, userid)
344
347
345 Revoke a users permissions in a user group.
348 Revoke a users permissions in a user group.
346
349
347 :param apiuser: This is filled automatically from the |authtoken|.
350 :param apiuser: This is filled automatically from the |authtoken|.
348 :type apiuser: AuthUser
351 :type apiuser: AuthUser
349 :param usergroupid: Set the user group from which to revoke the user
352 :param usergroupid: Set the user group from which to revoke the user
350 permissions.
353 permissions.
351 :type: usergroupid: str or int
354 :type: usergroupid: str or int
352 :param userid: Set the userid of the user whose permissions will be
355 :param userid: Set the userid of the user whose permissions will be
353 revoked.
356 revoked.
354 :type userid: str
357 :type userid: str
355
358
356 Example output:
359 Example output:
357
360
358 .. code-block:: bash
361 .. code-block:: bash
359
362
360 id : <id_given_in_input>
363 id : <id_given_in_input>
361 result : {
364 result : {
362 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
365 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
363 "success": true
366 "success": true
364 }
367 }
365 error : null
368 error : null
366
369
367
370
368 update_user_group
371 update_user_group
369 -----------------
372 -----------------
370
373
371 .. py:function:: update_user_group(apiuser, usergroupid, group_name=<Optional:''>, description=<Optional:''>, owner=<Optional:None>, active=<Optional:True>)
374 .. py:function:: update_user_group(apiuser, usergroupid, group_name=<Optional:''>, description=<Optional:''>, owner=<Optional:None>, active=<Optional:True>, sync=<Optional:None>)
372
375
373 Updates the specified `user group` with the details provided.
376 Updates the specified `user group` with the details provided.
374
377
375 This command can only be run using an |authtoken| with admin rights to
378 This command can only be run using an |authtoken| with admin rights to
376 the specified repository.
379 the specified repository.
377
380
378 :param apiuser: This is filled automatically from the |authtoken|.
381 :param apiuser: This is filled automatically from the |authtoken|.
379 :type apiuser: AuthUser
382 :type apiuser: AuthUser
380 :param usergroupid: Set the id of the `user group` to update.
383 :param usergroupid: Set the id of the `user group` to update.
381 :type usergroupid: str or int
384 :type usergroupid: str or int
382 :param group_name: Set the new name the `user group`
385 :param group_name: Set the new name the `user group`
383 :type group_name: str
386 :type group_name: str
384 :param description: Give a description for the `user group`
387 :param description: Give a description for the `user group`
385 :type description: str
388 :type description: str
386 :param owner: Set the owner of the `user group`.
389 :param owner: Set the owner of the `user group`.
387 :type owner: Optional(str or int)
390 :type owner: Optional(str or int)
388 :param active: Set the group as active.
391 :param active: Set the group as active.
389 :type active: Optional(``True`` | ``False``)
392 :type active: Optional(``True`` | ``False``)
393 :param sync: Set enabled or disabled the automatically sync from
394 external authentication types like ldap.
395 :type sync: Optional(``True`` | ``False``)
390
396
391 Example output:
397 Example output:
392
398
393 .. code-block:: bash
399 .. code-block:: bash
394
400
395 id : <id_given_in_input>
401 id : <id_given_in_input>
396 result : {
402 result : {
397 "msg": 'updated user group ID:<user group id> <user group name>',
403 "msg": 'updated user group ID:<user group id> <user group name>',
398 "user_group": <user_group_object>
404 "user_group": <user_group_object>
399 }
405 }
400 error : null
406 error : null
401
407
402 Example error output:
408 Example error output:
403
409
404 .. code-block:: bash
410 .. code-block:: bash
405
411
406 id : <id_given_in_input>
412 id : <id_given_in_input>
407 result : null
413 result : null
408 error : {
414 error : {
409 "failed to update user group `<user group name>`"
415 "failed to update user group `<user group name>`"
410 }
416 }
411
417
412
418
1 NO CONTENT: file renamed from docs/auth/crowd-auth.rst to docs/auth/auth-crowd.rst
NO CONTENT: file renamed from docs/auth/crowd-auth.rst to docs/auth/auth-crowd.rst
@@ -1,90 +1,89 b''
1 .. _config-ldap-ref:
1 .. _config-ldap-ref:
2
2
3 LDAP
3 LDAP/AD
4 ----
4 -------
5
5
6 |RCM| supports LDAP (Lightweight Directory Access Protocol) or
6 |RCM| supports LDAP (Lightweight Directory Access Protocol) or
7 AD (active Directory) authentication.
7 AD (active Directory) authentication.
8 All LDAP versions are supported, with the following |RCM| plugins managing each:
8 All LDAP versions are supported, with the following |RCM| plugins managing each:
9
9
10 * For LDAPv3 use ``LDAP (egg:rhodecode-enterprise-ce#ldap)``
10 * For LDAP or Active Directory use ``LDAP (egg:rhodecode-enterprise-ce#ldap)``
11 * For LDAPv3 with user group sync use ``LDAP + User Groups (egg:rhodecode-enterprise-ee#ldap_group)``
11
12 RhodeCode reads all data defined from plugin and creates corresponding
13 accounts on local database after receiving data from LDAP. This is done on
14 every user log-in including operations like pushing/pulling/checkout.
12
15
13
16
14 .. important::
17 .. important::
15
18
16 The email used with your |RCE| super-admin account needs to match the email
19 The email used with your |RCE| super-admin account needs to match the email
17 address attached to your admin profile in LDAP. This is because
20 address attached to your admin profile in LDAP. This is because
18 within |RCE| the user email needs to be unique, and multiple users
21 within |RCE| the user email needs to be unique, and multiple users
19 cannot share an email account.
22 cannot share an email account.
20
23
21 Likewise, if as an admin you also have a user account, the email address
24 Likewise, if as an admin you also have a user account, the email address
22 attached to the user account needs to be different.
25 attached to the user account needs to be different.
23
26
27
24 LDAP Configuration Steps
28 LDAP Configuration Steps
25 ^^^^^^^^^^^^^^^^^^^^^^^^
29 ^^^^^^^^^^^^^^^^^^^^^^^^
26
30
27 To configure |LDAP|, use the following steps:
31 To configure |LDAP|, use the following steps:
28
32
29 1. From the |RCM| interface, select
33 1. From the |RCM| interface, select
30 :menuselection:`Admin --> Authentication`
34 :menuselection:`Admin --> Authentication`
31 2. Enable the required plugin and select :guilabel:`Save`
35 2. Enable the ldap plugin and select :guilabel:`Save`
32 3. Select the :guilabel:`Enabled` check box in the plugin configuration section
36 3. Select the :guilabel:`Enabled` check box in the plugin configuration section
33 4. Add the required LDAP information and :guilabel:`Save`, for more details,
37 4. Add the required LDAP information and :guilabel:`Save`, for more details,
34 see :ref:`config-ldap-examples`
38 see :ref:`config-ldap-examples`
35
39
36 For a more detailed description of LDAP objects, see :ref:`ldap-gloss-ref`:
40 For a more detailed description of LDAP objects, see :ref:`ldap-gloss-ref`:
37
41
38 .. _config-ldap-examples:
42 .. _config-ldap-examples:
39
43
40 Example LDAP configuration
44 Example LDAP configuration
41 ^^^^^^^^^^^^^^^^^^^^^^^^^^
45 ^^^^^^^^^^^^^^^^^^^^^^^^^^
42 .. code-block:: bash
46 .. code-block:: bash
43
47
44 # Auth Cache TTL
48 # Auth Cache TTL, Defines the caching for authentication to offload LDAP server.
49 # This means that cache result will be saved for 3600 before contacting LDAP server to verify the user access
45 3600
50 3600
46 # Host
51 # Host, comma seperated format is optionally possible to specify more than 1 server
47 https://ldap1.server.com/ldap-admin/,https://ldap2.server.com/ldap-admin/
52 https://ldap1.server.com/ldap-admin/,https://ldap2.server.com/ldap-admin/
48 # Port
53 # Default LDAP Port, use 689 for LDAPS
49 389
54 389
50 # Account
55 # Account, used for SimpleBind if LDAP server requires an authentication
51 cn=admin,dc=rhodecode,dc=com
56 e.g admin@server.com
52 # Password
57 # Password used for simple bind
53 ldap-user-password
58 ldap-user-password
54 # LDAP connection security
59 # LDAP connection security
55 LDAPS
60 LDAPS
56 # Certificate checks level
61 # Certificate checks level
57 DEMAND
62 DEMAND
58 # Base DN
63 # Base DN
59 cn=Rufus Magillacuddy,ou=users,dc=rhodecode,dc=com
64 cn=Rufus Magillacuddy,ou=users,dc=rhodecode,dc=com
60 # User Search Base
65 # LDAP search filter to narrow the results
61 ou=groups,ou=users
62 # LDAP search filter
63 (objectClass=person)
66 (objectClass=person)
64 # LDAP search scope
67 # LDAP search scope
65 SUBTREE
68 SUBTREE
66 # Login attribute
69 # Login attribute
67 rmagillacuddy
70 sAMAccountName
68 # First Name Attribute
71 # First Name Attribute to read
69 Rufus
72 givenName
70 # Last Name Attribute
73 # Last Name Attribute to read
71 Magillacuddy
74 sn
72 # Email Attribute
75 # Email Attribute to read email address from
73 LDAP-Registered@email.ac
76 mail
74 # User Member of Attribute
77
75 Organizational Role
78
76 # Group search base
79 Below is example setup that can be used with Active Directory/LDAP server.
77 cn=users,ou=groups,dc=rhodecode,dc=com
80
78 # LDAP Group Search Filter
81 .. image:: ../images/ldap-example.png
79 (objectclass=posixGroup)
82 :alt: LDAP/AD setup example
80 # Group Name Attribute
83 :scale: 50 %
81 users
84
82 # Group Member Of Attribute
83 cn
84 # Admin Groups
85 admin,devops,qa
86
85
87 .. toctree::
86 .. toctree::
88
87
89 ldap-active-directory
88 ldap-active-directory
90 ldap-authentication
89 ldap-authentication
1 NO CONTENT: file renamed from docs/auth/pam-auth.rst to docs/auth/auth-pam.rst
NO CONTENT: file renamed from docs/auth/pam-auth.rst to docs/auth/auth-pam.rst
1 NO CONTENT: file renamed from docs/auth/token-auth.rst to docs/auth/auth-token.rst
NO CONTENT: file renamed from docs/auth/token-auth.rst to docs/auth/auth-token.rst
@@ -1,37 +1,32 b''
1 .. _authentication-ref:
1 .. _authentication-ref:
2
2
3 Authentication Options
3 Authentication Options
4 ======================
4 ======================
5
5
6 |RCE| provides a built in authentication plugin
6 |RCE| provides a built in authentication against its own database. This is
7 ``rhodecode.lib.auth_rhodecode``. This is enabled by default and accessed
7 implemented using ``rhodecode.lib.auth_rhodecode`` plugin. This plugin is
8 through the administrative interface. Additionally,
8 enabled by default.
9 |RCE| provides a Pluggable Authentication System (PAS). This gives the
9 Additionally, |RCE| provides a Pluggable Authentication System. This gives the
10 administrator greater control over how users authenticate with the system.
10 administrator greater control over how users authenticate with the system.
11
11
12 .. important::
12 .. important::
13
13
14 You can disable the built in |RCM| authentication plugin
14 You can disable the built in |RCM| authentication plugin
15 ``rhodecode.lib.auth_rhodecode`` and force all authentication to go
15 ``rhodecode.lib.auth_rhodecode`` and force all authentication to go
16 through your authentication plugin. However, if you do this,
16 through your authentication plugin of choice e.g LDAP only.
17 and your external authentication tools fails, you will be unable to
17 However, if you do this, and your external authentication tools fails,
18 access |RCM|.
18 you will be unable to access |RCM|.
19
19
20 |RCM| comes with the following user authentication management plugins:
20 |RCM| comes with the following user authentication management plugins:
21
21
22 .. only:: latex
23
24 * :ref:`config-ldap-ref`
25 * :ref:`config-pam-ref`
26 * :ref:`config-crowd-ref`
27 * :ref:`config-token-ref`
28
22
29 .. toctree::
23 .. toctree::
30
24
31 ldap-config-steps
25 auth-ldap
32 crowd-auth
26 auth-ldap-groups
33 pam-auth
27 auth-crowd
34 token-auth
28 auth-pam
29 auth-token
35 ssh-connection
30 ssh-connection
36
31
37
32
@@ -1,317 +1,316 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 #
2 #
3 # RhodeCode Enterprise documentation build configuration file, created by
3 # RhodeCode Enterprise documentation build configuration file, created by
4 # sphinx-quickstart on Tue Nov 4 11:48:37 2014.
4 # sphinx-quickstart on Tue Nov 4 11:48:37 2014.
5 #
5 #
6 # This file is execfile()d with the current directory set to its
6 # This file is execfile()d with the current directory set to its
7 # containing dir.
7 # containing dir.
8 #
8 #
9 # Note that not all possible configuration values are present in this
9 # Note that not all possible configuration values are present in this
10 # autogenerated file.
10 # autogenerated file.
11 #
11 #
12 # All configuration values have a default; values that are commented out
12 # All configuration values have a default; values that are commented out
13 # serve to show the default.
13 # serve to show the default.
14
14
15 import sys
15 import sys
16 import os
16 import os
17 import datetime
17 import datetime
18 import sphinx_rtd_theme
18 import sphinx_rtd_theme
19
19
20 # If extensions (or modules to document with autodoc) are in another directory,
20 # If extensions (or modules to document with autodoc) are in another directory,
21 # add these directories to sys.path here. If the directory is relative to the
21 # add these directories to sys.path here. If the directory is relative to the
22 # documentation root, use os.path.abspath to make it absolute, like shown here.
22 # documentation root, use os.path.abspath to make it absolute, like shown here.
23 sys.path.insert(0, os.path.abspath('.'))
23 sys.path.insert(0, os.path.abspath('.'))
24 import common
24 import common
25
25
26 # -- General configuration ------------------------------------------------
26 # -- General configuration ------------------------------------------------
27
27
28 # If your documentation needs a minimal Sphinx version, state it here.
28 # If your documentation needs a minimal Sphinx version, state it here.
29 #needs_sphinx = '1.0'
29 #needs_sphinx = '1.0'
30
30
31 # Add any Sphinx extension module names here, as strings. They can be
31 # Add any Sphinx extension module names here, as strings. They can be
32 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
32 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33 # ones.
33 # ones.
34 extensions = [
34 extensions = [
35 'sphinx.ext.intersphinx',
35 'sphinx.ext.intersphinx',
36 'sphinx.ext.todo',
36 'sphinx.ext.todo',
37 'sphinx.ext.pngmath'
37 'sphinx.ext.imgmath'
38 ]
38 ]
39
39
40 intersphinx_mapping = {
40 intersphinx_mapping = {
41 'enterprise': ('https://docs.rhodecode.com/RhodeCode-Enterprise/', None),
41 'enterprise': ('https://docs.rhodecode.com/RhodeCode-Enterprise/', None),
42 'control': ('https://docs.rhodecode.com/RhodeCode-Control/', None),
42 'control': ('https://docs.rhodecode.com/RhodeCode-Control/', None),
43 }
43 }
44
44
45 if tags.has('dev'):
45 if tags.has('dev'):
46 intersphinx_mapping.update({
46 intersphinx_mapping.update({
47 'enterprise': ('https://ci.rhodecode.com/documentation/Momentum/', None),
47 'enterprise': ('https://ci.rhodecode.com/documentation/Momentum/', None),
48 'control': ('https://ci.rhodecode.com/documentation/Control/', None),
48 'control': ('https://ci.rhodecode.com/documentation/Control/', None),
49 })
49 })
50
50
51
51
52 # Add any paths that contain templates here, relative to this directory.
52 # Add any paths that contain templates here, relative to this directory.
53 templates_path = ['_templates']
53 templates_path = ['_templates']
54
54
55 # The suffix of source filenames.
55 # The suffix of source filenames.
56 source_suffix = '.rst'
56 source_suffix = '.rst'
57
57
58 # The encoding of source files.
58 # The encoding of source files.
59 #source_encoding = 'utf-8-sig'
59 #source_encoding = 'utf-8-sig'
60
60
61 # The master toctree document.
61 # The master toctree document.
62 master_doc = 'index'
62 master_doc = 'index'
63
63
64 # The version info for the project you're documenting, acts as replacement for
64 # The version info for the project you're documenting, acts as replacement for
65 # |version| and |release|, also used in various other places throughout the
65 # |version| and |release|, also used in various other places throughout the
66 # built documents.
66 # built documents.
67
67
68 # TODO: johbo: Move into common package for documentation utilities
68 # TODO: johbo: Move into common package for documentation utilities
69 def _get_version():
69 def _get_version():
70 with open('../rhodecode/VERSION') as f:
70 with open('../rhodecode/VERSION') as f:
71 return f.read().strip()
71 return f.read().strip()
72
72
73 # The full version, including alpha/beta/rc tags.
73 # The full version, including alpha/beta/rc tags.
74 release = _get_version()
74 release = _get_version()
75 # The short X.Y version.
75 # The short X.Y version.
76 version = '.'.join(release.split('.', 2)[:2]) # First two parts of release
76 version = '.'.join(release.split('.', 2)[:2]) # First two parts of release
77
77
78 # General information about the project.
78 # General information about the project.
79 project = u'RhodeCode Enterprise %s ' % _get_version()
79 project = u'RhodeCode Enterprise %s ' % _get_version()
80 copyright = u'2010-{now.year}, RhodeCode GmbH'.format(
80 copyright = u'2010-{now.year}, RhodeCode GmbH'.format(
81 now=datetime.datetime.today())
81 now=datetime.datetime.today())
82
82
83
83
84 # The language for content autogenerated by Sphinx. Refer to documentation
84 # The language for content autogenerated by Sphinx. Refer to documentation
85 # for a list of supported languages.
85 # for a list of supported languages.
86 #language = None
86 #language = None
87
87
88 rst_epilog = common.rst_epilog + """
88 rst_epilog = common.rst_epilog + """
89 .. |async| replace:: asynchronous
89 .. |async| replace:: asynchronous
90 """
90 """
91
91
92 # There are two options for replacing |today|: either, you set today to some
92 # There are two options for replacing |today|: either, you set today to some
93 # non-false value, then it is used:
93 # non-false value, then it is used:
94 #today = ''
94 #today = ''
95 # Else, today_fmt is used as the format for a strftime call.
95 # Else, today_fmt is used as the format for a strftime call.
96 #today_fmt = '%B %d, %Y'
96 #today_fmt = '%B %d, %Y'
97
97
98 # List of patterns, relative to source directory, that match files and
98 # List of patterns, relative to source directory, that match files and
99 # directories to ignore when looking for source files.
99 # directories to ignore when looking for source files.
100 exclude_patterns = [
100 exclude_patterns = [
101 # Special directories
101 # Special directories
102 '_build',
102 '_build',
103 'result',
103 'result',
104
104
105 # Other RST files
105 # Other RST files
106 'admin/rhodecode-backup.rst',
106 'admin/rhodecode-backup.rst',
107 'auth/ldap-configuration-example.rst',
108 'issue-trackers/redmine.rst',
107 'issue-trackers/redmine.rst',
109 'known-issues/error-msg-guide.rst',
108 'known-issues/error-msg-guide.rst',
110 'tutorials/docs-build.rst',
109 'tutorials/docs-build.rst',
111 'integrations/example-ext.py',
110 'integrations/example-ext.py',
112 'collaboration/supported-workflows.rst',
111 'collaboration/supported-workflows.rst',
113 ]
112 ]
114
113
115
114
116 # The reST default role (used for this markup: `text`) to use for all
115 # The reST default role (used for this markup: `text`) to use for all
117 # documents.
116 # documents.
118 #default_role = None
117 #default_role = None
119
118
120 # If true, '()' will be appended to :func: etc. cross-reference text.
119 # If true, '()' will be appended to :func: etc. cross-reference text.
121 #add_function_parentheses = True
120 #add_function_parentheses = True
122
121
123 # If true, the current module name will be prepended to all description
122 # If true, the current module name will be prepended to all description
124 # unit titles (such as .. function::).
123 # unit titles (such as .. function::).
125 #add_module_names = True
124 #add_module_names = True
126
125
127 # If true, sectionauthor and moduleauthor directives will be shown in the
126 # If true, sectionauthor and moduleauthor directives will be shown in the
128 # output. They are ignored by default.
127 # output. They are ignored by default.
129 #show_authors = False
128 #show_authors = False
130
129
131 # The name of the Pygments (syntax highlighting) style to use.
130 # The name of the Pygments (syntax highlighting) style to use.
132 pygments_style = 'sphinx'
131 pygments_style = 'sphinx'
133
132
134 # A list of ignored prefixes for module index sorting.
133 # A list of ignored prefixes for module index sorting.
135 #modindex_common_prefix = []
134 #modindex_common_prefix = []
136
135
137 # If true, keep warnings as "system message" paragraphs in the built documents.
136 # If true, keep warnings as "system message" paragraphs in the built documents.
138 keep_warnings = tags.has("dev")
137 keep_warnings = tags.has("dev")
139
138
140
139
141 # -- Options for HTML output ----------------------------------------------
140 # -- Options for HTML output ----------------------------------------------
142
141
143 # The theme to use for HTML and HTML Help pages. See the documentation for
142 # The theme to use for HTML and HTML Help pages. See the documentation for
144 # a list of builtin themes.
143 # a list of builtin themes.
145 #html_theme = 'rctheme'
144 #html_theme = 'rctheme'
146 html_theme = 'sphinx_rtd_theme'
145 html_theme = 'sphinx_rtd_theme'
147
146
148 # Theme options are theme-specific and customize the look and feel of a theme
147 # Theme options are theme-specific and customize the look and feel of a theme
149 # further. For a list of options available for each theme, see the
148 # further. For a list of options available for each theme, see the
150 # documentation.
149 # documentation.
151 #html_theme_options = {}
150 #html_theme_options = {}
152 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
151 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
153
152
154 # Add any paths that contain custom themes here, relative to this directory.
153 # Add any paths that contain custom themes here, relative to this directory.
155 #html_theme_path = []
154 #html_theme_path = []
156
155
157 # The name for this set of Sphinx documents. If None, it defaults to
156 # The name for this set of Sphinx documents. If None, it defaults to
158 # "<project> v<release> documentation".
157 # "<project> v<release> documentation".
159 #html_title = None
158 #html_title = None
160
159
161 # A shorter title for the navigation bar. Default is the same as html_title.
160 # A shorter title for the navigation bar. Default is the same as html_title.
162 #html_short_title = None
161 #html_short_title = None
163
162
164 # The name of an image file (relative to this directory) to place at the top
163 # The name of an image file (relative to this directory) to place at the top
165 # of the sidebar.
164 # of the sidebar.
166 #html_logo = None
165 #html_logo = None
167 html_sidebars = {
166 html_sidebars = {
168 '**': ['globaltoc.html'],
167 '**': ['globaltoc.html'],
169 }
168 }
170
169
171 # The name of an image file (within the static path) to use as favicon of the
170 # The name of an image file (within the static path) to use as favicon of the
172 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
171 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
173 # pixels large.
172 # pixels large.
174 html_favicon = 'images/favicon.ico'
173 html_favicon = 'images/favicon.ico'
175
174
176 # Add any paths that contain custom static files (such as style sheets) here,
175 # Add any paths that contain custom static files (such as style sheets) here,
177 # relative to this directory. They are copied after the builtin static files,
176 # relative to this directory. They are copied after the builtin static files,
178 # so a file named "default.css" will overwrite the builtin "default.css".
177 # so a file named "default.css" will overwrite the builtin "default.css".
179 html_static_path = ['static/css/add.css']
178 html_static_path = ['static/css/add.css']
180
179
181 # Add any extra paths that contain custom files (such as robots.txt or
180 # Add any extra paths that contain custom files (such as robots.txt or
182 # .htaccess) here, relative to this directory. These files are copied
181 # .htaccess) here, relative to this directory. These files are copied
183 # directly to the root of the documentation.
182 # directly to the root of the documentation.
184 #html_extra_path = []
183 #html_extra_path = []
185
184
186 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
185 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
187 # using the given strftime format.
186 # using the given strftime format.
188 #html_last_updated_fmt = '%b %d, %Y'
187 #html_last_updated_fmt = '%b %d, %Y'
189
188
190 # If true, SmartyPants will be used to convert quotes and dashes to
189 # If true, SmartyPants will be used to convert quotes and dashes to
191 # typographically correct entities.
190 # typographically correct entities.
192 #html_use_smartypants = True
191 #html_use_smartypants = True
193
192
194 # Custom sidebar templates, maps document names to template names.
193 # Custom sidebar templates, maps document names to template names.
195 #html_sidebars = {}
194 #html_sidebars = {}
196
195
197 # Additional templates that should be rendered to pages, maps page names to
196 # Additional templates that should be rendered to pages, maps page names to
198 # template names.
197 # template names.
199 #html_additional_pages = {}
198 #html_additional_pages = {}
200
199
201 # If false, no module index is generated.
200 # If false, no module index is generated.
202 #html_domain_indices = True
201 #html_domain_indices = True
203
202
204 # If false, no index is generated.
203 # If false, no index is generated.
205 #html_use_index = True
204 #html_use_index = True
206
205
207 # If true, the index is split into individual pages for each letter.
206 # If true, the index is split into individual pages for each letter.
208 #html_split_index = False
207 #html_split_index = False
209
208
210 # If true, links to the reST sources are added to the pages.
209 # If true, links to the reST sources are added to the pages.
211 #html_show_sourcelink = True
210 #html_show_sourcelink = True
212
211
213 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
212 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
214 #html_show_sphinx = True
213 #html_show_sphinx = True
215
214
216 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
215 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
217 #html_show_copyright = True
216 #html_show_copyright = True
218
217
219 # If true, an OpenSearch description file will be output, and all pages will
218 # If true, an OpenSearch description file will be output, and all pages will
220 # contain a <link> tag referring to it. The value of this option must be the
219 # contain a <link> tag referring to it. The value of this option must be the
221 # base URL from which the finished HTML is served.
220 # base URL from which the finished HTML is served.
222 #html_use_opensearch = ''
221 #html_use_opensearch = ''
223
222
224 # This is the file name suffix for HTML files (e.g. ".xhtml").
223 # This is the file name suffix for HTML files (e.g. ".xhtml").
225 #html_file_suffix = None
224 #html_file_suffix = None
226
225
227 # Output file base name for HTML help builder.
226 # Output file base name for HTML help builder.
228 htmlhelp_basename = 'rhodecode-enterprise'
227 htmlhelp_basename = 'rhodecode-enterprise'
229
228
230
229
231 # -- Options for LaTeX output ---------------------------------------------
230 # -- Options for LaTeX output ---------------------------------------------
232
231
233 latex_elements = {
232 latex_elements = {
234 'classoptions': ',oneside',
233 'classoptions': ',oneside',
235 'babel': '\\usepackage[english]{babel}',
234 'babel': '\\usepackage[english]{babel}',
236
235
237 # The paper size ('letterpaper' or 'a4paper').
236 # The paper size ('letterpaper' or 'a4paper').
238 #'papersize': 'letterpaper',
237 #'papersize': 'letterpaper',
239
238
240 # The font size ('10pt', '11pt' or '12pt').
239 # The font size ('10pt', '11pt' or '12pt').
241 #'pointsize': '10pt',
240 #'pointsize': '10pt',
242
241
243 # Additional stuff for the LaTeX preamble.
242 # Additional stuff for the LaTeX preamble.
244 #'preamble': '',
243 #'preamble': '',
245 }
244 }
246
245
247 # Grouping the document tree into LaTeX files. List of tuples
246 # Grouping the document tree into LaTeX files. List of tuples
248 # (source start file, target name, title,
247 # (source start file, target name, title,
249 # author, documentclass [howto, manual, or own class]).
248 # author, documentclass [howto, manual, or own class]).
250 latex_documents = [
249 latex_documents = [
251 ('index', 'RhodeCodeEnterprise.tex', u'RhodeCode Enterprise',
250 ('index', 'RhodeCodeEnterprise.tex', u'RhodeCode Enterprise',
252 u'RhodeCode GmbH', 'manual'),
251 u'RhodeCode GmbH', 'manual'),
253 ]
252 ]
254
253
255 # The name of an image file (relative to this directory) to place at the top of
254 # The name of an image file (relative to this directory) to place at the top of
256 # the title page.
255 # the title page.
257 #latex_logo = None
256 #latex_logo = None
258
257
259 # For "manual" documents, if this is true, then toplevel headings are parts,
258 # For "manual" documents, if this is true, then toplevel headings are parts,
260 # not chapters.
259 # not chapters.
261 #latex_use_parts = False
260 #latex_use_parts = False
262
261
263 # If true, show page references after internal links.
262 # If true, show page references after internal links.
264 latex_show_pagerefs = True
263 latex_show_pagerefs = True
265
264
266 # If true, show URL addresses after external links.
265 # If true, show URL addresses after external links.
267 latex_show_urls = 'footnote'
266 latex_show_urls = 'footnote'
268
267
269 # Documents to append as an appendix to all manuals.
268 # Documents to append as an appendix to all manuals.
270 #latex_appendices = []
269 #latex_appendices = []
271
270
272 # If false, no module index is generated.
271 # If false, no module index is generated.
273 #latex_domain_indices = True
272 #latex_domain_indices = True
274
273
275 # Mode for literal blocks wider than the frame. Can be
274 # Mode for literal blocks wider than the frame. Can be
276 # overflow, shrink or truncate
275 # overflow, shrink or truncate
277 pdf_fit_mode = "truncate"
276 pdf_fit_mode = "truncate"
278
277
279
278
280 # -- Options for manual page output ---------------------------------------
279 # -- Options for manual page output ---------------------------------------
281
280
282 # One entry per manual page. List of tuples
281 # One entry per manual page. List of tuples
283 # (source start file, name, description, authors, manual section).
282 # (source start file, name, description, authors, manual section).
284 man_pages = [
283 man_pages = [
285 ('index', 'rhodecodeenterprise', u'RhodeCode Enterprise',
284 ('index', 'rhodecodeenterprise', u'RhodeCode Enterprise',
286 [u'RhodeCode GmbH'], 1)
285 [u'RhodeCode GmbH'], 1)
287 ]
286 ]
288
287
289 # If true, show URL addresses after external links.
288 # If true, show URL addresses after external links.
290 #man_show_urls = False
289 #man_show_urls = False
291
290
292
291
293 # -- Options for Texinfo output -------------------------------------------
292 # -- Options for Texinfo output -------------------------------------------
294
293
295 # Grouping the document tree into Texinfo files. List of tuples
294 # Grouping the document tree into Texinfo files. List of tuples
296 # (source start file, target name, title, author,
295 # (source start file, target name, title, author,
297 # dir menu entry, description, category)
296 # dir menu entry, description, category)
298 texinfo_documents = [
297 texinfo_documents = [
299 ('index', 'RhodeCodeEnterprise', u'RhodeCode Enterprise',
298 ('index', 'RhodeCodeEnterprise', u'RhodeCode Enterprise',
300 u'RhodeCode Docs Team', 'RhodeCodeEnterprise', 'RhodeCode Docs Project',
299 u'RhodeCode Docs Team', 'RhodeCodeEnterprise', 'RhodeCode Docs Project',
301 'Miscellaneous'),
300 'Miscellaneous'),
302 ]
301 ]
303
302
304 # Documents to append as an appendix to all manuals.
303 # Documents to append as an appendix to all manuals.
305 #texinfo_appendices = []
304 #texinfo_appendices = []
306
305
307 # If false, no module index is generated.
306 # If false, no module index is generated.
308 #texinfo_domain_indices = True
307 #texinfo_domain_indices = True
309
308
310 # How to display URL addresses: 'footnote', 'no', or 'inline'.
309 # How to display URL addresses: 'footnote', 'no', or 'inline'.
311 #texinfo_show_urls = 'footnote'
310 #texinfo_show_urls = 'footnote'
312
311
313 # If true, do not generate a @detailmenu in the "Top" node's menu.
312 # If true, do not generate a @detailmenu in the "Top" node's menu.
314 #texinfo_no_detailmenu = False
313 #texinfo_no_detailmenu = False
315
314
316 # We want to see todo notes in case of a pre-release build of the documentation
315 # We want to see todo notes in case of a pre-release build of the documentation
317 todo_include_todos = tags.has("dev")
316 todo_include_todos = tags.has("dev")
@@ -1,219 +1,226 b''
1 .. _dev-setup:
1 .. _dev-setup:
2
2
3 ===================
3 ===================
4 Development setup
4 Development setup
5 ===================
5 ===================
6
6
7
7
8 RhodeCode Enterprise runs inside a Nix managed environment. This ensures build
8 RhodeCode Enterprise runs inside a Nix managed environment. This ensures build
9 environment dependencies are correctly declared and installed during setup.
9 environment dependencies are correctly declared and installed during setup.
10 It also enables atomic upgrades, rollbacks, and multiple instances of RhodeCode
10 It also enables atomic upgrades, rollbacks, and multiple instances of RhodeCode
11 Enterprise running with isolation.
11 Enterprise running with isolation.
12
12
13 To set up RhodeCode Enterprise inside the Nix environment, use the following steps:
13 To set up RhodeCode Enterprise inside the Nix environment, use the following steps:
14
14
15
15
16
16
17 Setup Nix Package Manager
17 Setup Nix Package Manager
18 -------------------------
18 -------------------------
19
19
20 To install the Nix Package Manager, please run::
20 To install the Nix Package Manager, please run::
21
21
22 $ curl https://nixos.org/nix/install | sh
22 $ curl https://nixos.org/nix/install | sh
23
23
24 or go to https://nixos.org/nix/ and follow the installation instructions.
24 or go to https://nixos.org/nix/ and follow the installation instructions.
25 Once this is correctly set up on your system, you should be able to use the
25 Once this is correctly set up on your system, you should be able to use the
26 following commands:
26 following commands:
27
27
28 * `nix-env`
28 * `nix-env`
29
29
30 * `nix-shell`
30 * `nix-shell`
31
31
32
32
33 .. tip::
33 .. tip::
34
34
35 Update your channels frequently by running ``nix-channel --update``.
35 Update your channels frequently by running ``nix-channel --update``.
36
36
37 .. note::
38
39 To uninstall nix run the following:
40
41 remove the . "$HOME/.nix-profile/etc/profile.d/nix.sh" line in your ~/.profile or ~/.bash_profile
42 rm -rf $HOME/{.nix-channels,.nix-defexpr,.nix-profile,.config/nixpkgs}
43 sudo rm -rf /nix
37
44
38 Switch nix to the latest STABLE channel
45 Switch nix to the latest STABLE channel
39 ---------------------------------------
46 ---------------------------------------
40
47
41 run::
48 run::
42
49
43 nix-channel --add https://nixos.org/channels/nixos-16.03 nixpkgs
50 nix-channel --add https://nixos.org/channels/nixos-16.03 nixpkgs
44
51
45 Followed by::
52 Followed by::
46
53
47 nix-channel --update
54 nix-channel --update
48
55
49
56
50 Install required binaries
57 Install required binaries
51 -------------------------
58 -------------------------
52
59
53 We need some handy tools first.
60 We need some handy tools first.
54
61
55 run::
62 run::
56
63
57 nix-env -i nix-prefetch-hg
64 nix-env -i nix-prefetch-hg
58 nix-env -i nix-prefetch-git
65 nix-env -i nix-prefetch-git
59
66
60
67
61 Clone the required repositories
68 Clone the required repositories
62 -------------------------------
69 -------------------------------
63
70
64 After Nix is set up, clone the RhodeCode Enterprise Community Edition and
71 After Nix is set up, clone the RhodeCode Enterprise Community Edition and
65 RhodeCode VCSServer repositories into the same directory.
72 RhodeCode VCSServer repositories into the same directory.
66 RhodeCode currently is using Mercurial Version Control System, please make sure
73 RhodeCode currently is using Mercurial Version Control System, please make sure
67 you have it installed before continuing.
74 you have it installed before continuing.
68
75
69 To obtain the required sources, use the following commands::
76 To obtain the required sources, use the following commands::
70
77
71 mkdir rhodecode-develop && cd rhodecode-develop
78 mkdir rhodecode-develop && cd rhodecode-develop
72 hg clone https://code.rhodecode.com/rhodecode-enterprise-ce
79 hg clone https://code.rhodecode.com/rhodecode-enterprise-ce
73 hg clone https://code.rhodecode.com/rhodecode-vcsserver
80 hg clone https://code.rhodecode.com/rhodecode-vcsserver
74
81
75 .. note::
82 .. note::
76
83
77 If you cannot clone the repository, please contact us via support@rhodecode.com
84 If you cannot clone the repository, please contact us via support@rhodecode.com
78
85
79
86
80 Install some required libraries
87 Install some required libraries
81 -------------------------------
88 -------------------------------
82
89
83 There are some required drivers and dev libraries that we need to install to
90 There are some required drivers and dev libraries that we need to install to
84 test RhodeCode under different types of databases. For example in Ubuntu we
91 test RhodeCode under different types of databases. For example in Ubuntu we
85 need to install the following.
92 need to install the following.
86
93
87 required libraries::
94 required libraries::
88
95
89 sudo apt-get install libapr1-dev libaprutil1-dev
96 sudo apt-get install libapr1-dev libaprutil1-dev
90 sudo apt-get install libsvn-dev
97 sudo apt-get install libsvn-dev
91 sudo apt-get install mysql-server libmysqlclient-dev
98 sudo apt-get install mysql-server libmysqlclient-dev
92 sudo apt-get install postgresql postgresql-contrib libpq-dev
99 sudo apt-get install postgresql postgresql-contrib libpq-dev
93 sudo apt-get install libcurl4-openssl-dev
100 sudo apt-get install libcurl4-openssl-dev
94
101
95
102
96 Enter the Development Shell
103 Enter the Development Shell
97 ---------------------------
104 ---------------------------
98
105
99 The final step is to start the development shells. To do this, run the
106 The final step is to start the development shells. To do this, run the
100 following command from inside the cloned repository::
107 following command from inside the cloned repository::
101
108
102 #first, the vcsserver
109 #first, the vcsserver
103 cd ~/rhodecode-vcsserver
110 cd ~/rhodecode-vcsserver
104 nix-shell
111 nix-shell
105
112
106 # then enterprise sources
113 # then enterprise sources
107 cd ~/rhodecode-enterprise-ce
114 cd ~/rhodecode-enterprise-ce
108 nix-shell
115 nix-shell
109
116
110 .. note::
117 .. note::
111
118
112 On the first run, this will take a while to download and optionally compile
119 On the first run, this will take a while to download and optionally compile
113 a few things. The following runs will be faster. The development shell works
120 a few things. The following runs will be faster. The development shell works
114 fine on both MacOS and Linux platforms.
121 fine on both MacOS and Linux platforms.
115
122
116
123
117 Create config.nix for development
124 Create config.nix for development
118 ---------------------------------
125 ---------------------------------
119
126
120 In order to run proper tests and setup linking across projects, a config.nix
127 In order to run proper tests and setup linking across projects, a config.nix
121 file needs to be setup::
128 file needs to be setup::
122
129
123 # create config
130 # create config
124 mkdir -p ~/.nixpkgs
131 mkdir -p ~/.nixpkgs
125 touch ~/.nixpkgs/config.nix
132 touch ~/.nixpkgs/config.nix
126
133
127 # put the below content into the ~/.nixpkgs/config.nix file
134 # put the below content into the ~/.nixpkgs/config.nix file
128 # adjusts, the path to where you cloned your repositories.
135 # adjusts, the path to where you cloned your repositories.
129
136
130 {
137 {
131 rc = {
138 rc = {
132 sources = {
139 sources = {
133 rhodecode-vcsserver = "/home/dev/rhodecode-vcsserver";
140 rhodecode-vcsserver = "/home/dev/rhodecode-vcsserver";
134 rhodecode-enterprise-ce = "/home/dev/rhodecode-enterprise-ce";
141 rhodecode-enterprise-ce = "/home/dev/rhodecode-enterprise-ce";
135 rhodecode-enterprise-ee = "/home/dev/rhodecode-enterprise-ee";
142 rhodecode-enterprise-ee = "/home/dev/rhodecode-enterprise-ee";
136 };
143 };
137 };
144 };
138 }
145 }
139
146
140
147
141
148
142 Creating a Development Configuration
149 Creating a Development Configuration
143 ------------------------------------
150 ------------------------------------
144
151
145 To create a development environment for RhodeCode Enterprise,
152 To create a development environment for RhodeCode Enterprise,
146 use the following steps:
153 use the following steps:
147
154
148 1. Create a copy of vcsserver config:
155 1. Create a copy of vcsserver config:
149 `cp ~/rhodecode-vcsserver/configs/development.ini ~/rhodecode-vcsserver/configs/dev.ini`
156 `cp ~/rhodecode-vcsserver/configs/development.ini ~/rhodecode-vcsserver/configs/dev.ini`
150 2. Create a copy of rhodocode config:
157 2. Create a copy of rhodocode config:
151 `cp ~/rhodecode-enterprise-ce/configs/development.ini ~/rhodecode-enterprise-ce/configs/dev.ini`
158 `cp ~/rhodecode-enterprise-ce/configs/development.ini ~/rhodecode-enterprise-ce/configs/dev.ini`
152 3. Adjust the configuration settings to your needs if needed.
159 3. Adjust the configuration settings to your needs if needed.
153
160
154 .. note::
161 .. note::
155
162
156 It is recommended to use the name `dev.ini` since it's included in .hgignore file.
163 It is recommended to use the name `dev.ini` since it's included in .hgignore file.
157
164
158
165
159 Setup the Development Database
166 Setup the Development Database
160 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
167 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
161
168
162 To create a development database, use the following example. This is a one
169 To create a development database, use the following example. This is a one
163 time operation executed from the nix-shell of rhodecode-enterprise-ce sources ::
170 time operation executed from the nix-shell of rhodecode-enterprise-ce sources ::
164
171
165 rc-setup-app dev.ini \
172 rc-setup-app dev.ini \
166 --user=admin --password=secret \
173 --user=admin --password=secret \
167 --email=admin@example.com \
174 --email=admin@example.com \
168 --repos=~/my_dev_repos
175 --repos=~/my_dev_repos
169
176
170
177
171 Compile CSS and JavaScript
178 Compile CSS and JavaScript
172 ^^^^^^^^^^^^^^^^^^^^^^^^^^
179 ^^^^^^^^^^^^^^^^^^^^^^^^^^
173
180
174 To use the application's frontend and prepare it for production deployment,
181 To use the application's frontend and prepare it for production deployment,
175 you will need to compile the CSS and JavaScript with Grunt.
182 you will need to compile the CSS and JavaScript with Grunt.
176 This is easily done from within the nix-shell using the following command::
183 This is easily done from within the nix-shell using the following command::
177
184
178 grunt
185 grunt
179
186
180 When developing new features you will need to recompile following any
187 When developing new features you will need to recompile following any
181 changes made to the CSS or JavaScript files when developing the code::
188 changes made to the CSS or JavaScript files when developing the code::
182
189
183 grunt watch
190 grunt watch
184
191
185 This prepares the development (with comments/whitespace) versions of files.
192 This prepares the development (with comments/whitespace) versions of files.
186
193
187 Start the Development Servers
194 Start the Development Servers
188 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
195 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
189
196
190 From the rhodecode-vcsserver directory, start the development server in another
197 From the rhodecode-vcsserver directory, start the development server in another
191 nix-shell, using the following command::
198 nix-shell, using the following command::
192
199
193 pserve configs/dev.ini
200 pserve configs/dev.ini
194
201
195 In the adjacent nix-shell which you created for your development server, you may
202 In the adjacent nix-shell which you created for your development server, you may
196 now start CE with the following command::
203 now start CE with the following command::
197
204
198
205
199 pserve --reload configs/dev.ini
206 pserve --reload configs/dev.ini
200
207
201 .. note::
208 .. note::
202
209
203 `--reload` flag will automatically reload the server when source file changes.
210 `--reload` flag will automatically reload the server when source file changes.
204
211
205
212
206 Run the Environment Tests
213 Run the Environment Tests
207 ^^^^^^^^^^^^^^^^^^^^^^^^^
214 ^^^^^^^^^^^^^^^^^^^^^^^^^
208
215
209 Please make sure that the tests are passing to verify that your environment is
216 Please make sure that the tests are passing to verify that your environment is
210 set up correctly. RhodeCode uses py.test to run tests.
217 set up correctly. RhodeCode uses py.test to run tests.
211 While your instance is running, start a new nix-shell and simply run
218 While your instance is running, start a new nix-shell and simply run
212 ``make test`` to run the basic test suite.
219 ``make test`` to run the basic test suite.
213
220
214
221
215 Need Help?
222 Need Help?
216 ^^^^^^^^^^
223 ^^^^^^^^^^
217
224
218 Join us on Slack via https://rhodecode.com/join or post questions in our
225 Join us on Slack via https://rhodecode.com/join or post questions in our
219 Community Portal at https://community.rhodecode.com
226 Community Portal at https://community.rhodecode.com
@@ -1,269 +1,261 b''
1 { system ? builtins.currentSystem
1 { system ? builtins.currentSystem
2 }:
2 }:
3
3
4 let
4 let
5
5
6 pkgs = import <nixpkgs> { inherit system; };
6 pkgs = import <nixpkgs> { inherit system; };
7
7
8 inherit (pkgs) fetchurl fetchgit;
8 inherit (pkgs) fetchurl fetchgit;
9
9
10 buildPythonPackage = pkgs.python27Packages.buildPythonPackage;
10 buildPythonPackage = pkgs.python27Packages.buildPythonPackage;
11 python = pkgs.python27Packages.python;
11 python = pkgs.python27Packages.python;
12
12
13 Jinja2 = buildPythonPackage rec {
13 Jinja2 = buildPythonPackage rec {
14 name = "Jinja2-2.9.6";
14 name = "Jinja2-2.9.6";
15 buildInputs = [];
15 buildInputs = [];
16 doCheck = false;
16 doCheck = false;
17 propagatedBuildInputs = [MarkupSafe];
17 propagatedBuildInputs = [MarkupSafe];
18 src = fetchurl {
18 src = fetchurl {
19 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
19 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
20 md5 = "6411537324b4dba0956aaa8109f3c77b";
20 md5 = "6411537324b4dba0956aaa8109f3c77b";
21 };
21 };
22 };
22 };
23
23
24 MarkupSafe = buildPythonPackage rec {
24 MarkupSafe = buildPythonPackage rec {
25 name = "MarkupSafe-1.0";
25 name = "MarkupSafe-1.0";
26 buildInputs = [];
26 buildInputs = [];
27 doCheck = false;
27 doCheck = false;
28 propagatedBuildInputs = [];
28 propagatedBuildInputs = [];
29 src = fetchurl {
29 src = fetchurl {
30 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
30 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
31 md5 = "2fcedc9284d50e577b5192e8e3578355";
31 md5 = "2fcedc9284d50e577b5192e8e3578355";
32 };
32 };
33 };
33 };
34
34
35 Pygments = buildPythonPackage {
35 Pygments = buildPythonPackage {
36 name = "Pygments-2.2.0";
36 name = "Pygments-2.2.0";
37 buildInputs = [];
37 buildInputs = [];
38 doCheck = false;
38 doCheck = false;
39 propagatedBuildInputs = [];
39 propagatedBuildInputs = [];
40 src = fetchurl {
40 src = fetchurl {
41 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
41 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
42 md5 = "13037baca42f16917cbd5ad2fab50844";
42 md5 = "13037baca42f16917cbd5ad2fab50844";
43 };
43 };
44 };
44 };
45
45
46 Sphinx = buildPythonPackage (rec {
46 Sphinx = buildPythonPackage (rec {
47 name = "Sphinx-1.6.5";
47 name = "Sphinx-1.6.5";
48 src = fetchurl {
48 src = fetchurl {
49 url = "https://pypi.python.org/packages/8b/7e/b188d9a3b9c938e736e02a74c1363c2888e095d770df2c72b4c312f9fdcb/Sphinx-1.6.5.tar.gz";
49 url = "https://pypi.python.org/packages/8b/7e/b188d9a3b9c938e736e02a74c1363c2888e095d770df2c72b4c312f9fdcb/Sphinx-1.6.5.tar.gz";
50 md5 = "cd73118c21ec610432e63e6421ec54f1";
50 md5 = "cd73118c21ec610432e63e6421ec54f1";
51 };
51 };
52 propagatedBuildInputs = [
52 propagatedBuildInputs = [
53 six
53 six
54 Jinja2
54 Jinja2
55 Pygments
55 Pygments
56 docutils
56 docutils
57 snowballstemmer
57 snowballstemmer
58 babel
58 babel
59 alabaster
59 alabaster
60 imagesize
60 imagesize
61 requests
61 requests
62 setuptools
62 setuptools
63 sphinxcontrib-websupport
63 sphinxcontrib-websupport
64 typing
64 typing
65
65
66 # special cases
66 # special cases
67 pytz
67 pytz
68 sphinx_rtd_theme
68 sphinx_rtd_theme
69
69
70 ];
70 ];
71 });
71 });
72
72
73 alabaster = buildPythonPackage rec {
73 alabaster = buildPythonPackage rec {
74 name = "alabaster-0.7.10";
74 name = "alabaster-0.7.10";
75 buildInputs = [];
75 buildInputs = [];
76 doCheck = false;
76 doCheck = false;
77 propagatedBuildInputs = [];
77 propagatedBuildInputs = [];
78 src = fetchurl {
78 src = fetchurl {
79 url = "https://pypi.python.org/packages/d0/a5/e3a9ad3ee86aceeff71908ae562580643b955ea1b1d4f08ed6f7e8396bd7/alabaster-0.7.10.tar.gz";
79 url = "https://pypi.python.org/packages/d0/a5/e3a9ad3ee86aceeff71908ae562580643b955ea1b1d4f08ed6f7e8396bd7/alabaster-0.7.10.tar.gz";
80 md5 = "7934dccf38801faa105f6e7b4784f493";
80 md5 = "7934dccf38801faa105f6e7b4784f493";
81 };
81 };
82 };
82 };
83
83
84 babel = buildPythonPackage {
84 babel = buildPythonPackage {
85 name = "babel-2.5.1";
85 name = "babel-2.5.1";
86 buildInputs = [];
86 buildInputs = [];
87 doCheck = false;
87 doCheck = false;
88 propagatedBuildInputs = [pytz];
88 propagatedBuildInputs = [pytz];
89 src = fetchurl {
89 src = fetchurl {
90 url = "https://pypi.python.org/packages/5a/22/63f1dbb8514bb7e0d0c8a85cc9b14506599a075e231985f98afd70430e1f/Babel-2.5.1.tar.gz";
90 url = "https://pypi.python.org/packages/5a/22/63f1dbb8514bb7e0d0c8a85cc9b14506599a075e231985f98afd70430e1f/Babel-2.5.1.tar.gz";
91 md5 = "60228b3ce93a203357158b909afe8ae1";
91 md5 = "60228b3ce93a203357158b909afe8ae1";
92 };
92 };
93 };
93 };
94
94
95 certifi = buildPythonPackage {
95 certifi = buildPythonPackage {
96 name = "certifi-2017.11.5";
96 name = "certifi-2017.11.5";
97 buildInputs = [];
97 buildInputs = [];
98 doCheck = false;
98 doCheck = false;
99 propagatedBuildInputs = [];
99 propagatedBuildInputs = [];
100 src = fetchurl {
100 src = fetchurl {
101 url = "https://pypi.python.org/packages/23/3f/8be01c50ed24a4bd6b8da799839066ce0288f66f5e11f0367323467f0cbc/certifi-2017.11.5.tar.gz";
101 url = "https://pypi.python.org/packages/23/3f/8be01c50ed24a4bd6b8da799839066ce0288f66f5e11f0367323467f0cbc/certifi-2017.11.5.tar.gz";
102 md5 = "c15ac46ed1fe4b607ff3405928f9a992";
102 md5 = "c15ac46ed1fe4b607ff3405928f9a992";
103 };
103 };
104 };
104 };
105
105
106 chardet = buildPythonPackage {
106 chardet = buildPythonPackage {
107 name = "chardet-3.0.4";
107 name = "chardet-3.0.4";
108 buildInputs = [];
108 buildInputs = [];
109 doCheck = false;
109 doCheck = false;
110 propagatedBuildInputs = [];
110 propagatedBuildInputs = [];
111 src = fetchurl {
111 src = fetchurl {
112 url = "https://pypi.python.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz";
112 url = "https://pypi.python.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz";
113 md5 = "7dd1ba7f9c77e32351b0a0cfacf4055c";
113 md5 = "7dd1ba7f9c77e32351b0a0cfacf4055c";
114 };
114 };
115 };
115 };
116
116
117 docutils = buildPythonPackage {
117 docutils = buildPythonPackage {
118 name = "docutils-0.14";
118 name = "docutils-0.14";
119 buildInputs = [];
119 buildInputs = [];
120 doCheck = false;
120 doCheck = false;
121 propagatedBuildInputs = [];
121 propagatedBuildInputs = [];
122 src = fetchurl {
122 src = fetchurl {
123 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
123 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
124 md5 = "c53768d63db3873b7d452833553469de";
124 md5 = "c53768d63db3873b7d452833553469de";
125 };
125 };
126 };
126 };
127
127
128 idna = buildPythonPackage {
128 idna = buildPythonPackage {
129 name = "idna-2.6";
129 name = "idna-2.6";
130 buildInputs = [];
130 buildInputs = [];
131 doCheck = false;
131 doCheck = false;
132 propagatedBuildInputs = [];
132 propagatedBuildInputs = [];
133 src = fetchurl {
133 src = fetchurl {
134 url = "https://pypi.python.org/packages/f4/bd/0467d62790828c23c47fc1dfa1b1f052b24efdf5290f071c7a91d0d82fd3/idna-2.6.tar.gz";
134 url = "https://pypi.python.org/packages/f4/bd/0467d62790828c23c47fc1dfa1b1f052b24efdf5290f071c7a91d0d82fd3/idna-2.6.tar.gz";
135 md5 = "c706e2790b016bd0ed4edd2d4ba4d147";
135 md5 = "c706e2790b016bd0ed4edd2d4ba4d147";
136 };
136 };
137 };
137 };
138
138
139 imagesize = buildPythonPackage {
139 imagesize = buildPythonPackage {
140 name = "imagesize-0.7.1";
140 name = "imagesize-0.7.1";
141 buildInputs = [];
141 buildInputs = [];
142 doCheck = false;
142 doCheck = false;
143 propagatedBuildInputs = [];
143 propagatedBuildInputs = [];
144 src = fetchurl {
144 src = fetchurl {
145 url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/imagesize-0.7.1.tar.gz";
145 url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/imagesize-0.7.1.tar.gz";
146 md5 = "976148283286a6ba5f69b0f81aef8052";
146 md5 = "976148283286a6ba5f69b0f81aef8052";
147 };
147 };
148 };
148 };
149
149
150 pytz = buildPythonPackage {
150 pytz = buildPythonPackage {
151 name = "pytz-2017.3";
151 name = "pytz-2017.3";
152 buildInputs = [];
152 buildInputs = [];
153 doCheck = false;
153 doCheck = false;
154 propagatedBuildInputs = [];
154 propagatedBuildInputs = [];
155 src = fetchurl {
155 src = fetchurl {
156 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
156 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
157 md5 = "7006b56c0d68a162d9fe57d4249c3171";
157 md5 = "7006b56c0d68a162d9fe57d4249c3171";
158 };
158 };
159 };
159 };
160
160
161 requests = buildPythonPackage {
161 requests = buildPythonPackage {
162 name = "requests-2.18.4";
162 name = "requests-2.18.4";
163 buildInputs = [];
163 buildInputs = [];
164 doCheck = false;
164 doCheck = false;
165 propagatedBuildInputs = [chardet idna urllib3 certifi];
165 propagatedBuildInputs = [chardet idna urllib3 certifi];
166 src = fetchurl {
166 src = fetchurl {
167 url = "https://pypi.python.org/packages/b0/e1/eab4fc3752e3d240468a8c0b284607899d2fbfb236a56b7377a329aa8d09/requests-2.18.4.tar.gz";
167 url = "https://pypi.python.org/packages/b0/e1/eab4fc3752e3d240468a8c0b284607899d2fbfb236a56b7377a329aa8d09/requests-2.18.4.tar.gz";
168 md5 = "081412b2ef79bdc48229891af13f4d82";
168 md5 = "081412b2ef79bdc48229891af13f4d82";
169 };
169 };
170 };
170 };
171
171
172 setuptools = buildPythonPackage {
173 name = "setuptools-36.6.0";
174 buildInputs = [];
175 doCheck = false;
176 propagatedBuildInputs = [];
177 src = fetchurl {
178 url = "https://pypi.python.org/packages/45/29/8814bf414e7cd1031e1a3c8a4169218376e284ea2553cc0822a6ea1c2d78/setuptools-36.6.0.zip";
179 md5 = "74663b15117d9a2cc5295d76011e6fd1";
180 };
181 };
182
183 six = buildPythonPackage {
172 six = buildPythonPackage {
184 name = "six-1.11.0";
173 name = "six-1.11.0";
185 buildInputs = [];
174 buildInputs = [];
186 doCheck = false;
175 doCheck = false;
187 propagatedBuildInputs = [];
176 propagatedBuildInputs = [];
188 src = fetchurl {
177 src = fetchurl {
189 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
178 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
190 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
179 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
191 };
180 };
192 };
181 };
193
182
194 snowballstemmer = buildPythonPackage {
183 snowballstemmer = buildPythonPackage {
195 name = "snowballstemmer-1.2.1";
184 name = "snowballstemmer-1.2.1";
196 buildInputs = [];
185 buildInputs = [];
197 doCheck = false;
186 doCheck = false;
198 propagatedBuildInputs = [];
187 propagatedBuildInputs = [];
199 src = fetchurl {
188 src = fetchurl {
200 url = "https://pypi.python.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz";
189 url = "https://pypi.python.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz";
201 md5 = "643b019667a708a922172e33a99bf2fa";
190 md5 = "643b019667a708a922172e33a99bf2fa";
202 };
191 };
203 };
192 };
204
193
205 sphinx-rtd-theme = buildPythonPackage {
194 sphinx-rtd-theme = buildPythonPackage {
206 name = "sphinx-rtd-theme-0.2.5b1";
195 name = "sphinx-rtd-theme-0.2.5b1";
207 buildInputs = [];
196 buildInputs = [];
208 doCheck = false;
197 doCheck = false;
209 propagatedBuildInputs = [];
198 propagatedBuildInputs = [];
210 src = fetchurl {
199 src = fetchurl {
211 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
200 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
212 md5 = "0923473a43bd2527f32151f195f2a521";
201 md5 = "0923473a43bd2527f32151f195f2a521";
213 };
202 };
214 };
203 };
215
204
216 sphinxcontrib-websupport = buildPythonPackage {
205 sphinxcontrib-websupport = buildPythonPackage {
217 name = "sphinxcontrib-websupport-1.0.1";
206 name = "sphinxcontrib-websupport-1.0.1";
218 buildInputs = [];
207 buildInputs = [];
219 doCheck = false;
208 doCheck = false;
220 propagatedBuildInputs = [];
209 propagatedBuildInputs = [];
221 src = fetchurl {
210 src = fetchurl {
222 url = "https://pypi.python.org/packages/c5/6b/f0630436b931ad4f8331a9399ca18a7d447f0fcc0c7178fb56b1aee68d01/sphinxcontrib-websupport-1.0.1.tar.gz";
211 url = "https://pypi.python.org/packages/c5/6b/f0630436b931ad4f8331a9399ca18a7d447f0fcc0c7178fb56b1aee68d01/sphinxcontrib-websupport-1.0.1.tar.gz";
223 md5 = "84df26463b1ba65b07f926dbe2055665";
212 md5 = "84df26463b1ba65b07f926dbe2055665";
224 };
213 };
225 };
214 };
226
215
227 typing = buildPythonPackage {
216 typing = buildPythonPackage {
228 name = "typing-3.6.2";
217 name = "typing-3.6.2";
229 buildInputs = [];
218 buildInputs = [];
230 doCheck = false;
219 doCheck = false;
231 propagatedBuildInputs = [];
220 propagatedBuildInputs = [];
232 src = fetchurl {
221 src = fetchurl {
233 url = "https://pypi.python.org/packages/ca/38/16ba8d542e609997fdcd0214628421c971f8c395084085354b11ff4ac9c3/typing-3.6.2.tar.gz";
222 url = "https://pypi.python.org/packages/ca/38/16ba8d542e609997fdcd0214628421c971f8c395084085354b11ff4ac9c3/typing-3.6.2.tar.gz";
234 md5 = "143af0bf3afd1887622771f2f1ffe8e1";
223 md5 = "143af0bf3afd1887622771f2f1ffe8e1";
235 };
224 };
236 };
225 };
237
226
238 urllib3 = buildPythonPackage {
227 urllib3 = buildPythonPackage {
239 name = "urllib3-1.22";
228 name = "urllib3-1.22";
240 buildInputs = [];
229 buildInputs = [];
241 doCheck = false;
230 doCheck = false;
242 propagatedBuildInputs = [];
231 propagatedBuildInputs = [];
243 src = fetchurl {
232 src = fetchurl {
244 url = "https://pypi.python.org/packages/ee/11/7c59620aceedcc1ef65e156cc5ce5a24ef87be4107c2b74458464e437a5d/urllib3-1.22.tar.gz";
233 url = "https://pypi.python.org/packages/ee/11/7c59620aceedcc1ef65e156cc5ce5a24ef87be4107c2b74458464e437a5d/urllib3-1.22.tar.gz";
245 md5 = "0da7bed3fe94bf7dc59ae37885cc72f7";
234 md5 = "0da7bed3fe94bf7dc59ae37885cc72f7";
246 };
235 };
247 };
236 };
248
237
249
238
250 sphinx_rtd_theme = buildPythonPackage rec {
239 sphinx_rtd_theme = buildPythonPackage rec {
251 name = "sphinx-rtd-theme-0.2.5b1";
240 name = "sphinx-rtd-theme-0.2.5b1";
252 buildInputs = [];
241 buildInputs = [];
253 doCheck = false;
242 doCheck = false;
254 propagatedBuildInputs = [];
243 propagatedBuildInputs = [];
255 src = fetchurl {
244 src = fetchurl {
256 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
245 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
257 md5 = "0923473a43bd2527f32151f195f2a521";
246 md5 = "0923473a43bd2527f32151f195f2a521";
258 };
247 };
259
248
260
249
261 };
250 };
251 # Avoid that setuptools is replaced, this leads to trouble
252 # with buildPythonPackage.
253 setuptools = pkgs.python27Packages.setuptools;
262
254
263 in python.buildEnv.override {
255 in python.buildEnv.override {
264 inherit python;
256 inherit python;
265 extraLibs = [
257 extraLibs = [
266 Sphinx
258 Sphinx
267 sphinx_rtd_theme
259 sphinx_rtd_theme
268 ];
260 ];
269 }
261 }
@@ -1,114 +1,115 b''
1 .. _rhodecode-release-notes-ref:
1 .. _rhodecode-release-notes-ref:
2
2
3 Release Notes
3 Release Notes
4 =============
4 =============
5
5
6 |RCE| 4.x Versions
6 |RCE| 4.x Versions
7 ------------------
7 ------------------
8
8
9 .. toctree::
9 .. toctree::
10 :maxdepth: 1
10 :maxdepth: 1
11
11
12 release-notes-4.12.0.rst
12 release-notes-4.11.6.rst
13 release-notes-4.11.6.rst
13 release-notes-4.11.5.rst
14 release-notes-4.11.5.rst
14 release-notes-4.11.4.rst
15 release-notes-4.11.4.rst
15 release-notes-4.11.3.rst
16 release-notes-4.11.3.rst
16 release-notes-4.11.2.rst
17 release-notes-4.11.2.rst
17 release-notes-4.11.1.rst
18 release-notes-4.11.1.rst
18 release-notes-4.11.0.rst
19 release-notes-4.11.0.rst
19 release-notes-4.10.6.rst
20 release-notes-4.10.6.rst
20 release-notes-4.10.5.rst
21 release-notes-4.10.5.rst
21 release-notes-4.10.4.rst
22 release-notes-4.10.4.rst
22 release-notes-4.10.3.rst
23 release-notes-4.10.3.rst
23 release-notes-4.10.2.rst
24 release-notes-4.10.2.rst
24 release-notes-4.10.1.rst
25 release-notes-4.10.1.rst
25 release-notes-4.10.0.rst
26 release-notes-4.10.0.rst
26 release-notes-4.9.1.rst
27 release-notes-4.9.1.rst
27 release-notes-4.9.0.rst
28 release-notes-4.9.0.rst
28 release-notes-4.8.0.rst
29 release-notes-4.8.0.rst
29 release-notes-4.7.2.rst
30 release-notes-4.7.2.rst
30 release-notes-4.7.1.rst
31 release-notes-4.7.1.rst
31 release-notes-4.7.0.rst
32 release-notes-4.7.0.rst
32 release-notes-4.6.1.rst
33 release-notes-4.6.1.rst
33 release-notes-4.6.0.rst
34 release-notes-4.6.0.rst
34 release-notes-4.5.2.rst
35 release-notes-4.5.2.rst
35 release-notes-4.5.1.rst
36 release-notes-4.5.1.rst
36 release-notes-4.5.0.rst
37 release-notes-4.5.0.rst
37 release-notes-4.4.2.rst
38 release-notes-4.4.2.rst
38 release-notes-4.4.1.rst
39 release-notes-4.4.1.rst
39 release-notes-4.4.0.rst
40 release-notes-4.4.0.rst
40 release-notes-4.3.1.rst
41 release-notes-4.3.1.rst
41 release-notes-4.3.0.rst
42 release-notes-4.3.0.rst
42 release-notes-4.2.1.rst
43 release-notes-4.2.1.rst
43 release-notes-4.2.0.rst
44 release-notes-4.2.0.rst
44 release-notes-4.1.2.rst
45 release-notes-4.1.2.rst
45 release-notes-4.1.1.rst
46 release-notes-4.1.1.rst
46 release-notes-4.1.0.rst
47 release-notes-4.1.0.rst
47 release-notes-4.0.1.rst
48 release-notes-4.0.1.rst
48 release-notes-4.0.0.rst
49 release-notes-4.0.0.rst
49
50
50 |RCE| 3.x Versions
51 |RCE| 3.x Versions
51 ------------------
52 ------------------
52
53
53 .. toctree::
54 .. toctree::
54 :maxdepth: 1
55 :maxdepth: 1
55
56
56 release-notes-3.8.4.rst
57 release-notes-3.8.4.rst
57 release-notes-3.8.3.rst
58 release-notes-3.8.3.rst
58 release-notes-3.8.2.rst
59 release-notes-3.8.2.rst
59 release-notes-3.8.1.rst
60 release-notes-3.8.1.rst
60 release-notes-3.8.0.rst
61 release-notes-3.8.0.rst
61 release-notes-3.7.1.rst
62 release-notes-3.7.1.rst
62 release-notes-3.7.0.rst
63 release-notes-3.7.0.rst
63 release-notes-3.6.1.rst
64 release-notes-3.6.1.rst
64 release-notes-3.6.0.rst
65 release-notes-3.6.0.rst
65 release-notes-3.5.2.rst
66 release-notes-3.5.2.rst
66 release-notes-3.5.1.rst
67 release-notes-3.5.1.rst
67 release-notes-3.5.0.rst
68 release-notes-3.5.0.rst
68 release-notes-3.4.1.rst
69 release-notes-3.4.1.rst
69 release-notes-3.4.0.rst
70 release-notes-3.4.0.rst
70 release-notes-3.3.4.rst
71 release-notes-3.3.4.rst
71 release-notes-3.3.3.rst
72 release-notes-3.3.3.rst
72 release-notes-3.3.2.rst
73 release-notes-3.3.2.rst
73 release-notes-3.3.1.rst
74 release-notes-3.3.1.rst
74 release-notes-3.3.0.rst
75 release-notes-3.3.0.rst
75 release-notes-3.2.3.rst
76 release-notes-3.2.3.rst
76 release-notes-3.2.2.rst
77 release-notes-3.2.2.rst
77 release-notes-3.2.1.rst
78 release-notes-3.2.1.rst
78 release-notes-3.2.0.rst
79 release-notes-3.2.0.rst
79 release-notes-3.1.1.rst
80 release-notes-3.1.1.rst
80 release-notes-3.1.0.rst
81 release-notes-3.1.0.rst
81 release-notes-3.0.2.rst
82 release-notes-3.0.2.rst
82 release-notes-3.0.1.rst
83 release-notes-3.0.1.rst
83 release-notes-3.0.0.rst
84 release-notes-3.0.0.rst
84
85
85 |RCE| 2.x Versions
86 |RCE| 2.x Versions
86 ------------------
87 ------------------
87
88
88 .. toctree::
89 .. toctree::
89 :maxdepth: 1
90 :maxdepth: 1
90
91
91 release-notes-2.2.8.rst
92 release-notes-2.2.8.rst
92 release-notes-2.2.7.rst
93 release-notes-2.2.7.rst
93 release-notes-2.2.6.rst
94 release-notes-2.2.6.rst
94 release-notes-2.2.5.rst
95 release-notes-2.2.5.rst
95 release-notes-2.2.4.rst
96 release-notes-2.2.4.rst
96 release-notes-2.2.3.rst
97 release-notes-2.2.3.rst
97 release-notes-2.2.2.rst
98 release-notes-2.2.2.rst
98 release-notes-2.2.1.rst
99 release-notes-2.2.1.rst
99 release-notes-2.2.0.rst
100 release-notes-2.2.0.rst
100 release-notes-2.1.0.rst
101 release-notes-2.1.0.rst
101 release-notes-2.0.2.rst
102 release-notes-2.0.2.rst
102 release-notes-2.0.1.rst
103 release-notes-2.0.1.rst
103 release-notes-2.0.0.rst
104 release-notes-2.0.0.rst
104
105
105 |RCE| 1.x Versions
106 |RCE| 1.x Versions
106 ------------------
107 ------------------
107
108
108 .. toctree::
109 .. toctree::
109 :maxdepth: 1
110 :maxdepth: 1
110
111
111 release-notes-1.7.2.rst
112 release-notes-1.7.2.rst
112 release-notes-1.7.1.rst
113 release-notes-1.7.1.rst
113 release-notes-1.7.0.rst
114 release-notes-1.7.0.rst
114 release-notes-1.6.0.rst
115 release-notes-1.6.0.rst
@@ -1,220 +1,220 b''
1 .. _hosted-solution:
1 .. _hosted-solution:
2
2
3 Deploy |RCE| From a Hosted Server
3 Deploy |RCE| From a Hosted Server
4 =================================
4 =================================
5
5
6 If you wish to deploy your own |RCE| instance from something like a
6 If you wish to deploy your own |RCE| instance from something like a
7 `Digital Ocean`_ droplet, or a `hetzner`_ server use the following
7 `Digital Ocean`_ droplet, or a `hetzner`_ server use the following
8 instructions to get it setup.
8 instructions to get it setup.
9
9
10 I'm using an Ubuntu 14.04 image for the purposes of this
10 I'm using an Ubuntu 14.04 image for the purposes of this
11 tutorial, but all other Unix environments will be pretty similar. You can
11 tutorial, but all other Unix environments will be pretty similar. You can
12 check out the full lists of supported platforms and versions in the
12 check out the full lists of supported platforms and versions in the
13 :ref:`system-overview-ref` section.
13 :ref:`system-overview-ref` section.
14
14
15
15
16 Create a Digital Ocean Droplet
16 Create a Digital Ocean Droplet
17 ------------------------------
17 ------------------------------
18
18
19 1. Sign into Digital Ocean.
19 1. Sign into Digital Ocean.
20 2. Create a Droplet choosing Ubuntu 14.04 as your |os|.
20 2. Create a Droplet choosing Ubuntu 14.04 as your |os|.
21 3. (Optional) Add SSH keys if you have them set up.
21 3. (Optional) Add SSH keys if you have them set up.
22
22
23 Configure Your Server
23 Configure Your Server
24 ---------------------
24 ---------------------
25
25
26 Once you have your server created, you need to sign into it and set it up to
26 Once you have your server created, you need to sign into it and set it up to
27 host |RCE|.
27 host |RCE|.
28
28
29 1. Open a terminal and sign into your server. Digital Ocean will mail you the
29 1. Open a terminal and sign into your server. Digital Ocean will mail you the
30 IP address. You'll need to change your password on the first login if you
30 IP address. You'll need to change your password on the first login if you
31 don not have SSH keys set up.
31 don not have SSH keys set up.
32
32
33 .. code-block:: bash
33 .. code-block:: bash
34
34
35 $ ssh root@203.0.113.113
35 $ ssh root@203.0.113.113
36
36
37 2. It is not advised to install |RCE| as the ``root`` user. So create a user
37 2. It is not advised to install |RCE| as the ``root`` user. So create a user
38 with sudo permissions and then carry out the rest of the steps from that user
38 with sudo permissions and then carry out the rest of the steps from that user
39 account.
39 account.
40
40
41 .. code-block:: bash
41 .. code-block:: bash
42
42
43 # Create a user with sudo permissions
43 # Create a user with sudo permissions
44 root@rhodecode:~# sudo useradd -m -s /bin/bash -d /home/brian -U brian
44 root@rhodecode:~# sudo useradd -m -s /bin/bash -d /home/brian -U brian
45 root@rhodecode:~# sudo usermod -a -G sudo brian
45 root@rhodecode:~# sudo usermod -a -G sudo brian
46
46
47 # Set the password for that user
47 # Set the password for that user
48 root@rhodecode:~# passwd brian
48 root@rhodecode:~# passwd brian
49 Enter new UNIX password:
49 Enter new UNIX password:
50 Retype new UNIX password:
50 Retype new UNIX password:
51 passwd: password updated successfully
51 passwd: password updated successfully
52
52
53 # Switch to that user for the rest of the steps
53 # Switch to that user for the rest of the steps
54 root@rhodecode:~# su brian
54 root@rhodecode:~# su brian
55
55
56 # You should see your home dir change to what was set during installation
56 # You should see your home dir change to what was set during installation
57 brian@rhodecode:~$ cd ~
57 brian@rhodecode:~$ cd ~
58 brian@rhodecode:~$ pwd
58 brian@rhodecode:~$ pwd
59 /home/brian
59 /home/brian
60
60
61 Once you have this set up, you are ready to install |RCC|.
61 Once you have this set up, you are ready to install |RCC|.
62
62
63 Install |RCC|
63 Install |RCC|
64 -------------
64 -------------
65
65
66 |RCC| will install and manage the package dependencies for your |RCE| instance.
66 |RCC| will install and manage the package dependencies for your |RCE| instance.
67
67
68 1. Download the |RCC| installer from https://rhodecode.com/download/
68 1. Download the |RCC| installer from https://rhodecode.com/download/
69 2. Once downloaded to your computer, transfer the package to your server
69 2. Once downloaded to your computer, transfer the package to your server
70
70
71 .. note::
71 .. note::
72
72
73 These steps happen on your computer, not on the server.
73 These steps happen on your computer, not on the server.
74
74
75 .. code-block:: bash
75 .. code-block:: bash
76
76
77 # Change to where the file is downloaded
77 # Change to where the file is downloaded
78 $ cd Downloads/
78 $ cd Downloads/
79
79
80 # SFTP to your server
80 # SFTP to your server
81 $ sftp brian@203.0.113.113
81 $ sftp brian@203.0.113.113
82
82
83 # Use mput to transfer the file
83 # Use mput to transfer the file
84 sftp> mput RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3
84 sftp> mput RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3
85 Uploading RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3 to /home/brian/RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3
85 Uploading RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3 to /home/brian/RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3
86 RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d 100% 289MB 4.1MB/s 01:11
86 RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d 100% 289MB 4.1MB/s 01:11
87 sftp> exit
87 sftp> exit
88
88
89 The |RCC| installer is now on your server, and you can read the full
89 The |RCC| installer is now on your server, and you can read the full
90 instructions here
90 instructions here
91 :ref:`Install RhodeCode Control <control:rcc-install-ref>`,
91 :ref:`Install RhodeCode Control <control:rcc-linux-ref>` ,
92 but below is the example shortcut.
92 but below is the example shortcut.
93
93
94 .. code-block:: bash
94 .. code-block:: bash
95
95
96 # Check that the script is uploaded to your home directory
96 # Check that the script is uploaded to your home directory
97 $ ls -1
97 $ ls -1
98 RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3
98 RhodeCode-installer-linux-391_b1a804c4d69b_d6c087d520e3
99
99
100 # Change the script permissions
100 # Change the script permissions
101 $ chmod 755 RhodeCode-installer-linux*
101 $ chmod 755 RhodeCode-installer-linux*
102
102
103 # Run the installer and accept the prompts
103 # Run the installer and accept the prompts
104 $ ./RhodeCode-installer-linux-*
104 $ ./RhodeCode-installer-linux-*
105
105
106 .. important::
106 .. important::
107
107
108 Once finished, exit the terminal and sign in again. This is to refresh you
108 Once finished, exit the terminal and sign in again. This is to refresh you
109 session to pick up the new commands.
109 session to pick up the new commands.
110
110
111 Install |RCE|
111 Install |RCE|
112 -------------
112 -------------
113
113
114 Now that |RCC| is installed, you can install |RCE|. For the full
114 Now that |RCC| is installed, you can install |RCE|. For the full
115 instructions, see
115 instructions, see
116 :ref:`Install RhodeCode Enterprise <control:rce-cli-install-ref>`,
116 :ref:`Install RhodeCode Enterprise <control:rce-cli-install-ref>`,
117 but the below is an example shortcut.
117 but the below is an example shortcut.
118
118
119 .. code-block:: bash
119 .. code-block:: bash
120
120
121 # Install a VCS Server and follow the prompts
121 # Install a VCS Server and follow the prompts
122 $ rccontrol install VCSServer --start-at-boot
122 $ rccontrol install VCSServer --start-at-boot
123
123
124 Extracting VCSServer ...
124 Extracting VCSServer ...
125 Configuring RhodeCode VCS Server ...
125 Configuring RhodeCode VCS Server ...
126 Supervisord state is: RUNNING
126 Supervisord state is: RUNNING
127 Added process group vcsserver-1
127 Added process group vcsserver-1
128
128
129 # Install a RhodeCode Enterprise instance and follow the prompts
129 # Install a RhodeCode Enterprise instance and follow the prompts
130 $ rccontrol install Enterprise --start-at-boot
130 $ rccontrol install Enterprise --start-at-boot
131
131
132 Configuration of RhodeCode Enterprise passed.
132 Configuration of RhodeCode Enterprise passed.
133 Supervisord state is: RUNNING
133 Supervisord state is: RUNNING
134 Added process group enterprise-1
134 Added process group enterprise-1
135
135
136 |RCE| is now installed on your server, and is running on the port displayed
136 |RCE| is now installed on your server, and is running on the port displayed
137 by the ``rccontrol status`` command.
137 by the ``rccontrol status`` command.
138
138
139 .. code-block:: bash
139 .. code-block:: bash
140
140
141 brian@rhodecode:~$ rccontrol status
141 brian@rhodecode:~$ rccontrol status
142
142
143 - NAME: enterprise-1
143 - NAME: enterprise-1
144 - STATUS: RUNNING
144 - STATUS: RUNNING
145 - TYPE: Enterprise
145 - TYPE: Enterprise
146 - VERSION: 3.1.1
146 - VERSION: 3.1.1
147 - URL: http://127.0.0.1:10002
147 - URL: http://127.0.0.1:10002
148
148
149 - NAME: vcsserver-1
149 - NAME: vcsserver-1
150 - STATUS: RUNNING
150 - STATUS: RUNNING
151 - TYPE: VCSServer
151 - TYPE: VCSServer
152 - VERSION: 1.1.1
152 - VERSION: 1.1.1
153 - URL: http://127.0.0.1:10001
153 - URL: http://127.0.0.1:10001
154
154
155 Serve |RCE| using Nginx
155 Serve |RCE| using Nginx
156 -----------------------
156 -----------------------
157
157
158 Now that |RCE| is running, you need to use Nginx or Apache to serve it to
158 Now that |RCE| is running, you need to use Nginx or Apache to serve it to
159 users. For detailed instructions about setting up your webserver, see the
159 users. For detailed instructions about setting up your webserver, see the
160 :ref:`rhodecode-admin-ref` section. But the below shortcut should help serve
160 :ref:`rhodecode-admin-ref` section. But the below shortcut should help serve
161 it.
161 it.
162
162
163 1. Install Nginx on your server.
163 1. Install Nginx on your server.
164
164
165 .. code-block:: bash
165 .. code-block:: bash
166
166
167 # Install nginx
167 # Install nginx
168 $ sudo apt-get install nginx
168 $ sudo apt-get install nginx
169
169
170 2. Create a virtual hosts file for RhodeCode Enterprise. Create
170 2. Create a virtual hosts file for RhodeCode Enterprise. Create
171 the file in this location :file:`/etc/nginx/sites-available`. In this demo
171 the file in this location :file:`/etc/nginx/sites-available`. In this demo
172 I have called it ``vcs.conf``
172 I have called it ``vcs.conf``
173
173
174 .. code-block:: bash
174 .. code-block:: bash
175
175
176 # Create the file
176 # Create the file
177 $ sudo vi /etc/nginx/sites-available/vcs.conf
177 $ sudo vi /etc/nginx/sites-available/vcs.conf
178
178
179 Use the following example to create yours.
179 Use the following example to create yours.
180
180
181 .. code-block:: nginx
181 .. code-block:: nginx
182
182
183 server {
183 server {
184 listen 80;
184 listen 80;
185 # Change to your IP, or a domain name if you've set that up
185 # Change to your IP, or a domain name if you've set that up
186 server_name 203.0.113.113 ;
186 server_name 203.0.113.113 ;
187
187
188 location / {
188 location / {
189 # Set this line to match the RhodeCode Enterprise Instance URL
189 # Set this line to match the RhodeCode Enterprise Instance URL
190 proxy_pass http://127.0.0.1:10002/;
190 proxy_pass http://127.0.0.1:10002/;
191 proxy_set_header Host $Host;
191 proxy_set_header Host $Host;
192 proxy_buffering off;
192 proxy_buffering off;
193 # Setting this to a high number allows large repo pushes
193 # Setting this to a high number allows large repo pushes
194 client_max_body_size 4G;
194 client_max_body_size 4G;
195 }
195 }
196 }
196 }
197
197
198 3. Symlink the virtual hosts file to the ``sites-enabled`` folder,
198 3. Symlink the virtual hosts file to the ``sites-enabled`` folder,
199 and then restart Nginx.
199 and then restart Nginx.
200
200
201 .. code-block:: bash
201 .. code-block:: bash
202
202
203 # Symlink the virtual hosts file
203 # Symlink the virtual hosts file
204 $ ln -s /etc/nginx/sites-available/vcs.conf /etc/nginx/sites-enabled/vcs.conf
204 $ ln -s /etc/nginx/sites-available/vcs.conf /etc/nginx/sites-enabled/vcs.conf
205
205
206 # You can also delete the Nginx default symlink
206 # You can also delete the Nginx default symlink
207 $ rm /etc/nginx/sites-enabled/default
207 $ rm /etc/nginx/sites-enabled/default
208
208
209 # Restart Nginx
209 # Restart Nginx
210 $ sudo /etc/init.d/nginx restart
210 $ sudo /etc/init.d/nginx restart
211 * Restarting nginx nginx [ OK ]
211 * Restarting nginx nginx [ OK ]
212
212
213 Once restarted, you should see a clean |RCE| instance running on the IP
213 Once restarted, you should see a clean |RCE| instance running on the IP
214 address, or the domain you have set up.
214 address, or the domain you have set up.
215
215
216 .. image:: ../images/clean-rce.png
216 .. image:: ../images/clean-rce.png
217 :alt: A fresh RhodeCode Enterprise Instance
217 :alt: A fresh RhodeCode Enterprise Instance
218
218
219 .. _Digital Ocean: https://www.digitalocean.com/
219 .. _Digital Ocean: https://www.digitalocean.com/
220 .. _hetzner: https://www.hetzner.de/en/
220 .. _hetzner: https://www.hetzner.de/en/
@@ -1,251 +1,257 b''
1 # Overrides for the generated python-packages.nix
1 # Overrides for the generated python-packages.nix
2 #
2 #
3 # This function is intended to be used as an extension to the generated file
3 # This function is intended to be used as an extension to the generated file
4 # python-packages.nix. The main objective is to add needed dependencies of C
4 # python-packages.nix. The main objective is to add needed dependencies of C
5 # libraries and tweak the build instructions where needed.
5 # libraries and tweak the build instructions where needed.
6
6
7 { pkgs, basePythonPackages }:
7 { pkgs, basePythonPackages }:
8
8
9 let
9 let
10 sed = "sed -i";
10 sed = "sed -i";
11 localLicenses = {
11 localLicenses = {
12 repoze = {
12 repoze = {
13 fullName = "Repoze License";
13 fullName = "Repoze License";
14 url = http://www.repoze.org/LICENSE.txt;
14 url = http://www.repoze.org/LICENSE.txt;
15 };
15 };
16 };
16 };
17
17
18 in
18 in
19
19
20 self: super: {
20 self: super: {
21
21
22 appenlight-client = super.appenlight-client.override (attrs: {
22 appenlight-client = super.appenlight-client.override (attrs: {
23 meta = {
23 meta = {
24 license = [ pkgs.lib.licenses.bsdOriginal ];
24 license = [ pkgs.lib.licenses.bsdOriginal ];
25 };
25 };
26 });
26 });
27
27
28 Beaker = super.Beaker.override (attrs: {
29 patches = [
30 ./patch-beaker-lock-func-debug.diff
31 ];
32 });
33
28 future = super.future.override (attrs: {
34 future = super.future.override (attrs: {
29 meta = {
35 meta = {
30 license = [ pkgs.lib.licenses.mit ];
36 license = [ pkgs.lib.licenses.mit ];
31 };
37 };
32 });
38 });
33
39
34 testpath = super.testpath.override (attrs: {
40 testpath = super.testpath.override (attrs: {
35 meta = {
41 meta = {
36 license = [ pkgs.lib.licenses.mit ];
42 license = [ pkgs.lib.licenses.mit ];
37 };
43 };
38 });
44 });
39
45
40 gnureadline = super.gnureadline.override (attrs: {
46 gnureadline = super.gnureadline.override (attrs: {
41 buildInputs = attrs.buildInputs ++ [
47 buildInputs = attrs.buildInputs ++ [
42 pkgs.ncurses
48 pkgs.ncurses
43 ];
49 ];
44 patchPhase = ''
50 patchPhase = ''
45 substituteInPlace setup.py --replace "/bin/bash" "${pkgs.bash}/bin/bash"
51 substituteInPlace setup.py --replace "/bin/bash" "${pkgs.bash}/bin/bash"
46 '';
52 '';
47 });
53 });
48
54
49 gunicorn = super.gunicorn.override (attrs: {
55 gunicorn = super.gunicorn.override (attrs: {
50 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
56 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
51 # johbo: futures is needed as long as we are on Python 2, otherwise
57 # johbo: futures is needed as long as we are on Python 2, otherwise
52 # gunicorn explodes if used with multiple threads per worker.
58 # gunicorn explodes if used with multiple threads per worker.
53 self.futures
59 self.futures
54 ];
60 ];
55 });
61 });
56
62
57 nbconvert = super.nbconvert.override (attrs: {
63 nbconvert = super.nbconvert.override (attrs: {
58 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
64 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
59 # marcink: plug in jupyter-client for notebook rendering
65 # marcink: plug in jupyter-client for notebook rendering
60 self.jupyter-client
66 self.jupyter-client
61 ];
67 ];
62 });
68 });
63
69
64 ipython = super.ipython.override (attrs: {
70 ipython = super.ipython.override (attrs: {
65 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
71 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
66 self.gnureadline
72 self.gnureadline
67 ];
73 ];
68 });
74 });
69
75
70 lxml = super.lxml.override (attrs: {
76 lxml = super.lxml.override (attrs: {
71 # johbo: On 16.09 we need this to compile on darwin, otherwise compilation
77 # johbo: On 16.09 we need this to compile on darwin, otherwise compilation
72 # fails on Darwin.
78 # fails on Darwin.
73 hardeningDisable = if pkgs.stdenv.isDarwin then [ "format" ] else null;
79 hardeningDisable = if pkgs.stdenv.isDarwin then [ "format" ] else null;
74 buildInputs = with self; [
80 buildInputs = with self; [
75 pkgs.libxml2
81 pkgs.libxml2
76 pkgs.libxslt
82 pkgs.libxslt
77 ];
83 ];
78 });
84 });
79
85
80 MySQL-python = super.MySQL-python.override (attrs: {
86 MySQL-python = super.MySQL-python.override (attrs: {
81 buildInputs = attrs.buildInputs ++ [
87 buildInputs = attrs.buildInputs ++ [
82 pkgs.openssl
88 pkgs.openssl
83 ];
89 ];
84 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
90 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
85 pkgs.mysql.lib
91 pkgs.libmysql
86 pkgs.zlib
92 pkgs.zlib
87 ];
93 ];
88 });
94 });
89
95
90 psutil = super.psutil.override (attrs: {
96 psutil = super.psutil.override (attrs: {
91 buildInputs = attrs.buildInputs ++
97 buildInputs = attrs.buildInputs ++
92 pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.darwin.IOKit;
98 pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.darwin.IOKit;
93 });
99 });
94
100
95 psycopg2 = super.psycopg2.override (attrs: {
101 psycopg2 = super.psycopg2.override (attrs: {
96 buildInputs = attrs.buildInputs ++
102 buildInputs = attrs.buildInputs ++
97 pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.openssl;
103 pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.openssl;
98 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
104 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
99 pkgs.postgresql
105 pkgs.postgresql
100 ];
106 ];
101 meta = {
107 meta = {
102 license = pkgs.lib.licenses.lgpl3Plus;
108 license = pkgs.lib.licenses.lgpl3Plus;
103 };
109 };
104 });
110 });
105
111
106 pycurl = super.pycurl.override (attrs: {
112 pycurl = super.pycurl.override (attrs: {
107 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
113 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
108 pkgs.curl
114 pkgs.curl
109 pkgs.openssl
115 pkgs.openssl
110 ];
116 ];
111 preConfigure = ''
117 preConfigure = ''
112 substituteInPlace setup.py --replace '--static-libs' '--libs'
118 substituteInPlace setup.py --replace '--static-libs' '--libs'
113 export PYCURL_SSL_LIBRARY=openssl
119 export PYCURL_SSL_LIBRARY=openssl
114 '';
120 '';
115 meta = {
121 meta = {
116 # TODO: It is LGPL and MIT
122 # TODO: It is LGPL and MIT
117 license = pkgs.lib.licenses.mit;
123 license = pkgs.lib.licenses.mit;
118 };
124 };
119 });
125 });
120
126
121 pyramid = super.pyramid.override (attrs: {
127 pyramid = super.pyramid.override (attrs: {
122 postFixup = ''
128 postFixup = ''
123 wrapPythonPrograms
129 wrapPythonPrograms
124 # TODO: johbo: "wrapPython" adds this magic line which
130 # TODO: johbo: "wrapPython" adds this magic line which
125 # confuses pserve.
131 # confuses pserve.
126 ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped
132 ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped
127 '';
133 '';
128 meta = {
134 meta = {
129 license = localLicenses.repoze;
135 license = localLicenses.repoze;
130 };
136 };
131 });
137 });
132
138
133 pyramid-debugtoolbar = super.pyramid-debugtoolbar.override (attrs: {
139 pyramid-debugtoolbar = super.pyramid-debugtoolbar.override (attrs: {
134 meta = {
140 meta = {
135 license = [ pkgs.lib.licenses.bsdOriginal localLicenses.repoze ];
141 license = [ pkgs.lib.licenses.bsdOriginal localLicenses.repoze ];
136 };
142 };
137 });
143 });
138
144
139 pysqlite = super.pysqlite.override (attrs: {
145 pysqlite = super.pysqlite.override (attrs: {
140 propagatedBuildInputs = [
146 propagatedBuildInputs = [
141 pkgs.sqlite
147 pkgs.sqlite
142 ];
148 ];
143 meta = {
149 meta = {
144 license = [ pkgs.lib.licenses.zlib pkgs.lib.licenses.libpng ];
150 license = [ pkgs.lib.licenses.zlib pkgs.lib.licenses.libpng ];
145 };
151 };
146 });
152 });
147
153
148 pytest-runner = super.pytest-runner.override (attrs: {
154 pytest-runner = super.pytest-runner.override (attrs: {
149 propagatedBuildInputs = [
155 propagatedBuildInputs = [
150 self.setuptools-scm
156 self.setuptools-scm
151 ];
157 ];
152 });
158 });
153
159
154 python-ldap = super.python-ldap.override (attrs: {
160 python-ldap = super.python-ldap.override (attrs: {
155 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
161 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
156 pkgs.cyrus_sasl
162 pkgs.cyrus_sasl
157 pkgs.openldap
163 pkgs.openldap
158 pkgs.openssl
164 pkgs.openssl
159 ];
165 ];
160 # TODO: johbo: Remove the "or" once we drop 16.03 support.
166 # TODO: johbo: Remove the "or" once we drop 16.03 support.
161 NIX_CFLAGS_COMPILE = "-I${pkgs.cyrus_sasl.dev or pkgs.cyrus_sasl}/include/sasl";
167 NIX_CFLAGS_COMPILE = "-I${pkgs.cyrus_sasl.dev or pkgs.cyrus_sasl}/include/sasl";
162 });
168 });
163
169
164 python-pam = super.python-pam.override (attrs:
170 python-pam = super.python-pam.override (attrs:
165 let
171 let
166 includeLibPam = pkgs.stdenv.isLinux;
172 includeLibPam = pkgs.stdenv.isLinux;
167 in {
173 in {
168 # TODO: johbo: Move the option up into the default.nix, we should
174 # TODO: johbo: Move the option up into the default.nix, we should
169 # include python-pam only on supported platforms.
175 # include python-pam only on supported platforms.
170 propagatedBuildInputs = attrs.propagatedBuildInputs ++
176 propagatedBuildInputs = attrs.propagatedBuildInputs ++
171 pkgs.lib.optional includeLibPam [
177 pkgs.lib.optional includeLibPam [
172 pkgs.pam
178 pkgs.pam
173 ];
179 ];
174 # TODO: johbo: Check if this can be avoided, or transform into
180 # TODO: johbo: Check if this can be avoided, or transform into
175 # a real patch
181 # a real patch
176 patchPhase = pkgs.lib.optionals includeLibPam ''
182 patchPhase = pkgs.lib.optionals includeLibPam ''
177 substituteInPlace pam.py \
183 substituteInPlace pam.py \
178 --replace 'find_library("pam")' '"${pkgs.pam}/lib/libpam.so.0"'
184 --replace 'find_library("pam")' '"${pkgs.pam}/lib/libpam.so.0"'
179 '';
185 '';
180 });
186 });
181
187
182 URLObject = super.URLObject.override (attrs: {
188 URLObject = super.URLObject.override (attrs: {
183 meta = {
189 meta = {
184 license = {
190 license = {
185 spdxId = "Unlicense";
191 spdxId = "Unlicense";
186 fullName = "The Unlicense";
192 fullName = "The Unlicense";
187 url = http://unlicense.org/;
193 url = http://unlicense.org/;
188 };
194 };
189 };
195 };
190 });
196 });
191
197
192 docutils = super.docutils.override (attrs: {
198 docutils = super.docutils.override (attrs: {
193 meta = {
199 meta = {
194 license = pkgs.lib.licenses.bsd2;
200 license = pkgs.lib.licenses.bsd2;
195 };
201 };
196 });
202 });
197
203
198 colander = super.colander.override (attrs: {
204 colander = super.colander.override (attrs: {
199 meta = {
205 meta = {
200 license = localLicenses.repoze;
206 license = localLicenses.repoze;
201 };
207 };
202 });
208 });
203
209
204 pyramid-beaker = super.pyramid-beaker.override (attrs: {
210 pyramid-beaker = super.pyramid-beaker.override (attrs: {
205 meta = {
211 meta = {
206 license = localLicenses.repoze;
212 license = localLicenses.repoze;
207 };
213 };
208 });
214 });
209
215
210 pyramid-mako = super.pyramid-mako.override (attrs: {
216 pyramid-mako = super.pyramid-mako.override (attrs: {
211 meta = {
217 meta = {
212 license = localLicenses.repoze;
218 license = localLicenses.repoze;
213 };
219 };
214 });
220 });
215
221
216 repoze.lru = super.repoze.lru.override (attrs: {
222 repoze.lru = super.repoze.lru.override (attrs: {
217 meta = {
223 meta = {
218 license = localLicenses.repoze;
224 license = localLicenses.repoze;
219 };
225 };
220 });
226 });
221
227
222 recaptcha-client = super.recaptcha-client.override (attrs: {
228 recaptcha-client = super.recaptcha-client.override (attrs: {
223 meta = {
229 meta = {
224 # TODO: It is MIT/X11
230 # TODO: It is MIT/X11
225 license = pkgs.lib.licenses.mit;
231 license = pkgs.lib.licenses.mit;
226 };
232 };
227 });
233 });
228
234
229 python-editor = super.python-editor.override (attrs: {
235 python-editor = super.python-editor.override (attrs: {
230 meta = {
236 meta = {
231 license = pkgs.lib.licenses.asl20;
237 license = pkgs.lib.licenses.asl20;
232 };
238 };
233 });
239 });
234
240
235 translationstring = super.translationstring.override (attrs: {
241 translationstring = super.translationstring.override (attrs: {
236 meta = {
242 meta = {
237 license = localLicenses.repoze;
243 license = localLicenses.repoze;
238 };
244 };
239 });
245 });
240
246
241 venusian = super.venusian.override (attrs: {
247 venusian = super.venusian.override (attrs: {
242 meta = {
248 meta = {
243 license = localLicenses.repoze;
249 license = localLicenses.repoze;
244 };
250 };
245 });
251 });
246
252
247 # Avoid that setuptools is replaced, this leads to trouble
253 # Avoid that setuptools is replaced, this leads to trouble
248 # with buildPythonPackage.
254 # with buildPythonPackage.
249 setuptools = basePythonPackages.setuptools;
255 setuptools = basePythonPackages.setuptools;
250
256
251 }
257 }
@@ -1,2086 +1,2099 b''
1 # Generated by pip2nix 0.4.0
1 # Generated by pip2nix 0.4.0
2 # See https://github.com/johbo/pip2nix
2 # See https://github.com/johbo/pip2nix
3
3
4 {
4 {
5 Babel = super.buildPythonPackage {
5 Babel = super.buildPythonPackage {
6 name = "Babel-1.3";
6 name = "Babel-1.3";
7 buildInputs = with self; [];
7 buildInputs = with self; [];
8 doCheck = false;
8 doCheck = false;
9 propagatedBuildInputs = with self; [pytz];
9 propagatedBuildInputs = with self; [pytz];
10 src = fetchurl {
10 src = fetchurl {
11 url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz";
11 url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz";
12 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
12 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
13 };
13 };
14 meta = {
14 meta = {
15 license = [ pkgs.lib.licenses.bsdOriginal ];
15 license = [ pkgs.lib.licenses.bsdOriginal ];
16 };
16 };
17 };
17 };
18 Beaker = super.buildPythonPackage {
18 Beaker = super.buildPythonPackage {
19 name = "Beaker-1.9.0";
19 name = "Beaker-1.9.1";
20 buildInputs = with self; [];
20 buildInputs = with self; [];
21 doCheck = false;
21 doCheck = false;
22 propagatedBuildInputs = with self; [funcsigs];
22 propagatedBuildInputs = with self; [funcsigs];
23 src = fetchurl {
23 src = fetchurl {
24 url = "https://pypi.python.org/packages/93/b2/12de6937b06e9615dbb3cb3a1c9af17f133f435bdef59f4ad42032b6eb49/Beaker-1.9.0.tar.gz";
24 url = "https://pypi.python.org/packages/ca/14/a626188d0d0c7b55dd7cf1902046c2743bd392a7078bb53073e13280eb1e/Beaker-1.9.1.tar.gz";
25 md5 = "38b3fcdfa24faf97c6cf66991eb54e9c";
25 md5 = "46fda0a164e2b0d24ccbda51a2310301";
26 };
26 };
27 meta = {
27 meta = {
28 license = [ pkgs.lib.licenses.bsdOriginal ];
28 license = [ pkgs.lib.licenses.bsdOriginal ];
29 };
29 };
30 };
30 };
31 CProfileV = super.buildPythonPackage {
31 CProfileV = super.buildPythonPackage {
32 name = "CProfileV-1.0.7";
32 name = "CProfileV-1.0.7";
33 buildInputs = with self; [];
33 buildInputs = with self; [];
34 doCheck = false;
34 doCheck = false;
35 propagatedBuildInputs = with self; [bottle];
35 propagatedBuildInputs = with self; [bottle];
36 src = fetchurl {
36 src = fetchurl {
37 url = "https://pypi.python.org/packages/df/50/d8c1ada7d537c64b0f76453fa31dedb6af6e27b82fcf0331e5f71a4cf98b/CProfileV-1.0.7.tar.gz";
37 url = "https://pypi.python.org/packages/df/50/d8c1ada7d537c64b0f76453fa31dedb6af6e27b82fcf0331e5f71a4cf98b/CProfileV-1.0.7.tar.gz";
38 md5 = "db4c7640438aa3d8887e194c81c7a019";
38 md5 = "db4c7640438aa3d8887e194c81c7a019";
39 };
39 };
40 meta = {
40 meta = {
41 license = [ pkgs.lib.licenses.mit ];
41 license = [ pkgs.lib.licenses.mit ];
42 };
42 };
43 };
43 };
44 Chameleon = super.buildPythonPackage {
44 Chameleon = super.buildPythonPackage {
45 name = "Chameleon-2.24";
45 name = "Chameleon-2.24";
46 buildInputs = with self; [];
46 buildInputs = with self; [];
47 doCheck = false;
47 doCheck = false;
48 propagatedBuildInputs = with self; [];
48 propagatedBuildInputs = with self; [];
49 src = fetchurl {
49 src = fetchurl {
50 url = "https://pypi.python.org/packages/5a/9e/637379ffa13c5172b5c0e704833ffea6bf51cec7567f93fd6e903d53ed74/Chameleon-2.24.tar.gz";
50 url = "https://pypi.python.org/packages/5a/9e/637379ffa13c5172b5c0e704833ffea6bf51cec7567f93fd6e903d53ed74/Chameleon-2.24.tar.gz";
51 md5 = "1b01f1f6533a8a11d0d2f2366dec5342";
51 md5 = "1b01f1f6533a8a11d0d2f2366dec5342";
52 };
52 };
53 meta = {
53 meta = {
54 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
54 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
55 };
55 };
56 };
56 };
57 FormEncode = super.buildPythonPackage {
57 FormEncode = super.buildPythonPackage {
58 name = "FormEncode-1.2.4";
58 name = "FormEncode-1.2.4";
59 buildInputs = with self; [];
59 buildInputs = with self; [];
60 doCheck = false;
60 doCheck = false;
61 propagatedBuildInputs = with self; [];
61 propagatedBuildInputs = with self; [];
62 src = fetchurl {
62 src = fetchurl {
63 url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz";
63 url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz";
64 md5 = "6bc17fb9aed8aea198975e888e2077f4";
64 md5 = "6bc17fb9aed8aea198975e888e2077f4";
65 };
65 };
66 meta = {
66 meta = {
67 license = [ pkgs.lib.licenses.psfl ];
67 license = [ pkgs.lib.licenses.psfl ];
68 };
68 };
69 };
69 };
70 Jinja2 = super.buildPythonPackage {
70 Jinja2 = super.buildPythonPackage {
71 name = "Jinja2-2.9.6";
71 name = "Jinja2-2.9.6";
72 buildInputs = with self; [];
72 buildInputs = with self; [];
73 doCheck = false;
73 doCheck = false;
74 propagatedBuildInputs = with self; [MarkupSafe];
74 propagatedBuildInputs = with self; [MarkupSafe];
75 src = fetchurl {
75 src = fetchurl {
76 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
76 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
77 md5 = "6411537324b4dba0956aaa8109f3c77b";
77 md5 = "6411537324b4dba0956aaa8109f3c77b";
78 };
78 };
79 meta = {
79 meta = {
80 license = [ pkgs.lib.licenses.bsdOriginal ];
80 license = [ pkgs.lib.licenses.bsdOriginal ];
81 };
81 };
82 };
82 };
83 Mako = super.buildPythonPackage {
83 Mako = super.buildPythonPackage {
84 name = "Mako-1.0.7";
84 name = "Mako-1.0.7";
85 buildInputs = with self; [];
85 buildInputs = with self; [];
86 doCheck = false;
86 doCheck = false;
87 propagatedBuildInputs = with self; [MarkupSafe];
87 propagatedBuildInputs = with self; [MarkupSafe];
88 src = fetchurl {
88 src = fetchurl {
89 url = "https://pypi.python.org/packages/eb/f3/67579bb486517c0d49547f9697e36582cd19dafb5df9e687ed8e22de57fa/Mako-1.0.7.tar.gz";
89 url = "https://pypi.python.org/packages/eb/f3/67579bb486517c0d49547f9697e36582cd19dafb5df9e687ed8e22de57fa/Mako-1.0.7.tar.gz";
90 md5 = "5836cc997b1b773ef389bf6629c30e65";
90 md5 = "5836cc997b1b773ef389bf6629c30e65";
91 };
91 };
92 meta = {
92 meta = {
93 license = [ pkgs.lib.licenses.mit ];
93 license = [ pkgs.lib.licenses.mit ];
94 };
94 };
95 };
95 };
96 Markdown = super.buildPythonPackage {
96 Markdown = super.buildPythonPackage {
97 name = "Markdown-2.6.9";
97 name = "Markdown-2.6.11";
98 buildInputs = with self; [];
98 buildInputs = with self; [];
99 doCheck = false;
99 doCheck = false;
100 propagatedBuildInputs = with self; [];
100 propagatedBuildInputs = with self; [];
101 src = fetchurl {
101 src = fetchurl {
102 url = "https://pypi.python.org/packages/29/82/dfe242bcfd9eec0e7bf93a80a8f8d8515a95b980c44f5c0b45606397a423/Markdown-2.6.9.tar.gz";
102 url = "https://pypi.python.org/packages/b3/73/fc5c850f44af5889192dff783b7b0d8f3fe8d30b65c8e3f78f8f0265fecf/Markdown-2.6.11.tar.gz";
103 md5 = "56547d362a9abcf30955b8950b08b5e3";
103 md5 = "a67c1b2914f7d74eeede2ebe0fdae470";
104 };
104 };
105 meta = {
105 meta = {
106 license = [ pkgs.lib.licenses.bsdOriginal ];
106 license = [ pkgs.lib.licenses.bsdOriginal ];
107 };
107 };
108 };
108 };
109 MarkupSafe = super.buildPythonPackage {
109 MarkupSafe = super.buildPythonPackage {
110 name = "MarkupSafe-1.0";
110 name = "MarkupSafe-1.0";
111 buildInputs = with self; [];
111 buildInputs = with self; [];
112 doCheck = false;
112 doCheck = false;
113 propagatedBuildInputs = with self; [];
113 propagatedBuildInputs = with self; [];
114 src = fetchurl {
114 src = fetchurl {
115 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
115 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
116 md5 = "2fcedc9284d50e577b5192e8e3578355";
116 md5 = "2fcedc9284d50e577b5192e8e3578355";
117 };
117 };
118 meta = {
118 meta = {
119 license = [ pkgs.lib.licenses.bsdOriginal ];
119 license = [ pkgs.lib.licenses.bsdOriginal ];
120 };
120 };
121 };
121 };
122 MySQL-python = super.buildPythonPackage {
122 MySQL-python = super.buildPythonPackage {
123 name = "MySQL-python-1.2.5";
123 name = "MySQL-python-1.2.5";
124 buildInputs = with self; [];
124 buildInputs = with self; [];
125 doCheck = false;
125 doCheck = false;
126 propagatedBuildInputs = with self; [];
126 propagatedBuildInputs = with self; [];
127 src = fetchurl {
127 src = fetchurl {
128 url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip";
128 url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip";
129 md5 = "654f75b302db6ed8dc5a898c625e030c";
129 md5 = "654f75b302db6ed8dc5a898c625e030c";
130 };
130 };
131 meta = {
131 meta = {
132 license = [ pkgs.lib.licenses.gpl1 ];
132 license = [ pkgs.lib.licenses.gpl1 ];
133 };
133 };
134 };
134 };
135 Paste = super.buildPythonPackage {
135 Paste = super.buildPythonPackage {
136 name = "Paste-2.0.3";
136 name = "Paste-2.0.3";
137 buildInputs = with self; [];
137 buildInputs = with self; [];
138 doCheck = false;
138 doCheck = false;
139 propagatedBuildInputs = with self; [six];
139 propagatedBuildInputs = with self; [six];
140 src = fetchurl {
140 src = fetchurl {
141 url = "https://pypi.python.org/packages/30/c3/5c2f7c7a02e4f58d4454353fa1c32c94f79fa4e36d07a67c0ac295ea369e/Paste-2.0.3.tar.gz";
141 url = "https://pypi.python.org/packages/30/c3/5c2f7c7a02e4f58d4454353fa1c32c94f79fa4e36d07a67c0ac295ea369e/Paste-2.0.3.tar.gz";
142 md5 = "1231e14eae62fa7ed76e9130b04bc61e";
142 md5 = "1231e14eae62fa7ed76e9130b04bc61e";
143 };
143 };
144 meta = {
144 meta = {
145 license = [ pkgs.lib.licenses.mit ];
145 license = [ pkgs.lib.licenses.mit ];
146 };
146 };
147 };
147 };
148 PasteDeploy = super.buildPythonPackage {
148 PasteDeploy = super.buildPythonPackage {
149 name = "PasteDeploy-1.5.2";
149 name = "PasteDeploy-1.5.2";
150 buildInputs = with self; [];
150 buildInputs = with self; [];
151 doCheck = false;
151 doCheck = false;
152 propagatedBuildInputs = with self; [];
152 propagatedBuildInputs = with self; [];
153 src = fetchurl {
153 src = fetchurl {
154 url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz";
154 url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz";
155 md5 = "352b7205c78c8de4987578d19431af3b";
155 md5 = "352b7205c78c8de4987578d19431af3b";
156 };
156 };
157 meta = {
157 meta = {
158 license = [ pkgs.lib.licenses.mit ];
158 license = [ pkgs.lib.licenses.mit ];
159 };
159 };
160 };
160 };
161 PasteScript = super.buildPythonPackage {
161 PasteScript = super.buildPythonPackage {
162 name = "PasteScript-2.0.2";
162 name = "PasteScript-2.0.2";
163 buildInputs = with self; [];
163 buildInputs = with self; [];
164 doCheck = false;
164 doCheck = false;
165 propagatedBuildInputs = with self; [Paste PasteDeploy six];
165 propagatedBuildInputs = with self; [Paste PasteDeploy six];
166 src = fetchurl {
166 src = fetchurl {
167 url = "https://pypi.python.org/packages/e5/f0/78e766c3dcc61a4f3a6f71dd8c95168ae9c7a31722b5663d19c1fdf62cb6/PasteScript-2.0.2.tar.gz";
167 url = "https://pypi.python.org/packages/e5/f0/78e766c3dcc61a4f3a6f71dd8c95168ae9c7a31722b5663d19c1fdf62cb6/PasteScript-2.0.2.tar.gz";
168 md5 = "ccb3045445097192ca71a13b746c77b2";
168 md5 = "ccb3045445097192ca71a13b746c77b2";
169 };
169 };
170 meta = {
170 meta = {
171 license = [ pkgs.lib.licenses.mit ];
171 license = [ pkgs.lib.licenses.mit ];
172 };
172 };
173 };
173 };
174 Pygments = super.buildPythonPackage {
174 Pygments = super.buildPythonPackage {
175 name = "Pygments-2.2.0";
175 name = "Pygments-2.2.0";
176 buildInputs = with self; [];
176 buildInputs = with self; [];
177 doCheck = false;
177 doCheck = false;
178 propagatedBuildInputs = with self; [];
178 propagatedBuildInputs = with self; [];
179 src = fetchurl {
179 src = fetchurl {
180 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
180 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
181 md5 = "13037baca42f16917cbd5ad2fab50844";
181 md5 = "13037baca42f16917cbd5ad2fab50844";
182 };
182 };
183 meta = {
183 meta = {
184 license = [ pkgs.lib.licenses.bsdOriginal ];
184 license = [ pkgs.lib.licenses.bsdOriginal ];
185 };
185 };
186 };
186 };
187 Routes = super.buildPythonPackage {
187 Routes = super.buildPythonPackage {
188 name = "Routes-2.4.1";
188 name = "Routes-2.4.1";
189 buildInputs = with self; [];
189 buildInputs = with self; [];
190 doCheck = false;
190 doCheck = false;
191 propagatedBuildInputs = with self; [six repoze.lru];
191 propagatedBuildInputs = with self; [six repoze.lru];
192 src = fetchurl {
192 src = fetchurl {
193 url = "https://pypi.python.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz";
193 url = "https://pypi.python.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz";
194 md5 = "c058dff6832941dec47e0d0052548ad8";
194 md5 = "c058dff6832941dec47e0d0052548ad8";
195 };
195 };
196 meta = {
196 meta = {
197 license = [ pkgs.lib.licenses.mit ];
197 license = [ pkgs.lib.licenses.mit ];
198 };
198 };
199 };
199 };
200 SQLAlchemy = super.buildPythonPackage {
200 SQLAlchemy = super.buildPythonPackage {
201 name = "SQLAlchemy-1.1.15";
201 name = "SQLAlchemy-1.1.15";
202 buildInputs = with self; [];
202 buildInputs = with self; [];
203 doCheck = false;
203 doCheck = false;
204 propagatedBuildInputs = with self; [];
204 propagatedBuildInputs = with self; [];
205 src = fetchurl {
205 src = fetchurl {
206 url = "https://pypi.python.org/packages/c2/f6/11fcc1ce19a7cb81b1c9377f4e27ce3813265611922e355905e57c44d164/SQLAlchemy-1.1.15.tar.gz";
206 url = "https://pypi.python.org/packages/c2/f6/11fcc1ce19a7cb81b1c9377f4e27ce3813265611922e355905e57c44d164/SQLAlchemy-1.1.15.tar.gz";
207 md5 = "077f9bd3339957f53068b5572a152674";
207 md5 = "077f9bd3339957f53068b5572a152674";
208 };
208 };
209 meta = {
209 meta = {
210 license = [ pkgs.lib.licenses.mit ];
210 license = [ pkgs.lib.licenses.mit ];
211 };
211 };
212 };
212 };
213 Tempita = super.buildPythonPackage {
213 Tempita = super.buildPythonPackage {
214 name = "Tempita-0.5.2";
214 name = "Tempita-0.5.2";
215 buildInputs = with self; [];
215 buildInputs = with self; [];
216 doCheck = false;
216 doCheck = false;
217 propagatedBuildInputs = with self; [];
217 propagatedBuildInputs = with self; [];
218 src = fetchurl {
218 src = fetchurl {
219 url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz";
219 url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz";
220 md5 = "4c2f17bb9d481821c41b6fbee904cea1";
220 md5 = "4c2f17bb9d481821c41b6fbee904cea1";
221 };
221 };
222 meta = {
222 meta = {
223 license = [ pkgs.lib.licenses.mit ];
223 license = [ pkgs.lib.licenses.mit ];
224 };
224 };
225 };
225 };
226 URLObject = super.buildPythonPackage {
226 URLObject = super.buildPythonPackage {
227 name = "URLObject-2.4.0";
227 name = "URLObject-2.4.0";
228 buildInputs = with self; [];
228 buildInputs = with self; [];
229 doCheck = false;
229 doCheck = false;
230 propagatedBuildInputs = with self; [];
230 propagatedBuildInputs = with self; [];
231 src = fetchurl {
231 src = fetchurl {
232 url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz";
232 url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz";
233 md5 = "2ed819738a9f0a3051f31dc9924e3065";
233 md5 = "2ed819738a9f0a3051f31dc9924e3065";
234 };
234 };
235 meta = {
235 meta = {
236 license = [ ];
236 license = [ ];
237 };
237 };
238 };
238 };
239 WebError = super.buildPythonPackage {
239 WebError = super.buildPythonPackage {
240 name = "WebError-0.10.3";
240 name = "WebError-0.10.3";
241 buildInputs = with self; [];
241 buildInputs = with self; [];
242 doCheck = false;
242 doCheck = false;
243 propagatedBuildInputs = with self; [WebOb Tempita Pygments Paste];
243 propagatedBuildInputs = with self; [WebOb Tempita Pygments Paste];
244 src = fetchurl {
244 src = fetchurl {
245 url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz";
245 url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz";
246 md5 = "84b9990b0baae6fd440b1e60cdd06f9a";
246 md5 = "84b9990b0baae6fd440b1e60cdd06f9a";
247 };
247 };
248 meta = {
248 meta = {
249 license = [ pkgs.lib.licenses.mit ];
249 license = [ pkgs.lib.licenses.mit ];
250 };
250 };
251 };
251 };
252 WebHelpers = super.buildPythonPackage {
252 WebHelpers = super.buildPythonPackage {
253 name = "WebHelpers-1.3";
253 name = "WebHelpers-1.3";
254 buildInputs = with self; [];
254 buildInputs = with self; [];
255 doCheck = false;
255 doCheck = false;
256 propagatedBuildInputs = with self; [MarkupSafe];
256 propagatedBuildInputs = with self; [MarkupSafe];
257 src = fetchurl {
257 src = fetchurl {
258 url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz";
258 url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz";
259 md5 = "32749ffadfc40fea51075a7def32588b";
259 md5 = "32749ffadfc40fea51075a7def32588b";
260 };
260 };
261 meta = {
261 meta = {
262 license = [ pkgs.lib.licenses.bsdOriginal ];
262 license = [ pkgs.lib.licenses.bsdOriginal ];
263 };
263 };
264 };
264 };
265 WebHelpers2 = super.buildPythonPackage {
265 WebHelpers2 = super.buildPythonPackage {
266 name = "WebHelpers2-2.0";
266 name = "WebHelpers2-2.0";
267 buildInputs = with self; [];
267 buildInputs = with self; [];
268 doCheck = false;
268 doCheck = false;
269 propagatedBuildInputs = with self; [MarkupSafe six];
269 propagatedBuildInputs = with self; [MarkupSafe six];
270 src = fetchurl {
270 src = fetchurl {
271 url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz";
271 url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz";
272 md5 = "0f6b68d70c12ee0aed48c00b24da13d3";
272 md5 = "0f6b68d70c12ee0aed48c00b24da13d3";
273 };
273 };
274 meta = {
274 meta = {
275 license = [ pkgs.lib.licenses.mit ];
275 license = [ pkgs.lib.licenses.mit ];
276 };
276 };
277 };
277 };
278 WebOb = super.buildPythonPackage {
278 WebOb = super.buildPythonPackage {
279 name = "WebOb-1.7.4";
279 name = "WebOb-1.7.4";
280 buildInputs = with self; [];
280 buildInputs = with self; [];
281 doCheck = false;
281 doCheck = false;
282 propagatedBuildInputs = with self; [];
282 propagatedBuildInputs = with self; [];
283 src = fetchurl {
283 src = fetchurl {
284 url = "https://pypi.python.org/packages/75/34/731e23f52371852dfe7490a61644826ba7fe70fd52a377aaca0f4956ba7f/WebOb-1.7.4.tar.gz";
284 url = "https://pypi.python.org/packages/75/34/731e23f52371852dfe7490a61644826ba7fe70fd52a377aaca0f4956ba7f/WebOb-1.7.4.tar.gz";
285 md5 = "397e46892d7f199b1a07eb20a2d3d9bd";
285 md5 = "397e46892d7f199b1a07eb20a2d3d9bd";
286 };
286 };
287 meta = {
287 meta = {
288 license = [ pkgs.lib.licenses.mit ];
288 license = [ pkgs.lib.licenses.mit ];
289 };
289 };
290 };
290 };
291 WebTest = super.buildPythonPackage {
291 WebTest = super.buildPythonPackage {
292 name = "WebTest-2.0.29";
292 name = "WebTest-2.0.29";
293 buildInputs = with self; [];
293 buildInputs = with self; [];
294 doCheck = false;
294 doCheck = false;
295 propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4];
295 propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4];
296 src = fetchurl {
296 src = fetchurl {
297 url = "https://pypi.python.org/packages/94/de/8f94738be649997da99c47b104aa3c3984ecec51a1d8153ed09638253d56/WebTest-2.0.29.tar.gz";
297 url = "https://pypi.python.org/packages/94/de/8f94738be649997da99c47b104aa3c3984ecec51a1d8153ed09638253d56/WebTest-2.0.29.tar.gz";
298 md5 = "30b4cf0d340b9a5335fac4389e6f84fc";
298 md5 = "30b4cf0d340b9a5335fac4389e6f84fc";
299 };
299 };
300 meta = {
300 meta = {
301 license = [ pkgs.lib.licenses.mit ];
301 license = [ pkgs.lib.licenses.mit ];
302 };
302 };
303 };
303 };
304 Whoosh = super.buildPythonPackage {
304 Whoosh = super.buildPythonPackage {
305 name = "Whoosh-2.7.4";
305 name = "Whoosh-2.7.4";
306 buildInputs = with self; [];
306 buildInputs = with self; [];
307 doCheck = false;
307 doCheck = false;
308 propagatedBuildInputs = with self; [];
308 propagatedBuildInputs = with self; [];
309 src = fetchurl {
309 src = fetchurl {
310 url = "https://pypi.python.org/packages/25/2b/6beed2107b148edc1321da0d489afc4617b9ed317ef7b72d4993cad9b684/Whoosh-2.7.4.tar.gz";
310 url = "https://pypi.python.org/packages/25/2b/6beed2107b148edc1321da0d489afc4617b9ed317ef7b72d4993cad9b684/Whoosh-2.7.4.tar.gz";
311 md5 = "c2710105f20b3e29936bd2357383c325";
311 md5 = "c2710105f20b3e29936bd2357383c325";
312 };
312 };
313 meta = {
313 meta = {
314 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ];
314 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ];
315 };
315 };
316 };
316 };
317 alembic = super.buildPythonPackage {
317 alembic = super.buildPythonPackage {
318 name = "alembic-0.9.6";
318 name = "alembic-0.9.8";
319 buildInputs = with self; [];
319 buildInputs = with self; [];
320 doCheck = false;
320 doCheck = false;
321 propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil];
321 propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil];
322 src = fetchurl {
322 src = fetchurl {
323 url = "https://pypi.python.org/packages/bf/b3/b28ea715824f8455635ece3c12f59d5d205f98cc378858e414e3aa6ebdbc/alembic-0.9.6.tar.gz";
323 url = "https://pypi.python.org/packages/a1/95/2252783859df9ec76b9a25d968c2827ed75a43ba34c6e8d38f87a5c0fb26/alembic-0.9.8.tar.gz";
324 md5 = "fcb096bccc87c8770bd07a04606cb989";
324 md5 = "5cfef58641c9a94d4a5d547e951a7dda";
325 };
325 };
326 meta = {
326 meta = {
327 license = [ pkgs.lib.licenses.mit ];
327 license = [ pkgs.lib.licenses.mit ];
328 };
328 };
329 };
329 };
330 amqp = super.buildPythonPackage {
330 amqp = super.buildPythonPackage {
331 name = "amqp-2.2.2";
331 name = "amqp-2.2.2";
332 buildInputs = with self; [];
332 buildInputs = with self; [];
333 doCheck = false;
333 doCheck = false;
334 propagatedBuildInputs = with self; [vine];
334 propagatedBuildInputs = with self; [vine];
335 src = fetchurl {
335 src = fetchurl {
336 url = "https://pypi.python.org/packages/e0/70/9ab9ccd8247fb7d2adb717e9f6a0ed358c9e1ab2c349048b0352f9e80ee2/amqp-2.2.2.tar.gz";
336 url = "https://pypi.python.org/packages/e0/70/9ab9ccd8247fb7d2adb717e9f6a0ed358c9e1ab2c349048b0352f9e80ee2/amqp-2.2.2.tar.gz";
337 md5 = "0971a3fd2d635ded45c349cfc17106bd";
337 md5 = "0971a3fd2d635ded45c349cfc17106bd";
338 };
338 };
339 meta = {
339 meta = {
340 license = [ pkgs.lib.licenses.bsdOriginal ];
340 license = [ pkgs.lib.licenses.bsdOriginal ];
341 };
341 };
342 };
342 };
343 appenlight-client = super.buildPythonPackage {
343 appenlight-client = super.buildPythonPackage {
344 name = "appenlight-client-0.6.22";
344 name = "appenlight-client-0.6.25";
345 buildInputs = with self; [];
345 buildInputs = with self; [];
346 doCheck = false;
346 doCheck = false;
347 propagatedBuildInputs = with self; [WebOb requests six];
347 propagatedBuildInputs = with self; [WebOb requests six];
348 src = fetchurl {
348 src = fetchurl {
349 url = "https://pypi.python.org/packages/73/37/0a64460fa9670b17c061adc433bc8be5079cba21e8b3a92d824adccb12bc/appenlight_client-0.6.22.tar.gz";
349 url = "https://pypi.python.org/packages/fa/44/2911ef85ea4f4fe65058fd22959d8dad598fab6a3c84e5bcb569d15c8783/appenlight_client-0.6.25.tar.gz";
350 md5 = "641afc114a9a3b3af4f75b11c70968ee";
350 md5 = "76dd2f9d42659fae8f290982078dc880";
351 };
351 };
352 meta = {
352 meta = {
353 license = [ pkgs.lib.licenses.bsdOriginal ];
353 license = [ pkgs.lib.licenses.bsdOriginal ];
354 };
354 };
355 };
355 };
356 authomatic = super.buildPythonPackage {
356 authomatic = super.buildPythonPackage {
357 name = "authomatic-0.1.0.post1";
357 name = "authomatic-0.1.0.post1";
358 buildInputs = with self; [];
358 buildInputs = with self; [];
359 doCheck = false;
359 doCheck = false;
360 propagatedBuildInputs = with self; [];
360 propagatedBuildInputs = with self; [];
361 src = fetchurl {
361 src = fetchurl {
362 url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz";
362 url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz";
363 md5 = "be3f3ce08747d776aae6d6cc8dcb49a9";
363 md5 = "be3f3ce08747d776aae6d6cc8dcb49a9";
364 };
364 };
365 meta = {
365 meta = {
366 license = [ pkgs.lib.licenses.mit ];
366 license = [ pkgs.lib.licenses.mit ];
367 };
367 };
368 };
368 };
369 backports.shutil-get-terminal-size = super.buildPythonPackage {
369 backports.shutil-get-terminal-size = super.buildPythonPackage {
370 name = "backports.shutil-get-terminal-size-1.0.0";
370 name = "backports.shutil-get-terminal-size-1.0.0";
371 buildInputs = with self; [];
371 buildInputs = with self; [];
372 doCheck = false;
372 doCheck = false;
373 propagatedBuildInputs = with self; [];
373 propagatedBuildInputs = with self; [];
374 src = fetchurl {
374 src = fetchurl {
375 url = "https://pypi.python.org/packages/ec/9c/368086faa9c016efce5da3e0e13ba392c9db79e3ab740b763fe28620b18b/backports.shutil_get_terminal_size-1.0.0.tar.gz";
375 url = "https://pypi.python.org/packages/ec/9c/368086faa9c016efce5da3e0e13ba392c9db79e3ab740b763fe28620b18b/backports.shutil_get_terminal_size-1.0.0.tar.gz";
376 md5 = "03267762480bd86b50580dc19dff3c66";
376 md5 = "03267762480bd86b50580dc19dff3c66";
377 };
377 };
378 meta = {
378 meta = {
379 license = [ pkgs.lib.licenses.mit ];
379 license = [ pkgs.lib.licenses.mit ];
380 };
380 };
381 };
381 };
382 beautifulsoup4 = super.buildPythonPackage {
382 beautifulsoup4 = super.buildPythonPackage {
383 name = "beautifulsoup4-4.6.0";
383 name = "beautifulsoup4-4.6.0";
384 buildInputs = with self; [];
384 buildInputs = with self; [];
385 doCheck = false;
385 doCheck = false;
386 propagatedBuildInputs = with self; [];
386 propagatedBuildInputs = with self; [];
387 src = fetchurl {
387 src = fetchurl {
388 url = "https://pypi.python.org/packages/fa/8d/1d14391fdaed5abada4e0f63543fef49b8331a34ca60c88bd521bcf7f782/beautifulsoup4-4.6.0.tar.gz";
388 url = "https://pypi.python.org/packages/fa/8d/1d14391fdaed5abada4e0f63543fef49b8331a34ca60c88bd521bcf7f782/beautifulsoup4-4.6.0.tar.gz";
389 md5 = "c17714d0f91a23b708a592cb3c697728";
389 md5 = "c17714d0f91a23b708a592cb3c697728";
390 };
390 };
391 meta = {
391 meta = {
392 license = [ pkgs.lib.licenses.mit ];
392 license = [ pkgs.lib.licenses.mit ];
393 };
393 };
394 };
394 };
395 billiard = super.buildPythonPackage {
395 billiard = super.buildPythonPackage {
396 name = "billiard-3.5.0.3";
396 name = "billiard-3.5.0.3";
397 buildInputs = with self; [];
397 buildInputs = with self; [];
398 doCheck = false;
398 doCheck = false;
399 propagatedBuildInputs = with self; [];
399 propagatedBuildInputs = with self; [];
400 src = fetchurl {
400 src = fetchurl {
401 url = "https://pypi.python.org/packages/39/ac/f5571210cca2e4f4532e38aaff242f26c8654c5e2436bee966c230647ccc/billiard-3.5.0.3.tar.gz";
401 url = "https://pypi.python.org/packages/39/ac/f5571210cca2e4f4532e38aaff242f26c8654c5e2436bee966c230647ccc/billiard-3.5.0.3.tar.gz";
402 md5 = "113ba481e48400adbf6fbbf59a2f8554";
402 md5 = "113ba481e48400adbf6fbbf59a2f8554";
403 };
403 };
404 meta = {
404 meta = {
405 license = [ pkgs.lib.licenses.bsdOriginal ];
405 license = [ pkgs.lib.licenses.bsdOriginal ];
406 };
406 };
407 };
407 };
408 bleach = super.buildPythonPackage {
408 bleach = super.buildPythonPackage {
409 name = "bleach-2.1.1";
409 name = "bleach-2.1.2";
410 buildInputs = with self; [];
410 buildInputs = with self; [];
411 doCheck = false;
411 doCheck = false;
412 propagatedBuildInputs = with self; [six html5lib];
412 propagatedBuildInputs = with self; [six html5lib];
413 src = fetchurl {
413 src = fetchurl {
414 url = "https://pypi.python.org/packages/d4/3f/d517089af35b01bb9bc4eac5ea04bae342b37a5e9abbb27b7c3ce0eae070/bleach-2.1.1.tar.gz";
414 url = "https://pypi.python.org/packages/b3/5f/0da670d30d3ffbc57cc97fa82947f81bbe3eab8d441e2d42e661f215baf2/bleach-2.1.2.tar.gz";
415 md5 = "7c5dfb1d66ea979b5a465afb12c82ec4";
415 md5 = "d0b14ae43a437ee0c650e04c6063eedd";
416 };
416 };
417 meta = {
417 meta = {
418 license = [ pkgs.lib.licenses.asl20 ];
418 license = [ pkgs.lib.licenses.asl20 ];
419 };
419 };
420 };
420 };
421 bottle = super.buildPythonPackage {
421 bottle = super.buildPythonPackage {
422 name = "bottle-0.12.13";
422 name = "bottle-0.12.13";
423 buildInputs = with self; [];
423 buildInputs = with self; [];
424 doCheck = false;
424 doCheck = false;
425 propagatedBuildInputs = with self; [];
425 propagatedBuildInputs = with self; [];
426 src = fetchurl {
426 src = fetchurl {
427 url = "https://pypi.python.org/packages/bd/99/04dc59ced52a8261ee0f965a8968717a255ea84a36013e527944dbf3468c/bottle-0.12.13.tar.gz";
427 url = "https://pypi.python.org/packages/bd/99/04dc59ced52a8261ee0f965a8968717a255ea84a36013e527944dbf3468c/bottle-0.12.13.tar.gz";
428 md5 = "d2fe1b48c1d49217e78bf326b1cad437";
428 md5 = "d2fe1b48c1d49217e78bf326b1cad437";
429 };
429 };
430 meta = {
430 meta = {
431 license = [ pkgs.lib.licenses.mit ];
431 license = [ pkgs.lib.licenses.mit ];
432 };
432 };
433 };
433 };
434 bumpversion = super.buildPythonPackage {
434 bumpversion = super.buildPythonPackage {
435 name = "bumpversion-0.5.3";
435 name = "bumpversion-0.5.3";
436 buildInputs = with self; [];
436 buildInputs = with self; [];
437 doCheck = false;
437 doCheck = false;
438 propagatedBuildInputs = with self; [];
438 propagatedBuildInputs = with self; [];
439 src = fetchurl {
439 src = fetchurl {
440 url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz";
440 url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz";
441 md5 = "c66a3492eafcf5ad4b024be9fca29820";
441 md5 = "c66a3492eafcf5ad4b024be9fca29820";
442 };
442 };
443 meta = {
443 meta = {
444 license = [ pkgs.lib.licenses.mit ];
444 license = [ pkgs.lib.licenses.mit ];
445 };
445 };
446 };
446 };
447 celery = super.buildPythonPackage {
447 celery = super.buildPythonPackage {
448 name = "celery-4.1.0";
448 name = "celery-4.1.0";
449 buildInputs = with self; [];
449 buildInputs = with self; [];
450 doCheck = false;
450 doCheck = false;
451 propagatedBuildInputs = with self; [pytz billiard kombu];
451 propagatedBuildInputs = with self; [pytz billiard kombu];
452 src = fetchurl {
452 src = fetchurl {
453 url = "https://pypi.python.org/packages/07/65/88a2a45fc80f487872c93121a701a53bbbc3d3d832016876fac84fc8d46a/celery-4.1.0.tar.gz";
453 url = "https://pypi.python.org/packages/07/65/88a2a45fc80f487872c93121a701a53bbbc3d3d832016876fac84fc8d46a/celery-4.1.0.tar.gz";
454 md5 = "db91e1d26936381127f01e150fe3054a";
454 md5 = "db91e1d26936381127f01e150fe3054a";
455 };
455 };
456 meta = {
456 meta = {
457 license = [ pkgs.lib.licenses.bsdOriginal ];
457 license = [ pkgs.lib.licenses.bsdOriginal ];
458 };
458 };
459 };
459 };
460 channelstream = super.buildPythonPackage {
460 channelstream = super.buildPythonPackage {
461 name = "channelstream-0.5.2";
461 name = "channelstream-0.5.2";
462 buildInputs = with self; [];
462 buildInputs = with self; [];
463 doCheck = false;
463 doCheck = false;
464 propagatedBuildInputs = with self; [gevent ws4py pyramid pyramid-jinja2 itsdangerous requests six];
464 propagatedBuildInputs = with self; [gevent ws4py pyramid pyramid-jinja2 itsdangerous requests six];
465 src = fetchurl {
465 src = fetchurl {
466 url = "https://pypi.python.org/packages/2b/31/29a8e085cf5bf97fa88e7b947adabfc581a18a3463adf77fb6dada34a65f/channelstream-0.5.2.tar.gz";
466 url = "https://pypi.python.org/packages/2b/31/29a8e085cf5bf97fa88e7b947adabfc581a18a3463adf77fb6dada34a65f/channelstream-0.5.2.tar.gz";
467 md5 = "1c5eb2a8a405be6f1073da94da6d81d3";
467 md5 = "1c5eb2a8a405be6f1073da94da6d81d3";
468 };
468 };
469 meta = {
469 meta = {
470 license = [ pkgs.lib.licenses.bsdOriginal ];
470 license = [ pkgs.lib.licenses.bsdOriginal ];
471 };
471 };
472 };
472 };
473 click = super.buildPythonPackage {
473 click = super.buildPythonPackage {
474 name = "click-6.6";
474 name = "click-6.6";
475 buildInputs = with self; [];
475 buildInputs = with self; [];
476 doCheck = false;
476 doCheck = false;
477 propagatedBuildInputs = with self; [];
477 propagatedBuildInputs = with self; [];
478 src = fetchurl {
478 src = fetchurl {
479 url = "https://pypi.python.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz";
479 url = "https://pypi.python.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz";
480 md5 = "d0b09582123605220ad6977175f3e51d";
480 md5 = "d0b09582123605220ad6977175f3e51d";
481 };
481 };
482 meta = {
482 meta = {
483 license = [ pkgs.lib.licenses.bsdOriginal ];
483 license = [ pkgs.lib.licenses.bsdOriginal ];
484 };
484 };
485 };
485 };
486 colander = super.buildPythonPackage {
486 colander = super.buildPythonPackage {
487 name = "colander-1.4";
487 name = "colander-1.4";
488 buildInputs = with self; [];
488 buildInputs = with self; [];
489 doCheck = false;
489 doCheck = false;
490 propagatedBuildInputs = with self; [translationstring iso8601];
490 propagatedBuildInputs = with self; [translationstring iso8601];
491 src = fetchurl {
491 src = fetchurl {
492 url = "https://pypi.python.org/packages/cc/e2/c4e716ac4a426d8ad4dfe306c34f0018a22275d2420815784005bf771c84/colander-1.4.tar.gz";
492 url = "https://pypi.python.org/packages/cc/e2/c4e716ac4a426d8ad4dfe306c34f0018a22275d2420815784005bf771c84/colander-1.4.tar.gz";
493 md5 = "cbb8e403c2ba05aeaa419d51fdb93736";
493 md5 = "cbb8e403c2ba05aeaa419d51fdb93736";
494 };
494 };
495 meta = {
495 meta = {
496 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
496 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
497 };
497 };
498 };
498 };
499 configobj = super.buildPythonPackage {
499 configobj = super.buildPythonPackage {
500 name = "configobj-5.0.6";
500 name = "configobj-5.0.6";
501 buildInputs = with self; [];
501 buildInputs = with self; [];
502 doCheck = false;
502 doCheck = false;
503 propagatedBuildInputs = with self; [six];
503 propagatedBuildInputs = with self; [six];
504 src = fetchurl {
504 src = fetchurl {
505 url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz";
505 url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz";
506 md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6";
506 md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6";
507 };
507 };
508 meta = {
508 meta = {
509 license = [ pkgs.lib.licenses.bsdOriginal ];
509 license = [ pkgs.lib.licenses.bsdOriginal ];
510 };
510 };
511 };
511 };
512 configparser = super.buildPythonPackage {
512 configparser = super.buildPythonPackage {
513 name = "configparser-3.5.0";
513 name = "configparser-3.5.0";
514 buildInputs = with self; [];
514 buildInputs = with self; [];
515 doCheck = false;
515 doCheck = false;
516 propagatedBuildInputs = with self; [];
516 propagatedBuildInputs = with self; [];
517 src = fetchurl {
517 src = fetchurl {
518 url = "https://pypi.python.org/packages/7c/69/c2ce7e91c89dc073eb1aa74c0621c3eefbffe8216b3f9af9d3885265c01c/configparser-3.5.0.tar.gz";
518 url = "https://pypi.python.org/packages/7c/69/c2ce7e91c89dc073eb1aa74c0621c3eefbffe8216b3f9af9d3885265c01c/configparser-3.5.0.tar.gz";
519 md5 = "cfdd915a5b7a6c09917a64a573140538";
519 md5 = "cfdd915a5b7a6c09917a64a573140538";
520 };
520 };
521 meta = {
521 meta = {
522 license = [ pkgs.lib.licenses.mit ];
522 license = [ pkgs.lib.licenses.mit ];
523 };
523 };
524 };
524 };
525 cov-core = super.buildPythonPackage {
525 cov-core = super.buildPythonPackage {
526 name = "cov-core-1.15.0";
526 name = "cov-core-1.15.0";
527 buildInputs = with self; [];
527 buildInputs = with self; [];
528 doCheck = false;
528 doCheck = false;
529 propagatedBuildInputs = with self; [coverage];
529 propagatedBuildInputs = with self; [coverage];
530 src = fetchurl {
530 src = fetchurl {
531 url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
531 url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
532 md5 = "f519d4cb4c4e52856afb14af52919fe6";
532 md5 = "f519d4cb4c4e52856afb14af52919fe6";
533 };
533 };
534 meta = {
534 meta = {
535 license = [ pkgs.lib.licenses.mit ];
535 license = [ pkgs.lib.licenses.mit ];
536 };
536 };
537 };
537 };
538 coverage = super.buildPythonPackage {
538 coverage = super.buildPythonPackage {
539 name = "coverage-3.7.1";
539 name = "coverage-3.7.1";
540 buildInputs = with self; [];
540 buildInputs = with self; [];
541 doCheck = false;
541 doCheck = false;
542 propagatedBuildInputs = with self; [];
542 propagatedBuildInputs = with self; [];
543 src = fetchurl {
543 src = fetchurl {
544 url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz";
544 url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz";
545 md5 = "c47b36ceb17eaff3ecfab3bcd347d0df";
545 md5 = "c47b36ceb17eaff3ecfab3bcd347d0df";
546 };
546 };
547 meta = {
547 meta = {
548 license = [ pkgs.lib.licenses.bsdOriginal ];
548 license = [ pkgs.lib.licenses.bsdOriginal ];
549 };
549 };
550 };
550 };
551 cssselect = super.buildPythonPackage {
551 cssselect = super.buildPythonPackage {
552 name = "cssselect-1.0.1";
552 name = "cssselect-1.0.1";
553 buildInputs = with self; [];
553 buildInputs = with self; [];
554 doCheck = false;
554 doCheck = false;
555 propagatedBuildInputs = with self; [];
555 propagatedBuildInputs = with self; [];
556 src = fetchurl {
556 src = fetchurl {
557 url = "https://pypi.python.org/packages/77/ff/9c865275cd19290feba56344eba570e719efb7ca5b34d67ed12b22ebbb0d/cssselect-1.0.1.tar.gz";
557 url = "https://pypi.python.org/packages/77/ff/9c865275cd19290feba56344eba570e719efb7ca5b34d67ed12b22ebbb0d/cssselect-1.0.1.tar.gz";
558 md5 = "3fa03bf82a9f0b1223c0f1eb1369e139";
558 md5 = "3fa03bf82a9f0b1223c0f1eb1369e139";
559 };
559 };
560 meta = {
560 meta = {
561 license = [ pkgs.lib.licenses.bsdOriginal ];
561 license = [ pkgs.lib.licenses.bsdOriginal ];
562 };
562 };
563 };
563 };
564 decorator = super.buildPythonPackage {
564 decorator = super.buildPythonPackage {
565 name = "decorator-4.1.2";
565 name = "decorator-4.1.2";
566 buildInputs = with self; [];
566 buildInputs = with self; [];
567 doCheck = false;
567 doCheck = false;
568 propagatedBuildInputs = with self; [];
568 propagatedBuildInputs = with self; [];
569 src = fetchurl {
569 src = fetchurl {
570 url = "https://pypi.python.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz";
570 url = "https://pypi.python.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz";
571 md5 = "a0f7f4fe00ae2dde93494d90c192cf8c";
571 md5 = "a0f7f4fe00ae2dde93494d90c192cf8c";
572 };
572 };
573 meta = {
573 meta = {
574 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
574 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
575 };
575 };
576 };
576 };
577 deform = super.buildPythonPackage {
577 deform = super.buildPythonPackage {
578 name = "deform-2.0.4";
578 name = "deform-2.0.4";
579 buildInputs = with self; [];
579 buildInputs = with self; [];
580 doCheck = false;
580 doCheck = false;
581 propagatedBuildInputs = with self; [Chameleon colander iso8601 peppercorn translationstring zope.deprecation];
581 propagatedBuildInputs = with self; [Chameleon colander iso8601 peppercorn translationstring zope.deprecation];
582 src = fetchurl {
582 src = fetchurl {
583 url = "https://pypi.python.org/packages/66/3b/eefcb07abcab7a97f6665aa2d0cf1af741d9d6e78a2e4657fd2b89f89880/deform-2.0.4.tar.gz";
583 url = "https://pypi.python.org/packages/66/3b/eefcb07abcab7a97f6665aa2d0cf1af741d9d6e78a2e4657fd2b89f89880/deform-2.0.4.tar.gz";
584 md5 = "34756e42cf50dd4b4430809116c4ec0a";
584 md5 = "34756e42cf50dd4b4430809116c4ec0a";
585 };
585 };
586 meta = {
586 meta = {
587 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
587 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
588 };
588 };
589 };
589 };
590 docutils = super.buildPythonPackage {
590 docutils = super.buildPythonPackage {
591 name = "docutils-0.14";
591 name = "docutils-0.14";
592 buildInputs = with self; [];
592 buildInputs = with self; [];
593 doCheck = false;
593 doCheck = false;
594 propagatedBuildInputs = with self; [];
594 propagatedBuildInputs = with self; [];
595 src = fetchurl {
595 src = fetchurl {
596 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
596 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
597 md5 = "c53768d63db3873b7d452833553469de";
597 md5 = "c53768d63db3873b7d452833553469de";
598 };
598 };
599 meta = {
599 meta = {
600 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.publicDomain pkgs.lib.licenses.gpl1 { fullName = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; } pkgs.lib.licenses.psfl ];
600 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.publicDomain pkgs.lib.licenses.gpl1 { fullName = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; } pkgs.lib.licenses.psfl ];
601 };
601 };
602 };
602 };
603 dogpile.cache = super.buildPythonPackage {
603 dogpile.cache = super.buildPythonPackage {
604 name = "dogpile.cache-0.6.4";
604 name = "dogpile.cache-0.6.4";
605 buildInputs = with self; [];
605 buildInputs = with self; [];
606 doCheck = false;
606 doCheck = false;
607 propagatedBuildInputs = with self; [];
607 propagatedBuildInputs = with self; [];
608 src = fetchurl {
608 src = fetchurl {
609 url = "https://pypi.python.org/packages/b6/3d/35c05ca01c070bb70d9d422f2c4858ecb021b05b21af438fec5ccd7b945c/dogpile.cache-0.6.4.tar.gz";
609 url = "https://pypi.python.org/packages/b6/3d/35c05ca01c070bb70d9d422f2c4858ecb021b05b21af438fec5ccd7b945c/dogpile.cache-0.6.4.tar.gz";
610 md5 = "66e0a6cae6c08cb1ea25f89d0eadfeb0";
610 md5 = "66e0a6cae6c08cb1ea25f89d0eadfeb0";
611 };
611 };
612 meta = {
612 meta = {
613 license = [ pkgs.lib.licenses.bsdOriginal ];
613 license = [ pkgs.lib.licenses.bsdOriginal ];
614 };
614 };
615 };
615 };
616 dogpile.core = super.buildPythonPackage {
616 dogpile.core = super.buildPythonPackage {
617 name = "dogpile.core-0.4.1";
617 name = "dogpile.core-0.4.1";
618 buildInputs = with self; [];
618 buildInputs = with self; [];
619 doCheck = false;
619 doCheck = false;
620 propagatedBuildInputs = with self; [];
620 propagatedBuildInputs = with self; [];
621 src = fetchurl {
621 src = fetchurl {
622 url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz";
622 url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz";
623 md5 = "01cb19f52bba3e95c9b560f39341f045";
623 md5 = "01cb19f52bba3e95c9b560f39341f045";
624 };
624 };
625 meta = {
625 meta = {
626 license = [ pkgs.lib.licenses.bsdOriginal ];
626 license = [ pkgs.lib.licenses.bsdOriginal ];
627 };
627 };
628 };
628 };
629 ecdsa = super.buildPythonPackage {
629 ecdsa = super.buildPythonPackage {
630 name = "ecdsa-0.13";
630 name = "ecdsa-0.13";
631 buildInputs = with self; [];
631 buildInputs = with self; [];
632 doCheck = false;
632 doCheck = false;
633 propagatedBuildInputs = with self; [];
633 propagatedBuildInputs = with self; [];
634 src = fetchurl {
634 src = fetchurl {
635 url = "https://pypi.python.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz";
635 url = "https://pypi.python.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz";
636 md5 = "1f60eda9cb5c46722856db41a3ae6670";
636 md5 = "1f60eda9cb5c46722856db41a3ae6670";
637 };
637 };
638 meta = {
638 meta = {
639 license = [ pkgs.lib.licenses.mit ];
639 license = [ pkgs.lib.licenses.mit ];
640 };
640 };
641 };
641 };
642 elasticsearch = super.buildPythonPackage {
642 elasticsearch = super.buildPythonPackage {
643 name = "elasticsearch-2.3.0";
643 name = "elasticsearch-2.3.0";
644 buildInputs = with self; [];
644 buildInputs = with self; [];
645 doCheck = false;
645 doCheck = false;
646 propagatedBuildInputs = with self; [urllib3];
646 propagatedBuildInputs = with self; [urllib3];
647 src = fetchurl {
647 src = fetchurl {
648 url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz";
648 url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz";
649 md5 = "2550f3b51629cf1ef9636608af92c340";
649 md5 = "2550f3b51629cf1ef9636608af92c340";
650 };
650 };
651 meta = {
651 meta = {
652 license = [ pkgs.lib.licenses.asl20 ];
652 license = [ pkgs.lib.licenses.asl20 ];
653 };
653 };
654 };
654 };
655 elasticsearch-dsl = super.buildPythonPackage {
655 elasticsearch-dsl = super.buildPythonPackage {
656 name = "elasticsearch-dsl-2.2.0";
656 name = "elasticsearch-dsl-2.2.0";
657 buildInputs = with self; [];
657 buildInputs = with self; [];
658 doCheck = false;
658 doCheck = false;
659 propagatedBuildInputs = with self; [six python-dateutil elasticsearch];
659 propagatedBuildInputs = with self; [six python-dateutil elasticsearch];
660 src = fetchurl {
660 src = fetchurl {
661 url = "https://pypi.python.org/packages/66/2f/52a086968788e58461641570f45c3207a52d46ebbe9b77dc22b6a8ffda66/elasticsearch-dsl-2.2.0.tar.gz";
661 url = "https://pypi.python.org/packages/66/2f/52a086968788e58461641570f45c3207a52d46ebbe9b77dc22b6a8ffda66/elasticsearch-dsl-2.2.0.tar.gz";
662 md5 = "fa6bd3c87ea3caa8f0f051bc37c53221";
662 md5 = "fa6bd3c87ea3caa8f0f051bc37c53221";
663 };
663 };
664 meta = {
664 meta = {
665 license = [ pkgs.lib.licenses.asl20 ];
665 license = [ pkgs.lib.licenses.asl20 ];
666 };
666 };
667 };
667 };
668 entrypoints = super.buildPythonPackage {
668 entrypoints = super.buildPythonPackage {
669 name = "entrypoints-0.2.2";
669 name = "entrypoints-0.2.2";
670 buildInputs = with self; [];
670 buildInputs = with self; [];
671 doCheck = false;
671 doCheck = false;
672 propagatedBuildInputs = with self; [configparser];
672 propagatedBuildInputs = with self; [configparser];
673 src = fetchurl {
673 src = fetchurl {
674 url = "https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313";
674 url = "https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313";
675 md5 = "7db37771aea9ac9fefe093e5d6987313";
675 md5 = "7db37771aea9ac9fefe093e5d6987313";
676 };
676 };
677 meta = {
677 meta = {
678 license = [ pkgs.lib.licenses.mit ];
678 license = [ pkgs.lib.licenses.mit ];
679 };
679 };
680 };
680 };
681 enum34 = super.buildPythonPackage {
681 enum34 = super.buildPythonPackage {
682 name = "enum34-1.1.6";
682 name = "enum34-1.1.6";
683 buildInputs = with self; [];
683 buildInputs = with self; [];
684 doCheck = false;
684 doCheck = false;
685 propagatedBuildInputs = with self; [];
685 propagatedBuildInputs = with self; [];
686 src = fetchurl {
686 src = fetchurl {
687 url = "https://pypi.python.org/packages/bf/3e/31d502c25302814a7c2f1d3959d2a3b3f78e509002ba91aea64993936876/enum34-1.1.6.tar.gz";
687 url = "https://pypi.python.org/packages/bf/3e/31d502c25302814a7c2f1d3959d2a3b3f78e509002ba91aea64993936876/enum34-1.1.6.tar.gz";
688 md5 = "5f13a0841a61f7fc295c514490d120d0";
688 md5 = "5f13a0841a61f7fc295c514490d120d0";
689 };
689 };
690 meta = {
690 meta = {
691 license = [ pkgs.lib.licenses.bsdOriginal ];
691 license = [ pkgs.lib.licenses.bsdOriginal ];
692 };
692 };
693 };
693 };
694 funcsigs = super.buildPythonPackage {
694 funcsigs = super.buildPythonPackage {
695 name = "funcsigs-1.0.2";
695 name = "funcsigs-1.0.2";
696 buildInputs = with self; [];
696 buildInputs = with self; [];
697 doCheck = false;
697 doCheck = false;
698 propagatedBuildInputs = with self; [];
698 propagatedBuildInputs = with self; [];
699 src = fetchurl {
699 src = fetchurl {
700 url = "https://pypi.python.org/packages/94/4a/db842e7a0545de1cdb0439bb80e6e42dfe82aaeaadd4072f2263a4fbed23/funcsigs-1.0.2.tar.gz";
700 url = "https://pypi.python.org/packages/94/4a/db842e7a0545de1cdb0439bb80e6e42dfe82aaeaadd4072f2263a4fbed23/funcsigs-1.0.2.tar.gz";
701 md5 = "7e583285b1fb8a76305d6d68f4ccc14e";
701 md5 = "7e583285b1fb8a76305d6d68f4ccc14e";
702 };
702 };
703 meta = {
703 meta = {
704 license = [ { fullName = "ASL"; } pkgs.lib.licenses.asl20 ];
704 license = [ { fullName = "ASL"; } pkgs.lib.licenses.asl20 ];
705 };
705 };
706 };
706 };
707 functools32 = super.buildPythonPackage {
707 functools32 = super.buildPythonPackage {
708 name = "functools32-3.2.3.post2";
708 name = "functools32-3.2.3.post2";
709 buildInputs = with self; [];
709 buildInputs = with self; [];
710 doCheck = false;
710 doCheck = false;
711 propagatedBuildInputs = with self; [];
711 propagatedBuildInputs = with self; [];
712 src = fetchurl {
712 src = fetchurl {
713 url = "https://pypi.python.org/packages/5e/1a/0aa2c8195a204a9f51284018562dea77e25511f02fe924fac202fc012172/functools32-3.2.3-2.zip";
713 url = "https://pypi.python.org/packages/c5/60/6ac26ad05857c601308d8fb9e87fa36d0ebf889423f47c3502ef034365db/functools32-3.2.3-2.tar.gz";
714 md5 = "d55232eb132ec779e6893c902a0bc5ad";
714 md5 = "09f24ffd9af9f6cd0f63cb9f4e23d4b2";
715 };
715 };
716 meta = {
716 meta = {
717 license = [ pkgs.lib.licenses.psfl ];
717 license = [ pkgs.lib.licenses.psfl ];
718 };
718 };
719 };
719 };
720 future = super.buildPythonPackage {
720 future = super.buildPythonPackage {
721 name = "future-0.14.3";
721 name = "future-0.14.3";
722 buildInputs = with self; [];
722 buildInputs = with self; [];
723 doCheck = false;
723 doCheck = false;
724 propagatedBuildInputs = with self; [];
724 propagatedBuildInputs = with self; [];
725 src = fetchurl {
725 src = fetchurl {
726 url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz";
726 url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz";
727 md5 = "e94079b0bd1fc054929e8769fc0f6083";
727 md5 = "e94079b0bd1fc054929e8769fc0f6083";
728 };
728 };
729 meta = {
729 meta = {
730 license = [ { fullName = "OSI Approved"; } pkgs.lib.licenses.mit ];
730 license = [ { fullName = "OSI Approved"; } pkgs.lib.licenses.mit ];
731 };
731 };
732 };
732 };
733 futures = super.buildPythonPackage {
733 futures = super.buildPythonPackage {
734 name = "futures-3.0.2";
734 name = "futures-3.0.2";
735 buildInputs = with self; [];
735 buildInputs = with self; [];
736 doCheck = false;
736 doCheck = false;
737 propagatedBuildInputs = with self; [];
737 propagatedBuildInputs = with self; [];
738 src = fetchurl {
738 src = fetchurl {
739 url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz";
739 url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz";
740 md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a";
740 md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a";
741 };
741 };
742 meta = {
742 meta = {
743 license = [ pkgs.lib.licenses.bsdOriginal ];
743 license = [ pkgs.lib.licenses.bsdOriginal ];
744 };
744 };
745 };
745 };
746 gevent = super.buildPythonPackage {
746 gevent = super.buildPythonPackage {
747 name = "gevent-1.2.2";
747 name = "gevent-1.2.2";
748 buildInputs = with self; [];
748 buildInputs = with self; [];
749 doCheck = false;
749 doCheck = false;
750 propagatedBuildInputs = with self; [greenlet];
750 propagatedBuildInputs = with self; [greenlet];
751 src = fetchurl {
751 src = fetchurl {
752 url = "https://pypi.python.org/packages/1b/92/b111f76e54d2be11375b47b213b56687214f258fd9dae703546d30b837be/gevent-1.2.2.tar.gz";
752 url = "https://pypi.python.org/packages/1b/92/b111f76e54d2be11375b47b213b56687214f258fd9dae703546d30b837be/gevent-1.2.2.tar.gz";
753 md5 = "7f0baf355384fe5ff2ecf66853422554";
753 md5 = "7f0baf355384fe5ff2ecf66853422554";
754 };
754 };
755 meta = {
755 meta = {
756 license = [ pkgs.lib.licenses.mit ];
756 license = [ pkgs.lib.licenses.mit ];
757 };
757 };
758 };
758 };
759 gnureadline = super.buildPythonPackage {
759 gnureadline = super.buildPythonPackage {
760 name = "gnureadline-6.3.8";
760 name = "gnureadline-6.3.8";
761 buildInputs = with self; [];
761 buildInputs = with self; [];
762 doCheck = false;
762 doCheck = false;
763 propagatedBuildInputs = with self; [];
763 propagatedBuildInputs = with self; [];
764 src = fetchurl {
764 src = fetchurl {
765 url = "https://pypi.python.org/packages/50/64/86085c823cd78f9df9d8e33dce0baa71618016f8860460b82cf6610e1eb3/gnureadline-6.3.8.tar.gz";
765 url = "https://pypi.python.org/packages/50/64/86085c823cd78f9df9d8e33dce0baa71618016f8860460b82cf6610e1eb3/gnureadline-6.3.8.tar.gz";
766 md5 = "ba341f4b907250bd1f47dbc06290604f";
766 md5 = "ba341f4b907250bd1f47dbc06290604f";
767 };
767 };
768 meta = {
768 meta = {
769 license = [ { fullName = "GNU General Public License v3 (GPLv3)"; } pkgs.lib.licenses.gpl1 ];
769 license = [ { fullName = "GNU General Public License v3 (GPLv3)"; } pkgs.lib.licenses.gpl1 ];
770 };
770 };
771 };
771 };
772 gprof2dot = super.buildPythonPackage {
772 gprof2dot = super.buildPythonPackage {
773 name = "gprof2dot-2017.9.19";
773 name = "gprof2dot-2017.9.19";
774 buildInputs = with self; [];
774 buildInputs = with self; [];
775 doCheck = false;
775 doCheck = false;
776 propagatedBuildInputs = with self; [];
776 propagatedBuildInputs = with self; [];
777 src = fetchurl {
777 src = fetchurl {
778 url = "https://pypi.python.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz";
778 url = "https://pypi.python.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz";
779 md5 = "cda2d552bb0d0b9f16e6824a9aabd225";
779 md5 = "cda2d552bb0d0b9f16e6824a9aabd225";
780 };
780 };
781 meta = {
781 meta = {
782 license = [ { fullName = "GNU Lesser General Public License v3 or later (LGPLv3+)"; } { fullName = "LGPL"; } ];
782 license = [ { fullName = "GNU Lesser General Public License v3 or later (LGPLv3+)"; } { fullName = "LGPL"; } ];
783 };
783 };
784 };
784 };
785 graphviz = super.buildPythonPackage {
785 graphviz = super.buildPythonPackage {
786 name = "graphviz-0.8.1";
786 name = "graphviz-0.8.2";
787 buildInputs = with self; [];
787 buildInputs = with self; [];
788 doCheck = false;
788 doCheck = false;
789 propagatedBuildInputs = with self; [];
789 propagatedBuildInputs = with self; [];
790 src = fetchurl {
790 src = fetchurl {
791 url = "https://pypi.python.org/packages/a9/a6/ee6721349489a2da6eedd3dba124f2b5ac15ee1e0a7bd4d3cfdc4fff0327/graphviz-0.8.1.zip";
791 url = "https://pypi.python.org/packages/fa/d1/63b62dee9e55368f60b5ea445e6afb361bb47e692fc27553f3672e16efb8/graphviz-0.8.2.zip";
792 md5 = "88d8efa88c02a735b3659fe0feaf0b96";
792 md5 = "50866e780f43e1cb0d073c70424fcaff";
793 };
793 };
794 meta = {
794 meta = {
795 license = [ pkgs.lib.licenses.mit ];
795 license = [ pkgs.lib.licenses.mit ];
796 };
796 };
797 };
797 };
798 greenlet = super.buildPythonPackage {
798 greenlet = super.buildPythonPackage {
799 name = "greenlet-0.4.12";
799 name = "greenlet-0.4.13";
800 buildInputs = with self; [];
800 buildInputs = with self; [];
801 doCheck = false;
801 doCheck = false;
802 propagatedBuildInputs = with self; [];
802 propagatedBuildInputs = with self; [];
803 src = fetchurl {
803 src = fetchurl {
804 url = "https://pypi.python.org/packages/be/76/82af375d98724054b7e273b5d9369346937324f9bcc20980b45b068ef0b0/greenlet-0.4.12.tar.gz";
804 url = "https://pypi.python.org/packages/13/de/ba92335e9e76040ca7274224942282a80d54f85e342a5e33c5277c7f87eb/greenlet-0.4.13.tar.gz";
805 md5 = "e8637647d58a26c4a1f51ca393e53c00";
805 md5 = "6e0b9dd5385f81d478451ec8ed1d62b3";
806 };
806 };
807 meta = {
807 meta = {
808 license = [ pkgs.lib.licenses.mit ];
808 license = [ pkgs.lib.licenses.mit ];
809 };
809 };
810 };
810 };
811 gunicorn = super.buildPythonPackage {
811 gunicorn = super.buildPythonPackage {
812 name = "gunicorn-19.7.1";
812 name = "gunicorn-19.7.1";
813 buildInputs = with self; [];
813 buildInputs = with self; [];
814 doCheck = false;
814 doCheck = false;
815 propagatedBuildInputs = with self; [];
815 propagatedBuildInputs = with self; [];
816 src = fetchurl {
816 src = fetchurl {
817 url = "https://pypi.python.org/packages/30/3a/10bb213cede0cc4d13ac2263316c872a64bf4c819000c8ccd801f1d5f822/gunicorn-19.7.1.tar.gz";
817 url = "https://pypi.python.org/packages/30/3a/10bb213cede0cc4d13ac2263316c872a64bf4c819000c8ccd801f1d5f822/gunicorn-19.7.1.tar.gz";
818 md5 = "174d3c3cd670a5be0404d84c484e590c";
818 md5 = "174d3c3cd670a5be0404d84c484e590c";
819 };
819 };
820 meta = {
820 meta = {
821 license = [ pkgs.lib.licenses.mit ];
821 license = [ pkgs.lib.licenses.mit ];
822 };
822 };
823 };
823 };
824 html5lib = super.buildPythonPackage {
824 html5lib = super.buildPythonPackage {
825 name = "html5lib-1.0b10";
825 name = "html5lib-1.0.1";
826 buildInputs = with self; [];
826 buildInputs = with self; [];
827 doCheck = false;
827 doCheck = false;
828 propagatedBuildInputs = with self; [six webencodings setuptools];
828 propagatedBuildInputs = with self; [six webencodings];
829 src = fetchurl {
829 src = fetchurl {
830 url = "https://pypi.python.org/packages/97/16/982214624095c1420c75f3bd295d9e658794aafb95fc075823de107e0ae4/html5lib-1.0b10.tar.gz";
830 url = "https://pypi.python.org/packages/85/3e/cf449cf1b5004e87510b9368e7a5f1acd8831c2d6691edd3c62a0823f98f/html5lib-1.0.1.tar.gz";
831 md5 = "5ada1243b7a863624b2f35245b2186e9";
831 md5 = "942a0688d6bdf20d087c9805c40182ad";
832 };
832 };
833 meta = {
833 meta = {
834 license = [ pkgs.lib.licenses.mit ];
834 license = [ pkgs.lib.licenses.mit ];
835 };
835 };
836 };
836 };
837 hupper = super.buildPythonPackage {
837 hupper = super.buildPythonPackage {
838 name = "hupper-1.0";
838 name = "hupper-1.0";
839 buildInputs = with self; [];
839 buildInputs = with self; [];
840 doCheck = false;
840 doCheck = false;
841 propagatedBuildInputs = with self; [];
841 propagatedBuildInputs = with self; [];
842 src = fetchurl {
842 src = fetchurl {
843 url = "https://pypi.python.org/packages/2e/07/df892c564dc09bb3cf6f6deb976c26adf9117db75ba218cb4353dbc9d826/hupper-1.0.tar.gz";
843 url = "https://pypi.python.org/packages/2e/07/df892c564dc09bb3cf6f6deb976c26adf9117db75ba218cb4353dbc9d826/hupper-1.0.tar.gz";
844 md5 = "26e77da7d5ac5858f59af050d1a6eb5a";
844 md5 = "26e77da7d5ac5858f59af050d1a6eb5a";
845 };
845 };
846 meta = {
846 meta = {
847 license = [ pkgs.lib.licenses.mit ];
847 license = [ pkgs.lib.licenses.mit ];
848 };
848 };
849 };
849 };
850 infrae.cache = super.buildPythonPackage {
850 infrae.cache = super.buildPythonPackage {
851 name = "infrae.cache-1.0.1";
851 name = "infrae.cache-1.0.1";
852 buildInputs = with self; [];
852 buildInputs = with self; [];
853 doCheck = false;
853 doCheck = false;
854 propagatedBuildInputs = with self; [Beaker repoze.lru];
854 propagatedBuildInputs = with self; [Beaker repoze.lru];
855 src = fetchurl {
855 src = fetchurl {
856 url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz";
856 url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz";
857 md5 = "b09076a766747e6ed2a755cc62088e32";
857 md5 = "b09076a766747e6ed2a755cc62088e32";
858 };
858 };
859 meta = {
859 meta = {
860 license = [ pkgs.lib.licenses.zpt21 ];
860 license = [ pkgs.lib.licenses.zpt21 ];
861 };
861 };
862 };
862 };
863 invoke = super.buildPythonPackage {
863 invoke = super.buildPythonPackage {
864 name = "invoke-0.13.0";
864 name = "invoke-0.13.0";
865 buildInputs = with self; [];
865 buildInputs = with self; [];
866 doCheck = false;
866 doCheck = false;
867 propagatedBuildInputs = with self; [];
867 propagatedBuildInputs = with self; [];
868 src = fetchurl {
868 src = fetchurl {
869 url = "https://pypi.python.org/packages/47/bf/d07ef52fa1ac645468858bbac7cb95b246a972a045e821493d17d89c81be/invoke-0.13.0.tar.gz";
869 url = "https://pypi.python.org/packages/47/bf/d07ef52fa1ac645468858bbac7cb95b246a972a045e821493d17d89c81be/invoke-0.13.0.tar.gz";
870 md5 = "c0d1ed4bfb34eaab551662d8cfee6540";
870 md5 = "c0d1ed4bfb34eaab551662d8cfee6540";
871 };
871 };
872 meta = {
872 meta = {
873 license = [ pkgs.lib.licenses.bsdOriginal ];
873 license = [ pkgs.lib.licenses.bsdOriginal ];
874 };
874 };
875 };
875 };
876 ipaddress = super.buildPythonPackage {
876 ipaddress = super.buildPythonPackage {
877 name = "ipaddress-1.0.18";
877 name = "ipaddress-1.0.19";
878 buildInputs = with self; [];
878 buildInputs = with self; [];
879 doCheck = false;
879 doCheck = false;
880 propagatedBuildInputs = with self; [];
880 propagatedBuildInputs = with self; [];
881 src = fetchurl {
881 src = fetchurl {
882 url = "https://pypi.python.org/packages/4e/13/774faf38b445d0b3a844b65747175b2e0500164b7c28d78e34987a5bfe06/ipaddress-1.0.18.tar.gz";
882 url = "https://pypi.python.org/packages/f0/ba/860a4a3e283456d6b7e2ab39ce5cf11a3490ee1a363652ac50abf9f0f5df/ipaddress-1.0.19.tar.gz";
883 md5 = "310c2dfd64eb6f0df44aa8c59f2334a7";
883 md5 = "d0687efaf93a32476d81e90ba0609c57";
884 };
884 };
885 meta = {
885 meta = {
886 license = [ pkgs.lib.licenses.psfl ];
886 license = [ pkgs.lib.licenses.psfl ];
887 };
887 };
888 };
888 };
889 ipdb = super.buildPythonPackage {
889 ipdb = super.buildPythonPackage {
890 name = "ipdb-0.10.3";
890 name = "ipdb-0.10.3";
891 buildInputs = with self; [];
891 buildInputs = with self; [];
892 doCheck = false;
892 doCheck = false;
893 propagatedBuildInputs = with self; [setuptools ipython];
893 propagatedBuildInputs = with self; [setuptools ipython];
894 src = fetchurl {
894 src = fetchurl {
895 url = "https://pypi.python.org/packages/ad/cc/0e7298e1fbf2efd52667c9354a12aa69fb6f796ce230cca03525051718ef/ipdb-0.10.3.tar.gz";
895 url = "https://pypi.python.org/packages/ad/cc/0e7298e1fbf2efd52667c9354a12aa69fb6f796ce230cca03525051718ef/ipdb-0.10.3.tar.gz";
896 md5 = "def1f6ac075d54bdee07e6501263d4fa";
896 md5 = "def1f6ac075d54bdee07e6501263d4fa";
897 };
897 };
898 meta = {
898 meta = {
899 license = [ pkgs.lib.licenses.bsdOriginal ];
899 license = [ pkgs.lib.licenses.bsdOriginal ];
900 };
900 };
901 };
901 };
902 ipython = super.buildPythonPackage {
902 ipython = super.buildPythonPackage {
903 name = "ipython-5.1.0";
903 name = "ipython-5.1.0";
904 buildInputs = with self; [];
904 buildInputs = with self; [];
905 doCheck = false;
905 doCheck = false;
906 propagatedBuildInputs = with self; [setuptools decorator pickleshare simplegeneric traitlets prompt-toolkit Pygments pexpect backports.shutil-get-terminal-size pathlib2 pexpect];
906 propagatedBuildInputs = with self; [setuptools decorator pickleshare simplegeneric traitlets prompt-toolkit Pygments pexpect backports.shutil-get-terminal-size pathlib2 pexpect];
907 src = fetchurl {
907 src = fetchurl {
908 url = "https://pypi.python.org/packages/89/63/a9292f7cd9d0090a0f995e1167f3f17d5889dcbc9a175261719c513b9848/ipython-5.1.0.tar.gz";
908 url = "https://pypi.python.org/packages/89/63/a9292f7cd9d0090a0f995e1167f3f17d5889dcbc9a175261719c513b9848/ipython-5.1.0.tar.gz";
909 md5 = "47c8122420f65b58784cb4b9b4af35e3";
909 md5 = "47c8122420f65b58784cb4b9b4af35e3";
910 };
910 };
911 meta = {
911 meta = {
912 license = [ pkgs.lib.licenses.bsdOriginal ];
912 license = [ pkgs.lib.licenses.bsdOriginal ];
913 };
913 };
914 };
914 };
915 ipython-genutils = super.buildPythonPackage {
915 ipython-genutils = super.buildPythonPackage {
916 name = "ipython-genutils-0.2.0";
916 name = "ipython-genutils-0.2.0";
917 buildInputs = with self; [];
917 buildInputs = with self; [];
918 doCheck = false;
918 doCheck = false;
919 propagatedBuildInputs = with self; [];
919 propagatedBuildInputs = with self; [];
920 src = fetchurl {
920 src = fetchurl {
921 url = "https://pypi.python.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz";
921 url = "https://pypi.python.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz";
922 md5 = "5a4f9781f78466da0ea1a648f3e1f79f";
922 md5 = "5a4f9781f78466da0ea1a648f3e1f79f";
923 };
923 };
924 meta = {
924 meta = {
925 license = [ pkgs.lib.licenses.bsdOriginal ];
925 license = [ pkgs.lib.licenses.bsdOriginal ];
926 };
926 };
927 };
927 };
928 iso8601 = super.buildPythonPackage {
928 iso8601 = super.buildPythonPackage {
929 name = "iso8601-0.1.12";
929 name = "iso8601-0.1.12";
930 buildInputs = with self; [];
930 buildInputs = with self; [];
931 doCheck = false;
931 doCheck = false;
932 propagatedBuildInputs = with self; [];
932 propagatedBuildInputs = with self; [];
933 src = fetchurl {
933 src = fetchurl {
934 url = "https://pypi.python.org/packages/45/13/3db24895497345fb44c4248c08b16da34a9eb02643cea2754b21b5ed08b0/iso8601-0.1.12.tar.gz";
934 url = "https://pypi.python.org/packages/45/13/3db24895497345fb44c4248c08b16da34a9eb02643cea2754b21b5ed08b0/iso8601-0.1.12.tar.gz";
935 md5 = "4de940f691c5ea759fb254384c8ddcf6";
935 md5 = "4de940f691c5ea759fb254384c8ddcf6";
936 };
936 };
937 meta = {
937 meta = {
938 license = [ pkgs.lib.licenses.mit ];
938 license = [ pkgs.lib.licenses.mit ];
939 };
939 };
940 };
940 };
941 itsdangerous = super.buildPythonPackage {
941 itsdangerous = super.buildPythonPackage {
942 name = "itsdangerous-0.24";
942 name = "itsdangerous-0.24";
943 buildInputs = with self; [];
943 buildInputs = with self; [];
944 doCheck = false;
944 doCheck = false;
945 propagatedBuildInputs = with self; [];
945 propagatedBuildInputs = with self; [];
946 src = fetchurl {
946 src = fetchurl {
947 url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz";
947 url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz";
948 md5 = "a3d55aa79369aef5345c036a8a26307f";
948 md5 = "a3d55aa79369aef5345c036a8a26307f";
949 };
949 };
950 meta = {
950 meta = {
951 license = [ pkgs.lib.licenses.bsdOriginal ];
951 license = [ pkgs.lib.licenses.bsdOriginal ];
952 };
952 };
953 };
953 };
954 jsonschema = super.buildPythonPackage {
954 jsonschema = super.buildPythonPackage {
955 name = "jsonschema-2.6.0";
955 name = "jsonschema-2.6.0";
956 buildInputs = with self; [];
956 buildInputs = with self; [];
957 doCheck = false;
957 doCheck = false;
958 propagatedBuildInputs = with self; [functools32];
958 propagatedBuildInputs = with self; [functools32];
959 src = fetchurl {
959 src = fetchurl {
960 url = "https://pypi.python.org/packages/58/b9/171dbb07e18c6346090a37f03c7e74410a1a56123f847efed59af260a298/jsonschema-2.6.0.tar.gz";
960 url = "https://pypi.python.org/packages/58/b9/171dbb07e18c6346090a37f03c7e74410a1a56123f847efed59af260a298/jsonschema-2.6.0.tar.gz";
961 md5 = "50c6b69a373a8b55ff1e0ec6e78f13f4";
961 md5 = "50c6b69a373a8b55ff1e0ec6e78f13f4";
962 };
962 };
963 meta = {
963 meta = {
964 license = [ pkgs.lib.licenses.mit ];
964 license = [ pkgs.lib.licenses.mit ];
965 };
965 };
966 };
966 };
967 jupyter-client = super.buildPythonPackage {
967 jupyter-client = super.buildPythonPackage {
968 name = "jupyter-client-5.0.0";
968 name = "jupyter-client-5.0.0";
969 buildInputs = with self; [];
969 buildInputs = with self; [];
970 doCheck = false;
970 doCheck = false;
971 propagatedBuildInputs = with self; [traitlets jupyter-core pyzmq python-dateutil];
971 propagatedBuildInputs = with self; [traitlets jupyter-core pyzmq python-dateutil];
972 src = fetchurl {
972 src = fetchurl {
973 url = "https://pypi.python.org/packages/e5/6f/65412ed462202b90134b7e761b0b7e7f949e07a549c1755475333727b3d0/jupyter_client-5.0.0.tar.gz";
973 url = "https://pypi.python.org/packages/e5/6f/65412ed462202b90134b7e761b0b7e7f949e07a549c1755475333727b3d0/jupyter_client-5.0.0.tar.gz";
974 md5 = "1acd331b5c9fb4d79dae9939e79f2426";
974 md5 = "1acd331b5c9fb4d79dae9939e79f2426";
975 };
975 };
976 meta = {
976 meta = {
977 license = [ pkgs.lib.licenses.bsdOriginal ];
977 license = [ pkgs.lib.licenses.bsdOriginal ];
978 };
978 };
979 };
979 };
980 jupyter-core = super.buildPythonPackage {
980 jupyter-core = super.buildPythonPackage {
981 name = "jupyter-core-4.4.0";
981 name = "jupyter-core-4.4.0";
982 buildInputs = with self; [];
982 buildInputs = with self; [];
983 doCheck = false;
983 doCheck = false;
984 propagatedBuildInputs = with self; [traitlets];
984 propagatedBuildInputs = with self; [traitlets];
985 src = fetchurl {
985 src = fetchurl {
986 url = "https://pypi.python.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
986 url = "https://pypi.python.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
987 md5 = "7829fc07884ed98459e170f217e2a5ba";
987 md5 = "7829fc07884ed98459e170f217e2a5ba";
988 };
988 };
989 meta = {
989 meta = {
990 license = [ pkgs.lib.licenses.bsdOriginal ];
990 license = [ pkgs.lib.licenses.bsdOriginal ];
991 };
991 };
992 };
992 };
993 kombu = super.buildPythonPackage {
993 kombu = super.buildPythonPackage {
994 name = "kombu-4.1.0";
994 name = "kombu-4.1.0";
995 buildInputs = with self; [];
995 buildInputs = with self; [];
996 doCheck = false;
996 doCheck = false;
997 propagatedBuildInputs = with self; [amqp];
997 propagatedBuildInputs = with self; [amqp];
998 src = fetchurl {
998 src = fetchurl {
999 url = "https://pypi.python.org/packages/03/5e/1a47d1e543d4943d65330af4e4406049f443878818fb65bfdc651bb93a96/kombu-4.1.0.tar.gz";
999 url = "https://pypi.python.org/packages/03/5e/1a47d1e543d4943d65330af4e4406049f443878818fb65bfdc651bb93a96/kombu-4.1.0.tar.gz";
1000 md5 = "2fb2be9fec0e6514231bba23a3779439";
1000 md5 = "2fb2be9fec0e6514231bba23a3779439";
1001 };
1001 };
1002 meta = {
1002 meta = {
1003 license = [ pkgs.lib.licenses.bsdOriginal ];
1003 license = [ pkgs.lib.licenses.bsdOriginal ];
1004 };
1004 };
1005 };
1005 };
1006 lxml = super.buildPythonPackage {
1006 lxml = super.buildPythonPackage {
1007 name = "lxml-3.7.3";
1007 name = "lxml-3.7.3";
1008 buildInputs = with self; [];
1008 buildInputs = with self; [];
1009 doCheck = false;
1009 doCheck = false;
1010 propagatedBuildInputs = with self; [];
1010 propagatedBuildInputs = with self; [];
1011 src = fetchurl {
1011 src = fetchurl {
1012 url = "https://pypi.python.org/packages/39/e8/a8e0b1fa65dd021d48fe21464f71783655f39a41f218293c1c590d54eb82/lxml-3.7.3.tar.gz";
1012 url = "https://pypi.python.org/packages/39/e8/a8e0b1fa65dd021d48fe21464f71783655f39a41f218293c1c590d54eb82/lxml-3.7.3.tar.gz";
1013 md5 = "075692ce442e69bbd604d44e21c02753";
1013 md5 = "075692ce442e69bbd604d44e21c02753";
1014 };
1014 };
1015 meta = {
1015 meta = {
1016 license = [ pkgs.lib.licenses.bsdOriginal ];
1016 license = [ pkgs.lib.licenses.bsdOriginal ];
1017 };
1017 };
1018 };
1018 };
1019 meld3 = super.buildPythonPackage {
1019 meld3 = super.buildPythonPackage {
1020 name = "meld3-1.0.2";
1020 name = "meld3-1.0.2";
1021 buildInputs = with self; [];
1021 buildInputs = with self; [];
1022 doCheck = false;
1022 doCheck = false;
1023 propagatedBuildInputs = with self; [];
1023 propagatedBuildInputs = with self; [];
1024 src = fetchurl {
1024 src = fetchurl {
1025 url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz";
1025 url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz";
1026 md5 = "3ccc78cd79cffd63a751ad7684c02c91";
1026 md5 = "3ccc78cd79cffd63a751ad7684c02c91";
1027 };
1027 };
1028 meta = {
1028 meta = {
1029 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1029 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1030 };
1030 };
1031 };
1031 };
1032 mistune = super.buildPythonPackage {
1032 mistune = super.buildPythonPackage {
1033 name = "mistune-0.8.3";
1033 name = "mistune-0.8.3";
1034 buildInputs = with self; [];
1034 buildInputs = with self; [];
1035 doCheck = false;
1035 doCheck = false;
1036 propagatedBuildInputs = with self; [];
1036 propagatedBuildInputs = with self; [];
1037 src = fetchurl {
1037 src = fetchurl {
1038 url = "https://pypi.python.org/packages/9d/be/e06d4346cc608a01dec6bf770d7d0303a4fd6db588b318ced18f5f257145/mistune-0.8.3.tar.gz";
1038 url = "https://pypi.python.org/packages/9d/be/e06d4346cc608a01dec6bf770d7d0303a4fd6db588b318ced18f5f257145/mistune-0.8.3.tar.gz";
1039 md5 = "a5e4043e93fb8f9082e27f29eeb5e054";
1039 md5 = "a5e4043e93fb8f9082e27f29eeb5e054";
1040 };
1040 };
1041 meta = {
1041 meta = {
1042 license = [ pkgs.lib.licenses.bsdOriginal ];
1042 license = [ pkgs.lib.licenses.bsdOriginal ];
1043 };
1043 };
1044 };
1044 };
1045 mock = super.buildPythonPackage {
1045 mock = super.buildPythonPackage {
1046 name = "mock-1.0.1";
1046 name = "mock-1.0.1";
1047 buildInputs = with self; [];
1047 buildInputs = with self; [];
1048 doCheck = false;
1048 doCheck = false;
1049 propagatedBuildInputs = with self; [];
1049 propagatedBuildInputs = with self; [];
1050 src = fetchurl {
1050 src = fetchurl {
1051 url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip";
1051 url = "https://pypi.python.org/packages/a2/52/7edcd94f0afb721a2d559a5b9aae8af4f8f2c79bc63fdbe8a8a6c9b23bbe/mock-1.0.1.tar.gz";
1052 md5 = "869f08d003c289a97c1a6610faf5e913";
1052 md5 = "c3971991738caa55ec7c356bbc154ee2";
1053 };
1053 };
1054 meta = {
1054 meta = {
1055 license = [ pkgs.lib.licenses.bsdOriginal ];
1055 license = [ pkgs.lib.licenses.bsdOriginal ];
1056 };
1056 };
1057 };
1057 };
1058 msgpack-python = super.buildPythonPackage {
1058 msgpack-python = super.buildPythonPackage {
1059 name = "msgpack-python-0.4.8";
1059 name = "msgpack-python-0.4.8";
1060 buildInputs = with self; [];
1060 buildInputs = with self; [];
1061 doCheck = false;
1061 doCheck = false;
1062 propagatedBuildInputs = with self; [];
1062 propagatedBuildInputs = with self; [];
1063 src = fetchurl {
1063 src = fetchurl {
1064 url = "https://pypi.python.org/packages/21/27/8a1d82041c7a2a51fcc73675875a5f9ea06c2663e02fcfeb708be1d081a0/msgpack-python-0.4.8.tar.gz";
1064 url = "https://pypi.python.org/packages/21/27/8a1d82041c7a2a51fcc73675875a5f9ea06c2663e02fcfeb708be1d081a0/msgpack-python-0.4.8.tar.gz";
1065 md5 = "dcd854fb41ee7584ebbf35e049e6be98";
1065 md5 = "dcd854fb41ee7584ebbf35e049e6be98";
1066 };
1066 };
1067 meta = {
1067 meta = {
1068 license = [ pkgs.lib.licenses.asl20 ];
1068 license = [ pkgs.lib.licenses.asl20 ];
1069 };
1069 };
1070 };
1070 };
1071 nbconvert = super.buildPythonPackage {
1071 nbconvert = super.buildPythonPackage {
1072 name = "nbconvert-5.3.1";
1072 name = "nbconvert-5.3.1";
1073 buildInputs = with self; [];
1073 buildInputs = with self; [];
1074 doCheck = false;
1074 doCheck = false;
1075 propagatedBuildInputs = with self; [mistune Jinja2 Pygments traitlets jupyter-core nbformat entrypoints bleach pandocfilters testpath];
1075 propagatedBuildInputs = with self; [mistune Jinja2 Pygments traitlets jupyter-core nbformat entrypoints bleach pandocfilters testpath];
1076 src = fetchurl {
1076 src = fetchurl {
1077 url = "https://pypi.python.org/packages/b9/a4/d0a0938ad6f5eeb4dea4e73d255c617ef94b0b2849d51194c9bbdb838412/nbconvert-5.3.1.tar.gz";
1077 url = "https://pypi.python.org/packages/b9/a4/d0a0938ad6f5eeb4dea4e73d255c617ef94b0b2849d51194c9bbdb838412/nbconvert-5.3.1.tar.gz";
1078 md5 = "c128d0d93d02f70a85429a383dae96d2";
1078 md5 = "c128d0d93d02f70a85429a383dae96d2";
1079 };
1079 };
1080 meta = {
1080 meta = {
1081 license = [ pkgs.lib.licenses.bsdOriginal ];
1081 license = [ pkgs.lib.licenses.bsdOriginal ];
1082 };
1082 };
1083 };
1083 };
1084 nbformat = super.buildPythonPackage {
1084 nbformat = super.buildPythonPackage {
1085 name = "nbformat-4.4.0";
1085 name = "nbformat-4.4.0";
1086 buildInputs = with self; [];
1086 buildInputs = with self; [];
1087 doCheck = false;
1087 doCheck = false;
1088 propagatedBuildInputs = with self; [ipython-genutils traitlets jsonschema jupyter-core];
1088 propagatedBuildInputs = with self; [ipython-genutils traitlets jsonschema jupyter-core];
1089 src = fetchurl {
1089 src = fetchurl {
1090 url = "https://pypi.python.org/packages/6e/0e/160754f7ae3e984863f585a3743b0ed1702043a81245907c8fae2d537155/nbformat-4.4.0.tar.gz";
1090 url = "https://pypi.python.org/packages/6e/0e/160754f7ae3e984863f585a3743b0ed1702043a81245907c8fae2d537155/nbformat-4.4.0.tar.gz";
1091 md5 = "2d5f873138d9fbc2a3f9eaaebca3b8a1";
1091 md5 = "2d5f873138d9fbc2a3f9eaaebca3b8a1";
1092 };
1092 };
1093 meta = {
1093 meta = {
1094 license = [ pkgs.lib.licenses.bsdOriginal ];
1094 license = [ pkgs.lib.licenses.bsdOriginal ];
1095 };
1095 };
1096 };
1096 };
1097 objgraph = super.buildPythonPackage {
1097 objgraph = super.buildPythonPackage {
1098 name = "objgraph-3.1.1";
1098 name = "objgraph-3.1.1";
1099 buildInputs = with self; [];
1099 buildInputs = with self; [];
1100 doCheck = false;
1100 doCheck = false;
1101 propagatedBuildInputs = with self; [graphviz];
1101 propagatedBuildInputs = with self; [graphviz];
1102 src = fetchurl {
1102 src = fetchurl {
1103 url = "https://pypi.python.org/packages/be/58/9ca81a20cc837054e94866df1475d899caaa94f3732b8a46006858b015f7/objgraph-3.1.1.tar.gz";
1103 url = "https://pypi.python.org/packages/be/58/9ca81a20cc837054e94866df1475d899caaa94f3732b8a46006858b015f7/objgraph-3.1.1.tar.gz";
1104 md5 = "253af9944763377877c3678d8aaebb8b";
1104 md5 = "253af9944763377877c3678d8aaebb8b";
1105 };
1105 };
1106 meta = {
1106 meta = {
1107 license = [ pkgs.lib.licenses.mit ];
1107 license = [ pkgs.lib.licenses.mit ];
1108 };
1108 };
1109 };
1109 };
1110 packaging = super.buildPythonPackage {
1110 packaging = super.buildPythonPackage {
1111 name = "packaging-15.2";
1111 name = "packaging-15.2";
1112 buildInputs = with self; [];
1112 buildInputs = with self; [];
1113 doCheck = false;
1113 doCheck = false;
1114 propagatedBuildInputs = with self; [];
1114 propagatedBuildInputs = with self; [];
1115 src = fetchurl {
1115 src = fetchurl {
1116 url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz";
1116 url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz";
1117 md5 = "c16093476f6ced42128bf610e5db3784";
1117 md5 = "c16093476f6ced42128bf610e5db3784";
1118 };
1118 };
1119 meta = {
1119 meta = {
1120 license = [ pkgs.lib.licenses.asl20 ];
1120 license = [ pkgs.lib.licenses.asl20 ];
1121 };
1121 };
1122 };
1122 };
1123 pandocfilters = super.buildPythonPackage {
1123 pandocfilters = super.buildPythonPackage {
1124 name = "pandocfilters-1.4.2";
1124 name = "pandocfilters-1.4.2";
1125 buildInputs = with self; [];
1125 buildInputs = with self; [];
1126 doCheck = false;
1126 doCheck = false;
1127 propagatedBuildInputs = with self; [];
1127 propagatedBuildInputs = with self; [];
1128 src = fetchurl {
1128 src = fetchurl {
1129 url = "https://pypi.python.org/packages/4c/ea/236e2584af67bb6df960832731a6e5325fd4441de001767da328c33368ce/pandocfilters-1.4.2.tar.gz";
1129 url = "https://pypi.python.org/packages/4c/ea/236e2584af67bb6df960832731a6e5325fd4441de001767da328c33368ce/pandocfilters-1.4.2.tar.gz";
1130 md5 = "dc391791ef54c7de1572d7b46b63361f";
1130 md5 = "dc391791ef54c7de1572d7b46b63361f";
1131 };
1131 };
1132 meta = {
1132 meta = {
1133 license = [ pkgs.lib.licenses.bsdOriginal ];
1133 license = [ pkgs.lib.licenses.bsdOriginal ];
1134 };
1134 };
1135 };
1135 };
1136 pathlib2 = super.buildPythonPackage {
1136 pathlib2 = super.buildPythonPackage {
1137 name = "pathlib2-2.3.0";
1137 name = "pathlib2-2.3.0";
1138 buildInputs = with self; [];
1138 buildInputs = with self; [];
1139 doCheck = false;
1139 doCheck = false;
1140 propagatedBuildInputs = with self; [six scandir];
1140 propagatedBuildInputs = with self; [six scandir];
1141 src = fetchurl {
1141 src = fetchurl {
1142 url = "https://pypi.python.org/packages/a1/14/df0deb867c2733f7d857523c10942b3d6612a1b222502fdffa9439943dfb/pathlib2-2.3.0.tar.gz";
1142 url = "https://pypi.python.org/packages/a1/14/df0deb867c2733f7d857523c10942b3d6612a1b222502fdffa9439943dfb/pathlib2-2.3.0.tar.gz";
1143 md5 = "89c90409d11fd5947966b6a30a47d18c";
1143 md5 = "89c90409d11fd5947966b6a30a47d18c";
1144 };
1144 };
1145 meta = {
1145 meta = {
1146 license = [ pkgs.lib.licenses.mit ];
1146 license = [ pkgs.lib.licenses.mit ];
1147 };
1147 };
1148 };
1148 };
1149 peppercorn = super.buildPythonPackage {
1149 peppercorn = super.buildPythonPackage {
1150 name = "peppercorn-0.5";
1150 name = "peppercorn-0.5";
1151 buildInputs = with self; [];
1151 buildInputs = with self; [];
1152 doCheck = false;
1152 doCheck = false;
1153 propagatedBuildInputs = with self; [];
1153 propagatedBuildInputs = with self; [];
1154 src = fetchurl {
1154 src = fetchurl {
1155 url = "https://pypi.python.org/packages/45/ec/a62ec317d1324a01567c5221b420742f094f05ee48097e5157d32be3755c/peppercorn-0.5.tar.gz";
1155 url = "https://pypi.python.org/packages/45/ec/a62ec317d1324a01567c5221b420742f094f05ee48097e5157d32be3755c/peppercorn-0.5.tar.gz";
1156 md5 = "f08efbca5790019ab45d76b7244abd40";
1156 md5 = "f08efbca5790019ab45d76b7244abd40";
1157 };
1157 };
1158 meta = {
1158 meta = {
1159 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1159 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1160 };
1160 };
1161 };
1161 };
1162 pexpect = super.buildPythonPackage {
1162 pexpect = super.buildPythonPackage {
1163 name = "pexpect-4.3.0";
1163 name = "pexpect-4.4.0";
1164 buildInputs = with self; [];
1164 buildInputs = with self; [];
1165 doCheck = false;
1165 doCheck = false;
1166 propagatedBuildInputs = with self; [ptyprocess];
1166 propagatedBuildInputs = with self; [ptyprocess];
1167 src = fetchurl {
1167 src = fetchurl {
1168 url = "https://pypi.python.org/packages/f8/44/5466c30e49762bb92e442bbdf4472d6904608d211258eb3198a11f0309a4/pexpect-4.3.0.tar.gz";
1168 url = "https://pypi.python.org/packages/fa/c3/60c0cbf96f242d0b47a82e9ca634dcd6dcb043832cf05e17540812e1c707/pexpect-4.4.0.tar.gz";
1169 md5 = "047a486dcd26134b74f2e67046bb61a0";
1169 md5 = "e9b07f0765df8245ac72201d757baaef";
1170 };
1170 };
1171 meta = {
1171 meta = {
1172 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
1172 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
1173 };
1173 };
1174 };
1174 };
1175 pickleshare = super.buildPythonPackage {
1175 pickleshare = super.buildPythonPackage {
1176 name = "pickleshare-0.7.4";
1176 name = "pickleshare-0.7.4";
1177 buildInputs = with self; [];
1177 buildInputs = with self; [];
1178 doCheck = false;
1178 doCheck = false;
1179 propagatedBuildInputs = with self; [pathlib2];
1179 propagatedBuildInputs = with self; [pathlib2];
1180 src = fetchurl {
1180 src = fetchurl {
1181 url = "https://pypi.python.org/packages/69/fe/dd137d84daa0fd13a709e448138e310d9ea93070620c9db5454e234af525/pickleshare-0.7.4.tar.gz";
1181 url = "https://pypi.python.org/packages/69/fe/dd137d84daa0fd13a709e448138e310d9ea93070620c9db5454e234af525/pickleshare-0.7.4.tar.gz";
1182 md5 = "6a9e5dd8dfc023031f6b7b3f824cab12";
1182 md5 = "6a9e5dd8dfc023031f6b7b3f824cab12";
1183 };
1183 };
1184 meta = {
1184 meta = {
1185 license = [ pkgs.lib.licenses.mit ];
1185 license = [ pkgs.lib.licenses.mit ];
1186 };
1186 };
1187 };
1187 };
1188 plaster = super.buildPythonPackage {
1188 plaster = super.buildPythonPackage {
1189 name = "plaster-1.0";
1189 name = "plaster-1.0";
1190 buildInputs = with self; [];
1190 buildInputs = with self; [];
1191 doCheck = false;
1191 doCheck = false;
1192 propagatedBuildInputs = with self; [setuptools];
1192 propagatedBuildInputs = with self; [setuptools];
1193 src = fetchurl {
1193 src = fetchurl {
1194 url = "https://pypi.python.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz";
1194 url = "https://pypi.python.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz";
1195 md5 = "80e6beb4760c16fea31754babcc0576e";
1195 md5 = "80e6beb4760c16fea31754babcc0576e";
1196 };
1196 };
1197 meta = {
1197 meta = {
1198 license = [ pkgs.lib.licenses.mit ];
1198 license = [ pkgs.lib.licenses.mit ];
1199 };
1199 };
1200 };
1200 };
1201 plaster-pastedeploy = super.buildPythonPackage {
1201 plaster-pastedeploy = super.buildPythonPackage {
1202 name = "plaster-pastedeploy-0.4.2";
1202 name = "plaster-pastedeploy-0.4.2";
1203 buildInputs = with self; [];
1203 buildInputs = with self; [];
1204 doCheck = false;
1204 doCheck = false;
1205 propagatedBuildInputs = with self; [PasteDeploy plaster];
1205 propagatedBuildInputs = with self; [PasteDeploy plaster];
1206 src = fetchurl {
1206 src = fetchurl {
1207 url = "https://pypi.python.org/packages/2c/62/0daf9c0be958e785023e583e51baac15863699e956bfb3d448898d80edd8/plaster_pastedeploy-0.4.2.tar.gz";
1207 url = "https://pypi.python.org/packages/2c/62/0daf9c0be958e785023e583e51baac15863699e956bfb3d448898d80edd8/plaster_pastedeploy-0.4.2.tar.gz";
1208 md5 = "58fd7852002909378e818c9d5b71e90a";
1208 md5 = "58fd7852002909378e818c9d5b71e90a";
1209 };
1209 };
1210 meta = {
1210 meta = {
1211 license = [ pkgs.lib.licenses.mit ];
1211 license = [ pkgs.lib.licenses.mit ];
1212 };
1212 };
1213 };
1213 };
1214 prompt-toolkit = super.buildPythonPackage {
1214 prompt-toolkit = super.buildPythonPackage {
1215 name = "prompt-toolkit-1.0.15";
1215 name = "prompt-toolkit-1.0.15";
1216 buildInputs = with self; [];
1216 buildInputs = with self; [];
1217 doCheck = false;
1217 doCheck = false;
1218 propagatedBuildInputs = with self; [six wcwidth];
1218 propagatedBuildInputs = with self; [six wcwidth];
1219 src = fetchurl {
1219 src = fetchurl {
1220 url = "https://pypi.python.org/packages/8a/ad/cf6b128866e78ad6d7f1dc5b7f99885fb813393d9860778b2984582e81b5/prompt_toolkit-1.0.15.tar.gz";
1220 url = "https://pypi.python.org/packages/8a/ad/cf6b128866e78ad6d7f1dc5b7f99885fb813393d9860778b2984582e81b5/prompt_toolkit-1.0.15.tar.gz";
1221 md5 = "8fe70295006dbc8afedd43e5eba99032";
1221 md5 = "8fe70295006dbc8afedd43e5eba99032";
1222 };
1222 };
1223 meta = {
1223 meta = {
1224 license = [ pkgs.lib.licenses.bsdOriginal ];
1224 license = [ pkgs.lib.licenses.bsdOriginal ];
1225 };
1225 };
1226 };
1226 };
1227 psutil = super.buildPythonPackage {
1227 psutil = super.buildPythonPackage {
1228 name = "psutil-5.4.0";
1228 name = "psutil-5.4.3";
1229 buildInputs = with self; [];
1229 buildInputs = with self; [];
1230 doCheck = false;
1230 doCheck = false;
1231 propagatedBuildInputs = with self; [];
1231 propagatedBuildInputs = with self; [];
1232 src = fetchurl {
1232 src = fetchurl {
1233 url = "https://pypi.python.org/packages/8d/96/1fc6468be91521192861966c40bd73fdf8b065eae6d82dd0f870b9825a65/psutil-5.4.0.tar.gz";
1233 url = "https://pypi.python.org/packages/e2/e1/600326635f97fee89bf8426fef14c5c29f4849c79f68fd79f433d8c1bd96/psutil-5.4.3.tar.gz";
1234 md5 = "01af6219b1e8fcfd53603023967713bf";
1234 md5 = "3b291833dbea631db9d271aa602a169a";
1235 };
1235 };
1236 meta = {
1236 meta = {
1237 license = [ pkgs.lib.licenses.bsdOriginal ];
1237 license = [ pkgs.lib.licenses.bsdOriginal ];
1238 };
1238 };
1239 };
1239 };
1240 psycopg2 = super.buildPythonPackage {
1240 psycopg2 = super.buildPythonPackage {
1241 name = "psycopg2-2.7.3.2";
1241 name = "psycopg2-2.7.3.2";
1242 buildInputs = with self; [];
1242 buildInputs = with self; [];
1243 doCheck = false;
1243 doCheck = false;
1244 propagatedBuildInputs = with self; [];
1244 propagatedBuildInputs = with self; [];
1245 src = fetchurl {
1245 src = fetchurl {
1246 url = "https://pypi.python.org/packages/dd/47/000b405d73ca22980684fd7bd3318690cc03cfa3b2ae1c5b7fff8050b28a/psycopg2-2.7.3.2.tar.gz";
1246 url = "https://pypi.python.org/packages/dd/47/000b405d73ca22980684fd7bd3318690cc03cfa3b2ae1c5b7fff8050b28a/psycopg2-2.7.3.2.tar.gz";
1247 md5 = "8114e672d5f23fa5329874a4314fbd6f";
1247 md5 = "8114e672d5f23fa5329874a4314fbd6f";
1248 };
1248 };
1249 meta = {
1249 meta = {
1250 license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
1250 license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
1251 };
1251 };
1252 };
1252 };
1253 ptyprocess = super.buildPythonPackage {
1253 ptyprocess = super.buildPythonPackage {
1254 name = "ptyprocess-0.5.2";
1254 name = "ptyprocess-0.5.2";
1255 buildInputs = with self; [];
1255 buildInputs = with self; [];
1256 doCheck = false;
1256 doCheck = false;
1257 propagatedBuildInputs = with self; [];
1257 propagatedBuildInputs = with self; [];
1258 src = fetchurl {
1258 src = fetchurl {
1259 url = "https://pypi.python.org/packages/51/83/5d07dc35534640b06f9d9f1a1d2bc2513fb9cc7595a1b0e28ae5477056ce/ptyprocess-0.5.2.tar.gz";
1259 url = "https://pypi.python.org/packages/51/83/5d07dc35534640b06f9d9f1a1d2bc2513fb9cc7595a1b0e28ae5477056ce/ptyprocess-0.5.2.tar.gz";
1260 md5 = "d3b8febae1b8c53b054bd818d0bb8665";
1260 md5 = "d3b8febae1b8c53b054bd818d0bb8665";
1261 };
1261 };
1262 meta = {
1262 meta = {
1263 license = [ ];
1263 license = [ ];
1264 };
1264 };
1265 };
1265 };
1266 py = super.buildPythonPackage {
1266 py = super.buildPythonPackage {
1267 name = "py-1.5.2";
1267 name = "py-1.5.2";
1268 buildInputs = with self; [];
1268 buildInputs = with self; [];
1269 doCheck = false;
1269 doCheck = false;
1270 propagatedBuildInputs = with self; [];
1270 propagatedBuildInputs = with self; [];
1271 src = fetchurl {
1271 src = fetchurl {
1272 url = "https://pypi.python.org/packages/90/e3/e075127d39d35f09a500ebb4a90afd10f9ef0a1d28a6d09abeec0e444fdd/py-1.5.2.tar.gz";
1272 url = "https://pypi.python.org/packages/90/e3/e075127d39d35f09a500ebb4a90afd10f9ef0a1d28a6d09abeec0e444fdd/py-1.5.2.tar.gz";
1273 md5 = "279ca69c632069e1b71e11b14641ca28";
1273 md5 = "279ca69c632069e1b71e11b14641ca28";
1274 };
1274 };
1275 meta = {
1275 meta = {
1276 license = [ pkgs.lib.licenses.mit ];
1276 license = [ pkgs.lib.licenses.mit ];
1277 };
1277 };
1278 };
1278 };
1279 py-bcrypt = super.buildPythonPackage {
1279 py-bcrypt = super.buildPythonPackage {
1280 name = "py-bcrypt-0.4";
1280 name = "py-bcrypt-0.4";
1281 buildInputs = with self; [];
1281 buildInputs = with self; [];
1282 doCheck = false;
1282 doCheck = false;
1283 propagatedBuildInputs = with self; [];
1283 propagatedBuildInputs = with self; [];
1284 src = fetchurl {
1284 src = fetchurl {
1285 url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz";
1285 url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz";
1286 md5 = "dd8b367d6b716a2ea2e72392525f4e36";
1286 md5 = "dd8b367d6b716a2ea2e72392525f4e36";
1287 };
1287 };
1288 meta = {
1288 meta = {
1289 license = [ pkgs.lib.licenses.bsdOriginal ];
1289 license = [ pkgs.lib.licenses.bsdOriginal ];
1290 };
1290 };
1291 };
1291 };
1292 py-gfm = super.buildPythonPackage {
1292 py-gfm = super.buildPythonPackage {
1293 name = "py-gfm-0.1.3";
1293 name = "py-gfm-0.1.3";
1294 buildInputs = with self; [];
1294 buildInputs = with self; [];
1295 doCheck = false;
1295 doCheck = false;
1296 propagatedBuildInputs = with self; [setuptools Markdown];
1296 propagatedBuildInputs = with self; [setuptools Markdown];
1297 src = fetchurl {
1297 src = fetchurl {
1298 url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
1298 url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
1299 md5 = "e588d9e69640a241b97e2c59c22527a6";
1299 md5 = "e588d9e69640a241b97e2c59c22527a6";
1300 };
1300 };
1301 meta = {
1301 meta = {
1302 license = [ pkgs.lib.licenses.bsdOriginal ];
1302 license = [ pkgs.lib.licenses.bsdOriginal ];
1303 };
1303 };
1304 };
1304 };
1305 pycrypto = super.buildPythonPackage {
1305 pycrypto = super.buildPythonPackage {
1306 name = "pycrypto-2.6.1";
1306 name = "pycrypto-2.6.1";
1307 buildInputs = with self; [];
1307 buildInputs = with self; [];
1308 doCheck = false;
1308 doCheck = false;
1309 propagatedBuildInputs = with self; [];
1309 propagatedBuildInputs = with self; [];
1310 src = fetchurl {
1310 src = fetchurl {
1311 url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz";
1311 url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz";
1312 md5 = "55a61a054aa66812daf5161a0d5d7eda";
1312 md5 = "55a61a054aa66812daf5161a0d5d7eda";
1313 };
1313 };
1314 meta = {
1314 meta = {
1315 license = [ pkgs.lib.licenses.publicDomain ];
1315 license = [ pkgs.lib.licenses.publicDomain ];
1316 };
1316 };
1317 };
1317 };
1318 pycurl = super.buildPythonPackage {
1318 pycurl = super.buildPythonPackage {
1319 name = "pycurl-7.19.5";
1319 name = "pycurl-7.19.5";
1320 buildInputs = with self; [];
1320 buildInputs = with self; [];
1321 doCheck = false;
1321 doCheck = false;
1322 propagatedBuildInputs = with self; [];
1322 propagatedBuildInputs = with self; [];
1323 src = fetchurl {
1323 src = fetchurl {
1324 url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz";
1324 url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz";
1325 md5 = "47b4eac84118e2606658122104e62072";
1325 md5 = "47b4eac84118e2606658122104e62072";
1326 };
1326 };
1327 meta = {
1327 meta = {
1328 license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1328 license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1329 };
1329 };
1330 };
1330 };
1331 pyflakes = super.buildPythonPackage {
1331 pyflakes = super.buildPythonPackage {
1332 name = "pyflakes-0.8.1";
1332 name = "pyflakes-0.8.1";
1333 buildInputs = with self; [];
1333 buildInputs = with self; [];
1334 doCheck = false;
1334 doCheck = false;
1335 propagatedBuildInputs = with self; [];
1335 propagatedBuildInputs = with self; [];
1336 src = fetchurl {
1336 src = fetchurl {
1337 url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
1337 url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
1338 md5 = "905fe91ad14b912807e8fdc2ac2e2c23";
1338 md5 = "905fe91ad14b912807e8fdc2ac2e2c23";
1339 };
1339 };
1340 meta = {
1340 meta = {
1341 license = [ pkgs.lib.licenses.mit ];
1341 license = [ pkgs.lib.licenses.mit ];
1342 };
1342 };
1343 };
1343 };
1344 pygments-markdown-lexer = super.buildPythonPackage {
1344 pygments-markdown-lexer = super.buildPythonPackage {
1345 name = "pygments-markdown-lexer-0.1.0.dev39";
1345 name = "pygments-markdown-lexer-0.1.0.dev39";
1346 buildInputs = with self; [];
1346 buildInputs = with self; [];
1347 doCheck = false;
1347 doCheck = false;
1348 propagatedBuildInputs = with self; [Pygments];
1348 propagatedBuildInputs = with self; [Pygments];
1349 src = fetchurl {
1349 src = fetchurl {
1350 url = "https://pypi.python.org/packages/c3/12/674cdee66635d638cedb2c5d9c85ce507b7b2f91bdba29e482f1b1160ff6/pygments-markdown-lexer-0.1.0.dev39.zip";
1350 url = "https://pypi.python.org/packages/c3/12/674cdee66635d638cedb2c5d9c85ce507b7b2f91bdba29e482f1b1160ff6/pygments-markdown-lexer-0.1.0.dev39.zip";
1351 md5 = "6360fe0f6d1f896e35b7a0142ce6459c";
1351 md5 = "6360fe0f6d1f896e35b7a0142ce6459c";
1352 };
1352 };
1353 meta = {
1353 meta = {
1354 license = [ pkgs.lib.licenses.asl20 ];
1354 license = [ pkgs.lib.licenses.asl20 ];
1355 };
1355 };
1356 };
1356 };
1357 pyparsing = super.buildPythonPackage {
1357 pyparsing = super.buildPythonPackage {
1358 name = "pyparsing-1.5.7";
1358 name = "pyparsing-1.5.7";
1359 buildInputs = with self; [];
1359 buildInputs = with self; [];
1360 doCheck = false;
1360 doCheck = false;
1361 propagatedBuildInputs = with self; [];
1361 propagatedBuildInputs = with self; [];
1362 src = fetchurl {
1362 src = fetchurl {
1363 url = "https://pypi.python.org/packages/2e/26/e8fb5b4256a5f5036be7ce115ef8db8d06bc537becfbdc46c6af008314ee/pyparsing-1.5.7.zip";
1363 url = "https://pypi.python.org/packages/6f/2c/47457771c02a8ff0f302b695e094ec309e30452232bd79198ee94fda689f/pyparsing-1.5.7.tar.gz";
1364 md5 = "b86854857a368d6ccb4d5b6e76d0637f";
1364 md5 = "9be0fcdcc595199c646ab317c1d9a709";
1365 };
1365 };
1366 meta = {
1366 meta = {
1367 license = [ pkgs.lib.licenses.mit ];
1367 license = [ pkgs.lib.licenses.mit ];
1368 };
1368 };
1369 };
1369 };
1370 pyramid = super.buildPythonPackage {
1370 pyramid = super.buildPythonPackage {
1371 name = "pyramid-1.9.1";
1371 name = "pyramid-1.9.1";
1372 buildInputs = with self; [];
1372 buildInputs = with self; [];
1373 doCheck = false;
1373 doCheck = false;
1374 propagatedBuildInputs = with self; [setuptools WebOb repoze.lru zope.interface zope.deprecation venusian translationstring PasteDeploy plaster plaster-pastedeploy hupper];
1374 propagatedBuildInputs = with self; [setuptools WebOb repoze.lru zope.interface zope.deprecation venusian translationstring PasteDeploy plaster plaster-pastedeploy hupper];
1375 src = fetchurl {
1375 src = fetchurl {
1376 url = "https://pypi.python.org/packages/9a/57/73447be9e7d0512d601e3f0a1fb9d7d1efb941911f49efdfe036d2826507/pyramid-1.9.1.tar.gz";
1376 url = "https://pypi.python.org/packages/9a/57/73447be9e7d0512d601e3f0a1fb9d7d1efb941911f49efdfe036d2826507/pyramid-1.9.1.tar.gz";
1377 md5 = "0163e19c58c2d12976a3b6fdb57e052d";
1377 md5 = "0163e19c58c2d12976a3b6fdb57e052d";
1378 };
1378 };
1379 meta = {
1379 meta = {
1380 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1380 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1381 };
1381 };
1382 };
1382 };
1383 pyramid-beaker = super.buildPythonPackage {
1383 pyramid-beaker = super.buildPythonPackage {
1384 name = "pyramid-beaker-0.8";
1384 name = "pyramid-beaker-0.8";
1385 buildInputs = with self; [];
1385 buildInputs = with self; [];
1386 doCheck = false;
1386 doCheck = false;
1387 propagatedBuildInputs = with self; [pyramid Beaker];
1387 propagatedBuildInputs = with self; [pyramid Beaker];
1388 src = fetchurl {
1388 src = fetchurl {
1389 url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
1389 url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
1390 md5 = "22f14be31b06549f80890e2c63a93834";
1390 md5 = "22f14be31b06549f80890e2c63a93834";
1391 };
1391 };
1392 meta = {
1392 meta = {
1393 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1393 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1394 };
1394 };
1395 };
1395 };
1396 pyramid-debugtoolbar = super.buildPythonPackage {
1396 pyramid-debugtoolbar = super.buildPythonPackage {
1397 name = "pyramid-debugtoolbar-4.3";
1397 name = "pyramid-debugtoolbar-4.3";
1398 buildInputs = with self; [];
1398 buildInputs = with self; [];
1399 doCheck = false;
1399 doCheck = false;
1400 propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress];
1400 propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress];
1401 src = fetchurl {
1401 src = fetchurl {
1402 url = "https://pypi.python.org/packages/a4/40/f09d8800bfc3c09bdb6c95f37bb61c890dc62c19c4e7caa304da7aa77403/pyramid_debugtoolbar-4.3.tar.gz";
1402 url = "https://pypi.python.org/packages/a4/40/f09d8800bfc3c09bdb6c95f37bb61c890dc62c19c4e7caa304da7aa77403/pyramid_debugtoolbar-4.3.tar.gz";
1403 md5 = "9c49029e9f0695130499ef6416ffaaf8";
1403 md5 = "9c49029e9f0695130499ef6416ffaaf8";
1404 };
1404 };
1405 meta = {
1405 meta = {
1406 license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ];
1406 license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ];
1407 };
1407 };
1408 };
1408 };
1409 pyramid-jinja2 = super.buildPythonPackage {
1409 pyramid-jinja2 = super.buildPythonPackage {
1410 name = "pyramid-jinja2-2.7";
1410 name = "pyramid-jinja2-2.7";
1411 buildInputs = with self; [];
1411 buildInputs = with self; [];
1412 doCheck = false;
1412 doCheck = false;
1413 propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe];
1413 propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe];
1414 src = fetchurl {
1414 src = fetchurl {
1415 url = "https://pypi.python.org/packages/d8/80/d60a7233823de22ce77bd864a8a83736a1fe8b49884b08303a2e68b2c853/pyramid_jinja2-2.7.tar.gz";
1415 url = "https://pypi.python.org/packages/d8/80/d60a7233823de22ce77bd864a8a83736a1fe8b49884b08303a2e68b2c853/pyramid_jinja2-2.7.tar.gz";
1416 md5 = "c2f8b2cd7b73a6f1d9a311fcfaf4fb92";
1416 md5 = "c2f8b2cd7b73a6f1d9a311fcfaf4fb92";
1417 };
1417 };
1418 meta = {
1418 meta = {
1419 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1419 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1420 };
1420 };
1421 };
1421 };
1422 pyramid-mako = super.buildPythonPackage {
1422 pyramid-mako = super.buildPythonPackage {
1423 name = "pyramid-mako-1.0.2";
1423 name = "pyramid-mako-1.0.2";
1424 buildInputs = with self; [];
1424 buildInputs = with self; [];
1425 doCheck = false;
1425 doCheck = false;
1426 propagatedBuildInputs = with self; [pyramid Mako];
1426 propagatedBuildInputs = with self; [pyramid Mako];
1427 src = fetchurl {
1427 src = fetchurl {
1428 url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz";
1428 url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz";
1429 md5 = "ee25343a97eb76bd90abdc2a774eb48a";
1429 md5 = "ee25343a97eb76bd90abdc2a774eb48a";
1430 };
1430 };
1431 meta = {
1431 meta = {
1432 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1432 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1433 };
1433 };
1434 };
1434 };
1435 pysqlite = super.buildPythonPackage {
1435 pysqlite = super.buildPythonPackage {
1436 name = "pysqlite-2.8.3";
1436 name = "pysqlite-2.8.3";
1437 buildInputs = with self; [];
1437 buildInputs = with self; [];
1438 doCheck = false;
1438 doCheck = false;
1439 propagatedBuildInputs = with self; [];
1439 propagatedBuildInputs = with self; [];
1440 src = fetchurl {
1440 src = fetchurl {
1441 url = "https://pypi.python.org/packages/42/02/981b6703e3c83c5b25a829c6e77aad059f9481b0bbacb47e6e8ca12bd731/pysqlite-2.8.3.tar.gz";
1441 url = "https://pypi.python.org/packages/42/02/981b6703e3c83c5b25a829c6e77aad059f9481b0bbacb47e6e8ca12bd731/pysqlite-2.8.3.tar.gz";
1442 md5 = "033f17b8644577715aee55e8832ac9fc";
1442 md5 = "033f17b8644577715aee55e8832ac9fc";
1443 };
1443 };
1444 meta = {
1444 meta = {
1445 license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ];
1445 license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ];
1446 };
1446 };
1447 };
1447 };
1448 pytest = super.buildPythonPackage {
1448 pytest = super.buildPythonPackage {
1449 name = "pytest-3.2.5";
1449 name = "pytest-3.2.5";
1450 buildInputs = with self; [];
1450 buildInputs = with self; [];
1451 doCheck = false;
1451 doCheck = false;
1452 propagatedBuildInputs = with self; [py setuptools];
1452 propagatedBuildInputs = with self; [py setuptools];
1453 src = fetchurl {
1453 src = fetchurl {
1454 url = "https://pypi.python.org/packages/1f/f8/8cd74c16952163ce0db0bd95fdd8810cbf093c08be00e6e665ebf0dc3138/pytest-3.2.5.tar.gz";
1454 url = "https://pypi.python.org/packages/1f/f8/8cd74c16952163ce0db0bd95fdd8810cbf093c08be00e6e665ebf0dc3138/pytest-3.2.5.tar.gz";
1455 md5 = "6dbe9bb093883f75394a689a1426ac6f";
1455 md5 = "6dbe9bb093883f75394a689a1426ac6f";
1456 };
1456 };
1457 meta = {
1457 meta = {
1458 license = [ pkgs.lib.licenses.mit ];
1458 license = [ pkgs.lib.licenses.mit ];
1459 };
1459 };
1460 };
1460 };
1461 pytest-catchlog = super.buildPythonPackage {
1461 pytest-catchlog = super.buildPythonPackage {
1462 name = "pytest-catchlog-1.2.2";
1462 name = "pytest-catchlog-1.2.2";
1463 buildInputs = with self; [];
1463 buildInputs = with self; [];
1464 doCheck = false;
1464 doCheck = false;
1465 propagatedBuildInputs = with self; [py pytest];
1465 propagatedBuildInputs = with self; [py pytest];
1466 src = fetchurl {
1466 src = fetchurl {
1467 url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip";
1467 url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip";
1468 md5 = "09d890c54c7456c818102b7ff8c182c8";
1468 md5 = "09d890c54c7456c818102b7ff8c182c8";
1469 };
1469 };
1470 meta = {
1470 meta = {
1471 license = [ pkgs.lib.licenses.mit ];
1471 license = [ pkgs.lib.licenses.mit ];
1472 };
1472 };
1473 };
1473 };
1474 pytest-cov = super.buildPythonPackage {
1474 pytest-cov = super.buildPythonPackage {
1475 name = "pytest-cov-2.5.1";
1475 name = "pytest-cov-2.5.1";
1476 buildInputs = with self; [];
1476 buildInputs = with self; [];
1477 doCheck = false;
1477 doCheck = false;
1478 propagatedBuildInputs = with self; [pytest coverage];
1478 propagatedBuildInputs = with self; [pytest coverage];
1479 src = fetchurl {
1479 src = fetchurl {
1480 url = "https://pypi.python.org/packages/24/b4/7290d65b2f3633db51393bdf8ae66309b37620bc3ec116c5e357e3e37238/pytest-cov-2.5.1.tar.gz";
1480 url = "https://pypi.python.org/packages/24/b4/7290d65b2f3633db51393bdf8ae66309b37620bc3ec116c5e357e3e37238/pytest-cov-2.5.1.tar.gz";
1481 md5 = "5acf38d4909e19819eb5c1754fbfc0ac";
1481 md5 = "5acf38d4909e19819eb5c1754fbfc0ac";
1482 };
1482 };
1483 meta = {
1483 meta = {
1484 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ];
1484 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ];
1485 };
1485 };
1486 };
1486 };
1487 pytest-profiling = super.buildPythonPackage {
1487 pytest-profiling = super.buildPythonPackage {
1488 name = "pytest-profiling-1.2.11";
1488 name = "pytest-profiling-1.2.11";
1489 buildInputs = with self; [];
1489 buildInputs = with self; [];
1490 doCheck = false;
1490 doCheck = false;
1491 propagatedBuildInputs = with self; [six pytest gprof2dot];
1491 propagatedBuildInputs = with self; [six pytest gprof2dot];
1492 src = fetchurl {
1492 src = fetchurl {
1493 url = "https://pypi.python.org/packages/c0/4a/b4aa786e93c07a86f1f87c581a36bf355a9e06a9da7e00dbd05047626bd2/pytest-profiling-1.2.11.tar.gz";
1493 url = "https://pypi.python.org/packages/c0/4a/b4aa786e93c07a86f1f87c581a36bf355a9e06a9da7e00dbd05047626bd2/pytest-profiling-1.2.11.tar.gz";
1494 md5 = "9ef6b60248731be5d44477980408e8f7";
1494 md5 = "9ef6b60248731be5d44477980408e8f7";
1495 };
1495 };
1496 meta = {
1496 meta = {
1497 license = [ pkgs.lib.licenses.mit ];
1497 license = [ pkgs.lib.licenses.mit ];
1498 };
1498 };
1499 };
1499 };
1500 pytest-runner = super.buildPythonPackage {
1500 pytest-runner = super.buildPythonPackage {
1501 name = "pytest-runner-3.0";
1501 name = "pytest-runner-3.0";
1502 buildInputs = with self; [];
1502 buildInputs = with self; [];
1503 doCheck = false;
1503 doCheck = false;
1504 propagatedBuildInputs = with self; [];
1504 propagatedBuildInputs = with self; [];
1505 src = fetchurl {
1505 src = fetchurl {
1506 url = "https://pypi.python.org/packages/65/b4/ae89338cd2d81e2cc54bd6db2e962bfe948f612303610d68ab24539ac2d1/pytest-runner-3.0.tar.gz";
1506 url = "https://pypi.python.org/packages/65/b4/ae89338cd2d81e2cc54bd6db2e962bfe948f612303610d68ab24539ac2d1/pytest-runner-3.0.tar.gz";
1507 md5 = "8f8363a52bbabc4cedd5e239beb2ba11";
1507 md5 = "8f8363a52bbabc4cedd5e239beb2ba11";
1508 };
1508 };
1509 meta = {
1509 meta = {
1510 license = [ pkgs.lib.licenses.mit ];
1510 license = [ pkgs.lib.licenses.mit ];
1511 };
1511 };
1512 };
1512 };
1513 pytest-sugar = super.buildPythonPackage {
1513 pytest-sugar = super.buildPythonPackage {
1514 name = "pytest-sugar-0.9.0";
1514 name = "pytest-sugar-0.9.0";
1515 buildInputs = with self; [];
1515 buildInputs = with self; [];
1516 doCheck = false;
1516 doCheck = false;
1517 propagatedBuildInputs = with self; [pytest termcolor];
1517 propagatedBuildInputs = with self; [pytest termcolor];
1518 src = fetchurl {
1518 src = fetchurl {
1519 url = "https://pypi.python.org/packages/49/d8/c5ff6cca3ce2ebd8b73eec89779bf6b4a7737456a70e8ea4d44c1ff90f71/pytest-sugar-0.9.0.tar.gz";
1519 url = "https://pypi.python.org/packages/49/d8/c5ff6cca3ce2ebd8b73eec89779bf6b4a7737456a70e8ea4d44c1ff90f71/pytest-sugar-0.9.0.tar.gz";
1520 md5 = "89fbff17277fa6a95a560a04b68cb9f9";
1520 md5 = "89fbff17277fa6a95a560a04b68cb9f9";
1521 };
1521 };
1522 meta = {
1522 meta = {
1523 license = [ pkgs.lib.licenses.bsdOriginal ];
1523 license = [ pkgs.lib.licenses.bsdOriginal ];
1524 };
1524 };
1525 };
1525 };
1526 pytest-timeout = super.buildPythonPackage {
1526 pytest-timeout = super.buildPythonPackage {
1527 name = "pytest-timeout-1.2.0";
1527 name = "pytest-timeout-1.2.0";
1528 buildInputs = with self; [];
1528 buildInputs = with self; [];
1529 doCheck = false;
1529 doCheck = false;
1530 propagatedBuildInputs = with self; [pytest];
1530 propagatedBuildInputs = with self; [pytest];
1531 src = fetchurl {
1531 src = fetchurl {
1532 url = "https://pypi.python.org/packages/cc/b7/b2a61365ea6b6d2e8881360ae7ed8dad0327ad2df89f2f0be4a02304deb2/pytest-timeout-1.2.0.tar.gz";
1532 url = "https://pypi.python.org/packages/cc/b7/b2a61365ea6b6d2e8881360ae7ed8dad0327ad2df89f2f0be4a02304deb2/pytest-timeout-1.2.0.tar.gz";
1533 md5 = "83607d91aa163562c7ee835da57d061d";
1533 md5 = "83607d91aa163562c7ee835da57d061d";
1534 };
1534 };
1535 meta = {
1535 meta = {
1536 license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ];
1536 license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ];
1537 };
1537 };
1538 };
1538 };
1539 python-dateutil = super.buildPythonPackage {
1539 python-dateutil = super.buildPythonPackage {
1540 name = "python-dateutil-2.6.1";
1540 name = "python-dateutil-2.6.1";
1541 buildInputs = with self; [];
1541 buildInputs = with self; [];
1542 doCheck = false;
1542 doCheck = false;
1543 propagatedBuildInputs = with self; [six];
1543 propagatedBuildInputs = with self; [six];
1544 src = fetchurl {
1544 src = fetchurl {
1545 url = "https://pypi.python.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz";
1545 url = "https://pypi.python.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz";
1546 md5 = "db38f6b4511cefd76014745bb0cc45a4";
1546 md5 = "db38f6b4511cefd76014745bb0cc45a4";
1547 };
1547 };
1548 meta = {
1548 meta = {
1549 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "Simplified BSD"; } ];
1549 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "Simplified BSD"; } ];
1550 };
1550 };
1551 };
1551 };
1552 python-editor = super.buildPythonPackage {
1552 python-editor = super.buildPythonPackage {
1553 name = "python-editor-1.0.3";
1553 name = "python-editor-1.0.3";
1554 buildInputs = with self; [];
1554 buildInputs = with self; [];
1555 doCheck = false;
1555 doCheck = false;
1556 propagatedBuildInputs = with self; [];
1556 propagatedBuildInputs = with self; [];
1557 src = fetchurl {
1557 src = fetchurl {
1558 url = "https://pypi.python.org/packages/65/1e/adf6e000ea5dc909aa420352d6ba37f16434c8a3c2fa030445411a1ed545/python-editor-1.0.3.tar.gz";
1558 url = "https://pypi.python.org/packages/65/1e/adf6e000ea5dc909aa420352d6ba37f16434c8a3c2fa030445411a1ed545/python-editor-1.0.3.tar.gz";
1559 md5 = "0aca5f2ef176ce68e98a5b7e31372835";
1559 md5 = "0aca5f2ef176ce68e98a5b7e31372835";
1560 };
1560 };
1561 meta = {
1561 meta = {
1562 license = [ pkgs.lib.licenses.asl20 { fullName = "Apache"; } ];
1562 license = [ pkgs.lib.licenses.asl20 { fullName = "Apache"; } ];
1563 };
1563 };
1564 };
1564 };
1565 python-ldap = super.buildPythonPackage {
1565 python-ldap = super.buildPythonPackage {
1566 name = "python-ldap-2.4.45";
1566 name = "python-ldap-2.4.45";
1567 buildInputs = with self; [];
1567 buildInputs = with self; [];
1568 doCheck = false;
1568 doCheck = false;
1569 propagatedBuildInputs = with self; [setuptools];
1569 propagatedBuildInputs = with self; [setuptools];
1570 src = fetchurl {
1570 src = fetchurl {
1571 url = "https://pypi.python.org/packages/ce/52/6b5372d0166820f4a4b0a88ed73dc7504219355049fc1d266d8ccdb7942e/python-ldap-2.4.45.tar.gz";
1571 url = "https://pypi.python.org/packages/ce/52/6b5372d0166820f4a4b0a88ed73dc7504219355049fc1d266d8ccdb7942e/python-ldap-2.4.45.tar.gz";
1572 md5 = "6108e189a44eea8bc7d1cc281c222978";
1572 md5 = "6108e189a44eea8bc7d1cc281c222978";
1573 };
1573 };
1574 meta = {
1574 meta = {
1575 license = [ pkgs.lib.licenses.psfl ];
1575 license = [ pkgs.lib.licenses.psfl ];
1576 };
1576 };
1577 };
1577 };
1578 python-memcached = super.buildPythonPackage {
1578 python-memcached = super.buildPythonPackage {
1579 name = "python-memcached-1.58";
1579 name = "python-memcached-1.58";
1580 buildInputs = with self; [];
1580 buildInputs = with self; [];
1581 doCheck = false;
1581 doCheck = false;
1582 propagatedBuildInputs = with self; [six];
1582 propagatedBuildInputs = with self; [six];
1583 src = fetchurl {
1583 src = fetchurl {
1584 url = "https://pypi.python.org/packages/f7/62/14b2448cfb04427366f24104c9da97cf8ea380d7258a3233f066a951a8d8/python-memcached-1.58.tar.gz";
1584 url = "https://pypi.python.org/packages/f7/62/14b2448cfb04427366f24104c9da97cf8ea380d7258a3233f066a951a8d8/python-memcached-1.58.tar.gz";
1585 md5 = "23b258105013d14d899828d334e6b044";
1585 md5 = "23b258105013d14d899828d334e6b044";
1586 };
1586 };
1587 meta = {
1587 meta = {
1588 license = [ pkgs.lib.licenses.psfl ];
1588 license = [ pkgs.lib.licenses.psfl ];
1589 };
1589 };
1590 };
1590 };
1591 python-pam = super.buildPythonPackage {
1591 python-pam = super.buildPythonPackage {
1592 name = "python-pam-1.8.2";
1592 name = "python-pam-1.8.2";
1593 buildInputs = with self; [];
1593 buildInputs = with self; [];
1594 doCheck = false;
1594 doCheck = false;
1595 propagatedBuildInputs = with self; [];
1595 propagatedBuildInputs = with self; [];
1596 src = fetchurl {
1596 src = fetchurl {
1597 url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz";
1597 url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz";
1598 md5 = "db71b6b999246fb05d78ecfbe166629d";
1598 md5 = "db71b6b999246fb05d78ecfbe166629d";
1599 };
1599 };
1600 meta = {
1600 meta = {
1601 license = [ { fullName = "License :: OSI Approved :: MIT License"; } pkgs.lib.licenses.mit ];
1601 license = [ { fullName = "License :: OSI Approved :: MIT License"; } pkgs.lib.licenses.mit ];
1602 };
1602 };
1603 };
1603 };
1604 pytz = super.buildPythonPackage {
1604 pytz = super.buildPythonPackage {
1605 name = "pytz-2017.3";
1605 name = "pytz-2018.3";
1606 buildInputs = with self; [];
1606 buildInputs = with self; [];
1607 doCheck = false;
1607 doCheck = false;
1608 propagatedBuildInputs = with self; [];
1608 propagatedBuildInputs = with self; [];
1609 src = fetchurl {
1609 src = fetchurl {
1610 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
1610 url = "https://pypi.python.org/packages/1b/50/4cdc62fc0753595fc16c8f722a89740f487c6e5670c644eb8983946777be/pytz-2018.3.tar.gz";
1611 md5 = "7006b56c0d68a162d9fe57d4249c3171";
1611 md5 = "abb07c09c79f78d7c04f222a550c99ef";
1612 };
1612 };
1613 meta = {
1613 meta = {
1614 license = [ pkgs.lib.licenses.mit ];
1614 license = [ pkgs.lib.licenses.mit ];
1615 };
1615 };
1616 };
1616 };
1617 pyzmq = super.buildPythonPackage {
1617 pyzmq = super.buildPythonPackage {
1618 name = "pyzmq-14.6.0";
1618 name = "pyzmq-14.6.0";
1619 buildInputs = with self; [];
1619 buildInputs = with self; [];
1620 doCheck = false;
1620 doCheck = false;
1621 propagatedBuildInputs = with self; [];
1621 propagatedBuildInputs = with self; [];
1622 src = fetchurl {
1622 src = fetchurl {
1623 url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz";
1623 url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz";
1624 md5 = "395b5de95a931afa5b14c9349a5b8024";
1624 md5 = "395b5de95a931afa5b14c9349a5b8024";
1625 };
1625 };
1626 meta = {
1626 meta = {
1627 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1627 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1628 };
1628 };
1629 };
1629 };
1630 recaptcha-client = super.buildPythonPackage {
1630 recaptcha-client = super.buildPythonPackage {
1631 name = "recaptcha-client-1.0.6";
1631 name = "recaptcha-client-1.0.6";
1632 buildInputs = with self; [];
1632 buildInputs = with self; [];
1633 doCheck = false;
1633 doCheck = false;
1634 propagatedBuildInputs = with self; [];
1634 propagatedBuildInputs = with self; [];
1635 src = fetchurl {
1635 src = fetchurl {
1636 url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz";
1636 url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz";
1637 md5 = "74228180f7e1fb76c4d7089160b0d919";
1637 md5 = "74228180f7e1fb76c4d7089160b0d919";
1638 };
1638 };
1639 meta = {
1639 meta = {
1640 license = [ { fullName = "MIT/X11"; } ];
1640 license = [ { fullName = "MIT/X11"; } ];
1641 };
1641 };
1642 };
1642 };
1643 redis = super.buildPythonPackage {
1643 redis = super.buildPythonPackage {
1644 name = "redis-2.10.6";
1644 name = "redis-2.10.6";
1645 buildInputs = with self; [];
1645 buildInputs = with self; [];
1646 doCheck = false;
1646 doCheck = false;
1647 propagatedBuildInputs = with self; [];
1647 propagatedBuildInputs = with self; [];
1648 src = fetchurl {
1648 src = fetchurl {
1649 url = "https://pypi.python.org/packages/09/8d/6d34b75326bf96d4139a2ddd8e74b80840f800a0a79f9294399e212cb9a7/redis-2.10.6.tar.gz";
1649 url = "https://pypi.python.org/packages/09/8d/6d34b75326bf96d4139a2ddd8e74b80840f800a0a79f9294399e212cb9a7/redis-2.10.6.tar.gz";
1650 md5 = "048348d8cfe0b5d0bba2f4d835005c3b";
1650 md5 = "048348d8cfe0b5d0bba2f4d835005c3b";
1651 };
1651 };
1652 meta = {
1652 meta = {
1653 license = [ pkgs.lib.licenses.mit ];
1653 license = [ pkgs.lib.licenses.mit ];
1654 };
1654 };
1655 };
1655 };
1656 repoze.lru = super.buildPythonPackage {
1656 repoze.lru = super.buildPythonPackage {
1657 name = "repoze.lru-0.7";
1657 name = "repoze.lru-0.7";
1658 buildInputs = with self; [];
1658 buildInputs = with self; [];
1659 doCheck = false;
1659 doCheck = false;
1660 propagatedBuildInputs = with self; [];
1660 propagatedBuildInputs = with self; [];
1661 src = fetchurl {
1661 src = fetchurl {
1662 url = "https://pypi.python.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz";
1662 url = "https://pypi.python.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz";
1663 md5 = "c08cc030387e0b1fc53c5c7d964b35e2";
1663 md5 = "c08cc030387e0b1fc53c5c7d964b35e2";
1664 };
1664 };
1665 meta = {
1665 meta = {
1666 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1666 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1667 };
1667 };
1668 };
1668 };
1669 requests = super.buildPythonPackage {
1669 requests = super.buildPythonPackage {
1670 name = "requests-2.9.1";
1670 name = "requests-2.9.1";
1671 buildInputs = with self; [];
1671 buildInputs = with self; [];
1672 doCheck = false;
1672 doCheck = false;
1673 propagatedBuildInputs = with self; [];
1673 propagatedBuildInputs = with self; [];
1674 src = fetchurl {
1674 src = fetchurl {
1675 url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz";
1675 url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz";
1676 md5 = "0b7f480d19012ec52bab78292efd976d";
1676 md5 = "0b7f480d19012ec52bab78292efd976d";
1677 };
1677 };
1678 meta = {
1678 meta = {
1679 license = [ pkgs.lib.licenses.asl20 ];
1679 license = [ pkgs.lib.licenses.asl20 ];
1680 };
1680 };
1681 };
1681 };
1682 rhodecode-enterprise-ce = super.buildPythonPackage {
1682 rhodecode-enterprise-ce = super.buildPythonPackage {
1683 name = "rhodecode-enterprise-ce-4.11.6";
1683 name = "rhodecode-enterprise-ce-4.12.0";
1684 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
1684 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
1685 doCheck = true;
1685 doCheck = true;
1686 propagatedBuildInputs = with self; [setuptools-scm amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz pyzmq py-gfm recaptcha-client redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 supervisor Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
1686 propagatedBuildInputs = with self; [setuptools-scm amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz tzlocal pyzmq py-gfm recaptcha-client redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 supervisor Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
1687 src = ./.;
1687 src = ./.;
1688 meta = {
1688 meta = {
1689 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1689 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1690 };
1690 };
1691 };
1691 };
1692 rhodecode-tools = super.buildPythonPackage {
1692 rhodecode-tools = super.buildPythonPackage {
1693 name = "rhodecode-tools-0.14.1";
1693 name = "rhodecode-tools-0.14.1";
1694 buildInputs = with self; [];
1694 buildInputs = with self; [];
1695 doCheck = false;
1695 doCheck = false;
1696 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh];
1696 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh];
1697 src = fetchurl {
1697 src = fetchurl {
1698 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2";
1698 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2";
1699 md5 = "0b9c2caad160b68889f8172ea54af7b2";
1699 md5 = "0b9c2caad160b68889f8172ea54af7b2";
1700 };
1700 };
1701 meta = {
1701 meta = {
1702 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1702 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1703 };
1703 };
1704 };
1704 };
1705 scandir = super.buildPythonPackage {
1705 scandir = super.buildPythonPackage {
1706 name = "scandir-1.6";
1706 name = "scandir-1.7";
1707 buildInputs = with self; [];
1707 buildInputs = with self; [];
1708 doCheck = false;
1708 doCheck = false;
1709 propagatedBuildInputs = with self; [];
1709 propagatedBuildInputs = with self; [];
1710 src = fetchurl {
1710 src = fetchurl {
1711 url = "https://pypi.python.org/packages/77/3f/916f524f50ee65e3f465a280d2851bd63685250fddb3020c212b3977664d/scandir-1.6.tar.gz";
1711 url = "https://pypi.python.org/packages/13/bb/e541b74230bbf7a20a3949a2ee6631be299378a784f5445aa5d0047c192b/scandir-1.7.tar.gz";
1712 md5 = "0180ddb97c96cbb2d4f25d2ae11c64ac";
1712 md5 = "037e5f24d1a0e78b17faca72dea9555f";
1713 };
1713 };
1714 meta = {
1714 meta = {
1715 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
1715 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
1716 };
1716 };
1717 };
1717 };
1718 setproctitle = super.buildPythonPackage {
1718 setproctitle = super.buildPythonPackage {
1719 name = "setproctitle-1.1.10";
1719 name = "setproctitle-1.1.10";
1720 buildInputs = with self; [];
1720 buildInputs = with self; [];
1721 doCheck = false;
1721 doCheck = false;
1722 propagatedBuildInputs = with self; [];
1722 propagatedBuildInputs = with self; [];
1723 src = fetchurl {
1723 src = fetchurl {
1724 url = "https://pypi.python.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz";
1724 url = "https://pypi.python.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz";
1725 md5 = "2dcdd1b761700a5a13252fea3dfd1977";
1725 md5 = "2dcdd1b761700a5a13252fea3dfd1977";
1726 };
1726 };
1727 meta = {
1727 meta = {
1728 license = [ pkgs.lib.licenses.bsdOriginal ];
1728 license = [ pkgs.lib.licenses.bsdOriginal ];
1729 };
1729 };
1730 };
1730 };
1731 setuptools = super.buildPythonPackage {
1731 setuptools = super.buildPythonPackage {
1732 name = "setuptools-30.1.0";
1732 name = "setuptools-30.1.0";
1733 buildInputs = with self; [];
1733 buildInputs = with self; [];
1734 doCheck = false;
1734 doCheck = false;
1735 propagatedBuildInputs = with self; [];
1735 propagatedBuildInputs = with self; [];
1736 src = fetchurl {
1736 src = fetchurl {
1737 url = "https://pypi.python.org/packages/1e/43/002c8616db9a3e7be23c2556e39b90a32bb40ba0dc652de1999d5334d372/setuptools-30.1.0.tar.gz";
1737 url = "https://pypi.python.org/packages/1e/43/002c8616db9a3e7be23c2556e39b90a32bb40ba0dc652de1999d5334d372/setuptools-30.1.0.tar.gz";
1738 md5 = "cac497f42e5096ac8df29e38d3f81c3e";
1738 md5 = "cac497f42e5096ac8df29e38d3f81c3e";
1739 };
1739 };
1740 meta = {
1740 meta = {
1741 license = [ pkgs.lib.licenses.mit ];
1741 license = [ pkgs.lib.licenses.mit ];
1742 };
1742 };
1743 };
1743 };
1744 setuptools-scm = super.buildPythonPackage {
1744 setuptools-scm = super.buildPythonPackage {
1745 name = "setuptools-scm-1.15.6";
1745 name = "setuptools-scm-1.15.6";
1746 buildInputs = with self; [];
1746 buildInputs = with self; [];
1747 doCheck = false;
1747 doCheck = false;
1748 propagatedBuildInputs = with self; [];
1748 propagatedBuildInputs = with self; [];
1749 src = fetchurl {
1749 src = fetchurl {
1750 url = "https://pypi.python.org/packages/03/6d/aafdd01edd227ee879b691455bf19895091872af7e48192bea1758c82032/setuptools_scm-1.15.6.tar.gz";
1750 url = "https://pypi.python.org/packages/03/6d/aafdd01edd227ee879b691455bf19895091872af7e48192bea1758c82032/setuptools_scm-1.15.6.tar.gz";
1751 md5 = "f17493d53f0d842bb0152f214775640b";
1751 md5 = "f17493d53f0d842bb0152f214775640b";
1752 };
1752 };
1753 meta = {
1753 meta = {
1754 license = [ pkgs.lib.licenses.mit ];
1754 license = [ pkgs.lib.licenses.mit ];
1755 };
1755 };
1756 };
1756 };
1757 simplegeneric = super.buildPythonPackage {
1757 simplegeneric = super.buildPythonPackage {
1758 name = "simplegeneric-0.8.1";
1758 name = "simplegeneric-0.8.1";
1759 buildInputs = with self; [];
1759 buildInputs = with self; [];
1760 doCheck = false;
1760 doCheck = false;
1761 propagatedBuildInputs = with self; [];
1761 propagatedBuildInputs = with self; [];
1762 src = fetchurl {
1762 src = fetchurl {
1763 url = "https://pypi.python.org/packages/3d/57/4d9c9e3ae9a255cd4e1106bb57e24056d3d0709fc01b2e3e345898e49d5b/simplegeneric-0.8.1.zip";
1763 url = "https://pypi.python.org/packages/3d/57/4d9c9e3ae9a255cd4e1106bb57e24056d3d0709fc01b2e3e345898e49d5b/simplegeneric-0.8.1.zip";
1764 md5 = "f9c1fab00fd981be588fc32759f474e3";
1764 md5 = "f9c1fab00fd981be588fc32759f474e3";
1765 };
1765 };
1766 meta = {
1766 meta = {
1767 license = [ pkgs.lib.licenses.zpt21 ];
1767 license = [ pkgs.lib.licenses.zpt21 ];
1768 };
1768 };
1769 };
1769 };
1770 simplejson = super.buildPythonPackage {
1770 simplejson = super.buildPythonPackage {
1771 name = "simplejson-3.11.1";
1771 name = "simplejson-3.11.1";
1772 buildInputs = with self; [];
1772 buildInputs = with self; [];
1773 doCheck = false;
1773 doCheck = false;
1774 propagatedBuildInputs = with self; [];
1774 propagatedBuildInputs = with self; [];
1775 src = fetchurl {
1775 src = fetchurl {
1776 url = "https://pypi.python.org/packages/08/48/c97b668d6da7d7bebe7ea1817a6f76394b0ec959cb04214ca833c34359df/simplejson-3.11.1.tar.gz";
1776 url = "https://pypi.python.org/packages/08/48/c97b668d6da7d7bebe7ea1817a6f76394b0ec959cb04214ca833c34359df/simplejson-3.11.1.tar.gz";
1777 md5 = "6e2f1bd5fb0a926facf5d89d217a7183";
1777 md5 = "6e2f1bd5fb0a926facf5d89d217a7183";
1778 };
1778 };
1779 meta = {
1779 meta = {
1780 license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ];
1780 license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ];
1781 };
1781 };
1782 };
1782 };
1783 six = super.buildPythonPackage {
1783 six = super.buildPythonPackage {
1784 name = "six-1.11.0";
1784 name = "six-1.11.0";
1785 buildInputs = with self; [];
1785 buildInputs = with self; [];
1786 doCheck = false;
1786 doCheck = false;
1787 propagatedBuildInputs = with self; [];
1787 propagatedBuildInputs = with self; [];
1788 src = fetchurl {
1788 src = fetchurl {
1789 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
1789 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
1790 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
1790 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
1791 };
1791 };
1792 meta = {
1792 meta = {
1793 license = [ pkgs.lib.licenses.mit ];
1793 license = [ pkgs.lib.licenses.mit ];
1794 };
1794 };
1795 };
1795 };
1796 sshpubkeys = super.buildPythonPackage {
1796 sshpubkeys = super.buildPythonPackage {
1797 name = "sshpubkeys-2.2.0";
1797 name = "sshpubkeys-2.2.0";
1798 buildInputs = with self; [];
1798 buildInputs = with self; [];
1799 doCheck = false;
1799 doCheck = false;
1800 propagatedBuildInputs = with self; [pycrypto ecdsa];
1800 propagatedBuildInputs = with self; [pycrypto ecdsa];
1801 src = fetchurl {
1801 src = fetchurl {
1802 url = "https://pypi.python.org/packages/27/da/337fabeb3dca6b62039a93ceaa636f25065e0ae92b575b1235342076cf0a/sshpubkeys-2.2.0.tar.gz";
1802 url = "https://pypi.python.org/packages/27/da/337fabeb3dca6b62039a93ceaa636f25065e0ae92b575b1235342076cf0a/sshpubkeys-2.2.0.tar.gz";
1803 md5 = "458e45f6b92b1afa84f0ffe1f1c90935";
1803 md5 = "458e45f6b92b1afa84f0ffe1f1c90935";
1804 };
1804 };
1805 meta = {
1805 meta = {
1806 license = [ pkgs.lib.licenses.bsdOriginal ];
1806 license = [ pkgs.lib.licenses.bsdOriginal ];
1807 };
1807 };
1808 };
1808 };
1809 subprocess32 = super.buildPythonPackage {
1809 subprocess32 = super.buildPythonPackage {
1810 name = "subprocess32-3.2.7";
1810 name = "subprocess32-3.2.7";
1811 buildInputs = with self; [];
1811 buildInputs = with self; [];
1812 doCheck = false;
1812 doCheck = false;
1813 propagatedBuildInputs = with self; [];
1813 propagatedBuildInputs = with self; [];
1814 src = fetchurl {
1814 src = fetchurl {
1815 url = "https://pypi.python.org/packages/b8/2f/49e53b0d0e94611a2dc624a1ad24d41b6d94d0f1b0a078443407ea2214c2/subprocess32-3.2.7.tar.gz";
1815 url = "https://pypi.python.org/packages/b8/2f/49e53b0d0e94611a2dc624a1ad24d41b6d94d0f1b0a078443407ea2214c2/subprocess32-3.2.7.tar.gz";
1816 md5 = "824c801e479d3e916879aae3e9c15e16";
1816 md5 = "824c801e479d3e916879aae3e9c15e16";
1817 };
1817 };
1818 meta = {
1818 meta = {
1819 license = [ pkgs.lib.licenses.psfl ];
1819 license = [ pkgs.lib.licenses.psfl ];
1820 };
1820 };
1821 };
1821 };
1822 supervisor = super.buildPythonPackage {
1822 supervisor = super.buildPythonPackage {
1823 name = "supervisor-3.3.3";
1823 name = "supervisor-3.3.4";
1824 buildInputs = with self; [];
1824 buildInputs = with self; [];
1825 doCheck = false;
1825 doCheck = false;
1826 propagatedBuildInputs = with self; [meld3];
1826 propagatedBuildInputs = with self; [meld3];
1827 src = fetchurl {
1827 src = fetchurl {
1828 url = "https://pypi.python.org/packages/31/7e/788fc6566211e77c395ea272058eb71299c65cc5e55b6214d479c6c2ec9a/supervisor-3.3.3.tar.gz";
1828 url = "https://pypi.python.org/packages/44/60/698e54b4a4a9b956b2d709b4b7b676119c833d811d53ee2500f1b5e96dc3/supervisor-3.3.4.tar.gz";
1829 md5 = "0fe86dfec4e5c5d98324d24c4cf944bd";
1829 md5 = "f1814d71d820ddfa8c86d46a72314cec";
1830 };
1830 };
1831 meta = {
1831 meta = {
1832 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1832 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1833 };
1833 };
1834 };
1834 };
1835 termcolor = super.buildPythonPackage {
1835 termcolor = super.buildPythonPackage {
1836 name = "termcolor-1.1.0";
1836 name = "termcolor-1.1.0";
1837 buildInputs = with self; [];
1837 buildInputs = with self; [];
1838 doCheck = false;
1838 doCheck = false;
1839 propagatedBuildInputs = with self; [];
1839 propagatedBuildInputs = with self; [];
1840 src = fetchurl {
1840 src = fetchurl {
1841 url = "https://pypi.python.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
1841 url = "https://pypi.python.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
1842 md5 = "043e89644f8909d462fbbfa511c768df";
1842 md5 = "043e89644f8909d462fbbfa511c768df";
1843 };
1843 };
1844 meta = {
1844 meta = {
1845 license = [ pkgs.lib.licenses.mit ];
1845 license = [ pkgs.lib.licenses.mit ];
1846 };
1846 };
1847 };
1847 };
1848 testpath = super.buildPythonPackage {
1848 testpath = super.buildPythonPackage {
1849 name = "testpath-0.3.1";
1849 name = "testpath-0.3.1";
1850 buildInputs = with self; [];
1850 buildInputs = with self; [];
1851 doCheck = false;
1851 doCheck = false;
1852 propagatedBuildInputs = with self; [];
1852 propagatedBuildInputs = with self; [];
1853 src = fetchurl {
1853 src = fetchurl {
1854 url = "https://pypi.python.org/packages/f4/8b/b71e9ee10e5f751e9d959bc750ab122ba04187f5aa52aabdc4e63b0e31a7/testpath-0.3.1.tar.gz";
1854 url = "https://pypi.python.org/packages/f4/8b/b71e9ee10e5f751e9d959bc750ab122ba04187f5aa52aabdc4e63b0e31a7/testpath-0.3.1.tar.gz";
1855 md5 = "2cd5ed5522fda781bb497c9d80ae2fc9";
1855 md5 = "2cd5ed5522fda781bb497c9d80ae2fc9";
1856 };
1856 };
1857 meta = {
1857 meta = {
1858 license = [ pkgs.lib.licenses.mit ];
1858 license = [ pkgs.lib.licenses.mit ];
1859 };
1859 };
1860 };
1860 };
1861 traitlets = super.buildPythonPackage {
1861 traitlets = super.buildPythonPackage {
1862 name = "traitlets-4.3.2";
1862 name = "traitlets-4.3.2";
1863 buildInputs = with self; [];
1863 buildInputs = with self; [];
1864 doCheck = false;
1864 doCheck = false;
1865 propagatedBuildInputs = with self; [ipython-genutils six decorator enum34];
1865 propagatedBuildInputs = with self; [ipython-genutils six decorator enum34];
1866 src = fetchurl {
1866 src = fetchurl {
1867 url = "https://pypi.python.org/packages/a5/98/7f5ef2fe9e9e071813aaf9cb91d1a732e0a68b6c44a32b38cb8e14c3f069/traitlets-4.3.2.tar.gz";
1867 url = "https://pypi.python.org/packages/a5/98/7f5ef2fe9e9e071813aaf9cb91d1a732e0a68b6c44a32b38cb8e14c3f069/traitlets-4.3.2.tar.gz";
1868 md5 = "3068663f2f38fd939a9eb3a500ccc154";
1868 md5 = "3068663f2f38fd939a9eb3a500ccc154";
1869 };
1869 };
1870 meta = {
1870 meta = {
1871 license = [ pkgs.lib.licenses.bsdOriginal ];
1871 license = [ pkgs.lib.licenses.bsdOriginal ];
1872 };
1872 };
1873 };
1873 };
1874 transifex-client = super.buildPythonPackage {
1874 transifex-client = super.buildPythonPackage {
1875 name = "transifex-client-0.12.5";
1875 name = "transifex-client-0.12.5";
1876 buildInputs = with self; [];
1876 buildInputs = with self; [];
1877 doCheck = false;
1877 doCheck = false;
1878 propagatedBuildInputs = with self; [urllib3 six];
1878 propagatedBuildInputs = with self; [urllib3 six];
1879 src = fetchurl {
1879 src = fetchurl {
1880 url = "https://pypi.python.org/packages/7b/86/60f31a0c9b8d0b1266ce15b6c80b55f88522140c8acfc395d5aec5e23475/transifex-client-0.12.5.tar.gz";
1880 url = "https://pypi.python.org/packages/7b/86/60f31a0c9b8d0b1266ce15b6c80b55f88522140c8acfc395d5aec5e23475/transifex-client-0.12.5.tar.gz";
1881 md5 = "e6e278117b23f60702c06e203b7e51ae";
1881 md5 = "e6e278117b23f60702c06e203b7e51ae";
1882 };
1882 };
1883 meta = {
1883 meta = {
1884 license = [ pkgs.lib.licenses.gpl2 ];
1884 license = [ pkgs.lib.licenses.gpl2 ];
1885 };
1885 };
1886 };
1886 };
1887 translationstring = super.buildPythonPackage {
1887 translationstring = super.buildPythonPackage {
1888 name = "translationstring-1.3";
1888 name = "translationstring-1.3";
1889 buildInputs = with self; [];
1889 buildInputs = with self; [];
1890 doCheck = false;
1890 doCheck = false;
1891 propagatedBuildInputs = with self; [];
1891 propagatedBuildInputs = with self; [];
1892 src = fetchurl {
1892 src = fetchurl {
1893 url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
1893 url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
1894 md5 = "a4b62e0f3c189c783a1685b3027f7c90";
1894 md5 = "a4b62e0f3c189c783a1685b3027f7c90";
1895 };
1895 };
1896 meta = {
1896 meta = {
1897 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
1897 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
1898 };
1898 };
1899 };
1899 };
1900 trollius = super.buildPythonPackage {
1900 trollius = super.buildPythonPackage {
1901 name = "trollius-1.0.4";
1901 name = "trollius-1.0.4";
1902 buildInputs = with self; [];
1902 buildInputs = with self; [];
1903 doCheck = false;
1903 doCheck = false;
1904 propagatedBuildInputs = with self; [futures];
1904 propagatedBuildInputs = with self; [futures];
1905 src = fetchurl {
1905 src = fetchurl {
1906 url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz";
1906 url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz";
1907 md5 = "3631a464d49d0cbfd30ab2918ef2b783";
1907 md5 = "3631a464d49d0cbfd30ab2918ef2b783";
1908 };
1908 };
1909 meta = {
1909 meta = {
1910 license = [ pkgs.lib.licenses.asl20 ];
1910 license = [ pkgs.lib.licenses.asl20 ];
1911 };
1911 };
1912 };
1912 };
1913 tzlocal = super.buildPythonPackage {
1914 name = "tzlocal-1.5.1";
1915 buildInputs = with self; [];
1916 doCheck = false;
1917 propagatedBuildInputs = with self; [pytz];
1918 src = fetchurl {
1919 url = "https://pypi.python.org/packages/cb/89/e3687d3ed99bc882793f82634e9824e62499fdfdc4b1ae39e211c5b05017/tzlocal-1.5.1.tar.gz";
1920 md5 = "4553be891efa0812c4adfb0c6e818eec";
1921 };
1922 meta = {
1923 license = [ pkgs.lib.licenses.mit ];
1924 };
1925 };
1913 uWSGI = super.buildPythonPackage {
1926 uWSGI = super.buildPythonPackage {
1914 name = "uWSGI-2.0.15";
1927 name = "uWSGI-2.0.15";
1915 buildInputs = with self; [];
1928 buildInputs = with self; [];
1916 doCheck = false;
1929 doCheck = false;
1917 propagatedBuildInputs = with self; [];
1930 propagatedBuildInputs = with self; [];
1918 src = fetchurl {
1931 src = fetchurl {
1919 url = "https://pypi.python.org/packages/bb/0a/45e5aa80dc135889594bb371c082d20fb7ee7303b174874c996888cc8511/uwsgi-2.0.15.tar.gz";
1932 url = "https://pypi.python.org/packages/bb/0a/45e5aa80dc135889594bb371c082d20fb7ee7303b174874c996888cc8511/uwsgi-2.0.15.tar.gz";
1920 md5 = "fc50bd9e83b7602fa474b032167010a7";
1933 md5 = "fc50bd9e83b7602fa474b032167010a7";
1921 };
1934 };
1922 meta = {
1935 meta = {
1923 license = [ pkgs.lib.licenses.gpl2 ];
1936 license = [ pkgs.lib.licenses.gpl2 ];
1924 };
1937 };
1925 };
1938 };
1926 urllib3 = super.buildPythonPackage {
1939 urllib3 = super.buildPythonPackage {
1927 name = "urllib3-1.16";
1940 name = "urllib3-1.16";
1928 buildInputs = with self; [];
1941 buildInputs = with self; [];
1929 doCheck = false;
1942 doCheck = false;
1930 propagatedBuildInputs = with self; [];
1943 propagatedBuildInputs = with self; [];
1931 src = fetchurl {
1944 src = fetchurl {
1932 url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz";
1945 url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz";
1933 md5 = "fcaab1c5385c57deeb7053d3d7d81d59";
1946 md5 = "fcaab1c5385c57deeb7053d3d7d81d59";
1934 };
1947 };
1935 meta = {
1948 meta = {
1936 license = [ pkgs.lib.licenses.mit ];
1949 license = [ pkgs.lib.licenses.mit ];
1937 };
1950 };
1938 };
1951 };
1939 venusian = super.buildPythonPackage {
1952 venusian = super.buildPythonPackage {
1940 name = "venusian-1.1.0";
1953 name = "venusian-1.1.0";
1941 buildInputs = with self; [];
1954 buildInputs = with self; [];
1942 doCheck = false;
1955 doCheck = false;
1943 propagatedBuildInputs = with self; [];
1956 propagatedBuildInputs = with self; [];
1944 src = fetchurl {
1957 src = fetchurl {
1945 url = "https://pypi.python.org/packages/38/24/b4b470ab9e0a2e2e9b9030c7735828c8934b4c6b45befd1bb713ec2aeb2d/venusian-1.1.0.tar.gz";
1958 url = "https://pypi.python.org/packages/38/24/b4b470ab9e0a2e2e9b9030c7735828c8934b4c6b45befd1bb713ec2aeb2d/venusian-1.1.0.tar.gz";
1946 md5 = "56bc5e6756e4bda37bcdb94f74a72b8f";
1959 md5 = "56bc5e6756e4bda37bcdb94f74a72b8f";
1947 };
1960 };
1948 meta = {
1961 meta = {
1949 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1962 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1950 };
1963 };
1951 };
1964 };
1952 vine = super.buildPythonPackage {
1965 vine = super.buildPythonPackage {
1953 name = "vine-1.1.4";
1966 name = "vine-1.1.4";
1954 buildInputs = with self; [];
1967 buildInputs = with self; [];
1955 doCheck = false;
1968 doCheck = false;
1956 propagatedBuildInputs = with self; [];
1969 propagatedBuildInputs = with self; [];
1957 src = fetchurl {
1970 src = fetchurl {
1958 url = "https://pypi.python.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz";
1971 url = "https://pypi.python.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz";
1959 md5 = "9fdb971e7fd15b181b84f3bfcf20d11c";
1972 md5 = "9fdb971e7fd15b181b84f3bfcf20d11c";
1960 };
1973 };
1961 meta = {
1974 meta = {
1962 license = [ pkgs.lib.licenses.bsdOriginal ];
1975 license = [ pkgs.lib.licenses.bsdOriginal ];
1963 };
1976 };
1964 };
1977 };
1965 waitress = super.buildPythonPackage {
1978 waitress = super.buildPythonPackage {
1966 name = "waitress-1.1.0";
1979 name = "waitress-1.1.0";
1967 buildInputs = with self; [];
1980 buildInputs = with self; [];
1968 doCheck = false;
1981 doCheck = false;
1969 propagatedBuildInputs = with self; [];
1982 propagatedBuildInputs = with self; [];
1970 src = fetchurl {
1983 src = fetchurl {
1971 url = "https://pypi.python.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz";
1984 url = "https://pypi.python.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz";
1972 md5 = "0f1eb7fdfdbf2e6d18decbda1733045c";
1985 md5 = "0f1eb7fdfdbf2e6d18decbda1733045c";
1973 };
1986 };
1974 meta = {
1987 meta = {
1975 license = [ pkgs.lib.licenses.zpt21 ];
1988 license = [ pkgs.lib.licenses.zpt21 ];
1976 };
1989 };
1977 };
1990 };
1978 wcwidth = super.buildPythonPackage {
1991 wcwidth = super.buildPythonPackage {
1979 name = "wcwidth-0.1.7";
1992 name = "wcwidth-0.1.7";
1980 buildInputs = with self; [];
1993 buildInputs = with self; [];
1981 doCheck = false;
1994 doCheck = false;
1982 propagatedBuildInputs = with self; [];
1995 propagatedBuildInputs = with self; [];
1983 src = fetchurl {
1996 src = fetchurl {
1984 url = "https://pypi.python.org/packages/55/11/e4a2bb08bb450fdbd42cc709dd40de4ed2c472cf0ccb9e64af22279c5495/wcwidth-0.1.7.tar.gz";
1997 url = "https://pypi.python.org/packages/55/11/e4a2bb08bb450fdbd42cc709dd40de4ed2c472cf0ccb9e64af22279c5495/wcwidth-0.1.7.tar.gz";
1985 md5 = "b3b6a0a08f0c8a34d1de8cf44150a4ad";
1998 md5 = "b3b6a0a08f0c8a34d1de8cf44150a4ad";
1986 };
1999 };
1987 meta = {
2000 meta = {
1988 license = [ pkgs.lib.licenses.mit ];
2001 license = [ pkgs.lib.licenses.mit ];
1989 };
2002 };
1990 };
2003 };
1991 webencodings = super.buildPythonPackage {
2004 webencodings = super.buildPythonPackage {
1992 name = "webencodings-0.5.1";
2005 name = "webencodings-0.5.1";
1993 buildInputs = with self; [];
2006 buildInputs = with self; [];
1994 doCheck = false;
2007 doCheck = false;
1995 propagatedBuildInputs = with self; [];
2008 propagatedBuildInputs = with self; [];
1996 src = fetchurl {
2009 src = fetchurl {
1997 url = "https://pypi.python.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz";
2010 url = "https://pypi.python.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz";
1998 md5 = "32f6e261d52e57bf7e1c4d41546d15b8";
2011 md5 = "32f6e261d52e57bf7e1c4d41546d15b8";
1999 };
2012 };
2000 meta = {
2013 meta = {
2001 license = [ pkgs.lib.licenses.bsdOriginal ];
2014 license = [ pkgs.lib.licenses.bsdOriginal ];
2002 };
2015 };
2003 };
2016 };
2004 ws4py = super.buildPythonPackage {
2017 ws4py = super.buildPythonPackage {
2005 name = "ws4py-0.4.2";
2018 name = "ws4py-0.4.3";
2006 buildInputs = with self; [];
2019 buildInputs = with self; [];
2007 doCheck = false;
2020 doCheck = false;
2008 propagatedBuildInputs = with self; [];
2021 propagatedBuildInputs = with self; [];
2009 src = fetchurl {
2022 src = fetchurl {
2010 url = "https://pypi.python.org/packages/b8/98/a90f1d96ffcb15dfc220af524ce23e0a5881258dafa197673357ce1683dd/ws4py-0.4.2.tar.gz";
2023 url = "https://pypi.python.org/packages/fa/a1/33c43a4304ac3b4dc81deb93cbd329de9297dd034d75c47cce64fda806bc/ws4py-0.4.3.tar.gz";
2011 md5 = "f0603ae376707a58d205bd87a67758a2";
2024 md5 = "d5834cf7d3965bb0da31bbb02bd8513a";
2012 };
2025 };
2013 meta = {
2026 meta = {
2014 license = [ pkgs.lib.licenses.bsdOriginal ];
2027 license = [ pkgs.lib.licenses.bsdOriginal ];
2015 };
2028 };
2016 };
2029 };
2017 wsgiref = super.buildPythonPackage {
2030 wsgiref = super.buildPythonPackage {
2018 name = "wsgiref-0.1.2";
2031 name = "wsgiref-0.1.2";
2019 buildInputs = with self; [];
2032 buildInputs = with self; [];
2020 doCheck = false;
2033 doCheck = false;
2021 propagatedBuildInputs = with self; [];
2034 propagatedBuildInputs = with self; [];
2022 src = fetchurl {
2035 src = fetchurl {
2023 url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip";
2036 url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip";
2024 md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb";
2037 md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb";
2025 };
2038 };
2026 meta = {
2039 meta = {
2027 license = [ { fullName = "PSF or ZPL"; } ];
2040 license = [ { fullName = "PSF or ZPL"; } ];
2028 };
2041 };
2029 };
2042 };
2030 zope.cachedescriptors = super.buildPythonPackage {
2043 zope.cachedescriptors = super.buildPythonPackage {
2031 name = "zope.cachedescriptors-4.0.0";
2044 name = "zope.cachedescriptors-4.3.1";
2032 buildInputs = with self; [];
2045 buildInputs = with self; [];
2033 doCheck = false;
2046 doCheck = false;
2034 propagatedBuildInputs = with self; [setuptools];
2047 propagatedBuildInputs = with self; [setuptools];
2035 src = fetchurl {
2048 src = fetchurl {
2036 url = "https://pypi.python.org/packages/40/33/694b6644c37f28553f4b9f20b3c3a20fb709a22574dff20b5bdffb09ecd5/zope.cachedescriptors-4.0.0.tar.gz";
2049 url = "https://pypi.python.org/packages/2f/89/ebe1890cc6d3291ebc935558fa764d5fffe571018dbbee200e9db78762cb/zope.cachedescriptors-4.3.1.tar.gz";
2037 md5 = "8d308de8c936792c8e758058fcb7d0f0";
2050 md5 = "42f3693f43bc93f3b1eb86940f58acf3";
2038 };
2051 };
2039 meta = {
2052 meta = {
2040 license = [ pkgs.lib.licenses.zpt21 ];
2053 license = [ pkgs.lib.licenses.zpt21 ];
2041 };
2054 };
2042 };
2055 };
2043 zope.deprecation = super.buildPythonPackage {
2056 zope.deprecation = super.buildPythonPackage {
2044 name = "zope.deprecation-4.1.2";
2057 name = "zope.deprecation-4.3.0";
2045 buildInputs = with self; [];
2058 buildInputs = with self; [];
2046 doCheck = false;
2059 doCheck = false;
2047 propagatedBuildInputs = with self; [setuptools];
2060 propagatedBuildInputs = with self; [setuptools];
2048 src = fetchurl {
2061 src = fetchurl {
2049 url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz";
2062 url = "https://pypi.python.org/packages/a1/18/2dc5e6bfe64fdc3b79411b67464c55bb0b43b127051a20f7f492ab767758/zope.deprecation-4.3.0.tar.gz";
2050 md5 = "e9a663ded58f4f9f7881beb56cae2782";
2063 md5 = "2166b2cb7e0e96a21104e6f8f9b696bb";
2051 };
2064 };
2052 meta = {
2065 meta = {
2053 license = [ pkgs.lib.licenses.zpt21 ];
2066 license = [ pkgs.lib.licenses.zpt21 ];
2054 };
2067 };
2055 };
2068 };
2056 zope.event = super.buildPythonPackage {
2069 zope.event = super.buildPythonPackage {
2057 name = "zope.event-4.0.3";
2070 name = "zope.event-4.3.0";
2058 buildInputs = with self; [];
2071 buildInputs = with self; [];
2059 doCheck = false;
2072 doCheck = false;
2060 propagatedBuildInputs = with self; [setuptools];
2073 propagatedBuildInputs = with self; [setuptools];
2061 src = fetchurl {
2074 src = fetchurl {
2062 url = "https://pypi.python.org/packages/c1/29/91ba884d7d6d96691df592e9e9c2bfa57a47040ec1ff47eff18c85137152/zope.event-4.0.3.tar.gz";
2075 url = "https://pypi.python.org/packages/9e/d0/54ba59f19a0635f6591b74be259cf6fbf67e73f4edda27b5cd0cf4d26efa/zope.event-4.3.0.tar.gz";
2063 md5 = "9a3780916332b18b8b85f522bcc3e249";
2076 md5 = "8ca737960741c6fd112972f3313303bd";
2064 };
2077 };
2065 meta = {
2078 meta = {
2066 license = [ pkgs.lib.licenses.zpt21 ];
2079 license = [ pkgs.lib.licenses.zpt21 ];
2067 };
2080 };
2068 };
2081 };
2069 zope.interface = super.buildPythonPackage {
2082 zope.interface = super.buildPythonPackage {
2070 name = "zope.interface-4.1.3";
2083 name = "zope.interface-4.4.3";
2071 buildInputs = with self; [];
2084 buildInputs = with self; [];
2072 doCheck = false;
2085 doCheck = false;
2073 propagatedBuildInputs = with self; [setuptools];
2086 propagatedBuildInputs = with self; [setuptools];
2074 src = fetchurl {
2087 src = fetchurl {
2075 url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz";
2088 url = "https://pypi.python.org/packages/bd/d2/25349ed41f9dcff7b3baf87bd88a4c82396cf6e02f1f42bb68657a3132af/zope.interface-4.4.3.tar.gz";
2076 md5 = "9ae3d24c0c7415deb249dd1a132f0f79";
2089 md5 = "8700a4f527c1203b34b10c2b4e7a6912";
2077 };
2090 };
2078 meta = {
2091 meta = {
2079 license = [ pkgs.lib.licenses.zpt21 ];
2092 license = [ pkgs.lib.licenses.zpt21 ];
2080 };
2093 };
2081 };
2094 };
2082
2095
2083 ### Test requirements
2096 ### Test requirements
2084
2097
2085
2098
2086 }
2099 }
@@ -1,131 +1,132 b''
1 ## core
1 ## core
2 setuptools==30.1.0
2 setuptools==30.1.0
3 setuptools-scm==1.15.6
3 setuptools-scm==1.15.6
4
4
5 amqp==2.2.2
5 amqp==2.2.2
6 authomatic==0.1.0.post1
6 authomatic==0.1.0.post1
7 Babel==1.3
7 Babel==1.3
8 Beaker==1.9.0
8 Beaker==1.9.1
9 celery==4.1.0
9 celery==4.1.0
10 Chameleon==2.24
10 Chameleon==2.24
11 channelstream==0.5.2
11 channelstream==0.5.2
12 click==6.6
12 click==6.6
13 colander==1.4.0
13 colander==1.4.0
14 configobj==5.0.6
14 configobj==5.0.6
15 cssselect==1.0.1
15 cssselect==1.0.1
16 decorator==4.1.2
16 decorator==4.1.2
17 deform==2.0.4
17 deform==2.0.4
18 docutils==0.14.0
18 docutils==0.14.0
19 dogpile.cache==0.6.4
19 dogpile.cache==0.6.4
20 dogpile.core==0.4.1
20 dogpile.core==0.4.1
21 ecdsa==0.13
21 ecdsa==0.13
22 FormEncode==1.2.4
22 FormEncode==1.2.4
23 future==0.14.3
23 future==0.14.3
24 futures==3.0.2
24 futures==3.0.2
25 gnureadline==6.3.8
25 gnureadline==6.3.8
26 infrae.cache==1.0.1
26 infrae.cache==1.0.1
27 iso8601==0.1.12
27 iso8601==0.1.12
28 itsdangerous==0.24
28 itsdangerous==0.24
29 Jinja2==2.9.6
29 Jinja2==2.9.6
30 billiard==3.5.0.3
30 billiard==3.5.0.3
31 kombu==4.1.0
31 kombu==4.1.0
32 lxml==3.7.3
32 lxml==3.7.3
33 Mako==1.0.7
33 Mako==1.0.7
34 Markdown==2.6.9
34 Markdown==2.6.11
35 MarkupSafe==1.0.0
35 MarkupSafe==1.0.0
36 msgpack-python==0.4.8
36 msgpack-python==0.4.8
37 MySQL-python==1.2.5
37 MySQL-python==1.2.5
38 objgraph==3.1.1
38 objgraph==3.1.1
39 packaging==15.2
39 packaging==15.2
40 Paste==2.0.3
40 Paste==2.0.3
41 PasteDeploy==1.5.2
41 PasteDeploy==1.5.2
42 PasteScript==2.0.2
42 PasteScript==2.0.2
43 pathlib2==2.3.0
43 pathlib2==2.3.0
44 peppercorn==0.5
44 peppercorn==0.5
45 psutil==5.4.0
45 psutil==5.4.3
46 psycopg2==2.7.3.2
46 psycopg2==2.7.3.2
47 py-bcrypt==0.4
47 py-bcrypt==0.4
48 pycrypto==2.6.1
48 pycrypto==2.6.1
49 pycurl==7.19.5
49 pycurl==7.19.5
50 pyflakes==0.8.1
50 pyflakes==0.8.1
51 pygments-markdown-lexer==0.1.0.dev39
51 pygments-markdown-lexer==0.1.0.dev39
52 Pygments==2.2.0
52 Pygments==2.2.0
53 pyparsing==1.5.7
53 pyparsing==1.5.7
54 pyramid-beaker==0.8
54 pyramid-beaker==0.8
55 pyramid-debugtoolbar==4.3.0
55 pyramid-debugtoolbar==4.3.0
56 pyramid-jinja2==2.7
56 pyramid-jinja2==2.7
57 pyramid-mako==1.0.2
57 pyramid-mako==1.0.2
58 pyramid==1.9.1
58 pyramid==1.9.1
59 pysqlite==2.8.3
59 pysqlite==2.8.3
60 python-dateutil
60 python-dateutil
61 python-ldap==2.4.45
61 python-ldap==2.4.45
62 python-memcached==1.58
62 python-memcached==1.58
63 python-pam==1.8.2
63 python-pam==1.8.2
64 pytz==2017.3
64 pytz==2018.3
65 tzlocal==1.5.1
65 pyzmq==14.6.0
66 pyzmq==14.6.0
66 py-gfm==0.1.3
67 py-gfm==0.1.3
67 recaptcha-client==1.0.6
68 recaptcha-client==1.0.6
68 redis==2.10.6
69 redis==2.10.6
69 repoze.lru==0.7
70 repoze.lru==0.7
70 requests==2.9.1
71 requests==2.9.1
71 Routes==2.4.1
72 Routes==2.4.1
72 setproctitle==1.1.10
73 setproctitle==1.1.10
73 simplejson==3.11.1
74 simplejson==3.11.1
74 six==1.11.0
75 six==1.11.0
75 SQLAlchemy==1.1.15
76 SQLAlchemy==1.1.15
76 sshpubkeys==2.2.0
77 sshpubkeys==2.2.0
77 subprocess32==3.2.7
78 subprocess32==3.2.7
78 supervisor==3.3.3
79 supervisor==3.3.4
79 Tempita==0.5.2
80 Tempita==0.5.2
80 translationstring==1.3
81 translationstring==1.3
81 trollius==1.0.4
82 trollius==1.0.4
82 urllib3==1.16
83 urllib3==1.16
83 URLObject==2.4.0
84 URLObject==2.4.0
84 venusian==1.1.0
85 venusian==1.1.0
85 WebError==0.10.3
86 WebError==0.10.3
86 WebHelpers2==2.0
87 WebHelpers2==2.0
87 WebHelpers==1.3
88 WebHelpers==1.3
88 WebOb==1.7.4
89 WebOb==1.7.4
89 Whoosh==2.7.4
90 Whoosh==2.7.4
90 wsgiref==0.1.2
91 wsgiref==0.1.2
91 zope.cachedescriptors==4.0.0
92 zope.cachedescriptors==4.3.1
92 zope.deprecation==4.1.2
93 zope.deprecation==4.3.0
93 zope.event==4.0.3
94 zope.event==4.3.0
94 zope.interface==4.1.3
95 zope.interface==4.4.3
95
96
96
97
97 # IPYTHON RENDERING
98 # IPYTHON RENDERING
98 # entrypoints backport, pypi version doesn't support egg installs
99 # entrypoints backport, pypi version doesn't support egg installs
99 https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1
100 https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1
100 nbconvert==5.3.1
101 nbconvert==5.3.1
101 bleach==2.1.1
102 bleach==2.1.2
102 nbformat==4.4.0
103 nbformat==4.4.0
103 jupyter_client==5.0.0
104 jupyter_client==5.0.0
104
105
105 ## cli tools
106 ## cli tools
106 alembic==0.9.6
107 alembic==0.9.8
107 invoke==0.13.0
108 invoke==0.13.0
108 bumpversion==0.5.3
109 bumpversion==0.5.3
109 transifex-client==0.12.5
110 transifex-client==0.12.5
110
111
111 ## http servers
112 ## http servers
112 gevent==1.2.2
113 gevent==1.2.2
113 greenlet==0.4.12
114 greenlet==0.4.13
114 gunicorn==19.7.1
115 gunicorn==19.7.1
115 waitress==1.1.0
116 waitress==1.1.0
116 uWSGI==2.0.15
117 uWSGI==2.0.15
117
118
118 ## debug
119 ## debug
119 ipdb==0.10.3
120 ipdb==0.10.3
120 ipython==5.1.0
121 ipython==5.1.0
121 CProfileV==1.0.7
122 CProfileV==1.0.7
122 bottle==0.12.13
123 bottle==0.12.13
123
124
124 ## rhodecode-tools, special case
125 ## rhodecode-tools, special case
125 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2#egg=rhodecode-tools==0.14.1
126 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2#egg=rhodecode-tools==0.14.1
126
127
127 ## appenlight
128 ## appenlight
128 appenlight-client==0.6.22
129 appenlight-client==0.6.25
129
130
130 ## test related requirements
131 ## test related requirements
131 -r requirements_test.txt
132 -r requirements_test.txt
@@ -1,1 +1,1 b''
1 4.11.6 No newline at end of file
1 4.12.0 No newline at end of file
@@ -1,63 +1,63 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22
22
23 RhodeCode, a web based repository management software
23 RhodeCode, a web based repository management software
24 versioning implementation: http://www.python.org/dev/peps/pep-0386/
24 versioning implementation: http://www.python.org/dev/peps/pep-0386/
25 """
25 """
26
26
27 import os
27 import os
28 import sys
28 import sys
29 import platform
29 import platform
30
30
31 VERSION = tuple(open(os.path.join(
31 VERSION = tuple(open(os.path.join(
32 os.path.dirname(__file__), 'VERSION')).read().split('.'))
32 os.path.dirname(__file__), 'VERSION')).read().split('.'))
33
33
34 BACKENDS = {
34 BACKENDS = {
35 'hg': 'Mercurial repository',
35 'hg': 'Mercurial repository',
36 'git': 'Git repository',
36 'git': 'Git repository',
37 'svn': 'Subversion repository',
37 'svn': 'Subversion repository',
38 }
38 }
39
39
40 CELERY_ENABLED = False
40 CELERY_ENABLED = False
41 CELERY_EAGER = False
41 CELERY_EAGER = False
42
42
43 # link to config for pyramid
43 # link to config for pyramid
44 CONFIG = {}
44 CONFIG = {}
45
45
46 # Populated with the settings dictionary from application init in
46 # Populated with the settings dictionary from application init in
47 # rhodecode.conf.environment.load_pyramid_environment
47 # rhodecode.conf.environment.load_pyramid_environment
48 PYRAMID_SETTINGS = {}
48 PYRAMID_SETTINGS = {}
49
49
50 # Linked module for extensions
50 # Linked module for extensions
51 EXTENSIONS = {}
51 EXTENSIONS = {}
52
52
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 85 # defines current db version for migrations
54 __dbversion__ = 86 # defines current db version for migrations
55 __platform__ = platform.system()
55 __platform__ = platform.system()
56 __license__ = 'AGPLv3, and Commercial License'
56 __license__ = 'AGPLv3, and Commercial License'
57 __author__ = 'RhodeCode GmbH'
57 __author__ = 'RhodeCode GmbH'
58 __url__ = 'https://code.rhodecode.com'
58 __url__ = 'https://code.rhodecode.com'
59
59
60 is_windows = __platform__ in ['Windows']
60 is_windows = __platform__ in ['Windows']
61 is_unix = not is_windows
61 is_unix = not is_windows
62 is_test = False
62 is_test = False
63 disable_error_handler = False
63 disable_error_handler = False
@@ -1,140 +1,141 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import pytest
22 import pytest
23
23
24 from rhodecode.api.tests.utils import build_data, api_call, assert_error
24 from rhodecode.api.tests.utils import build_data, api_call, assert_error
25
25
26
26
27 @pytest.mark.usefixtures("testuser_api", "app")
27 @pytest.mark.usefixtures("testuser_api", "app")
28 class TestGetRepoChangeset(object):
28 class TestGetRepoChangeset(object):
29 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
29 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
30 def test_get_repo_changeset(self, details, backend):
30 def test_get_repo_changeset(self, details, backend):
31 commit = backend.repo.get_commit(commit_idx=0)
31 commit = backend.repo.get_commit(commit_idx=0)
32 __, params = build_data(
32 __, params = build_data(
33 self.apikey, 'get_repo_changeset',
33 self.apikey, 'get_repo_changeset',
34 repoid=backend.repo_name, revision=commit.raw_id,
34 repoid=backend.repo_name, revision=commit.raw_id,
35 details=details,
35 details=details,
36 )
36 )
37 response = api_call(self.app, params)
37 response = api_call(self.app, params)
38 result = response.json['result']
38 result = response.json['result']
39 assert result['revision'] == 0
39 assert result['revision'] == 0
40 assert result['raw_id'] == commit.raw_id
40 assert result['raw_id'] == commit.raw_id
41
41
42 if details == 'full':
42 if details == 'full':
43 assert result['refs']['bookmarks'] == getattr(
43 assert result['refs']['bookmarks'] == getattr(
44 commit, 'bookmarks', [])
44 commit, 'bookmarks', [])
45 assert result['refs']['branches'] == [commit.branch]
45 branches = [commit.branch] if commit.branch else []
46 assert result['refs']['branches'] == branches
46 assert result['refs']['tags'] == commit.tags
47 assert result['refs']['tags'] == commit.tags
47
48
48 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
49 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
49 def test_get_repo_changeset_bad_type(self, details, backend):
50 def test_get_repo_changeset_bad_type(self, details, backend):
50 id_, params = build_data(
51 id_, params = build_data(
51 self.apikey, 'get_repo_changeset',
52 self.apikey, 'get_repo_changeset',
52 repoid=backend.repo_name, revision=0,
53 repoid=backend.repo_name, revision=0,
53 details=details,
54 details=details,
54 )
55 )
55 response = api_call(self.app, params)
56 response = api_call(self.app, params)
56 expected = 'commit_id must be a string value'
57 expected = 'commit_id must be a string value'
57 assert_error(id_, expected, given=response.body)
58 assert_error(id_, expected, given=response.body)
58
59
59 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
60 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
60 def test_get_repo_changesets(self, details, backend):
61 def test_get_repo_changesets(self, details, backend):
61 limit = 2
62 limit = 2
62 commit = backend.repo.get_commit(commit_idx=0)
63 commit = backend.repo.get_commit(commit_idx=0)
63 __, params = build_data(
64 __, params = build_data(
64 self.apikey, 'get_repo_changesets',
65 self.apikey, 'get_repo_changesets',
65 repoid=backend.repo_name, start_rev=commit.raw_id, limit=limit,
66 repoid=backend.repo_name, start_rev=commit.raw_id, limit=limit,
66 details=details,
67 details=details,
67 )
68 )
68 response = api_call(self.app, params)
69 response = api_call(self.app, params)
69 result = response.json['result']
70 result = response.json['result']
70 assert result
71 assert result
71 assert len(result) == limit
72 assert len(result) == limit
72 for x in xrange(limit):
73 for x in xrange(limit):
73 assert result[x]['revision'] == x
74 assert result[x]['revision'] == x
74
75
75 if details == 'full':
76 if details == 'full':
76 for x in xrange(limit):
77 for x in xrange(limit):
77 assert 'bookmarks' in result[x]['refs']
78 assert 'bookmarks' in result[x]['refs']
78 assert 'branches' in result[x]['refs']
79 assert 'branches' in result[x]['refs']
79 assert 'tags' in result[x]['refs']
80 assert 'tags' in result[x]['refs']
80
81
81 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
82 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
82 @pytest.mark.parametrize("start_rev, expected_revision", [
83 @pytest.mark.parametrize("start_rev, expected_revision", [
83 ("0", 0),
84 ("0", 0),
84 ("10", 10),
85 ("10", 10),
85 ("20", 20),
86 ("20", 20),
86 ])
87 ])
87 @pytest.mark.backends("hg", "git")
88 @pytest.mark.backends("hg", "git")
88 def test_get_repo_changesets_commit_range(
89 def test_get_repo_changesets_commit_range(
89 self, details, backend, start_rev, expected_revision):
90 self, details, backend, start_rev, expected_revision):
90 limit = 10
91 limit = 10
91 __, params = build_data(
92 __, params = build_data(
92 self.apikey, 'get_repo_changesets',
93 self.apikey, 'get_repo_changesets',
93 repoid=backend.repo_name, start_rev=start_rev, limit=limit,
94 repoid=backend.repo_name, start_rev=start_rev, limit=limit,
94 details=details,
95 details=details,
95 )
96 )
96 response = api_call(self.app, params)
97 response = api_call(self.app, params)
97 result = response.json['result']
98 result = response.json['result']
98 assert result
99 assert result
99 assert len(result) == limit
100 assert len(result) == limit
100 for i in xrange(limit):
101 for i in xrange(limit):
101 assert result[i]['revision'] == int(expected_revision) + i
102 assert result[i]['revision'] == int(expected_revision) + i
102
103
103 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
104 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
104 @pytest.mark.parametrize("start_rev, expected_revision", [
105 @pytest.mark.parametrize("start_rev, expected_revision", [
105 ("0", 0),
106 ("0", 0),
106 ("10", 9),
107 ("10", 9),
107 ("20", 19),
108 ("20", 19),
108 ])
109 ])
109 def test_get_repo_changesets_commit_range_svn(
110 def test_get_repo_changesets_commit_range_svn(
110 self, details, backend_svn, start_rev, expected_revision):
111 self, details, backend_svn, start_rev, expected_revision):
111
112
112 # TODO: johbo: SVN showed a problem here: The parameter "start_rev"
113 # TODO: johbo: SVN showed a problem here: The parameter "start_rev"
113 # in our API allows to pass in a "Commit ID" as well as a
114 # in our API allows to pass in a "Commit ID" as well as a
114 # "Commit Index". In the case of Subversion it is not possible to
115 # "Commit Index". In the case of Subversion it is not possible to
115 # distinguish these cases. As a workaround we implemented this
116 # distinguish these cases. As a workaround we implemented this
116 # behavior which gives a preference to see it as a "Commit ID".
117 # behavior which gives a preference to see it as a "Commit ID".
117
118
118 limit = 10
119 limit = 10
119 __, params = build_data(
120 __, params = build_data(
120 self.apikey, 'get_repo_changesets',
121 self.apikey, 'get_repo_changesets',
121 repoid=backend_svn.repo_name, start_rev=start_rev, limit=limit,
122 repoid=backend_svn.repo_name, start_rev=start_rev, limit=limit,
122 details=details,
123 details=details,
123 )
124 )
124 response = api_call(self.app, params)
125 response = api_call(self.app, params)
125 result = response.json['result']
126 result = response.json['result']
126 assert result
127 assert result
127 assert len(result) == limit
128 assert len(result) == limit
128 for i in xrange(limit):
129 for i in xrange(limit):
129 assert result[i]['revision'] == int(expected_revision) + i
130 assert result[i]['revision'] == int(expected_revision) + i
130
131
131 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
132 @pytest.mark.parametrize("details", ['basic', 'extended', 'full'])
132 def test_get_repo_changesets_bad_type(self, details, backend):
133 def test_get_repo_changesets_bad_type(self, details, backend):
133 id_, params = build_data(
134 id_, params = build_data(
134 self.apikey, 'get_repo_changesets',
135 self.apikey, 'get_repo_changesets',
135 repoid=backend.repo_name, start_rev=0, limit=2,
136 repoid=backend.repo_name, start_rev=0, limit=2,
136 details=details,
137 details=details,
137 )
138 )
138 response = api_call(self.app, params)
139 response = api_call(self.app, params)
139 expected = 'commit_id must be a string value'
140 expected = 'commit_id must be a string value'
140 assert_error(id_, expected, given=response.body)
141 assert_error(id_, expected, given=response.body)
@@ -1,51 +1,53 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22
22
23 import pytest
23 import pytest
24
24
25 from rhodecode.tests import TESTS_TMP_PATH
25 from rhodecode.tests import TESTS_TMP_PATH
26 from rhodecode.api.tests.utils import (
26 from rhodecode.api.tests.utils import (
27 build_data, api_call, assert_ok, assert_error)
27 build_data, api_call, assert_ok, assert_error)
28
28
29
29
30 @pytest.mark.usefixtures("testuser_api", "app")
30 @pytest.mark.usefixtures("testuser_api", "app")
31 class TestPull(object):
31 class TestPull(object):
32 @pytest.mark.backends("git", "hg")
32 @pytest.mark.backends("git", "hg")
33 def test_api_pull(self, backend):
33 def test_api_pull(self, backend):
34 r = backend.create_repo()
34 r = backend.create_repo()
35 repo_name = r.repo_name
35 repo_name = r.repo_name
36 r.clone_uri = os.path.join(TESTS_TMP_PATH, backend.repo_name)
36 clone_uri = os.path.join(TESTS_TMP_PATH, backend.repo_name)
37 r.clone_uri = clone_uri
37
38
38 id_, params = build_data(self.apikey, 'pull', repoid=repo_name,)
39 id_, params = build_data(self.apikey, 'pull', repoid=repo_name,)
39 response = api_call(self.app, params)
40 response = api_call(self.app, params)
40
41 msg = 'Pulled from url `%s` on repo `%s`' % (
41 expected = {'msg': 'Pulled from `%s`' % (repo_name,),
42 clone_uri, repo_name)
43 expected = {'msg': msg,
42 'repository': repo_name}
44 'repository': repo_name}
43 assert_ok(id_, expected, given=response.body)
45 assert_ok(id_, expected, given=response.body)
44
46
45 def test_api_pull_error(self, backend):
47 def test_api_pull_error(self, backend):
46 id_, params = build_data(
48 id_, params = build_data(
47 self.apikey, 'pull', repoid=backend.repo_name)
49 self.apikey, 'pull', repoid=backend.repo_name)
48 response = api_call(self.app, params)
50 response = api_call(self.app, params)
49
51
50 expected = 'Unable to pull changes from `%s`' % (backend.repo_name,)
52 expected = 'Unable to pull changes from `None`'
51 assert_error(id_, expected, given=response.body)
53 assert_error(id_, expected, given=response.body)
@@ -1,194 +1,197 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import mock
21 import mock
22 import pytest
22 import pytest
23
23
24 from rhodecode.model.repo import RepoModel
24 from rhodecode.model.repo import RepoModel
25 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN
25 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN
26 from rhodecode.api.tests.utils import (
26 from rhodecode.api.tests.utils import (
27 build_data, api_call, assert_error, assert_ok, crash, jsonify)
27 build_data, api_call, assert_error, assert_ok, crash, jsonify)
28 from rhodecode.tests.fixture import Fixture
28 from rhodecode.tests.fixture import Fixture
29 from rhodecode.tests.plugin import http_host_stub, http_host_only_stub
29 from rhodecode.tests.plugin import http_host_stub, http_host_only_stub
30
30
31 fixture = Fixture()
31 fixture = Fixture()
32
32
33 UPDATE_REPO_NAME = 'api_update_me'
33 UPDATE_REPO_NAME = 'api_update_me'
34
34
35
35
36 class SAME_AS_UPDATES(object):
36 class SAME_AS_UPDATES(object):
37 """ Constant used for tests below """
37 """ Constant used for tests below """
38
38
39
39
40 @pytest.mark.usefixtures("testuser_api", "app")
40 @pytest.mark.usefixtures("testuser_api", "app")
41 class TestApiUpdateRepo(object):
41 class TestApiUpdateRepo(object):
42
42
43 @pytest.mark.parametrize("updates, expected", [
43 @pytest.mark.parametrize("updates, expected", [
44 ({'owner': TEST_USER_REGULAR_LOGIN},
44 ({'owner': TEST_USER_REGULAR_LOGIN},
45 SAME_AS_UPDATES),
45 SAME_AS_UPDATES),
46
46
47 ({'description': 'new description'},
47 ({'description': 'new description'},
48 SAME_AS_UPDATES),
48 SAME_AS_UPDATES),
49
49
50 ({'clone_uri': 'http://foo.com/repo'},
50 ({'clone_uri': 'http://foo.com/repo'},
51 SAME_AS_UPDATES),
51 SAME_AS_UPDATES),
52
52
53 ({'clone_uri': None},
53 ({'clone_uri': None},
54 {'clone_uri': ''}),
54 {'clone_uri': ''}),
55
55
56 ({'clone_uri': ''},
56 ({'clone_uri': ''},
57 {'clone_uri': ''}),
57 {'clone_uri': ''}),
58
58
59 ({'push_uri': ''},
60 {'push_uri': ''}),
61
59 ({'landing_rev': 'rev:tip'},
62 ({'landing_rev': 'rev:tip'},
60 {'landing_rev': ['rev', 'tip']}),
63 {'landing_rev': ['rev', 'tip']}),
61
64
62 ({'enable_statistics': True},
65 ({'enable_statistics': True},
63 SAME_AS_UPDATES),
66 SAME_AS_UPDATES),
64
67
65 ({'enable_locking': True},
68 ({'enable_locking': True},
66 SAME_AS_UPDATES),
69 SAME_AS_UPDATES),
67
70
68 ({'enable_downloads': True},
71 ({'enable_downloads': True},
69 SAME_AS_UPDATES),
72 SAME_AS_UPDATES),
70
73
71 ({'repo_name': 'new_repo_name'},
74 ({'repo_name': 'new_repo_name'},
72 {
75 {
73 'repo_name': 'new_repo_name',
76 'repo_name': 'new_repo_name',
74 'url': 'http://{}/new_repo_name'.format(http_host_only_stub())
77 'url': 'http://{}/new_repo_name'.format(http_host_only_stub())
75 }),
78 }),
76
79
77 ({'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
80 ({'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
78 '_group': 'test_group_for_update'},
81 '_group': 'test_group_for_update'},
79 {
82 {
80 'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
83 'repo_name': 'test_group_for_update/{}'.format(UPDATE_REPO_NAME),
81 'url': 'http://{}/test_group_for_update/{}'.format(
84 'url': 'http://{}/test_group_for_update/{}'.format(
82 http_host_only_stub(), UPDATE_REPO_NAME)
85 http_host_only_stub(), UPDATE_REPO_NAME)
83 }),
86 }),
84 ])
87 ])
85 def test_api_update_repo(self, updates, expected, backend):
88 def test_api_update_repo(self, updates, expected, backend):
86 repo_name = UPDATE_REPO_NAME
89 repo_name = UPDATE_REPO_NAME
87 repo = fixture.create_repo(repo_name, repo_type=backend.alias)
90 repo = fixture.create_repo(repo_name, repo_type=backend.alias)
88 if updates.get('_group'):
91 if updates.get('_group'):
89 fixture.create_repo_group(updates['_group'])
92 fixture.create_repo_group(updates['_group'])
90
93
91 expected_api_data = repo.get_api_data(include_secrets=True)
94 expected_api_data = repo.get_api_data(include_secrets=True)
92 if expected is SAME_AS_UPDATES:
95 if expected is SAME_AS_UPDATES:
93 expected_api_data.update(updates)
96 expected_api_data.update(updates)
94 else:
97 else:
95 expected_api_data.update(expected)
98 expected_api_data.update(expected)
96
99
97 id_, params = build_data(
100 id_, params = build_data(
98 self.apikey, 'update_repo', repoid=repo_name, **updates)
101 self.apikey, 'update_repo', repoid=repo_name, **updates)
99
102
100 with mock.patch('rhodecode.model.validation_schema.validators.url_validator'):
103 with mock.patch('rhodecode.model.validation_schema.validators.url_validator'):
101 response = api_call(self.app, params)
104 response = api_call(self.app, params)
102
105
103 if updates.get('repo_name'):
106 if updates.get('repo_name'):
104 repo_name = updates['repo_name']
107 repo_name = updates['repo_name']
105
108
106 try:
109 try:
107 expected = {
110 expected = {
108 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
111 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
109 'repository': jsonify(expected_api_data)
112 'repository': jsonify(expected_api_data)
110 }
113 }
111 assert_ok(id_, expected, given=response.body)
114 assert_ok(id_, expected, given=response.body)
112 finally:
115 finally:
113 fixture.destroy_repo(repo_name)
116 fixture.destroy_repo(repo_name)
114 if updates.get('_group'):
117 if updates.get('_group'):
115 fixture.destroy_repo_group(updates['_group'])
118 fixture.destroy_repo_group(updates['_group'])
116
119
117 def test_api_update_repo_fork_of_field(self, backend):
120 def test_api_update_repo_fork_of_field(self, backend):
118 master_repo = backend.create_repo()
121 master_repo = backend.create_repo()
119 repo = backend.create_repo()
122 repo = backend.create_repo()
120 updates = {
123 updates = {
121 'fork_of': master_repo.repo_name,
124 'fork_of': master_repo.repo_name,
122 'fork_of_id': master_repo.repo_id
125 'fork_of_id': master_repo.repo_id
123 }
126 }
124 expected_api_data = repo.get_api_data(include_secrets=True)
127 expected_api_data = repo.get_api_data(include_secrets=True)
125 expected_api_data.update(updates)
128 expected_api_data.update(updates)
126
129
127 id_, params = build_data(
130 id_, params = build_data(
128 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
131 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
129 response = api_call(self.app, params)
132 response = api_call(self.app, params)
130 expected = {
133 expected = {
131 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
134 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
132 'repository': jsonify(expected_api_data)
135 'repository': jsonify(expected_api_data)
133 }
136 }
134 assert_ok(id_, expected, given=response.body)
137 assert_ok(id_, expected, given=response.body)
135 result = response.json['result']['repository']
138 result = response.json['result']['repository']
136 assert result['fork_of'] == master_repo.repo_name
139 assert result['fork_of'] == master_repo.repo_name
137 assert result['fork_of_id'] == master_repo.repo_id
140 assert result['fork_of_id'] == master_repo.repo_id
138
141
139 def test_api_update_repo_fork_of_not_found(self, backend):
142 def test_api_update_repo_fork_of_not_found(self, backend):
140 master_repo_name = 'fake-parent-repo'
143 master_repo_name = 'fake-parent-repo'
141 repo = backend.create_repo()
144 repo = backend.create_repo()
142 updates = {
145 updates = {
143 'fork_of': master_repo_name
146 'fork_of': master_repo_name
144 }
147 }
145 id_, params = build_data(
148 id_, params = build_data(
146 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
149 self.apikey, 'update_repo', repoid=repo.repo_name, **updates)
147 response = api_call(self.app, params)
150 response = api_call(self.app, params)
148 expected = {
151 expected = {
149 'repo_fork_of': 'Fork with id `{}` does not exists'.format(
152 'repo_fork_of': 'Fork with id `{}` does not exists'.format(
150 master_repo_name)}
153 master_repo_name)}
151 assert_error(id_, expected, given=response.body)
154 assert_error(id_, expected, given=response.body)
152
155
153 def test_api_update_repo_with_repo_group_not_existing(self):
156 def test_api_update_repo_with_repo_group_not_existing(self):
154 repo_name = 'admin_owned'
157 repo_name = 'admin_owned'
155 fake_repo_group = 'test_group_for_update'
158 fake_repo_group = 'test_group_for_update'
156 fixture.create_repo(repo_name)
159 fixture.create_repo(repo_name)
157 updates = {'repo_name': '{}/{}'.format(fake_repo_group, repo_name)}
160 updates = {'repo_name': '{}/{}'.format(fake_repo_group, repo_name)}
158 id_, params = build_data(
161 id_, params = build_data(
159 self.apikey, 'update_repo', repoid=repo_name, **updates)
162 self.apikey, 'update_repo', repoid=repo_name, **updates)
160 response = api_call(self.app, params)
163 response = api_call(self.app, params)
161 try:
164 try:
162 expected = {
165 expected = {
163 'repo_group': 'Repository group `{}` does not exist'.format(fake_repo_group)
166 'repo_group': 'Repository group `{}` does not exist'.format(fake_repo_group)
164 }
167 }
165 assert_error(id_, expected, given=response.body)
168 assert_error(id_, expected, given=response.body)
166 finally:
169 finally:
167 fixture.destroy_repo(repo_name)
170 fixture.destroy_repo(repo_name)
168
171
169 def test_api_update_repo_regular_user_not_allowed(self):
172 def test_api_update_repo_regular_user_not_allowed(self):
170 repo_name = 'admin_owned'
173 repo_name = 'admin_owned'
171 fixture.create_repo(repo_name)
174 fixture.create_repo(repo_name)
172 updates = {'active': False}
175 updates = {'active': False}
173 id_, params = build_data(
176 id_, params = build_data(
174 self.apikey_regular, 'update_repo', repoid=repo_name, **updates)
177 self.apikey_regular, 'update_repo', repoid=repo_name, **updates)
175 response = api_call(self.app, params)
178 response = api_call(self.app, params)
176 try:
179 try:
177 expected = 'repository `%s` does not exist' % (repo_name,)
180 expected = 'repository `%s` does not exist' % (repo_name,)
178 assert_error(id_, expected, given=response.body)
181 assert_error(id_, expected, given=response.body)
179 finally:
182 finally:
180 fixture.destroy_repo(repo_name)
183 fixture.destroy_repo(repo_name)
181
184
182 @mock.patch.object(RepoModel, 'update', crash)
185 @mock.patch.object(RepoModel, 'update', crash)
183 def test_api_update_repo_exception_occurred(self, backend):
186 def test_api_update_repo_exception_occurred(self, backend):
184 repo_name = UPDATE_REPO_NAME
187 repo_name = UPDATE_REPO_NAME
185 fixture.create_repo(repo_name, repo_type=backend.alias)
188 fixture.create_repo(repo_name, repo_type=backend.alias)
186 id_, params = build_data(
189 id_, params = build_data(
187 self.apikey, 'update_repo', repoid=repo_name,
190 self.apikey, 'update_repo', repoid=repo_name,
188 owner=TEST_USER_ADMIN_LOGIN,)
191 owner=TEST_USER_ADMIN_LOGIN,)
189 response = api_call(self.app, params)
192 response = api_call(self.app, params)
190 try:
193 try:
191 expected = 'failed to update repo `%s`' % (repo_name,)
194 expected = 'failed to update repo `%s`' % (repo_name,)
192 assert_error(id_, expected, given=response.body)
195 assert_error(id_, expected, given=response.body)
193 finally:
196 finally:
194 fixture.destroy_repo(repo_name)
197 fixture.destroy_repo(repo_name)
@@ -1,110 +1,125 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import mock
21 import mock
22 import pytest
22 import pytest
23
23
24 from rhodecode.model.user import UserModel
24 from rhodecode.model.user import UserModel
25 from rhodecode.model.user_group import UserGroupModel
25 from rhodecode.model.user_group import UserGroupModel
26 from rhodecode.tests import TEST_USER_ADMIN_EMAIL
26 from rhodecode.tests import TEST_USER_ADMIN_EMAIL
27 from rhodecode.api.tests.utils import (
27 from rhodecode.api.tests.utils import (
28 build_data, api_call, assert_error, assert_ok, crash, jsonify)
28 build_data, api_call, assert_error, assert_ok, crash, jsonify)
29
29
30
30
31 @pytest.mark.usefixtures("testuser_api", "app")
31 @pytest.mark.usefixtures("testuser_api", "app")
32 class TestUpdateUserGroup(object):
32 class TestUpdateUserGroup(object):
33 @pytest.mark.parametrize("changing_attr, updates", [
33 @pytest.mark.parametrize("changing_attr, updates", [
34 ('group_name', {'group_name': 'new_group_name'}),
34 ('group_name', {'group_name': 'new_group_name'}),
35 ('group_name', {'group_name': 'test_group_for_update'}),
35 ('group_name', {'group_name': 'test_group_for_update'}),
36 # ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
36 # ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
37 ('owner_email', {'owner_email': TEST_USER_ADMIN_EMAIL}),
37 ('owner_email', {'owner_email': TEST_USER_ADMIN_EMAIL}),
38 ('active', {'active': False}),
38 ('active', {'active': False}),
39 ('active', {'active': True})
39 ('active', {'active': True}),
40 ('sync', {'sync': False}),
41 ('sync', {'sync': True})
40 ])
42 ])
41 def test_api_update_user_group(self, changing_attr, updates, user_util):
43 def test_api_update_user_group(self, changing_attr, updates, user_util):
42 user_group = user_util.create_user_group()
44 user_group = user_util.create_user_group()
43 group_name = user_group.users_group_name
45 group_name = user_group.users_group_name
44 expected_api_data = user_group.get_api_data()
46 expected_api_data = user_group.get_api_data()
45 expected_api_data.update(updates)
47 expected_api_data.update(updates)
46
48
47 id_, params = build_data(
49 id_, params = build_data(
48 self.apikey, 'update_user_group', usergroupid=group_name,
50 self.apikey, 'update_user_group', usergroupid=group_name,
49 **updates)
51 **updates)
50 response = api_call(self.app, params)
52 response = api_call(self.app, params)
51
53
54 # special case for sync
55 if changing_attr == 'sync' and updates['sync'] is False:
56 expected_api_data['sync'] = None
57 elif changing_attr == 'sync' and updates['sync'] is True:
58 expected_api_data['sync'] = 'manual_api'
59
52 expected = {
60 expected = {
53 'msg': 'updated user group ID:%s %s' % (
61 'msg': 'updated user group ID:%s %s' % (
54 user_group.users_group_id, user_group.users_group_name),
62 user_group.users_group_id, user_group.users_group_name),
55 'user_group': jsonify(expected_api_data)
63 'user_group': jsonify(expected_api_data)
56 }
64 }
57 assert_ok(id_, expected, given=response.body)
65 assert_ok(id_, expected, given=response.body)
58
66
59 @pytest.mark.parametrize("changing_attr, updates", [
67 @pytest.mark.parametrize("changing_attr, updates", [
60 # TODO: mikhail: decide if we need to test against the commented params
68 # TODO: mikhail: decide if we need to test against the commented params
61 # ('group_name', {'group_name': 'new_group_name'}),
69 # ('group_name', {'group_name': 'new_group_name'}),
62 # ('group_name', {'group_name': 'test_group_for_update'}),
70 # ('group_name', {'group_name': 'test_group_for_update'}),
63 # ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
71 # ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
64 ('owner_email', {'owner_email': TEST_USER_ADMIN_EMAIL}),
72 ('owner_email', {'owner_email': TEST_USER_ADMIN_EMAIL}),
65 ('active', {'active': False}),
73 ('active', {'active': False}),
66 ('active', {'active': True})
74 ('active', {'active': True}),
75 ('sync', {'sync': False}),
76 ('sync', {'sync': True})
67 ])
77 ])
68 def test_api_update_user_group_regular_user(
78 def test_api_update_user_group_regular_user(
69 self, changing_attr, updates, user_util):
79 self, changing_attr, updates, user_util):
70 user_group = user_util.create_user_group()
80 user_group = user_util.create_user_group()
71 group_name = user_group.users_group_name
81 group_name = user_group.users_group_name
72 expected_api_data = user_group.get_api_data()
82 expected_api_data = user_group.get_api_data()
73 expected_api_data.update(updates)
83 expected_api_data.update(updates)
74
84
75
76 # grant permission to this user
85 # grant permission to this user
77 user = UserModel().get_by_username(self.TEST_USER_LOGIN)
86 user = UserModel().get_by_username(self.TEST_USER_LOGIN)
78
87
79 user_util.grant_user_permission_to_user_group(
88 user_util.grant_user_permission_to_user_group(
80 user_group, user, 'usergroup.admin')
89 user_group, user, 'usergroup.admin')
81 id_, params = build_data(
90 id_, params = build_data(
82 self.apikey_regular, 'update_user_group',
91 self.apikey_regular, 'update_user_group',
83 usergroupid=group_name, **updates)
92 usergroupid=group_name, **updates)
84 response = api_call(self.app, params)
93 response = api_call(self.app, params)
94 # special case for sync
95 if changing_attr == 'sync' and updates['sync'] is False:
96 expected_api_data['sync'] = None
97 elif changing_attr == 'sync' and updates['sync'] is True:
98 expected_api_data['sync'] = 'manual_api'
99
85 expected = {
100 expected = {
86 'msg': 'updated user group ID:%s %s' % (
101 'msg': 'updated user group ID:%s %s' % (
87 user_group.users_group_id, user_group.users_group_name),
102 user_group.users_group_id, user_group.users_group_name),
88 'user_group': jsonify(expected_api_data)
103 'user_group': jsonify(expected_api_data)
89 }
104 }
90 assert_ok(id_, expected, given=response.body)
105 assert_ok(id_, expected, given=response.body)
91
106
92 def test_api_update_user_group_regular_user_no_permission(self, user_util):
107 def test_api_update_user_group_regular_user_no_permission(self, user_util):
93 user_group = user_util.create_user_group()
108 user_group = user_util.create_user_group()
94 group_name = user_group.users_group_name
109 group_name = user_group.users_group_name
95 id_, params = build_data(
110 id_, params = build_data(
96 self.apikey_regular, 'update_user_group', usergroupid=group_name)
111 self.apikey_regular, 'update_user_group', usergroupid=group_name)
97 response = api_call(self.app, params)
112 response = api_call(self.app, params)
98
113
99 expected = 'user group `%s` does not exist' % (group_name)
114 expected = 'user group `%s` does not exist' % (group_name)
100 assert_error(id_, expected, given=response.body)
115 assert_error(id_, expected, given=response.body)
101
116
102 @mock.patch.object(UserGroupModel, 'update', crash)
117 @mock.patch.object(UserGroupModel, 'update', crash)
103 def test_api_update_user_group_exception_occurred(self, user_util):
118 def test_api_update_user_group_exception_occurred(self, user_util):
104 user_group = user_util.create_user_group()
119 user_group = user_util.create_user_group()
105 group_name = user_group.users_group_name
120 group_name = user_group.users_group_name
106 id_, params = build_data(
121 id_, params = build_data(
107 self.apikey, 'update_user_group', usergroupid=group_name)
122 self.apikey, 'update_user_group', usergroupid=group_name)
108 response = api_call(self.app, params)
123 response = api_call(self.app, params)
109 expected = 'failed to update user group `%s`' % (group_name,)
124 expected = 'failed to update user group `%s`' % (group_name,)
110 assert_error(id_, expected, given=response.body)
125 assert_error(id_, expected, given=response.body)
@@ -1,2046 +1,2064 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2018 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import time
22 import time
23
23
24 import rhodecode
24 import rhodecode
25 from rhodecode.api import (
25 from rhodecode.api import (
26 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
26 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
27 from rhodecode.api.utils import (
27 from rhodecode.api.utils import (
28 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
28 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
29 get_user_group_or_error, get_user_or_error, validate_repo_permissions,
29 get_user_group_or_error, get_user_or_error, validate_repo_permissions,
30 get_perm_or_error, parse_args, get_origin, build_commit_data,
30 get_perm_or_error, parse_args, get_origin, build_commit_data,
31 validate_set_owner_permissions)
31 validate_set_owner_permissions)
32 from rhodecode.lib import audit_logger
32 from rhodecode.lib import audit_logger
33 from rhodecode.lib import repo_maintenance
33 from rhodecode.lib import repo_maintenance
34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
34 from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi
35 from rhodecode.lib.celerylib.utils import get_task_id
35 from rhodecode.lib.celerylib.utils import get_task_id
36 from rhodecode.lib.utils2 import str2bool, time_to_datetime
36 from rhodecode.lib.utils2 import str2bool, time_to_datetime
37 from rhodecode.lib.ext_json import json
37 from rhodecode.lib.ext_json import json
38 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
38 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
39 from rhodecode.model.changeset_status import ChangesetStatusModel
39 from rhodecode.model.changeset_status import ChangesetStatusModel
40 from rhodecode.model.comment import CommentsModel
40 from rhodecode.model.comment import CommentsModel
41 from rhodecode.model.db import (
41 from rhodecode.model.db import (
42 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
42 Session, ChangesetStatus, RepositoryField, Repository, RepoGroup,
43 ChangesetComment)
43 ChangesetComment)
44 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo import RepoModel
45 from rhodecode.model.scm import ScmModel, RepoList
45 from rhodecode.model.scm import ScmModel, RepoList
46 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
46 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
47 from rhodecode.model import validation_schema
47 from rhodecode.model import validation_schema
48 from rhodecode.model.validation_schema.schemas import repo_schema
48 from rhodecode.model.validation_schema.schemas import repo_schema
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 @jsonrpc_method()
53 @jsonrpc_method()
54 def get_repo(request, apiuser, repoid, cache=Optional(True)):
54 def get_repo(request, apiuser, repoid, cache=Optional(True)):
55 """
55 """
56 Gets an existing repository by its name or repository_id.
56 Gets an existing repository by its name or repository_id.
57
57
58 The members section so the output returns users groups or users
58 The members section so the output returns users groups or users
59 associated with that repository.
59 associated with that repository.
60
60
61 This command can only be run using an |authtoken| with admin rights,
61 This command can only be run using an |authtoken| with admin rights,
62 or users with at least read rights to the |repo|.
62 or users with at least read rights to the |repo|.
63
63
64 :param apiuser: This is filled automatically from the |authtoken|.
64 :param apiuser: This is filled automatically from the |authtoken|.
65 :type apiuser: AuthUser
65 :type apiuser: AuthUser
66 :param repoid: The repository name or repository id.
66 :param repoid: The repository name or repository id.
67 :type repoid: str or int
67 :type repoid: str or int
68 :param cache: use the cached value for last changeset
68 :param cache: use the cached value for last changeset
69 :type: cache: Optional(bool)
69 :type: cache: Optional(bool)
70
70
71 Example output:
71 Example output:
72
72
73 .. code-block:: bash
73 .. code-block:: bash
74
74
75 {
75 {
76 "error": null,
76 "error": null,
77 "id": <repo_id>,
77 "id": <repo_id>,
78 "result": {
78 "result": {
79 "clone_uri": null,
79 "clone_uri": null,
80 "created_on": "timestamp",
80 "created_on": "timestamp",
81 "description": "repo description",
81 "description": "repo description",
82 "enable_downloads": false,
82 "enable_downloads": false,
83 "enable_locking": false,
83 "enable_locking": false,
84 "enable_statistics": false,
84 "enable_statistics": false,
85 "followers": [
85 "followers": [
86 {
86 {
87 "active": true,
87 "active": true,
88 "admin": false,
88 "admin": false,
89 "api_key": "****************************************",
89 "api_key": "****************************************",
90 "api_keys": [
90 "api_keys": [
91 "****************************************"
91 "****************************************"
92 ],
92 ],
93 "email": "user@example.com",
93 "email": "user@example.com",
94 "emails": [
94 "emails": [
95 "user@example.com"
95 "user@example.com"
96 ],
96 ],
97 "extern_name": "rhodecode",
97 "extern_name": "rhodecode",
98 "extern_type": "rhodecode",
98 "extern_type": "rhodecode",
99 "firstname": "username",
99 "firstname": "username",
100 "ip_addresses": [],
100 "ip_addresses": [],
101 "language": null,
101 "language": null,
102 "last_login": "2015-09-16T17:16:35.854",
102 "last_login": "2015-09-16T17:16:35.854",
103 "lastname": "surname",
103 "lastname": "surname",
104 "user_id": <user_id>,
104 "user_id": <user_id>,
105 "username": "name"
105 "username": "name"
106 }
106 }
107 ],
107 ],
108 "fork_of": "parent-repo",
108 "fork_of": "parent-repo",
109 "landing_rev": [
109 "landing_rev": [
110 "rev",
110 "rev",
111 "tip"
111 "tip"
112 ],
112 ],
113 "last_changeset": {
113 "last_changeset": {
114 "author": "User <user@example.com>",
114 "author": "User <user@example.com>",
115 "branch": "default",
115 "branch": "default",
116 "date": "timestamp",
116 "date": "timestamp",
117 "message": "last commit message",
117 "message": "last commit message",
118 "parents": [
118 "parents": [
119 {
119 {
120 "raw_id": "commit-id"
120 "raw_id": "commit-id"
121 }
121 }
122 ],
122 ],
123 "raw_id": "commit-id",
123 "raw_id": "commit-id",
124 "revision": <revision number>,
124 "revision": <revision number>,
125 "short_id": "short id"
125 "short_id": "short id"
126 },
126 },
127 "lock_reason": null,
127 "lock_reason": null,
128 "locked_by": null,
128 "locked_by": null,
129 "locked_date": null,
129 "locked_date": null,
130 "owner": "owner-name",
130 "owner": "owner-name",
131 "permissions": [
131 "permissions": [
132 {
132 {
133 "name": "super-admin-name",
133 "name": "super-admin-name",
134 "origin": "super-admin",
134 "origin": "super-admin",
135 "permission": "repository.admin",
135 "permission": "repository.admin",
136 "type": "user"
136 "type": "user"
137 },
137 },
138 {
138 {
139 "name": "owner-name",
139 "name": "owner-name",
140 "origin": "owner",
140 "origin": "owner",
141 "permission": "repository.admin",
141 "permission": "repository.admin",
142 "type": "user"
142 "type": "user"
143 },
143 },
144 {
144 {
145 "name": "user-group-name",
145 "name": "user-group-name",
146 "origin": "permission",
146 "origin": "permission",
147 "permission": "repository.write",
147 "permission": "repository.write",
148 "type": "user_group"
148 "type": "user_group"
149 }
149 }
150 ],
150 ],
151 "private": true,
151 "private": true,
152 "repo_id": 676,
152 "repo_id": 676,
153 "repo_name": "user-group/repo-name",
153 "repo_name": "user-group/repo-name",
154 "repo_type": "hg"
154 "repo_type": "hg"
155 }
155 }
156 }
156 }
157 """
157 """
158
158
159 repo = get_repo_or_error(repoid)
159 repo = get_repo_or_error(repoid)
160 cache = Optional.extract(cache)
160 cache = Optional.extract(cache)
161
161
162 include_secrets = False
162 include_secrets = False
163 if has_superadmin_permission(apiuser):
163 if has_superadmin_permission(apiuser):
164 include_secrets = True
164 include_secrets = True
165 else:
165 else:
166 # check if we have at least read permission for this repo !
166 # check if we have at least read permission for this repo !
167 _perms = (
167 _perms = (
168 'repository.admin', 'repository.write', 'repository.read',)
168 'repository.admin', 'repository.write', 'repository.read',)
169 validate_repo_permissions(apiuser, repoid, repo, _perms)
169 validate_repo_permissions(apiuser, repoid, repo, _perms)
170
170
171 permissions = []
171 permissions = []
172 for _user in repo.permissions():
172 for _user in repo.permissions():
173 user_data = {
173 user_data = {
174 'name': _user.username,
174 'name': _user.username,
175 'permission': _user.permission,
175 'permission': _user.permission,
176 'origin': get_origin(_user),
176 'origin': get_origin(_user),
177 'type': "user",
177 'type': "user",
178 }
178 }
179 permissions.append(user_data)
179 permissions.append(user_data)
180
180
181 for _user_group in repo.permission_user_groups():
181 for _user_group in repo.permission_user_groups():
182 user_group_data = {
182 user_group_data = {
183 'name': _user_group.users_group_name,
183 'name': _user_group.users_group_name,
184 'permission': _user_group.permission,
184 'permission': _user_group.permission,
185 'origin': get_origin(_user_group),
185 'origin': get_origin(_user_group),
186 'type': "user_group",
186 'type': "user_group",
187 }
187 }
188 permissions.append(user_group_data)
188 permissions.append(user_group_data)
189
189
190 following_users = [
190 following_users = [
191 user.user.get_api_data(include_secrets=include_secrets)
191 user.user.get_api_data(include_secrets=include_secrets)
192 for user in repo.followers]
192 for user in repo.followers]
193
193
194 if not cache:
194 if not cache:
195 repo.update_commit_cache()
195 repo.update_commit_cache()
196 data = repo.get_api_data(include_secrets=include_secrets)
196 data = repo.get_api_data(include_secrets=include_secrets)
197 data['permissions'] = permissions
197 data['permissions'] = permissions
198 data['followers'] = following_users
198 data['followers'] = following_users
199 return data
199 return data
200
200
201
201
202 @jsonrpc_method()
202 @jsonrpc_method()
203 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
203 def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
204 """
204 """
205 Lists all existing repositories.
205 Lists all existing repositories.
206
206
207 This command can only be run using an |authtoken| with admin rights,
207 This command can only be run using an |authtoken| with admin rights,
208 or users with at least read rights to |repos|.
208 or users with at least read rights to |repos|.
209
209
210 :param apiuser: This is filled automatically from the |authtoken|.
210 :param apiuser: This is filled automatically from the |authtoken|.
211 :type apiuser: AuthUser
211 :type apiuser: AuthUser
212 :param root: specify root repository group to fetch repositories.
212 :param root: specify root repository group to fetch repositories.
213 filters the returned repositories to be members of given root group.
213 filters the returned repositories to be members of given root group.
214 :type root: Optional(None)
214 :type root: Optional(None)
215 :param traverse: traverse given root into subrepositories. With this flag
215 :param traverse: traverse given root into subrepositories. With this flag
216 set to False, it will only return top-level repositories from `root`.
216 set to False, it will only return top-level repositories from `root`.
217 if root is empty it will return just top-level repositories.
217 if root is empty it will return just top-level repositories.
218 :type traverse: Optional(True)
218 :type traverse: Optional(True)
219
219
220
220
221 Example output:
221 Example output:
222
222
223 .. code-block:: bash
223 .. code-block:: bash
224
224
225 id : <id_given_in_input>
225 id : <id_given_in_input>
226 result: [
226 result: [
227 {
227 {
228 "repo_id" : "<repo_id>",
228 "repo_id" : "<repo_id>",
229 "repo_name" : "<reponame>"
229 "repo_name" : "<reponame>"
230 "repo_type" : "<repo_type>",
230 "repo_type" : "<repo_type>",
231 "clone_uri" : "<clone_uri>",
231 "clone_uri" : "<clone_uri>",
232 "private": : "<bool>",
232 "private": : "<bool>",
233 "created_on" : "<datetimecreated>",
233 "created_on" : "<datetimecreated>",
234 "description" : "<description>",
234 "description" : "<description>",
235 "landing_rev": "<landing_rev>",
235 "landing_rev": "<landing_rev>",
236 "owner": "<repo_owner>",
236 "owner": "<repo_owner>",
237 "fork_of": "<name_of_fork_parent>",
237 "fork_of": "<name_of_fork_parent>",
238 "enable_downloads": "<bool>",
238 "enable_downloads": "<bool>",
239 "enable_locking": "<bool>",
239 "enable_locking": "<bool>",
240 "enable_statistics": "<bool>",
240 "enable_statistics": "<bool>",
241 },
241 },
242 ...
242 ...
243 ]
243 ]
244 error: null
244 error: null
245 """
245 """
246
246
247 include_secrets = has_superadmin_permission(apiuser)
247 include_secrets = has_superadmin_permission(apiuser)
248 _perms = ('repository.read', 'repository.write', 'repository.admin',)
248 _perms = ('repository.read', 'repository.write', 'repository.admin',)
249 extras = {'user': apiuser}
249 extras = {'user': apiuser}
250
250
251 root = Optional.extract(root)
251 root = Optional.extract(root)
252 traverse = Optional.extract(traverse, binary=True)
252 traverse = Optional.extract(traverse, binary=True)
253
253
254 if root:
254 if root:
255 # verify parent existance, if it's empty return an error
255 # verify parent existance, if it's empty return an error
256 parent = RepoGroup.get_by_group_name(root)
256 parent = RepoGroup.get_by_group_name(root)
257 if not parent:
257 if not parent:
258 raise JSONRPCError(
258 raise JSONRPCError(
259 'Root repository group `{}` does not exist'.format(root))
259 'Root repository group `{}` does not exist'.format(root))
260
260
261 if traverse:
261 if traverse:
262 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
262 repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
263 else:
263 else:
264 repos = RepoModel().get_repos_for_root(root=parent)
264 repos = RepoModel().get_repos_for_root(root=parent)
265 else:
265 else:
266 if traverse:
266 if traverse:
267 repos = RepoModel().get_all()
267 repos = RepoModel().get_all()
268 else:
268 else:
269 # return just top-level
269 # return just top-level
270 repos = RepoModel().get_repos_for_root(root=None)
270 repos = RepoModel().get_repos_for_root(root=None)
271
271
272 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
272 repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
273 return [repo.get_api_data(include_secrets=include_secrets)
273 return [repo.get_api_data(include_secrets=include_secrets)
274 for repo in repo_list]
274 for repo in repo_list]
275
275
276
276
277 @jsonrpc_method()
277 @jsonrpc_method()
278 def get_repo_changeset(request, apiuser, repoid, revision,
278 def get_repo_changeset(request, apiuser, repoid, revision,
279 details=Optional('basic')):
279 details=Optional('basic')):
280 """
280 """
281 Returns information about a changeset.
281 Returns information about a changeset.
282
282
283 Additionally parameters define the amount of details returned by
283 Additionally parameters define the amount of details returned by
284 this function.
284 this function.
285
285
286 This command can only be run using an |authtoken| with admin rights,
286 This command can only be run using an |authtoken| with admin rights,
287 or users with at least read rights to the |repo|.
287 or users with at least read rights to the |repo|.
288
288
289 :param apiuser: This is filled automatically from the |authtoken|.
289 :param apiuser: This is filled automatically from the |authtoken|.
290 :type apiuser: AuthUser
290 :type apiuser: AuthUser
291 :param repoid: The repository name or repository id
291 :param repoid: The repository name or repository id
292 :type repoid: str or int
292 :type repoid: str or int
293 :param revision: revision for which listing should be done
293 :param revision: revision for which listing should be done
294 :type revision: str
294 :type revision: str
295 :param details: details can be 'basic|extended|full' full gives diff
295 :param details: details can be 'basic|extended|full' full gives diff
296 info details like the diff itself, and number of changed files etc.
296 info details like the diff itself, and number of changed files etc.
297 :type details: Optional(str)
297 :type details: Optional(str)
298
298
299 """
299 """
300 repo = get_repo_or_error(repoid)
300 repo = get_repo_or_error(repoid)
301 if not has_superadmin_permission(apiuser):
301 if not has_superadmin_permission(apiuser):
302 _perms = (
302 _perms = (
303 'repository.admin', 'repository.write', 'repository.read',)
303 'repository.admin', 'repository.write', 'repository.read',)
304 validate_repo_permissions(apiuser, repoid, repo, _perms)
304 validate_repo_permissions(apiuser, repoid, repo, _perms)
305
305
306 changes_details = Optional.extract(details)
306 changes_details = Optional.extract(details)
307 _changes_details_types = ['basic', 'extended', 'full']
307 _changes_details_types = ['basic', 'extended', 'full']
308 if changes_details not in _changes_details_types:
308 if changes_details not in _changes_details_types:
309 raise JSONRPCError(
309 raise JSONRPCError(
310 'ret_type must be one of %s' % (
310 'ret_type must be one of %s' % (
311 ','.join(_changes_details_types)))
311 ','.join(_changes_details_types)))
312
312
313 pre_load = ['author', 'branch', 'date', 'message', 'parents',
313 pre_load = ['author', 'branch', 'date', 'message', 'parents',
314 'status', '_commit', '_file_paths']
314 'status', '_commit', '_file_paths']
315
315
316 try:
316 try:
317 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
317 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
318 except TypeError as e:
318 except TypeError as e:
319 raise JSONRPCError(e.message)
319 raise JSONRPCError(e.message)
320 _cs_json = cs.__json__()
320 _cs_json = cs.__json__()
321 _cs_json['diff'] = build_commit_data(cs, changes_details)
321 _cs_json['diff'] = build_commit_data(cs, changes_details)
322 if changes_details == 'full':
322 if changes_details == 'full':
323 _cs_json['refs'] = cs._get_refs()
323 _cs_json['refs'] = cs._get_refs()
324 return _cs_json
324 return _cs_json
325
325
326
326
327 @jsonrpc_method()
327 @jsonrpc_method()
328 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
328 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
329 details=Optional('basic')):
329 details=Optional('basic')):
330 """
330 """
331 Returns a set of commits limited by the number starting
331 Returns a set of commits limited by the number starting
332 from the `start_rev` option.
332 from the `start_rev` option.
333
333
334 Additional parameters define the amount of details returned by this
334 Additional parameters define the amount of details returned by this
335 function.
335 function.
336
336
337 This command can only be run using an |authtoken| with admin rights,
337 This command can only be run using an |authtoken| with admin rights,
338 or users with at least read rights to |repos|.
338 or users with at least read rights to |repos|.
339
339
340 :param apiuser: This is filled automatically from the |authtoken|.
340 :param apiuser: This is filled automatically from the |authtoken|.
341 :type apiuser: AuthUser
341 :type apiuser: AuthUser
342 :param repoid: The repository name or repository ID.
342 :param repoid: The repository name or repository ID.
343 :type repoid: str or int
343 :type repoid: str or int
344 :param start_rev: The starting revision from where to get changesets.
344 :param start_rev: The starting revision from where to get changesets.
345 :type start_rev: str
345 :type start_rev: str
346 :param limit: Limit the number of commits to this amount
346 :param limit: Limit the number of commits to this amount
347 :type limit: str or int
347 :type limit: str or int
348 :param details: Set the level of detail returned. Valid option are:
348 :param details: Set the level of detail returned. Valid option are:
349 ``basic``, ``extended`` and ``full``.
349 ``basic``, ``extended`` and ``full``.
350 :type details: Optional(str)
350 :type details: Optional(str)
351
351
352 .. note::
352 .. note::
353
353
354 Setting the parameter `details` to the value ``full`` is extensive
354 Setting the parameter `details` to the value ``full`` is extensive
355 and returns details like the diff itself, and the number
355 and returns details like the diff itself, and the number
356 of changed files.
356 of changed files.
357
357
358 """
358 """
359 repo = get_repo_or_error(repoid)
359 repo = get_repo_or_error(repoid)
360 if not has_superadmin_permission(apiuser):
360 if not has_superadmin_permission(apiuser):
361 _perms = (
361 _perms = (
362 'repository.admin', 'repository.write', 'repository.read',)
362 'repository.admin', 'repository.write', 'repository.read',)
363 validate_repo_permissions(apiuser, repoid, repo, _perms)
363 validate_repo_permissions(apiuser, repoid, repo, _perms)
364
364
365 changes_details = Optional.extract(details)
365 changes_details = Optional.extract(details)
366 _changes_details_types = ['basic', 'extended', 'full']
366 _changes_details_types = ['basic', 'extended', 'full']
367 if changes_details not in _changes_details_types:
367 if changes_details not in _changes_details_types:
368 raise JSONRPCError(
368 raise JSONRPCError(
369 'ret_type must be one of %s' % (
369 'ret_type must be one of %s' % (
370 ','.join(_changes_details_types)))
370 ','.join(_changes_details_types)))
371
371
372 limit = int(limit)
372 limit = int(limit)
373 pre_load = ['author', 'branch', 'date', 'message', 'parents',
373 pre_load = ['author', 'branch', 'date', 'message', 'parents',
374 'status', '_commit', '_file_paths']
374 'status', '_commit', '_file_paths']
375
375
376 vcs_repo = repo.scm_instance()
376 vcs_repo = repo.scm_instance()
377 # SVN needs a special case to distinguish its index and commit id
377 # SVN needs a special case to distinguish its index and commit id
378 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
378 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
379 start_rev = vcs_repo.commit_ids[0]
379 start_rev = vcs_repo.commit_ids[0]
380
380
381 try:
381 try:
382 commits = vcs_repo.get_commits(
382 commits = vcs_repo.get_commits(
383 start_id=start_rev, pre_load=pre_load)
383 start_id=start_rev, pre_load=pre_load)
384 except TypeError as e:
384 except TypeError as e:
385 raise JSONRPCError(e.message)
385 raise JSONRPCError(e.message)
386 except Exception:
386 except Exception:
387 log.exception('Fetching of commits failed')
387 log.exception('Fetching of commits failed')
388 raise JSONRPCError('Error occurred during commit fetching')
388 raise JSONRPCError('Error occurred during commit fetching')
389
389
390 ret = []
390 ret = []
391 for cnt, commit in enumerate(commits):
391 for cnt, commit in enumerate(commits):
392 if cnt >= limit != -1:
392 if cnt >= limit != -1:
393 break
393 break
394 _cs_json = commit.__json__()
394 _cs_json = commit.__json__()
395 _cs_json['diff'] = build_commit_data(commit, changes_details)
395 _cs_json['diff'] = build_commit_data(commit, changes_details)
396 if changes_details == 'full':
396 if changes_details == 'full':
397 _cs_json['refs'] = {
397 _cs_json['refs'] = {
398 'branches': [commit.branch],
398 'branches': [commit.branch],
399 'bookmarks': getattr(commit, 'bookmarks', []),
399 'bookmarks': getattr(commit, 'bookmarks', []),
400 'tags': commit.tags
400 'tags': commit.tags
401 }
401 }
402 ret.append(_cs_json)
402 ret.append(_cs_json)
403 return ret
403 return ret
404
404
405
405
406 @jsonrpc_method()
406 @jsonrpc_method()
407 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
407 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
408 ret_type=Optional('all'), details=Optional('basic'),
408 ret_type=Optional('all'), details=Optional('basic'),
409 max_file_bytes=Optional(None)):
409 max_file_bytes=Optional(None)):
410 """
410 """
411 Returns a list of nodes and children in a flat list for a given
411 Returns a list of nodes and children in a flat list for a given
412 path at given revision.
412 path at given revision.
413
413
414 It's possible to specify ret_type to show only `files` or `dirs`.
414 It's possible to specify ret_type to show only `files` or `dirs`.
415
415
416 This command can only be run using an |authtoken| with admin rights,
416 This command can only be run using an |authtoken| with admin rights,
417 or users with at least read rights to |repos|.
417 or users with at least read rights to |repos|.
418
418
419 :param apiuser: This is filled automatically from the |authtoken|.
419 :param apiuser: This is filled automatically from the |authtoken|.
420 :type apiuser: AuthUser
420 :type apiuser: AuthUser
421 :param repoid: The repository name or repository ID.
421 :param repoid: The repository name or repository ID.
422 :type repoid: str or int
422 :type repoid: str or int
423 :param revision: The revision for which listing should be done.
423 :param revision: The revision for which listing should be done.
424 :type revision: str
424 :type revision: str
425 :param root_path: The path from which to start displaying.
425 :param root_path: The path from which to start displaying.
426 :type root_path: str
426 :type root_path: str
427 :param ret_type: Set the return type. Valid options are
427 :param ret_type: Set the return type. Valid options are
428 ``all`` (default), ``files`` and ``dirs``.
428 ``all`` (default), ``files`` and ``dirs``.
429 :type ret_type: Optional(str)
429 :type ret_type: Optional(str)
430 :param details: Returns extended information about nodes, such as
430 :param details: Returns extended information about nodes, such as
431 md5, binary, and or content. The valid options are ``basic`` and
431 md5, binary, and or content. The valid options are ``basic`` and
432 ``full``.
432 ``full``.
433 :type details: Optional(str)
433 :type details: Optional(str)
434 :param max_file_bytes: Only return file content under this file size bytes
434 :param max_file_bytes: Only return file content under this file size bytes
435 :type details: Optional(int)
435 :type details: Optional(int)
436
436
437 Example output:
437 Example output:
438
438
439 .. code-block:: bash
439 .. code-block:: bash
440
440
441 id : <id_given_in_input>
441 id : <id_given_in_input>
442 result: [
442 result: [
443 {
443 {
444 "name" : "<name>"
444 "name" : "<name>"
445 "type" : "<type>",
445 "type" : "<type>",
446 "binary": "<true|false>" (only in extended mode)
446 "binary": "<true|false>" (only in extended mode)
447 "md5" : "<md5 of file content>" (only in extended mode)
447 "md5" : "<md5 of file content>" (only in extended mode)
448 },
448 },
449 ...
449 ...
450 ]
450 ]
451 error: null
451 error: null
452 """
452 """
453
453
454 repo = get_repo_or_error(repoid)
454 repo = get_repo_or_error(repoid)
455 if not has_superadmin_permission(apiuser):
455 if not has_superadmin_permission(apiuser):
456 _perms = (
456 _perms = (
457 'repository.admin', 'repository.write', 'repository.read',)
457 'repository.admin', 'repository.write', 'repository.read',)
458 validate_repo_permissions(apiuser, repoid, repo, _perms)
458 validate_repo_permissions(apiuser, repoid, repo, _perms)
459
459
460 ret_type = Optional.extract(ret_type)
460 ret_type = Optional.extract(ret_type)
461 details = Optional.extract(details)
461 details = Optional.extract(details)
462 _extended_types = ['basic', 'full']
462 _extended_types = ['basic', 'full']
463 if details not in _extended_types:
463 if details not in _extended_types:
464 raise JSONRPCError(
464 raise JSONRPCError(
465 'ret_type must be one of %s' % (','.join(_extended_types)))
465 'ret_type must be one of %s' % (','.join(_extended_types)))
466 extended_info = False
466 extended_info = False
467 content = False
467 content = False
468 if details == 'basic':
468 if details == 'basic':
469 extended_info = True
469 extended_info = True
470
470
471 if details == 'full':
471 if details == 'full':
472 extended_info = content = True
472 extended_info = content = True
473
473
474 _map = {}
474 _map = {}
475 try:
475 try:
476 # check if repo is not empty by any chance, skip quicker if it is.
476 # check if repo is not empty by any chance, skip quicker if it is.
477 _scm = repo.scm_instance()
477 _scm = repo.scm_instance()
478 if _scm.is_empty():
478 if _scm.is_empty():
479 return []
479 return []
480
480
481 _d, _f = ScmModel().get_nodes(
481 _d, _f = ScmModel().get_nodes(
482 repo, revision, root_path, flat=False,
482 repo, revision, root_path, flat=False,
483 extended_info=extended_info, content=content,
483 extended_info=extended_info, content=content,
484 max_file_bytes=max_file_bytes)
484 max_file_bytes=max_file_bytes)
485 _map = {
485 _map = {
486 'all': _d + _f,
486 'all': _d + _f,
487 'files': _f,
487 'files': _f,
488 'dirs': _d,
488 'dirs': _d,
489 }
489 }
490 return _map[ret_type]
490 return _map[ret_type]
491 except KeyError:
491 except KeyError:
492 raise JSONRPCError(
492 raise JSONRPCError(
493 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
493 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
494 except Exception:
494 except Exception:
495 log.exception("Exception occurred while trying to get repo nodes")
495 log.exception("Exception occurred while trying to get repo nodes")
496 raise JSONRPCError(
496 raise JSONRPCError(
497 'failed to get repo: `%s` nodes' % repo.repo_name
497 'failed to get repo: `%s` nodes' % repo.repo_name
498 )
498 )
499
499
500
500
501 @jsonrpc_method()
501 @jsonrpc_method()
502 def get_repo_refs(request, apiuser, repoid):
502 def get_repo_refs(request, apiuser, repoid):
503 """
503 """
504 Returns a dictionary of current references. It returns
504 Returns a dictionary of current references. It returns
505 bookmarks, branches, closed_branches, and tags for given repository
505 bookmarks, branches, closed_branches, and tags for given repository
506
506
507 It's possible to specify ret_type to show only `files` or `dirs`.
507 It's possible to specify ret_type to show only `files` or `dirs`.
508
508
509 This command can only be run using an |authtoken| with admin rights,
509 This command can only be run using an |authtoken| with admin rights,
510 or users with at least read rights to |repos|.
510 or users with at least read rights to |repos|.
511
511
512 :param apiuser: This is filled automatically from the |authtoken|.
512 :param apiuser: This is filled automatically from the |authtoken|.
513 :type apiuser: AuthUser
513 :type apiuser: AuthUser
514 :param repoid: The repository name or repository ID.
514 :param repoid: The repository name or repository ID.
515 :type repoid: str or int
515 :type repoid: str or int
516
516
517 Example output:
517 Example output:
518
518
519 .. code-block:: bash
519 .. code-block:: bash
520
520
521 id : <id_given_in_input>
521 id : <id_given_in_input>
522 "result": {
522 "result": {
523 "bookmarks": {
523 "bookmarks": {
524 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
524 "dev": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
525 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
525 "master": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
526 },
526 },
527 "branches": {
527 "branches": {
528 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
528 "default": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
529 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
529 "stable": "367f590445081d8ec8c2ea0456e73ae1f1c3d6cf"
530 },
530 },
531 "branches_closed": {},
531 "branches_closed": {},
532 "tags": {
532 "tags": {
533 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
533 "tip": "5611d30200f4040ba2ab4f3d64e5b06408a02188",
534 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
534 "v4.4.0": "1232313f9e6adac5ce5399c2a891dc1e72b79022",
535 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
535 "v4.4.1": "cbb9f1d329ae5768379cdec55a62ebdd546c4e27",
536 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
536 "v4.4.2": "24ffe44a27fcd1c5b6936144e176b9f6dd2f3a17",
537 }
537 }
538 }
538 }
539 error: null
539 error: null
540 """
540 """
541
541
542 repo = get_repo_or_error(repoid)
542 repo = get_repo_or_error(repoid)
543 if not has_superadmin_permission(apiuser):
543 if not has_superadmin_permission(apiuser):
544 _perms = ('repository.admin', 'repository.write', 'repository.read',)
544 _perms = ('repository.admin', 'repository.write', 'repository.read',)
545 validate_repo_permissions(apiuser, repoid, repo, _perms)
545 validate_repo_permissions(apiuser, repoid, repo, _perms)
546
546
547 try:
547 try:
548 # check if repo is not empty by any chance, skip quicker if it is.
548 # check if repo is not empty by any chance, skip quicker if it is.
549 vcs_instance = repo.scm_instance()
549 vcs_instance = repo.scm_instance()
550 refs = vcs_instance.refs()
550 refs = vcs_instance.refs()
551 return refs
551 return refs
552 except Exception:
552 except Exception:
553 log.exception("Exception occurred while trying to get repo refs")
553 log.exception("Exception occurred while trying to get repo refs")
554 raise JSONRPCError(
554 raise JSONRPCError(
555 'failed to get repo: `%s` references' % repo.repo_name
555 'failed to get repo: `%s` references' % repo.repo_name
556 )
556 )
557
557
558
558
559 @jsonrpc_method()
559 @jsonrpc_method()
560 def create_repo(
560 def create_repo(
561 request, apiuser, repo_name, repo_type,
561 request, apiuser, repo_name, repo_type,
562 owner=Optional(OAttr('apiuser')),
562 owner=Optional(OAttr('apiuser')),
563 description=Optional(''),
563 description=Optional(''),
564 private=Optional(False),
564 private=Optional(False),
565 clone_uri=Optional(None),
565 clone_uri=Optional(None),
566 push_uri=Optional(None),
566 landing_rev=Optional('rev:tip'),
567 landing_rev=Optional('rev:tip'),
567 enable_statistics=Optional(False),
568 enable_statistics=Optional(False),
568 enable_locking=Optional(False),
569 enable_locking=Optional(False),
569 enable_downloads=Optional(False),
570 enable_downloads=Optional(False),
570 copy_permissions=Optional(False)):
571 copy_permissions=Optional(False)):
571 """
572 """
572 Creates a repository.
573 Creates a repository.
573
574
574 * If the repository name contains "/", repository will be created inside
575 * If the repository name contains "/", repository will be created inside
575 a repository group or nested repository groups
576 a repository group or nested repository groups
576
577
577 For example "foo/bar/repo1" will create |repo| called "repo1" inside
578 For example "foo/bar/repo1" will create |repo| called "repo1" inside
578 group "foo/bar". You have to have permissions to access and write to
579 group "foo/bar". You have to have permissions to access and write to
579 the last repository group ("bar" in this example)
580 the last repository group ("bar" in this example)
580
581
581 This command can only be run using an |authtoken| with at least
582 This command can only be run using an |authtoken| with at least
582 permissions to create repositories, or write permissions to
583 permissions to create repositories, or write permissions to
583 parent repository groups.
584 parent repository groups.
584
585
585 :param apiuser: This is filled automatically from the |authtoken|.
586 :param apiuser: This is filled automatically from the |authtoken|.
586 :type apiuser: AuthUser
587 :type apiuser: AuthUser
587 :param repo_name: Set the repository name.
588 :param repo_name: Set the repository name.
588 :type repo_name: str
589 :type repo_name: str
589 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
590 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
590 :type repo_type: str
591 :type repo_type: str
591 :param owner: user_id or username
592 :param owner: user_id or username
592 :type owner: Optional(str)
593 :type owner: Optional(str)
593 :param description: Set the repository description.
594 :param description: Set the repository description.
594 :type description: Optional(str)
595 :type description: Optional(str)
595 :param private: set repository as private
596 :param private: set repository as private
596 :type private: bool
597 :type private: bool
597 :param clone_uri: set clone_uri
598 :param clone_uri: set clone_uri
598 :type clone_uri: str
599 :type clone_uri: str
600 :param push_uri: set push_uri
601 :type push_uri: str
599 :param landing_rev: <rev_type>:<rev>
602 :param landing_rev: <rev_type>:<rev>
600 :type landing_rev: str
603 :type landing_rev: str
601 :param enable_locking:
604 :param enable_locking:
602 :type enable_locking: bool
605 :type enable_locking: bool
603 :param enable_downloads:
606 :param enable_downloads:
604 :type enable_downloads: bool
607 :type enable_downloads: bool
605 :param enable_statistics:
608 :param enable_statistics:
606 :type enable_statistics: bool
609 :type enable_statistics: bool
607 :param copy_permissions: Copy permission from group in which the
610 :param copy_permissions: Copy permission from group in which the
608 repository is being created.
611 repository is being created.
609 :type copy_permissions: bool
612 :type copy_permissions: bool
610
613
611
614
612 Example output:
615 Example output:
613
616
614 .. code-block:: bash
617 .. code-block:: bash
615
618
616 id : <id_given_in_input>
619 id : <id_given_in_input>
617 result: {
620 result: {
618 "msg": "Created new repository `<reponame>`",
621 "msg": "Created new repository `<reponame>`",
619 "success": true,
622 "success": true,
620 "task": "<celery task id or None if done sync>"
623 "task": "<celery task id or None if done sync>"
621 }
624 }
622 error: null
625 error: null
623
626
624
627
625 Example error output:
628 Example error output:
626
629
627 .. code-block:: bash
630 .. code-block:: bash
628
631
629 id : <id_given_in_input>
632 id : <id_given_in_input>
630 result : null
633 result : null
631 error : {
634 error : {
632 'failed to create repository `<repo_name>`'
635 'failed to create repository `<repo_name>`'
633 }
636 }
634
637
635 """
638 """
636
639
637 owner = validate_set_owner_permissions(apiuser, owner)
640 owner = validate_set_owner_permissions(apiuser, owner)
638
641
639 description = Optional.extract(description)
642 description = Optional.extract(description)
640 copy_permissions = Optional.extract(copy_permissions)
643 copy_permissions = Optional.extract(copy_permissions)
641 clone_uri = Optional.extract(clone_uri)
644 clone_uri = Optional.extract(clone_uri)
645 push_uri = Optional.extract(push_uri)
642 landing_commit_ref = Optional.extract(landing_rev)
646 landing_commit_ref = Optional.extract(landing_rev)
643
647
644 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
648 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
645 if isinstance(private, Optional):
649 if isinstance(private, Optional):
646 private = defs.get('repo_private') or Optional.extract(private)
650 private = defs.get('repo_private') or Optional.extract(private)
647 if isinstance(repo_type, Optional):
651 if isinstance(repo_type, Optional):
648 repo_type = defs.get('repo_type')
652 repo_type = defs.get('repo_type')
649 if isinstance(enable_statistics, Optional):
653 if isinstance(enable_statistics, Optional):
650 enable_statistics = defs.get('repo_enable_statistics')
654 enable_statistics = defs.get('repo_enable_statistics')
651 if isinstance(enable_locking, Optional):
655 if isinstance(enable_locking, Optional):
652 enable_locking = defs.get('repo_enable_locking')
656 enable_locking = defs.get('repo_enable_locking')
653 if isinstance(enable_downloads, Optional):
657 if isinstance(enable_downloads, Optional):
654 enable_downloads = defs.get('repo_enable_downloads')
658 enable_downloads = defs.get('repo_enable_downloads')
655
659
656 schema = repo_schema.RepoSchema().bind(
660 schema = repo_schema.RepoSchema().bind(
657 repo_type_options=rhodecode.BACKENDS.keys(),
661 repo_type_options=rhodecode.BACKENDS.keys(),
658 repo_type=repo_type,
662 repo_type=repo_type,
659 # user caller
663 # user caller
660 user=apiuser)
664 user=apiuser)
661
665
662 try:
666 try:
663 schema_data = schema.deserialize(dict(
667 schema_data = schema.deserialize(dict(
664 repo_name=repo_name,
668 repo_name=repo_name,
665 repo_type=repo_type,
669 repo_type=repo_type,
666 repo_owner=owner.username,
670 repo_owner=owner.username,
667 repo_description=description,
671 repo_description=description,
668 repo_landing_commit_ref=landing_commit_ref,
672 repo_landing_commit_ref=landing_commit_ref,
669 repo_clone_uri=clone_uri,
673 repo_clone_uri=clone_uri,
674 repo_push_uri=push_uri,
670 repo_private=private,
675 repo_private=private,
671 repo_copy_permissions=copy_permissions,
676 repo_copy_permissions=copy_permissions,
672 repo_enable_statistics=enable_statistics,
677 repo_enable_statistics=enable_statistics,
673 repo_enable_downloads=enable_downloads,
678 repo_enable_downloads=enable_downloads,
674 repo_enable_locking=enable_locking))
679 repo_enable_locking=enable_locking))
675 except validation_schema.Invalid as err:
680 except validation_schema.Invalid as err:
676 raise JSONRPCValidationError(colander_exc=err)
681 raise JSONRPCValidationError(colander_exc=err)
677
682
678 try:
683 try:
679 data = {
684 data = {
680 'owner': owner,
685 'owner': owner,
681 'repo_name': schema_data['repo_group']['repo_name_without_group'],
686 'repo_name': schema_data['repo_group']['repo_name_without_group'],
682 'repo_name_full': schema_data['repo_name'],
687 'repo_name_full': schema_data['repo_name'],
683 'repo_group': schema_data['repo_group']['repo_group_id'],
688 'repo_group': schema_data['repo_group']['repo_group_id'],
684 'repo_type': schema_data['repo_type'],
689 'repo_type': schema_data['repo_type'],
685 'repo_description': schema_data['repo_description'],
690 'repo_description': schema_data['repo_description'],
686 'repo_private': schema_data['repo_private'],
691 'repo_private': schema_data['repo_private'],
687 'clone_uri': schema_data['repo_clone_uri'],
692 'clone_uri': schema_data['repo_clone_uri'],
693 'push_uri': schema_data['repo_push_uri'],
688 'repo_landing_rev': schema_data['repo_landing_commit_ref'],
694 'repo_landing_rev': schema_data['repo_landing_commit_ref'],
689 'enable_statistics': schema_data['repo_enable_statistics'],
695 'enable_statistics': schema_data['repo_enable_statistics'],
690 'enable_locking': schema_data['repo_enable_locking'],
696 'enable_locking': schema_data['repo_enable_locking'],
691 'enable_downloads': schema_data['repo_enable_downloads'],
697 'enable_downloads': schema_data['repo_enable_downloads'],
692 'repo_copy_permissions': schema_data['repo_copy_permissions'],
698 'repo_copy_permissions': schema_data['repo_copy_permissions'],
693 }
699 }
694
700
695 task = RepoModel().create(form_data=data, cur_user=owner)
701 task = RepoModel().create(form_data=data, cur_user=owner.user_id)
696 task_id = get_task_id(task)
702 task_id = get_task_id(task)
697 # no commit, it's done in RepoModel, or async via celery
703 # no commit, it's done in RepoModel, or async via celery
698 return {
704 return {
699 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
705 'msg': "Created new repository `%s`" % (schema_data['repo_name'],),
700 'success': True, # cannot return the repo data here since fork
706 'success': True, # cannot return the repo data here since fork
701 # can be done async
707 # can be done async
702 'task': task_id
708 'task': task_id
703 }
709 }
704 except Exception:
710 except Exception:
705 log.exception(
711 log.exception(
706 u"Exception while trying to create the repository %s",
712 u"Exception while trying to create the repository %s",
707 schema_data['repo_name'])
713 schema_data['repo_name'])
708 raise JSONRPCError(
714 raise JSONRPCError(
709 'failed to create repository `%s`' % (schema_data['repo_name'],))
715 'failed to create repository `%s`' % (schema_data['repo_name'],))
710
716
711
717
712 @jsonrpc_method()
718 @jsonrpc_method()
713 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
719 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
714 description=Optional('')):
720 description=Optional('')):
715 """
721 """
716 Adds an extra field to a repository.
722 Adds an extra field to a repository.
717
723
718 This command can only be run using an |authtoken| with at least
724 This command can only be run using an |authtoken| with at least
719 write permissions to the |repo|.
725 write permissions to the |repo|.
720
726
721 :param apiuser: This is filled automatically from the |authtoken|.
727 :param apiuser: This is filled automatically from the |authtoken|.
722 :type apiuser: AuthUser
728 :type apiuser: AuthUser
723 :param repoid: Set the repository name or repository id.
729 :param repoid: Set the repository name or repository id.
724 :type repoid: str or int
730 :type repoid: str or int
725 :param key: Create a unique field key for this repository.
731 :param key: Create a unique field key for this repository.
726 :type key: str
732 :type key: str
727 :param label:
733 :param label:
728 :type label: Optional(str)
734 :type label: Optional(str)
729 :param description:
735 :param description:
730 :type description: Optional(str)
736 :type description: Optional(str)
731 """
737 """
732 repo = get_repo_or_error(repoid)
738 repo = get_repo_or_error(repoid)
733 if not has_superadmin_permission(apiuser):
739 if not has_superadmin_permission(apiuser):
734 _perms = ('repository.admin',)
740 _perms = ('repository.admin',)
735 validate_repo_permissions(apiuser, repoid, repo, _perms)
741 validate_repo_permissions(apiuser, repoid, repo, _perms)
736
742
737 label = Optional.extract(label) or key
743 label = Optional.extract(label) or key
738 description = Optional.extract(description)
744 description = Optional.extract(description)
739
745
740 field = RepositoryField.get_by_key_name(key, repo)
746 field = RepositoryField.get_by_key_name(key, repo)
741 if field:
747 if field:
742 raise JSONRPCError('Field with key '
748 raise JSONRPCError('Field with key '
743 '`%s` exists for repo `%s`' % (key, repoid))
749 '`%s` exists for repo `%s`' % (key, repoid))
744
750
745 try:
751 try:
746 RepoModel().add_repo_field(repo, key, field_label=label,
752 RepoModel().add_repo_field(repo, key, field_label=label,
747 field_desc=description)
753 field_desc=description)
748 Session().commit()
754 Session().commit()
749 return {
755 return {
750 'msg': "Added new repository field `%s`" % (key,),
756 'msg': "Added new repository field `%s`" % (key,),
751 'success': True,
757 'success': True,
752 }
758 }
753 except Exception:
759 except Exception:
754 log.exception("Exception occurred while trying to add field to repo")
760 log.exception("Exception occurred while trying to add field to repo")
755 raise JSONRPCError(
761 raise JSONRPCError(
756 'failed to create new field for repository `%s`' % (repoid,))
762 'failed to create new field for repository `%s`' % (repoid,))
757
763
758
764
759 @jsonrpc_method()
765 @jsonrpc_method()
760 def remove_field_from_repo(request, apiuser, repoid, key):
766 def remove_field_from_repo(request, apiuser, repoid, key):
761 """
767 """
762 Removes an extra field from a repository.
768 Removes an extra field from a repository.
763
769
764 This command can only be run using an |authtoken| with at least
770 This command can only be run using an |authtoken| with at least
765 write permissions to the |repo|.
771 write permissions to the |repo|.
766
772
767 :param apiuser: This is filled automatically from the |authtoken|.
773 :param apiuser: This is filled automatically from the |authtoken|.
768 :type apiuser: AuthUser
774 :type apiuser: AuthUser
769 :param repoid: Set the repository name or repository ID.
775 :param repoid: Set the repository name or repository ID.
770 :type repoid: str or int
776 :type repoid: str or int
771 :param key: Set the unique field key for this repository.
777 :param key: Set the unique field key for this repository.
772 :type key: str
778 :type key: str
773 """
779 """
774
780
775 repo = get_repo_or_error(repoid)
781 repo = get_repo_or_error(repoid)
776 if not has_superadmin_permission(apiuser):
782 if not has_superadmin_permission(apiuser):
777 _perms = ('repository.admin',)
783 _perms = ('repository.admin',)
778 validate_repo_permissions(apiuser, repoid, repo, _perms)
784 validate_repo_permissions(apiuser, repoid, repo, _perms)
779
785
780 field = RepositoryField.get_by_key_name(key, repo)
786 field = RepositoryField.get_by_key_name(key, repo)
781 if not field:
787 if not field:
782 raise JSONRPCError('Field with key `%s` does not '
788 raise JSONRPCError('Field with key `%s` does not '
783 'exists for repo `%s`' % (key, repoid))
789 'exists for repo `%s`' % (key, repoid))
784
790
785 try:
791 try:
786 RepoModel().delete_repo_field(repo, field_key=key)
792 RepoModel().delete_repo_field(repo, field_key=key)
787 Session().commit()
793 Session().commit()
788 return {
794 return {
789 'msg': "Deleted repository field `%s`" % (key,),
795 'msg': "Deleted repository field `%s`" % (key,),
790 'success': True,
796 'success': True,
791 }
797 }
792 except Exception:
798 except Exception:
793 log.exception(
799 log.exception(
794 "Exception occurred while trying to delete field from repo")
800 "Exception occurred while trying to delete field from repo")
795 raise JSONRPCError(
801 raise JSONRPCError(
796 'failed to delete field for repository `%s`' % (repoid,))
802 'failed to delete field for repository `%s`' % (repoid,))
797
803
798
804
799 @jsonrpc_method()
805 @jsonrpc_method()
800 def update_repo(
806 def update_repo(
801 request, apiuser, repoid, repo_name=Optional(None),
807 request, apiuser, repoid, repo_name=Optional(None),
802 owner=Optional(OAttr('apiuser')), description=Optional(''),
808 owner=Optional(OAttr('apiuser')), description=Optional(''),
803 private=Optional(False), clone_uri=Optional(None),
809 private=Optional(False),
810 clone_uri=Optional(None), push_uri=Optional(None),
804 landing_rev=Optional('rev:tip'), fork_of=Optional(None),
811 landing_rev=Optional('rev:tip'), fork_of=Optional(None),
805 enable_statistics=Optional(False),
812 enable_statistics=Optional(False),
806 enable_locking=Optional(False),
813 enable_locking=Optional(False),
807 enable_downloads=Optional(False), fields=Optional('')):
814 enable_downloads=Optional(False), fields=Optional('')):
808 """
815 """
809 Updates a repository with the given information.
816 Updates a repository with the given information.
810
817
811 This command can only be run using an |authtoken| with at least
818 This command can only be run using an |authtoken| with at least
812 admin permissions to the |repo|.
819 admin permissions to the |repo|.
813
820
814 * If the repository name contains "/", repository will be updated
821 * If the repository name contains "/", repository will be updated
815 accordingly with a repository group or nested repository groups
822 accordingly with a repository group or nested repository groups
816
823
817 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
824 For example repoid=repo-test name="foo/bar/repo-test" will update |repo|
818 called "repo-test" and place it inside group "foo/bar".
825 called "repo-test" and place it inside group "foo/bar".
819 You have to have permissions to access and write to the last repository
826 You have to have permissions to access and write to the last repository
820 group ("bar" in this example)
827 group ("bar" in this example)
821
828
822 :param apiuser: This is filled automatically from the |authtoken|.
829 :param apiuser: This is filled automatically from the |authtoken|.
823 :type apiuser: AuthUser
830 :type apiuser: AuthUser
824 :param repoid: repository name or repository ID.
831 :param repoid: repository name or repository ID.
825 :type repoid: str or int
832 :type repoid: str or int
826 :param repo_name: Update the |repo| name, including the
833 :param repo_name: Update the |repo| name, including the
827 repository group it's in.
834 repository group it's in.
828 :type repo_name: str
835 :type repo_name: str
829 :param owner: Set the |repo| owner.
836 :param owner: Set the |repo| owner.
830 :type owner: str
837 :type owner: str
831 :param fork_of: Set the |repo| as fork of another |repo|.
838 :param fork_of: Set the |repo| as fork of another |repo|.
832 :type fork_of: str
839 :type fork_of: str
833 :param description: Update the |repo| description.
840 :param description: Update the |repo| description.
834 :type description: str
841 :type description: str
835 :param private: Set the |repo| as private. (True | False)
842 :param private: Set the |repo| as private. (True | False)
836 :type private: bool
843 :type private: bool
837 :param clone_uri: Update the |repo| clone URI.
844 :param clone_uri: Update the |repo| clone URI.
838 :type clone_uri: str
845 :type clone_uri: str
839 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
846 :param landing_rev: Set the |repo| landing revision. Default is ``rev:tip``.
840 :type landing_rev: str
847 :type landing_rev: str
841 :param enable_statistics: Enable statistics on the |repo|, (True | False).
848 :param enable_statistics: Enable statistics on the |repo|, (True | False).
842 :type enable_statistics: bool
849 :type enable_statistics: bool
843 :param enable_locking: Enable |repo| locking.
850 :param enable_locking: Enable |repo| locking.
844 :type enable_locking: bool
851 :type enable_locking: bool
845 :param enable_downloads: Enable downloads from the |repo|, (True | False).
852 :param enable_downloads: Enable downloads from the |repo|, (True | False).
846 :type enable_downloads: bool
853 :type enable_downloads: bool
847 :param fields: Add extra fields to the |repo|. Use the following
854 :param fields: Add extra fields to the |repo|. Use the following
848 example format: ``field_key=field_val,field_key2=fieldval2``.
855 example format: ``field_key=field_val,field_key2=fieldval2``.
849 Escape ', ' with \,
856 Escape ', ' with \,
850 :type fields: str
857 :type fields: str
851 """
858 """
852
859
853 repo = get_repo_or_error(repoid)
860 repo = get_repo_or_error(repoid)
854
861
855 include_secrets = False
862 include_secrets = False
856 if not has_superadmin_permission(apiuser):
863 if not has_superadmin_permission(apiuser):
857 validate_repo_permissions(apiuser, repoid, repo, ('repository.admin',))
864 validate_repo_permissions(apiuser, repoid, repo, ('repository.admin',))
858 else:
865 else:
859 include_secrets = True
866 include_secrets = True
860
867
861 updates = dict(
868 updates = dict(
862 repo_name=repo_name
869 repo_name=repo_name
863 if not isinstance(repo_name, Optional) else repo.repo_name,
870 if not isinstance(repo_name, Optional) else repo.repo_name,
864
871
865 fork_id=fork_of
872 fork_id=fork_of
866 if not isinstance(fork_of, Optional) else repo.fork.repo_name if repo.fork else None,
873 if not isinstance(fork_of, Optional) else repo.fork.repo_name if repo.fork else None,
867
874
868 user=owner
875 user=owner
869 if not isinstance(owner, Optional) else repo.user.username,
876 if not isinstance(owner, Optional) else repo.user.username,
870
877
871 repo_description=description
878 repo_description=description
872 if not isinstance(description, Optional) else repo.description,
879 if not isinstance(description, Optional) else repo.description,
873
880
874 repo_private=private
881 repo_private=private
875 if not isinstance(private, Optional) else repo.private,
882 if not isinstance(private, Optional) else repo.private,
876
883
877 clone_uri=clone_uri
884 clone_uri=clone_uri
878 if not isinstance(clone_uri, Optional) else repo.clone_uri,
885 if not isinstance(clone_uri, Optional) else repo.clone_uri,
879
886
887 push_uri=push_uri
888 if not isinstance(push_uri, Optional) else repo.push_uri,
889
880 repo_landing_rev=landing_rev
890 repo_landing_rev=landing_rev
881 if not isinstance(landing_rev, Optional) else repo._landing_revision,
891 if not isinstance(landing_rev, Optional) else repo._landing_revision,
882
892
883 repo_enable_statistics=enable_statistics
893 repo_enable_statistics=enable_statistics
884 if not isinstance(enable_statistics, Optional) else repo.enable_statistics,
894 if not isinstance(enable_statistics, Optional) else repo.enable_statistics,
885
895
886 repo_enable_locking=enable_locking
896 repo_enable_locking=enable_locking
887 if not isinstance(enable_locking, Optional) else repo.enable_locking,
897 if not isinstance(enable_locking, Optional) else repo.enable_locking,
888
898
889 repo_enable_downloads=enable_downloads
899 repo_enable_downloads=enable_downloads
890 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
900 if not isinstance(enable_downloads, Optional) else repo.enable_downloads)
891
901
892 ref_choices, _labels = ScmModel().get_repo_landing_revs(
902 ref_choices, _labels = ScmModel().get_repo_landing_revs(
893 request.translate, repo=repo)
903 request.translate, repo=repo)
894
904
895 old_values = repo.get_api_data()
905 old_values = repo.get_api_data()
896 repo_type = repo.repo_type
906 repo_type = repo.repo_type
897 schema = repo_schema.RepoSchema().bind(
907 schema = repo_schema.RepoSchema().bind(
898 repo_type_options=rhodecode.BACKENDS.keys(),
908 repo_type_options=rhodecode.BACKENDS.keys(),
899 repo_ref_options=ref_choices,
909 repo_ref_options=ref_choices,
900 repo_type=repo_type,
910 repo_type=repo_type,
901 # user caller
911 # user caller
902 user=apiuser,
912 user=apiuser,
903 old_values=old_values)
913 old_values=old_values)
904 try:
914 try:
905 schema_data = schema.deserialize(dict(
915 schema_data = schema.deserialize(dict(
906 # we save old value, users cannot change type
916 # we save old value, users cannot change type
907 repo_type=repo_type,
917 repo_type=repo_type,
908
918
909 repo_name=updates['repo_name'],
919 repo_name=updates['repo_name'],
910 repo_owner=updates['user'],
920 repo_owner=updates['user'],
911 repo_description=updates['repo_description'],
921 repo_description=updates['repo_description'],
912 repo_clone_uri=updates['clone_uri'],
922 repo_clone_uri=updates['clone_uri'],
923 repo_push_uri=updates['push_uri'],
913 repo_fork_of=updates['fork_id'],
924 repo_fork_of=updates['fork_id'],
914 repo_private=updates['repo_private'],
925 repo_private=updates['repo_private'],
915 repo_landing_commit_ref=updates['repo_landing_rev'],
926 repo_landing_commit_ref=updates['repo_landing_rev'],
916 repo_enable_statistics=updates['repo_enable_statistics'],
927 repo_enable_statistics=updates['repo_enable_statistics'],
917 repo_enable_downloads=updates['repo_enable_downloads'],
928 repo_enable_downloads=updates['repo_enable_downloads'],
918 repo_enable_locking=updates['repo_enable_locking']))
929 repo_enable_locking=updates['repo_enable_locking']))
919 except validation_schema.Invalid as err:
930 except validation_schema.Invalid as err:
920 raise JSONRPCValidationError(colander_exc=err)
931 raise JSONRPCValidationError(colander_exc=err)
921
932
922 # save validated data back into the updates dict
933 # save validated data back into the updates dict
923 validated_updates = dict(
934 validated_updates = dict(
924 repo_name=schema_data['repo_group']['repo_name_without_group'],
935 repo_name=schema_data['repo_group']['repo_name_without_group'],
925 repo_group=schema_data['repo_group']['repo_group_id'],
936 repo_group=schema_data['repo_group']['repo_group_id'],
926
937
927 user=schema_data['repo_owner'],
938 user=schema_data['repo_owner'],
928 repo_description=schema_data['repo_description'],
939 repo_description=schema_data['repo_description'],
929 repo_private=schema_data['repo_private'],
940 repo_private=schema_data['repo_private'],
930 clone_uri=schema_data['repo_clone_uri'],
941 clone_uri=schema_data['repo_clone_uri'],
942 push_uri=schema_data['repo_push_uri'],
931 repo_landing_rev=schema_data['repo_landing_commit_ref'],
943 repo_landing_rev=schema_data['repo_landing_commit_ref'],
932 repo_enable_statistics=schema_data['repo_enable_statistics'],
944 repo_enable_statistics=schema_data['repo_enable_statistics'],
933 repo_enable_locking=schema_data['repo_enable_locking'],
945 repo_enable_locking=schema_data['repo_enable_locking'],
934 repo_enable_downloads=schema_data['repo_enable_downloads'],
946 repo_enable_downloads=schema_data['repo_enable_downloads'],
935 )
947 )
936
948
937 if schema_data['repo_fork_of']:
949 if schema_data['repo_fork_of']:
938 fork_repo = get_repo_or_error(schema_data['repo_fork_of'])
950 fork_repo = get_repo_or_error(schema_data['repo_fork_of'])
939 validated_updates['fork_id'] = fork_repo.repo_id
951 validated_updates['fork_id'] = fork_repo.repo_id
940
952
941 # extra fields
953 # extra fields
942 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
954 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
943 if fields:
955 if fields:
944 validated_updates.update(fields)
956 validated_updates.update(fields)
945
957
946 try:
958 try:
947 RepoModel().update(repo, **validated_updates)
959 RepoModel().update(repo, **validated_updates)
948 audit_logger.store_api(
960 audit_logger.store_api(
949 'repo.edit', action_data={'old_data': old_values},
961 'repo.edit', action_data={'old_data': old_values},
950 user=apiuser, repo=repo)
962 user=apiuser, repo=repo)
951 Session().commit()
963 Session().commit()
952 return {
964 return {
953 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
965 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
954 'repository': repo.get_api_data(include_secrets=include_secrets)
966 'repository': repo.get_api_data(include_secrets=include_secrets)
955 }
967 }
956 except Exception:
968 except Exception:
957 log.exception(
969 log.exception(
958 u"Exception while trying to update the repository %s",
970 u"Exception while trying to update the repository %s",
959 repoid)
971 repoid)
960 raise JSONRPCError('failed to update repo `%s`' % repoid)
972 raise JSONRPCError('failed to update repo `%s`' % repoid)
961
973
962
974
963 @jsonrpc_method()
975 @jsonrpc_method()
964 def fork_repo(request, apiuser, repoid, fork_name,
976 def fork_repo(request, apiuser, repoid, fork_name,
965 owner=Optional(OAttr('apiuser')),
977 owner=Optional(OAttr('apiuser')),
966 description=Optional(''),
978 description=Optional(''),
967 private=Optional(False),
979 private=Optional(False),
968 clone_uri=Optional(None),
980 clone_uri=Optional(None),
969 landing_rev=Optional('rev:tip'),
981 landing_rev=Optional('rev:tip'),
970 copy_permissions=Optional(False)):
982 copy_permissions=Optional(False)):
971 """
983 """
972 Creates a fork of the specified |repo|.
984 Creates a fork of the specified |repo|.
973
985
974 * If the fork_name contains "/", fork will be created inside
986 * If the fork_name contains "/", fork will be created inside
975 a repository group or nested repository groups
987 a repository group or nested repository groups
976
988
977 For example "foo/bar/fork-repo" will create fork called "fork-repo"
989 For example "foo/bar/fork-repo" will create fork called "fork-repo"
978 inside group "foo/bar". You have to have permissions to access and
990 inside group "foo/bar". You have to have permissions to access and
979 write to the last repository group ("bar" in this example)
991 write to the last repository group ("bar" in this example)
980
992
981 This command can only be run using an |authtoken| with minimum
993 This command can only be run using an |authtoken| with minimum
982 read permissions of the forked repo, create fork permissions for an user.
994 read permissions of the forked repo, create fork permissions for an user.
983
995
984 :param apiuser: This is filled automatically from the |authtoken|.
996 :param apiuser: This is filled automatically from the |authtoken|.
985 :type apiuser: AuthUser
997 :type apiuser: AuthUser
986 :param repoid: Set repository name or repository ID.
998 :param repoid: Set repository name or repository ID.
987 :type repoid: str or int
999 :type repoid: str or int
988 :param fork_name: Set the fork name, including it's repository group membership.
1000 :param fork_name: Set the fork name, including it's repository group membership.
989 :type fork_name: str
1001 :type fork_name: str
990 :param owner: Set the fork owner.
1002 :param owner: Set the fork owner.
991 :type owner: str
1003 :type owner: str
992 :param description: Set the fork description.
1004 :param description: Set the fork description.
993 :type description: str
1005 :type description: str
994 :param copy_permissions: Copy permissions from parent |repo|. The
1006 :param copy_permissions: Copy permissions from parent |repo|. The
995 default is False.
1007 default is False.
996 :type copy_permissions: bool
1008 :type copy_permissions: bool
997 :param private: Make the fork private. The default is False.
1009 :param private: Make the fork private. The default is False.
998 :type private: bool
1010 :type private: bool
999 :param landing_rev: Set the landing revision. The default is tip.
1011 :param landing_rev: Set the landing revision. The default is tip.
1000
1012
1001 Example output:
1013 Example output:
1002
1014
1003 .. code-block:: bash
1015 .. code-block:: bash
1004
1016
1005 id : <id_for_response>
1017 id : <id_for_response>
1006 api_key : "<api_key>"
1018 api_key : "<api_key>"
1007 args: {
1019 args: {
1008 "repoid" : "<reponame or repo_id>",
1020 "repoid" : "<reponame or repo_id>",
1009 "fork_name": "<forkname>",
1021 "fork_name": "<forkname>",
1010 "owner": "<username or user_id = Optional(=apiuser)>",
1022 "owner": "<username or user_id = Optional(=apiuser)>",
1011 "description": "<description>",
1023 "description": "<description>",
1012 "copy_permissions": "<bool>",
1024 "copy_permissions": "<bool>",
1013 "private": "<bool>",
1025 "private": "<bool>",
1014 "landing_rev": "<landing_rev>"
1026 "landing_rev": "<landing_rev>"
1015 }
1027 }
1016
1028
1017 Example error output:
1029 Example error output:
1018
1030
1019 .. code-block:: bash
1031 .. code-block:: bash
1020
1032
1021 id : <id_given_in_input>
1033 id : <id_given_in_input>
1022 result: {
1034 result: {
1023 "msg": "Created fork of `<reponame>` as `<forkname>`",
1035 "msg": "Created fork of `<reponame>` as `<forkname>`",
1024 "success": true,
1036 "success": true,
1025 "task": "<celery task id or None if done sync>"
1037 "task": "<celery task id or None if done sync>"
1026 }
1038 }
1027 error: null
1039 error: null
1028
1040
1029 """
1041 """
1030
1042
1031 repo = get_repo_or_error(repoid)
1043 repo = get_repo_or_error(repoid)
1032 repo_name = repo.repo_name
1044 repo_name = repo.repo_name
1033
1045
1034 if not has_superadmin_permission(apiuser):
1046 if not has_superadmin_permission(apiuser):
1035 # check if we have at least read permission for
1047 # check if we have at least read permission for
1036 # this repo that we fork !
1048 # this repo that we fork !
1037 _perms = (
1049 _perms = (
1038 'repository.admin', 'repository.write', 'repository.read')
1050 'repository.admin', 'repository.write', 'repository.read')
1039 validate_repo_permissions(apiuser, repoid, repo, _perms)
1051 validate_repo_permissions(apiuser, repoid, repo, _perms)
1040
1052
1041 # check if the regular user has at least fork permissions as well
1053 # check if the regular user has at least fork permissions as well
1042 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
1054 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
1043 raise JSONRPCForbidden()
1055 raise JSONRPCForbidden()
1044
1056
1045 # check if user can set owner parameter
1057 # check if user can set owner parameter
1046 owner = validate_set_owner_permissions(apiuser, owner)
1058 owner = validate_set_owner_permissions(apiuser, owner)
1047
1059
1048 description = Optional.extract(description)
1060 description = Optional.extract(description)
1049 copy_permissions = Optional.extract(copy_permissions)
1061 copy_permissions = Optional.extract(copy_permissions)
1050 clone_uri = Optional.extract(clone_uri)
1062 clone_uri = Optional.extract(clone_uri)
1051 landing_commit_ref = Optional.extract(landing_rev)
1063 landing_commit_ref = Optional.extract(landing_rev)
1052 private = Optional.extract(private)
1064 private = Optional.extract(private)
1053
1065
1054 schema = repo_schema.RepoSchema().bind(
1066 schema = repo_schema.RepoSchema().bind(
1055 repo_type_options=rhodecode.BACKENDS.keys(),
1067 repo_type_options=rhodecode.BACKENDS.keys(),
1056 repo_type=repo.repo_type,
1068 repo_type=repo.repo_type,
1057 # user caller
1069 # user caller
1058 user=apiuser)
1070 user=apiuser)
1059
1071
1060 try:
1072 try:
1061 schema_data = schema.deserialize(dict(
1073 schema_data = schema.deserialize(dict(
1062 repo_name=fork_name,
1074 repo_name=fork_name,
1063 repo_type=repo.repo_type,
1075 repo_type=repo.repo_type,
1064 repo_owner=owner.username,
1076 repo_owner=owner.username,
1065 repo_description=description,
1077 repo_description=description,
1066 repo_landing_commit_ref=landing_commit_ref,
1078 repo_landing_commit_ref=landing_commit_ref,
1067 repo_clone_uri=clone_uri,
1079 repo_clone_uri=clone_uri,
1068 repo_private=private,
1080 repo_private=private,
1069 repo_copy_permissions=copy_permissions))
1081 repo_copy_permissions=copy_permissions))
1070 except validation_schema.Invalid as err:
1082 except validation_schema.Invalid as err:
1071 raise JSONRPCValidationError(colander_exc=err)
1083 raise JSONRPCValidationError(colander_exc=err)
1072
1084
1073 try:
1085 try:
1074 data = {
1086 data = {
1075 'fork_parent_id': repo.repo_id,
1087 'fork_parent_id': repo.repo_id,
1076
1088
1077 'repo_name': schema_data['repo_group']['repo_name_without_group'],
1089 'repo_name': schema_data['repo_group']['repo_name_without_group'],
1078 'repo_name_full': schema_data['repo_name'],
1090 'repo_name_full': schema_data['repo_name'],
1079 'repo_group': schema_data['repo_group']['repo_group_id'],
1091 'repo_group': schema_data['repo_group']['repo_group_id'],
1080 'repo_type': schema_data['repo_type'],
1092 'repo_type': schema_data['repo_type'],
1081 'description': schema_data['repo_description'],
1093 'description': schema_data['repo_description'],
1082 'private': schema_data['repo_private'],
1094 'private': schema_data['repo_private'],
1083 'copy_permissions': schema_data['repo_copy_permissions'],
1095 'copy_permissions': schema_data['repo_copy_permissions'],
1084 'landing_rev': schema_data['repo_landing_commit_ref'],
1096 'landing_rev': schema_data['repo_landing_commit_ref'],
1085 }
1097 }
1086
1098
1087 task = RepoModel().create_fork(data, cur_user=owner)
1099 task = RepoModel().create_fork(data, cur_user=owner.user_id)
1088 # no commit, it's done in RepoModel, or async via celery
1100 # no commit, it's done in RepoModel, or async via celery
1089 task_id = get_task_id(task)
1101 task_id = get_task_id(task)
1090
1102
1091 return {
1103 return {
1092 'msg': 'Created fork of `%s` as `%s`' % (
1104 'msg': 'Created fork of `%s` as `%s`' % (
1093 repo.repo_name, schema_data['repo_name']),
1105 repo.repo_name, schema_data['repo_name']),
1094 'success': True, # cannot return the repo data here since fork
1106 'success': True, # cannot return the repo data here since fork
1095 # can be done async
1107 # can be done async
1096 'task': task_id
1108 'task': task_id
1097 }
1109 }
1098 except Exception:
1110 except Exception:
1099 log.exception(
1111 log.exception(
1100 u"Exception while trying to create fork %s",
1112 u"Exception while trying to create fork %s",
1101 schema_data['repo_name'])
1113 schema_data['repo_name'])
1102 raise JSONRPCError(
1114 raise JSONRPCError(
1103 'failed to fork repository `%s` as `%s`' % (
1115 'failed to fork repository `%s` as `%s`' % (
1104 repo_name, schema_data['repo_name']))
1116 repo_name, schema_data['repo_name']))
1105
1117
1106
1118
1107 @jsonrpc_method()
1119 @jsonrpc_method()
1108 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1120 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1109 """
1121 """
1110 Deletes a repository.
1122 Deletes a repository.
1111
1123
1112 * When the `forks` parameter is set it's possible to detach or delete
1124 * When the `forks` parameter is set it's possible to detach or delete
1113 forks of deleted repository.
1125 forks of deleted repository.
1114
1126
1115 This command can only be run using an |authtoken| with admin
1127 This command can only be run using an |authtoken| with admin
1116 permissions on the |repo|.
1128 permissions on the |repo|.
1117
1129
1118 :param apiuser: This is filled automatically from the |authtoken|.
1130 :param apiuser: This is filled automatically from the |authtoken|.
1119 :type apiuser: AuthUser
1131 :type apiuser: AuthUser
1120 :param repoid: Set the repository name or repository ID.
1132 :param repoid: Set the repository name or repository ID.
1121 :type repoid: str or int
1133 :type repoid: str or int
1122 :param forks: Set to `detach` or `delete` forks from the |repo|.
1134 :param forks: Set to `detach` or `delete` forks from the |repo|.
1123 :type forks: Optional(str)
1135 :type forks: Optional(str)
1124
1136
1125 Example error output:
1137 Example error output:
1126
1138
1127 .. code-block:: bash
1139 .. code-block:: bash
1128
1140
1129 id : <id_given_in_input>
1141 id : <id_given_in_input>
1130 result: {
1142 result: {
1131 "msg": "Deleted repository `<reponame>`",
1143 "msg": "Deleted repository `<reponame>`",
1132 "success": true
1144 "success": true
1133 }
1145 }
1134 error: null
1146 error: null
1135 """
1147 """
1136
1148
1137 repo = get_repo_or_error(repoid)
1149 repo = get_repo_or_error(repoid)
1138 repo_name = repo.repo_name
1150 repo_name = repo.repo_name
1139 if not has_superadmin_permission(apiuser):
1151 if not has_superadmin_permission(apiuser):
1140 _perms = ('repository.admin',)
1152 _perms = ('repository.admin',)
1141 validate_repo_permissions(apiuser, repoid, repo, _perms)
1153 validate_repo_permissions(apiuser, repoid, repo, _perms)
1142
1154
1143 try:
1155 try:
1144 handle_forks = Optional.extract(forks)
1156 handle_forks = Optional.extract(forks)
1145 _forks_msg = ''
1157 _forks_msg = ''
1146 _forks = [f for f in repo.forks]
1158 _forks = [f for f in repo.forks]
1147 if handle_forks == 'detach':
1159 if handle_forks == 'detach':
1148 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1160 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1149 elif handle_forks == 'delete':
1161 elif handle_forks == 'delete':
1150 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1162 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1151 elif _forks:
1163 elif _forks:
1152 raise JSONRPCError(
1164 raise JSONRPCError(
1153 'Cannot delete `%s` it still contains attached forks' %
1165 'Cannot delete `%s` it still contains attached forks' %
1154 (repo.repo_name,)
1166 (repo.repo_name,)
1155 )
1167 )
1156 old_data = repo.get_api_data()
1168 old_data = repo.get_api_data()
1157 RepoModel().delete(repo, forks=forks)
1169 RepoModel().delete(repo, forks=forks)
1158
1170
1159 repo = audit_logger.RepoWrap(repo_id=None,
1171 repo = audit_logger.RepoWrap(repo_id=None,
1160 repo_name=repo.repo_name)
1172 repo_name=repo.repo_name)
1161
1173
1162 audit_logger.store_api(
1174 audit_logger.store_api(
1163 'repo.delete', action_data={'old_data': old_data},
1175 'repo.delete', action_data={'old_data': old_data},
1164 user=apiuser, repo=repo)
1176 user=apiuser, repo=repo)
1165
1177
1166 ScmModel().mark_for_invalidation(repo_name, delete=True)
1178 ScmModel().mark_for_invalidation(repo_name, delete=True)
1167 Session().commit()
1179 Session().commit()
1168 return {
1180 return {
1169 'msg': 'Deleted repository `%s`%s' % (repo_name, _forks_msg),
1181 'msg': 'Deleted repository `%s`%s' % (repo_name, _forks_msg),
1170 'success': True
1182 'success': True
1171 }
1183 }
1172 except Exception:
1184 except Exception:
1173 log.exception("Exception occurred while trying to delete repo")
1185 log.exception("Exception occurred while trying to delete repo")
1174 raise JSONRPCError(
1186 raise JSONRPCError(
1175 'failed to delete repository `%s`' % (repo_name,)
1187 'failed to delete repository `%s`' % (repo_name,)
1176 )
1188 )
1177
1189
1178
1190
1179 #TODO: marcink, change name ?
1191 #TODO: marcink, change name ?
1180 @jsonrpc_method()
1192 @jsonrpc_method()
1181 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1193 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1182 """
1194 """
1183 Invalidates the cache for the specified repository.
1195 Invalidates the cache for the specified repository.
1184
1196
1185 This command can only be run using an |authtoken| with admin rights to
1197 This command can only be run using an |authtoken| with admin rights to
1186 the specified repository.
1198 the specified repository.
1187
1199
1188 This command takes the following options:
1200 This command takes the following options:
1189
1201
1190 :param apiuser: This is filled automatically from |authtoken|.
1202 :param apiuser: This is filled automatically from |authtoken|.
1191 :type apiuser: AuthUser
1203 :type apiuser: AuthUser
1192 :param repoid: Sets the repository name or repository ID.
1204 :param repoid: Sets the repository name or repository ID.
1193 :type repoid: str or int
1205 :type repoid: str or int
1194 :param delete_keys: This deletes the invalidated keys instead of
1206 :param delete_keys: This deletes the invalidated keys instead of
1195 just flagging them.
1207 just flagging them.
1196 :type delete_keys: Optional(``True`` | ``False``)
1208 :type delete_keys: Optional(``True`` | ``False``)
1197
1209
1198 Example output:
1210 Example output:
1199
1211
1200 .. code-block:: bash
1212 .. code-block:: bash
1201
1213
1202 id : <id_given_in_input>
1214 id : <id_given_in_input>
1203 result : {
1215 result : {
1204 'msg': Cache for repository `<repository name>` was invalidated,
1216 'msg': Cache for repository `<repository name>` was invalidated,
1205 'repository': <repository name>
1217 'repository': <repository name>
1206 }
1218 }
1207 error : null
1219 error : null
1208
1220
1209 Example error output:
1221 Example error output:
1210
1222
1211 .. code-block:: bash
1223 .. code-block:: bash
1212
1224
1213 id : <id_given_in_input>
1225 id : <id_given_in_input>
1214 result : null
1226 result : null
1215 error : {
1227 error : {
1216 'Error occurred during cache invalidation action'
1228 'Error occurred during cache invalidation action'
1217 }
1229 }
1218
1230
1219 """
1231 """
1220
1232
1221 repo = get_repo_or_error(repoid)
1233 repo = get_repo_or_error(repoid)
1222 if not has_superadmin_permission(apiuser):
1234 if not has_superadmin_permission(apiuser):
1223 _perms = ('repository.admin', 'repository.write',)
1235 _perms = ('repository.admin', 'repository.write',)
1224 validate_repo_permissions(apiuser, repoid, repo, _perms)
1236 validate_repo_permissions(apiuser, repoid, repo, _perms)
1225
1237
1226 delete = Optional.extract(delete_keys)
1238 delete = Optional.extract(delete_keys)
1227 try:
1239 try:
1228 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1240 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1229 return {
1241 return {
1230 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1242 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1231 'repository': repo.repo_name
1243 'repository': repo.repo_name
1232 }
1244 }
1233 except Exception:
1245 except Exception:
1234 log.exception(
1246 log.exception(
1235 "Exception occurred while trying to invalidate repo cache")
1247 "Exception occurred while trying to invalidate repo cache")
1236 raise JSONRPCError(
1248 raise JSONRPCError(
1237 'Error occurred during cache invalidation action'
1249 'Error occurred during cache invalidation action'
1238 )
1250 )
1239
1251
1240
1252
1241 #TODO: marcink, change name ?
1253 #TODO: marcink, change name ?
1242 @jsonrpc_method()
1254 @jsonrpc_method()
1243 def lock(request, apiuser, repoid, locked=Optional(None),
1255 def lock(request, apiuser, repoid, locked=Optional(None),
1244 userid=Optional(OAttr('apiuser'))):
1256 userid=Optional(OAttr('apiuser'))):
1245 """
1257 """
1246 Sets the lock state of the specified |repo| by the given user.
1258 Sets the lock state of the specified |repo| by the given user.
1247 From more information, see :ref:`repo-locking`.
1259 From more information, see :ref:`repo-locking`.
1248
1260
1249 * If the ``userid`` option is not set, the repository is locked to the
1261 * If the ``userid`` option is not set, the repository is locked to the
1250 user who called the method.
1262 user who called the method.
1251 * If the ``locked`` parameter is not set, the current lock state of the
1263 * If the ``locked`` parameter is not set, the current lock state of the
1252 repository is displayed.
1264 repository is displayed.
1253
1265
1254 This command can only be run using an |authtoken| with admin rights to
1266 This command can only be run using an |authtoken| with admin rights to
1255 the specified repository.
1267 the specified repository.
1256
1268
1257 This command takes the following options:
1269 This command takes the following options:
1258
1270
1259 :param apiuser: This is filled automatically from the |authtoken|.
1271 :param apiuser: This is filled automatically from the |authtoken|.
1260 :type apiuser: AuthUser
1272 :type apiuser: AuthUser
1261 :param repoid: Sets the repository name or repository ID.
1273 :param repoid: Sets the repository name or repository ID.
1262 :type repoid: str or int
1274 :type repoid: str or int
1263 :param locked: Sets the lock state.
1275 :param locked: Sets the lock state.
1264 :type locked: Optional(``True`` | ``False``)
1276 :type locked: Optional(``True`` | ``False``)
1265 :param userid: Set the repository lock to this user.
1277 :param userid: Set the repository lock to this user.
1266 :type userid: Optional(str or int)
1278 :type userid: Optional(str or int)
1267
1279
1268 Example error output:
1280 Example error output:
1269
1281
1270 .. code-block:: bash
1282 .. code-block:: bash
1271
1283
1272 id : <id_given_in_input>
1284 id : <id_given_in_input>
1273 result : {
1285 result : {
1274 'repo': '<reponame>',
1286 'repo': '<reponame>',
1275 'locked': <bool: lock state>,
1287 'locked': <bool: lock state>,
1276 'locked_since': <int: lock timestamp>,
1288 'locked_since': <int: lock timestamp>,
1277 'locked_by': <username of person who made the lock>,
1289 'locked_by': <username of person who made the lock>,
1278 'lock_reason': <str: reason for locking>,
1290 'lock_reason': <str: reason for locking>,
1279 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1291 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1280 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1292 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1281 or
1293 or
1282 'msg': 'Repo `<repository name>` not locked.'
1294 'msg': 'Repo `<repository name>` not locked.'
1283 or
1295 or
1284 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1296 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1285 }
1297 }
1286 error : null
1298 error : null
1287
1299
1288 Example error output:
1300 Example error output:
1289
1301
1290 .. code-block:: bash
1302 .. code-block:: bash
1291
1303
1292 id : <id_given_in_input>
1304 id : <id_given_in_input>
1293 result : null
1305 result : null
1294 error : {
1306 error : {
1295 'Error occurred locking repository `<reponame>`'
1307 'Error occurred locking repository `<reponame>`'
1296 }
1308 }
1297 """
1309 """
1298
1310
1299 repo = get_repo_or_error(repoid)
1311 repo = get_repo_or_error(repoid)
1300 if not has_superadmin_permission(apiuser):
1312 if not has_superadmin_permission(apiuser):
1301 # check if we have at least write permission for this repo !
1313 # check if we have at least write permission for this repo !
1302 _perms = ('repository.admin', 'repository.write',)
1314 _perms = ('repository.admin', 'repository.write',)
1303 validate_repo_permissions(apiuser, repoid, repo, _perms)
1315 validate_repo_permissions(apiuser, repoid, repo, _perms)
1304
1316
1305 # make sure normal user does not pass someone else userid,
1317 # make sure normal user does not pass someone else userid,
1306 # he is not allowed to do that
1318 # he is not allowed to do that
1307 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1319 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1308 raise JSONRPCError('userid is not the same as your user')
1320 raise JSONRPCError('userid is not the same as your user')
1309
1321
1310 if isinstance(userid, Optional):
1322 if isinstance(userid, Optional):
1311 userid = apiuser.user_id
1323 userid = apiuser.user_id
1312
1324
1313 user = get_user_or_error(userid)
1325 user = get_user_or_error(userid)
1314
1326
1315 if isinstance(locked, Optional):
1327 if isinstance(locked, Optional):
1316 lockobj = repo.locked
1328 lockobj = repo.locked
1317
1329
1318 if lockobj[0] is None:
1330 if lockobj[0] is None:
1319 _d = {
1331 _d = {
1320 'repo': repo.repo_name,
1332 'repo': repo.repo_name,
1321 'locked': False,
1333 'locked': False,
1322 'locked_since': None,
1334 'locked_since': None,
1323 'locked_by': None,
1335 'locked_by': None,
1324 'lock_reason': None,
1336 'lock_reason': None,
1325 'lock_state_changed': False,
1337 'lock_state_changed': False,
1326 'msg': 'Repo `%s` not locked.' % repo.repo_name
1338 'msg': 'Repo `%s` not locked.' % repo.repo_name
1327 }
1339 }
1328 return _d
1340 return _d
1329 else:
1341 else:
1330 _user_id, _time, _reason = lockobj
1342 _user_id, _time, _reason = lockobj
1331 lock_user = get_user_or_error(userid)
1343 lock_user = get_user_or_error(userid)
1332 _d = {
1344 _d = {
1333 'repo': repo.repo_name,
1345 'repo': repo.repo_name,
1334 'locked': True,
1346 'locked': True,
1335 'locked_since': _time,
1347 'locked_since': _time,
1336 'locked_by': lock_user.username,
1348 'locked_by': lock_user.username,
1337 'lock_reason': _reason,
1349 'lock_reason': _reason,
1338 'lock_state_changed': False,
1350 'lock_state_changed': False,
1339 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1351 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1340 % (repo.repo_name, lock_user.username,
1352 % (repo.repo_name, lock_user.username,
1341 json.dumps(time_to_datetime(_time))))
1353 json.dumps(time_to_datetime(_time))))
1342 }
1354 }
1343 return _d
1355 return _d
1344
1356
1345 # force locked state through a flag
1357 # force locked state through a flag
1346 else:
1358 else:
1347 locked = str2bool(locked)
1359 locked = str2bool(locked)
1348 lock_reason = Repository.LOCK_API
1360 lock_reason = Repository.LOCK_API
1349 try:
1361 try:
1350 if locked:
1362 if locked:
1351 lock_time = time.time()
1363 lock_time = time.time()
1352 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1364 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1353 else:
1365 else:
1354 lock_time = None
1366 lock_time = None
1355 Repository.unlock(repo)
1367 Repository.unlock(repo)
1356 _d = {
1368 _d = {
1357 'repo': repo.repo_name,
1369 'repo': repo.repo_name,
1358 'locked': locked,
1370 'locked': locked,
1359 'locked_since': lock_time,
1371 'locked_since': lock_time,
1360 'locked_by': user.username,
1372 'locked_by': user.username,
1361 'lock_reason': lock_reason,
1373 'lock_reason': lock_reason,
1362 'lock_state_changed': True,
1374 'lock_state_changed': True,
1363 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1375 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1364 % (user.username, repo.repo_name, locked))
1376 % (user.username, repo.repo_name, locked))
1365 }
1377 }
1366 return _d
1378 return _d
1367 except Exception:
1379 except Exception:
1368 log.exception(
1380 log.exception(
1369 "Exception occurred while trying to lock repository")
1381 "Exception occurred while trying to lock repository")
1370 raise JSONRPCError(
1382 raise JSONRPCError(
1371 'Error occurred locking repository `%s`' % repo.repo_name
1383 'Error occurred locking repository `%s`' % repo.repo_name
1372 )
1384 )
1373
1385
1374
1386
1375 @jsonrpc_method()
1387 @jsonrpc_method()
1376 def comment_commit(
1388 def comment_commit(
1377 request, apiuser, repoid, commit_id, message, status=Optional(None),
1389 request, apiuser, repoid, commit_id, message, status=Optional(None),
1378 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1390 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
1379 resolves_comment_id=Optional(None),
1391 resolves_comment_id=Optional(None),
1380 userid=Optional(OAttr('apiuser'))):
1392 userid=Optional(OAttr('apiuser'))):
1381 """
1393 """
1382 Set a commit comment, and optionally change the status of the commit.
1394 Set a commit comment, and optionally change the status of the commit.
1383
1395
1384 :param apiuser: This is filled automatically from the |authtoken|.
1396 :param apiuser: This is filled automatically from the |authtoken|.
1385 :type apiuser: AuthUser
1397 :type apiuser: AuthUser
1386 :param repoid: Set the repository name or repository ID.
1398 :param repoid: Set the repository name or repository ID.
1387 :type repoid: str or int
1399 :type repoid: str or int
1388 :param commit_id: Specify the commit_id for which to set a comment.
1400 :param commit_id: Specify the commit_id for which to set a comment.
1389 :type commit_id: str
1401 :type commit_id: str
1390 :param message: The comment text.
1402 :param message: The comment text.
1391 :type message: str
1403 :type message: str
1392 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1404 :param status: (**Optional**) status of commit, one of: 'not_reviewed',
1393 'approved', 'rejected', 'under_review'
1405 'approved', 'rejected', 'under_review'
1394 :type status: str
1406 :type status: str
1395 :param comment_type: Comment type, one of: 'note', 'todo'
1407 :param comment_type: Comment type, one of: 'note', 'todo'
1396 :type comment_type: Optional(str), default: 'note'
1408 :type comment_type: Optional(str), default: 'note'
1397 :param userid: Set the user name of the comment creator.
1409 :param userid: Set the user name of the comment creator.
1398 :type userid: Optional(str or int)
1410 :type userid: Optional(str or int)
1399
1411
1400 Example error output:
1412 Example error output:
1401
1413
1402 .. code-block:: bash
1414 .. code-block:: bash
1403
1415
1404 {
1416 {
1405 "id" : <id_given_in_input>,
1417 "id" : <id_given_in_input>,
1406 "result" : {
1418 "result" : {
1407 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1419 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1408 "status_change": null or <status>,
1420 "status_change": null or <status>,
1409 "success": true
1421 "success": true
1410 },
1422 },
1411 "error" : null
1423 "error" : null
1412 }
1424 }
1413
1425
1414 """
1426 """
1415 repo = get_repo_or_error(repoid)
1427 repo = get_repo_or_error(repoid)
1416 if not has_superadmin_permission(apiuser):
1428 if not has_superadmin_permission(apiuser):
1417 _perms = ('repository.read', 'repository.write', 'repository.admin')
1429 _perms = ('repository.read', 'repository.write', 'repository.admin')
1418 validate_repo_permissions(apiuser, repoid, repo, _perms)
1430 validate_repo_permissions(apiuser, repoid, repo, _perms)
1419
1431
1420 try:
1432 try:
1421 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1433 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1422 except Exception as e:
1434 except Exception as e:
1423 log.exception('Failed to fetch commit')
1435 log.exception('Failed to fetch commit')
1424 raise JSONRPCError(e.message)
1436 raise JSONRPCError(e.message)
1425
1437
1426 if isinstance(userid, Optional):
1438 if isinstance(userid, Optional):
1427 userid = apiuser.user_id
1439 userid = apiuser.user_id
1428
1440
1429 user = get_user_or_error(userid)
1441 user = get_user_or_error(userid)
1430 status = Optional.extract(status)
1442 status = Optional.extract(status)
1431 comment_type = Optional.extract(comment_type)
1443 comment_type = Optional.extract(comment_type)
1432 resolves_comment_id = Optional.extract(resolves_comment_id)
1444 resolves_comment_id = Optional.extract(resolves_comment_id)
1433
1445
1434 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1446 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1435 if status and status not in allowed_statuses:
1447 if status and status not in allowed_statuses:
1436 raise JSONRPCError('Bad status, must be on '
1448 raise JSONRPCError('Bad status, must be on '
1437 'of %s got %s' % (allowed_statuses, status,))
1449 'of %s got %s' % (allowed_statuses, status,))
1438
1450
1439 if resolves_comment_id:
1451 if resolves_comment_id:
1440 comment = ChangesetComment.get(resolves_comment_id)
1452 comment = ChangesetComment.get(resolves_comment_id)
1441 if not comment:
1453 if not comment:
1442 raise JSONRPCError(
1454 raise JSONRPCError(
1443 'Invalid resolves_comment_id `%s` for this commit.'
1455 'Invalid resolves_comment_id `%s` for this commit.'
1444 % resolves_comment_id)
1456 % resolves_comment_id)
1445 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1457 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
1446 raise JSONRPCError(
1458 raise JSONRPCError(
1447 'Comment `%s` is wrong type for setting status to resolved.'
1459 'Comment `%s` is wrong type for setting status to resolved.'
1448 % resolves_comment_id)
1460 % resolves_comment_id)
1449
1461
1450 try:
1462 try:
1451 rc_config = SettingsModel().get_all_settings()
1463 rc_config = SettingsModel().get_all_settings()
1452 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1464 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1453 status_change_label = ChangesetStatus.get_status_lbl(status)
1465 status_change_label = ChangesetStatus.get_status_lbl(status)
1454 comment = CommentsModel().create(
1466 comment = CommentsModel().create(
1455 message, repo, user, commit_id=commit_id,
1467 message, repo, user, commit_id=commit_id,
1456 status_change=status_change_label,
1468 status_change=status_change_label,
1457 status_change_type=status,
1469 status_change_type=status,
1458 renderer=renderer,
1470 renderer=renderer,
1459 comment_type=comment_type,
1471 comment_type=comment_type,
1460 resolves_comment_id=resolves_comment_id
1472 resolves_comment_id=resolves_comment_id
1461 )
1473 )
1462 if status:
1474 if status:
1463 # also do a status change
1475 # also do a status change
1464 try:
1476 try:
1465 ChangesetStatusModel().set_status(
1477 ChangesetStatusModel().set_status(
1466 repo, status, user, comment, revision=commit_id,
1478 repo, status, user, comment, revision=commit_id,
1467 dont_allow_on_closed_pull_request=True
1479 dont_allow_on_closed_pull_request=True
1468 )
1480 )
1469 except StatusChangeOnClosedPullRequestError:
1481 except StatusChangeOnClosedPullRequestError:
1470 log.exception(
1482 log.exception(
1471 "Exception occurred while trying to change repo commit status")
1483 "Exception occurred while trying to change repo commit status")
1472 msg = ('Changing status on a changeset associated with '
1484 msg = ('Changing status on a changeset associated with '
1473 'a closed pull request is not allowed')
1485 'a closed pull request is not allowed')
1474 raise JSONRPCError(msg)
1486 raise JSONRPCError(msg)
1475
1487
1476 Session().commit()
1488 Session().commit()
1477 return {
1489 return {
1478 'msg': (
1490 'msg': (
1479 'Commented on commit `%s` for repository `%s`' % (
1491 'Commented on commit `%s` for repository `%s`' % (
1480 comment.revision, repo.repo_name)),
1492 comment.revision, repo.repo_name)),
1481 'status_change': status,
1493 'status_change': status,
1482 'success': True,
1494 'success': True,
1483 }
1495 }
1484 except JSONRPCError:
1496 except JSONRPCError:
1485 # catch any inside errors, and re-raise them to prevent from
1497 # catch any inside errors, and re-raise them to prevent from
1486 # below global catch to silence them
1498 # below global catch to silence them
1487 raise
1499 raise
1488 except Exception:
1500 except Exception:
1489 log.exception("Exception occurred while trying to comment on commit")
1501 log.exception("Exception occurred while trying to comment on commit")
1490 raise JSONRPCError(
1502 raise JSONRPCError(
1491 'failed to set comment on repository `%s`' % (repo.repo_name,)
1503 'failed to set comment on repository `%s`' % (repo.repo_name,)
1492 )
1504 )
1493
1505
1494
1506
1495 @jsonrpc_method()
1507 @jsonrpc_method()
1496 def grant_user_permission(request, apiuser, repoid, userid, perm):
1508 def grant_user_permission(request, apiuser, repoid, userid, perm):
1497 """
1509 """
1498 Grant permissions for the specified user on the given repository,
1510 Grant permissions for the specified user on the given repository,
1499 or update existing permissions if found.
1511 or update existing permissions if found.
1500
1512
1501 This command can only be run using an |authtoken| with admin
1513 This command can only be run using an |authtoken| with admin
1502 permissions on the |repo|.
1514 permissions on the |repo|.
1503
1515
1504 :param apiuser: This is filled automatically from the |authtoken|.
1516 :param apiuser: This is filled automatically from the |authtoken|.
1505 :type apiuser: AuthUser
1517 :type apiuser: AuthUser
1506 :param repoid: Set the repository name or repository ID.
1518 :param repoid: Set the repository name or repository ID.
1507 :type repoid: str or int
1519 :type repoid: str or int
1508 :param userid: Set the user name.
1520 :param userid: Set the user name.
1509 :type userid: str
1521 :type userid: str
1510 :param perm: Set the user permissions, using the following format
1522 :param perm: Set the user permissions, using the following format
1511 ``(repository.(none|read|write|admin))``
1523 ``(repository.(none|read|write|admin))``
1512 :type perm: str
1524 :type perm: str
1513
1525
1514 Example output:
1526 Example output:
1515
1527
1516 .. code-block:: bash
1528 .. code-block:: bash
1517
1529
1518 id : <id_given_in_input>
1530 id : <id_given_in_input>
1519 result: {
1531 result: {
1520 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1532 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1521 "success": true
1533 "success": true
1522 }
1534 }
1523 error: null
1535 error: null
1524 """
1536 """
1525
1537
1526 repo = get_repo_or_error(repoid)
1538 repo = get_repo_or_error(repoid)
1527 user = get_user_or_error(userid)
1539 user = get_user_or_error(userid)
1528 perm = get_perm_or_error(perm)
1540 perm = get_perm_or_error(perm)
1529 if not has_superadmin_permission(apiuser):
1541 if not has_superadmin_permission(apiuser):
1530 _perms = ('repository.admin',)
1542 _perms = ('repository.admin',)
1531 validate_repo_permissions(apiuser, repoid, repo, _perms)
1543 validate_repo_permissions(apiuser, repoid, repo, _perms)
1532
1544
1533 try:
1545 try:
1534
1546
1535 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1547 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1536
1548
1537 Session().commit()
1549 Session().commit()
1538 return {
1550 return {
1539 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1551 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1540 perm.permission_name, user.username, repo.repo_name
1552 perm.permission_name, user.username, repo.repo_name
1541 ),
1553 ),
1542 'success': True
1554 'success': True
1543 }
1555 }
1544 except Exception:
1556 except Exception:
1545 log.exception(
1557 log.exception(
1546 "Exception occurred while trying edit permissions for repo")
1558 "Exception occurred while trying edit permissions for repo")
1547 raise JSONRPCError(
1559 raise JSONRPCError(
1548 'failed to edit permission for user: `%s` in repo: `%s`' % (
1560 'failed to edit permission for user: `%s` in repo: `%s`' % (
1549 userid, repoid
1561 userid, repoid
1550 )
1562 )
1551 )
1563 )
1552
1564
1553
1565
1554 @jsonrpc_method()
1566 @jsonrpc_method()
1555 def revoke_user_permission(request, apiuser, repoid, userid):
1567 def revoke_user_permission(request, apiuser, repoid, userid):
1556 """
1568 """
1557 Revoke permission for a user on the specified repository.
1569 Revoke permission for a user on the specified repository.
1558
1570
1559 This command can only be run using an |authtoken| with admin
1571 This command can only be run using an |authtoken| with admin
1560 permissions on the |repo|.
1572 permissions on the |repo|.
1561
1573
1562 :param apiuser: This is filled automatically from the |authtoken|.
1574 :param apiuser: This is filled automatically from the |authtoken|.
1563 :type apiuser: AuthUser
1575 :type apiuser: AuthUser
1564 :param repoid: Set the repository name or repository ID.
1576 :param repoid: Set the repository name or repository ID.
1565 :type repoid: str or int
1577 :type repoid: str or int
1566 :param userid: Set the user name of revoked user.
1578 :param userid: Set the user name of revoked user.
1567 :type userid: str or int
1579 :type userid: str or int
1568
1580
1569 Example error output:
1581 Example error output:
1570
1582
1571 .. code-block:: bash
1583 .. code-block:: bash
1572
1584
1573 id : <id_given_in_input>
1585 id : <id_given_in_input>
1574 result: {
1586 result: {
1575 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1587 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1576 "success": true
1588 "success": true
1577 }
1589 }
1578 error: null
1590 error: null
1579 """
1591 """
1580
1592
1581 repo = get_repo_or_error(repoid)
1593 repo = get_repo_or_error(repoid)
1582 user = get_user_or_error(userid)
1594 user = get_user_or_error(userid)
1583 if not has_superadmin_permission(apiuser):
1595 if not has_superadmin_permission(apiuser):
1584 _perms = ('repository.admin',)
1596 _perms = ('repository.admin',)
1585 validate_repo_permissions(apiuser, repoid, repo, _perms)
1597 validate_repo_permissions(apiuser, repoid, repo, _perms)
1586
1598
1587 try:
1599 try:
1588 RepoModel().revoke_user_permission(repo=repo, user=user)
1600 RepoModel().revoke_user_permission(repo=repo, user=user)
1589 Session().commit()
1601 Session().commit()
1590 return {
1602 return {
1591 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1603 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1592 user.username, repo.repo_name
1604 user.username, repo.repo_name
1593 ),
1605 ),
1594 'success': True
1606 'success': True
1595 }
1607 }
1596 except Exception:
1608 except Exception:
1597 log.exception(
1609 log.exception(
1598 "Exception occurred while trying revoke permissions to repo")
1610 "Exception occurred while trying revoke permissions to repo")
1599 raise JSONRPCError(
1611 raise JSONRPCError(
1600 'failed to edit permission for user: `%s` in repo: `%s`' % (
1612 'failed to edit permission for user: `%s` in repo: `%s`' % (
1601 userid, repoid
1613 userid, repoid
1602 )
1614 )
1603 )
1615 )
1604
1616
1605
1617
1606 @jsonrpc_method()
1618 @jsonrpc_method()
1607 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1619 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1608 """
1620 """
1609 Grant permission for a user group on the specified repository,
1621 Grant permission for a user group on the specified repository,
1610 or update existing permissions.
1622 or update existing permissions.
1611
1623
1612 This command can only be run using an |authtoken| with admin
1624 This command can only be run using an |authtoken| with admin
1613 permissions on the |repo|.
1625 permissions on the |repo|.
1614
1626
1615 :param apiuser: This is filled automatically from the |authtoken|.
1627 :param apiuser: This is filled automatically from the |authtoken|.
1616 :type apiuser: AuthUser
1628 :type apiuser: AuthUser
1617 :param repoid: Set the repository name or repository ID.
1629 :param repoid: Set the repository name or repository ID.
1618 :type repoid: str or int
1630 :type repoid: str or int
1619 :param usergroupid: Specify the ID of the user group.
1631 :param usergroupid: Specify the ID of the user group.
1620 :type usergroupid: str or int
1632 :type usergroupid: str or int
1621 :param perm: Set the user group permissions using the following
1633 :param perm: Set the user group permissions using the following
1622 format: (repository.(none|read|write|admin))
1634 format: (repository.(none|read|write|admin))
1623 :type perm: str
1635 :type perm: str
1624
1636
1625 Example output:
1637 Example output:
1626
1638
1627 .. code-block:: bash
1639 .. code-block:: bash
1628
1640
1629 id : <id_given_in_input>
1641 id : <id_given_in_input>
1630 result : {
1642 result : {
1631 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1643 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1632 "success": true
1644 "success": true
1633
1645
1634 }
1646 }
1635 error : null
1647 error : null
1636
1648
1637 Example error output:
1649 Example error output:
1638
1650
1639 .. code-block:: bash
1651 .. code-block:: bash
1640
1652
1641 id : <id_given_in_input>
1653 id : <id_given_in_input>
1642 result : null
1654 result : null
1643 error : {
1655 error : {
1644 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1656 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1645 }
1657 }
1646
1658
1647 """
1659 """
1648
1660
1649 repo = get_repo_or_error(repoid)
1661 repo = get_repo_or_error(repoid)
1650 perm = get_perm_or_error(perm)
1662 perm = get_perm_or_error(perm)
1651 if not has_superadmin_permission(apiuser):
1663 if not has_superadmin_permission(apiuser):
1652 _perms = ('repository.admin',)
1664 _perms = ('repository.admin',)
1653 validate_repo_permissions(apiuser, repoid, repo, _perms)
1665 validate_repo_permissions(apiuser, repoid, repo, _perms)
1654
1666
1655 user_group = get_user_group_or_error(usergroupid)
1667 user_group = get_user_group_or_error(usergroupid)
1656 if not has_superadmin_permission(apiuser):
1668 if not has_superadmin_permission(apiuser):
1657 # check if we have at least read permission for this user group !
1669 # check if we have at least read permission for this user group !
1658 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1670 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1659 if not HasUserGroupPermissionAnyApi(*_perms)(
1671 if not HasUserGroupPermissionAnyApi(*_perms)(
1660 user=apiuser, user_group_name=user_group.users_group_name):
1672 user=apiuser, user_group_name=user_group.users_group_name):
1661 raise JSONRPCError(
1673 raise JSONRPCError(
1662 'user group `%s` does not exist' % (usergroupid,))
1674 'user group `%s` does not exist' % (usergroupid,))
1663
1675
1664 try:
1676 try:
1665 RepoModel().grant_user_group_permission(
1677 RepoModel().grant_user_group_permission(
1666 repo=repo, group_name=user_group, perm=perm)
1678 repo=repo, group_name=user_group, perm=perm)
1667
1679
1668 Session().commit()
1680 Session().commit()
1669 return {
1681 return {
1670 'msg': 'Granted perm: `%s` for user group: `%s` in '
1682 'msg': 'Granted perm: `%s` for user group: `%s` in '
1671 'repo: `%s`' % (
1683 'repo: `%s`' % (
1672 perm.permission_name, user_group.users_group_name,
1684 perm.permission_name, user_group.users_group_name,
1673 repo.repo_name
1685 repo.repo_name
1674 ),
1686 ),
1675 'success': True
1687 'success': True
1676 }
1688 }
1677 except Exception:
1689 except Exception:
1678 log.exception(
1690 log.exception(
1679 "Exception occurred while trying change permission on repo")
1691 "Exception occurred while trying change permission on repo")
1680 raise JSONRPCError(
1692 raise JSONRPCError(
1681 'failed to edit permission for user group: `%s` in '
1693 'failed to edit permission for user group: `%s` in '
1682 'repo: `%s`' % (
1694 'repo: `%s`' % (
1683 usergroupid, repo.repo_name
1695 usergroupid, repo.repo_name
1684 )
1696 )
1685 )
1697 )
1686
1698
1687
1699
1688 @jsonrpc_method()
1700 @jsonrpc_method()
1689 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1701 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1690 """
1702 """
1691 Revoke the permissions of a user group on a given repository.
1703 Revoke the permissions of a user group on a given repository.
1692
1704
1693 This command can only be run using an |authtoken| with admin
1705 This command can only be run using an |authtoken| with admin
1694 permissions on the |repo|.
1706 permissions on the |repo|.
1695
1707
1696 :param apiuser: This is filled automatically from the |authtoken|.
1708 :param apiuser: This is filled automatically from the |authtoken|.
1697 :type apiuser: AuthUser
1709 :type apiuser: AuthUser
1698 :param repoid: Set the repository name or repository ID.
1710 :param repoid: Set the repository name or repository ID.
1699 :type repoid: str or int
1711 :type repoid: str or int
1700 :param usergroupid: Specify the user group ID.
1712 :param usergroupid: Specify the user group ID.
1701 :type usergroupid: str or int
1713 :type usergroupid: str or int
1702
1714
1703 Example output:
1715 Example output:
1704
1716
1705 .. code-block:: bash
1717 .. code-block:: bash
1706
1718
1707 id : <id_given_in_input>
1719 id : <id_given_in_input>
1708 result: {
1720 result: {
1709 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1721 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1710 "success": true
1722 "success": true
1711 }
1723 }
1712 error: null
1724 error: null
1713 """
1725 """
1714
1726
1715 repo = get_repo_or_error(repoid)
1727 repo = get_repo_or_error(repoid)
1716 if not has_superadmin_permission(apiuser):
1728 if not has_superadmin_permission(apiuser):
1717 _perms = ('repository.admin',)
1729 _perms = ('repository.admin',)
1718 validate_repo_permissions(apiuser, repoid, repo, _perms)
1730 validate_repo_permissions(apiuser, repoid, repo, _perms)
1719
1731
1720 user_group = get_user_group_or_error(usergroupid)
1732 user_group = get_user_group_or_error(usergroupid)
1721 if not has_superadmin_permission(apiuser):
1733 if not has_superadmin_permission(apiuser):
1722 # check if we have at least read permission for this user group !
1734 # check if we have at least read permission for this user group !
1723 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1735 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1724 if not HasUserGroupPermissionAnyApi(*_perms)(
1736 if not HasUserGroupPermissionAnyApi(*_perms)(
1725 user=apiuser, user_group_name=user_group.users_group_name):
1737 user=apiuser, user_group_name=user_group.users_group_name):
1726 raise JSONRPCError(
1738 raise JSONRPCError(
1727 'user group `%s` does not exist' % (usergroupid,))
1739 'user group `%s` does not exist' % (usergroupid,))
1728
1740
1729 try:
1741 try:
1730 RepoModel().revoke_user_group_permission(
1742 RepoModel().revoke_user_group_permission(
1731 repo=repo, group_name=user_group)
1743 repo=repo, group_name=user_group)
1732
1744
1733 Session().commit()
1745 Session().commit()
1734 return {
1746 return {
1735 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1747 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1736 user_group.users_group_name, repo.repo_name
1748 user_group.users_group_name, repo.repo_name
1737 ),
1749 ),
1738 'success': True
1750 'success': True
1739 }
1751 }
1740 except Exception:
1752 except Exception:
1741 log.exception("Exception occurred while trying revoke "
1753 log.exception("Exception occurred while trying revoke "
1742 "user group permission on repo")
1754 "user group permission on repo")
1743 raise JSONRPCError(
1755 raise JSONRPCError(
1744 'failed to edit permission for user group: `%s` in '
1756 'failed to edit permission for user group: `%s` in '
1745 'repo: `%s`' % (
1757 'repo: `%s`' % (
1746 user_group.users_group_name, repo.repo_name
1758 user_group.users_group_name, repo.repo_name
1747 )
1759 )
1748 )
1760 )
1749
1761
1750
1762
1751 @jsonrpc_method()
1763 @jsonrpc_method()
1752 def pull(request, apiuser, repoid):
1764 def pull(request, apiuser, repoid, remote_uri=Optional(None)):
1753 """
1765 """
1754 Triggers a pull on the given repository from a remote location. You
1766 Triggers a pull on the given repository from a remote location. You
1755 can use this to keep remote repositories up-to-date.
1767 can use this to keep remote repositories up-to-date.
1756
1768
1757 This command can only be run using an |authtoken| with admin
1769 This command can only be run using an |authtoken| with admin
1758 rights to the specified repository. For more information,
1770 rights to the specified repository. For more information,
1759 see :ref:`config-token-ref`.
1771 see :ref:`config-token-ref`.
1760
1772
1761 This command takes the following options:
1773 This command takes the following options:
1762
1774
1763 :param apiuser: This is filled automatically from the |authtoken|.
1775 :param apiuser: This is filled automatically from the |authtoken|.
1764 :type apiuser: AuthUser
1776 :type apiuser: AuthUser
1765 :param repoid: The repository name or repository ID.
1777 :param repoid: The repository name or repository ID.
1766 :type repoid: str or int
1778 :type repoid: str or int
1779 :param remote_uri: Optional remote URI to pass in for pull
1780 :type remote_uri: str
1767
1781
1768 Example output:
1782 Example output:
1769
1783
1770 .. code-block:: bash
1784 .. code-block:: bash
1771
1785
1772 id : <id_given_in_input>
1786 id : <id_given_in_input>
1773 result : {
1787 result : {
1774 "msg": "Pulled from `<repository name>`"
1788 "msg": "Pulled from url `<remote_url>` on repo `<repository name>`"
1775 "repository": "<repository name>"
1789 "repository": "<repository name>"
1776 }
1790 }
1777 error : null
1791 error : null
1778
1792
1779 Example error output:
1793 Example error output:
1780
1794
1781 .. code-block:: bash
1795 .. code-block:: bash
1782
1796
1783 id : <id_given_in_input>
1797 id : <id_given_in_input>
1784 result : null
1798 result : null
1785 error : {
1799 error : {
1786 "Unable to pull changes from `<reponame>`"
1800 "Unable to push changes from `<remote_url>`"
1787 }
1801 }
1788
1802
1789 """
1803 """
1790
1804
1791 repo = get_repo_or_error(repoid)
1805 repo = get_repo_or_error(repoid)
1806 remote_uri = Optional.extract(remote_uri)
1807 remote_uri_display = remote_uri or repo.clone_uri_hidden
1792 if not has_superadmin_permission(apiuser):
1808 if not has_superadmin_permission(apiuser):
1793 _perms = ('repository.admin',)
1809 _perms = ('repository.admin',)
1794 validate_repo_permissions(apiuser, repoid, repo, _perms)
1810 validate_repo_permissions(apiuser, repoid, repo, _perms)
1795
1811
1796 try:
1812 try:
1797 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1813 ScmModel().pull_changes(
1814 repo.repo_name, apiuser.username, remote_uri=remote_uri)
1798 return {
1815 return {
1799 'msg': 'Pulled from `%s`' % repo.repo_name,
1816 'msg': 'Pulled from url `%s` on repo `%s`' % (
1817 remote_uri_display, repo.repo_name),
1800 'repository': repo.repo_name
1818 'repository': repo.repo_name
1801 }
1819 }
1802 except Exception:
1820 except Exception:
1803 log.exception("Exception occurred while trying to "
1821 log.exception("Exception occurred while trying to "
1804 "pull changes from remote location")
1822 "pull changes from remote location")
1805 raise JSONRPCError(
1823 raise JSONRPCError(
1806 'Unable to pull changes from `%s`' % repo.repo_name
1824 'Unable to pull changes from `%s`' % remote_uri_display
1807 )
1825 )
1808
1826
1809
1827
1810 @jsonrpc_method()
1828 @jsonrpc_method()
1811 def strip(request, apiuser, repoid, revision, branch):
1829 def strip(request, apiuser, repoid, revision, branch):
1812 """
1830 """
1813 Strips the given revision from the specified repository.
1831 Strips the given revision from the specified repository.
1814
1832
1815 * This will remove the revision and all of its decendants.
1833 * This will remove the revision and all of its decendants.
1816
1834
1817 This command can only be run using an |authtoken| with admin rights to
1835 This command can only be run using an |authtoken| with admin rights to
1818 the specified repository.
1836 the specified repository.
1819
1837
1820 This command takes the following options:
1838 This command takes the following options:
1821
1839
1822 :param apiuser: This is filled automatically from the |authtoken|.
1840 :param apiuser: This is filled automatically from the |authtoken|.
1823 :type apiuser: AuthUser
1841 :type apiuser: AuthUser
1824 :param repoid: The repository name or repository ID.
1842 :param repoid: The repository name or repository ID.
1825 :type repoid: str or int
1843 :type repoid: str or int
1826 :param revision: The revision you wish to strip.
1844 :param revision: The revision you wish to strip.
1827 :type revision: str
1845 :type revision: str
1828 :param branch: The branch from which to strip the revision.
1846 :param branch: The branch from which to strip the revision.
1829 :type branch: str
1847 :type branch: str
1830
1848
1831 Example output:
1849 Example output:
1832
1850
1833 .. code-block:: bash
1851 .. code-block:: bash
1834
1852
1835 id : <id_given_in_input>
1853 id : <id_given_in_input>
1836 result : {
1854 result : {
1837 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1855 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1838 "repository": "<repository name>"
1856 "repository": "<repository name>"
1839 }
1857 }
1840 error : null
1858 error : null
1841
1859
1842 Example error output:
1860 Example error output:
1843
1861
1844 .. code-block:: bash
1862 .. code-block:: bash
1845
1863
1846 id : <id_given_in_input>
1864 id : <id_given_in_input>
1847 result : null
1865 result : null
1848 error : {
1866 error : {
1849 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1867 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1850 }
1868 }
1851
1869
1852 """
1870 """
1853
1871
1854 repo = get_repo_or_error(repoid)
1872 repo = get_repo_or_error(repoid)
1855 if not has_superadmin_permission(apiuser):
1873 if not has_superadmin_permission(apiuser):
1856 _perms = ('repository.admin',)
1874 _perms = ('repository.admin',)
1857 validate_repo_permissions(apiuser, repoid, repo, _perms)
1875 validate_repo_permissions(apiuser, repoid, repo, _perms)
1858
1876
1859 try:
1877 try:
1860 ScmModel().strip(repo, revision, branch)
1878 ScmModel().strip(repo, revision, branch)
1861 audit_logger.store_api(
1879 audit_logger.store_api(
1862 'repo.commit.strip', action_data={'commit_id': revision},
1880 'repo.commit.strip', action_data={'commit_id': revision},
1863 repo=repo,
1881 repo=repo,
1864 user=apiuser, commit=True)
1882 user=apiuser, commit=True)
1865
1883
1866 return {
1884 return {
1867 'msg': 'Stripped commit %s from repo `%s`' % (
1885 'msg': 'Stripped commit %s from repo `%s`' % (
1868 revision, repo.repo_name),
1886 revision, repo.repo_name),
1869 'repository': repo.repo_name
1887 'repository': repo.repo_name
1870 }
1888 }
1871 except Exception:
1889 except Exception:
1872 log.exception("Exception while trying to strip")
1890 log.exception("Exception while trying to strip")
1873 raise JSONRPCError(
1891 raise JSONRPCError(
1874 'Unable to strip commit %s from repo `%s`' % (
1892 'Unable to strip commit %s from repo `%s`' % (
1875 revision, repo.repo_name)
1893 revision, repo.repo_name)
1876 )
1894 )
1877
1895
1878
1896
1879 @jsonrpc_method()
1897 @jsonrpc_method()
1880 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1898 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1881 """
1899 """
1882 Returns all settings for a repository. If key is given it only returns the
1900 Returns all settings for a repository. If key is given it only returns the
1883 setting identified by the key or null.
1901 setting identified by the key or null.
1884
1902
1885 :param apiuser: This is filled automatically from the |authtoken|.
1903 :param apiuser: This is filled automatically from the |authtoken|.
1886 :type apiuser: AuthUser
1904 :type apiuser: AuthUser
1887 :param repoid: The repository name or repository id.
1905 :param repoid: The repository name or repository id.
1888 :type repoid: str or int
1906 :type repoid: str or int
1889 :param key: Key of the setting to return.
1907 :param key: Key of the setting to return.
1890 :type: key: Optional(str)
1908 :type: key: Optional(str)
1891
1909
1892 Example output:
1910 Example output:
1893
1911
1894 .. code-block:: bash
1912 .. code-block:: bash
1895
1913
1896 {
1914 {
1897 "error": null,
1915 "error": null,
1898 "id": 237,
1916 "id": 237,
1899 "result": {
1917 "result": {
1900 "extensions_largefiles": true,
1918 "extensions_largefiles": true,
1901 "extensions_evolve": true,
1919 "extensions_evolve": true,
1902 "hooks_changegroup_push_logger": true,
1920 "hooks_changegroup_push_logger": true,
1903 "hooks_changegroup_repo_size": false,
1921 "hooks_changegroup_repo_size": false,
1904 "hooks_outgoing_pull_logger": true,
1922 "hooks_outgoing_pull_logger": true,
1905 "phases_publish": "True",
1923 "phases_publish": "True",
1906 "rhodecode_hg_use_rebase_for_merging": true,
1924 "rhodecode_hg_use_rebase_for_merging": true,
1907 "rhodecode_pr_merge_enabled": true,
1925 "rhodecode_pr_merge_enabled": true,
1908 "rhodecode_use_outdated_comments": true
1926 "rhodecode_use_outdated_comments": true
1909 }
1927 }
1910 }
1928 }
1911 """
1929 """
1912
1930
1913 # Restrict access to this api method to admins only.
1931 # Restrict access to this api method to admins only.
1914 if not has_superadmin_permission(apiuser):
1932 if not has_superadmin_permission(apiuser):
1915 raise JSONRPCForbidden()
1933 raise JSONRPCForbidden()
1916
1934
1917 try:
1935 try:
1918 repo = get_repo_or_error(repoid)
1936 repo = get_repo_or_error(repoid)
1919 settings_model = VcsSettingsModel(repo=repo)
1937 settings_model = VcsSettingsModel(repo=repo)
1920 settings = settings_model.get_global_settings()
1938 settings = settings_model.get_global_settings()
1921 settings.update(settings_model.get_repo_settings())
1939 settings.update(settings_model.get_repo_settings())
1922
1940
1923 # If only a single setting is requested fetch it from all settings.
1941 # If only a single setting is requested fetch it from all settings.
1924 key = Optional.extract(key)
1942 key = Optional.extract(key)
1925 if key is not None:
1943 if key is not None:
1926 settings = settings.get(key, None)
1944 settings = settings.get(key, None)
1927 except Exception:
1945 except Exception:
1928 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1946 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1929 log.exception(msg)
1947 log.exception(msg)
1930 raise JSONRPCError(msg)
1948 raise JSONRPCError(msg)
1931
1949
1932 return settings
1950 return settings
1933
1951
1934
1952
1935 @jsonrpc_method()
1953 @jsonrpc_method()
1936 def set_repo_settings(request, apiuser, repoid, settings):
1954 def set_repo_settings(request, apiuser, repoid, settings):
1937 """
1955 """
1938 Update repository settings. Returns true on success.
1956 Update repository settings. Returns true on success.
1939
1957
1940 :param apiuser: This is filled automatically from the |authtoken|.
1958 :param apiuser: This is filled automatically from the |authtoken|.
1941 :type apiuser: AuthUser
1959 :type apiuser: AuthUser
1942 :param repoid: The repository name or repository id.
1960 :param repoid: The repository name or repository id.
1943 :type repoid: str or int
1961 :type repoid: str or int
1944 :param settings: The new settings for the repository.
1962 :param settings: The new settings for the repository.
1945 :type: settings: dict
1963 :type: settings: dict
1946
1964
1947 Example output:
1965 Example output:
1948
1966
1949 .. code-block:: bash
1967 .. code-block:: bash
1950
1968
1951 {
1969 {
1952 "error": null,
1970 "error": null,
1953 "id": 237,
1971 "id": 237,
1954 "result": true
1972 "result": true
1955 }
1973 }
1956 """
1974 """
1957 # Restrict access to this api method to admins only.
1975 # Restrict access to this api method to admins only.
1958 if not has_superadmin_permission(apiuser):
1976 if not has_superadmin_permission(apiuser):
1959 raise JSONRPCForbidden()
1977 raise JSONRPCForbidden()
1960
1978
1961 if type(settings) is not dict:
1979 if type(settings) is not dict:
1962 raise JSONRPCError('Settings have to be a JSON Object.')
1980 raise JSONRPCError('Settings have to be a JSON Object.')
1963
1981
1964 try:
1982 try:
1965 settings_model = VcsSettingsModel(repo=repoid)
1983 settings_model = VcsSettingsModel(repo=repoid)
1966
1984
1967 # Merge global, repo and incoming settings.
1985 # Merge global, repo and incoming settings.
1968 new_settings = settings_model.get_global_settings()
1986 new_settings = settings_model.get_global_settings()
1969 new_settings.update(settings_model.get_repo_settings())
1987 new_settings.update(settings_model.get_repo_settings())
1970 new_settings.update(settings)
1988 new_settings.update(settings)
1971
1989
1972 # Update the settings.
1990 # Update the settings.
1973 inherit_global_settings = new_settings.get(
1991 inherit_global_settings = new_settings.get(
1974 'inherit_global_settings', False)
1992 'inherit_global_settings', False)
1975 settings_model.create_or_update_repo_settings(
1993 settings_model.create_or_update_repo_settings(
1976 new_settings, inherit_global_settings=inherit_global_settings)
1994 new_settings, inherit_global_settings=inherit_global_settings)
1977 Session().commit()
1995 Session().commit()
1978 except Exception:
1996 except Exception:
1979 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1997 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1980 log.exception(msg)
1998 log.exception(msg)
1981 raise JSONRPCError(msg)
1999 raise JSONRPCError(msg)
1982
2000
1983 # Indicate success.
2001 # Indicate success.
1984 return True
2002 return True
1985
2003
1986
2004
1987 @jsonrpc_method()
2005 @jsonrpc_method()
1988 def maintenance(request, apiuser, repoid):
2006 def maintenance(request, apiuser, repoid):
1989 """
2007 """
1990 Triggers a maintenance on the given repository.
2008 Triggers a maintenance on the given repository.
1991
2009
1992 This command can only be run using an |authtoken| with admin
2010 This command can only be run using an |authtoken| with admin
1993 rights to the specified repository. For more information,
2011 rights to the specified repository. For more information,
1994 see :ref:`config-token-ref`.
2012 see :ref:`config-token-ref`.
1995
2013
1996 This command takes the following options:
2014 This command takes the following options:
1997
2015
1998 :param apiuser: This is filled automatically from the |authtoken|.
2016 :param apiuser: This is filled automatically from the |authtoken|.
1999 :type apiuser: AuthUser
2017 :type apiuser: AuthUser
2000 :param repoid: The repository name or repository ID.
2018 :param repoid: The repository name or repository ID.
2001 :type repoid: str or int
2019 :type repoid: str or int
2002
2020
2003 Example output:
2021 Example output:
2004
2022
2005 .. code-block:: bash
2023 .. code-block:: bash
2006
2024
2007 id : <id_given_in_input>
2025 id : <id_given_in_input>
2008 result : {
2026 result : {
2009 "msg": "executed maintenance command",
2027 "msg": "executed maintenance command",
2010 "executed_actions": [
2028 "executed_actions": [
2011 <action_message>, <action_message2>...
2029 <action_message>, <action_message2>...
2012 ],
2030 ],
2013 "repository": "<repository name>"
2031 "repository": "<repository name>"
2014 }
2032 }
2015 error : null
2033 error : null
2016
2034
2017 Example error output:
2035 Example error output:
2018
2036
2019 .. code-block:: bash
2037 .. code-block:: bash
2020
2038
2021 id : <id_given_in_input>
2039 id : <id_given_in_input>
2022 result : null
2040 result : null
2023 error : {
2041 error : {
2024 "Unable to execute maintenance on `<reponame>`"
2042 "Unable to execute maintenance on `<reponame>`"
2025 }
2043 }
2026
2044
2027 """
2045 """
2028
2046
2029 repo = get_repo_or_error(repoid)
2047 repo = get_repo_or_error(repoid)
2030 if not has_superadmin_permission(apiuser):
2048 if not has_superadmin_permission(apiuser):
2031 _perms = ('repository.admin',)
2049 _perms = ('repository.admin',)
2032 validate_repo_permissions(apiuser, repoid, repo, _perms)
2050 validate_repo_permissions(apiuser, repoid, repo, _perms)
2033
2051
2034 try:
2052 try:
2035 maintenance = repo_maintenance.RepoMaintenance()
2053 maintenance = repo_maintenance.RepoMaintenance()
2036 executed_actions = maintenance.execute(repo)
2054 executed_actions = maintenance.execute(repo)
2037
2055
2038 return {
2056 return {
2039 'msg': 'executed maintenance command',
2057 'msg': 'executed maintenance command',
2040 'executed_actions': executed_actions,
2058 'executed_actions': executed_actions,
2041 'repository': repo.repo_name
2059 'repository': repo.repo_name
2042 }
2060 }
2043 except Exception:
2061 except Exception:
2044 log.exception("Exception occurred while trying to run maintenance")
2062 log.exception("Exception occurred while trying to run maintenance")
2045 raise JSONRPCError(
2063 raise JSONRPCError(
2046 'Unable to execute maintenance on `%s`' % repo.repo_name)
2064 'Unable to execute maintenance on `%s`' % repo.repo_name)
@@ -1,829 +1,895 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2018 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.api import (
23 from rhodecode.api import (
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
25 from rhodecode.api.utils import (
25 from rhodecode.api.utils import (
26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
30 from rhodecode.lib.exceptions import UserGroupAssignedException
30 from rhodecode.lib.exceptions import UserGroupAssignedException
31 from rhodecode.model.db import Session
31 from rhodecode.model.db import Session
32 from rhodecode.model.scm import UserGroupList
32 from rhodecode.model.scm import UserGroupList
33 from rhodecode.model.user_group import UserGroupModel
33 from rhodecode.model.user_group import UserGroupModel
34 from rhodecode.model import validation_schema
34 from rhodecode.model import validation_schema
35 from rhodecode.model.validation_schema.schemas import user_group_schema
35 from rhodecode.model.validation_schema.schemas import user_group_schema
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 @jsonrpc_method()
40 @jsonrpc_method()
41 def get_user_group(request, apiuser, usergroupid):
41 def get_user_group(request, apiuser, usergroupid):
42 """
42 """
43 Returns the data of an existing user group.
43 Returns the data of an existing user group.
44
44
45 This command can only be run using an |authtoken| with admin rights to
45 This command can only be run using an |authtoken| with admin rights to
46 the specified repository.
46 the specified repository.
47
47
48 :param apiuser: This is filled automatically from the |authtoken|.
48 :param apiuser: This is filled automatically from the |authtoken|.
49 :type apiuser: AuthUser
49 :type apiuser: AuthUser
50 :param usergroupid: Set the user group from which to return data.
50 :param usergroupid: Set the user group from which to return data.
51 :type usergroupid: str or int
51 :type usergroupid: str or int
52
52
53 Example error output:
53 Example error output:
54
54
55 .. code-block:: bash
55 .. code-block:: bash
56
56
57 {
57 {
58 "error": null,
58 "error": null,
59 "id": <id>,
59 "id": <id>,
60 "result": {
60 "result": {
61 "active": true,
61 "active": true,
62 "group_description": "group description",
62 "group_description": "group description",
63 "group_name": "group name",
63 "group_name": "group name",
64 "permissions": [
64 "permissions": [
65 {
65 {
66 "name": "owner-name",
66 "name": "owner-name",
67 "origin": "owner",
67 "origin": "owner",
68 "permission": "usergroup.admin",
68 "permission": "usergroup.admin",
69 "type": "user"
69 "type": "user"
70 },
70 },
71 {
71 {
72 {
72 {
73 "name": "user name",
73 "name": "user name",
74 "origin": "permission",
74 "origin": "permission",
75 "permission": "usergroup.admin",
75 "permission": "usergroup.admin",
76 "type": "user"
76 "type": "user"
77 },
77 },
78 {
78 {
79 "name": "user group name",
79 "name": "user group name",
80 "origin": "permission",
80 "origin": "permission",
81 "permission": "usergroup.write",
81 "permission": "usergroup.write",
82 "type": "user_group"
82 "type": "user_group"
83 }
83 }
84 ],
84 ],
85 "permissions_summary": {
85 "permissions_summary": {
86 "repositories": {
86 "repositories": {
87 "aa-root-level-repo-1": "repository.admin"
87 "aa-root-level-repo-1": "repository.admin"
88 },
88 },
89 "repositories_groups": {}
89 "repositories_groups": {}
90 },
90 },
91 "owner": "owner name",
91 "owner": "owner name",
92 "users": [],
92 "users": [],
93 "users_group_id": 2
93 "users_group_id": 2
94 }
94 }
95 }
95 }
96
96
97 """
97 """
98
98
99 user_group = get_user_group_or_error(usergroupid)
99 user_group = get_user_group_or_error(usergroupid)
100 if not has_superadmin_permission(apiuser):
100 if not has_superadmin_permission(apiuser):
101 # check if we have at least read permission for this user group !
101 # check if we have at least read permission for this user group !
102 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
102 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
103 if not HasUserGroupPermissionAnyApi(*_perms)(
103 if not HasUserGroupPermissionAnyApi(*_perms)(
104 user=apiuser, user_group_name=user_group.users_group_name):
104 user=apiuser, user_group_name=user_group.users_group_name):
105 raise JSONRPCError('user group `%s` does not exist' % (
105 raise JSONRPCError('user group `%s` does not exist' % (
106 usergroupid,))
106 usergroupid,))
107
107
108 permissions = []
108 permissions = []
109 for _user in user_group.permissions():
109 for _user in user_group.permissions():
110 user_data = {
110 user_data = {
111 'name': _user.username,
111 'name': _user.username,
112 'permission': _user.permission,
112 'permission': _user.permission,
113 'origin': get_origin(_user),
113 'origin': get_origin(_user),
114 'type': "user",
114 'type': "user",
115 }
115 }
116 permissions.append(user_data)
116 permissions.append(user_data)
117
117
118 for _user_group in user_group.permission_user_groups():
118 for _user_group in user_group.permission_user_groups():
119 user_group_data = {
119 user_group_data = {
120 'name': _user_group.users_group_name,
120 'name': _user_group.users_group_name,
121 'permission': _user_group.permission,
121 'permission': _user_group.permission,
122 'origin': get_origin(_user_group),
122 'origin': get_origin(_user_group),
123 'type': "user_group",
123 'type': "user_group",
124 }
124 }
125 permissions.append(user_group_data)
125 permissions.append(user_group_data)
126
126
127 data = user_group.get_api_data()
127 data = user_group.get_api_data()
128 data["permissions"] = permissions
128 data["permissions"] = permissions
129 data["permissions_summary"] = UserGroupModel().get_perms_summary(
129 data["permissions_summary"] = UserGroupModel().get_perms_summary(
130 user_group.users_group_id)
130 user_group.users_group_id)
131 return data
131 return data
132
132
133
133
134 @jsonrpc_method()
134 @jsonrpc_method()
135 def get_user_groups(request, apiuser):
135 def get_user_groups(request, apiuser):
136 """
136 """
137 Lists all the existing user groups within RhodeCode.
137 Lists all the existing user groups within RhodeCode.
138
138
139 This command can only be run using an |authtoken| with admin rights to
139 This command can only be run using an |authtoken| with admin rights to
140 the specified repository.
140 the specified repository.
141
141
142 This command takes the following options:
142 This command takes the following options:
143
143
144 :param apiuser: This is filled automatically from the |authtoken|.
144 :param apiuser: This is filled automatically from the |authtoken|.
145 :type apiuser: AuthUser
145 :type apiuser: AuthUser
146
146
147 Example error output:
147 Example error output:
148
148
149 .. code-block:: bash
149 .. code-block:: bash
150
150
151 id : <id_given_in_input>
151 id : <id_given_in_input>
152 result : [<user_group_obj>,...]
152 result : [<user_group_obj>,...]
153 error : null
153 error : null
154 """
154 """
155
155
156 include_secrets = has_superadmin_permission(apiuser)
156 include_secrets = has_superadmin_permission(apiuser)
157
157
158 result = []
158 result = []
159 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
159 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
160 extras = {'user': apiuser}
160 extras = {'user': apiuser}
161 for user_group in UserGroupList(UserGroupModel().get_all(),
161 for user_group in UserGroupList(UserGroupModel().get_all(),
162 perm_set=_perms, extra_kwargs=extras):
162 perm_set=_perms, extra_kwargs=extras):
163 result.append(
163 result.append(
164 user_group.get_api_data(include_secrets=include_secrets))
164 user_group.get_api_data(include_secrets=include_secrets))
165 return result
165 return result
166
166
167
167
168 @jsonrpc_method()
168 @jsonrpc_method()
169 def create_user_group(
169 def create_user_group(
170 request, apiuser, group_name, description=Optional(''),
170 request, apiuser, group_name, description=Optional(''),
171 owner=Optional(OAttr('apiuser')), active=Optional(True)):
171 owner=Optional(OAttr('apiuser')), active=Optional(True),
172 sync=Optional(None)):
172 """
173 """
173 Creates a new user group.
174 Creates a new user group.
174
175
175 This command can only be run using an |authtoken| with admin rights to
176 This command can only be run using an |authtoken| with admin rights to
176 the specified repository.
177 the specified repository.
177
178
178 This command takes the following options:
179 This command takes the following options:
179
180
180 :param apiuser: This is filled automatically from the |authtoken|.
181 :param apiuser: This is filled automatically from the |authtoken|.
181 :type apiuser: AuthUser
182 :type apiuser: AuthUser
182 :param group_name: Set the name of the new user group.
183 :param group_name: Set the name of the new user group.
183 :type group_name: str
184 :type group_name: str
184 :param description: Give a description of the new user group.
185 :param description: Give a description of the new user group.
185 :type description: str
186 :type description: str
186 :param owner: Set the owner of the new user group.
187 :param owner: Set the owner of the new user group.
187 If not set, the owner is the |authtoken| user.
188 If not set, the owner is the |authtoken| user.
188 :type owner: Optional(str or int)
189 :type owner: Optional(str or int)
189 :param active: Set this group as active.
190 :param active: Set this group as active.
190 :type active: Optional(``True`` | ``False``)
191 :type active: Optional(``True`` | ``False``)
192 :param sync: Set enabled or disabled the automatically sync from
193 external authentication types like ldap.
194 :type sync: Optional(``True`` | ``False``)
191
195
192 Example output:
196 Example output:
193
197
194 .. code-block:: bash
198 .. code-block:: bash
195
199
196 id : <id_given_in_input>
200 id : <id_given_in_input>
197 result: {
201 result: {
198 "msg": "created new user group `<groupname>`",
202 "msg": "created new user group `<groupname>`",
199 "user_group": <user_group_object>
203 "user_group": <user_group_object>
200 }
204 }
201 error: null
205 error: null
202
206
203 Example error output:
207 Example error output:
204
208
205 .. code-block:: bash
209 .. code-block:: bash
206
210
207 id : <id_given_in_input>
211 id : <id_given_in_input>
208 result : null
212 result : null
209 error : {
213 error : {
210 "user group `<group name>` already exist"
214 "user group `<group name>` already exist"
211 or
215 or
212 "failed to create group `<group name>`"
216 "failed to create group `<group name>`"
213 }
217 }
214
218
215 """
219 """
216
220
217 if not has_superadmin_permission(apiuser):
221 if not has_superadmin_permission(apiuser):
218 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
222 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
219 raise JSONRPCForbidden()
223 raise JSONRPCForbidden()
220
224
221 if UserGroupModel().get_by_name(group_name):
225 if UserGroupModel().get_by_name(group_name):
222 raise JSONRPCError("user group `%s` already exist" % (group_name,))
226 raise JSONRPCError("user group `%s` already exist" % (group_name,))
223
227
224 if isinstance(owner, Optional):
228 if isinstance(owner, Optional):
225 owner = apiuser.user_id
229 owner = apiuser.user_id
226
230
227 owner = get_user_or_error(owner)
231 owner = get_user_or_error(owner)
228 active = Optional.extract(active)
232 active = Optional.extract(active)
229 description = Optional.extract(description)
233 description = Optional.extract(description)
234 sync = Optional.extract(sync)
235
236 # set the sync option based on group_data
237 group_data = None
238 if sync:
239 group_data = {
240 'extern_type': 'manual_api',
241 'extern_type_set_by': apiuser.username
242 }
230
243
231 schema = user_group_schema.UserGroupSchema().bind(
244 schema = user_group_schema.UserGroupSchema().bind(
232 # user caller
245 # user caller
233 user=apiuser)
246 user=apiuser)
234 try:
247 try:
235 schema_data = schema.deserialize(dict(
248 schema_data = schema.deserialize(dict(
236 user_group_name=group_name,
249 user_group_name=group_name,
237 user_group_description=description,
250 user_group_description=description,
238 user_group_owner=owner.username,
251 user_group_owner=owner.username,
239 user_group_active=active,
252 user_group_active=active,
240 ))
253 ))
241 except validation_schema.Invalid as err:
254 except validation_schema.Invalid as err:
242 raise JSONRPCValidationError(colander_exc=err)
255 raise JSONRPCValidationError(colander_exc=err)
243
256
244 try:
257 try:
245 user_group = UserGroupModel().create(
258 user_group = UserGroupModel().create(
246 name=schema_data['user_group_name'],
259 name=schema_data['user_group_name'],
247 description=schema_data['user_group_description'],
260 description=schema_data['user_group_description'],
248 owner=owner,
261 owner=owner,
249 active=schema_data['user_group_active'])
262 active=schema_data['user_group_active'], group_data=group_data)
250 Session().flush()
263 Session().flush()
251 creation_data = user_group.get_api_data()
264 creation_data = user_group.get_api_data()
252 audit_logger.store_api(
265 audit_logger.store_api(
253 'user_group.create', action_data={'data': creation_data},
266 'user_group.create', action_data={'data': creation_data},
254 user=apiuser)
267 user=apiuser)
255 Session().commit()
268 Session().commit()
256 return {
269 return {
257 'msg': 'created new user group `%s`' % group_name,
270 'msg': 'created new user group `%s`' % group_name,
258 'user_group': creation_data
271 'user_group': creation_data
259 }
272 }
260 except Exception:
273 except Exception:
261 log.exception("Error occurred during creation of user group")
274 log.exception("Error occurred during creation of user group")
262 raise JSONRPCError('failed to create group `%s`' % (group_name,))
275 raise JSONRPCError('failed to create group `%s`' % (group_name,))
263
276
264
277
265 @jsonrpc_method()
278 @jsonrpc_method()
266 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
279 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
267 description=Optional(''), owner=Optional(None),
280 description=Optional(''), owner=Optional(None),
268 active=Optional(True)):
281 active=Optional(True), sync=Optional(None)):
269 """
282 """
270 Updates the specified `user group` with the details provided.
283 Updates the specified `user group` with the details provided.
271
284
272 This command can only be run using an |authtoken| with admin rights to
285 This command can only be run using an |authtoken| with admin rights to
273 the specified repository.
286 the specified repository.
274
287
275 :param apiuser: This is filled automatically from the |authtoken|.
288 :param apiuser: This is filled automatically from the |authtoken|.
276 :type apiuser: AuthUser
289 :type apiuser: AuthUser
277 :param usergroupid: Set the id of the `user group` to update.
290 :param usergroupid: Set the id of the `user group` to update.
278 :type usergroupid: str or int
291 :type usergroupid: str or int
279 :param group_name: Set the new name the `user group`
292 :param group_name: Set the new name the `user group`
280 :type group_name: str
293 :type group_name: str
281 :param description: Give a description for the `user group`
294 :param description: Give a description for the `user group`
282 :type description: str
295 :type description: str
283 :param owner: Set the owner of the `user group`.
296 :param owner: Set the owner of the `user group`.
284 :type owner: Optional(str or int)
297 :type owner: Optional(str or int)
285 :param active: Set the group as active.
298 :param active: Set the group as active.
286 :type active: Optional(``True`` | ``False``)
299 :type active: Optional(``True`` | ``False``)
300 :param sync: Set enabled or disabled the automatically sync from
301 external authentication types like ldap.
302 :type sync: Optional(``True`` | ``False``)
287
303
288 Example output:
304 Example output:
289
305
290 .. code-block:: bash
306 .. code-block:: bash
291
307
292 id : <id_given_in_input>
308 id : <id_given_in_input>
293 result : {
309 result : {
294 "msg": 'updated user group ID:<user group id> <user group name>',
310 "msg": 'updated user group ID:<user group id> <user group name>',
295 "user_group": <user_group_object>
311 "user_group": <user_group_object>
296 }
312 }
297 error : null
313 error : null
298
314
299 Example error output:
315 Example error output:
300
316
301 .. code-block:: bash
317 .. code-block:: bash
302
318
303 id : <id_given_in_input>
319 id : <id_given_in_input>
304 result : null
320 result : null
305 error : {
321 error : {
306 "failed to update user group `<user group name>`"
322 "failed to update user group `<user group name>`"
307 }
323 }
308
324
309 """
325 """
310
326
311 user_group = get_user_group_or_error(usergroupid)
327 user_group = get_user_group_or_error(usergroupid)
312 include_secrets = False
328 include_secrets = False
313 if not has_superadmin_permission(apiuser):
329 if not has_superadmin_permission(apiuser):
314 # check if we have admin permission for this user group !
330 # check if we have admin permission for this user group !
315 _perms = ('usergroup.admin',)
331 _perms = ('usergroup.admin',)
316 if not HasUserGroupPermissionAnyApi(*_perms)(
332 if not HasUserGroupPermissionAnyApi(*_perms)(
317 user=apiuser, user_group_name=user_group.users_group_name):
333 user=apiuser, user_group_name=user_group.users_group_name):
318 raise JSONRPCError(
334 raise JSONRPCError(
319 'user group `%s` does not exist' % (usergroupid,))
335 'user group `%s` does not exist' % (usergroupid,))
320 else:
336 else:
321 include_secrets = True
337 include_secrets = True
322
338
323 if not isinstance(owner, Optional):
339 if not isinstance(owner, Optional):
324 owner = get_user_or_error(owner)
340 owner = get_user_or_error(owner)
325
341
326 old_data = user_group.get_api_data()
342 old_data = user_group.get_api_data()
327 updates = {}
343 updates = {}
328 store_update(updates, group_name, 'users_group_name')
344 store_update(updates, group_name, 'users_group_name')
329 store_update(updates, description, 'user_group_description')
345 store_update(updates, description, 'user_group_description')
330 store_update(updates, owner, 'user')
346 store_update(updates, owner, 'user')
331 store_update(updates, active, 'users_group_active')
347 store_update(updates, active, 'users_group_active')
348
349 sync = Optional.extract(sync)
350 group_data = None
351 if sync is True:
352 group_data = {
353 'extern_type': 'manual_api',
354 'extern_type_set_by': apiuser.username
355 }
356 if sync is False:
357 group_data = user_group.group_data
358 if group_data and "extern_type" in group_data:
359 del group_data["extern_type"]
360
332 try:
361 try:
333 UserGroupModel().update(user_group, updates)
362 UserGroupModel().update(user_group, updates, group_data=group_data)
334 audit_logger.store_api(
363 audit_logger.store_api(
335 'user_group.edit', action_data={'old_data': old_data},
364 'user_group.edit', action_data={'old_data': old_data},
336 user=apiuser)
365 user=apiuser)
337 Session().commit()
366 Session().commit()
338 return {
367 return {
339 'msg': 'updated user group ID:%s %s' % (
368 'msg': 'updated user group ID:%s %s' % (
340 user_group.users_group_id, user_group.users_group_name),
369 user_group.users_group_id, user_group.users_group_name),
341 'user_group': user_group.get_api_data(
370 'user_group': user_group.get_api_data(
342 include_secrets=include_secrets)
371 include_secrets=include_secrets)
343 }
372 }
344 except Exception:
373 except Exception:
345 log.exception("Error occurred during update of user group")
374 log.exception("Error occurred during update of user group")
346 raise JSONRPCError(
375 raise JSONRPCError(
347 'failed to update user group `%s`' % (usergroupid,))
376 'failed to update user group `%s`' % (usergroupid,))
348
377
349
378
350 @jsonrpc_method()
379 @jsonrpc_method()
351 def delete_user_group(request, apiuser, usergroupid):
380 def delete_user_group(request, apiuser, usergroupid):
352 """
381 """
353 Deletes the specified `user group`.
382 Deletes the specified `user group`.
354
383
355 This command can only be run using an |authtoken| with admin rights to
384 This command can only be run using an |authtoken| with admin rights to
356 the specified repository.
385 the specified repository.
357
386
358 This command takes the following options:
387 This command takes the following options:
359
388
360 :param apiuser: filled automatically from apikey
389 :param apiuser: filled automatically from apikey
361 :type apiuser: AuthUser
390 :type apiuser: AuthUser
362 :param usergroupid:
391 :param usergroupid:
363 :type usergroupid: int
392 :type usergroupid: int
364
393
365 Example output:
394 Example output:
366
395
367 .. code-block:: bash
396 .. code-block:: bash
368
397
369 id : <id_given_in_input>
398 id : <id_given_in_input>
370 result : {
399 result : {
371 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
400 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
372 }
401 }
373 error : null
402 error : null
374
403
375 Example error output:
404 Example error output:
376
405
377 .. code-block:: bash
406 .. code-block:: bash
378
407
379 id : <id_given_in_input>
408 id : <id_given_in_input>
380 result : null
409 result : null
381 error : {
410 error : {
382 "failed to delete user group ID:<user_group_id> <user_group_name>"
411 "failed to delete user group ID:<user_group_id> <user_group_name>"
383 or
412 or
384 "RepoGroup assigned to <repo_groups_list>"
413 "RepoGroup assigned to <repo_groups_list>"
385 }
414 }
386
415
387 """
416 """
388
417
389 user_group = get_user_group_or_error(usergroupid)
418 user_group = get_user_group_or_error(usergroupid)
390 if not has_superadmin_permission(apiuser):
419 if not has_superadmin_permission(apiuser):
391 # check if we have admin permission for this user group !
420 # check if we have admin permission for this user group !
392 _perms = ('usergroup.admin',)
421 _perms = ('usergroup.admin',)
393 if not HasUserGroupPermissionAnyApi(*_perms)(
422 if not HasUserGroupPermissionAnyApi(*_perms)(
394 user=apiuser, user_group_name=user_group.users_group_name):
423 user=apiuser, user_group_name=user_group.users_group_name):
395 raise JSONRPCError(
424 raise JSONRPCError(
396 'user group `%s` does not exist' % (usergroupid,))
425 'user group `%s` does not exist' % (usergroupid,))
397
426
398 old_data = user_group.get_api_data()
427 old_data = user_group.get_api_data()
399 try:
428 try:
400 UserGroupModel().delete(user_group)
429 UserGroupModel().delete(user_group)
401 audit_logger.store_api(
430 audit_logger.store_api(
402 'user_group.delete', action_data={'old_data': old_data},
431 'user_group.delete', action_data={'old_data': old_data},
403 user=apiuser)
432 user=apiuser)
404 Session().commit()
433 Session().commit()
405 return {
434 return {
406 'msg': 'deleted user group ID:%s %s' % (
435 'msg': 'deleted user group ID:%s %s' % (
407 user_group.users_group_id, user_group.users_group_name),
436 user_group.users_group_id, user_group.users_group_name),
408 'user_group': None
437 'user_group': None
409 }
438 }
410 except UserGroupAssignedException as e:
439 except UserGroupAssignedException as e:
411 log.exception("UserGroupAssigned error")
440 log.exception("UserGroupAssigned error")
412 raise JSONRPCError(str(e))
441 raise JSONRPCError(str(e))
413 except Exception:
442 except Exception:
414 log.exception("Error occurred during deletion of user group")
443 log.exception("Error occurred during deletion of user group")
415 raise JSONRPCError(
444 raise JSONRPCError(
416 'failed to delete user group ID:%s %s' %(
445 'failed to delete user group ID:%s %s' %(
417 user_group.users_group_id, user_group.users_group_name))
446 user_group.users_group_id, user_group.users_group_name))
418
447
419
448
420 @jsonrpc_method()
449 @jsonrpc_method()
421 def add_user_to_user_group(request, apiuser, usergroupid, userid):
450 def add_user_to_user_group(request, apiuser, usergroupid, userid):
422 """
451 """
423 Adds a user to a `user group`. If the user already exists in the group
452 Adds a user to a `user group`. If the user already exists in the group
424 this command will return false.
453 this command will return false.
425
454
426 This command can only be run using an |authtoken| with admin rights to
455 This command can only be run using an |authtoken| with admin rights to
427 the specified user group.
456 the specified user group.
428
457
429 This command takes the following options:
458 This command takes the following options:
430
459
431 :param apiuser: This is filled automatically from the |authtoken|.
460 :param apiuser: This is filled automatically from the |authtoken|.
432 :type apiuser: AuthUser
461 :type apiuser: AuthUser
433 :param usergroupid: Set the name of the `user group` to which a
462 :param usergroupid: Set the name of the `user group` to which a
434 user will be added.
463 user will be added.
435 :type usergroupid: int
464 :type usergroupid: int
436 :param userid: Set the `user_id` of the user to add to the group.
465 :param userid: Set the `user_id` of the user to add to the group.
437 :type userid: int
466 :type userid: int
438
467
439 Example output:
468 Example output:
440
469
441 .. code-block:: bash
470 .. code-block:: bash
442
471
443 id : <id_given_in_input>
472 id : <id_given_in_input>
444 result : {
473 result : {
445 "success": True|False # depends on if member is in group
474 "success": True|False # depends on if member is in group
446 "msg": "added member `<username>` to user group `<groupname>` |
475 "msg": "added member `<username>` to user group `<groupname>` |
447 User is already in that group"
476 User is already in that group"
448
477
449 }
478 }
450 error : null
479 error : null
451
480
452 Example error output:
481 Example error output:
453
482
454 .. code-block:: bash
483 .. code-block:: bash
455
484
456 id : <id_given_in_input>
485 id : <id_given_in_input>
457 result : null
486 result : null
458 error : {
487 error : {
459 "failed to add member to user group `<user_group_name>`"
488 "failed to add member to user group `<user_group_name>`"
460 }
489 }
461
490
462 """
491 """
463
492
464 user = get_user_or_error(userid)
493 user = get_user_or_error(userid)
465 user_group = get_user_group_or_error(usergroupid)
494 user_group = get_user_group_or_error(usergroupid)
466 if not has_superadmin_permission(apiuser):
495 if not has_superadmin_permission(apiuser):
467 # check if we have admin permission for this user group !
496 # check if we have admin permission for this user group !
468 _perms = ('usergroup.admin',)
497 _perms = ('usergroup.admin',)
469 if not HasUserGroupPermissionAnyApi(*_perms)(
498 if not HasUserGroupPermissionAnyApi(*_perms)(
470 user=apiuser, user_group_name=user_group.users_group_name):
499 user=apiuser, user_group_name=user_group.users_group_name):
471 raise JSONRPCError('user group `%s` does not exist' % (
500 raise JSONRPCError('user group `%s` does not exist' % (
472 usergroupid,))
501 usergroupid,))
473
502
474 old_values = user_group.get_api_data()
503 old_values = user_group.get_api_data()
475 try:
504 try:
476 ugm = UserGroupModel().add_user_to_group(user_group, user)
505 ugm = UserGroupModel().add_user_to_group(user_group, user)
477 success = True if ugm is not True else False
506 success = True if ugm is not True else False
478 msg = 'added member `%s` to user group `%s`' % (
507 msg = 'added member `%s` to user group `%s`' % (
479 user.username, user_group.users_group_name
508 user.username, user_group.users_group_name
480 )
509 )
481 msg = msg if success else 'User is already in that group'
510 msg = msg if success else 'User is already in that group'
482 if success:
511 if success:
483 user_data = user.get_api_data()
512 user_data = user.get_api_data()
484 audit_logger.store_api(
513 audit_logger.store_api(
485 'user_group.edit.member.add',
514 'user_group.edit.member.add',
486 action_data={'user': user_data, 'old_data': old_values},
515 action_data={'user': user_data, 'old_data': old_values},
487 user=apiuser)
516 user=apiuser)
488
517
489 Session().commit()
518 Session().commit()
490
519
491 return {
520 return {
492 'success': success,
521 'success': success,
493 'msg': msg
522 'msg': msg
494 }
523 }
495 except Exception:
524 except Exception:
496 log.exception("Error occurred during adding a member to user group")
525 log.exception("Error occurred during adding a member to user group")
497 raise JSONRPCError(
526 raise JSONRPCError(
498 'failed to add member to user group `%s`' % (
527 'failed to add member to user group `%s`' % (
499 user_group.users_group_name,
528 user_group.users_group_name,
500 )
529 )
501 )
530 )
502
531
503
532
504 @jsonrpc_method()
533 @jsonrpc_method()
505 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
534 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
506 """
535 """
507 Removes a user from a user group.
536 Removes a user from a user group.
508
537
509 * If the specified user is not in the group, this command will return
538 * If the specified user is not in the group, this command will return
510 `false`.
539 `false`.
511
540
512 This command can only be run using an |authtoken| with admin rights to
541 This command can only be run using an |authtoken| with admin rights to
513 the specified user group.
542 the specified user group.
514
543
515 :param apiuser: This is filled automatically from the |authtoken|.
544 :param apiuser: This is filled automatically from the |authtoken|.
516 :type apiuser: AuthUser
545 :type apiuser: AuthUser
517 :param usergroupid: Sets the user group name.
546 :param usergroupid: Sets the user group name.
518 :type usergroupid: str or int
547 :type usergroupid: str or int
519 :param userid: The user you wish to remove from |RCE|.
548 :param userid: The user you wish to remove from |RCE|.
520 :type userid: str or int
549 :type userid: str or int
521
550
522 Example output:
551 Example output:
523
552
524 .. code-block:: bash
553 .. code-block:: bash
525
554
526 id : <id_given_in_input>
555 id : <id_given_in_input>
527 result: {
556 result: {
528 "success": True|False, # depends on if member is in group
557 "success": True|False, # depends on if member is in group
529 "msg": "removed member <username> from user group <groupname> |
558 "msg": "removed member <username> from user group <groupname> |
530 User wasn't in group"
559 User wasn't in group"
531 }
560 }
532 error: null
561 error: null
533
562
534 """
563 """
535
564
536 user = get_user_or_error(userid)
565 user = get_user_or_error(userid)
537 user_group = get_user_group_or_error(usergroupid)
566 user_group = get_user_group_or_error(usergroupid)
538 if not has_superadmin_permission(apiuser):
567 if not has_superadmin_permission(apiuser):
539 # check if we have admin permission for this user group !
568 # check if we have admin permission for this user group !
540 _perms = ('usergroup.admin',)
569 _perms = ('usergroup.admin',)
541 if not HasUserGroupPermissionAnyApi(*_perms)(
570 if not HasUserGroupPermissionAnyApi(*_perms)(
542 user=apiuser, user_group_name=user_group.users_group_name):
571 user=apiuser, user_group_name=user_group.users_group_name):
543 raise JSONRPCError(
572 raise JSONRPCError(
544 'user group `%s` does not exist' % (usergroupid,))
573 'user group `%s` does not exist' % (usergroupid,))
545
574
546 old_values = user_group.get_api_data()
575 old_values = user_group.get_api_data()
547 try:
576 try:
548 success = UserGroupModel().remove_user_from_group(user_group, user)
577 success = UserGroupModel().remove_user_from_group(user_group, user)
549 msg = 'removed member `%s` from user group `%s`' % (
578 msg = 'removed member `%s` from user group `%s`' % (
550 user.username, user_group.users_group_name
579 user.username, user_group.users_group_name
551 )
580 )
552 msg = msg if success else "User wasn't in group"
581 msg = msg if success else "User wasn't in group"
553 if success:
582 if success:
554 user_data = user.get_api_data()
583 user_data = user.get_api_data()
555 audit_logger.store_api(
584 audit_logger.store_api(
556 'user_group.edit.member.delete',
585 'user_group.edit.member.delete',
557 action_data={'user': user_data, 'old_data': old_values},
586 action_data={'user': user_data, 'old_data': old_values},
558 user=apiuser)
587 user=apiuser)
559
588
560 Session().commit()
589 Session().commit()
561 return {'success': success, 'msg': msg}
590 return {'success': success, 'msg': msg}
562 except Exception:
591 except Exception:
563 log.exception("Error occurred during removing an member from user group")
592 log.exception("Error occurred during removing an member from user group")
564 raise JSONRPCError(
593 raise JSONRPCError(
565 'failed to remove member from user group `%s`' % (
594 'failed to remove member from user group `%s`' % (
566 user_group.users_group_name,
595 user_group.users_group_name,
567 )
596 )
568 )
597 )
569
598
570
599
571 @jsonrpc_method()
600 @jsonrpc_method()
572 def grant_user_permission_to_user_group(
601 def grant_user_permission_to_user_group(
573 request, apiuser, usergroupid, userid, perm):
602 request, apiuser, usergroupid, userid, perm):
574 """
603 """
575 Set permissions for a user in a user group.
604 Set permissions for a user in a user group.
576
605
577 :param apiuser: This is filled automatically from the |authtoken|.
606 :param apiuser: This is filled automatically from the |authtoken|.
578 :type apiuser: AuthUser
607 :type apiuser: AuthUser
579 :param usergroupid: Set the user group to edit permissions on.
608 :param usergroupid: Set the user group to edit permissions on.
580 :type usergroupid: str or int
609 :type usergroupid: str or int
581 :param userid: Set the user from whom you wish to set permissions.
610 :param userid: Set the user from whom you wish to set permissions.
582 :type userid: str
611 :type userid: str
583 :param perm: (usergroup.(none|read|write|admin))
612 :param perm: (usergroup.(none|read|write|admin))
584 :type perm: str
613 :type perm: str
585
614
586 Example output:
615 Example output:
587
616
588 .. code-block:: bash
617 .. code-block:: bash
589
618
590 id : <id_given_in_input>
619 id : <id_given_in_input>
591 result : {
620 result : {
592 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
621 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
593 "success": true
622 "success": true
594 }
623 }
595 error : null
624 error : null
596 """
625 """
597
626
598 user_group = get_user_group_or_error(usergroupid)
627 user_group = get_user_group_or_error(usergroupid)
599
628
600 if not has_superadmin_permission(apiuser):
629 if not has_superadmin_permission(apiuser):
601 # check if we have admin permission for this user group !
630 # check if we have admin permission for this user group !
602 _perms = ('usergroup.admin',)
631 _perms = ('usergroup.admin',)
603 if not HasUserGroupPermissionAnyApi(*_perms)(
632 if not HasUserGroupPermissionAnyApi(*_perms)(
604 user=apiuser, user_group_name=user_group.users_group_name):
633 user=apiuser, user_group_name=user_group.users_group_name):
605 raise JSONRPCError(
634 raise JSONRPCError(
606 'user group `%s` does not exist' % (usergroupid,))
635 'user group `%s` does not exist' % (usergroupid,))
607
636
608 user = get_user_or_error(userid)
637 user = get_user_or_error(userid)
609 perm = get_perm_or_error(perm, prefix='usergroup.')
638 perm = get_perm_or_error(perm, prefix='usergroup.')
610
639
611 try:
640 try:
612 UserGroupModel().grant_user_permission(
641 changes = UserGroupModel().grant_user_permission(
613 user_group=user_group, user=user, perm=perm)
642 user_group=user_group, user=user, perm=perm)
643
644 action_data = {
645 'added': changes['added'],
646 'updated': changes['updated'],
647 'deleted': changes['deleted'],
648 }
649 audit_logger.store_api(
650 'user_group.edit.permissions', action_data=action_data,
651 user=apiuser)
652
614 Session().commit()
653 Session().commit()
615 return {
654 return {
616 'msg':
655 'msg':
617 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
656 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
618 perm.permission_name, user.username,
657 perm.permission_name, user.username,
619 user_group.users_group_name
658 user_group.users_group_name
620 ),
659 ),
621 'success': True
660 'success': True
622 }
661 }
623 except Exception:
662 except Exception:
624 log.exception("Error occurred during editing permissions "
663 log.exception("Error occurred during editing permissions "
625 "for user in user group")
664 "for user in user group")
626 raise JSONRPCError(
665 raise JSONRPCError(
627 'failed to edit permission for user: '
666 'failed to edit permission for user: '
628 '`%s` in user group: `%s`' % (
667 '`%s` in user group: `%s`' % (
629 userid, user_group.users_group_name))
668 userid, user_group.users_group_name))
630
669
631
670
632 @jsonrpc_method()
671 @jsonrpc_method()
633 def revoke_user_permission_from_user_group(
672 def revoke_user_permission_from_user_group(
634 request, apiuser, usergroupid, userid):
673 request, apiuser, usergroupid, userid):
635 """
674 """
636 Revoke a users permissions in a user group.
675 Revoke a users permissions in a user group.
637
676
638 :param apiuser: This is filled automatically from the |authtoken|.
677 :param apiuser: This is filled automatically from the |authtoken|.
639 :type apiuser: AuthUser
678 :type apiuser: AuthUser
640 :param usergroupid: Set the user group from which to revoke the user
679 :param usergroupid: Set the user group from which to revoke the user
641 permissions.
680 permissions.
642 :type: usergroupid: str or int
681 :type: usergroupid: str or int
643 :param userid: Set the userid of the user whose permissions will be
682 :param userid: Set the userid of the user whose permissions will be
644 revoked.
683 revoked.
645 :type userid: str
684 :type userid: str
646
685
647 Example output:
686 Example output:
648
687
649 .. code-block:: bash
688 .. code-block:: bash
650
689
651 id : <id_given_in_input>
690 id : <id_given_in_input>
652 result : {
691 result : {
653 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
692 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
654 "success": true
693 "success": true
655 }
694 }
656 error : null
695 error : null
657 """
696 """
658
697
659 user_group = get_user_group_or_error(usergroupid)
698 user_group = get_user_group_or_error(usergroupid)
660
699
661 if not has_superadmin_permission(apiuser):
700 if not has_superadmin_permission(apiuser):
662 # check if we have admin permission for this user group !
701 # check if we have admin permission for this user group !
663 _perms = ('usergroup.admin',)
702 _perms = ('usergroup.admin',)
664 if not HasUserGroupPermissionAnyApi(*_perms)(
703 if not HasUserGroupPermissionAnyApi(*_perms)(
665 user=apiuser, user_group_name=user_group.users_group_name):
704 user=apiuser, user_group_name=user_group.users_group_name):
666 raise JSONRPCError(
705 raise JSONRPCError(
667 'user group `%s` does not exist' % (usergroupid,))
706 'user group `%s` does not exist' % (usergroupid,))
668
707
669 user = get_user_or_error(userid)
708 user = get_user_or_error(userid)
670
709
671 try:
710 try:
672 UserGroupModel().revoke_user_permission(
711 changes = UserGroupModel().revoke_user_permission(
673 user_group=user_group, user=user)
712 user_group=user_group, user=user)
713 action_data = {
714 'added': changes['added'],
715 'updated': changes['updated'],
716 'deleted': changes['deleted'],
717 }
718 audit_logger.store_api(
719 'user_group.edit.permissions', action_data=action_data,
720 user=apiuser)
721
674 Session().commit()
722 Session().commit()
675 return {
723 return {
676 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
724 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
677 user.username, user_group.users_group_name
725 user.username, user_group.users_group_name
678 ),
726 ),
679 'success': True
727 'success': True
680 }
728 }
681 except Exception:
729 except Exception:
682 log.exception("Error occurred during editing permissions "
730 log.exception("Error occurred during editing permissions "
683 "for user in user group")
731 "for user in user group")
684 raise JSONRPCError(
732 raise JSONRPCError(
685 'failed to edit permission for user: `%s` in user group: `%s`'
733 'failed to edit permission for user: `%s` in user group: `%s`'
686 % (userid, user_group.users_group_name))
734 % (userid, user_group.users_group_name))
687
735
688
736
689 @jsonrpc_method()
737 @jsonrpc_method()
690 def grant_user_group_permission_to_user_group(
738 def grant_user_group_permission_to_user_group(
691 request, apiuser, usergroupid, sourceusergroupid, perm):
739 request, apiuser, usergroupid, sourceusergroupid, perm):
692 """
740 """
693 Give one user group permissions to another user group.
741 Give one user group permissions to another user group.
694
742
695 :param apiuser: This is filled automatically from the |authtoken|.
743 :param apiuser: This is filled automatically from the |authtoken|.
696 :type apiuser: AuthUser
744 :type apiuser: AuthUser
697 :param usergroupid: Set the user group on which to edit permissions.
745 :param usergroupid: Set the user group on which to edit permissions.
698 :type usergroupid: str or int
746 :type usergroupid: str or int
699 :param sourceusergroupid: Set the source user group to which
747 :param sourceusergroupid: Set the source user group to which
700 access/permissions will be granted.
748 access/permissions will be granted.
701 :type sourceusergroupid: str or int
749 :type sourceusergroupid: str or int
702 :param perm: (usergroup.(none|read|write|admin))
750 :param perm: (usergroup.(none|read|write|admin))
703 :type perm: str
751 :type perm: str
704
752
705 Example output:
753 Example output:
706
754
707 .. code-block:: bash
755 .. code-block:: bash
708
756
709 id : <id_given_in_input>
757 id : <id_given_in_input>
710 result : {
758 result : {
711 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
759 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
712 "success": true
760 "success": true
713 }
761 }
714 error : null
762 error : null
715 """
763 """
716
764
717 user_group = get_user_group_or_error(sourceusergroupid)
765 user_group = get_user_group_or_error(sourceusergroupid)
718 target_user_group = get_user_group_or_error(usergroupid)
766 target_user_group = get_user_group_or_error(usergroupid)
719 perm = get_perm_or_error(perm, prefix='usergroup.')
767 perm = get_perm_or_error(perm, prefix='usergroup.')
720
768
721 if not has_superadmin_permission(apiuser):
769 if not has_superadmin_permission(apiuser):
722 # check if we have admin permission for this user group !
770 # check if we have admin permission for this user group !
723 _perms = ('usergroup.admin',)
771 _perms = ('usergroup.admin',)
724 if not HasUserGroupPermissionAnyApi(*_perms)(
772 if not HasUserGroupPermissionAnyApi(*_perms)(
725 user=apiuser,
773 user=apiuser,
726 user_group_name=target_user_group.users_group_name):
774 user_group_name=target_user_group.users_group_name):
727 raise JSONRPCError(
775 raise JSONRPCError(
728 'to user group `%s` does not exist' % (usergroupid,))
776 'to user group `%s` does not exist' % (usergroupid,))
729
777
730 # check if we have at least read permission for source user group !
778 # check if we have at least read permission for source user group !
731 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
779 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
732 if not HasUserGroupPermissionAnyApi(*_perms)(
780 if not HasUserGroupPermissionAnyApi(*_perms)(
733 user=apiuser, user_group_name=user_group.users_group_name):
781 user=apiuser, user_group_name=user_group.users_group_name):
734 raise JSONRPCError(
782 raise JSONRPCError(
735 'user group `%s` does not exist' % (sourceusergroupid,))
783 'user group `%s` does not exist' % (sourceusergroupid,))
736
784
737 try:
785 try:
738 UserGroupModel().grant_user_group_permission(
786 changes = UserGroupModel().grant_user_group_permission(
739 target_user_group=target_user_group,
787 target_user_group=target_user_group,
740 user_group=user_group, perm=perm)
788 user_group=user_group, perm=perm)
789
790 action_data = {
791 'added': changes['added'],
792 'updated': changes['updated'],
793 'deleted': changes['deleted'],
794 }
795 audit_logger.store_api(
796 'user_group.edit.permissions', action_data=action_data,
797 user=apiuser)
798
741 Session().commit()
799 Session().commit()
742
743 return {
800 return {
744 'msg': 'Granted perm: `%s` for user group: `%s` '
801 'msg': 'Granted perm: `%s` for user group: `%s` '
745 'in user group: `%s`' % (
802 'in user group: `%s`' % (
746 perm.permission_name, user_group.users_group_name,
803 perm.permission_name, user_group.users_group_name,
747 target_user_group.users_group_name
804 target_user_group.users_group_name
748 ),
805 ),
749 'success': True
806 'success': True
750 }
807 }
751 except Exception:
808 except Exception:
752 log.exception("Error occurred during editing permissions "
809 log.exception("Error occurred during editing permissions "
753 "for user group in user group")
810 "for user group in user group")
754 raise JSONRPCError(
811 raise JSONRPCError(
755 'failed to edit permission for user group: `%s` in '
812 'failed to edit permission for user group: `%s` in '
756 'user group: `%s`' % (
813 'user group: `%s`' % (
757 sourceusergroupid, target_user_group.users_group_name
814 sourceusergroupid, target_user_group.users_group_name
758 )
815 )
759 )
816 )
760
817
761
818
762 @jsonrpc_method()
819 @jsonrpc_method()
763 def revoke_user_group_permission_from_user_group(
820 def revoke_user_group_permission_from_user_group(
764 request, apiuser, usergroupid, sourceusergroupid):
821 request, apiuser, usergroupid, sourceusergroupid):
765 """
822 """
766 Revoke the permissions that one user group has to another.
823 Revoke the permissions that one user group has to another.
767
824
768 :param apiuser: This is filled automatically from the |authtoken|.
825 :param apiuser: This is filled automatically from the |authtoken|.
769 :type apiuser: AuthUser
826 :type apiuser: AuthUser
770 :param usergroupid: Set the user group on which to edit permissions.
827 :param usergroupid: Set the user group on which to edit permissions.
771 :type usergroupid: str or int
828 :type usergroupid: str or int
772 :param sourceusergroupid: Set the user group from which permissions
829 :param sourceusergroupid: Set the user group from which permissions
773 are revoked.
830 are revoked.
774 :type sourceusergroupid: str or int
831 :type sourceusergroupid: str or int
775
832
776 Example output:
833 Example output:
777
834
778 .. code-block:: bash
835 .. code-block:: bash
779
836
780 id : <id_given_in_input>
837 id : <id_given_in_input>
781 result : {
838 result : {
782 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
839 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
783 "success": true
840 "success": true
784 }
841 }
785 error : null
842 error : null
786 """
843 """
787
844
788 user_group = get_user_group_or_error(sourceusergroupid)
845 user_group = get_user_group_or_error(sourceusergroupid)
789 target_user_group = get_user_group_or_error(usergroupid)
846 target_user_group = get_user_group_or_error(usergroupid)
790
847
791 if not has_superadmin_permission(apiuser):
848 if not has_superadmin_permission(apiuser):
792 # check if we have admin permission for this user group !
849 # check if we have admin permission for this user group !
793 _perms = ('usergroup.admin',)
850 _perms = ('usergroup.admin',)
794 if not HasUserGroupPermissionAnyApi(*_perms)(
851 if not HasUserGroupPermissionAnyApi(*_perms)(
795 user=apiuser,
852 user=apiuser,
796 user_group_name=target_user_group.users_group_name):
853 user_group_name=target_user_group.users_group_name):
797 raise JSONRPCError(
854 raise JSONRPCError(
798 'to user group `%s` does not exist' % (usergroupid,))
855 'to user group `%s` does not exist' % (usergroupid,))
799
856
800 # check if we have at least read permission
857 # check if we have at least read permission
801 # for the source user group !
858 # for the source user group !
802 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
859 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
803 if not HasUserGroupPermissionAnyApi(*_perms)(
860 if not HasUserGroupPermissionAnyApi(*_perms)(
804 user=apiuser, user_group_name=user_group.users_group_name):
861 user=apiuser, user_group_name=user_group.users_group_name):
805 raise JSONRPCError(
862 raise JSONRPCError(
806 'user group `%s` does not exist' % (sourceusergroupid,))
863 'user group `%s` does not exist' % (sourceusergroupid,))
807
864
808 try:
865 try:
809 UserGroupModel().revoke_user_group_permission(
866 changes = UserGroupModel().revoke_user_group_permission(
810 target_user_group=target_user_group, user_group=user_group)
867 target_user_group=target_user_group, user_group=user_group)
868 action_data = {
869 'added': changes['added'],
870 'updated': changes['updated'],
871 'deleted': changes['deleted'],
872 }
873 audit_logger.store_api(
874 'user_group.edit.permissions', action_data=action_data,
875 user=apiuser)
876
811 Session().commit()
877 Session().commit()
812
878
813 return {
879 return {
814 'msg': 'Revoked perm for user group: '
880 'msg': 'Revoked perm for user group: '
815 '`%s` in user group: `%s`' % (
881 '`%s` in user group: `%s`' % (
816 user_group.users_group_name,
882 user_group.users_group_name,
817 target_user_group.users_group_name
883 target_user_group.users_group_name
818 ),
884 ),
819 'success': True
885 'success': True
820 }
886 }
821 except Exception:
887 except Exception:
822 log.exception("Error occurred during editing permissions "
888 log.exception("Error occurred during editing permissions "
823 "for user group in user group")
889 "for user group in user group")
824 raise JSONRPCError(
890 raise JSONRPCError(
825 'failed to edit permission for user group: '
891 'failed to edit permission for user group: '
826 '`%s` in user group: `%s`' % (
892 '`%s` in user group: `%s`' % (
827 sourceusergroupid, target_user_group.users_group_name
893 sourceusergroupid, target_user_group.users_group_name
828 )
894 )
829 )
895 )
@@ -1,564 +1,641 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import time
21 import time
22 import logging
22 import logging
23 import operator
23 import operator
24
24
25 from pyramid.httpexceptions import HTTPFound
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
26
26
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h, diffs
28 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int, datetime_to_time
28 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int, datetime_to_time
29 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
29 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
30 from rhodecode.model import repo
30 from rhodecode.model import repo
31 from rhodecode.model import repo_group
31 from rhodecode.model import repo_group
32 from rhodecode.model import user_group
32 from rhodecode.model import user_group
33 from rhodecode.model import user
33 from rhodecode.model import user
34 from rhodecode.model.db import User
34 from rhodecode.model.db import User
35 from rhodecode.model.scm import ScmModel
35 from rhodecode.model.scm import ScmModel
36 from rhodecode.model.settings import VcsSettingsModel
36
37
37 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
38
39
39
40
40 ADMIN_PREFIX = '/_admin'
41 ADMIN_PREFIX = '/_admin'
41 STATIC_FILE_PREFIX = '/_static'
42 STATIC_FILE_PREFIX = '/_static'
42
43
43 URL_NAME_REQUIREMENTS = {
44 URL_NAME_REQUIREMENTS = {
44 # group name can have a slash in them, but they must not end with a slash
45 # group name can have a slash in them, but they must not end with a slash
45 'group_name': r'.*?[^/]',
46 'group_name': r'.*?[^/]',
46 'repo_group_name': r'.*?[^/]',
47 'repo_group_name': r'.*?[^/]',
47 # repo names can have a slash in them, but they must not end with a slash
48 # repo names can have a slash in them, but they must not end with a slash
48 'repo_name': r'.*?[^/]',
49 'repo_name': r'.*?[^/]',
49 # file path eats up everything at the end
50 # file path eats up everything at the end
50 'f_path': r'.*',
51 'f_path': r'.*',
51 # reference types
52 # reference types
52 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
53 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
53 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
54 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
54 }
55 }
55
56
56
57
57 def add_route_with_slash(config,name, pattern, **kw):
58 def add_route_with_slash(config,name, pattern, **kw):
58 config.add_route(name, pattern, **kw)
59 config.add_route(name, pattern, **kw)
59 if not pattern.endswith('/'):
60 if not pattern.endswith('/'):
60 config.add_route(name + '_slash', pattern + '/', **kw)
61 config.add_route(name + '_slash', pattern + '/', **kw)
61
62
62
63
63 def add_route_requirements(route_path, requirements=URL_NAME_REQUIREMENTS):
64 def add_route_requirements(route_path, requirements=URL_NAME_REQUIREMENTS):
64 """
65 """
65 Adds regex requirements to pyramid routes using a mapping dict
66 Adds regex requirements to pyramid routes using a mapping dict
66 e.g::
67 e.g::
67 add_route_requirements('{repo_name}/settings')
68 add_route_requirements('{repo_name}/settings')
68 """
69 """
69 for key, regex in requirements.items():
70 for key, regex in requirements.items():
70 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
71 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
71 return route_path
72 return route_path
72
73
73
74
74 def get_format_ref_id(repo):
75 def get_format_ref_id(repo):
75 """Returns a `repo` specific reference formatter function"""
76 """Returns a `repo` specific reference formatter function"""
76 if h.is_svn(repo):
77 if h.is_svn(repo):
77 return _format_ref_id_svn
78 return _format_ref_id_svn
78 else:
79 else:
79 return _format_ref_id
80 return _format_ref_id
80
81
81
82
82 def _format_ref_id(name, raw_id):
83 def _format_ref_id(name, raw_id):
83 """Default formatting of a given reference `name`"""
84 """Default formatting of a given reference `name`"""
84 return name
85 return name
85
86
86
87
87 def _format_ref_id_svn(name, raw_id):
88 def _format_ref_id_svn(name, raw_id):
88 """Special way of formatting a reference for Subversion including path"""
89 """Special way of formatting a reference for Subversion including path"""
89 return '%s@%s' % (name, raw_id)
90 return '%s@%s' % (name, raw_id)
90
91
91
92
92 class TemplateArgs(StrictAttributeDict):
93 class TemplateArgs(StrictAttributeDict):
93 pass
94 pass
94
95
95
96
96 class BaseAppView(object):
97 class BaseAppView(object):
97
98
98 def __init__(self, context, request):
99 def __init__(self, context, request):
99 self.request = request
100 self.request = request
100 self.context = context
101 self.context = context
101 self.session = request.session
102 self.session = request.session
102 self._rhodecode_user = request.user # auth user
103 self._rhodecode_user = request.user # auth user
103 self._rhodecode_db_user = self._rhodecode_user.get_instance()
104 self._rhodecode_db_user = self._rhodecode_user.get_instance()
104 self._maybe_needs_password_change(
105 self._maybe_needs_password_change(
105 request.matched_route.name, self._rhodecode_db_user)
106 request.matched_route.name, self._rhodecode_db_user)
106
107
107 def _maybe_needs_password_change(self, view_name, user_obj):
108 def _maybe_needs_password_change(self, view_name, user_obj):
108 log.debug('Checking if user %s needs password change on view %s',
109 log.debug('Checking if user %s needs password change on view %s',
109 user_obj, view_name)
110 user_obj, view_name)
110 skip_user_views = [
111 skip_user_views = [
111 'logout', 'login',
112 'logout', 'login',
112 'my_account_password', 'my_account_password_update'
113 'my_account_password', 'my_account_password_update'
113 ]
114 ]
114
115
115 if not user_obj:
116 if not user_obj:
116 return
117 return
117
118
118 if user_obj.username == User.DEFAULT_USER:
119 if user_obj.username == User.DEFAULT_USER:
119 return
120 return
120
121
121 now = time.time()
122 now = time.time()
122 should_change = user_obj.user_data.get('force_password_change')
123 should_change = user_obj.user_data.get('force_password_change')
123 change_after = safe_int(should_change) or 0
124 change_after = safe_int(should_change) or 0
124 if should_change and now > change_after:
125 if should_change and now > change_after:
125 log.debug('User %s requires password change', user_obj)
126 log.debug('User %s requires password change', user_obj)
126 h.flash('You are required to change your password', 'warning',
127 h.flash('You are required to change your password', 'warning',
127 ignore_duplicate=True)
128 ignore_duplicate=True)
128
129
129 if view_name not in skip_user_views:
130 if view_name not in skip_user_views:
130 raise HTTPFound(
131 raise HTTPFound(
131 self.request.route_path('my_account_password'))
132 self.request.route_path('my_account_password'))
132
133
133 def _log_creation_exception(self, e, repo_name):
134 def _log_creation_exception(self, e, repo_name):
134 _ = self.request.translate
135 _ = self.request.translate
135 reason = None
136 reason = None
136 if len(e.args) == 2:
137 if len(e.args) == 2:
137 reason = e.args[1]
138 reason = e.args[1]
138
139
139 if reason == 'INVALID_CERTIFICATE':
140 if reason == 'INVALID_CERTIFICATE':
140 log.exception(
141 log.exception(
141 'Exception creating a repository: invalid certificate')
142 'Exception creating a repository: invalid certificate')
142 msg = (_('Error creating repository %s: invalid certificate')
143 msg = (_('Error creating repository %s: invalid certificate')
143 % repo_name)
144 % repo_name)
144 else:
145 else:
145 log.exception("Exception creating a repository")
146 log.exception("Exception creating a repository")
146 msg = (_('Error creating repository %s')
147 msg = (_('Error creating repository %s')
147 % repo_name)
148 % repo_name)
148 return msg
149 return msg
149
150
150 def _get_local_tmpl_context(self, include_app_defaults=True):
151 def _get_local_tmpl_context(self, include_app_defaults=True):
151 c = TemplateArgs()
152 c = TemplateArgs()
152 c.auth_user = self.request.user
153 c.auth_user = self.request.user
153 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
154 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
154 c.rhodecode_user = self.request.user
155 c.rhodecode_user = self.request.user
155
156
156 if include_app_defaults:
157 if include_app_defaults:
157 from rhodecode.lib.base import attach_context_attributes
158 from rhodecode.lib.base import attach_context_attributes
158 attach_context_attributes(c, self.request, self.request.user.user_id)
159 attach_context_attributes(c, self.request, self.request.user.user_id)
159
160
160 return c
161 return c
161
162
162 def _get_template_context(self, tmpl_args, **kwargs):
163 def _get_template_context(self, tmpl_args, **kwargs):
163
164
164 local_tmpl_args = {
165 local_tmpl_args = {
165 'defaults': {},
166 'defaults': {},
166 'errors': {},
167 'errors': {},
167 'c': tmpl_args
168 'c': tmpl_args
168 }
169 }
169 local_tmpl_args.update(kwargs)
170 local_tmpl_args.update(kwargs)
170 return local_tmpl_args
171 return local_tmpl_args
171
172
172 def load_default_context(self):
173 def load_default_context(self):
173 """
174 """
174 example:
175 example:
175
176
176 def load_default_context(self):
177 def load_default_context(self):
177 c = self._get_local_tmpl_context()
178 c = self._get_local_tmpl_context()
178 c.custom_var = 'foobar'
179 c.custom_var = 'foobar'
179
180
180 return c
181 return c
181 """
182 """
182 raise NotImplementedError('Needs implementation in view class')
183 raise NotImplementedError('Needs implementation in view class')
183
184
184
185
185 class RepoAppView(BaseAppView):
186 class RepoAppView(BaseAppView):
186
187
187 def __init__(self, context, request):
188 def __init__(self, context, request):
188 super(RepoAppView, self).__init__(context, request)
189 super(RepoAppView, self).__init__(context, request)
189 self.db_repo = request.db_repo
190 self.db_repo = request.db_repo
190 self.db_repo_name = self.db_repo.repo_name
191 self.db_repo_name = self.db_repo.repo_name
191 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
192 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
192
193
193 def _handle_missing_requirements(self, error):
194 def _handle_missing_requirements(self, error):
194 log.error(
195 log.error(
195 'Requirements are missing for repository %s: %s',
196 'Requirements are missing for repository %s: %s',
196 self.db_repo_name, error.message)
197 self.db_repo_name, error.message)
197
198
198 def _get_local_tmpl_context(self, include_app_defaults=True):
199 def _get_local_tmpl_context(self, include_app_defaults=True):
199 _ = self.request.translate
200 _ = self.request.translate
200 c = super(RepoAppView, self)._get_local_tmpl_context(
201 c = super(RepoAppView, self)._get_local_tmpl_context(
201 include_app_defaults=include_app_defaults)
202 include_app_defaults=include_app_defaults)
202
203
203 # register common vars for this type of view
204 # register common vars for this type of view
204 c.rhodecode_db_repo = self.db_repo
205 c.rhodecode_db_repo = self.db_repo
205 c.repo_name = self.db_repo_name
206 c.repo_name = self.db_repo_name
206 c.repository_pull_requests = self.db_repo_pull_requests
207 c.repository_pull_requests = self.db_repo_pull_requests
208 self.path_filter = PathFilter(None)
207
209
208 c.repository_requirements_missing = False
210 c.repository_requirements_missing = {}
209 try:
211 try:
210 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
212 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
213 if self.rhodecode_vcs_repo:
214 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
215 c.auth_user.username)
216 self.path_filter = PathFilter(path_perms)
211 except RepositoryRequirementError as e:
217 except RepositoryRequirementError as e:
212 c.repository_requirements_missing = True
218 c.repository_requirements_missing = {'error': str(e)}
213 self._handle_missing_requirements(e)
219 self._handle_missing_requirements(e)
214 self.rhodecode_vcs_repo = None
220 self.rhodecode_vcs_repo = None
215
221
216 if (not c.repository_requirements_missing
222 c.path_filter = self.path_filter # used by atom_feed_entry.mako
217 and self.rhodecode_vcs_repo is None):
223
224 if self.rhodecode_vcs_repo is None:
218 # unable to fetch this repo as vcs instance, report back to user
225 # unable to fetch this repo as vcs instance, report back to user
219 h.flash(_(
226 h.flash(_(
220 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
227 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
221 "Please check if it exist, or is not damaged.") %
228 "Please check if it exist, or is not damaged.") %
222 {'repo_name': c.repo_name},
229 {'repo_name': c.repo_name},
223 category='error', ignore_duplicate=True)
230 category='error', ignore_duplicate=True)
224 raise HTTPFound(h.route_path('home'))
231 if c.repository_requirements_missing:
232 route = self.request.matched_route.name
233 if route.startswith(('edit_repo', 'repo_summary')):
234 # allow summary and edit repo on missing requirements
235 return c
236
237 raise HTTPFound(
238 h.route_path('repo_summary', repo_name=self.db_repo_name))
239
240 else: # redirect if we don't show missing requirements
241 raise HTTPFound(h.route_path('home'))
225
242
226 return c
243 return c
227
244
228 def _get_f_path(self, matchdict, default=None):
245 def _get_f_path_unchecked(self, matchdict, default=None):
246 """
247 Should only be used by redirects, everything else should call _get_f_path
248 """
229 f_path = matchdict.get('f_path')
249 f_path = matchdict.get('f_path')
230 if f_path:
250 if f_path:
231 # fix for multiple initial slashes that causes errors for GIT
251 # fix for multiple initial slashes that causes errors for GIT
232 return f_path.lstrip('/')
252 return f_path.lstrip('/')
233
253
234 return default
254 return default
235
255
256 def _get_f_path(self, matchdict, default=None):
257 f_path_match = self._get_f_path_unchecked(matchdict, default)
258 return self.path_filter.assert_path_permissions(f_path_match)
259
260 def _get_general_setting(self, target_repo, settings_key, default=False):
261 settings_model = VcsSettingsModel(repo=target_repo)
262 settings = settings_model.get_general_settings()
263 return settings.get(settings_key, default)
264
265
266 class PathFilter(object):
267
268 # Expects and instance of BasePathPermissionChecker or None
269 def __init__(self, permission_checker):
270 self.permission_checker = permission_checker
271
272 def assert_path_permissions(self, path):
273 if path and self.permission_checker and not self.permission_checker.has_access(path):
274 raise HTTPForbidden()
275 return path
276
277 def filter_patchset(self, patchset):
278 if not self.permission_checker or not patchset:
279 return patchset, False
280 had_filtered = False
281 filtered_patchset = []
282 for patch in patchset:
283 filename = patch.get('filename', None)
284 if not filename or self.permission_checker.has_access(filename):
285 filtered_patchset.append(patch)
286 else:
287 had_filtered = True
288 if had_filtered:
289 if isinstance(patchset, diffs.LimitedDiffContainer):
290 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
291 return filtered_patchset, True
292 else:
293 return patchset, False
294
295 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
296 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
297 result = diffset.render_patchset(filtered_patchset, source_ref=source_ref, target_ref=target_ref)
298 result.has_hidden_changes = has_hidden_changes
299 return result
300
301 def get_raw_patch(self, diff_processor):
302 if self.permission_checker is None:
303 return diff_processor.as_raw()
304 elif self.permission_checker.has_full_access:
305 return diff_processor.as_raw()
306 else:
307 return '# Repository has user-specific filters, raw patch generation is disabled.'
308
309 @property
310 def is_enabled(self):
311 return self.permission_checker is not None
312
236
313
237 class RepoGroupAppView(BaseAppView):
314 class RepoGroupAppView(BaseAppView):
238 def __init__(self, context, request):
315 def __init__(self, context, request):
239 super(RepoGroupAppView, self).__init__(context, request)
316 super(RepoGroupAppView, self).__init__(context, request)
240 self.db_repo_group = request.db_repo_group
317 self.db_repo_group = request.db_repo_group
241 self.db_repo_group_name = self.db_repo_group.group_name
318 self.db_repo_group_name = self.db_repo_group.group_name
242
319
243 def _revoke_perms_on_yourself(self, form_result):
320 def _revoke_perms_on_yourself(self, form_result):
244 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
321 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
245 form_result['perm_updates'])
322 form_result['perm_updates'])
246 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
323 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
247 form_result['perm_additions'])
324 form_result['perm_additions'])
248 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
325 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
249 form_result['perm_deletions'])
326 form_result['perm_deletions'])
250 admin_perm = 'group.admin'
327 admin_perm = 'group.admin'
251 if _updates and _updates[0][1] != admin_perm or \
328 if _updates and _updates[0][1] != admin_perm or \
252 _additions and _additions[0][1] != admin_perm or \
329 _additions and _additions[0][1] != admin_perm or \
253 _deletions and _deletions[0][1] != admin_perm:
330 _deletions and _deletions[0][1] != admin_perm:
254 return True
331 return True
255 return False
332 return False
256
333
257
334
258 class UserGroupAppView(BaseAppView):
335 class UserGroupAppView(BaseAppView):
259 def __init__(self, context, request):
336 def __init__(self, context, request):
260 super(UserGroupAppView, self).__init__(context, request)
337 super(UserGroupAppView, self).__init__(context, request)
261 self.db_user_group = request.db_user_group
338 self.db_user_group = request.db_user_group
262 self.db_user_group_name = self.db_user_group.users_group_name
339 self.db_user_group_name = self.db_user_group.users_group_name
263
340
264
341
265 class UserAppView(BaseAppView):
342 class UserAppView(BaseAppView):
266 def __init__(self, context, request):
343 def __init__(self, context, request):
267 super(UserAppView, self).__init__(context, request)
344 super(UserAppView, self).__init__(context, request)
268 self.db_user = request.db_user
345 self.db_user = request.db_user
269 self.db_user_id = self.db_user.user_id
346 self.db_user_id = self.db_user.user_id
270
347
271 _ = self.request.translate
348 _ = self.request.translate
272 if not request.db_user_supports_default:
349 if not request.db_user_supports_default:
273 if self.db_user.username == User.DEFAULT_USER:
350 if self.db_user.username == User.DEFAULT_USER:
274 h.flash(_("Editing user `{}` is disabled.".format(
351 h.flash(_("Editing user `{}` is disabled.".format(
275 User.DEFAULT_USER)), category='warning')
352 User.DEFAULT_USER)), category='warning')
276 raise HTTPFound(h.route_path('users'))
353 raise HTTPFound(h.route_path('users'))
277
354
278
355
279 class DataGridAppView(object):
356 class DataGridAppView(object):
280 """
357 """
281 Common class to have re-usable grid rendering components
358 Common class to have re-usable grid rendering components
282 """
359 """
283
360
284 def _extract_ordering(self, request, column_map=None):
361 def _extract_ordering(self, request, column_map=None):
285 column_map = column_map or {}
362 column_map = column_map or {}
286 column_index = safe_int(request.GET.get('order[0][column]'))
363 column_index = safe_int(request.GET.get('order[0][column]'))
287 order_dir = request.GET.get(
364 order_dir = request.GET.get(
288 'order[0][dir]', 'desc')
365 'order[0][dir]', 'desc')
289 order_by = request.GET.get(
366 order_by = request.GET.get(
290 'columns[%s][data][sort]' % column_index, 'name_raw')
367 'columns[%s][data][sort]' % column_index, 'name_raw')
291
368
292 # translate datatable to DB columns
369 # translate datatable to DB columns
293 order_by = column_map.get(order_by) or order_by
370 order_by = column_map.get(order_by) or order_by
294
371
295 search_q = request.GET.get('search[value]')
372 search_q = request.GET.get('search[value]')
296 return search_q, order_by, order_dir
373 return search_q, order_by, order_dir
297
374
298 def _extract_chunk(self, request):
375 def _extract_chunk(self, request):
299 start = safe_int(request.GET.get('start'), 0)
376 start = safe_int(request.GET.get('start'), 0)
300 length = safe_int(request.GET.get('length'), 25)
377 length = safe_int(request.GET.get('length'), 25)
301 draw = safe_int(request.GET.get('draw'))
378 draw = safe_int(request.GET.get('draw'))
302 return draw, start, length
379 return draw, start, length
303
380
304 def _get_order_col(self, order_by, model):
381 def _get_order_col(self, order_by, model):
305 if isinstance(order_by, basestring):
382 if isinstance(order_by, basestring):
306 try:
383 try:
307 return operator.attrgetter(order_by)(model)
384 return operator.attrgetter(order_by)(model)
308 except AttributeError:
385 except AttributeError:
309 return None
386 return None
310 else:
387 else:
311 return order_by
388 return order_by
312
389
313
390
314 class BaseReferencesView(RepoAppView):
391 class BaseReferencesView(RepoAppView):
315 """
392 """
316 Base for reference view for branches, tags and bookmarks.
393 Base for reference view for branches, tags and bookmarks.
317 """
394 """
318 def load_default_context(self):
395 def load_default_context(self):
319 c = self._get_local_tmpl_context()
396 c = self._get_local_tmpl_context()
320
397
321
398
322 return c
399 return c
323
400
324 def load_refs_context(self, ref_items, partials_template):
401 def load_refs_context(self, ref_items, partials_template):
325 _render = self.request.get_partial_renderer(partials_template)
402 _render = self.request.get_partial_renderer(partials_template)
326 pre_load = ["author", "date", "message"]
403 pre_load = ["author", "date", "message"]
327
404
328 is_svn = h.is_svn(self.rhodecode_vcs_repo)
405 is_svn = h.is_svn(self.rhodecode_vcs_repo)
329 is_hg = h.is_hg(self.rhodecode_vcs_repo)
406 is_hg = h.is_hg(self.rhodecode_vcs_repo)
330
407
331 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
408 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
332
409
333 closed_refs = {}
410 closed_refs = {}
334 if is_hg:
411 if is_hg:
335 closed_refs = self.rhodecode_vcs_repo.branches_closed
412 closed_refs = self.rhodecode_vcs_repo.branches_closed
336
413
337 data = []
414 data = []
338 for ref_name, commit_id in ref_items:
415 for ref_name, commit_id in ref_items:
339 commit = self.rhodecode_vcs_repo.get_commit(
416 commit = self.rhodecode_vcs_repo.get_commit(
340 commit_id=commit_id, pre_load=pre_load)
417 commit_id=commit_id, pre_load=pre_load)
341 closed = ref_name in closed_refs
418 closed = ref_name in closed_refs
342
419
343 # TODO: johbo: Unify generation of reference links
420 # TODO: johbo: Unify generation of reference links
344 use_commit_id = '/' in ref_name or is_svn
421 use_commit_id = '/' in ref_name or is_svn
345
422
346 if use_commit_id:
423 if use_commit_id:
347 files_url = h.route_path(
424 files_url = h.route_path(
348 'repo_files',
425 'repo_files',
349 repo_name=self.db_repo_name,
426 repo_name=self.db_repo_name,
350 f_path=ref_name if is_svn else '',
427 f_path=ref_name if is_svn else '',
351 commit_id=commit_id)
428 commit_id=commit_id)
352
429
353 else:
430 else:
354 files_url = h.route_path(
431 files_url = h.route_path(
355 'repo_files',
432 'repo_files',
356 repo_name=self.db_repo_name,
433 repo_name=self.db_repo_name,
357 f_path=ref_name if is_svn else '',
434 f_path=ref_name if is_svn else '',
358 commit_id=ref_name,
435 commit_id=ref_name,
359 _query=dict(at=ref_name))
436 _query=dict(at=ref_name))
360
437
361 data.append({
438 data.append({
362 "name": _render('name', ref_name, files_url, closed),
439 "name": _render('name', ref_name, files_url, closed),
363 "name_raw": ref_name,
440 "name_raw": ref_name,
364 "date": _render('date', commit.date),
441 "date": _render('date', commit.date),
365 "date_raw": datetime_to_time(commit.date),
442 "date_raw": datetime_to_time(commit.date),
366 "author": _render('author', commit.author),
443 "author": _render('author', commit.author),
367 "commit": _render(
444 "commit": _render(
368 'commit', commit.message, commit.raw_id, commit.idx),
445 'commit', commit.message, commit.raw_id, commit.idx),
369 "commit_raw": commit.idx,
446 "commit_raw": commit.idx,
370 "compare": _render(
447 "compare": _render(
371 'compare', format_ref_id(ref_name, commit.raw_id)),
448 'compare', format_ref_id(ref_name, commit.raw_id)),
372 })
449 })
373
450
374 return data
451 return data
375
452
376
453
377 class RepoRoutePredicate(object):
454 class RepoRoutePredicate(object):
378 def __init__(self, val, config):
455 def __init__(self, val, config):
379 self.val = val
456 self.val = val
380
457
381 def text(self):
458 def text(self):
382 return 'repo_route = %s' % self.val
459 return 'repo_route = %s' % self.val
383
460
384 phash = text
461 phash = text
385
462
386 def __call__(self, info, request):
463 def __call__(self, info, request):
387
464
388 if hasattr(request, 'vcs_call'):
465 if hasattr(request, 'vcs_call'):
389 # skip vcs calls
466 # skip vcs calls
390 return
467 return
391
468
392 repo_name = info['match']['repo_name']
469 repo_name = info['match']['repo_name']
393 repo_model = repo.RepoModel()
470 repo_model = repo.RepoModel()
394 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
471 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
395
472
396 def redirect_if_creating(db_repo):
473 def redirect_if_creating(db_repo):
397 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
474 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
398 raise HTTPFound(
475 raise HTTPFound(
399 request.route_path('repo_creating',
476 request.route_path('repo_creating',
400 repo_name=db_repo.repo_name))
477 repo_name=db_repo.repo_name))
401
478
402 if by_name_match:
479 if by_name_match:
403 # register this as request object we can re-use later
480 # register this as request object we can re-use later
404 request.db_repo = by_name_match
481 request.db_repo = by_name_match
405 redirect_if_creating(by_name_match)
482 redirect_if_creating(by_name_match)
406 return True
483 return True
407
484
408 by_id_match = repo_model.get_repo_by_id(repo_name)
485 by_id_match = repo_model.get_repo_by_id(repo_name)
409 if by_id_match:
486 if by_id_match:
410 request.db_repo = by_id_match
487 request.db_repo = by_id_match
411 redirect_if_creating(by_id_match)
488 redirect_if_creating(by_id_match)
412 return True
489 return True
413
490
414 return False
491 return False
415
492
416
493
417 class RepoTypeRoutePredicate(object):
494 class RepoTypeRoutePredicate(object):
418 def __init__(self, val, config):
495 def __init__(self, val, config):
419 self.val = val or ['hg', 'git', 'svn']
496 self.val = val or ['hg', 'git', 'svn']
420
497
421 def text(self):
498 def text(self):
422 return 'repo_accepted_type = %s' % self.val
499 return 'repo_accepted_type = %s' % self.val
423
500
424 phash = text
501 phash = text
425
502
426 def __call__(self, info, request):
503 def __call__(self, info, request):
427 if hasattr(request, 'vcs_call'):
504 if hasattr(request, 'vcs_call'):
428 # skip vcs calls
505 # skip vcs calls
429 return
506 return
430
507
431 rhodecode_db_repo = request.db_repo
508 rhodecode_db_repo = request.db_repo
432
509
433 log.debug(
510 log.debug(
434 '%s checking repo type for %s in %s',
511 '%s checking repo type for %s in %s',
435 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
512 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
436
513
437 if rhodecode_db_repo.repo_type in self.val:
514 if rhodecode_db_repo.repo_type in self.val:
438 return True
515 return True
439 else:
516 else:
440 log.warning('Current view is not supported for repo type:%s',
517 log.warning('Current view is not supported for repo type:%s',
441 rhodecode_db_repo.repo_type)
518 rhodecode_db_repo.repo_type)
442 #
519 #
443 # h.flash(h.literal(
520 # h.flash(h.literal(
444 # _('Action not supported for %s.' % rhodecode_repo.alias)),
521 # _('Action not supported for %s.' % rhodecode_repo.alias)),
445 # category='warning')
522 # category='warning')
446 # return redirect(
523 # return redirect(
447 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
524 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
448
525
449 return False
526 return False
450
527
451
528
452 class RepoGroupRoutePredicate(object):
529 class RepoGroupRoutePredicate(object):
453 def __init__(self, val, config):
530 def __init__(self, val, config):
454 self.val = val
531 self.val = val
455
532
456 def text(self):
533 def text(self):
457 return 'repo_group_route = %s' % self.val
534 return 'repo_group_route = %s' % self.val
458
535
459 phash = text
536 phash = text
460
537
461 def __call__(self, info, request):
538 def __call__(self, info, request):
462 if hasattr(request, 'vcs_call'):
539 if hasattr(request, 'vcs_call'):
463 # skip vcs calls
540 # skip vcs calls
464 return
541 return
465
542
466 repo_group_name = info['match']['repo_group_name']
543 repo_group_name = info['match']['repo_group_name']
467 repo_group_model = repo_group.RepoGroupModel()
544 repo_group_model = repo_group.RepoGroupModel()
468 by_name_match = repo_group_model.get_by_group_name(
545 by_name_match = repo_group_model.get_by_group_name(
469 repo_group_name, cache=True)
546 repo_group_name, cache=True)
470
547
471 if by_name_match:
548 if by_name_match:
472 # register this as request object we can re-use later
549 # register this as request object we can re-use later
473 request.db_repo_group = by_name_match
550 request.db_repo_group = by_name_match
474 return True
551 return True
475
552
476 return False
553 return False
477
554
478
555
479 class UserGroupRoutePredicate(object):
556 class UserGroupRoutePredicate(object):
480 def __init__(self, val, config):
557 def __init__(self, val, config):
481 self.val = val
558 self.val = val
482
559
483 def text(self):
560 def text(self):
484 return 'user_group_route = %s' % self.val
561 return 'user_group_route = %s' % self.val
485
562
486 phash = text
563 phash = text
487
564
488 def __call__(self, info, request):
565 def __call__(self, info, request):
489 if hasattr(request, 'vcs_call'):
566 if hasattr(request, 'vcs_call'):
490 # skip vcs calls
567 # skip vcs calls
491 return
568 return
492
569
493 user_group_id = info['match']['user_group_id']
570 user_group_id = info['match']['user_group_id']
494 user_group_model = user_group.UserGroup()
571 user_group_model = user_group.UserGroup()
495 by_id_match = user_group_model.get(
572 by_id_match = user_group_model.get(
496 user_group_id, cache=True)
573 user_group_id, cache=True)
497
574
498 if by_id_match:
575 if by_id_match:
499 # register this as request object we can re-use later
576 # register this as request object we can re-use later
500 request.db_user_group = by_id_match
577 request.db_user_group = by_id_match
501 return True
578 return True
502
579
503 return False
580 return False
504
581
505
582
506 class UserRoutePredicateBase(object):
583 class UserRoutePredicateBase(object):
507 supports_default = None
584 supports_default = None
508
585
509 def __init__(self, val, config):
586 def __init__(self, val, config):
510 self.val = val
587 self.val = val
511
588
512 def text(self):
589 def text(self):
513 raise NotImplementedError()
590 raise NotImplementedError()
514
591
515 def __call__(self, info, request):
592 def __call__(self, info, request):
516 if hasattr(request, 'vcs_call'):
593 if hasattr(request, 'vcs_call'):
517 # skip vcs calls
594 # skip vcs calls
518 return
595 return
519
596
520 user_id = info['match']['user_id']
597 user_id = info['match']['user_id']
521 user_model = user.User()
598 user_model = user.User()
522 by_id_match = user_model.get(
599 by_id_match = user_model.get(
523 user_id, cache=True)
600 user_id, cache=True)
524
601
525 if by_id_match:
602 if by_id_match:
526 # register this as request object we can re-use later
603 # register this as request object we can re-use later
527 request.db_user = by_id_match
604 request.db_user = by_id_match
528 request.db_user_supports_default = self.supports_default
605 request.db_user_supports_default = self.supports_default
529 return True
606 return True
530
607
531 return False
608 return False
532
609
533
610
534 class UserRoutePredicate(UserRoutePredicateBase):
611 class UserRoutePredicate(UserRoutePredicateBase):
535 supports_default = False
612 supports_default = False
536
613
537 def text(self):
614 def text(self):
538 return 'user_route = %s' % self.val
615 return 'user_route = %s' % self.val
539
616
540 phash = text
617 phash = text
541
618
542
619
543 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
620 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
544 supports_default = True
621 supports_default = True
545
622
546 def text(self):
623 def text(self):
547 return 'user_with_default_route = %s' % self.val
624 return 'user_with_default_route = %s' % self.val
548
625
549 phash = text
626 phash = text
550
627
551
628
552 def includeme(config):
629 def includeme(config):
553 config.add_route_predicate(
630 config.add_route_predicate(
554 'repo_route', RepoRoutePredicate)
631 'repo_route', RepoRoutePredicate)
555 config.add_route_predicate(
632 config.add_route_predicate(
556 'repo_accepted_types', RepoTypeRoutePredicate)
633 'repo_accepted_types', RepoTypeRoutePredicate)
557 config.add_route_predicate(
634 config.add_route_predicate(
558 'repo_group_route', RepoGroupRoutePredicate)
635 'repo_group_route', RepoGroupRoutePredicate)
559 config.add_route_predicate(
636 config.add_route_predicate(
560 'user_group_route', UserGroupRoutePredicate)
637 'user_group_route', UserGroupRoutePredicate)
561 config.add_route_predicate(
638 config.add_route_predicate(
562 'user_route_with_default', UserRouteWithDefaultPredicate)
639 'user_route_with_default', UserRouteWithDefaultPredicate)
563 config.add_route_predicate(
640 config.add_route_predicate(
564 'user_route', UserRoutePredicate) No newline at end of file
641 'user_route', UserRoutePredicate)
@@ -1,409 +1,414 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 from rhodecode.apps._base import ADMIN_PREFIX
22 from rhodecode.apps._base import ADMIN_PREFIX
23
23
24
24
25 def admin_routes(config):
25 def admin_routes(config):
26 """
26 """
27 Admin prefixed routes
27 Admin prefixed routes
28 """
28 """
29
29
30 config.add_route(
30 config.add_route(
31 name='admin_audit_logs',
31 name='admin_audit_logs',
32 pattern='/audit_logs')
32 pattern='/audit_logs')
33
33
34 config.add_route(
34 config.add_route(
35 name='admin_audit_log_entry',
35 name='admin_audit_log_entry',
36 pattern='/audit_logs/{audit_log_id}')
36 pattern='/audit_logs/{audit_log_id}')
37
37
38 config.add_route(
38 config.add_route(
39 name='pull_requests_global_0', # backward compat
39 name='pull_requests_global_0', # backward compat
40 pattern='/pull_requests/{pull_request_id:\d+}')
40 pattern='/pull_requests/{pull_request_id:\d+}')
41 config.add_route(
41 config.add_route(
42 name='pull_requests_global_1', # backward compat
42 name='pull_requests_global_1', # backward compat
43 pattern='/pull-requests/{pull_request_id:\d+}')
43 pattern='/pull-requests/{pull_request_id:\d+}')
44 config.add_route(
44 config.add_route(
45 name='pull_requests_global',
45 name='pull_requests_global',
46 pattern='/pull-request/{pull_request_id:\d+}')
46 pattern='/pull-request/{pull_request_id:\d+}')
47
47
48 config.add_route(
48 config.add_route(
49 name='admin_settings_open_source',
49 name='admin_settings_open_source',
50 pattern='/settings/open_source')
50 pattern='/settings/open_source')
51 config.add_route(
51 config.add_route(
52 name='admin_settings_vcs_svn_generate_cfg',
52 name='admin_settings_vcs_svn_generate_cfg',
53 pattern='/settings/vcs/svn_generate_cfg')
53 pattern='/settings/vcs/svn_generate_cfg')
54
54
55 config.add_route(
55 config.add_route(
56 name='admin_settings_system',
56 name='admin_settings_system',
57 pattern='/settings/system')
57 pattern='/settings/system')
58 config.add_route(
58 config.add_route(
59 name='admin_settings_system_update',
59 name='admin_settings_system_update',
60 pattern='/settings/system/updates')
60 pattern='/settings/system/updates')
61
61
62 config.add_route(
62 config.add_route(
63 name='admin_settings_sessions',
63 name='admin_settings_sessions',
64 pattern='/settings/sessions')
64 pattern='/settings/sessions')
65 config.add_route(
65 config.add_route(
66 name='admin_settings_sessions_cleanup',
66 name='admin_settings_sessions_cleanup',
67 pattern='/settings/sessions/cleanup')
67 pattern='/settings/sessions/cleanup')
68
68
69 config.add_route(
69 config.add_route(
70 name='admin_settings_process_management',
70 name='admin_settings_process_management',
71 pattern='/settings/process_management')
71 pattern='/settings/process_management')
72 config.add_route(
72 config.add_route(
73 name='admin_settings_process_management_data',
73 name='admin_settings_process_management_data',
74 pattern='/settings/process_management/data')
74 pattern='/settings/process_management/data')
75 config.add_route(
75 config.add_route(
76 name='admin_settings_process_management_signal',
76 name='admin_settings_process_management_signal',
77 pattern='/settings/process_management/signal')
77 pattern='/settings/process_management/signal')
78 config.add_route(
78 config.add_route(
79 name='admin_settings_process_management_master_signal',
79 name='admin_settings_process_management_master_signal',
80 pattern='/settings/process_management/master_signal')
80 pattern='/settings/process_management/master_signal')
81
81
82 # default settings
82 # default settings
83 config.add_route(
83 config.add_route(
84 name='admin_defaults_repositories',
84 name='admin_defaults_repositories',
85 pattern='/defaults/repositories')
85 pattern='/defaults/repositories')
86 config.add_route(
86 config.add_route(
87 name='admin_defaults_repositories_update',
87 name='admin_defaults_repositories_update',
88 pattern='/defaults/repositories/update')
88 pattern='/defaults/repositories/update')
89
89
90 # admin settings
90 # admin settings
91
91
92 config.add_route(
92 config.add_route(
93 name='admin_settings',
93 name='admin_settings',
94 pattern='/settings')
94 pattern='/settings')
95 config.add_route(
95 config.add_route(
96 name='admin_settings_update',
96 name='admin_settings_update',
97 pattern='/settings/update')
97 pattern='/settings/update')
98
98
99 config.add_route(
99 config.add_route(
100 name='admin_settings_global',
100 name='admin_settings_global',
101 pattern='/settings/global')
101 pattern='/settings/global')
102 config.add_route(
102 config.add_route(
103 name='admin_settings_global_update',
103 name='admin_settings_global_update',
104 pattern='/settings/global/update')
104 pattern='/settings/global/update')
105
105
106 config.add_route(
106 config.add_route(
107 name='admin_settings_vcs',
107 name='admin_settings_vcs',
108 pattern='/settings/vcs')
108 pattern='/settings/vcs')
109 config.add_route(
109 config.add_route(
110 name='admin_settings_vcs_update',
110 name='admin_settings_vcs_update',
111 pattern='/settings/vcs/update')
111 pattern='/settings/vcs/update')
112 config.add_route(
112 config.add_route(
113 name='admin_settings_vcs_svn_pattern_delete',
113 name='admin_settings_vcs_svn_pattern_delete',
114 pattern='/settings/vcs/svn_pattern_delete')
114 pattern='/settings/vcs/svn_pattern_delete')
115
115
116 config.add_route(
116 config.add_route(
117 name='admin_settings_mapping',
117 name='admin_settings_mapping',
118 pattern='/settings/mapping')
118 pattern='/settings/mapping')
119 config.add_route(
119 config.add_route(
120 name='admin_settings_mapping_update',
120 name='admin_settings_mapping_update',
121 pattern='/settings/mapping/update')
121 pattern='/settings/mapping/update')
122
122
123 config.add_route(
123 config.add_route(
124 name='admin_settings_visual',
124 name='admin_settings_visual',
125 pattern='/settings/visual')
125 pattern='/settings/visual')
126 config.add_route(
126 config.add_route(
127 name='admin_settings_visual_update',
127 name='admin_settings_visual_update',
128 pattern='/settings/visual/update')
128 pattern='/settings/visual/update')
129
129
130
130
131 config.add_route(
131 config.add_route(
132 name='admin_settings_issuetracker',
132 name='admin_settings_issuetracker',
133 pattern='/settings/issue-tracker')
133 pattern='/settings/issue-tracker')
134 config.add_route(
134 config.add_route(
135 name='admin_settings_issuetracker_update',
135 name='admin_settings_issuetracker_update',
136 pattern='/settings/issue-tracker/update')
136 pattern='/settings/issue-tracker/update')
137 config.add_route(
137 config.add_route(
138 name='admin_settings_issuetracker_test',
138 name='admin_settings_issuetracker_test',
139 pattern='/settings/issue-tracker/test')
139 pattern='/settings/issue-tracker/test')
140 config.add_route(
140 config.add_route(
141 name='admin_settings_issuetracker_delete',
141 name='admin_settings_issuetracker_delete',
142 pattern='/settings/issue-tracker/delete')
142 pattern='/settings/issue-tracker/delete')
143
143
144 config.add_route(
144 config.add_route(
145 name='admin_settings_email',
145 name='admin_settings_email',
146 pattern='/settings/email')
146 pattern='/settings/email')
147 config.add_route(
147 config.add_route(
148 name='admin_settings_email_update',
148 name='admin_settings_email_update',
149 pattern='/settings/email/update')
149 pattern='/settings/email/update')
150
150
151 config.add_route(
151 config.add_route(
152 name='admin_settings_hooks',
152 name='admin_settings_hooks',
153 pattern='/settings/hooks')
153 pattern='/settings/hooks')
154 config.add_route(
154 config.add_route(
155 name='admin_settings_hooks_update',
155 name='admin_settings_hooks_update',
156 pattern='/settings/hooks/update')
156 pattern='/settings/hooks/update')
157 config.add_route(
157 config.add_route(
158 name='admin_settings_hooks_delete',
158 name='admin_settings_hooks_delete',
159 pattern='/settings/hooks/delete')
159 pattern='/settings/hooks/delete')
160
160
161 config.add_route(
161 config.add_route(
162 name='admin_settings_search',
162 name='admin_settings_search',
163 pattern='/settings/search')
163 pattern='/settings/search')
164
164
165 config.add_route(
165 config.add_route(
166 name='admin_settings_labs',
166 name='admin_settings_labs',
167 pattern='/settings/labs')
167 pattern='/settings/labs')
168 config.add_route(
168 config.add_route(
169 name='admin_settings_labs_update',
169 name='admin_settings_labs_update',
170 pattern='/settings/labs/update')
170 pattern='/settings/labs/update')
171
171
172 # Automation EE feature
173 config.add_route(
174 'admin_settings_automation',
175 pattern=ADMIN_PREFIX + '/settings/automation')
176
172 # global permissions
177 # global permissions
173
178
174 config.add_route(
179 config.add_route(
175 name='admin_permissions_application',
180 name='admin_permissions_application',
176 pattern='/permissions/application')
181 pattern='/permissions/application')
177 config.add_route(
182 config.add_route(
178 name='admin_permissions_application_update',
183 name='admin_permissions_application_update',
179 pattern='/permissions/application/update')
184 pattern='/permissions/application/update')
180
185
181 config.add_route(
186 config.add_route(
182 name='admin_permissions_global',
187 name='admin_permissions_global',
183 pattern='/permissions/global')
188 pattern='/permissions/global')
184 config.add_route(
189 config.add_route(
185 name='admin_permissions_global_update',
190 name='admin_permissions_global_update',
186 pattern='/permissions/global/update')
191 pattern='/permissions/global/update')
187
192
188 config.add_route(
193 config.add_route(
189 name='admin_permissions_object',
194 name='admin_permissions_object',
190 pattern='/permissions/object')
195 pattern='/permissions/object')
191 config.add_route(
196 config.add_route(
192 name='admin_permissions_object_update',
197 name='admin_permissions_object_update',
193 pattern='/permissions/object/update')
198 pattern='/permissions/object/update')
194
199
195 config.add_route(
200 config.add_route(
196 name='admin_permissions_ips',
201 name='admin_permissions_ips',
197 pattern='/permissions/ips')
202 pattern='/permissions/ips')
198
203
199 config.add_route(
204 config.add_route(
200 name='admin_permissions_overview',
205 name='admin_permissions_overview',
201 pattern='/permissions/overview')
206 pattern='/permissions/overview')
202
207
203 config.add_route(
208 config.add_route(
204 name='admin_permissions_auth_token_access',
209 name='admin_permissions_auth_token_access',
205 pattern='/permissions/auth_token_access')
210 pattern='/permissions/auth_token_access')
206
211
207 config.add_route(
212 config.add_route(
208 name='admin_permissions_ssh_keys',
213 name='admin_permissions_ssh_keys',
209 pattern='/permissions/ssh_keys')
214 pattern='/permissions/ssh_keys')
210 config.add_route(
215 config.add_route(
211 name='admin_permissions_ssh_keys_data',
216 name='admin_permissions_ssh_keys_data',
212 pattern='/permissions/ssh_keys/data')
217 pattern='/permissions/ssh_keys/data')
213 config.add_route(
218 config.add_route(
214 name='admin_permissions_ssh_keys_update',
219 name='admin_permissions_ssh_keys_update',
215 pattern='/permissions/ssh_keys/update')
220 pattern='/permissions/ssh_keys/update')
216
221
217 # users admin
222 # users admin
218 config.add_route(
223 config.add_route(
219 name='users',
224 name='users',
220 pattern='/users')
225 pattern='/users')
221
226
222 config.add_route(
227 config.add_route(
223 name='users_data',
228 name='users_data',
224 pattern='/users_data')
229 pattern='/users_data')
225
230
226 config.add_route(
231 config.add_route(
227 name='users_create',
232 name='users_create',
228 pattern='/users/create')
233 pattern='/users/create')
229
234
230 config.add_route(
235 config.add_route(
231 name='users_new',
236 name='users_new',
232 pattern='/users/new')
237 pattern='/users/new')
233
238
234 # user management
239 # user management
235 config.add_route(
240 config.add_route(
236 name='user_edit',
241 name='user_edit',
237 pattern='/users/{user_id:\d+}/edit',
242 pattern='/users/{user_id:\d+}/edit',
238 user_route=True)
243 user_route=True)
239 config.add_route(
244 config.add_route(
240 name='user_edit_advanced',
245 name='user_edit_advanced',
241 pattern='/users/{user_id:\d+}/edit/advanced',
246 pattern='/users/{user_id:\d+}/edit/advanced',
242 user_route=True)
247 user_route=True)
243 config.add_route(
248 config.add_route(
244 name='user_edit_global_perms',
249 name='user_edit_global_perms',
245 pattern='/users/{user_id:\d+}/edit/global_permissions',
250 pattern='/users/{user_id:\d+}/edit/global_permissions',
246 user_route=True)
251 user_route=True)
247 config.add_route(
252 config.add_route(
248 name='user_edit_global_perms_update',
253 name='user_edit_global_perms_update',
249 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
254 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
250 user_route=True)
255 user_route=True)
251 config.add_route(
256 config.add_route(
252 name='user_update',
257 name='user_update',
253 pattern='/users/{user_id:\d+}/update',
258 pattern='/users/{user_id:\d+}/update',
254 user_route=True)
259 user_route=True)
255 config.add_route(
260 config.add_route(
256 name='user_delete',
261 name='user_delete',
257 pattern='/users/{user_id:\d+}/delete',
262 pattern='/users/{user_id:\d+}/delete',
258 user_route=True)
263 user_route=True)
259 config.add_route(
264 config.add_route(
260 name='user_force_password_reset',
265 name='user_force_password_reset',
261 pattern='/users/{user_id:\d+}/password_reset',
266 pattern='/users/{user_id:\d+}/password_reset',
262 user_route=True)
267 user_route=True)
263 config.add_route(
268 config.add_route(
264 name='user_create_personal_repo_group',
269 name='user_create_personal_repo_group',
265 pattern='/users/{user_id:\d+}/create_repo_group',
270 pattern='/users/{user_id:\d+}/create_repo_group',
266 user_route=True)
271 user_route=True)
267
272
268 # user auth tokens
273 # user auth tokens
269 config.add_route(
274 config.add_route(
270 name='edit_user_auth_tokens',
275 name='edit_user_auth_tokens',
271 pattern='/users/{user_id:\d+}/edit/auth_tokens',
276 pattern='/users/{user_id:\d+}/edit/auth_tokens',
272 user_route=True)
277 user_route=True)
273 config.add_route(
278 config.add_route(
274 name='edit_user_auth_tokens_add',
279 name='edit_user_auth_tokens_add',
275 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
280 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
276 user_route=True)
281 user_route=True)
277 config.add_route(
282 config.add_route(
278 name='edit_user_auth_tokens_delete',
283 name='edit_user_auth_tokens_delete',
279 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
284 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
280 user_route=True)
285 user_route=True)
281
286
282 # user ssh keys
287 # user ssh keys
283 config.add_route(
288 config.add_route(
284 name='edit_user_ssh_keys',
289 name='edit_user_ssh_keys',
285 pattern='/users/{user_id:\d+}/edit/ssh_keys',
290 pattern='/users/{user_id:\d+}/edit/ssh_keys',
286 user_route=True)
291 user_route=True)
287 config.add_route(
292 config.add_route(
288 name='edit_user_ssh_keys_generate_keypair',
293 name='edit_user_ssh_keys_generate_keypair',
289 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
294 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
290 user_route=True)
295 user_route=True)
291 config.add_route(
296 config.add_route(
292 name='edit_user_ssh_keys_add',
297 name='edit_user_ssh_keys_add',
293 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
298 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
294 user_route=True)
299 user_route=True)
295 config.add_route(
300 config.add_route(
296 name='edit_user_ssh_keys_delete',
301 name='edit_user_ssh_keys_delete',
297 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
302 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
298 user_route=True)
303 user_route=True)
299
304
300 # user emails
305 # user emails
301 config.add_route(
306 config.add_route(
302 name='edit_user_emails',
307 name='edit_user_emails',
303 pattern='/users/{user_id:\d+}/edit/emails',
308 pattern='/users/{user_id:\d+}/edit/emails',
304 user_route=True)
309 user_route=True)
305 config.add_route(
310 config.add_route(
306 name='edit_user_emails_add',
311 name='edit_user_emails_add',
307 pattern='/users/{user_id:\d+}/edit/emails/new',
312 pattern='/users/{user_id:\d+}/edit/emails/new',
308 user_route=True)
313 user_route=True)
309 config.add_route(
314 config.add_route(
310 name='edit_user_emails_delete',
315 name='edit_user_emails_delete',
311 pattern='/users/{user_id:\d+}/edit/emails/delete',
316 pattern='/users/{user_id:\d+}/edit/emails/delete',
312 user_route=True)
317 user_route=True)
313
318
314 # user IPs
319 # user IPs
315 config.add_route(
320 config.add_route(
316 name='edit_user_ips',
321 name='edit_user_ips',
317 pattern='/users/{user_id:\d+}/edit/ips',
322 pattern='/users/{user_id:\d+}/edit/ips',
318 user_route=True)
323 user_route=True)
319 config.add_route(
324 config.add_route(
320 name='edit_user_ips_add',
325 name='edit_user_ips_add',
321 pattern='/users/{user_id:\d+}/edit/ips/new',
326 pattern='/users/{user_id:\d+}/edit/ips/new',
322 user_route_with_default=True) # enabled for default user too
327 user_route_with_default=True) # enabled for default user too
323 config.add_route(
328 config.add_route(
324 name='edit_user_ips_delete',
329 name='edit_user_ips_delete',
325 pattern='/users/{user_id:\d+}/edit/ips/delete',
330 pattern='/users/{user_id:\d+}/edit/ips/delete',
326 user_route_with_default=True) # enabled for default user too
331 user_route_with_default=True) # enabled for default user too
327
332
328 # user perms
333 # user perms
329 config.add_route(
334 config.add_route(
330 name='edit_user_perms_summary',
335 name='edit_user_perms_summary',
331 pattern='/users/{user_id:\d+}/edit/permissions_summary',
336 pattern='/users/{user_id:\d+}/edit/permissions_summary',
332 user_route=True)
337 user_route=True)
333 config.add_route(
338 config.add_route(
334 name='edit_user_perms_summary_json',
339 name='edit_user_perms_summary_json',
335 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
340 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
336 user_route=True)
341 user_route=True)
337
342
338 # user user groups management
343 # user user groups management
339 config.add_route(
344 config.add_route(
340 name='edit_user_groups_management',
345 name='edit_user_groups_management',
341 pattern='/users/{user_id:\d+}/edit/groups_management',
346 pattern='/users/{user_id:\d+}/edit/groups_management',
342 user_route=True)
347 user_route=True)
343
348
344 config.add_route(
349 config.add_route(
345 name='edit_user_groups_management_updates',
350 name='edit_user_groups_management_updates',
346 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
351 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
347 user_route=True)
352 user_route=True)
348
353
349 # user audit logs
354 # user audit logs
350 config.add_route(
355 config.add_route(
351 name='edit_user_audit_logs',
356 name='edit_user_audit_logs',
352 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
357 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
353
358
354 # user-groups admin
359 # user-groups admin
355 config.add_route(
360 config.add_route(
356 name='user_groups',
361 name='user_groups',
357 pattern='/user_groups')
362 pattern='/user_groups')
358
363
359 config.add_route(
364 config.add_route(
360 name='user_groups_data',
365 name='user_groups_data',
361 pattern='/user_groups_data')
366 pattern='/user_groups_data')
362
367
363 config.add_route(
368 config.add_route(
364 name='user_groups_new',
369 name='user_groups_new',
365 pattern='/user_groups/new')
370 pattern='/user_groups/new')
366
371
367 config.add_route(
372 config.add_route(
368 name='user_groups_create',
373 name='user_groups_create',
369 pattern='/user_groups/create')
374 pattern='/user_groups/create')
370
375
371 # repos admin
376 # repos admin
372 config.add_route(
377 config.add_route(
373 name='repos',
378 name='repos',
374 pattern='/repos')
379 pattern='/repos')
375
380
376 config.add_route(
381 config.add_route(
377 name='repo_new',
382 name='repo_new',
378 pattern='/repos/new')
383 pattern='/repos/new')
379
384
380 config.add_route(
385 config.add_route(
381 name='repo_create',
386 name='repo_create',
382 pattern='/repos/create')
387 pattern='/repos/create')
383
388
384 # repo groups admin
389 # repo groups admin
385 config.add_route(
390 config.add_route(
386 name='repo_groups',
391 name='repo_groups',
387 pattern='/repo_groups')
392 pattern='/repo_groups')
388
393
389 config.add_route(
394 config.add_route(
390 name='repo_group_new',
395 name='repo_group_new',
391 pattern='/repo_group/new')
396 pattern='/repo_group/new')
392
397
393 config.add_route(
398 config.add_route(
394 name='repo_group_create',
399 name='repo_group_create',
395 pattern='/repo_group/create')
400 pattern='/repo_group/create')
396
401
397
402
398 def includeme(config):
403 def includeme(config):
399 from rhodecode.apps.admin.navigation import includeme as nav_includeme
404 from rhodecode.apps.admin.navigation import includeme as nav_includeme
400
405
401 # Create admin navigation registry and add it to the pyramid registry.
406 # Create admin navigation registry and add it to the pyramid registry.
402 nav_includeme(config)
407 nav_includeme(config)
403
408
404 # main admin routes
409 # main admin routes
405 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
410 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
406 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
411 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
407
412
408 # Scan module for configuration decorators.
413 # Scan module for configuration decorators.
409 config.scan('.views', ignore='.tests')
414 config.scan('.views', ignore='.tests')
@@ -1,143 +1,144 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23 import collections
23 import collections
24
24
25 from zope.interface import implementer
25 from zope.interface import implementer
26
26
27 from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry
27 from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry
28 from rhodecode.lib.utils2 import str2bool
28 from rhodecode.lib.utils2 import str2bool
29 from rhodecode.translation import _
29 from rhodecode.translation import _
30
30
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34 NavListEntry = collections.namedtuple(
34 NavListEntry = collections.namedtuple(
35 'NavListEntry', ['key', 'name', 'url', 'active_list'])
35 'NavListEntry', ['key', 'name', 'url', 'active_list'])
36
36
37
37
38 class NavEntry(object):
38 class NavEntry(object):
39 """
39 """
40 Represents an entry in the admin navigation.
40 Represents an entry in the admin navigation.
41
41
42 :param key: Unique identifier used to store reference in an OrderedDict.
42 :param key: Unique identifier used to store reference in an OrderedDict.
43 :param name: Display name, usually a translation string.
43 :param name: Display name, usually a translation string.
44 :param view_name: Name of the view, used generate the URL.
44 :param view_name: Name of the view, used generate the URL.
45 :param active_list: list of urls that we select active for this element
45 :param active_list: list of urls that we select active for this element
46 """
46 """
47
47
48 def __init__(self, key, name, view_name, active_list=None):
48 def __init__(self, key, name, view_name, active_list=None):
49 self.key = key
49 self.key = key
50 self.name = name
50 self.name = name
51 self.view_name = view_name
51 self.view_name = view_name
52 self._active_list = active_list or []
52 self._active_list = active_list or []
53
53
54 def generate_url(self, request):
54 def generate_url(self, request):
55 return request.route_path(self.view_name)
55 return request.route_path(self.view_name)
56
56
57 def get_localized_name(self, request):
57 def get_localized_name(self, request):
58 return request.translate(self.name)
58 return request.translate(self.name)
59
59
60 @property
60 @property
61 def active_list(self):
61 def active_list(self):
62 active_list = [self.key]
62 active_list = [self.key]
63 if self._active_list:
63 if self._active_list:
64 active_list = self._active_list
64 active_list = self._active_list
65 return active_list
65 return active_list
66
66
67
67
68 @implementer(IAdminNavigationRegistry)
68 @implementer(IAdminNavigationRegistry)
69 class NavigationRegistry(object):
69 class NavigationRegistry(object):
70
70
71 _base_entries = [
71 _base_entries = [
72 NavEntry('global', _('Global'),
72 NavEntry('global', _('Global'),
73 'admin_settings_global'),
73 'admin_settings_global'),
74 NavEntry('vcs', _('VCS'),
74 NavEntry('vcs', _('VCS'),
75 'admin_settings_vcs'),
75 'admin_settings_vcs'),
76 NavEntry('visual', _('Visual'),
76 NavEntry('visual', _('Visual'),
77 'admin_settings_visual'),
77 'admin_settings_visual'),
78 NavEntry('mapping', _('Remap and Rescan'),
78 NavEntry('mapping', _('Remap and Rescan'),
79 'admin_settings_mapping'),
79 'admin_settings_mapping'),
80 NavEntry('issuetracker', _('Issue Tracker'),
80 NavEntry('issuetracker', _('Issue Tracker'),
81 'admin_settings_issuetracker'),
81 'admin_settings_issuetracker'),
82 NavEntry('email', _('Email'),
82 NavEntry('email', _('Email'),
83 'admin_settings_email'),
83 'admin_settings_email'),
84 NavEntry('hooks', _('Hooks'),
84 NavEntry('hooks', _('Hooks'),
85 'admin_settings_hooks'),
85 'admin_settings_hooks'),
86 NavEntry('search', _('Full Text Search'),
86 NavEntry('search', _('Full Text Search'),
87 'admin_settings_search'),
87 'admin_settings_search'),
88 NavEntry('integrations', _('Integrations'),
88 NavEntry('integrations', _('Integrations'),
89 'global_integrations_home'),
89 'global_integrations_home'),
90 NavEntry('system', _('System Info'),
90 NavEntry('system', _('System Info'),
91 'admin_settings_system'),
91 'admin_settings_system'),
92 NavEntry('process_management', _('Processes'),
92 NavEntry('process_management', _('Processes'),
93 'admin_settings_process_management'),
93 'admin_settings_process_management'),
94 NavEntry('sessions', _('User Sessions'),
94 NavEntry('sessions', _('User Sessions'),
95 'admin_settings_sessions'),
95 'admin_settings_sessions'),
96 NavEntry('open_source', _('Open Source Licenses'),
96 NavEntry('open_source', _('Open Source Licenses'),
97 'admin_settings_open_source'),
97 'admin_settings_open_source'),
98
98 NavEntry('automation', _('Automation'),
99 'admin_settings_automation')
99 ]
100 ]
100
101
101 _labs_entry = NavEntry('labs', _('Labs'),
102 _labs_entry = NavEntry('labs', _('Labs'),
102 'admin_settings_labs')
103 'admin_settings_labs')
103
104
104 def __init__(self, labs_active=False):
105 def __init__(self, labs_active=False):
105 self._registered_entries = collections.OrderedDict()
106 self._registered_entries = collections.OrderedDict()
106 for item in self.__class__._base_entries:
107 for item in self.__class__._base_entries:
107 self._registered_entries[item.key] = item
108 self._registered_entries[item.key] = item
108
109
109 if labs_active:
110 if labs_active:
110 self.add_entry(self._labs_entry)
111 self.add_entry(self._labs_entry)
111
112
112 def add_entry(self, entry):
113 def add_entry(self, entry):
113 self._registered_entries[entry.key] = entry
114 self._registered_entries[entry.key] = entry
114
115
115 def get_navlist(self, request):
116 def get_navlist(self, request):
116 navlist = [NavListEntry(i.key, i.get_localized_name(request),
117 navlist = [NavListEntry(i.key, i.get_localized_name(request),
117 i.generate_url(request), i.active_list)
118 i.generate_url(request), i.active_list)
118 for i in self._registered_entries.values()]
119 for i in self._registered_entries.values()]
119 return navlist
120 return navlist
120
121
121
122
122 def navigation_registry(request, registry=None):
123 def navigation_registry(request, registry=None):
123 """
124 """
124 Helper that returns the admin navigation registry.
125 Helper that returns the admin navigation registry.
125 """
126 """
126 pyramid_registry = registry or request.registry
127 pyramid_registry = registry or request.registry
127 nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry)
128 nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry)
128 return nav_registry
129 return nav_registry
129
130
130
131
131 def navigation_list(request):
132 def navigation_list(request):
132 """
133 """
133 Helper that returns the admin navigation as list of NavListEntry objects.
134 Helper that returns the admin navigation as list of NavListEntry objects.
134 """
135 """
135 return navigation_registry(request).get_navlist(request)
136 return navigation_registry(request).get_navlist(request)
136
137
137
138
138 def includeme(config):
139 def includeme(config):
139 # Create admin navigation registry and add it to the pyramid registry.
140 # Create admin navigation registry and add it to the pyramid registry.
140 settings = config.get_settings()
141 settings = config.get_settings()
141 labs_active = str2bool(settings.get('labs_settings_active', False))
142 labs_active = str2bool(settings.get('labs_settings_active', False))
142 navigation_registry = NavigationRegistry(labs_active=labs_active)
143 navigation_registry = NavigationRegistry(labs_active=labs_active)
143 config.registry.registerUtility(navigation_registry) No newline at end of file
144 config.registry.registerUtility(navigation_registry)
@@ -1,201 +1,202 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.tests import assert_session_flash
23 from rhodecode.tests import assert_session_flash
24 from rhodecode.tests.utils import AssertResponse
24 from rhodecode.tests.utils import AssertResponse
25 from rhodecode.model.db import Session
25 from rhodecode.model.db import Session
26 from rhodecode.model.settings import SettingsModel
26 from rhodecode.model.settings import SettingsModel
27
27
28
28
29 def assert_auth_settings_updated(response):
29 def assert_auth_settings_updated(response):
30 assert response.status_int == 302, 'Expected response HTTP Found 302'
30 assert response.status_int == 302, 'Expected response HTTP Found 302'
31 assert_session_flash(response, 'Auth settings updated successfully')
31 assert_session_flash(response, 'Auth settings updated successfully')
32
32
33
33
34 @pytest.mark.usefixtures("autologin_user", "app")
34 @pytest.mark.usefixtures("autologin_user", "app")
35 class TestAuthSettingsView(object):
35 class TestAuthSettingsView(object):
36
36
37 def _enable_plugins(self, plugins_list, csrf_token, override=None,
37 def _enable_plugins(self, plugins_list, csrf_token, override=None,
38 verify_response=False):
38 verify_response=False):
39 test_url = '/_admin/auth'
39 test_url = '/_admin/auth'
40 params = {
40 params = {
41 'auth_plugins': plugins_list,
41 'auth_plugins': plugins_list,
42 'csrf_token': csrf_token,
42 'csrf_token': csrf_token,
43 }
43 }
44 if override:
44 if override:
45 params.update(override)
45 params.update(override)
46 _enabled_plugins = []
46 _enabled_plugins = []
47 for plugin in plugins_list.split(','):
47 for plugin in plugins_list.split(','):
48 plugin_name = plugin.partition('#')[-1]
48 plugin_name = plugin.partition('#')[-1]
49 enabled_plugin = '%s_enabled' % plugin_name
49 enabled_plugin = '%s_enabled' % plugin_name
50 cache_ttl = '%s_cache_ttl' % plugin_name
50 cache_ttl = '%s_cache_ttl' % plugin_name
51
51
52 # default params that are needed for each plugin,
52 # default params that are needed for each plugin,
53 # `enabled` and `cache_ttl`
53 # `enabled` and `cache_ttl`
54 params.update({
54 params.update({
55 enabled_plugin: True,
55 enabled_plugin: True,
56 cache_ttl: 0
56 cache_ttl: 0
57 })
57 })
58 _enabled_plugins.append(enabled_plugin)
58 _enabled_plugins.append(enabled_plugin)
59
59
60 # we need to clean any enabled plugin before, since they require
60 # we need to clean any enabled plugin before, since they require
61 # form params to be present
61 # form params to be present
62 db_plugin = SettingsModel().get_setting_by_name('auth_plugins')
62 db_plugin = SettingsModel().get_setting_by_name('auth_plugins')
63 db_plugin.app_settings_value = \
63 db_plugin.app_settings_value = \
64 'egg:rhodecode-enterprise-ce#rhodecode'
64 'egg:rhodecode-enterprise-ce#rhodecode'
65 Session().add(db_plugin)
65 Session().add(db_plugin)
66 Session().commit()
66 Session().commit()
67 for _plugin in _enabled_plugins:
67 for _plugin in _enabled_plugins:
68 db_plugin = SettingsModel().get_setting_by_name(_plugin)
68 db_plugin = SettingsModel().get_setting_by_name(_plugin)
69 if db_plugin:
69 if db_plugin:
70 Session().delete(db_plugin)
70 Session().delete(db_plugin)
71 Session().commit()
71 Session().commit()
72
72
73 response = self.app.post(url=test_url, params=params)
73 response = self.app.post(url=test_url, params=params)
74
74
75 if verify_response:
75 if verify_response:
76 assert_auth_settings_updated(response)
76 assert_auth_settings_updated(response)
77 return params
77 return params
78
78
79 def _post_ldap_settings(self, params, override=None, force=False):
79 def _post_ldap_settings(self, params, override=None, force=False):
80
80
81 params.update({
81 params.update({
82 'filter': 'user',
82 'filter': 'user',
83 'user_member_of': '',
83 'user_member_of': '',
84 'user_search_base': '',
84 'user_search_base': '',
85 'user_search_filter': 'test_filter',
85 'user_search_filter': 'test_filter',
86
86
87 'host': 'dc.example.com',
87 'host': 'dc.example.com',
88 'port': '999',
88 'port': '999',
89 'timeout': 3600,
89 'tls_kind': 'PLAIN',
90 'tls_kind': 'PLAIN',
90 'tls_reqcert': 'NEVER',
91 'tls_reqcert': 'NEVER',
91
92
92 'dn_user': 'test_user',
93 'dn_user': 'test_user',
93 'dn_pass': 'test_pass',
94 'dn_pass': 'test_pass',
94 'base_dn': 'test_base_dn',
95 'base_dn': 'test_base_dn',
95 'search_scope': 'BASE',
96 'search_scope': 'BASE',
96 'attr_login': 'test_attr_login',
97 'attr_login': 'test_attr_login',
97 'attr_firstname': 'ima',
98 'attr_firstname': 'ima',
98 'attr_lastname': 'tester',
99 'attr_lastname': 'tester',
99 'attr_email': 'test@example.com',
100 'attr_email': 'test@example.com',
100 'cache_ttl': '0',
101 'cache_ttl': '0',
101 })
102 })
102 if force:
103 if force:
103 params = {}
104 params = {}
104 params.update(override or {})
105 params.update(override or {})
105
106
106 test_url = '/_admin/auth/ldap/'
107 test_url = '/_admin/auth/ldap/'
107
108
108 response = self.app.post(url=test_url, params=params)
109 response = self.app.post(url=test_url, params=params)
109 return response
110 return response
110
111
111 def test_index(self):
112 def test_index(self):
112 response = self.app.get('/_admin/auth')
113 response = self.app.get('/_admin/auth')
113 response.mustcontain('Authentication Plugins')
114 response.mustcontain('Authentication Plugins')
114
115
115 @pytest.mark.parametrize("disable_plugin, needs_import", [
116 @pytest.mark.parametrize("disable_plugin, needs_import", [
116 ('egg:rhodecode-enterprise-ce#headers', None),
117 ('egg:rhodecode-enterprise-ce#headers', None),
117 ('egg:rhodecode-enterprise-ce#crowd', None),
118 ('egg:rhodecode-enterprise-ce#crowd', None),
118 ('egg:rhodecode-enterprise-ce#jasig_cas', None),
119 ('egg:rhodecode-enterprise-ce#jasig_cas', None),
119 ('egg:rhodecode-enterprise-ce#ldap', None),
120 ('egg:rhodecode-enterprise-ce#ldap', None),
120 ('egg:rhodecode-enterprise-ce#pam', "pam"),
121 ('egg:rhodecode-enterprise-ce#pam', "pam"),
121 ])
122 ])
122 def test_disable_plugin(self, csrf_token, disable_plugin, needs_import):
123 def test_disable_plugin(self, csrf_token, disable_plugin, needs_import):
123 # TODO: johbo: "pam" is currently not available on darwin,
124 # TODO: johbo: "pam" is currently not available on darwin,
124 # although the docs state that it should work on darwin.
125 # although the docs state that it should work on darwin.
125 if needs_import:
126 if needs_import:
126 pytest.importorskip(needs_import)
127 pytest.importorskip(needs_import)
127
128
128 self._enable_plugins(
129 self._enable_plugins(
129 'egg:rhodecode-enterprise-ce#rhodecode,' + disable_plugin,
130 'egg:rhodecode-enterprise-ce#rhodecode,' + disable_plugin,
130 csrf_token, verify_response=True)
131 csrf_token, verify_response=True)
131
132
132 self._enable_plugins(
133 self._enable_plugins(
133 'egg:rhodecode-enterprise-ce#rhodecode', csrf_token,
134 'egg:rhodecode-enterprise-ce#rhodecode', csrf_token,
134 verify_response=True)
135 verify_response=True)
135
136
136 def test_ldap_save_settings(self, csrf_token):
137 def test_ldap_save_settings(self, csrf_token):
137 params = self._enable_plugins(
138 params = self._enable_plugins(
138 'egg:rhodecode-enterprise-ce#rhodecode,'
139 'egg:rhodecode-enterprise-ce#rhodecode,'
139 'egg:rhodecode-enterprise-ce#ldap',
140 'egg:rhodecode-enterprise-ce#ldap',
140 csrf_token)
141 csrf_token)
141 response = self._post_ldap_settings(params)
142 response = self._post_ldap_settings(params)
142 assert_auth_settings_updated(response)
143 assert_auth_settings_updated(response)
143
144
144 new_settings = SettingsModel().get_auth_settings()
145 new_settings = SettingsModel().get_auth_settings()
145 assert new_settings['auth_ldap_host'] == u'dc.example.com', \
146 assert new_settings['auth_ldap_host'] == u'dc.example.com', \
146 'fail db write compare'
147 'fail db write compare'
147
148
148 def test_ldap_error_form_wrong_port_number(self, csrf_token):
149 def test_ldap_error_form_wrong_port_number(self, csrf_token):
149 params = self._enable_plugins(
150 params = self._enable_plugins(
150 'egg:rhodecode-enterprise-ce#rhodecode,'
151 'egg:rhodecode-enterprise-ce#rhodecode,'
151 'egg:rhodecode-enterprise-ce#ldap',
152 'egg:rhodecode-enterprise-ce#ldap',
152 csrf_token)
153 csrf_token)
153 invalid_port_value = 'invalid-port-number'
154 invalid_port_value = 'invalid-port-number'
154 response = self._post_ldap_settings(params, override={
155 response = self._post_ldap_settings(params, override={
155 'port': invalid_port_value,
156 'port': invalid_port_value,
156 })
157 })
157 assertr = AssertResponse(response)
158 assertr = AssertResponse(response)
158 assertr.element_contains(
159 assertr.element_contains(
159 '.form .field #port ~ .error-message',
160 '.form .field #port ~ .error-message',
160 invalid_port_value)
161 invalid_port_value)
161
162
162 def test_ldap_error_form(self, csrf_token):
163 def test_ldap_error_form(self, csrf_token):
163 params = self._enable_plugins(
164 params = self._enable_plugins(
164 'egg:rhodecode-enterprise-ce#rhodecode,'
165 'egg:rhodecode-enterprise-ce#rhodecode,'
165 'egg:rhodecode-enterprise-ce#ldap',
166 'egg:rhodecode-enterprise-ce#ldap',
166 csrf_token)
167 csrf_token)
167 response = self._post_ldap_settings(params, override={
168 response = self._post_ldap_settings(params, override={
168 'attr_login': '',
169 'attr_login': '',
169 })
170 })
170 response.mustcontain("""<span class="error-message">The LDAP Login"""
171 response.mustcontain("""<span class="error-message">The LDAP Login"""
171 """ attribute of the CN must be specified""")
172 """ attribute of the CN must be specified""")
172
173
173 def test_post_ldap_group_settings(self, csrf_token):
174 def test_post_ldap_group_settings(self, csrf_token):
174 params = self._enable_plugins(
175 params = self._enable_plugins(
175 'egg:rhodecode-enterprise-ce#rhodecode,'
176 'egg:rhodecode-enterprise-ce#rhodecode,'
176 'egg:rhodecode-enterprise-ce#ldap',
177 'egg:rhodecode-enterprise-ce#ldap',
177 csrf_token)
178 csrf_token)
178
179
179 response = self._post_ldap_settings(params, override={
180 response = self._post_ldap_settings(params, override={
180 'host': 'dc-legacy.example.com',
181 'host': 'dc-legacy.example.com',
181 'port': '999',
182 'port': '999',
182 'tls_kind': 'PLAIN',
183 'tls_kind': 'PLAIN',
183 'tls_reqcert': 'NEVER',
184 'tls_reqcert': 'NEVER',
184 'dn_user': 'test_user',
185 'dn_user': 'test_user',
185 'dn_pass': 'test_pass',
186 'dn_pass': 'test_pass',
186 'base_dn': 'test_base_dn',
187 'base_dn': 'test_base_dn',
187 'filter': 'test_filter',
188 'filter': 'test_filter',
188 'search_scope': 'BASE',
189 'search_scope': 'BASE',
189 'attr_login': 'test_attr_login',
190 'attr_login': 'test_attr_login',
190 'attr_firstname': 'ima',
191 'attr_firstname': 'ima',
191 'attr_lastname': 'tester',
192 'attr_lastname': 'tester',
192 'attr_email': 'test@example.com',
193 'attr_email': 'test@example.com',
193 'cache_ttl': '60',
194 'cache_ttl': '60',
194 'csrf_token': csrf_token,
195 'csrf_token': csrf_token,
195 }
196 }
196 )
197 )
197 assert_auth_settings_updated(response)
198 assert_auth_settings_updated(response)
198
199
199 new_settings = SettingsModel().get_auth_settings()
200 new_settings = SettingsModel().get_auth_settings()
200 assert new_settings['auth_ldap_host'] == u'dc-legacy.example.com', \
201 assert new_settings['auth_ldap_host'] == u'dc-legacy.example.com', \
201 'fail db write compare'
202 'fail db write compare'
@@ -1,173 +1,176 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.model.db import User, UserSshKeys
23 from rhodecode.model.db import User, UserSshKeys
24
24
25 from rhodecode.tests import TestController, assert_session_flash
25 from rhodecode.tests import TestController, assert_session_flash
26 from rhodecode.tests.fixture import Fixture
26 from rhodecode.tests.fixture import Fixture
27
27
28 fixture = Fixture()
28 fixture = Fixture()
29
29
30
30
31 def route_path(name, params=None, **kwargs):
31 def route_path(name, params=None, **kwargs):
32 import urllib
32 import urllib
33 from rhodecode.apps._base import ADMIN_PREFIX
33 from rhodecode.apps._base import ADMIN_PREFIX
34
34
35 base_url = {
35 base_url = {
36 'edit_user_ssh_keys':
36 'edit_user_ssh_keys':
37 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys',
37 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys',
38 'edit_user_ssh_keys_generate_keypair':
38 'edit_user_ssh_keys_generate_keypair':
39 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/generate',
39 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/generate',
40 'edit_user_ssh_keys_add':
40 'edit_user_ssh_keys_add':
41 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/new',
41 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/new',
42 'edit_user_ssh_keys_delete':
42 'edit_user_ssh_keys_delete':
43 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/delete',
43 ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/delete',
44
44
45 }[name].format(**kwargs)
45 }[name].format(**kwargs)
46
46
47 if params:
47 if params:
48 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
48 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
49 return base_url
49 return base_url
50
50
51
51
52 class TestAdminUsersSshKeysView(TestController):
52 class TestAdminUsersSshKeysView(TestController):
53 INVALID_KEY = """\
53 INVALID_KEY = """\
54 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDk+77sjDzVeB6vevJsuZds1iNU5
54 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDk+77sjDzVeB6vevJsuZds1iNU5
55 LANOa5CU5G/9JYIA6RYsWWMO7mbsR82IUckdqOHmxSykfR1D1TdluyIpQLrwgH5kb
55 LANOa5CU5G/9JYIA6RYsWWMO7mbsR82IUckdqOHmxSykfR1D1TdluyIpQLrwgH5kb
56 n8FkVI8zBMCKakxowvN67B0R7b1BT4PPzW2JlOXei/m9W12ZY484VTow6/B+kf2Q8
56 n8FkVI8zBMCKakxowvN67B0R7b1BT4PPzW2JlOXei/m9W12ZY484VTow6/B+kf2Q8
57 cP8tmCJmKWZma5Em7OTUhvjyQVNz3v7HfeY5Hq0Ci4ECJ59hepFDabJvtAXg9XrI6
57 cP8tmCJmKWZma5Em7OTUhvjyQVNz3v7HfeY5Hq0Ci4ECJ59hepFDabJvtAXg9XrI6
58 jvdphZTc30I4fG8+hBHzpeFxUGvSGNtXPUbwaAY8j/oHYrTpMgkj6pUEFsiKfC5zP
58 jvdphZTc30I4fG8+hBHzpeFxUGvSGNtXPUbwaAY8j/oHYrTpMgkj6pUEFsiKfC5zP
59 qPFR5HyKTCHW0nFUJnZsbyFT5hMiF/hZkJc9A0ZbdSvJwCRQ/g3bmdL
59 qPFR5HyKTCHW0nFUJnZsbyFT5hMiF/hZkJc9A0ZbdSvJwCRQ/g3bmdL
60 your_email@example.com
60 your_email@example.com
61 """
61 """
62 VALID_KEY = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDk+77sjDzVeB6vev' \
62 VALID_KEY = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDk+77sjDzVeB6vev' \
63 'JsuZds1iNU5LANOa5CU5G/9JYIA6RYsWWMO7mbsR82IUckdqOHmxSy' \
63 'JsuZds1iNU5LANOa5CU5G/9JYIA6RYsWWMO7mbsR82IUckdqOHmxSy' \
64 'kfR1D1TdluyIpQLrwgH5kbn8FkVI8zBMCKakxowvN67B0R7b1BT4PP' \
64 'kfR1D1TdluyIpQLrwgH5kbn8FkVI8zBMCKakxowvN67B0R7b1BT4PP' \
65 'zW2JlOXei/m9W12ZY484VTow6/B+kf2Q8cP8tmCJmKWZma5Em7OTUh' \
65 'zW2JlOXei/m9W12ZY484VTow6/B+kf2Q8cP8tmCJmKWZma5Em7OTUh' \
66 'vjyQVNz3v7HfeY5Hq0Ci4ECJ59hepFDabJvtAXg9XrI6jvdphZTc30' \
66 'vjyQVNz3v7HfeY5Hq0Ci4ECJ59hepFDabJvtAXg9XrI6jvdphZTc30' \
67 'I4fG8+hBHzpeFxUGvSGNtXPUbwaAY8j/oHYrTpMgkj6pUEFsiKfC5zPq' \
67 'I4fG8+hBHzpeFxUGvSGNtXPUbwaAY8j/oHYrTpMgkj6pUEFsiKfC5zPq' \
68 'PFR5HyKTCHW0nFUJnZsbyFT5hMiF/hZkJc9A0ZbdSvJwCRQ/g3bmdL ' \
68 'PFR5HyKTCHW0nFUJnZsbyFT5hMiF/hZkJc9A0ZbdSvJwCRQ/g3bmdL ' \
69 'your_email@example.com'
69 'your_email@example.com'
70 FINGERPRINT = 'MD5:01:4f:ad:29:22:6e:01:37:c9:d2:52:26:52:b0:2d:93'
70
71
71 def test_ssh_keys_default_user(self):
72 def test_ssh_keys_default_user(self):
72 self.log_user()
73 self.log_user()
73 user = User.get_default_user()
74 user = User.get_default_user()
74 self.app.get(
75 self.app.get(
75 route_path('edit_user_ssh_keys', user_id=user.user_id),
76 route_path('edit_user_ssh_keys', user_id=user.user_id),
76 status=302)
77 status=302)
77
78
78 def test_add_ssh_key_error(self, user_util):
79 def test_add_ssh_key_error(self, user_util):
79 self.log_user()
80 self.log_user()
80 user = user_util.create_user()
81 user = user_util.create_user()
81 user_id = user.user_id
82 user_id = user.user_id
82
83
83 key_data = self.INVALID_KEY
84 key_data = self.INVALID_KEY
84
85
85 desc = 'MY SSH KEY'
86 desc = 'MY SSH KEY'
86 response = self.app.post(
87 response = self.app.post(
87 route_path('edit_user_ssh_keys_add', user_id=user_id),
88 route_path('edit_user_ssh_keys_add', user_id=user_id),
88 {'description': desc, 'key_data': key_data,
89 {'description': desc, 'key_data': key_data,
89 'csrf_token': self.csrf_token})
90 'csrf_token': self.csrf_token})
90 assert_session_flash(response, 'An error occurred during ssh '
91 assert_session_flash(response, 'An error occurred during ssh '
91 'key saving: Unable to decode the key')
92 'key saving: Unable to decode the key')
92
93
93 def test_ssh_key_duplicate(self, user_util):
94 def test_ssh_key_duplicate(self, user_util):
94 self.log_user()
95 self.log_user()
95 user = user_util.create_user()
96 user = user_util.create_user()
96 user_id = user.user_id
97 user_id = user.user_id
97
98
98 key_data = self.VALID_KEY
99 key_data = self.VALID_KEY
99
100
100 desc = 'MY SSH KEY'
101 desc = 'MY SSH KEY'
101 response = self.app.post(
102 response = self.app.post(
102 route_path('edit_user_ssh_keys_add', user_id=user_id),
103 route_path('edit_user_ssh_keys_add', user_id=user_id),
103 {'description': desc, 'key_data': key_data,
104 {'description': desc, 'key_data': key_data,
104 'csrf_token': self.csrf_token})
105 'csrf_token': self.csrf_token})
105 assert_session_flash(response, 'Ssh Key successfully created')
106 assert_session_flash(response, 'Ssh Key successfully created')
106 response.follow() # flush session flash
107 response.follow() # flush session flash
107
108
108 # add the same key AGAIN
109 # add the same key AGAIN
109 desc = 'MY SSH KEY'
110 desc = 'MY SSH KEY'
110 response = self.app.post(
111 response = self.app.post(
111 route_path('edit_user_ssh_keys_add', user_id=user_id),
112 route_path('edit_user_ssh_keys_add', user_id=user_id),
112 {'description': desc, 'key_data': key_data,
113 {'description': desc, 'key_data': key_data,
113 'csrf_token': self.csrf_token})
114 'csrf_token': self.csrf_token})
115
116 err = 'Such key with fingerprint `{}` already exists, ' \
117 'please use a different one'.format(self.FINGERPRINT)
114 assert_session_flash(response, 'An error occurred during ssh key '
118 assert_session_flash(response, 'An error occurred during ssh key '
115 'saving: Such key already exists, '
119 'saving: {}'.format(err))
116 'please use a different one')
117
120
118 def test_add_ssh_key(self, user_util):
121 def test_add_ssh_key(self, user_util):
119 self.log_user()
122 self.log_user()
120 user = user_util.create_user()
123 user = user_util.create_user()
121 user_id = user.user_id
124 user_id = user.user_id
122
125
123 key_data = self.VALID_KEY
126 key_data = self.VALID_KEY
124
127
125 desc = 'MY SSH KEY'
128 desc = 'MY SSH KEY'
126 response = self.app.post(
129 response = self.app.post(
127 route_path('edit_user_ssh_keys_add', user_id=user_id),
130 route_path('edit_user_ssh_keys_add', user_id=user_id),
128 {'description': desc, 'key_data': key_data,
131 {'description': desc, 'key_data': key_data,
129 'csrf_token': self.csrf_token})
132 'csrf_token': self.csrf_token})
130 assert_session_flash(response, 'Ssh Key successfully created')
133 assert_session_flash(response, 'Ssh Key successfully created')
131
134
132 response = response.follow()
135 response = response.follow()
133 response.mustcontain(desc)
136 response.mustcontain(desc)
134
137
135 def test_delete_ssh_key(self, user_util):
138 def test_delete_ssh_key(self, user_util):
136 self.log_user()
139 self.log_user()
137 user = user_util.create_user()
140 user = user_util.create_user()
138 user_id = user.user_id
141 user_id = user.user_id
139
142
140 key_data = self.VALID_KEY
143 key_data = self.VALID_KEY
141
144
142 desc = 'MY SSH KEY'
145 desc = 'MY SSH KEY'
143 response = self.app.post(
146 response = self.app.post(
144 route_path('edit_user_ssh_keys_add', user_id=user_id),
147 route_path('edit_user_ssh_keys_add', user_id=user_id),
145 {'description': desc, 'key_data': key_data,
148 {'description': desc, 'key_data': key_data,
146 'csrf_token': self.csrf_token})
149 'csrf_token': self.csrf_token})
147 assert_session_flash(response, 'Ssh Key successfully created')
150 assert_session_flash(response, 'Ssh Key successfully created')
148 response = response.follow() # flush the Session flash
151 response = response.follow() # flush the Session flash
149
152
150 # now delete our key
153 # now delete our key
151 keys = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).all()
154 keys = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).all()
152 assert 1 == len(keys)
155 assert 1 == len(keys)
153
156
154 response = self.app.post(
157 response = self.app.post(
155 route_path('edit_user_ssh_keys_delete', user_id=user_id),
158 route_path('edit_user_ssh_keys_delete', user_id=user_id),
156 {'del_ssh_key': keys[0].ssh_key_id,
159 {'del_ssh_key': keys[0].ssh_key_id,
157 'csrf_token': self.csrf_token})
160 'csrf_token': self.csrf_token})
158
161
159 assert_session_flash(response, 'Ssh key successfully deleted')
162 assert_session_flash(response, 'Ssh key successfully deleted')
160 keys = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).all()
163 keys = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).all()
161 assert 0 == len(keys)
164 assert 0 == len(keys)
162
165
163 def test_generate_keypair(self, user_util):
166 def test_generate_keypair(self, user_util):
164 self.log_user()
167 self.log_user()
165 user = user_util.create_user()
168 user = user_util.create_user()
166 user_id = user.user_id
169 user_id = user.user_id
167
170
168 response = self.app.get(
171 response = self.app.get(
169 route_path('edit_user_ssh_keys_generate_keypair', user_id=user_id))
172 route_path('edit_user_ssh_keys_generate_keypair', user_id=user_id))
170
173
171 response.mustcontain('Private key')
174 response.mustcontain('Private key')
172 response.mustcontain('Public key')
175 response.mustcontain('Public key')
173 response.mustcontain('-----BEGIN RSA PRIVATE KEY-----')
176 response.mustcontain('-----BEGIN RSA PRIVATE KEY-----')
@@ -1,133 +1,171 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 import psutil
23 import psutil
24 import signal
24 import signal
25 from pyramid.view import view_config
25 from pyramid.view import view_config
26
26
27 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps.admin.navigation import navigation_list
28 from rhodecode.apps.admin.navigation import navigation_list
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
30 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
31 from rhodecode.lib.utils2 import safe_int
31 from rhodecode.lib.utils2 import safe_int, StrictAttributeDict
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
35
35
36 class AdminProcessManagementView(BaseAppView):
36 class AdminProcessManagementView(BaseAppView):
37 def load_default_context(self):
37 def load_default_context(self):
38 c = self._get_local_tmpl_context()
38 c = self._get_local_tmpl_context()
39 return c
39
40
40 return c
41 def _format_proc(self, proc, with_children=False):
42 try:
43 mem = proc.memory_info()
44 proc_formatted = StrictAttributeDict({
45 'pid': proc.pid,
46 'name': proc.name(),
47 'mem_rss': mem.rss,
48 'mem_vms': mem.vms,
49 'cpu_percent': proc.cpu_percent(),
50 'create_time': proc.create_time(),
51 'cmd': ' '.join(proc.cmdline()),
52 })
53
54 if with_children:
55 proc_formatted.update({
56 'children': [self._format_proc(x)
57 for x in proc.children(recursive=True)]
58 })
59 except Exception:
60 log.exception('Failed to load proc')
61 proc_formatted = None
62 return proc_formatted
63
64 def get_processes(self):
65 proc_list = []
66 for p in psutil.process_iter():
67 if 'gunicorn' in p.name():
68 proc = self._format_proc(p, with_children=True)
69 if proc:
70 proc_list.append(proc)
71
72 return proc_list
41
73
42 @LoginRequired()
74 @LoginRequired()
43 @HasPermissionAllDecorator('hg.admin')
75 @HasPermissionAllDecorator('hg.admin')
44 @view_config(
76 @view_config(
45 route_name='admin_settings_process_management', request_method='GET',
77 route_name='admin_settings_process_management', request_method='GET',
46 renderer='rhodecode:templates/admin/settings/settings.mako')
78 renderer='rhodecode:templates/admin/settings/settings.mako')
47 def process_management(self):
79 def process_management(self):
48 _ = self.request.translate
80 _ = self.request.translate
49 c = self.load_default_context()
81 c = self.load_default_context()
50
82
51 c.active = 'process_management'
83 c.active = 'process_management'
52 c.navlist = navigation_list(self.request)
84 c.navlist = navigation_list(self.request)
53 c.gunicorn_processes = (
85 c.gunicorn_processes = self.get_processes()
54 p for p in psutil.process_iter() if 'gunicorn' in p.name())
55 return self._get_template_context(c)
86 return self._get_template_context(c)
56
87
57 @LoginRequired()
88 @LoginRequired()
58 @HasPermissionAllDecorator('hg.admin')
89 @HasPermissionAllDecorator('hg.admin')
59 @view_config(
90 @view_config(
60 route_name='admin_settings_process_management_data', request_method='GET',
91 route_name='admin_settings_process_management_data', request_method='GET',
61 renderer='rhodecode:templates/admin/settings/settings_process_management_data.mako')
92 renderer='rhodecode:templates/admin/settings/settings_process_management_data.mako')
62 def process_management_data(self):
93 def process_management_data(self):
63 _ = self.request.translate
94 _ = self.request.translate
64 c = self.load_default_context()
95 c = self.load_default_context()
65 c.gunicorn_processes = (
96 c.gunicorn_processes = self.get_processes()
66 p for p in psutil.process_iter() if 'gunicorn' in p.name())
67 return self._get_template_context(c)
97 return self._get_template_context(c)
68
98
69 @LoginRequired()
99 @LoginRequired()
70 @HasPermissionAllDecorator('hg.admin')
100 @HasPermissionAllDecorator('hg.admin')
71 @CSRFRequired()
101 @CSRFRequired()
72 @view_config(
102 @view_config(
73 route_name='admin_settings_process_management_signal',
103 route_name='admin_settings_process_management_signal',
74 request_method='POST', renderer='json_ext')
104 request_method='POST', renderer='json_ext')
75 def process_management_signal(self):
105 def process_management_signal(self):
76 pids = self.request.json.get('pids', [])
106 pids = self.request.json.get('pids', [])
77 result = []
107 result = []
108
78 def on_terminate(proc):
109 def on_terminate(proc):
79 msg = "process `PID:{}` terminated with exit code {}".format(
110 msg = "process `PID:{}` terminated with exit code {}".format(
80 proc.pid, proc.returncode)
111 proc.pid, proc.returncode or 0)
81 result.append(msg)
112 result.append(msg)
82
113
83 procs = []
114 procs = []
84 for pid in pids:
115 for pid in pids:
85 pid = safe_int(pid)
116 pid = safe_int(pid)
86 if pid:
117 if pid:
87 try:
118 try:
88 proc = psutil.Process(pid)
119 proc = psutil.Process(pid)
89 except psutil.NoSuchProcess:
120 except psutil.NoSuchProcess:
90 continue
121 continue
91
122
92 children = proc.children(recursive=True)
123 children = proc.children(recursive=True)
93 if children:
124 if children:
94 print('Wont kill Master Process')
125 log.warning('Wont kill Master Process')
95 else:
126 else:
96 procs.append(proc)
127 procs.append(proc)
97
128
98 for p in procs:
129 for p in procs:
99 p.terminate()
130 try:
131 p.terminate()
132 except psutil.AccessDenied as e:
133 log.warning('Access denied: {}'.format(e))
134
100 gone, alive = psutil.wait_procs(procs, timeout=10, callback=on_terminate)
135 gone, alive = psutil.wait_procs(procs, timeout=10, callback=on_terminate)
101 for p in alive:
136 for p in alive:
102 p.kill()
137 try:
138 p.kill()
139 except psutil.AccessDenied as e:
140 log.warning('Access denied: {}'.format(e))
103
141
104 return {'result': result}
142 return {'result': result}
105
143
106 @LoginRequired()
144 @LoginRequired()
107 @HasPermissionAllDecorator('hg.admin')
145 @HasPermissionAllDecorator('hg.admin')
108 @CSRFRequired()
146 @CSRFRequired()
109 @view_config(
147 @view_config(
110 route_name='admin_settings_process_management_master_signal',
148 route_name='admin_settings_process_management_master_signal',
111 request_method='POST', renderer='json_ext')
149 request_method='POST', renderer='json_ext')
112 def process_management_master_signal(self):
150 def process_management_master_signal(self):
113 pid_data = self.request.json.get('pid_data', {})
151 pid_data = self.request.json.get('pid_data', {})
114 pid = safe_int(pid_data['pid'])
152 pid = safe_int(pid_data['pid'])
115 action = pid_data['action']
153 action = pid_data['action']
116 if pid:
154 if pid:
117 try:
155 try:
118 proc = psutil.Process(pid)
156 proc = psutil.Process(pid)
119 except psutil.NoSuchProcess:
157 except psutil.NoSuchProcess:
120 return {'result': 'failure_no_such_process'}
158 return {'result': 'failure_no_such_process'}
121
159
122 children = proc.children(recursive=True)
160 children = proc.children(recursive=True)
123 if children:
161 if children:
124 # master process
162 # master process
125 if action == '+' and len(children) <= 20:
163 if action == '+' and len(children) <= 20:
126 proc.send_signal(signal.SIGTTIN)
164 proc.send_signal(signal.SIGTTIN)
127 elif action == '-' and len(children) >= 2:
165 elif action == '-' and len(children) >= 2:
128 proc.send_signal(signal.SIGTTOU)
166 proc.send_signal(signal.SIGTTOU)
129 else:
167 else:
130 return {'result': 'failure_wrong_action'}
168 return {'result': 'failure_wrong_action'}
131 return {'result': 'success'}
169 return {'result': 'success'}
132
170
133 return {'result': 'failure_not_master'}
171 return {'result': 'failure_not_master'}
@@ -1,764 +1,781 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23 import collections
23 import collections
24
24
25 import datetime
25 import datetime
26 import formencode
26 import formencode
27 import formencode.htmlfill
27 import formencode.htmlfill
28
28
29 import rhodecode
29 import rhodecode
30 from pyramid.view import view_config
30 from pyramid.view import view_config
31 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
31 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
32 from pyramid.renderers import render
32 from pyramid.renderers import render
33 from pyramid.response import Response
33 from pyramid.response import Response
34
34
35 from rhodecode.apps._base import BaseAppView
35 from rhodecode.apps._base import BaseAppView
36 from rhodecode.apps.admin.navigation import navigation_list
36 from rhodecode.apps.admin.navigation import navigation_list
37 from rhodecode.apps.svn_support.config_keys import generate_config
37 from rhodecode.apps.svn_support.config_keys import generate_config
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import (
39 from rhodecode.lib.auth import (
40 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
40 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
41 from rhodecode.lib.celerylib import tasks, run_task
41 from rhodecode.lib.celerylib import tasks, run_task
42 from rhodecode.lib.utils import repo2db_mapper
42 from rhodecode.lib.utils import repo2db_mapper
43 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
43 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
44 from rhodecode.lib.index import searcher_from_config
44 from rhodecode.lib.index import searcher_from_config
45
45
46 from rhodecode.model.db import RhodeCodeUi, Repository
46 from rhodecode.model.db import RhodeCodeUi, Repository
47 from rhodecode.model.forms import (ApplicationSettingsForm,
47 from rhodecode.model.forms import (ApplicationSettingsForm,
48 ApplicationUiSettingsForm, ApplicationVisualisationForm,
48 ApplicationUiSettingsForm, ApplicationVisualisationForm,
49 LabsSettingsForm, IssueTrackerPatternsForm)
49 LabsSettingsForm, IssueTrackerPatternsForm)
50 from rhodecode.model.repo_group import RepoGroupModel
50 from rhodecode.model.repo_group import RepoGroupModel
51
51
52 from rhodecode.model.scm import ScmModel
52 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.notification import EmailNotificationModel
53 from rhodecode.model.notification import EmailNotificationModel
54 from rhodecode.model.meta import Session
54 from rhodecode.model.meta import Session
55 from rhodecode.model.settings import (
55 from rhodecode.model.settings import (
56 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
56 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
57 SettingsModel)
57 SettingsModel)
58
58
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 class AdminSettingsView(BaseAppView):
63 class AdminSettingsView(BaseAppView):
64
64
65 def load_default_context(self):
65 def load_default_context(self):
66 c = self._get_local_tmpl_context()
66 c = self._get_local_tmpl_context()
67 c.labs_active = str2bool(
67 c.labs_active = str2bool(
68 rhodecode.CONFIG.get('labs_settings_active', 'true'))
68 rhodecode.CONFIG.get('labs_settings_active', 'true'))
69 c.navlist = navigation_list(self.request)
69 c.navlist = navigation_list(self.request)
70
70
71 return c
71 return c
72
72
73 @classmethod
73 @classmethod
74 def _get_ui_settings(cls):
74 def _get_ui_settings(cls):
75 ret = RhodeCodeUi.query().all()
75 ret = RhodeCodeUi.query().all()
76
76
77 if not ret:
77 if not ret:
78 raise Exception('Could not get application ui settings !')
78 raise Exception('Could not get application ui settings !')
79 settings = {}
79 settings = {}
80 for each in ret:
80 for each in ret:
81 k = each.ui_key
81 k = each.ui_key
82 v = each.ui_value
82 v = each.ui_value
83 if k == '/':
83 if k == '/':
84 k = 'root_path'
84 k = 'root_path'
85
85
86 if k in ['push_ssl', 'publish', 'enabled']:
86 if k in ['push_ssl', 'publish', 'enabled']:
87 v = str2bool(v)
87 v = str2bool(v)
88
88
89 if k.find('.') != -1:
89 if k.find('.') != -1:
90 k = k.replace('.', '_')
90 k = k.replace('.', '_')
91
91
92 if each.ui_section in ['hooks', 'extensions']:
92 if each.ui_section in ['hooks', 'extensions']:
93 v = each.ui_active
93 v = each.ui_active
94
94
95 settings[each.ui_section + '_' + k] = v
95 settings[each.ui_section + '_' + k] = v
96 return settings
96 return settings
97
97
98 @classmethod
98 @classmethod
99 def _form_defaults(cls):
99 def _form_defaults(cls):
100 defaults = SettingsModel().get_all_settings()
100 defaults = SettingsModel().get_all_settings()
101 defaults.update(cls._get_ui_settings())
101 defaults.update(cls._get_ui_settings())
102
102
103 defaults.update({
103 defaults.update({
104 'new_svn_branch': '',
104 'new_svn_branch': '',
105 'new_svn_tag': '',
105 'new_svn_tag': '',
106 })
106 })
107 return defaults
107 return defaults
108
108
109 @LoginRequired()
109 @LoginRequired()
110 @HasPermissionAllDecorator('hg.admin')
110 @HasPermissionAllDecorator('hg.admin')
111 @view_config(
111 @view_config(
112 route_name='admin_settings_vcs', request_method='GET',
112 route_name='admin_settings_vcs', request_method='GET',
113 renderer='rhodecode:templates/admin/settings/settings.mako')
113 renderer='rhodecode:templates/admin/settings/settings.mako')
114 def settings_vcs(self):
114 def settings_vcs(self):
115 c = self.load_default_context()
115 c = self.load_default_context()
116 c.active = 'vcs'
116 c.active = 'vcs'
117 model = VcsSettingsModel()
117 model = VcsSettingsModel()
118 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
118 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
119 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
119 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
120
120
121 settings = self.request.registry.settings
121 settings = self.request.registry.settings
122 c.svn_proxy_generate_config = settings[generate_config]
122 c.svn_proxy_generate_config = settings[generate_config]
123
123
124 defaults = self._form_defaults()
124 defaults = self._form_defaults()
125
125
126 model.create_largeobjects_dirs_if_needed(defaults['paths_root_path'])
126 model.create_largeobjects_dirs_if_needed(defaults['paths_root_path'])
127
127
128 data = render('rhodecode:templates/admin/settings/settings.mako',
128 data = render('rhodecode:templates/admin/settings/settings.mako',
129 self._get_template_context(c), self.request)
129 self._get_template_context(c), self.request)
130 html = formencode.htmlfill.render(
130 html = formencode.htmlfill.render(
131 data,
131 data,
132 defaults=defaults,
132 defaults=defaults,
133 encoding="UTF-8",
133 encoding="UTF-8",
134 force_defaults=False
134 force_defaults=False
135 )
135 )
136 return Response(html)
136 return Response(html)
137
137
138 @LoginRequired()
138 @LoginRequired()
139 @HasPermissionAllDecorator('hg.admin')
139 @HasPermissionAllDecorator('hg.admin')
140 @CSRFRequired()
140 @CSRFRequired()
141 @view_config(
141 @view_config(
142 route_name='admin_settings_vcs_update', request_method='POST',
142 route_name='admin_settings_vcs_update', request_method='POST',
143 renderer='rhodecode:templates/admin/settings/settings.mako')
143 renderer='rhodecode:templates/admin/settings/settings.mako')
144 def settings_vcs_update(self):
144 def settings_vcs_update(self):
145 _ = self.request.translate
145 _ = self.request.translate
146 c = self.load_default_context()
146 c = self.load_default_context()
147 c.active = 'vcs'
147 c.active = 'vcs'
148
148
149 model = VcsSettingsModel()
149 model = VcsSettingsModel()
150 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
150 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
151 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
151 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
152
152
153 settings = self.request.registry.settings
153 settings = self.request.registry.settings
154 c.svn_proxy_generate_config = settings[generate_config]
154 c.svn_proxy_generate_config = settings[generate_config]
155
155
156 application_form = ApplicationUiSettingsForm(self.request.translate)()
156 application_form = ApplicationUiSettingsForm(self.request.translate)()
157
157
158 try:
158 try:
159 form_result = application_form.to_python(dict(self.request.POST))
159 form_result = application_form.to_python(dict(self.request.POST))
160 except formencode.Invalid as errors:
160 except formencode.Invalid as errors:
161 h.flash(
161 h.flash(
162 _("Some form inputs contain invalid data."),
162 _("Some form inputs contain invalid data."),
163 category='error')
163 category='error')
164 data = render('rhodecode:templates/admin/settings/settings.mako',
164 data = render('rhodecode:templates/admin/settings/settings.mako',
165 self._get_template_context(c), self.request)
165 self._get_template_context(c), self.request)
166 html = formencode.htmlfill.render(
166 html = formencode.htmlfill.render(
167 data,
167 data,
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 force_defaults=False
172 force_defaults=False
173 )
173 )
174 return Response(html)
174 return Response(html)
175
175
176 try:
176 try:
177 if c.visual.allow_repo_location_change:
177 if c.visual.allow_repo_location_change:
178 model.update_global_path_setting(
178 model.update_global_path_setting(
179 form_result['paths_root_path'])
179 form_result['paths_root_path'])
180
180
181 model.update_global_ssl_setting(form_result['web_push_ssl'])
181 model.update_global_ssl_setting(form_result['web_push_ssl'])
182 model.update_global_hook_settings(form_result)
182 model.update_global_hook_settings(form_result)
183
183
184 model.create_or_update_global_svn_settings(form_result)
184 model.create_or_update_global_svn_settings(form_result)
185 model.create_or_update_global_hg_settings(form_result)
185 model.create_or_update_global_hg_settings(form_result)
186 model.create_or_update_global_git_settings(form_result)
186 model.create_or_update_global_git_settings(form_result)
187 model.create_or_update_global_pr_settings(form_result)
187 model.create_or_update_global_pr_settings(form_result)
188 except Exception:
188 except Exception:
189 log.exception("Exception while updating settings")
189 log.exception("Exception while updating settings")
190 h.flash(_('Error occurred during updating '
190 h.flash(_('Error occurred during updating '
191 'application settings'), category='error')
191 'application settings'), category='error')
192 else:
192 else:
193 Session().commit()
193 Session().commit()
194 h.flash(_('Updated VCS settings'), category='success')
194 h.flash(_('Updated VCS settings'), category='success')
195 raise HTTPFound(h.route_path('admin_settings_vcs'))
195 raise HTTPFound(h.route_path('admin_settings_vcs'))
196
196
197 data = render('rhodecode:templates/admin/settings/settings.mako',
197 data = render('rhodecode:templates/admin/settings/settings.mako',
198 self._get_template_context(c), self.request)
198 self._get_template_context(c), self.request)
199 html = formencode.htmlfill.render(
199 html = formencode.htmlfill.render(
200 data,
200 data,
201 defaults=self._form_defaults(),
201 defaults=self._form_defaults(),
202 encoding="UTF-8",
202 encoding="UTF-8",
203 force_defaults=False
203 force_defaults=False
204 )
204 )
205 return Response(html)
205 return Response(html)
206
206
207 @LoginRequired()
207 @LoginRequired()
208 @HasPermissionAllDecorator('hg.admin')
208 @HasPermissionAllDecorator('hg.admin')
209 @CSRFRequired()
209 @CSRFRequired()
210 @view_config(
210 @view_config(
211 route_name='admin_settings_vcs_svn_pattern_delete', request_method='POST',
211 route_name='admin_settings_vcs_svn_pattern_delete', request_method='POST',
212 renderer='json_ext', xhr=True)
212 renderer='json_ext', xhr=True)
213 def settings_vcs_delete_svn_pattern(self):
213 def settings_vcs_delete_svn_pattern(self):
214 delete_pattern_id = self.request.POST.get('delete_svn_pattern')
214 delete_pattern_id = self.request.POST.get('delete_svn_pattern')
215 model = VcsSettingsModel()
215 model = VcsSettingsModel()
216 try:
216 try:
217 model.delete_global_svn_pattern(delete_pattern_id)
217 model.delete_global_svn_pattern(delete_pattern_id)
218 except SettingNotFound:
218 except SettingNotFound:
219 log.exception(
219 log.exception(
220 'Failed to delete svn_pattern with id %s', delete_pattern_id)
220 'Failed to delete svn_pattern with id %s', delete_pattern_id)
221 raise HTTPNotFound()
221 raise HTTPNotFound()
222
222
223 Session().commit()
223 Session().commit()
224 return True
224 return True
225
225
226 @LoginRequired()
226 @LoginRequired()
227 @HasPermissionAllDecorator('hg.admin')
227 @HasPermissionAllDecorator('hg.admin')
228 @view_config(
228 @view_config(
229 route_name='admin_settings_mapping', request_method='GET',
229 route_name='admin_settings_mapping', request_method='GET',
230 renderer='rhodecode:templates/admin/settings/settings.mako')
230 renderer='rhodecode:templates/admin/settings/settings.mako')
231 def settings_mapping(self):
231 def settings_mapping(self):
232 c = self.load_default_context()
232 c = self.load_default_context()
233 c.active = 'mapping'
233 c.active = 'mapping'
234
234
235 data = render('rhodecode:templates/admin/settings/settings.mako',
235 data = render('rhodecode:templates/admin/settings/settings.mako',
236 self._get_template_context(c), self.request)
236 self._get_template_context(c), self.request)
237 html = formencode.htmlfill.render(
237 html = formencode.htmlfill.render(
238 data,
238 data,
239 defaults=self._form_defaults(),
239 defaults=self._form_defaults(),
240 encoding="UTF-8",
240 encoding="UTF-8",
241 force_defaults=False
241 force_defaults=False
242 )
242 )
243 return Response(html)
243 return Response(html)
244
244
245 @LoginRequired()
245 @LoginRequired()
246 @HasPermissionAllDecorator('hg.admin')
246 @HasPermissionAllDecorator('hg.admin')
247 @CSRFRequired()
247 @CSRFRequired()
248 @view_config(
248 @view_config(
249 route_name='admin_settings_mapping_update', request_method='POST',
249 route_name='admin_settings_mapping_update', request_method='POST',
250 renderer='rhodecode:templates/admin/settings/settings.mako')
250 renderer='rhodecode:templates/admin/settings/settings.mako')
251 def settings_mapping_update(self):
251 def settings_mapping_update(self):
252 _ = self.request.translate
252 _ = self.request.translate
253 c = self.load_default_context()
253 c = self.load_default_context()
254 c.active = 'mapping'
254 c.active = 'mapping'
255 rm_obsolete = self.request.POST.get('destroy', False)
255 rm_obsolete = self.request.POST.get('destroy', False)
256 invalidate_cache = self.request.POST.get('invalidate', False)
256 invalidate_cache = self.request.POST.get('invalidate', False)
257 log.debug(
257 log.debug(
258 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
258 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
259
259
260 if invalidate_cache:
260 if invalidate_cache:
261 log.debug('invalidating all repositories cache')
261 log.debug('invalidating all repositories cache')
262 for repo in Repository.get_all():
262 for repo in Repository.get_all():
263 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
263 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
264
264
265 filesystem_repos = ScmModel().repo_scan()
265 filesystem_repos = ScmModel().repo_scan()
266 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
266 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
267 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
267 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
268 h.flash(_('Repositories successfully '
268 h.flash(_('Repositories successfully '
269 'rescanned added: %s ; removed: %s') %
269 'rescanned added: %s ; removed: %s') %
270 (_repr(added), _repr(removed)),
270 (_repr(added), _repr(removed)),
271 category='success')
271 category='success')
272 raise HTTPFound(h.route_path('admin_settings_mapping'))
272 raise HTTPFound(h.route_path('admin_settings_mapping'))
273
273
274 @LoginRequired()
274 @LoginRequired()
275 @HasPermissionAllDecorator('hg.admin')
275 @HasPermissionAllDecorator('hg.admin')
276 @view_config(
276 @view_config(
277 route_name='admin_settings', request_method='GET',
277 route_name='admin_settings', request_method='GET',
278 renderer='rhodecode:templates/admin/settings/settings.mako')
278 renderer='rhodecode:templates/admin/settings/settings.mako')
279 @view_config(
279 @view_config(
280 route_name='admin_settings_global', request_method='GET',
280 route_name='admin_settings_global', request_method='GET',
281 renderer='rhodecode:templates/admin/settings/settings.mako')
281 renderer='rhodecode:templates/admin/settings/settings.mako')
282 def settings_global(self):
282 def settings_global(self):
283 c = self.load_default_context()
283 c = self.load_default_context()
284 c.active = 'global'
284 c.active = 'global'
285 c.personal_repo_group_default_pattern = RepoGroupModel()\
285 c.personal_repo_group_default_pattern = RepoGroupModel()\
286 .get_personal_group_name_pattern()
286 .get_personal_group_name_pattern()
287
287
288 data = render('rhodecode:templates/admin/settings/settings.mako',
288 data = render('rhodecode:templates/admin/settings/settings.mako',
289 self._get_template_context(c), self.request)
289 self._get_template_context(c), self.request)
290 html = formencode.htmlfill.render(
290 html = formencode.htmlfill.render(
291 data,
291 data,
292 defaults=self._form_defaults(),
292 defaults=self._form_defaults(),
293 encoding="UTF-8",
293 encoding="UTF-8",
294 force_defaults=False
294 force_defaults=False
295 )
295 )
296 return Response(html)
296 return Response(html)
297
297
298 @LoginRequired()
298 @LoginRequired()
299 @HasPermissionAllDecorator('hg.admin')
299 @HasPermissionAllDecorator('hg.admin')
300 @CSRFRequired()
300 @CSRFRequired()
301 @view_config(
301 @view_config(
302 route_name='admin_settings_update', request_method='POST',
302 route_name='admin_settings_update', request_method='POST',
303 renderer='rhodecode:templates/admin/settings/settings.mako')
303 renderer='rhodecode:templates/admin/settings/settings.mako')
304 @view_config(
304 @view_config(
305 route_name='admin_settings_global_update', request_method='POST',
305 route_name='admin_settings_global_update', request_method='POST',
306 renderer='rhodecode:templates/admin/settings/settings.mako')
306 renderer='rhodecode:templates/admin/settings/settings.mako')
307 def settings_global_update(self):
307 def settings_global_update(self):
308 _ = self.request.translate
308 _ = self.request.translate
309 c = self.load_default_context()
309 c = self.load_default_context()
310 c.active = 'global'
310 c.active = 'global'
311 c.personal_repo_group_default_pattern = RepoGroupModel()\
311 c.personal_repo_group_default_pattern = RepoGroupModel()\
312 .get_personal_group_name_pattern()
312 .get_personal_group_name_pattern()
313 application_form = ApplicationSettingsForm(self.request.translate)()
313 application_form = ApplicationSettingsForm(self.request.translate)()
314 try:
314 try:
315 form_result = application_form.to_python(dict(self.request.POST))
315 form_result = application_form.to_python(dict(self.request.POST))
316 except formencode.Invalid as errors:
316 except formencode.Invalid as errors:
317 h.flash(
318 _("Some form inputs contain invalid data."),
319 category='error')
317 data = render('rhodecode:templates/admin/settings/settings.mako',
320 data = render('rhodecode:templates/admin/settings/settings.mako',
318 self._get_template_context(c), self.request)
321 self._get_template_context(c), self.request)
319 html = formencode.htmlfill.render(
322 html = formencode.htmlfill.render(
320 data,
323 data,
321 defaults=errors.value,
324 defaults=errors.value,
322 errors=errors.error_dict or {},
325 errors=errors.error_dict or {},
323 prefix_error=False,
326 prefix_error=False,
324 encoding="UTF-8",
327 encoding="UTF-8",
325 force_defaults=False
328 force_defaults=False
326 )
329 )
327 return Response(html)
330 return Response(html)
328
331
329 settings = [
332 settings = [
330 ('title', 'rhodecode_title', 'unicode'),
333 ('title', 'rhodecode_title', 'unicode'),
331 ('realm', 'rhodecode_realm', 'unicode'),
334 ('realm', 'rhodecode_realm', 'unicode'),
332 ('pre_code', 'rhodecode_pre_code', 'unicode'),
335 ('pre_code', 'rhodecode_pre_code', 'unicode'),
333 ('post_code', 'rhodecode_post_code', 'unicode'),
336 ('post_code', 'rhodecode_post_code', 'unicode'),
334 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
337 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
335 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
338 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
336 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
339 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
337 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
340 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
338 ]
341 ]
339 try:
342 try:
340 for setting, form_key, type_ in settings:
343 for setting, form_key, type_ in settings:
341 sett = SettingsModel().create_or_update_setting(
344 sett = SettingsModel().create_or_update_setting(
342 setting, form_result[form_key], type_)
345 setting, form_result[form_key], type_)
343 Session().add(sett)
346 Session().add(sett)
344
347
345 Session().commit()
348 Session().commit()
346 SettingsModel().invalidate_settings_cache()
349 SettingsModel().invalidate_settings_cache()
347 h.flash(_('Updated application settings'), category='success')
350 h.flash(_('Updated application settings'), category='success')
348 except Exception:
351 except Exception:
349 log.exception("Exception while updating application settings")
352 log.exception("Exception while updating application settings")
350 h.flash(
353 h.flash(
351 _('Error occurred during updating application settings'),
354 _('Error occurred during updating application settings'),
352 category='error')
355 category='error')
353
356
354 raise HTTPFound(h.route_path('admin_settings_global'))
357 raise HTTPFound(h.route_path('admin_settings_global'))
355
358
356 @LoginRequired()
359 @LoginRequired()
357 @HasPermissionAllDecorator('hg.admin')
360 @HasPermissionAllDecorator('hg.admin')
358 @view_config(
361 @view_config(
359 route_name='admin_settings_visual', request_method='GET',
362 route_name='admin_settings_visual', request_method='GET',
360 renderer='rhodecode:templates/admin/settings/settings.mako')
363 renderer='rhodecode:templates/admin/settings/settings.mako')
361 def settings_visual(self):
364 def settings_visual(self):
362 c = self.load_default_context()
365 c = self.load_default_context()
363 c.active = 'visual'
366 c.active = 'visual'
364
367
365 data = render('rhodecode:templates/admin/settings/settings.mako',
368 data = render('rhodecode:templates/admin/settings/settings.mako',
366 self._get_template_context(c), self.request)
369 self._get_template_context(c), self.request)
367 html = formencode.htmlfill.render(
370 html = formencode.htmlfill.render(
368 data,
371 data,
369 defaults=self._form_defaults(),
372 defaults=self._form_defaults(),
370 encoding="UTF-8",
373 encoding="UTF-8",
371 force_defaults=False
374 force_defaults=False
372 )
375 )
373 return Response(html)
376 return Response(html)
374
377
375 @LoginRequired()
378 @LoginRequired()
376 @HasPermissionAllDecorator('hg.admin')
379 @HasPermissionAllDecorator('hg.admin')
377 @CSRFRequired()
380 @CSRFRequired()
378 @view_config(
381 @view_config(
379 route_name='admin_settings_visual_update', request_method='POST',
382 route_name='admin_settings_visual_update', request_method='POST',
380 renderer='rhodecode:templates/admin/settings/settings.mako')
383 renderer='rhodecode:templates/admin/settings/settings.mako')
381 def settings_visual_update(self):
384 def settings_visual_update(self):
382 _ = self.request.translate
385 _ = self.request.translate
383 c = self.load_default_context()
386 c = self.load_default_context()
384 c.active = 'visual'
387 c.active = 'visual'
385 application_form = ApplicationVisualisationForm(self.request.translate)()
388 application_form = ApplicationVisualisationForm(self.request.translate)()
386 try:
389 try:
387 form_result = application_form.to_python(dict(self.request.POST))
390 form_result = application_form.to_python(dict(self.request.POST))
388 except formencode.Invalid as errors:
391 except formencode.Invalid as errors:
392 h.flash(
393 _("Some form inputs contain invalid data."),
394 category='error')
389 data = render('rhodecode:templates/admin/settings/settings.mako',
395 data = render('rhodecode:templates/admin/settings/settings.mako',
390 self._get_template_context(c), self.request)
396 self._get_template_context(c), self.request)
391 html = formencode.htmlfill.render(
397 html = formencode.htmlfill.render(
392 data,
398 data,
393 defaults=errors.value,
399 defaults=errors.value,
394 errors=errors.error_dict or {},
400 errors=errors.error_dict or {},
395 prefix_error=False,
401 prefix_error=False,
396 encoding="UTF-8",
402 encoding="UTF-8",
397 force_defaults=False
403 force_defaults=False
398 )
404 )
399 return Response(html)
405 return Response(html)
400
406
401 try:
407 try:
402 settings = [
408 settings = [
403 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
409 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
404 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
410 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
405 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
411 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
406 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
412 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
407 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
413 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
408 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
414 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
409 ('show_version', 'rhodecode_show_version', 'bool'),
415 ('show_version', 'rhodecode_show_version', 'bool'),
410 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
416 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
411 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
417 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
412 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
418 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
413 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
419 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
414 ('clone_uri_ssh_tmpl', 'rhodecode_clone_uri_ssh_tmpl', 'unicode'),
420 ('clone_uri_ssh_tmpl', 'rhodecode_clone_uri_ssh_tmpl', 'unicode'),
415 ('support_url', 'rhodecode_support_url', 'unicode'),
421 ('support_url', 'rhodecode_support_url', 'unicode'),
416 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
422 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
417 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
423 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
418 ]
424 ]
419 for setting, form_key, type_ in settings:
425 for setting, form_key, type_ in settings:
420 sett = SettingsModel().create_or_update_setting(
426 sett = SettingsModel().create_or_update_setting(
421 setting, form_result[form_key], type_)
427 setting, form_result[form_key], type_)
422 Session().add(sett)
428 Session().add(sett)
423
429
424 Session().commit()
430 Session().commit()
425 SettingsModel().invalidate_settings_cache()
431 SettingsModel().invalidate_settings_cache()
426 h.flash(_('Updated visualisation settings'), category='success')
432 h.flash(_('Updated visualisation settings'), category='success')
427 except Exception:
433 except Exception:
428 log.exception("Exception updating visualization settings")
434 log.exception("Exception updating visualization settings")
429 h.flash(_('Error occurred during updating '
435 h.flash(_('Error occurred during updating '
430 'visualisation settings'),
436 'visualisation settings'),
431 category='error')
437 category='error')
432
438
433 raise HTTPFound(h.route_path('admin_settings_visual'))
439 raise HTTPFound(h.route_path('admin_settings_visual'))
434
440
435 @LoginRequired()
441 @LoginRequired()
436 @HasPermissionAllDecorator('hg.admin')
442 @HasPermissionAllDecorator('hg.admin')
437 @view_config(
443 @view_config(
438 route_name='admin_settings_issuetracker', request_method='GET',
444 route_name='admin_settings_issuetracker', request_method='GET',
439 renderer='rhodecode:templates/admin/settings/settings.mako')
445 renderer='rhodecode:templates/admin/settings/settings.mako')
440 def settings_issuetracker(self):
446 def settings_issuetracker(self):
441 c = self.load_default_context()
447 c = self.load_default_context()
442 c.active = 'issuetracker'
448 c.active = 'issuetracker'
443 defaults = SettingsModel().get_all_settings()
449 defaults = SettingsModel().get_all_settings()
444
450
445 entry_key = 'rhodecode_issuetracker_pat_'
451 entry_key = 'rhodecode_issuetracker_pat_'
446
452
447 c.issuetracker_entries = {}
453 c.issuetracker_entries = {}
448 for k, v in defaults.items():
454 for k, v in defaults.items():
449 if k.startswith(entry_key):
455 if k.startswith(entry_key):
450 uid = k[len(entry_key):]
456 uid = k[len(entry_key):]
451 c.issuetracker_entries[uid] = None
457 c.issuetracker_entries[uid] = None
452
458
453 for uid in c.issuetracker_entries:
459 for uid in c.issuetracker_entries:
454 c.issuetracker_entries[uid] = AttributeDict({
460 c.issuetracker_entries[uid] = AttributeDict({
455 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
461 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
456 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
462 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
457 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
463 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
458 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
464 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
459 })
465 })
460
466
461 return self._get_template_context(c)
467 return self._get_template_context(c)
462
468
463 @LoginRequired()
469 @LoginRequired()
464 @HasPermissionAllDecorator('hg.admin')
470 @HasPermissionAllDecorator('hg.admin')
465 @CSRFRequired()
471 @CSRFRequired()
466 @view_config(
472 @view_config(
467 route_name='admin_settings_issuetracker_test', request_method='POST',
473 route_name='admin_settings_issuetracker_test', request_method='POST',
468 renderer='string', xhr=True)
474 renderer='string', xhr=True)
469 def settings_issuetracker_test(self):
475 def settings_issuetracker_test(self):
470 return h.urlify_commit_message(
476 return h.urlify_commit_message(
471 self.request.POST.get('test_text', ''),
477 self.request.POST.get('test_text', ''),
472 'repo_group/test_repo1')
478 'repo_group/test_repo1')
473
479
474 @LoginRequired()
480 @LoginRequired()
475 @HasPermissionAllDecorator('hg.admin')
481 @HasPermissionAllDecorator('hg.admin')
476 @CSRFRequired()
482 @CSRFRequired()
477 @view_config(
483 @view_config(
478 route_name='admin_settings_issuetracker_update', request_method='POST',
484 route_name='admin_settings_issuetracker_update', request_method='POST',
479 renderer='rhodecode:templates/admin/settings/settings.mako')
485 renderer='rhodecode:templates/admin/settings/settings.mako')
480 def settings_issuetracker_update(self):
486 def settings_issuetracker_update(self):
481 _ = self.request.translate
487 _ = self.request.translate
482 self.load_default_context()
488 self.load_default_context()
483 settings_model = IssueTrackerSettingsModel()
489 settings_model = IssueTrackerSettingsModel()
484
490
485 try:
491 try:
486 form = IssueTrackerPatternsForm(self.request.translate)()
492 form = IssueTrackerPatternsForm(self.request.translate)()
487 data = form.to_python(self.request.POST)
493 data = form.to_python(self.request.POST)
488 except formencode.Invalid as errors:
494 except formencode.Invalid as errors:
489 log.exception('Failed to add new pattern')
495 log.exception('Failed to add new pattern')
490 error = errors
496 error = errors
491 h.flash(_('Invalid issue tracker pattern: {}'.format(error)),
497 h.flash(_('Invalid issue tracker pattern: {}'.format(error)),
492 category='error')
498 category='error')
493 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
499 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
494
500
495 if data:
501 if data:
496 for uid in data.get('delete_patterns', []):
502 for uid in data.get('delete_patterns', []):
497 settings_model.delete_entries(uid)
503 settings_model.delete_entries(uid)
498
504
499 for pattern in data.get('patterns', []):
505 for pattern in data.get('patterns', []):
500 for setting, value, type_ in pattern:
506 for setting, value, type_ in pattern:
501 sett = settings_model.create_or_update_setting(
507 sett = settings_model.create_or_update_setting(
502 setting, value, type_)
508 setting, value, type_)
503 Session().add(sett)
509 Session().add(sett)
504
510
505 Session().commit()
511 Session().commit()
506
512
507 SettingsModel().invalidate_settings_cache()
513 SettingsModel().invalidate_settings_cache()
508 h.flash(_('Updated issue tracker entries'), category='success')
514 h.flash(_('Updated issue tracker entries'), category='success')
509 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
515 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
510
516
511 @LoginRequired()
517 @LoginRequired()
512 @HasPermissionAllDecorator('hg.admin')
518 @HasPermissionAllDecorator('hg.admin')
513 @CSRFRequired()
519 @CSRFRequired()
514 @view_config(
520 @view_config(
515 route_name='admin_settings_issuetracker_delete', request_method='POST',
521 route_name='admin_settings_issuetracker_delete', request_method='POST',
516 renderer='rhodecode:templates/admin/settings/settings.mako')
522 renderer='rhodecode:templates/admin/settings/settings.mako')
517 def settings_issuetracker_delete(self):
523 def settings_issuetracker_delete(self):
518 _ = self.request.translate
524 _ = self.request.translate
519 self.load_default_context()
525 self.load_default_context()
520 uid = self.request.POST.get('uid')
526 uid = self.request.POST.get('uid')
521 try:
527 try:
522 IssueTrackerSettingsModel().delete_entries(uid)
528 IssueTrackerSettingsModel().delete_entries(uid)
523 except Exception:
529 except Exception:
524 log.exception('Failed to delete issue tracker setting %s', uid)
530 log.exception('Failed to delete issue tracker setting %s', uid)
525 raise HTTPNotFound()
531 raise HTTPNotFound()
526 h.flash(_('Removed issue tracker entry'), category='success')
532 h.flash(_('Removed issue tracker entry'), category='success')
527 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
533 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
528
534
529 @LoginRequired()
535 @LoginRequired()
530 @HasPermissionAllDecorator('hg.admin')
536 @HasPermissionAllDecorator('hg.admin')
531 @view_config(
537 @view_config(
532 route_name='admin_settings_email', request_method='GET',
538 route_name='admin_settings_email', request_method='GET',
533 renderer='rhodecode:templates/admin/settings/settings.mako')
539 renderer='rhodecode:templates/admin/settings/settings.mako')
534 def settings_email(self):
540 def settings_email(self):
535 c = self.load_default_context()
541 c = self.load_default_context()
536 c.active = 'email'
542 c.active = 'email'
537 c.rhodecode_ini = rhodecode.CONFIG
543 c.rhodecode_ini = rhodecode.CONFIG
538
544
539 data = render('rhodecode:templates/admin/settings/settings.mako',
545 data = render('rhodecode:templates/admin/settings/settings.mako',
540 self._get_template_context(c), self.request)
546 self._get_template_context(c), self.request)
541 html = formencode.htmlfill.render(
547 html = formencode.htmlfill.render(
542 data,
548 data,
543 defaults=self._form_defaults(),
549 defaults=self._form_defaults(),
544 encoding="UTF-8",
550 encoding="UTF-8",
545 force_defaults=False
551 force_defaults=False
546 )
552 )
547 return Response(html)
553 return Response(html)
548
554
549 @LoginRequired()
555 @LoginRequired()
550 @HasPermissionAllDecorator('hg.admin')
556 @HasPermissionAllDecorator('hg.admin')
551 @CSRFRequired()
557 @CSRFRequired()
552 @view_config(
558 @view_config(
553 route_name='admin_settings_email_update', request_method='POST',
559 route_name='admin_settings_email_update', request_method='POST',
554 renderer='rhodecode:templates/admin/settings/settings.mako')
560 renderer='rhodecode:templates/admin/settings/settings.mako')
555 def settings_email_update(self):
561 def settings_email_update(self):
556 _ = self.request.translate
562 _ = self.request.translate
557 c = self.load_default_context()
563 c = self.load_default_context()
558 c.active = 'email'
564 c.active = 'email'
559
565
560 test_email = self.request.POST.get('test_email')
566 test_email = self.request.POST.get('test_email')
561
567
562 if not test_email:
568 if not test_email:
563 h.flash(_('Please enter email address'), category='error')
569 h.flash(_('Please enter email address'), category='error')
564 raise HTTPFound(h.route_path('admin_settings_email'))
570 raise HTTPFound(h.route_path('admin_settings_email'))
565
571
566 email_kwargs = {
572 email_kwargs = {
567 'date': datetime.datetime.now(),
573 'date': datetime.datetime.now(),
568 'user': c.rhodecode_user,
574 'user': c.rhodecode_user,
569 'rhodecode_version': c.rhodecode_version
575 'rhodecode_version': c.rhodecode_version
570 }
576 }
571
577
572 (subject, headers, email_body,
578 (subject, headers, email_body,
573 email_body_plaintext) = EmailNotificationModel().render_email(
579 email_body_plaintext) = EmailNotificationModel().render_email(
574 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
580 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
575
581
576 recipients = [test_email] if test_email else None
582 recipients = [test_email] if test_email else None
577
583
578 run_task(tasks.send_email, recipients, subject,
584 run_task(tasks.send_email, recipients, subject,
579 email_body_plaintext, email_body)
585 email_body_plaintext, email_body)
580
586
581 h.flash(_('Send email task created'), category='success')
587 h.flash(_('Send email task created'), category='success')
582 raise HTTPFound(h.route_path('admin_settings_email'))
588 raise HTTPFound(h.route_path('admin_settings_email'))
583
589
584 @LoginRequired()
590 @LoginRequired()
585 @HasPermissionAllDecorator('hg.admin')
591 @HasPermissionAllDecorator('hg.admin')
586 @view_config(
592 @view_config(
587 route_name='admin_settings_hooks', request_method='GET',
593 route_name='admin_settings_hooks', request_method='GET',
588 renderer='rhodecode:templates/admin/settings/settings.mako')
594 renderer='rhodecode:templates/admin/settings/settings.mako')
589 def settings_hooks(self):
595 def settings_hooks(self):
590 c = self.load_default_context()
596 c = self.load_default_context()
591 c.active = 'hooks'
597 c.active = 'hooks'
592
598
593 model = SettingsModel()
599 model = SettingsModel()
594 c.hooks = model.get_builtin_hooks()
600 c.hooks = model.get_builtin_hooks()
595 c.custom_hooks = model.get_custom_hooks()
601 c.custom_hooks = model.get_custom_hooks()
596
602
597 data = render('rhodecode:templates/admin/settings/settings.mako',
603 data = render('rhodecode:templates/admin/settings/settings.mako',
598 self._get_template_context(c), self.request)
604 self._get_template_context(c), self.request)
599 html = formencode.htmlfill.render(
605 html = formencode.htmlfill.render(
600 data,
606 data,
601 defaults=self._form_defaults(),
607 defaults=self._form_defaults(),
602 encoding="UTF-8",
608 encoding="UTF-8",
603 force_defaults=False
609 force_defaults=False
604 )
610 )
605 return Response(html)
611 return Response(html)
606
612
607 @LoginRequired()
613 @LoginRequired()
608 @HasPermissionAllDecorator('hg.admin')
614 @HasPermissionAllDecorator('hg.admin')
609 @CSRFRequired()
615 @CSRFRequired()
610 @view_config(
616 @view_config(
611 route_name='admin_settings_hooks_update', request_method='POST',
617 route_name='admin_settings_hooks_update', request_method='POST',
612 renderer='rhodecode:templates/admin/settings/settings.mako')
618 renderer='rhodecode:templates/admin/settings/settings.mako')
613 @view_config(
619 @view_config(
614 route_name='admin_settings_hooks_delete', request_method='POST',
620 route_name='admin_settings_hooks_delete', request_method='POST',
615 renderer='rhodecode:templates/admin/settings/settings.mako')
621 renderer='rhodecode:templates/admin/settings/settings.mako')
616 def settings_hooks_update(self):
622 def settings_hooks_update(self):
617 _ = self.request.translate
623 _ = self.request.translate
618 c = self.load_default_context()
624 c = self.load_default_context()
619 c.active = 'hooks'
625 c.active = 'hooks'
620 if c.visual.allow_custom_hooks_settings:
626 if c.visual.allow_custom_hooks_settings:
621 ui_key = self.request.POST.get('new_hook_ui_key')
627 ui_key = self.request.POST.get('new_hook_ui_key')
622 ui_value = self.request.POST.get('new_hook_ui_value')
628 ui_value = self.request.POST.get('new_hook_ui_value')
623
629
624 hook_id = self.request.POST.get('hook_id')
630 hook_id = self.request.POST.get('hook_id')
625 new_hook = False
631 new_hook = False
626
632
627 model = SettingsModel()
633 model = SettingsModel()
628 try:
634 try:
629 if ui_value and ui_key:
635 if ui_value and ui_key:
630 model.create_or_update_hook(ui_key, ui_value)
636 model.create_or_update_hook(ui_key, ui_value)
631 h.flash(_('Added new hook'), category='success')
637 h.flash(_('Added new hook'), category='success')
632 new_hook = True
638 new_hook = True
633 elif hook_id:
639 elif hook_id:
634 RhodeCodeUi.delete(hook_id)
640 RhodeCodeUi.delete(hook_id)
635 Session().commit()
641 Session().commit()
636
642
637 # check for edits
643 # check for edits
638 update = False
644 update = False
639 _d = self.request.POST.dict_of_lists()
645 _d = self.request.POST.dict_of_lists()
640 for k, v in zip(_d.get('hook_ui_key', []),
646 for k, v in zip(_d.get('hook_ui_key', []),
641 _d.get('hook_ui_value_new', [])):
647 _d.get('hook_ui_value_new', [])):
642 model.create_or_update_hook(k, v)
648 model.create_or_update_hook(k, v)
643 update = True
649 update = True
644
650
645 if update and not new_hook:
651 if update and not new_hook:
646 h.flash(_('Updated hooks'), category='success')
652 h.flash(_('Updated hooks'), category='success')
647 Session().commit()
653 Session().commit()
648 except Exception:
654 except Exception:
649 log.exception("Exception during hook creation")
655 log.exception("Exception during hook creation")
650 h.flash(_('Error occurred during hook creation'),
656 h.flash(_('Error occurred during hook creation'),
651 category='error')
657 category='error')
652
658
653 raise HTTPFound(h.route_path('admin_settings_hooks'))
659 raise HTTPFound(h.route_path('admin_settings_hooks'))
654
660
655 @LoginRequired()
661 @LoginRequired()
656 @HasPermissionAllDecorator('hg.admin')
662 @HasPermissionAllDecorator('hg.admin')
657 @view_config(
663 @view_config(
658 route_name='admin_settings_search', request_method='GET',
664 route_name='admin_settings_search', request_method='GET',
659 renderer='rhodecode:templates/admin/settings/settings.mako')
665 renderer='rhodecode:templates/admin/settings/settings.mako')
660 def settings_search(self):
666 def settings_search(self):
661 c = self.load_default_context()
667 c = self.load_default_context()
662 c.active = 'search'
668 c.active = 'search'
663
669
664 searcher = searcher_from_config(self.request.registry.settings)
670 searcher = searcher_from_config(self.request.registry.settings)
665 c.statistics = searcher.statistics(self.request.translate)
671 c.statistics = searcher.statistics(self.request.translate)
666
672
667 return self._get_template_context(c)
673 return self._get_template_context(c)
668
674
669 @LoginRequired()
675 @LoginRequired()
670 @HasPermissionAllDecorator('hg.admin')
676 @HasPermissionAllDecorator('hg.admin')
671 @view_config(
677 @view_config(
678 route_name='admin_settings_automation', request_method='GET',
679 renderer='rhodecode:templates/admin/settings/settings.mako')
680 def settings_automation(self):
681 c = self.load_default_context()
682 c.active = 'automation'
683
684 return self._get_template_context(c)
685
686 @LoginRequired()
687 @HasPermissionAllDecorator('hg.admin')
688 @view_config(
672 route_name='admin_settings_labs', request_method='GET',
689 route_name='admin_settings_labs', request_method='GET',
673 renderer='rhodecode:templates/admin/settings/settings.mako')
690 renderer='rhodecode:templates/admin/settings/settings.mako')
674 def settings_labs(self):
691 def settings_labs(self):
675 c = self.load_default_context()
692 c = self.load_default_context()
676 if not c.labs_active:
693 if not c.labs_active:
677 raise HTTPFound(h.route_path('admin_settings'))
694 raise HTTPFound(h.route_path('admin_settings'))
678
695
679 c.active = 'labs'
696 c.active = 'labs'
680 c.lab_settings = _LAB_SETTINGS
697 c.lab_settings = _LAB_SETTINGS
681
698
682 data = render('rhodecode:templates/admin/settings/settings.mako',
699 data = render('rhodecode:templates/admin/settings/settings.mako',
683 self._get_template_context(c), self.request)
700 self._get_template_context(c), self.request)
684 html = formencode.htmlfill.render(
701 html = formencode.htmlfill.render(
685 data,
702 data,
686 defaults=self._form_defaults(),
703 defaults=self._form_defaults(),
687 encoding="UTF-8",
704 encoding="UTF-8",
688 force_defaults=False
705 force_defaults=False
689 )
706 )
690 return Response(html)
707 return Response(html)
691
708
692 @LoginRequired()
709 @LoginRequired()
693 @HasPermissionAllDecorator('hg.admin')
710 @HasPermissionAllDecorator('hg.admin')
694 @CSRFRequired()
711 @CSRFRequired()
695 @view_config(
712 @view_config(
696 route_name='admin_settings_labs_update', request_method='POST',
713 route_name='admin_settings_labs_update', request_method='POST',
697 renderer='rhodecode:templates/admin/settings/settings.mako')
714 renderer='rhodecode:templates/admin/settings/settings.mako')
698 def settings_labs_update(self):
715 def settings_labs_update(self):
699 _ = self.request.translate
716 _ = self.request.translate
700 c = self.load_default_context()
717 c = self.load_default_context()
701 c.active = 'labs'
718 c.active = 'labs'
702
719
703 application_form = LabsSettingsForm(self.request.translate)()
720 application_form = LabsSettingsForm(self.request.translate)()
704 try:
721 try:
705 form_result = application_form.to_python(dict(self.request.POST))
722 form_result = application_form.to_python(dict(self.request.POST))
706 except formencode.Invalid as errors:
723 except formencode.Invalid as errors:
707 h.flash(
724 h.flash(
708 _('Some form inputs contain invalid data.'),
725 _("Some form inputs contain invalid data."),
709 category='error')
726 category='error')
710 data = render('rhodecode:templates/admin/settings/settings.mako',
727 data = render('rhodecode:templates/admin/settings/settings.mako',
711 self._get_template_context(c), self.request)
728 self._get_template_context(c), self.request)
712 html = formencode.htmlfill.render(
729 html = formencode.htmlfill.render(
713 data,
730 data,
714 defaults=errors.value,
731 defaults=errors.value,
715 errors=errors.error_dict or {},
732 errors=errors.error_dict or {},
716 prefix_error=False,
733 prefix_error=False,
717 encoding="UTF-8",
734 encoding="UTF-8",
718 force_defaults=False
735 force_defaults=False
719 )
736 )
720 return Response(html)
737 return Response(html)
721
738
722 try:
739 try:
723 session = Session()
740 session = Session()
724 for setting in _LAB_SETTINGS:
741 for setting in _LAB_SETTINGS:
725 setting_name = setting.key[len('rhodecode_'):]
742 setting_name = setting.key[len('rhodecode_'):]
726 sett = SettingsModel().create_or_update_setting(
743 sett = SettingsModel().create_or_update_setting(
727 setting_name, form_result[setting.key], setting.type)
744 setting_name, form_result[setting.key], setting.type)
728 session.add(sett)
745 session.add(sett)
729
746
730 except Exception:
747 except Exception:
731 log.exception('Exception while updating lab settings')
748 log.exception('Exception while updating lab settings')
732 h.flash(_('Error occurred during updating labs settings'),
749 h.flash(_('Error occurred during updating labs settings'),
733 category='error')
750 category='error')
734 else:
751 else:
735 Session().commit()
752 Session().commit()
736 SettingsModel().invalidate_settings_cache()
753 SettingsModel().invalidate_settings_cache()
737 h.flash(_('Updated Labs settings'), category='success')
754 h.flash(_('Updated Labs settings'), category='success')
738 raise HTTPFound(h.route_path('admin_settings_labs'))
755 raise HTTPFound(h.route_path('admin_settings_labs'))
739
756
740 data = render('rhodecode:templates/admin/settings/settings.mako',
757 data = render('rhodecode:templates/admin/settings/settings.mako',
741 self._get_template_context(c), self.request)
758 self._get_template_context(c), self.request)
742 html = formencode.htmlfill.render(
759 html = formencode.htmlfill.render(
743 data,
760 data,
744 defaults=self._form_defaults(),
761 defaults=self._form_defaults(),
745 encoding="UTF-8",
762 encoding="UTF-8",
746 force_defaults=False
763 force_defaults=False
747 )
764 )
748 return Response(html)
765 return Response(html)
749
766
750
767
751 # :param key: name of the setting including the 'rhodecode_' prefix
768 # :param key: name of the setting including the 'rhodecode_' prefix
752 # :param type: the RhodeCodeSetting type to use.
769 # :param type: the RhodeCodeSetting type to use.
753 # :param group: the i18ned group in which we should dispaly this setting
770 # :param group: the i18ned group in which we should dispaly this setting
754 # :param label: the i18ned label we should display for this setting
771 # :param label: the i18ned label we should display for this setting
755 # :param help: the i18ned help we should dispaly for this setting
772 # :param help: the i18ned help we should dispaly for this setting
756 LabSetting = collections.namedtuple(
773 LabSetting = collections.namedtuple(
757 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
774 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
758
775
759
776
760 # This list has to be kept in sync with the form
777 # This list has to be kept in sync with the form
761 # rhodecode.model.forms.LabsSettingsForm.
778 # rhodecode.model.forms.LabsSettingsForm.
762 _LAB_SETTINGS = [
779 _LAB_SETTINGS = [
763
780
764 ]
781 ]
@@ -1,197 +1,200 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import urllib2
22 import urllib2
23
23
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25
25
26 import rhodecode
26 import rhodecode
27 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps.admin.navigation import navigation_list
28 from rhodecode.apps.admin.navigation import navigation_list
29 from rhodecode.lib import helpers as h
29 from rhodecode.lib import helpers as h
30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
31 from rhodecode.lib.utils2 import str2bool
31 from rhodecode.lib.utils2 import str2bool
32 from rhodecode.lib import system_info
32 from rhodecode.lib import system_info
33 from rhodecode.model.update import UpdateModel
33 from rhodecode.model.update import UpdateModel
34
34
35 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
36
36
37
37
38 class AdminSystemInfoSettingsView(BaseAppView):
38 class AdminSystemInfoSettingsView(BaseAppView):
39 def load_default_context(self):
39 def load_default_context(self):
40 c = self._get_local_tmpl_context()
40 c = self._get_local_tmpl_context()
41 return c
41 return c
42
42
43 @LoginRequired()
43 @LoginRequired()
44 @HasPermissionAllDecorator('hg.admin')
44 @HasPermissionAllDecorator('hg.admin')
45 @view_config(
45 @view_config(
46 route_name='admin_settings_system', request_method='GET',
46 route_name='admin_settings_system', request_method='GET',
47 renderer='rhodecode:templates/admin/settings/settings.mako')
47 renderer='rhodecode:templates/admin/settings/settings.mako')
48 def settings_system_info(self):
48 def settings_system_info(self):
49 _ = self.request.translate
49 _ = self.request.translate
50 c = self.load_default_context()
50 c = self.load_default_context()
51
51
52 c.active = 'system'
52 c.active = 'system'
53 c.navlist = navigation_list(self.request)
53 c.navlist = navigation_list(self.request)
54
54
55 # TODO(marcink), figure out how to allow only selected users to do this
55 # TODO(marcink), figure out how to allow only selected users to do this
56 c.allowed_to_snapshot = self._rhodecode_user.admin
56 c.allowed_to_snapshot = self._rhodecode_user.admin
57
57
58 snapshot = str2bool(self.request.params.get('snapshot'))
58 snapshot = str2bool(self.request.params.get('snapshot'))
59
59
60 c.rhodecode_update_url = UpdateModel().get_update_url()
60 c.rhodecode_update_url = UpdateModel().get_update_url()
61 server_info = system_info.get_system_info(self.request.environ)
61 server_info = system_info.get_system_info(self.request.environ)
62
62
63 for key, val in server_info.items():
63 for key, val in server_info.items():
64 setattr(c, key, val)
64 setattr(c, key, val)
65
65
66 def val(name, subkey='human_value'):
66 def val(name, subkey='human_value'):
67 return server_info[name][subkey]
67 return server_info[name][subkey]
68
68
69 def state(name):
69 def state(name):
70 return server_info[name]['state']
70 return server_info[name]['state']
71
71
72 def val2(name):
72 def val2(name):
73 val = server_info[name]['human_value']
73 val = server_info[name]['human_value']
74 state = server_info[name]['state']
74 state = server_info[name]['state']
75 return val, state
75 return val, state
76
76
77 update_info_msg = _('Note: please make sure this server can '
77 update_info_msg = _('Note: please make sure this server can '
78 'access `${url}` for the update link to work',
78 'access `${url}` for the update link to work',
79 mapping=dict(url=c.rhodecode_update_url))
79 mapping=dict(url=c.rhodecode_update_url))
80 version = UpdateModel().get_stored_version()
80 version = UpdateModel().get_stored_version()
81 is_outdated = UpdateModel().is_outdated(
81 is_outdated = UpdateModel().is_outdated(
82 rhodecode.__version__, version)
82 rhodecode.__version__, version)
83 update_state = {
83 update_state = {
84 'type': 'warning',
84 'type': 'warning',
85 'message': 'New version available: {}'.format(version)
85 'message': 'New version available: {}'.format(version)
86 } \
86 } \
87 if is_outdated else {}
87 if is_outdated else {}
88 c.data_items = [
88 c.data_items = [
89 # update info
89 # update info
90 (_('Update info'), h.literal(
90 (_('Update info'), h.literal(
91 '<span class="link" id="check_for_update" >%s.</span>' % (
91 '<span class="link" id="check_for_update" >%s.</span>' % (
92 _('Check for updates')) +
92 _('Check for updates')) +
93 '<br/> <span >%s.</span>' % (update_info_msg)
93 '<br/> <span >%s.</span>' % (update_info_msg)
94 ), ''),
94 ), ''),
95
95
96 # RhodeCode specific
96 # RhodeCode specific
97 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
97 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
98 (_('Latest version'), version, update_state),
98 (_('Latest version'), version, update_state),
99 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
99 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
100 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
100 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
101 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
101 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
102 (_('RhodeCode Certificate'), val('rhodecode_config')['cert_path'], state('rhodecode_config')),
102 (_('RhodeCode Certificate'), val('rhodecode_config')['cert_path'], state('rhodecode_config')),
103 (_('Workers'), val('rhodecode_config')['config']['server:main'].get('workers', '?'), state('rhodecode_config')),
103 (_('Workers'), val('rhodecode_config')['config']['server:main'].get('workers', '?'), state('rhodecode_config')),
104 (_('Worker Type'), val('rhodecode_config')['config']['server:main'].get('worker_class', 'sync'), state('rhodecode_config')),
104 (_('Worker Type'), val('rhodecode_config')['config']['server:main'].get('worker_class', 'sync'), state('rhodecode_config')),
105 ('', '', ''), # spacer
105 ('', '', ''), # spacer
106
106
107 # Database
107 # Database
108 (_('Database'), val('database')['url'], state('database')),
108 (_('Database'), val('database')['url'], state('database')),
109 (_('Database version'), val('database')['version'], state('database')),
109 (_('Database version'), val('database')['version'], state('database')),
110 ('', '', ''), # spacer
110 ('', '', ''), # spacer
111
111
112 # Platform/Python
112 # Platform/Python
113 (_('Platform'), val('platform')['name'], state('platform')),
113 (_('Platform'), val('platform')['name'], state('platform')),
114 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
114 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
115 (_('Python version'), val('python')['version'], state('python')),
115 (_('Python version'), val('python')['version'], state('python')),
116 (_('Python path'), val('python')['executable'], state('python')),
116 (_('Python path'), val('python')['executable'], state('python')),
117 ('', '', ''), # spacer
117 ('', '', ''), # spacer
118
118
119 # Systems stats
119 # Systems stats
120 (_('CPU'), val('cpu')['text'], state('cpu')),
120 (_('CPU'), val('cpu')['text'], state('cpu')),
121 (_('Load'), val('load')['text'], state('load')),
121 (_('Load'), val('load')['text'], state('load')),
122 (_('Memory'), val('memory')['text'], state('memory')),
122 (_('Memory'), val('memory')['text'], state('memory')),
123 (_('Uptime'), val('uptime')['text'], state('uptime')),
123 (_('Uptime'), val('uptime')['text'], state('uptime')),
124 ('', '', ''), # spacer
124 ('', '', ''), # spacer
125
125
126 # ulimit
127 (_('Ulimit'), val('ulimit')['text'], state('ulimit')),
128
126 # Repo storage
129 # Repo storage
127 (_('Storage location'), val('storage')['path'], state('storage')),
130 (_('Storage location'), val('storage')['path'], state('storage')),
128 (_('Storage info'), val('storage')['text'], state('storage')),
131 (_('Storage info'), val('storage')['text'], state('storage')),
129 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
132 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
130
133
131 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
134 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
132 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
135 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
133
136
134 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
137 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
135 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
138 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
136
139
137 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
140 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
138 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
141 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
139
142
140 (_('Search info'), val('search')['text'], state('search')),
143 (_('Search info'), val('search')['text'], state('search')),
141 (_('Search location'), val('search')['location'], state('search')),
144 (_('Search location'), val('search')['location'], state('search')),
142 ('', '', ''), # spacer
145 ('', '', ''), # spacer
143
146
144 # VCS specific
147 # VCS specific
145 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
148 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
146 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
149 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
147 (_('GIT'), val('git'), state('git')),
150 (_('GIT'), val('git'), state('git')),
148 (_('HG'), val('hg'), state('hg')),
151 (_('HG'), val('hg'), state('hg')),
149 (_('SVN'), val('svn'), state('svn')),
152 (_('SVN'), val('svn'), state('svn')),
150
153
151 ]
154 ]
152
155
153 if snapshot:
156 if snapshot:
154 if c.allowed_to_snapshot:
157 if c.allowed_to_snapshot:
155 c.data_items.pop(0) # remove server info
158 c.data_items.pop(0) # remove server info
156 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
159 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
157 else:
160 else:
158 h.flash('You are not allowed to do this', category='warning')
161 h.flash('You are not allowed to do this', category='warning')
159 return self._get_template_context(c)
162 return self._get_template_context(c)
160
163
161 @LoginRequired()
164 @LoginRequired()
162 @HasPermissionAllDecorator('hg.admin')
165 @HasPermissionAllDecorator('hg.admin')
163 @view_config(
166 @view_config(
164 route_name='admin_settings_system_update', request_method='GET',
167 route_name='admin_settings_system_update', request_method='GET',
165 renderer='rhodecode:templates/admin/settings/settings_system_update.mako')
168 renderer='rhodecode:templates/admin/settings/settings_system_update.mako')
166 def settings_system_info_check_update(self):
169 def settings_system_info_check_update(self):
167 _ = self.request.translate
170 _ = self.request.translate
168 c = self.load_default_context()
171 c = self.load_default_context()
169
172
170 update_url = UpdateModel().get_update_url()
173 update_url = UpdateModel().get_update_url()
171
174
172 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
175 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
173 try:
176 try:
174 data = UpdateModel().get_update_data(update_url)
177 data = UpdateModel().get_update_data(update_url)
175 except urllib2.URLError as e:
178 except urllib2.URLError as e:
176 log.exception("Exception contacting upgrade server")
179 log.exception("Exception contacting upgrade server")
177 self.request.override_renderer = 'string'
180 self.request.override_renderer = 'string'
178 return _err('Failed to contact upgrade server: %r' % e)
181 return _err('Failed to contact upgrade server: %r' % e)
179 except ValueError as e:
182 except ValueError as e:
180 log.exception("Bad data sent from update server")
183 log.exception("Bad data sent from update server")
181 self.request.override_renderer = 'string'
184 self.request.override_renderer = 'string'
182 return _err('Bad data sent from update server')
185 return _err('Bad data sent from update server')
183
186
184 latest = data['versions'][0]
187 latest = data['versions'][0]
185
188
186 c.update_url = update_url
189 c.update_url = update_url
187 c.latest_data = latest
190 c.latest_data = latest
188 c.latest_ver = latest['version']
191 c.latest_ver = latest['version']
189 c.cur_ver = rhodecode.__version__
192 c.cur_ver = rhodecode.__version__
190 c.should_upgrade = False
193 c.should_upgrade = False
191
194
192 is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
195 is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver)
193 if is_oudated:
196 if is_oudated:
194 c.should_upgrade = True
197 c.should_upgrade = True
195 c.important_notices = latest['general']
198 c.important_notices = latest['general']
196 UpdateModel().store_version(latest['version'])
199 UpdateModel().store_version(latest['version'])
197 return self._get_template_context(c)
200 return self._get_template_context(c)
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now