##// END OF EJS Templates
release: Merge default into stable for release preparation
marcink -
r306:08b6bdad merge stable
parent child Browse files
Show More

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

@@ -0,0 +1,137 b''
1 .. _checklist-tickets:
2
3 =================
4 Ticket Checklists
5 =================
6
7
8 Ticket Description
9 ==================
10
11 In general these things really matter in the description:
12
13 - Reasoning / Rationale. Explain "WHY" it makes sense and is important.
14
15 - How to reproduce. Easy to follow steps, that’s important.
16
17 - Observation: The problem (short)
18
19 - Expectation: How it should be (short)
20
21 - Specs: It is fine to draft them as good as it works.
22
23 If anything is unclear, please ask for a review or help on this via the
24 Community Portal or Slack channel.
25
26
27 Checklists for Tickets
28 ======================
29
30 BUG
31 ---
32
33 Definition: An existing function that does not work as expected for the user.
34
35 - Problem description
36 - Steps needed to recreate (gherkin)
37 - Link to the screen in question and/or description of how to find it via
38 navigation
39 - Explanation of what the expected outcome is
40 - Any hints into the source of the problem
41 - Information about platform/browser/db/etc. where applicable
42 - Examples of other similar cases which have different behaviour
43
44 DESIGN
45 ------
46
47 Definition: Styling and user interface issues, including cosmetic improvements
48 or appearance and behaviour of frontend functionality.
49
50 - Screenshot/animation of existing page/behaviour
51 - Sketches or wireframes if available
52 - Link to the screen in question and/or description of how to find it via
53 navigation
54 - Problem description
55 - Explanation of what the expected outcome is
56 - Since this may be examined by a designer; it should be written in a way that a
57 non-developer can understand
58
59 EPIC
60 ----
61
62 Definition: A collection of tickets which together complete a larger overall
63 project.
64
65 - Benefit explanation
66 - Clear objective - when is this complete?
67 - Explanations of exceptions/corner cases
68 - Documentation subtask
69 - Comprehensive wireframes and/or design subtasks
70 - Links to subtasks
71
72 FEATURE
73 -------
74
75 Definition: A new function in the software which previously did not exist.
76
77 - Benefit explanation
78 - Clear objective
79 - Explanations of exceptions/corner cases
80 - Documentation subtask
81 - Comprehensive wireframes and/or design subtasks
82
83 SUPPORT
84 -------
85
86 Definition: An issue related to a customer report.
87
88 - Link to support ticket, if available
89 - Problem description
90 - Steps needed to recreate (gherkin)
91 - Link to the screen in question and/or description of how to find it via
92 navigation
93 - Explanation of what the expected outcome is
94 - Any hints into the source of the problem
95 - Information about platform/browser/db/etc. where applicable
96 - Examples of other similar cases which have different behaviour
97
98 TASK
99 ----
100
101 Definition: An improvement or step towards implementing a feature or fixing
102 a bug. Includes refactoring and other tech debt.
103
104 - Clear objective
105 - Benefit explanation
106 - Links to parent/related tickets
107
108
109 All details below.
110
111
112 External links:
113
114 - Avoid linking to external images; they disappear over time. Please attach any
115 relevant images to the ticket itself.
116
117 - External links in general: They also disappear over time, consider copying the
118 relevant bit of information into a comment or write a paragraph to sum up the
119 general idea.
120
121
122 Hints
123 =====
124
125 Change Description
126 ------------------
127
128 It can be tricky to figure out how to change the description of a ticket. There
129 is a very small pencil which has to be clicked once you see the edit form of a
130 ticket.
131
132
133 .. figure:: images/redmine-description.png
134 :alt: Example of pencil to change the ticket description
135
136 Shows an example of the pencil which lets you change the description.
137
@@ -0,0 +1,153 b''
1
2 ==================================================
3 Code style and structure guide for frontend work
4 ==================================================
5
6 About: Outline of frontend development practices.
7
8
9
10
11 Templates
12 =========
13
14 - Indent with 4 spaces in general.
15 - Embedded Python code follows the same conventions as in the backend.
16
17 A common problem is missed spaces around operators.
18
19
20
21
22 Grunt
23 =====
24
25 We use Grunt to compile our JavaScript and LESS files. This is done automatically
26 when you start an instance. If you are changing these files, however, it is
27 recommended to amend `--reload` to the `runserver` command, or use `grunt watch`
28 - the Gruntfile is located in the base directory. For more info on Grunt, see
29 http://gruntjs.com/
30
31
32
33
34 LESS CSS
35 ========
36
37
38 Style
39 -----
40
41 - Use 4 spaces instead of tabs.
42 - Avoid ``!important``; it is very often an indicator for a problem.
43
44
45
46
47 Structure
48 ---------
49
50 It is important that we maintain consistency in the LESS files so that things
51 scale properly. CSS is organized using LESS and then compiled into a CSS file
52 to be used in production. Find the class you need to change and change it
53 there. Do not add overriding styles at the end of the file. The LESS file will
54 be minified; use plenty of spacing and comments for readability.
55
56 These will be kept in auxillary LESS files to be imported (in this order) at the top:
57
58 - `fonts.less` (font-face declarations)
59 - `mixins` (place all LESS mixins here)
60 - `helpers` (basic classes for hiding mobile elements, centering, etc)
61 - `variables` (theme-specific colors, spacing, and fonts which might change later)
62
63
64 Sections of the primary LESS file are as follows. Add comments describing
65 layout and modules.
66
67 .. code-block:: css
68
69 //--- BASE ------------------//
70 Very basic, sitewide styles.
71
72 //--- LAYOUT ------------------//
73 Essential layout, ex. containers and wrappers.
74 Do not put type styles in here.
75
76 //--- MODULES ------------------//
77 Reusable sections, such as sidebars and menus.
78
79 //--- THEME ------------------//
80 Theme styles, typography, etc.
81
82
83
84 Formatting rules
85 ~~~~~~~~~~~~~~~~
86
87 - Each rule should be indented on a separate line (this is helpful for diff
88 checking).
89
90 - Use a space after each colon and a semicolon after each last rule.
91
92 - Put a blank line between each class.
93
94 - Nested classes should be listed after the parent class' rules, separated with a
95 blank line, and indented.
96
97 - Using the below as a guide, place each rule in order of its effect on content,
98 layout, sizing, and last listing minor style changes such as font color and
99 backgrounds. Not every possible rule is listed here; when adding new ones,
100 judge where it should go in the list based on that hierarchy.
101
102 .. code-block:: scss
103
104 .class {
105 content
106 list-style-type
107 position
108 float
109 top
110 right
111 bottom
112 left
113 height
114 max-height
115 min-height
116 width
117 max-width
118 min-width
119 margin
120 padding
121 indent
122 vertical-align
123 text-align
124 border
125 border-radius
126 font-size
127 line-height
128 font
129 font-style
130 font-variant
131 font-weight
132 color
133 text-shadow
134 background
135 background-color
136 box-shadow
137 background-url
138 background-position
139 background-repeat
140 background-cover
141 transitions
142 cursor
143 pointer-events
144
145 .nested-class {
146 position
147 background-color
148
149 &:hover {
150 color
151 }
152 }
153 }
@@ -0,0 +1,111 b''
1
2 =======================
3 Contributing Overview
4 =======================
5
6
7 RhodeCode Community Edition is an open source code management platform. We
8 encourage contributions to our project from the community. This is a basic
9 overview of the procedures for adding your contribution to RhodeCode.
10
11
12
13 Check the Issue Tracker
14 =======================
15
16 Make an account at https://issues.rhodecode.com/account/register and browse the
17 current tickets for bugs to fix and tasks to do. Have a bug or feature that you
18 can't find in the tracker? Create a new issue for it. When you select a ticket,
19 make sure to assign it to yourself and mark it "in progress" to avoid duplicated
20 work.
21
22
23
24 Sign Up at code.rhodecode.com
25 =============================
26
27 Make an account at https://code.rhodecode.com/ using an email or your existing
28 GitHub, Bitbucket, Google, or Twitter account. Fork the repo you'd like to
29 contribute to; we suggest adding your username to the fork name. Clone your fork
30 to your computer. We use Mercurial for source control management; see
31 https://www.mercurial-scm.org/guide to get started quickly.
32
33
34
35 Set Up A Local Instance
36 =======================
37
38 You will need to set up an instance of RhodeCode CE using VCSServer so that you
39 can see your work locally as you make changes. We recommend using Linux for this
40 but it can also be built on OSX.
41
42 See :doc:`dev-setup` for instructions.
43
44
45
46 Code!
47 =====
48
49 You can now make, see, and test your changes locally. We are always improving to
50 keep our code clean and the cost of maintaining it low. This applies in the same
51 way for contributions. We run automated checks on our pull requests, and expect
52 understandable code. We also aim to provide test coverage for as much of our
53 codebase as possible; any new features should be augmented with tests.
54
55 Keep in mind that when we accept your contribution, we also take responsibility
56 for it; we must understand it to take on that responsibility.
57
58 See :doc:`standards` for more detailed information.
59
60
61
62 Commit And Push Your Changes
63 ============================
64
65 We highly recommend making a new bookmark for each feature, bug, or set of
66 commits you make so that you can point to it when creating your pull request.
67 Please also reference the ticket number in your commit messages. Don't forget to
68 push the bookmark!
69
70
71
72 Submit a Pull Request
73 =====================
74
75 Go to your fork, and choose "Create Pull Request" from the Options menu. Use
76 your bookmark as the source, and choose someone to review it. Don't worry about
77 chosing the right person; we'll assign the best contributor for the job. You'll
78 get feedback and an assigned status.
79
80 Be prepared to make updates to your pull request after some feedback.
81 Collaboration is part of the process and improvements can often be made.
82
83
84
85 Sign the Contributor License Agreement
86 ======================================
87
88 If your contribution is approved, you will need to virtually sign the license
89 agreement in order for it to be merged into the project's codebase. You can read
90 it on our website here: https://rhodecode.com/static/pdf/RhodeCode-CLA.pdf
91
92 To sign, go to code.rhodecode.com
93 and clone the CLA repository. Add your name and make a pull request to add it to
94 the contributor agreement; this serves as your virtual signature. Once your
95 signature is merged, add a link to the relevant commit to your contribution
96 pull request.
97
98
99
100 That's it! We'll take it from there. Thanks for your contribution!
101 ------------------------------------------------------------------
102
103 .. note:: If you have any questions or comments, feel free to contact us through
104 either the community portal(community.rhodecode.com), IRC
105 (irc.freenode.net), or Slack (rhodecode.com/join).
106
107
108
109
110
111
@@ -0,0 +1,177 b''
1
2 ======================
3 Contribution Standards
4 ======================
5
6 Standards help to improve the quality of our product and its development. Herein
7 we define our standards for processes and development to maintain consistency
8 and function well as a community. It is a work in progress; modifications to this
9 document should be discussed and agreed upon by the community.
10
11
12 --------------------------------------------------------------------------------
13
14 Code
15 ====
16
17 This provides an outline for standards we use in our codebase to keep our code
18 easy to read and easy to maintain. Much of our code guidelines are based on the
19 book `Clean Code <http://www.pearsonhighered.com/educator/product/Clean-Code-A-Handbook-of-Agile-Software-Craftsmanship/9780132350884.page>`_
20 by Robert Martin.
21
22 We maintain a Tech Glossary to provide consistency in terms and symbolic names
23 used for items and concepts within the application. This is found in the CE
24 project in /docs-internal/glossary.rst
25
26
27 Refactoring
28 -----------
29 Make it better than you found it!
30
31 Our codebase can always use improvement and often benefits from refactoring.
32 New code should be refactored as it is being written, and old code should be
33 treated with the same care as if it was new. Before doing any refactoring,
34 ensure that there is test coverage on the affected code; this will help
35 minimize issues.
36
37
38 Python
39 ------
40 For Python, we use `PEP8 <https://www.python.org/dev/peps/pep-0008/>`_.
41 We adjust lines of code to under 80 characters and use 4 spaces for indentation.
42
43
44 JavaScript
45 ----------
46 This currently remains undefined. Suggestions welcome!
47
48
49 HTML
50 ----
51 Unfortunately, we currently have no strict HTML standards, but there are a few
52 guidelines we do follow. Templates must work in all modern browsers. HTML should
53 be clean and easy to read, and additionally should be free of inline CSS or
54 JavaScript. It is recommended to use data attributes for JS actions where
55 possible in order to separate it from styling and prevent unintentional changes.
56
57
58 LESS/CSS
59 --------
60 We use LESS for our CSS; see :doc:`frontend` for structure and formatting
61 guidelines.
62
63
64 Linters
65 -------
66 Currently, we have a linter for pull requests which checks code against PEP8.
67 We intend to add more in the future as we clarify standards.
68
69
70 --------------------------------------------------------------------------------
71
72 Naming Conventions
73 ==================
74
75 These still need to be defined for naming everything from Python variables to
76 HTML classes to files and folders.
77
78
79 --------------------------------------------------------------------------------
80
81 Testing
82 =======
83
84 Testing is a very important aspect of our process, especially as we are our own
85 quality control team. While it is of course unrealistic to hit every potential
86 combination, our goal is to cover every line of Python code with a test.
87
88 The following is a brief introduction to our test suite. Our tests are primarily
89 written using `py.test <http://pytest.org/>`_
90
91
92 Acceptance Tests
93 ----------------
94 Also known as "ac tests", these test from the user and business perspective to
95 check if the requirements of a feature are met. Scenarios are created at a
96 feature's inception and help to define its value.
97
98 py.test is used for ac tests; they are located in a repo separate from the
99 other tests which follow. Each feature has a .feature file which contains a
100 brief description and the scenarios to be tested.
101
102
103 Functional Tests
104 ----------------
105 These test specific functionality in the application which checks through the
106 entire stack. Typically these are user actions or permissions which go through
107 the web browser. They are located in rhodecode/tests.
108
109
110 Unit Tests
111 ----------
112 These test isolated, individual modules to ensure that they function correctly.
113 They are located in rhodecode/tests.
114
115
116 Integration Tests
117 -----------------
118 These are used for testing performance of larger systems than the unit tests.
119 They are located in rhodecode/tests.
120
121
122 JavaScript Testing
123 ------------------
124 Currently, we have not defined how to test our JavaScript code.
125
126
127 --------------------------------------------------------------------------------
128
129 Pull Requests
130 =============
131
132 Pull requests should generally contain only one thing: a single feature, one bug
133 fix, etc.. The commit history should be concise and clean, and the pull request
134 should contain the ticket number (also a good idea for the commits themselves)
135 to provide context for the reviewer.
136
137 See also: :doc:`checklist-pull-request`
138
139
140 Reviewers
141 ---------
142 Each pull request must be approved by at least one member of the RhodeCode
143 team. Assignments may be based on expertise or familiarity with a particular
144 area of code, or simply availability. Switching up or adding extra community
145 members for different pull requests helps to share knowledge as well as provide
146 other perspectives.
147
148
149 Responsibility
150 --------------
151 The community is responsible for maintaining features and this must be taken
152 into consideration. External contributions must be held to the same standards
153 as internal contributions.
154
155
156 Feature Switch
157 --------------
158 Experimental and work-in-progress features can be hidden behind one of two
159 switches:
160
161 * A setting can be added to the Labs page in the Admin section which may allow
162 customers to access and toggle additional features.
163 * For work-in-progress or other features where customer access is not desired,
164 use a custom setting in the .ini file as a trigger.
165
166
167 --------------------------------------------------------------------------------
168
169 Tickets
170 =======
171
172 Redmine tickets are a crucial part of our development process. Any code added or
173 changed in our codebase should have a corresponding ticket to document it. With
174 this in mind, it is important that tickets be as clear and concise as possible,
175 including what the expected outcome is.
176
177 See also: :doc:`checklist-tickets`
@@ -0,0 +1,70 b''
1 |RCE| 4.2.0 |RNS|
2 -----------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2016-06-30
8
9
10 General
11 ^^^^^^^
12
13 - Autocomplete: add GET flag support to show/hide active users on autocomplete,
14 also display this information in autocomplete data. ref #3374
15 - Gravatar: add flag to show current gravatar + user as disabled user (non-active)
16 - Repos, repo groups, user groups: allow to use disabled users in owner field.
17 This fixes #3374.
18 - Repos, repo groups, user groups: visually show what user is an owner of a
19 resource, and if potentially he is disabled in the system.
20 - Pull requests: reorder navigation on repo pull requests, fixes #2995
21 - Dependencies: bump dulwich to 0.13.0
22
23 New Features
24 ^^^^^^^^^^^^
25
26 - My account: made pull requests aggregate view for users look like not
27 created in 1995. Now uses a consistent look with repo one.
28 - emails: expose profile link on registation email that super-admins receive.
29 Implements #3999.
30 - Social auth: move the buttons to the top of nav so they are easier to reach.
31
32
33 Security
34 ^^^^^^^^
35
36 - Encryption: allow to pass in alternative key for encryption values. Now
37 users can use `rhodecode.encrypted_values.secret` that is alternative key,
38 de-coupled from `beaker.session` key.
39 - Encryption: Implement a slightly improved AesCipher encryption.
40 This addresses issues from #4036.
41 - Encryption: encrypted values now by default uses HMAC signatures to detect
42 if data or secret key is incorrect. The strict checks can be disabled using
43 `rhodecode.encrypted_values.strict = false` .ini setting
44
45
46 Performance
47 ^^^^^^^^^^^
48
49 - Sql: use smarter JOINs when fetching repository information
50 - Helpers: optimize slight calls for link_to_user to save some intense queries.
51 - App settings: use computed caches for repository settings, this in some cases
52 brings almost 4x performance increase for large repos with a lot of issue
53 tracker patterns.
54
55
56 Fixes
57 ^^^^^
58
59 - Fixed events on user pre/post create actions
60 - Authentication: fixed problem with saving forms with errors on auth plugins
61 - Svn: Avoid chunked transfer for Subversion that caused checkout issues in some cases.
62 - Users: fix generate new user password helper.
63 - Celery: fixed problem with workers running action in sync mode in some cases.
64 - Setup-db: fix redundant question on writable dir. The question needs to be
65 asked only when the dir is actually not writable.
66 - Elasticsearch: fixed issues when searching single repo using elastic search
67 - Social auth: fix issues with non-active users using social authentication
68 causing a 500 error.
69 - Fixed problem with largefiles extensions on per-repo settings using local
70 .hgrc files present inside the repo directory.
@@ -0,0 +1,40 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 from rhodecode.admin.navigation import NavigationRegistry
23 from rhodecode.config.routing import ADMIN_PREFIX
24 from rhodecode.lib.utils2 import str2bool
25
26
27 def includeme(config):
28 settings = config.get_settings()
29
30 # Create admin navigation registry and add it to the pyramid registry.
31 labs_active = str2bool(settings.get('labs_settings_active', False))
32 navigation_registry = NavigationRegistry(labs_active=labs_active)
33 config.registry.registerUtility(navigation_registry)
34
35 config.add_route(
36 name='admin_settings_open_source',
37 pattern=ADMIN_PREFIX + '/settings/open_source')
38
39 # Scan module for configuration decorators.
40 config.scan()
@@ -0,0 +1,29 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 from zope.interface import Interface
22
23
24 class IAdminNavigationRegistry(Interface):
25 """
26 Interface for the admin navigation registry. Currently this is only
27 used to register and retrieve it via pyramids registry.
28 """
29 pass
@@ -0,0 +1,124 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import logging
23 import collections
24
25 from pylons import url
26 from zope.interface import implementer
27
28 from rhodecode.admin.interfaces import IAdminNavigationRegistry
29 from rhodecode.lib.utils import get_registry
30 from rhodecode.translation import _
31
32
33 log = logging.getLogger(__name__)
34
35 NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url'])
36
37
38 class NavEntry(object):
39 """
40 Represents an entry in the admin navigation.
41
42 :param key: Unique identifier used to store reference in an OrderedDict.
43 :param name: Display name, usually a translation string.
44 :param view_name: Name of the view, used generate the URL.
45 :param pyramid: Indicator to use pyramid for URL generation. This should
46 be removed as soon as we are fully migrated to pyramid.
47 """
48
49 def __init__(self, key, name, view_name, pyramid=False):
50 self.key = key
51 self.name = name
52 self.view_name = view_name
53 self.pyramid = pyramid
54
55 def generate_url(self, request):
56 if self.pyramid:
57 if hasattr(request, 'route_path'):
58 return request.route_path(self.view_name)
59 else:
60 # TODO: johbo: Remove this after migrating to pyramid.
61 # We need the pyramid request here to generate URLs to pyramid
62 # views from within pylons views.
63 from pyramid.threadlocal import get_current_request
64 pyramid_request = get_current_request()
65 return pyramid_request.route_path(self.view_name)
66 else:
67 return url(self.view_name)
68
69
70 @implementer(IAdminNavigationRegistry)
71 class NavigationRegistry(object):
72
73 _base_entries = [
74 NavEntry('global', _('Global'), 'admin_settings_global'),
75 NavEntry('vcs', _('VCS'), 'admin_settings_vcs'),
76 NavEntry('visual', _('Visual'), 'admin_settings_visual'),
77 NavEntry('mapping', _('Remap and Rescan'), 'admin_settings_mapping'),
78 NavEntry('issuetracker', _('Issue Tracker'),
79 'admin_settings_issuetracker'),
80 NavEntry('email', _('Email'), 'admin_settings_email'),
81 NavEntry('hooks', _('Hooks'), 'admin_settings_hooks'),
82 NavEntry('search', _('Full Text Search'), 'admin_settings_search'),
83 NavEntry('system', _('System Info'), 'admin_settings_system'),
84 NavEntry('open_source', _('Open Source Licenses'),
85 'admin_settings_open_source', pyramid=True),
86 # TODO: marcink: we disable supervisor now until the supervisor stats
87 # page is fixed in the nix configuration
88 # NavEntry('supervisor', _('Supervisor'), 'admin_settings_supervisor'),
89 ]
90
91 _labs_entry = NavEntry('labs', _('Labs'),
92 'admin_settings_labs')
93
94 def __init__(self, labs_active=False):
95 self._registered_entries = collections.OrderedDict([
96 (item.key, item) for item in self.__class__._base_entries
97 ])
98
99 if labs_active:
100 self.add_entry(self._labs_entry)
101
102 def add_entry(self, entry):
103 self._registered_entries[entry.key] = entry
104
105 def get_navlist(self, request):
106 navlist = [NavListEntry(i.key, i.name, i.generate_url(request))
107 for i in self._registered_entries.values()]
108 return navlist
109
110
111 def navigation_registry(request):
112 """
113 Helper that returns the admin navigation registry.
114 """
115 pyramid_registry = get_registry(request)
116 nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry)
117 return nav_registry
118
119
120 def navigation_list(request):
121 """
122 Helper that returns the admin navigation as list of NavListEntry objects.
123 """
124 return navigation_registry(request).get_navlist(request)
@@ -0,0 +1,55 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import collections
22 import logging
23
24 from pylons import tmpl_context as c
25 from pyramid.view import view_config
26
27 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
28 from rhodecode.lib.utils import read_opensource_licenses
29
30 from .navigation import navigation_list
31
32
33 log = logging.getLogger(__name__)
34
35
36 class AdminSettingsView(object):
37
38 def __init__(self, context, request):
39 self.request = request
40 self.context = context
41 self.session = request.session
42 self._rhodecode_user = request.user
43
44 @LoginRequired()
45 @HasPermissionAllDecorator('hg.admin')
46 @view_config(
47 route_name='admin_settings_open_source', request_method='GET',
48 renderer='rhodecode:templates/admin/settings/settings.html')
49 def open_source_licenses(self):
50 c.active = 'open_source'
51 c.navlist = navigation_list(self.request)
52 c.opensource_licenses = collections.OrderedDict(
53 sorted(read_opensource_licenses().items(), key=lambda t: t[0]))
54
55 return {}
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -0,0 +1,92 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import pytest
23
24
25 class EnabledAuthPlugin():
26 """
27 Context manager that updates the 'auth_plugins' setting in DB to enable
28 a plugin. Previous setting is restored on exit. The rhodecode auth plugin
29 is also enabled because it is needed to login the test users.
30 """
31
32 def __init__(self, plugin):
33 self.new_value = set([
34 'egg:rhodecode-enterprise-ce#rhodecode',
35 plugin.get_id()
36 ])
37
38 def __enter__(self):
39 from rhodecode.model.settings import SettingsModel
40 self._old_value = SettingsModel().get_auth_plugins()
41 SettingsModel().create_or_update_setting(
42 'auth_plugins', ','.join(self.new_value))
43
44 def __exit__(self, type, value, traceback):
45 from rhodecode.model.settings import SettingsModel
46 SettingsModel().create_or_update_setting(
47 'auth_plugins', ','.join(self._old_value))
48
49
50 class DisabledAuthPlugin():
51 """
52 Context manager that updates the 'auth_plugins' setting in DB to disable
53 a plugin. Previous setting is restored on exit.
54 """
55
56 def __init__(self, plugin):
57 self.plugin_id = plugin.get_id()
58
59 def __enter__(self):
60 from rhodecode.model.settings import SettingsModel
61 self._old_value = SettingsModel().get_auth_plugins()
62 new_value = [id_ for id_ in self._old_value if id_ != self.plugin_id]
63 SettingsModel().create_or_update_setting(
64 'auth_plugins', ','.join(new_value))
65
66 def __exit__(self, type, value, traceback):
67 from rhodecode.model.settings import SettingsModel
68 SettingsModel().create_or_update_setting(
69 'auth_plugins', ','.join(self._old_value))
70
71
72 @pytest.fixture(params=[
73 ('rhodecode.authentication.plugins.auth_crowd', 'egg:rhodecode-enterprise-ce#crowd'),
74 ('rhodecode.authentication.plugins.auth_headers', 'egg:rhodecode-enterprise-ce#headers'),
75 ('rhodecode.authentication.plugins.auth_jasig_cas', 'egg:rhodecode-enterprise-ce#jasig_cas'),
76 ('rhodecode.authentication.plugins.auth_ldap', 'egg:rhodecode-enterprise-ce#ldap'),
77 ('rhodecode.authentication.plugins.auth_pam', 'egg:rhodecode-enterprise-ce#pam'),
78 ('rhodecode.authentication.plugins.auth_rhodecode', 'egg:rhodecode-enterprise-ce#rhodecode'),
79 ('rhodecode.authentication.plugins.auth_token', 'egg:rhodecode-enterprise-ce#token'),
80 ])
81 def auth_plugin(request):
82 """
83 Fixture that provides instance for each authentication plugin. These
84 instances are NOT the instances which are registered to the authentication
85 registry.
86 """
87 from importlib import import_module
88
89 # Create plugin instance.
90 module, plugin_id = request.param
91 plugin_module = import_module(module)
92 return plugin_module.plugin_factory(plugin_id)
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -0,0 +1,77 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import pytest
23
24 from rhodecode.authentication.tests.conftest import (
25 EnabledAuthPlugin, DisabledAuthPlugin)
26 from rhodecode.config.routing import ADMIN_PREFIX
27
28
29 @pytest.mark.usefixtures('autologin_user', 'app')
30 class TestAuthenticationSettings:
31
32 def test_auth_settings_global_view_get(self, app):
33 url = '{prefix}/auth/'.format(prefix=ADMIN_PREFIX)
34 response = app.get(url)
35 assert response.status_code == 200
36
37 def test_plugin_settings_view_get(self, app, auth_plugin):
38 url = '{prefix}/auth/{name}'.format(
39 prefix=ADMIN_PREFIX,
40 name=auth_plugin.name)
41 with EnabledAuthPlugin(auth_plugin):
42 response = app.get(url)
43 assert response.status_code == 200
44
45 def test_plugin_settings_view_post(self, app, auth_plugin, csrf_token):
46 url = '{prefix}/auth/{name}'.format(
47 prefix=ADMIN_PREFIX,
48 name=auth_plugin.name)
49 params = {
50 'enabled': True,
51 'cache_ttl': 0,
52 'csrf_token': csrf_token,
53 }
54 with EnabledAuthPlugin(auth_plugin):
55 response = app.post(url, params=params)
56 assert response.status_code in [200, 302]
57
58 def test_plugin_settings_view_get_404(self, app, auth_plugin):
59 url = '{prefix}/auth/{name}'.format(
60 prefix=ADMIN_PREFIX,
61 name=auth_plugin.name)
62 with DisabledAuthPlugin(auth_plugin):
63 response = app.get(url, status=404)
64 assert response.status_code == 404
65
66 def test_plugin_settings_view_post_404(self, app, auth_plugin, csrf_token):
67 url = '{prefix}/auth/{name}'.format(
68 prefix=ADMIN_PREFIX,
69 name=auth_plugin.name)
70 params = {
71 'enabled': True,
72 'cache_ttl': 0,
73 'csrf_token': csrf_token,
74 }
75 with DisabledAuthPlugin(auth_plugin):
76 response = app.post(url, params=params, status=404)
77 assert response.status_code == 404
@@ -0,0 +1,28 b''
1 # Copyright (C) 2016 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 """
20 Checks around the API of the class RhodeCodeAuthPluginBase.
21 """
22
23 from rhodecode.authentication.base import RhodeCodeAuthPluginBase
24
25
26 def test_str_returns_plugin_id():
27 plugin = RhodeCodeAuthPluginBase(plugin_id='stub_plugin_id')
28 assert str(plugin) == 'stub_plugin_id'
@@ -0,0 +1,75 b''
1 <%
2 elems = [
3 ## general
4 (_('RhodeCode Enterprise version'), c.rhodecode_version, ''),
5 (_('Upgrade info endpoint'), c.rhodecode_update_url, ''),
6 (_('Configuration INI file'), c.rhodecode_config_ini, ''),
7 ## systems stats
8 (_('RhodeCode Enterprise Server IP'), c.server_ip, ''),
9 (_('RhodeCode Enterprise Server ID'), c.server_id, ''),
10 (_('Platform'), c.platform, ''),
11 (_('Uptime'), c.uptime_age, ''),
12 (_('Storage location'), c.storage, ''),
13 (_('Storage disk space'), "%s/%s, %s%% used%s" % (h.format_byte_size_binary(c.disk['used']), h.format_byte_size_binary(c.disk['total']),(c.disk['percent']), ' %s' % c.disk['error'] if 'error' in c.disk else ''), ''),
14
15 (_('Search index storage'), c.index_storage, ''),
16 (_('Search index size'), "%s %s" % (h.format_byte_size_binary(c.disk_index['used']), ' %s' % c.disk_index['error'] if 'error' in c.disk_index else ''), ''),
17
18 (_('Gist storage'), c.gist_storage, ''),
19 (_('Gist storage size'), "%s (%s items)%s" % (h.format_byte_size_binary(c.disk_gist['used']),c.disk_gist['items'], ' %s' % c.disk_gist['error'] if 'error' in c.disk_gist else ''), ''),
20
21 (_('Archive cache'), c.archive_storage, ''),
22 (_('Archive cache size'), "%s%s" % (h.format_byte_size_binary(c.disk_archive['used']), ' %s' % c.disk_archive['error'] if 'error' in c.disk_archive else ''), ''),
23
24 (_('System memory'), c.system_memory, ''),
25 (_('CPU'), '%s %%' %(c.cpu), ''),
26 (_('Load'), '1min: %s, 5min: %s, 15min: %s' %(c.load['1_min'],c.load['5_min'],c.load['15_min']), ''),
27
28 ## rhodecode stuff
29 (_('Python version'), c.py_version, ''),
30 (_('Python path'), c.py_path, ''),
31 (_('GIT version'), c.git_version, ''),
32 (_('HG version'), c.hg_version, ''),
33 (_('SVN version'), c.svn_version, ''),
34 (_('Database'), "%s @ version: %s" % (c.db_type, c.db_migrate_version), ''),
35 (_('Database version'), c.db_version, ''),
36
37 ]
38 %>
39
40 <pre>
41 SYSTEM INFO
42 -----------
43
44 % for dt, dd, tt in elems:
45 ${dt}: ${dd}
46 % endfor
47
48 PYTHON PACKAGES
49 ---------------
50
51 % for key, value in c.py_modules:
52 ${key}: ${value}
53 % endfor
54
55 SYSTEM SETTINGS
56 ---------------
57
58 % for key, value in sorted(c.rhodecode_ini_safe.items()):
59 % if isinstance(value, dict):
60
61 % for key2, value2 in value.items():
62 [${key}]${key2}: ${value2}
63 % endfor
64
65 % else:
66 ${key}: ${value}
67 % endif
68 % endfor
69
70 </pre>
71
72
73
74
75
@@ -1,5 +1,5 b''
1 [bumpversion]
1 [bumpversion]
2 current_version = 4.1.2
2 current_version = 4.2.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]
@@ -1,32 +1,26 b''
1 [DEFAULT]
1 [DEFAULT]
2 done = false
2 done = false
3
3
4 [task:fixes_on_stable]
5
6 [task:changelog_updated]
7
4 [task:bump_version]
8 [task:bump_version]
5 done = true
9 done = true
6
10
7 [task:rc_tools_pinned]
11 [task:generate_api_docs]
8 done = true
12
13 [task:updated_translation]
9
14
10 [task:fixes_on_stable]
15 [release]
11 done = true
16 state = in_progress
17 version = 4.2.0
18
19 [task:rc_tools_pinned]
12
20
13 [task:pip2nix_generated]
21 [task:pip2nix_generated]
14 done = true
15
16 [task:changelog_updated]
17 done = true
18
19 [task:generate_api_docs]
20 done = true
21
22
22 [task:generate_js_routes]
23 [task:generate_js_routes]
23 done = true
24
25 [release]
26 state = prepared
27 version = 4.1.2
28
29 [task:updated_translation]
30
24
31 [task:updated_trial_license]
25 [task:updated_trial_license]
32
26
@@ -41,6 +41,19 b' The latest sources can be obtained from '
41 https://code.rhodecode.com
41 https://code.rhodecode.com
42
42
43
43
44 Contributions
45 -------------
46
47 RhodeCode is open-source; contributions are welcome!
48
49 Please see the contribution documentation inside of the docs folder, which is
50 also available at
51 https://docs.rhodecode.com/RhodeCode-Enterprise/contributing/contributing.html
52
53 For additional information about collaboration tools, our issue tracker,
54 licensing, and contribution credit, visit https://rhodecode.com/open-source
55
56
44 RhodeCode Features
57 RhodeCode Features
45 ------------------
58 ------------------
46
59
@@ -1,7 +1,7 b''
1 README - Quickstart
1 README - Quickstart
2 ===================
2 ===================
3
3
4 This folder contains functional tests and the automation of specification
4 This folder contains the functional tests and automation of specification
5 examples. Details about testing can be found in
5 examples. Details about testing can be found in
6 `/docs-internal/testing/index.rst`.
6 `/docs-internal/testing/index.rst`.
7
7
@@ -21,7 +21,7 b' Use the following example call for the d'
21 --api-key=9999999999999999999999999999999999999999 \
21 --api-key=9999999999999999999999999999999999999999 \
22 your-enterprise-config.ini
22 your-enterprise-config.ini
23
23
24 This way the username, password and auth token of the admin user will match the
24 This way the username, password, and auth token of the admin user will match the
25 defaults from the test run.
25 defaults from the test run.
26
26
27
27
@@ -34,7 +34,7 b' 1. Make sure your Rhodecode Enterprise i'
34 2. Enter `nix-shell` from the acceptance_tests folder::
34 2. Enter `nix-shell` from the acceptance_tests folder::
35
35
36 cd acceptance_tests
36 cd acceptance_tests
37 nix-shell -I ~/dev
37 nix-shell
38
38
39 Make sure that `rcpkgs` and `rcnixpkgs` are available on the nix path.
39 Make sure that `rcpkgs` and `rcnixpkgs` are available on the nix path.
40
40
@@ -8,7 +8,6 b''
8
8
9 [DEFAULT]
9 [DEFAULT]
10 debug = true
10 debug = true
11 pdebug = false
12 ################################################################################
11 ################################################################################
13 ## Uncomment and replace with the email address which should receive ##
12 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
13 ## any error reports after an application crash ##
@@ -115,11 +114,23 b' rhodecode.api.url = /_admin/api'
115
114
116 ## END RHODECODE PLUGINS ##
115 ## END RHODECODE PLUGINS ##
117
116
117 ## encryption key used to encrypt social plugin tokens,
118 ## remote_urls with credentials etc, if not set it defaults to
119 ## `beaker.session.secret`
120 #rhodecode.encrypted_values.secret =
121
122 ## decryption strict mode (enabled by default). It controls if decryption raises
123 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
124 #rhodecode.encrypted_values.strict = false
125
118 full_stack = true
126 full_stack = true
119
127
120 ## Serve static files via RhodeCode, disable to serve them via HTTP server
128 ## Serve static files via RhodeCode, disable to serve them via HTTP server
121 static_files = true
129 static_files = true
122
130
131 # autogenerate javascript routes file on startup
132 generate_js_files = false
133
123 ## Optional Languages
134 ## Optional Languages
124 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
135 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
125 lang = en
136 lang = en
@@ -380,7 +391,6 b' beaker.session.auto = false'
380 search.module = rhodecode.lib.index.whoosh
391 search.module = rhodecode.lib.index.whoosh
381 search.location = %(here)s/data/index
392 search.location = %(here)s/data/index
382
393
383
384 ###################################
394 ###################################
385 ## APPENLIGHT CONFIG ##
395 ## APPENLIGHT CONFIG ##
386 ###################################
396 ###################################
@@ -514,7 +524,7 b' vcs.connection_timeout = 3600'
514 ### LOGGING CONFIGURATION ####
524 ### LOGGING CONFIGURATION ####
515 ################################
525 ################################
516 [loggers]
526 [loggers]
517 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates, whoosh_indexer
527 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates
518
528
519 [handlers]
529 [handlers]
520 keys = console, console_sql
530 keys = console, console_sql
@@ -566,12 +576,6 b' handlers = console_sql'
566 qualname = sqlalchemy.engine
576 qualname = sqlalchemy.engine
567 propagate = 0
577 propagate = 0
568
578
569 [logger_whoosh_indexer]
570 level = DEBUG
571 handlers =
572 qualname = whoosh_indexer
573 propagate = 1
574
575 ##############
579 ##############
576 ## HANDLERS ##
580 ## HANDLERS ##
577 ##############
581 ##############
@@ -8,7 +8,6 b''
8
8
9 [DEFAULT]
9 [DEFAULT]
10 debug = true
10 debug = true
11 pdebug = false
12 ################################################################################
11 ################################################################################
13 ## Uncomment and replace with the email address which should receive ##
12 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
13 ## any error reports after an application crash ##
@@ -89,11 +88,23 b' use = egg:rhodecode-enterprise-ce'
89 ## enable proxy prefix middleware, defined below
88 ## enable proxy prefix middleware, defined below
90 #filter-with = proxy-prefix
89 #filter-with = proxy-prefix
91
90
91 ## encryption key used to encrypt social plugin tokens,
92 ## remote_urls with credentials etc, if not set it defaults to
93 ## `beaker.session.secret`
94 #rhodecode.encrypted_values.secret =
95
96 ## decryption strict mode (enabled by default). It controls if decryption raises
97 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
98 #rhodecode.encrypted_values.strict = false
99
92 full_stack = true
100 full_stack = true
93
101
94 ## Serve static files via RhodeCode, disable to serve them via HTTP server
102 ## Serve static files via RhodeCode, disable to serve them via HTTP server
95 static_files = true
103 static_files = true
96
104
105 # autogenerate javascript routes file on startup
106 generate_js_files = false
107
97 ## Optional Languages
108 ## Optional Languages
98 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
109 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
99 lang = en
110 lang = en
@@ -354,7 +365,6 b' beaker.session.auto = false'
354 search.module = rhodecode.lib.index.whoosh
365 search.module = rhodecode.lib.index.whoosh
355 search.location = %(here)s/data/index
366 search.location = %(here)s/data/index
356
367
357
358 ###################################
368 ###################################
359 ## APPENLIGHT CONFIG ##
369 ## APPENLIGHT CONFIG ##
360 ###################################
370 ###################################
@@ -483,7 +493,7 b' vcs.connection_timeout = 3600'
483 ### LOGGING CONFIGURATION ####
493 ### LOGGING CONFIGURATION ####
484 ################################
494 ################################
485 [loggers]
495 [loggers]
486 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates, whoosh_indexer
496 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates
487
497
488 [handlers]
498 [handlers]
489 keys = console, console_sql
499 keys = console, console_sql
@@ -535,12 +545,6 b' handlers = console_sql'
535 qualname = sqlalchemy.engine
545 qualname = sqlalchemy.engine
536 propagate = 0
546 propagate = 0
537
547
538 [logger_whoosh_indexer]
539 level = DEBUG
540 handlers =
541 qualname = whoosh_indexer
542 propagate = 1
543
544 ##############
548 ##############
545 ## HANDLERS ##
549 ## HANDLERS ##
546 ##############
550 ##############
@@ -46,6 +46,7 b' let'
46 !elem ext ["egg-info" "pyc"] &&
46 !elem ext ["egg-info" "pyc"] &&
47 !startsWith "result" path;
47 !startsWith "result" path;
48
48
49 sources = pkgs.config.rc.sources or {};
49 rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.;
50 rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.;
50
51
51 # Load the generated node packages
52 # Load the generated node packages
@@ -98,9 +99,11 b' let'
98 '';
99 '';
99 in super.rhodecode-enterprise-ce.override (attrs: {
100 in super.rhodecode-enterprise-ce.override (attrs: {
100
101
101 inherit doCheck;
102 inherit
103 doCheck
104 version;
102 name = "rhodecode-enterprise-ce-${version}";
105 name = "rhodecode-enterprise-ce-${version}";
103 version = version;
106 releaseName = "RhodeCodeEnterpriseCE-${version}";
104 src = rhodecode-enterprise-ce-src;
107 src = rhodecode-enterprise-ce-src;
105
108
106 buildInputs =
109 buildInputs =
@@ -109,7 +112,7 b' let'
109 pkgs.nodePackages.grunt-cli
112 pkgs.nodePackages.grunt-cli
110 pkgs.subversion
113 pkgs.subversion
111 pytest-catchlog
114 pytest-catchlog
112 rc_testdata
115 rhodecode-testdata
113 ]);
116 ]);
114
117
115 propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [
118 propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [
@@ -197,17 +200,22 b' let'
197
200
198 });
201 });
199
202
200 rc_testdata = self.buildPythonPackage rec {
203 rhodecode-testdata = import "${rhodecode-testdata-src}/default.nix" {
201 name = "rc_testdata-0.7.0";
204 inherit
202 src = pkgs.fetchhg {
205 doCheck
203 url = "https://code.rhodecode.com/upstream/rc_testdata";
206 pkgs
204 rev = "v0.7.0";
207 pythonPackages;
205 sha256 = "0w3z0zn8lagr707v67lgys23sl6pbi4xg7pfvdbw58h3q384h6rx";
206 };
207 };
208 };
208
209
209 };
210 };
210
211
212 rhodecode-testdata-src = sources.rhodecode-testdata or (
213 pkgs.fetchhg {
214 url = "https://code.rhodecode.com/upstream/rc_testdata";
215 rev = "v0.8.0";
216 sha256 = "0hy1ba134rq2f9si85yx7j4qhc9ky0hjzdk553s3q026i7km809m";
217 });
218
211 # Apply all overrides and fix the final package set
219 # Apply all overrides and fix the final package set
212 myPythonPackagesUnfix =
220 myPythonPackagesUnfix =
213 (extends pythonExternalOverrides
221 (extends pythonExternalOverrides
@@ -47,7 +47,7 b' the ``debug`` level.'
47 ### LOGGING CONFIGURATION ####
47 ### LOGGING CONFIGURATION ####
48 ################################
48 ################################
49 [loggers]
49 [loggers]
50 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates, whoosh_indexer
50 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates
51
51
52 [handlers]
52 [handlers]
53 keys = console, console_sql, file, file_rotating
53 keys = console, console_sql, file, file_rotating
@@ -99,12 +99,6 b' the ``debug`` level.'
99 qualname = sqlalchemy.engine
99 qualname = sqlalchemy.engine
100 propagate = 0
100 propagate = 0
101
101
102 [logger_whoosh_indexer]
103 level = DEBUG
104 handlers =
105 qualname = whoosh_indexer
106 propagate = 1
107
108 ##############
102 ##############
109 ## HANDLERS ##
103 ## HANDLERS ##
110 ##############
104 ##############
@@ -5,13 +5,14 b' Contributing to RhodeCode'
5
5
6
6
7
7
8 Welcome to contribution guides and development docs of RhodeCode.
8 Welcome to the contribution guides and development docs of RhodeCode.
9
9
10
10
11
11
12 .. toctree::
12 .. toctree::
13 :maxdepth: 1
13 :maxdepth: 1
14
14
15 overview
15 testing/index
16 testing/index
16 dev-setup
17 dev-setup
17 db-schema
18 db-schema
@@ -2,7 +2,7 b''
2 DB Schema and Migration
2 DB Schema and Migration
3 =======================
3 =======================
4
4
5 To create or alter tables in the database it's necessary to change a couple of
5 To create or alter tables in the database, it's necessary to change a couple of
6 files, apart from configuring the settings pointing to the latest database
6 files, apart from configuring the settings pointing to the latest database
7 schema.
7 schema.
8
8
@@ -11,11 +11,11 b' Database Model and ORM'
11 ----------------------
11 ----------------------
12
12
13 On ``rhodecode.model.db`` you will find the database definition of all tables and
13 On ``rhodecode.model.db`` you will find the database definition of all tables and
14 fields. Any fresh install database will be correctly created by the definitions
14 fields. Any freshly installed database will be correctly created by the definitions
15 here. So, any change to this files will affect the tests without having to change
15 here. So, any change to this file will affect the tests without having to change
16 any other file.
16 any other file.
17
17
18 A second layer are the businness classes that are inside ``rhodecode.model``.
18 A second layer are the business classes inside ``rhodecode.model``.
19
19
20
20
21 Database Migration
21 Database Migration
@@ -30,7 +30,7 b' Three files play a role when creating da'
30
30
31 Schema is a snapshot of the database version BEFORE the migration. So, it's
31 Schema is a snapshot of the database version BEFORE the migration. So, it's
32 the initial state before any changes were added. The name convention is
32 the initial state before any changes were added. The name convention is
33 the latest release version where the snapshot were created, and not the
33 the latest release version where the snapshot was created, and not the
34 target version of this code.
34 target version of this code.
35
35
36 Version is the method that will define how to UPGRADE/DOWNGRADE the database.
36 Version is the method that will define how to UPGRADE/DOWNGRADE the database.
@@ -45,8 +45,8 b' For examples on how to create those file'
45 Migration Command
45 Migration Command
46 ^^^^^^^^^^^^^^^^^
46 ^^^^^^^^^^^^^^^^^
47
47
48 After you changed the database ORM and migration files, you can run::
48 After you've changed the database ORM and migration files, you can run::
49
49
50 paster upgrade-db <ini-file>
50 paster upgrade-db <ini-file>
51
51
52 And the database will be upgraded up to the version defined in the ``__init__`` file. No newline at end of file
52 The database will be upgraded up to the version defined in the ``__init__`` file. No newline at end of file
@@ -13,7 +13,7 b' purposes. This section contains an overv'
13 =============
13 =============
14
14
15 Enables the section "Style" in the application. This section provides an
15 Enables the section "Style" in the application. This section provides an
16 overview of all components which are found in the frontend style of the
16 overview of all components which are found in the frontend of the
17 application.
17 application.
18
18
19
19
@@ -29,9 +29,9 b' to ease development.'
29 `[logging]`
29 `[logging]`
30 ===========
30 ===========
31
31
32 Use this to configure loggig to your current needs. The documentation of
32 Use this to configure logging to your current needs. The documentation of
33 Python's `logging` module explains all details. The following snippets are
33 Python's `logging` module explains all of the details. The following snippets
34 useful for day to day development work.
34 are useful for day to day development work.
35
35
36
36
37 Mute SQL output
37 Mute SQL output
@@ -1,3 +1,4 b''
1 .. _dev-setup:
1
2
2 ===================
3 ===================
3 Development setup
4 Development setup
@@ -7,21 +8,21 b''
7 RhodeCode Enterprise runs inside a Nix managed environment. This ensures build
8 RhodeCode Enterprise runs inside a Nix managed environment. This ensures build
8 environment dependencies are correctly declared and installed during setup.
9 environment dependencies are correctly declared and installed during setup.
9 It also enables atomic upgrades, rollbacks, and multiple instances of RhodeCode
10 It also enables atomic upgrades, rollbacks, and multiple instances of RhodeCode
10 Enterprise for efficient cluster management.
11 Enterprise running with isolation.
11
12
12 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:
13
14
14
15
15
16
16 Setup Nix Package Manager
17 Setup Nix Package Manager
17 -------------------------
18 -------------------------
18
19
19 To install the Nix Package Manager please run::
20 To install the Nix Package Manager, please run::
20
21
21 $ curl https://nixos.org/nix/install | sh
22 $ curl https://nixos.org/nix/install | sh
22
23
23 or go to https://nixos.org/nix/ and follow their installation instructions.
24 or go to https://nixos.org/nix/ and follow the installation instructions.
24 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
25 following commands:
26 following commands:
26
27
27 * `nix-env`
28 * `nix-env`
@@ -34,8 +35,8 b' following commands:'
34 Update your channels frequently by running ``nix-channel --upgrade``.
35 Update your channels frequently by running ``nix-channel --upgrade``.
35
36
36
37
37 Switch nix to latest STABLE channel
38 Switch nix to the latest STABLE channel
38 -----------------------------------
39 ---------------------------------------
39
40
40 run::
41 run::
41
42
@@ -49,7 +50,7 b' Followed by::'
49 Clone the required repositories
50 Clone the required repositories
50 -------------------------------
51 -------------------------------
51
52
52 After Nix is set up, clone the RhodeCode Enterprise Community Edition, and
53 After Nix is set up, clone the RhodeCode Enterprise Community Edition and
53 RhodeCode VCSServer repositories into the same directory.
54 RhodeCode VCSServer repositories into the same directory.
54 To do this, use the following example::
55 To do this, use the following example::
55
56
@@ -59,23 +60,25 b' To do this, use the following example::'
59
60
60 .. note::
61 .. note::
61
62
62 If you cannot clone the repository, please request read permissions.
63 If you cannot clone the repository, please request read permissions
64 via support@rhodecode.com
63
65
64
66
65
67
66 Enter the Development Shell
68 Enter the Development Shell
67 ---------------------------
69 ---------------------------
68
70
69 The final step is to start into the development shell. To do this run the
71 The final step is to start the development shell. To do this, run the
70 following command from inside the cloned repository::
72 following command from inside the cloned repository::
71
73
72 cd ~/rhodecode-enterprise-ce
74 cd ~/rhodecode-enterprise-ce
73 nix-shell --arg dev true
75 nix-shell
74
76
75 .. note::
77 .. note::
76
78
77 On the first run, this will take a while to download and optionally compile
79 On the first run, this will take a while to download and optionally compile
78 a few things. The next runs of it will be faster.
80 a few things. The following runs will be faster. The development shell works
81 fine on MacOS and Linux platforms.
79
82
80
83
81
84
@@ -90,13 +93,13 b' 2. Adjust the configuration settings to '
90
93
91 .. note::
94 .. note::
92
95
93 It is recommended to call it `dev.ini`.
96 It is recommended to use the name `dev.ini`.
94
97
95
98
96 Setup the Development Database
99 Setup the Development Database
97 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
100 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
98
101
99 To create a development database use the following example. This is a one
102 To create a development database, use the following example. This is a one
100 time operation::
103 time operation::
101
104
102 paster setup-rhodecode dev.ini \
105 paster setup-rhodecode dev.ini \
@@ -109,7 +112,7 b' Start the Development Server'
109 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
112 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
110
113
111 When starting the development server, you should start the vcsserver as a
114 When starting the development server, you should start the vcsserver as a
112 separate process. To do this use one of the following examples:
115 separate process. To do this, use one of the following examples:
113
116
114 1. Set the `start.vcs_server` flag in the ``dev.ini`` file to true. For example:
117 1. Set the `start.vcs_server` flag in the ``dev.ini`` file to true. For example:
115
118
@@ -136,6 +139,6 b' 3. Start the development server in a dif'
136 Run the Environment Tests
139 Run the Environment Tests
137 ^^^^^^^^^^^^^^^^^^^^^^^^^
140 ^^^^^^^^^^^^^^^^^^^^^^^^^
138
141
139 Please make sure that the test are passing to verify that your environment is
142 Please make sure that the tests are passing to verify that your environment is
140 set up correctly. More details about the tests are described in:
143 set up correctly. RhodeCode uses py.test to run tests.
141 :file:`/docs/dev/testing`.
144 Please simply run ``make test`` to run the basic test suite.
@@ -17,12 +17,12 b''
17 Overview
17 Overview
18 ========
18 ========
19
19
20 We have a quite big test suite inside of :file:`rhodecode/tests` which is a mix
20 We have a quite large test suite inside of :file:`rhodecode/tests` which is a mix
21 of unit tests and functional or integration tests. More details are in
21 of unit tests and functional or integration tests. More details are in
22 :ref:`test-unit-and-functional`.
22 :ref:`test-unit-and-functional`.
23
23
24
24
25 Apart from that we start to apply "Specification by Example" and maintain a
25 Apart from that, we are starting to apply "Specification by Example" and maintain
26 collection of such specifications together with an implementation so that it can
26 a collection of such specifications together with an implementation so that it
27 be validated in an automatic way. The files can be found in
27 can be validated in an automatic way. The files can be found in
28 :file:`acceptance_tests`. More details are in :ref:`test-spec-by-example`.
28 :file:`acceptance_tests`. More details are in :ref:`test-spec-by-example`.
@@ -66,10 +66,10 b' Locators'
66 --------
66 --------
67
67
68 The specific information how to locate an element inside of the DOM tree of a
68 The specific information how to locate an element inside of the DOM tree of a
69 page is kept in a separate class. This class serves mainly as a data container,
69 page is kept in a separate class. This class serves mainly as a data container;
70 it shall not contain any logic.
70 it shall not contain any logic.
71
71
72 The reason for keeping the locators separate is that we expect a frequent need
72 The reason for keeping the locators separate is that we expect a frequent need
73 for change whenever we work on our templates. In such a case it is more
73 for change whenever we work on our templates. In such a case, it is more
74 efficient to have all locators together and update them there instead of having
74 efficient to have all of thelocators together and update them there instead of
75 to find all locators inside of the logic of a page object.
75 having to find every locator inside of the logic of a page object.
@@ -27,7 +27,7 b' py.test integration'
27 The integration with the test runner is based on the following three parts:
27 The integration with the test runner is based on the following three parts:
28
28
29 - `pytest_pylons` is a py.test plugin which does the integration with the
29 - `pytest_pylons` is a py.test plugin which does the integration with the
30 Pylons web framework. It sets up the Pylons environment based on a given ini
30 Pylons web framework. It sets up the Pylons environment based on the given ini
31 file.
31 file.
32
32
33 Tests which depend on the Pylons environment to be set up must request the
33 Tests which depend on the Pylons environment to be set up must request the
@@ -9,6 +9,7 b' Release Notes'
9 .. toctree::
9 .. toctree::
10 :maxdepth: 1
10 :maxdepth: 1
11
11
12 release-notes-4.2.0.rst
12 release-notes-4.1.2.rst
13 release-notes-4.1.2.rst
13 release-notes-4.1.1.rst
14 release-notes-4.1.1.rst
14 release-notes-4.1.0.rst
15 release-notes-4.1.0.rst
@@ -34,9 +34,6 b' let'
34 # figure it out without calling into nix-store.
34 # figure it out without calling into nix-store.
35 enterprise = import ./default.nix {
35 enterprise = import ./default.nix {
36 doCheck = false;
36 doCheck = false;
37 with_vcsserver = false;
38 with_pyramid = false;
39 cythonize = false;
40 };
37 };
41
38
42 # For a given derivation, return the list of all dependencies
39 # For a given derivation, return the list of all dependencies
@@ -8,10 +8,28 b''
8
8
9 let
9 let
10 sed = "sed -i";
10 sed = "sed -i";
11 localLicenses = {
12 repoze = {
13 fullName = "Repoze License";
14 url = http://www.repoze.org/LICENSE.txt;
15 };
16 };
11 in
17 in
12
18
13 self: super: {
19 self: super: {
14
20
21 appenlight-client = super.appenlight-client.override (attrs: {
22 meta = {
23 license = [ pkgs.lib.licenses.bsdOriginal ];
24 };
25 });
26
27 future = super.future.override (attrs: {
28 meta = {
29 license = [ pkgs.lib.licenses.mit ];
30 };
31 });
32
15 gnureadline = super.gnureadline.override (attrs: {
33 gnureadline = super.gnureadline.override (attrs: {
16 buildInputs = attrs.buildInputs ++ [
34 buildInputs = attrs.buildInputs ++ [
17 pkgs.ncurses
35 pkgs.ncurses
@@ -72,6 +90,9 b' self: super: {'
72 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
90 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
73 pkgs.postgresql
91 pkgs.postgresql
74 ];
92 ];
93 meta = {
94 license = pkgs.lib.licenses.lgpl3Plus;
95 };
75 });
96 });
76
97
77 pycurl = super.pycurl.override (attrs: {
98 pycurl = super.pycurl.override (attrs: {
@@ -83,6 +104,10 b' self: super: {'
83 substituteInPlace setup.py --replace '--static-libs' '--libs'
104 substituteInPlace setup.py --replace '--static-libs' '--libs'
84 export PYCURL_SSL_LIBRARY=openssl
105 export PYCURL_SSL_LIBRARY=openssl
85 '';
106 '';
107 meta = {
108 # TODO: It is LGPL and MIT
109 license = pkgs.lib.licenses.mit;
110 };
86 });
111 });
87
112
88 Pylons = super.Pylons.override (attrs: {
113 Pylons = super.Pylons.override (attrs: {
@@ -101,6 +126,15 b' self: super: {'
101 # confuses pserve.
126 # confuses pserve.
102 ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped
127 ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped
103 '';
128 '';
129 meta = {
130 license = localLicenses.repoze;
131 };
132 });
133
134 pyramid-debugtoolbar = super.pyramid-debugtoolbar.override (attrs: {
135 meta = {
136 license = [ pkgs.lib.licenses.bsdOriginal localLicenses.repoze ];
137 };
104 });
138 });
105
139
106 Pyro4 = super.Pyro4.override (attrs: {
140 Pyro4 = super.Pyro4.override (attrs: {
@@ -117,6 +151,9 b' self: super: {'
117 propagatedBuildInputs = [
151 propagatedBuildInputs = [
118 pkgs.sqlite
152 pkgs.sqlite
119 ];
153 ];
154 meta = {
155 license = [ pkgs.lib.licenses.zlib pkgs.lib.licenses.libpng ];
156 };
120 });
157 });
121
158
122 pytest-runner = super.pytest-runner.override (attrs: {
159 pytest-runner = super.pytest-runner.override (attrs: {
@@ -158,6 +195,77 b' self: super: {'
158 ];
195 ];
159 });
196 });
160
197
198 URLObject = super.URLObject.override (attrs: {
199 meta = {
200 license = {
201 spdxId = "Unlicense";
202 fullName = "The Unlicense";
203 url = http://unlicense.org/;
204 };
205 };
206 });
207
208 amqplib = super.amqplib.override (attrs: {
209 meta = {
210 license = pkgs.lib.licenses.lgpl3;
211 };
212 });
213
214 docutils = super.docutils.override (attrs: {
215 meta = {
216 license = pkgs.lib.licenses.bsd2;
217 };
218 });
219
220 colander = super.colander.override (attrs: {
221 meta = {
222 license = localLicenses.repoze;
223 };
224 });
225
226 pyramid-beaker = super.pyramid-beaker.override (attrs: {
227 meta = {
228 license = localLicenses.repoze;
229 };
230 });
231
232 pyramid-mako = super.pyramid-mako.override (attrs: {
233 meta = {
234 license = localLicenses.repoze;
235 };
236 });
237
238 repoze.lru = super.repoze.lru.override (attrs: {
239 meta = {
240 license = localLicenses.repoze;
241 };
242 });
243
244 recaptcha-client = super.recaptcha-client.override (attrs: {
245 meta = {
246 # TODO: It is MIT/X11
247 license = pkgs.lib.licenses.mit;
248 };
249 });
250
251 python-editor = super.python-editor.override (attrs: {
252 meta = {
253 license = pkgs.lib.licenses.asl20;
254 };
255 });
256
257 translationstring = super.translationstring.override (attrs: {
258 meta = {
259 license = localLicenses.repoze;
260 };
261 });
262
263 venusian = super.venusian.override (attrs: {
264 meta = {
265 license = localLicenses.repoze;
266 };
267 });
268
161 # Avoid that setuptools is replaced, this leads to trouble
269 # Avoid that setuptools is replaced, this leads to trouble
162 # with buildPythonPackage.
270 # with buildPythonPackage.
163 setuptools = basePythonPackages.setuptools;
271 setuptools = basePythonPackages.setuptools;
@@ -8,6 +8,9 b''
8 url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz";
8 url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz";
9 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
9 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
10 };
10 };
11 meta = {
12 license = [ pkgs.lib.licenses.bsdOriginal ];
13 };
11 };
14 };
12 Beaker = super.buildPythonPackage {
15 Beaker = super.buildPythonPackage {
13 name = "Beaker-1.7.0";
16 name = "Beaker-1.7.0";
@@ -18,6 +21,9 b''
18 url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz";
21 url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz";
19 md5 = "386be3f7fe427358881eee4622b428b3";
22 md5 = "386be3f7fe427358881eee4622b428b3";
20 };
23 };
24 meta = {
25 license = [ pkgs.lib.licenses.bsdOriginal ];
26 };
21 };
27 };
22 CProfileV = super.buildPythonPackage {
28 CProfileV = super.buildPythonPackage {
23 name = "CProfileV-1.0.6";
29 name = "CProfileV-1.0.6";
@@ -28,6 +34,9 b''
28 url = "https://pypi.python.org/packages/eb/df/983a0b6cfd3ac94abf023f5011cb04f33613ace196e33f53c86cf91850d5/CProfileV-1.0.6.tar.gz";
34 url = "https://pypi.python.org/packages/eb/df/983a0b6cfd3ac94abf023f5011cb04f33613ace196e33f53c86cf91850d5/CProfileV-1.0.6.tar.gz";
29 md5 = "08c7c242b6e64237bc53c5d13537e03d";
35 md5 = "08c7c242b6e64237bc53c5d13537e03d";
30 };
36 };
37 meta = {
38 license = [ pkgs.lib.licenses.mit ];
39 };
31 };
40 };
32 Fabric = super.buildPythonPackage {
41 Fabric = super.buildPythonPackage {
33 name = "Fabric-1.10.0";
42 name = "Fabric-1.10.0";
@@ -38,6 +47,9 b''
38 url = "https://pypi.python.org/packages/e3/5f/b6ebdb5241d5ec9eab582a5c8a01255c1107da396f849e538801d2fe64a5/Fabric-1.10.0.tar.gz";
47 url = "https://pypi.python.org/packages/e3/5f/b6ebdb5241d5ec9eab582a5c8a01255c1107da396f849e538801d2fe64a5/Fabric-1.10.0.tar.gz";
39 md5 = "2cb96473387f0e7aa035210892352f4a";
48 md5 = "2cb96473387f0e7aa035210892352f4a";
40 };
49 };
50 meta = {
51 license = [ pkgs.lib.licenses.bsdOriginal ];
52 };
41 };
53 };
42 FormEncode = super.buildPythonPackage {
54 FormEncode = super.buildPythonPackage {
43 name = "FormEncode-1.2.4";
55 name = "FormEncode-1.2.4";
@@ -48,6 +60,9 b''
48 url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz";
60 url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz";
49 md5 = "6bc17fb9aed8aea198975e888e2077f4";
61 md5 = "6bc17fb9aed8aea198975e888e2077f4";
50 };
62 };
63 meta = {
64 license = [ pkgs.lib.licenses.psfl ];
65 };
51 };
66 };
52 Jinja2 = super.buildPythonPackage {
67 Jinja2 = super.buildPythonPackage {
53 name = "Jinja2-2.7.3";
68 name = "Jinja2-2.7.3";
@@ -58,6 +73,9 b''
58 url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz";
73 url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz";
59 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
74 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
60 };
75 };
76 meta = {
77 license = [ pkgs.lib.licenses.bsdOriginal ];
78 };
61 };
79 };
62 Mako = super.buildPythonPackage {
80 Mako = super.buildPythonPackage {
63 name = "Mako-1.0.1";
81 name = "Mako-1.0.1";
@@ -68,6 +86,9 b''
68 url = "https://pypi.python.org/packages/8e/a4/aa56533ecaa5f22ca92428f74e074d0c9337282933c722391902c8f9e0f8/Mako-1.0.1.tar.gz";
86 url = "https://pypi.python.org/packages/8e/a4/aa56533ecaa5f22ca92428f74e074d0c9337282933c722391902c8f9e0f8/Mako-1.0.1.tar.gz";
69 md5 = "9f0aafd177b039ef67b90ea350497a54";
87 md5 = "9f0aafd177b039ef67b90ea350497a54";
70 };
88 };
89 meta = {
90 license = [ pkgs.lib.licenses.mit ];
91 };
71 };
92 };
72 Markdown = super.buildPythonPackage {
93 Markdown = super.buildPythonPackage {
73 name = "Markdown-2.6.2";
94 name = "Markdown-2.6.2";
@@ -78,6 +99,9 b''
78 url = "https://pypi.python.org/packages/62/8b/83658b5f6c220d5fcde9f9852d46ea54765d734cfbc5a9f4c05bfc36db4d/Markdown-2.6.2.tar.gz";
99 url = "https://pypi.python.org/packages/62/8b/83658b5f6c220d5fcde9f9852d46ea54765d734cfbc5a9f4c05bfc36db4d/Markdown-2.6.2.tar.gz";
79 md5 = "256d19afcc564dc4ce4c229bb762f7ae";
100 md5 = "256d19afcc564dc4ce4c229bb762f7ae";
80 };
101 };
102 meta = {
103 license = [ pkgs.lib.licenses.bsdOriginal ];
104 };
81 };
105 };
82 MarkupSafe = super.buildPythonPackage {
106 MarkupSafe = super.buildPythonPackage {
83 name = "MarkupSafe-0.23";
107 name = "MarkupSafe-0.23";
@@ -88,6 +112,9 b''
88 url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz";
112 url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz";
89 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
113 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
90 };
114 };
115 meta = {
116 license = [ pkgs.lib.licenses.bsdOriginal ];
117 };
91 };
118 };
92 MySQL-python = super.buildPythonPackage {
119 MySQL-python = super.buildPythonPackage {
93 name = "MySQL-python-1.2.5";
120 name = "MySQL-python-1.2.5";
@@ -98,6 +125,9 b''
98 url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip";
125 url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip";
99 md5 = "654f75b302db6ed8dc5a898c625e030c";
126 md5 = "654f75b302db6ed8dc5a898c625e030c";
100 };
127 };
128 meta = {
129 license = [ pkgs.lib.licenses.gpl1 ];
130 };
101 };
131 };
102 Paste = super.buildPythonPackage {
132 Paste = super.buildPythonPackage {
103 name = "Paste-2.0.2";
133 name = "Paste-2.0.2";
@@ -108,6 +138,9 b''
108 url = "https://pypi.python.org/packages/d5/8d/0f8ac40687b97ff3e07ebd1369be20bdb3f93864d2dc3c2ff542edb4ce50/Paste-2.0.2.tar.gz";
138 url = "https://pypi.python.org/packages/d5/8d/0f8ac40687b97ff3e07ebd1369be20bdb3f93864d2dc3c2ff542edb4ce50/Paste-2.0.2.tar.gz";
109 md5 = "4bfc8a7eaf858f6309d2ac0f40fc951c";
139 md5 = "4bfc8a7eaf858f6309d2ac0f40fc951c";
110 };
140 };
141 meta = {
142 license = [ pkgs.lib.licenses.mit ];
143 };
111 };
144 };
112 PasteDeploy = super.buildPythonPackage {
145 PasteDeploy = super.buildPythonPackage {
113 name = "PasteDeploy-1.5.2";
146 name = "PasteDeploy-1.5.2";
@@ -118,6 +151,9 b''
118 url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz";
151 url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz";
119 md5 = "352b7205c78c8de4987578d19431af3b";
152 md5 = "352b7205c78c8de4987578d19431af3b";
120 };
153 };
154 meta = {
155 license = [ pkgs.lib.licenses.mit ];
156 };
121 };
157 };
122 PasteScript = super.buildPythonPackage {
158 PasteScript = super.buildPythonPackage {
123 name = "PasteScript-1.7.5";
159 name = "PasteScript-1.7.5";
@@ -128,6 +164,9 b''
128 url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz";
164 url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz";
129 md5 = "4c72d78dcb6bb993f30536842c16af4d";
165 md5 = "4c72d78dcb6bb993f30536842c16af4d";
130 };
166 };
167 meta = {
168 license = [ pkgs.lib.licenses.mit ];
169 };
131 };
170 };
132 Pygments = super.buildPythonPackage {
171 Pygments = super.buildPythonPackage {
133 name = "Pygments-2.0.2";
172 name = "Pygments-2.0.2";
@@ -138,6 +177,9 b''
138 url = "https://pypi.python.org/packages/f4/c6/bdbc5a8a112256b2b6136af304dbae93d8b1ef8738ff2d12a51018800e46/Pygments-2.0.2.tar.gz";
177 url = "https://pypi.python.org/packages/f4/c6/bdbc5a8a112256b2b6136af304dbae93d8b1ef8738ff2d12a51018800e46/Pygments-2.0.2.tar.gz";
139 md5 = "238587a1370d62405edabd0794b3ec4a";
178 md5 = "238587a1370d62405edabd0794b3ec4a";
140 };
179 };
180 meta = {
181 license = [ pkgs.lib.licenses.bsdOriginal ];
182 };
141 };
183 };
142 Pylons = super.buildPythonPackage {
184 Pylons = super.buildPythonPackage {
143 name = "Pylons-1.0.1";
185 name = "Pylons-1.0.1";
@@ -148,6 +190,9 b''
148 url = "https://pypi.python.org/packages/a2/69/b835a6bad00acbfeed3f33c6e44fa3f936efc998c795bfb15c61a79ecf62/Pylons-1.0.1.tar.gz";
190 url = "https://pypi.python.org/packages/a2/69/b835a6bad00acbfeed3f33c6e44fa3f936efc998c795bfb15c61a79ecf62/Pylons-1.0.1.tar.gz";
149 md5 = "6cb880d75fa81213192142b07a6e4915";
191 md5 = "6cb880d75fa81213192142b07a6e4915";
150 };
192 };
193 meta = {
194 license = [ pkgs.lib.licenses.bsdOriginal ];
195 };
151 };
196 };
152 Pyro4 = super.buildPythonPackage {
197 Pyro4 = super.buildPythonPackage {
153 name = "Pyro4-4.41";
198 name = "Pyro4-4.41";
@@ -158,6 +203,9 b''
158 url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz";
203 url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz";
159 md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c";
204 md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c";
160 };
205 };
206 meta = {
207 license = [ pkgs.lib.licenses.mit ];
208 };
161 };
209 };
162 Routes = super.buildPythonPackage {
210 Routes = super.buildPythonPackage {
163 name = "Routes-1.13";
211 name = "Routes-1.13";
@@ -168,6 +216,9 b''
168 url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz";
216 url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz";
169 md5 = "d527b0ab7dd9172b1275a41f97448783";
217 md5 = "d527b0ab7dd9172b1275a41f97448783";
170 };
218 };
219 meta = {
220 license = [ pkgs.lib.licenses.bsdOriginal ];
221 };
171 };
222 };
172 SQLAlchemy = super.buildPythonPackage {
223 SQLAlchemy = super.buildPythonPackage {
173 name = "SQLAlchemy-0.9.9";
224 name = "SQLAlchemy-0.9.9";
@@ -178,6 +229,9 b''
178 url = "https://pypi.python.org/packages/28/f7/1bbfd0d8597e8c358d5e15a166a486ad82fc5579b4e67b6ef7c05b1d182b/SQLAlchemy-0.9.9.tar.gz";
229 url = "https://pypi.python.org/packages/28/f7/1bbfd0d8597e8c358d5e15a166a486ad82fc5579b4e67b6ef7c05b1d182b/SQLAlchemy-0.9.9.tar.gz";
179 md5 = "8a10a9bd13ed3336ef7333ac2cc679ff";
230 md5 = "8a10a9bd13ed3336ef7333ac2cc679ff";
180 };
231 };
232 meta = {
233 license = [ pkgs.lib.licenses.mit ];
234 };
181 };
235 };
182 Sphinx = super.buildPythonPackage {
236 Sphinx = super.buildPythonPackage {
183 name = "Sphinx-1.2.2";
237 name = "Sphinx-1.2.2";
@@ -188,6 +242,9 b''
188 url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz";
242 url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz";
189 md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4";
243 md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4";
190 };
244 };
245 meta = {
246 license = [ pkgs.lib.licenses.bsdOriginal ];
247 };
191 };
248 };
192 Tempita = super.buildPythonPackage {
249 Tempita = super.buildPythonPackage {
193 name = "Tempita-0.5.2";
250 name = "Tempita-0.5.2";
@@ -198,6 +255,9 b''
198 url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz";
255 url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz";
199 md5 = "4c2f17bb9d481821c41b6fbee904cea1";
256 md5 = "4c2f17bb9d481821c41b6fbee904cea1";
200 };
257 };
258 meta = {
259 license = [ pkgs.lib.licenses.mit ];
260 };
201 };
261 };
202 URLObject = super.buildPythonPackage {
262 URLObject = super.buildPythonPackage {
203 name = "URLObject-2.4.0";
263 name = "URLObject-2.4.0";
@@ -208,6 +268,9 b''
208 url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz";
268 url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz";
209 md5 = "2ed819738a9f0a3051f31dc9924e3065";
269 md5 = "2ed819738a9f0a3051f31dc9924e3065";
210 };
270 };
271 meta = {
272 license = [ ];
273 };
211 };
274 };
212 WebError = super.buildPythonPackage {
275 WebError = super.buildPythonPackage {
213 name = "WebError-0.10.3";
276 name = "WebError-0.10.3";
@@ -218,6 +281,9 b''
218 url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz";
281 url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz";
219 md5 = "84b9990b0baae6fd440b1e60cdd06f9a";
282 md5 = "84b9990b0baae6fd440b1e60cdd06f9a";
220 };
283 };
284 meta = {
285 license = [ pkgs.lib.licenses.mit ];
286 };
221 };
287 };
222 WebHelpers = super.buildPythonPackage {
288 WebHelpers = super.buildPythonPackage {
223 name = "WebHelpers-1.3";
289 name = "WebHelpers-1.3";
@@ -228,6 +294,9 b''
228 url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz";
294 url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz";
229 md5 = "32749ffadfc40fea51075a7def32588b";
295 md5 = "32749ffadfc40fea51075a7def32588b";
230 };
296 };
297 meta = {
298 license = [ pkgs.lib.licenses.bsdOriginal ];
299 };
231 };
300 };
232 WebHelpers2 = super.buildPythonPackage {
301 WebHelpers2 = super.buildPythonPackage {
233 name = "WebHelpers2-2.0";
302 name = "WebHelpers2-2.0";
@@ -238,6 +307,9 b''
238 url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz";
307 url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz";
239 md5 = "0f6b68d70c12ee0aed48c00b24da13d3";
308 md5 = "0f6b68d70c12ee0aed48c00b24da13d3";
240 };
309 };
310 meta = {
311 license = [ pkgs.lib.licenses.mit ];
312 };
241 };
313 };
242 WebOb = super.buildPythonPackage {
314 WebOb = super.buildPythonPackage {
243 name = "WebOb-1.3.1";
315 name = "WebOb-1.3.1";
@@ -248,6 +320,9 b''
248 url = "https://pypi.python.org/packages/16/78/adfc0380b8a0d75b2d543fa7085ba98a573b1ae486d9def88d172b81b9fa/WebOb-1.3.1.tar.gz";
320 url = "https://pypi.python.org/packages/16/78/adfc0380b8a0d75b2d543fa7085ba98a573b1ae486d9def88d172b81b9fa/WebOb-1.3.1.tar.gz";
249 md5 = "20918251c5726956ba8fef22d1556177";
321 md5 = "20918251c5726956ba8fef22d1556177";
250 };
322 };
323 meta = {
324 license = [ pkgs.lib.licenses.mit ];
325 };
251 };
326 };
252 WebTest = super.buildPythonPackage {
327 WebTest = super.buildPythonPackage {
253 name = "WebTest-1.4.3";
328 name = "WebTest-1.4.3";
@@ -258,6 +333,9 b''
258 url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip";
333 url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip";
259 md5 = "631ce728bed92c681a4020a36adbc353";
334 md5 = "631ce728bed92c681a4020a36adbc353";
260 };
335 };
336 meta = {
337 license = [ pkgs.lib.licenses.mit ];
338 };
261 };
339 };
262 Whoosh = super.buildPythonPackage {
340 Whoosh = super.buildPythonPackage {
263 name = "Whoosh-2.7.0";
341 name = "Whoosh-2.7.0";
@@ -268,6 +346,9 b''
268 url = "https://pypi.python.org/packages/1c/dc/2f0231ff3875ded36df8c1ab851451e51a237dc0e5a86d3d96036158da94/Whoosh-2.7.0.zip";
346 url = "https://pypi.python.org/packages/1c/dc/2f0231ff3875ded36df8c1ab851451e51a237dc0e5a86d3d96036158da94/Whoosh-2.7.0.zip";
269 md5 = "7abfd970f16fadc7311960f3fa0bc7a9";
347 md5 = "7abfd970f16fadc7311960f3fa0bc7a9";
270 };
348 };
349 meta = {
350 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ];
351 };
271 };
352 };
272 alembic = super.buildPythonPackage {
353 alembic = super.buildPythonPackage {
273 name = "alembic-0.8.4";
354 name = "alembic-0.8.4";
@@ -278,6 +359,9 b''
278 url = "https://pypi.python.org/packages/ca/7e/299b4499b5c75e5a38c5845145ad24755bebfb8eec07a2e1c366b7181eeb/alembic-0.8.4.tar.gz";
359 url = "https://pypi.python.org/packages/ca/7e/299b4499b5c75e5a38c5845145ad24755bebfb8eec07a2e1c366b7181eeb/alembic-0.8.4.tar.gz";
279 md5 = "5f95d8ee62b443f9b37eb5bee76c582d";
360 md5 = "5f95d8ee62b443f9b37eb5bee76c582d";
280 };
361 };
362 meta = {
363 license = [ pkgs.lib.licenses.mit ];
364 };
281 };
365 };
282 amqplib = super.buildPythonPackage {
366 amqplib = super.buildPythonPackage {
283 name = "amqplib-1.0.2";
367 name = "amqplib-1.0.2";
@@ -288,6 +372,9 b''
288 url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz";
372 url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz";
289 md5 = "5c92f17fbedd99b2b4a836d4352d1e2f";
373 md5 = "5c92f17fbedd99b2b4a836d4352d1e2f";
290 };
374 };
375 meta = {
376 license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
377 };
291 };
378 };
292 anyjson = super.buildPythonPackage {
379 anyjson = super.buildPythonPackage {
293 name = "anyjson-0.3.3";
380 name = "anyjson-0.3.3";
@@ -298,6 +385,9 b''
298 url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz";
385 url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz";
299 md5 = "2ea28d6ec311aeeebaf993cb3008b27c";
386 md5 = "2ea28d6ec311aeeebaf993cb3008b27c";
300 };
387 };
388 meta = {
389 license = [ pkgs.lib.licenses.bsdOriginal ];
390 };
301 };
391 };
302 appenlight-client = super.buildPythonPackage {
392 appenlight-client = super.buildPythonPackage {
303 name = "appenlight-client-0.6.14";
393 name = "appenlight-client-0.6.14";
@@ -308,6 +398,9 b''
308 url = "https://pypi.python.org/packages/4d/e0/23fee3ebada8143f707e65c06bcb82992040ee64ea8355e044ed55ebf0c1/appenlight_client-0.6.14.tar.gz";
398 url = "https://pypi.python.org/packages/4d/e0/23fee3ebada8143f707e65c06bcb82992040ee64ea8355e044ed55ebf0c1/appenlight_client-0.6.14.tar.gz";
309 md5 = "578c69b09f4356d898fff1199b98a95c";
399 md5 = "578c69b09f4356d898fff1199b98a95c";
310 };
400 };
401 meta = {
402 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "DFSG approved"; } ];
403 };
311 };
404 };
312 authomatic = super.buildPythonPackage {
405 authomatic = super.buildPythonPackage {
313 name = "authomatic-0.1.0.post1";
406 name = "authomatic-0.1.0.post1";
@@ -318,6 +411,9 b''
318 url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz";
411 url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz";
319 md5 = "be3f3ce08747d776aae6d6cc8dcb49a9";
412 md5 = "be3f3ce08747d776aae6d6cc8dcb49a9";
320 };
413 };
414 meta = {
415 license = [ pkgs.lib.licenses.mit ];
416 };
321 };
417 };
322 backport-ipaddress = super.buildPythonPackage {
418 backport-ipaddress = super.buildPythonPackage {
323 name = "backport-ipaddress-0.1";
419 name = "backport-ipaddress-0.1";
@@ -328,6 +424,9 b''
328 url = "https://pypi.python.org/packages/d3/30/54c6dab05a4dec44db25ff309f1fbb6b7a8bde3f2bade38bb9da67bbab8f/backport_ipaddress-0.1.tar.gz";
424 url = "https://pypi.python.org/packages/d3/30/54c6dab05a4dec44db25ff309f1fbb6b7a8bde3f2bade38bb9da67bbab8f/backport_ipaddress-0.1.tar.gz";
329 md5 = "9c1f45f4361f71b124d7293a60006c05";
425 md5 = "9c1f45f4361f71b124d7293a60006c05";
330 };
426 };
427 meta = {
428 license = [ pkgs.lib.licenses.psfl ];
429 };
331 };
430 };
332 bottle = super.buildPythonPackage {
431 bottle = super.buildPythonPackage {
333 name = "bottle-0.12.8";
432 name = "bottle-0.12.8";
@@ -338,6 +437,9 b''
338 url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz";
437 url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz";
339 md5 = "13132c0a8f607bf860810a6ee9064c5b";
438 md5 = "13132c0a8f607bf860810a6ee9064c5b";
340 };
439 };
440 meta = {
441 license = [ pkgs.lib.licenses.mit ];
442 };
341 };
443 };
342 bumpversion = super.buildPythonPackage {
444 bumpversion = super.buildPythonPackage {
343 name = "bumpversion-0.5.3";
445 name = "bumpversion-0.5.3";
@@ -348,6 +450,9 b''
348 url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz";
450 url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz";
349 md5 = "c66a3492eafcf5ad4b024be9fca29820";
451 md5 = "c66a3492eafcf5ad4b024be9fca29820";
350 };
452 };
453 meta = {
454 license = [ pkgs.lib.licenses.mit ];
455 };
351 };
456 };
352 celery = super.buildPythonPackage {
457 celery = super.buildPythonPackage {
353 name = "celery-2.2.10";
458 name = "celery-2.2.10";
@@ -358,6 +463,9 b''
358 url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz";
463 url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz";
359 md5 = "898bc87e54f278055b561316ba73e222";
464 md5 = "898bc87e54f278055b561316ba73e222";
360 };
465 };
466 meta = {
467 license = [ pkgs.lib.licenses.bsdOriginal ];
468 };
361 };
469 };
362 click = super.buildPythonPackage {
470 click = super.buildPythonPackage {
363 name = "click-5.1";
471 name = "click-5.1";
@@ -368,6 +476,9 b''
368 url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz";
476 url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz";
369 md5 = "9c5323008cccfe232a8b161fc8196d41";
477 md5 = "9c5323008cccfe232a8b161fc8196d41";
370 };
478 };
479 meta = {
480 license = [ pkgs.lib.licenses.bsdOriginal ];
481 };
371 };
482 };
372 colander = super.buildPythonPackage {
483 colander = super.buildPythonPackage {
373 name = "colander-1.2";
484 name = "colander-1.2";
@@ -378,6 +489,9 b''
378 url = "https://pypi.python.org/packages/14/23/c9ceba07a6a1dc0eefbb215fc0dc64aabc2b22ee756bc0f0c13278fa0887/colander-1.2.tar.gz";
489 url = "https://pypi.python.org/packages/14/23/c9ceba07a6a1dc0eefbb215fc0dc64aabc2b22ee756bc0f0c13278fa0887/colander-1.2.tar.gz";
379 md5 = "83db21b07936a0726e588dae1914b9ed";
490 md5 = "83db21b07936a0726e588dae1914b9ed";
380 };
491 };
492 meta = {
493 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
494 };
381 };
495 };
382 configobj = super.buildPythonPackage {
496 configobj = super.buildPythonPackage {
383 name = "configobj-5.0.6";
497 name = "configobj-5.0.6";
@@ -388,6 +502,9 b''
388 url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz";
502 url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz";
389 md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6";
503 md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6";
390 };
504 };
505 meta = {
506 license = [ pkgs.lib.licenses.bsdOriginal ];
507 };
391 };
508 };
392 cov-core = super.buildPythonPackage {
509 cov-core = super.buildPythonPackage {
393 name = "cov-core-1.15.0";
510 name = "cov-core-1.15.0";
@@ -398,6 +515,9 b''
398 url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
515 url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
399 md5 = "f519d4cb4c4e52856afb14af52919fe6";
516 md5 = "f519d4cb4c4e52856afb14af52919fe6";
400 };
517 };
518 meta = {
519 license = [ pkgs.lib.licenses.mit ];
520 };
401 };
521 };
402 coverage = super.buildPythonPackage {
522 coverage = super.buildPythonPackage {
403 name = "coverage-3.7.1";
523 name = "coverage-3.7.1";
@@ -408,6 +528,9 b''
408 url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz";
528 url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz";
409 md5 = "c47b36ceb17eaff3ecfab3bcd347d0df";
529 md5 = "c47b36ceb17eaff3ecfab3bcd347d0df";
410 };
530 };
531 meta = {
532 license = [ pkgs.lib.licenses.bsdOriginal ];
533 };
411 };
534 };
412 cssselect = super.buildPythonPackage {
535 cssselect = super.buildPythonPackage {
413 name = "cssselect-0.9.1";
536 name = "cssselect-0.9.1";
@@ -418,6 +541,9 b''
418 url = "https://pypi.python.org/packages/aa/e5/9ee1460d485b94a6d55732eb7ad5b6c084caf73dd6f9cb0bb7d2a78fafe8/cssselect-0.9.1.tar.gz";
541 url = "https://pypi.python.org/packages/aa/e5/9ee1460d485b94a6d55732eb7ad5b6c084caf73dd6f9cb0bb7d2a78fafe8/cssselect-0.9.1.tar.gz";
419 md5 = "c74f45966277dc7a0f768b9b0f3522ac";
542 md5 = "c74f45966277dc7a0f768b9b0f3522ac";
420 };
543 };
544 meta = {
545 license = [ pkgs.lib.licenses.bsdOriginal ];
546 };
421 };
547 };
422 decorator = super.buildPythonPackage {
548 decorator = super.buildPythonPackage {
423 name = "decorator-3.4.2";
549 name = "decorator-3.4.2";
@@ -428,6 +554,9 b''
428 url = "https://pypi.python.org/packages/35/3a/42566eb7a2cbac774399871af04e11d7ae3fc2579e7dae85213b8d1d1c57/decorator-3.4.2.tar.gz";
554 url = "https://pypi.python.org/packages/35/3a/42566eb7a2cbac774399871af04e11d7ae3fc2579e7dae85213b8d1d1c57/decorator-3.4.2.tar.gz";
429 md5 = "9e0536870d2b83ae27d58dbf22582f4d";
555 md5 = "9e0536870d2b83ae27d58dbf22582f4d";
430 };
556 };
557 meta = {
558 license = [ pkgs.lib.licenses.bsdOriginal ];
559 };
431 };
560 };
432 docutils = super.buildPythonPackage {
561 docutils = super.buildPythonPackage {
433 name = "docutils-0.12";
562 name = "docutils-0.12";
@@ -438,6 +567,9 b''
438 url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz";
567 url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz";
439 md5 = "4622263b62c5c771c03502afa3157768";
568 md5 = "4622263b62c5c771c03502afa3157768";
440 };
569 };
570 meta = {
571 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 ];
572 };
441 };
573 };
442 dogpile.cache = super.buildPythonPackage {
574 dogpile.cache = super.buildPythonPackage {
443 name = "dogpile.cache-0.5.7";
575 name = "dogpile.cache-0.5.7";
@@ -448,6 +580,9 b''
448 url = "https://pypi.python.org/packages/07/74/2a83bedf758156d9c95d112691bbad870d3b77ccbcfb781b4ef836ea7d96/dogpile.cache-0.5.7.tar.gz";
580 url = "https://pypi.python.org/packages/07/74/2a83bedf758156d9c95d112691bbad870d3b77ccbcfb781b4ef836ea7d96/dogpile.cache-0.5.7.tar.gz";
449 md5 = "3e58ce41af574aab41d78e9c4190f194";
581 md5 = "3e58ce41af574aab41d78e9c4190f194";
450 };
582 };
583 meta = {
584 license = [ pkgs.lib.licenses.bsdOriginal ];
585 };
451 };
586 };
452 dogpile.core = super.buildPythonPackage {
587 dogpile.core = super.buildPythonPackage {
453 name = "dogpile.core-0.4.1";
588 name = "dogpile.core-0.4.1";
@@ -458,6 +593,9 b''
458 url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz";
593 url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz";
459 md5 = "01cb19f52bba3e95c9b560f39341f045";
594 md5 = "01cb19f52bba3e95c9b560f39341f045";
460 };
595 };
596 meta = {
597 license = [ pkgs.lib.licenses.bsdOriginal ];
598 };
461 };
599 };
462 dulwich = super.buildPythonPackage {
600 dulwich = super.buildPythonPackage {
463 name = "dulwich-0.12.0";
601 name = "dulwich-0.12.0";
@@ -468,6 +606,9 b''
468 url = "https://pypi.python.org/packages/6f/04/fbe561b6d45c0ec758330d5b7f5ba4b6cb4f1ca1ab49859d2fc16320da75/dulwich-0.12.0.tar.gz";
606 url = "https://pypi.python.org/packages/6f/04/fbe561b6d45c0ec758330d5b7f5ba4b6cb4f1ca1ab49859d2fc16320da75/dulwich-0.12.0.tar.gz";
469 md5 = "f3a8a12bd9f9dd8c233e18f3d49436fa";
607 md5 = "f3a8a12bd9f9dd8c233e18f3d49436fa";
470 };
608 };
609 meta = {
610 license = [ pkgs.lib.licenses.gpl2Plus ];
611 };
471 };
612 };
472 ecdsa = super.buildPythonPackage {
613 ecdsa = super.buildPythonPackage {
473 name = "ecdsa-0.11";
614 name = "ecdsa-0.11";
@@ -478,6 +619,9 b''
478 url = "https://pypi.python.org/packages/6c/3f/92fe5dcdcaa7bd117be21e5520c9a54375112b66ec000d209e9e9519fad1/ecdsa-0.11.tar.gz";
619 url = "https://pypi.python.org/packages/6c/3f/92fe5dcdcaa7bd117be21e5520c9a54375112b66ec000d209e9e9519fad1/ecdsa-0.11.tar.gz";
479 md5 = "8ef586fe4dbb156697d756900cb41d7c";
620 md5 = "8ef586fe4dbb156697d756900cb41d7c";
480 };
621 };
622 meta = {
623 license = [ pkgs.lib.licenses.mit ];
624 };
481 };
625 };
482 elasticsearch = super.buildPythonPackage {
626 elasticsearch = super.buildPythonPackage {
483 name = "elasticsearch-2.3.0";
627 name = "elasticsearch-2.3.0";
@@ -488,6 +632,9 b''
488 url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz";
632 url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz";
489 md5 = "2550f3b51629cf1ef9636608af92c340";
633 md5 = "2550f3b51629cf1ef9636608af92c340";
490 };
634 };
635 meta = {
636 license = [ pkgs.lib.licenses.asl20 ];
637 };
491 };
638 };
492 elasticsearch-dsl = super.buildPythonPackage {
639 elasticsearch-dsl = super.buildPythonPackage {
493 name = "elasticsearch-dsl-2.0.0";
640 name = "elasticsearch-dsl-2.0.0";
@@ -498,6 +645,9 b''
498 url = "https://pypi.python.org/packages/4e/5d/e788ae8dbe2ff4d13426db0a027533386a5c276c77a2654dc0e2007ce04a/elasticsearch-dsl-2.0.0.tar.gz";
645 url = "https://pypi.python.org/packages/4e/5d/e788ae8dbe2ff4d13426db0a027533386a5c276c77a2654dc0e2007ce04a/elasticsearch-dsl-2.0.0.tar.gz";
499 md5 = "4cdfec81bb35383dd3b7d02d7dc5ee68";
646 md5 = "4cdfec81bb35383dd3b7d02d7dc5ee68";
500 };
647 };
648 meta = {
649 license = [ pkgs.lib.licenses.asl20 ];
650 };
501 };
651 };
502 flake8 = super.buildPythonPackage {
652 flake8 = super.buildPythonPackage {
503 name = "flake8-2.4.1";
653 name = "flake8-2.4.1";
@@ -508,6 +658,9 b''
508 url = "https://pypi.python.org/packages/8f/b5/9a73c66c7dba273bac8758398f060c008a25f3e84531063b42503b5d0a95/flake8-2.4.1.tar.gz";
658 url = "https://pypi.python.org/packages/8f/b5/9a73c66c7dba273bac8758398f060c008a25f3e84531063b42503b5d0a95/flake8-2.4.1.tar.gz";
509 md5 = "ed45d3db81a3b7c88bd63c6e37ca1d65";
659 md5 = "ed45d3db81a3b7c88bd63c6e37ca1d65";
510 };
660 };
661 meta = {
662 license = [ pkgs.lib.licenses.mit ];
663 };
511 };
664 };
512 future = super.buildPythonPackage {
665 future = super.buildPythonPackage {
513 name = "future-0.14.3";
666 name = "future-0.14.3";
@@ -518,6 +671,9 b''
518 url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz";
671 url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz";
519 md5 = "e94079b0bd1fc054929e8769fc0f6083";
672 md5 = "e94079b0bd1fc054929e8769fc0f6083";
520 };
673 };
674 meta = {
675 license = [ { fullName = "OSI Approved"; } pkgs.lib.licenses.mit ];
676 };
521 };
677 };
522 futures = super.buildPythonPackage {
678 futures = super.buildPythonPackage {
523 name = "futures-3.0.2";
679 name = "futures-3.0.2";
@@ -528,6 +684,9 b''
528 url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz";
684 url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz";
529 md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a";
685 md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a";
530 };
686 };
687 meta = {
688 license = [ pkgs.lib.licenses.bsdOriginal ];
689 };
531 };
690 };
532 gnureadline = super.buildPythonPackage {
691 gnureadline = super.buildPythonPackage {
533 name = "gnureadline-6.3.3";
692 name = "gnureadline-6.3.3";
@@ -538,9 +697,12 b''
538 url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz";
697 url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz";
539 md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c";
698 md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c";
540 };
699 };
700 meta = {
701 license = [ pkgs.lib.licenses.gpl1 ];
702 };
541 };
703 };
542 gprof2dot = super.buildPythonPackage {
704 gprof2dot = super.buildPythonPackage {
543 name = "gprof2dot-2015.12.01";
705 name = "gprof2dot-2015.12.1";
544 buildInputs = with self; [];
706 buildInputs = with self; [];
545 doCheck = false;
707 doCheck = false;
546 propagatedBuildInputs = with self; [];
708 propagatedBuildInputs = with self; [];
@@ -548,6 +710,9 b''
548 url = "https://pypi.python.org/packages/b9/34/7bf93c1952d40fa5c95ad963f4d8344b61ef58558632402eca18e6c14127/gprof2dot-2015.12.1.tar.gz";
710 url = "https://pypi.python.org/packages/b9/34/7bf93c1952d40fa5c95ad963f4d8344b61ef58558632402eca18e6c14127/gprof2dot-2015.12.1.tar.gz";
549 md5 = "e23bf4e2f94db032750c193384b4165b";
711 md5 = "e23bf4e2f94db032750c193384b4165b";
550 };
712 };
713 meta = {
714 license = [ { fullName = "LGPL"; } ];
715 };
551 };
716 };
552 greenlet = super.buildPythonPackage {
717 greenlet = super.buildPythonPackage {
553 name = "greenlet-0.4.9";
718 name = "greenlet-0.4.9";
@@ -558,6 +723,9 b''
558 url = "https://pypi.python.org/packages/4e/3d/9d421539b74e33608b245092870156b2e171fb49f2b51390aa4641eecb4a/greenlet-0.4.9.zip";
723 url = "https://pypi.python.org/packages/4e/3d/9d421539b74e33608b245092870156b2e171fb49f2b51390aa4641eecb4a/greenlet-0.4.9.zip";
559 md5 = "c6659cdb2a5e591723e629d2eef22e82";
724 md5 = "c6659cdb2a5e591723e629d2eef22e82";
560 };
725 };
726 meta = {
727 license = [ pkgs.lib.licenses.mit ];
728 };
561 };
729 };
562 gunicorn = super.buildPythonPackage {
730 gunicorn = super.buildPythonPackage {
563 name = "gunicorn-19.6.0";
731 name = "gunicorn-19.6.0";
@@ -568,6 +736,9 b''
568 url = "https://pypi.python.org/packages/84/ce/7ea5396efad1cef682bbc4068e72a0276341d9d9d0f501da609fab9fcb80/gunicorn-19.6.0.tar.gz";
736 url = "https://pypi.python.org/packages/84/ce/7ea5396efad1cef682bbc4068e72a0276341d9d9d0f501da609fab9fcb80/gunicorn-19.6.0.tar.gz";
569 md5 = "338e5e8a83ea0f0625f768dba4597530";
737 md5 = "338e5e8a83ea0f0625f768dba4597530";
570 };
738 };
739 meta = {
740 license = [ pkgs.lib.licenses.mit ];
741 };
571 };
742 };
572 infrae.cache = super.buildPythonPackage {
743 infrae.cache = super.buildPythonPackage {
573 name = "infrae.cache-1.0.1";
744 name = "infrae.cache-1.0.1";
@@ -578,15 +749,21 b''
578 url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz";
749 url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz";
579 md5 = "b09076a766747e6ed2a755cc62088e32";
750 md5 = "b09076a766747e6ed2a755cc62088e32";
580 };
751 };
752 meta = {
753 license = [ pkgs.lib.licenses.zpt21 ];
754 };
581 };
755 };
582 invoke = super.buildPythonPackage {
756 invoke = super.buildPythonPackage {
583 name = "invoke-0.11.1";
757 name = "invoke-0.13.0";
584 buildInputs = with self; [];
758 buildInputs = with self; [];
585 doCheck = false;
759 doCheck = false;
586 propagatedBuildInputs = with self; [];
760 propagatedBuildInputs = with self; [];
587 src = fetchurl {
761 src = fetchurl {
588 url = "https://pypi.python.org/packages/d3/bb/36a5558ea19882073def7b0edeef4a0e6282056fed96506dd10b1d532bd4/invoke-0.11.1.tar.gz";
762 url = "https://pypi.python.org/packages/47/bf/d07ef52fa1ac645468858bbac7cb95b246a972a045e821493d17d89c81be/invoke-0.13.0.tar.gz";
589 md5 = "3d4ecbe26779ceef1046ecf702c9c4a8";
763 md5 = "c0d1ed4bfb34eaab551662d8cfee6540";
764 };
765 meta = {
766 license = [ pkgs.lib.licenses.bsdOriginal ];
590 };
767 };
591 };
768 };
592 ipdb = super.buildPythonPackage {
769 ipdb = super.buildPythonPackage {
@@ -598,6 +775,9 b''
598 url = "https://pypi.python.org/packages/f0/25/d7dd430ced6cd8dc242a933c8682b5dbf32eb4011d82f87e34209e5ec845/ipdb-0.8.zip";
775 url = "https://pypi.python.org/packages/f0/25/d7dd430ced6cd8dc242a933c8682b5dbf32eb4011d82f87e34209e5ec845/ipdb-0.8.zip";
599 md5 = "96dca0712efa01aa5eaf6b22071dd3ed";
776 md5 = "96dca0712efa01aa5eaf6b22071dd3ed";
600 };
777 };
778 meta = {
779 license = [ pkgs.lib.licenses.gpl1 ];
780 };
601 };
781 };
602 ipython = super.buildPythonPackage {
782 ipython = super.buildPythonPackage {
603 name = "ipython-3.1.0";
783 name = "ipython-3.1.0";
@@ -608,6 +788,9 b''
608 url = "https://pypi.python.org/packages/06/91/120c0835254c120af89f066afaabf81289bc2726c1fc3ca0555df6882f58/ipython-3.1.0.tar.gz";
788 url = "https://pypi.python.org/packages/06/91/120c0835254c120af89f066afaabf81289bc2726c1fc3ca0555df6882f58/ipython-3.1.0.tar.gz";
609 md5 = "a749d90c16068687b0ec45a27e72ef8f";
789 md5 = "a749d90c16068687b0ec45a27e72ef8f";
610 };
790 };
791 meta = {
792 license = [ pkgs.lib.licenses.bsdOriginal ];
793 };
611 };
794 };
612 iso8601 = super.buildPythonPackage {
795 iso8601 = super.buildPythonPackage {
613 name = "iso8601-0.1.11";
796 name = "iso8601-0.1.11";
@@ -618,6 +801,9 b''
618 url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz";
801 url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz";
619 md5 = "b06d11cd14a64096f907086044f0fe38";
802 md5 = "b06d11cd14a64096f907086044f0fe38";
620 };
803 };
804 meta = {
805 license = [ pkgs.lib.licenses.mit ];
806 };
621 };
807 };
622 itsdangerous = super.buildPythonPackage {
808 itsdangerous = super.buildPythonPackage {
623 name = "itsdangerous-0.24";
809 name = "itsdangerous-0.24";
@@ -628,6 +814,9 b''
628 url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz";
814 url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz";
629 md5 = "a3d55aa79369aef5345c036a8a26307f";
815 md5 = "a3d55aa79369aef5345c036a8a26307f";
630 };
816 };
817 meta = {
818 license = [ pkgs.lib.licenses.bsdOriginal ];
819 };
631 };
820 };
632 kombu = super.buildPythonPackage {
821 kombu = super.buildPythonPackage {
633 name = "kombu-1.5.1";
822 name = "kombu-1.5.1";
@@ -638,6 +827,9 b''
638 url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz";
827 url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz";
639 md5 = "50662f3c7e9395b3d0721fb75d100b63";
828 md5 = "50662f3c7e9395b3d0721fb75d100b63";
640 };
829 };
830 meta = {
831 license = [ pkgs.lib.licenses.bsdOriginal ];
832 };
641 };
833 };
642 lxml = super.buildPythonPackage {
834 lxml = super.buildPythonPackage {
643 name = "lxml-3.4.4";
835 name = "lxml-3.4.4";
@@ -648,6 +840,9 b''
648 url = "https://pypi.python.org/packages/63/c7/4f2a2a4ad6c6fa99b14be6b3c1cece9142e2d915aa7c43c908677afc8fa4/lxml-3.4.4.tar.gz";
840 url = "https://pypi.python.org/packages/63/c7/4f2a2a4ad6c6fa99b14be6b3c1cece9142e2d915aa7c43c908677afc8fa4/lxml-3.4.4.tar.gz";
649 md5 = "a9a65972afc173ec7a39c585f4eea69c";
841 md5 = "a9a65972afc173ec7a39c585f4eea69c";
650 };
842 };
843 meta = {
844 license = [ pkgs.lib.licenses.bsdOriginal ];
845 };
651 };
846 };
652 mccabe = super.buildPythonPackage {
847 mccabe = super.buildPythonPackage {
653 name = "mccabe-0.3";
848 name = "mccabe-0.3";
@@ -658,6 +853,9 b''
658 url = "https://pypi.python.org/packages/c9/2e/75231479e11a906b64ac43bad9d0bb534d00080b18bdca8db9da46e1faf7/mccabe-0.3.tar.gz";
853 url = "https://pypi.python.org/packages/c9/2e/75231479e11a906b64ac43bad9d0bb534d00080b18bdca8db9da46e1faf7/mccabe-0.3.tar.gz";
659 md5 = "81640948ff226f8c12b3277059489157";
854 md5 = "81640948ff226f8c12b3277059489157";
660 };
855 };
856 meta = {
857 license = [ { fullName = "Expat license"; } pkgs.lib.licenses.mit ];
858 };
661 };
859 };
662 meld3 = super.buildPythonPackage {
860 meld3 = super.buildPythonPackage {
663 name = "meld3-1.0.2";
861 name = "meld3-1.0.2";
@@ -668,6 +866,9 b''
668 url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz";
866 url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz";
669 md5 = "3ccc78cd79cffd63a751ad7684c02c91";
867 md5 = "3ccc78cd79cffd63a751ad7684c02c91";
670 };
868 };
869 meta = {
870 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
871 };
671 };
872 };
672 mock = super.buildPythonPackage {
873 mock = super.buildPythonPackage {
673 name = "mock-1.0.1";
874 name = "mock-1.0.1";
@@ -678,6 +879,9 b''
678 url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip";
879 url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip";
679 md5 = "869f08d003c289a97c1a6610faf5e913";
880 md5 = "869f08d003c289a97c1a6610faf5e913";
680 };
881 };
882 meta = {
883 license = [ pkgs.lib.licenses.bsdOriginal ];
884 };
681 };
885 };
682 msgpack-python = super.buildPythonPackage {
886 msgpack-python = super.buildPythonPackage {
683 name = "msgpack-python-0.4.6";
887 name = "msgpack-python-0.4.6";
@@ -688,6 +892,9 b''
688 url = "https://pypi.python.org/packages/15/ce/ff2840885789ef8035f66cd506ea05bdb228340307d5e71a7b1e3f82224c/msgpack-python-0.4.6.tar.gz";
892 url = "https://pypi.python.org/packages/15/ce/ff2840885789ef8035f66cd506ea05bdb228340307d5e71a7b1e3f82224c/msgpack-python-0.4.6.tar.gz";
689 md5 = "8b317669314cf1bc881716cccdaccb30";
893 md5 = "8b317669314cf1bc881716cccdaccb30";
690 };
894 };
895 meta = {
896 license = [ pkgs.lib.licenses.asl20 ];
897 };
691 };
898 };
692 nose = super.buildPythonPackage {
899 nose = super.buildPythonPackage {
693 name = "nose-1.3.6";
900 name = "nose-1.3.6";
@@ -698,6 +905,9 b''
698 url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz";
905 url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz";
699 md5 = "0ca546d81ca8309080fc80cb389e7a16";
906 md5 = "0ca546d81ca8309080fc80cb389e7a16";
700 };
907 };
908 meta = {
909 license = [ { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "GNU LGPL"; } ];
910 };
701 };
911 };
702 objgraph = super.buildPythonPackage {
912 objgraph = super.buildPythonPackage {
703 name = "objgraph-2.0.0";
913 name = "objgraph-2.0.0";
@@ -708,6 +918,9 b''
708 url = "https://pypi.python.org/packages/d7/33/ace750b59247496ed769b170586c5def7202683f3d98e737b75b767ff29e/objgraph-2.0.0.tar.gz";
918 url = "https://pypi.python.org/packages/d7/33/ace750b59247496ed769b170586c5def7202683f3d98e737b75b767ff29e/objgraph-2.0.0.tar.gz";
709 md5 = "25b0d5e5adc74aa63ead15699614159c";
919 md5 = "25b0d5e5adc74aa63ead15699614159c";
710 };
920 };
921 meta = {
922 license = [ pkgs.lib.licenses.mit ];
923 };
711 };
924 };
712 packaging = super.buildPythonPackage {
925 packaging = super.buildPythonPackage {
713 name = "packaging-15.2";
926 name = "packaging-15.2";
@@ -718,6 +931,9 b''
718 url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz";
931 url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz";
719 md5 = "c16093476f6ced42128bf610e5db3784";
932 md5 = "c16093476f6ced42128bf610e5db3784";
720 };
933 };
934 meta = {
935 license = [ pkgs.lib.licenses.asl20 ];
936 };
721 };
937 };
722 paramiko = super.buildPythonPackage {
938 paramiko = super.buildPythonPackage {
723 name = "paramiko-1.15.1";
939 name = "paramiko-1.15.1";
@@ -728,6 +944,9 b''
728 url = "https://pypi.python.org/packages/04/2b/a22d2a560c1951abbbf95a0628e245945565f70dc082d9e784666887222c/paramiko-1.15.1.tar.gz";
944 url = "https://pypi.python.org/packages/04/2b/a22d2a560c1951abbbf95a0628e245945565f70dc082d9e784666887222c/paramiko-1.15.1.tar.gz";
729 md5 = "48c274c3f9b1282932567b21f6acf3b5";
945 md5 = "48c274c3f9b1282932567b21f6acf3b5";
730 };
946 };
947 meta = {
948 license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
949 };
731 };
950 };
732 pep8 = super.buildPythonPackage {
951 pep8 = super.buildPythonPackage {
733 name = "pep8-1.5.7";
952 name = "pep8-1.5.7";
@@ -738,6 +957,9 b''
738 url = "https://pypi.python.org/packages/8b/de/259f5e735897ada1683489dd514b2a1c91aaa74e5e6b68f80acf128a6368/pep8-1.5.7.tar.gz";
957 url = "https://pypi.python.org/packages/8b/de/259f5e735897ada1683489dd514b2a1c91aaa74e5e6b68f80acf128a6368/pep8-1.5.7.tar.gz";
739 md5 = "f6adbdd69365ecca20513c709f9b7c93";
958 md5 = "f6adbdd69365ecca20513c709f9b7c93";
740 };
959 };
960 meta = {
961 license = [ { fullName = "Expat license"; } pkgs.lib.licenses.mit ];
962 };
741 };
963 };
742 psutil = super.buildPythonPackage {
964 psutil = super.buildPythonPackage {
743 name = "psutil-2.2.1";
965 name = "psutil-2.2.1";
@@ -748,6 +970,9 b''
748 url = "https://pypi.python.org/packages/df/47/ee54ef14dd40f8ce831a7581001a5096494dc99fe71586260ca6b531fe86/psutil-2.2.1.tar.gz";
970 url = "https://pypi.python.org/packages/df/47/ee54ef14dd40f8ce831a7581001a5096494dc99fe71586260ca6b531fe86/psutil-2.2.1.tar.gz";
749 md5 = "1a2b58cd9e3a53528bb6148f0c4d5244";
971 md5 = "1a2b58cd9e3a53528bb6148f0c4d5244";
750 };
972 };
973 meta = {
974 license = [ pkgs.lib.licenses.bsdOriginal ];
975 };
751 };
976 };
752 psycopg2 = super.buildPythonPackage {
977 psycopg2 = super.buildPythonPackage {
753 name = "psycopg2-2.6";
978 name = "psycopg2-2.6";
@@ -758,6 +983,9 b''
758 url = "https://pypi.python.org/packages/dd/c7/9016ff8ff69da269b1848276eebfb264af5badf6b38caad805426771f04d/psycopg2-2.6.tar.gz";
983 url = "https://pypi.python.org/packages/dd/c7/9016ff8ff69da269b1848276eebfb264af5badf6b38caad805426771f04d/psycopg2-2.6.tar.gz";
759 md5 = "fbbb039a8765d561a1c04969bbae7c74";
984 md5 = "fbbb039a8765d561a1c04969bbae7c74";
760 };
985 };
986 meta = {
987 license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
988 };
761 };
989 };
762 py = super.buildPythonPackage {
990 py = super.buildPythonPackage {
763 name = "py-1.4.29";
991 name = "py-1.4.29";
@@ -768,6 +996,9 b''
768 url = "https://pypi.python.org/packages/2a/bc/a1a4a332ac10069b8e5e25136a35e08a03f01fd6ab03d819889d79a1fd65/py-1.4.29.tar.gz";
996 url = "https://pypi.python.org/packages/2a/bc/a1a4a332ac10069b8e5e25136a35e08a03f01fd6ab03d819889d79a1fd65/py-1.4.29.tar.gz";
769 md5 = "c28e0accba523a29b35a48bb703fb96c";
997 md5 = "c28e0accba523a29b35a48bb703fb96c";
770 };
998 };
999 meta = {
1000 license = [ pkgs.lib.licenses.mit ];
1001 };
771 };
1002 };
772 py-bcrypt = super.buildPythonPackage {
1003 py-bcrypt = super.buildPythonPackage {
773 name = "py-bcrypt-0.4";
1004 name = "py-bcrypt-0.4";
@@ -778,6 +1009,9 b''
778 url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz";
1009 url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz";
779 md5 = "dd8b367d6b716a2ea2e72392525f4e36";
1010 md5 = "dd8b367d6b716a2ea2e72392525f4e36";
780 };
1011 };
1012 meta = {
1013 license = [ pkgs.lib.licenses.bsdOriginal ];
1014 };
781 };
1015 };
782 pycrypto = super.buildPythonPackage {
1016 pycrypto = super.buildPythonPackage {
783 name = "pycrypto-2.6.1";
1017 name = "pycrypto-2.6.1";
@@ -788,6 +1022,9 b''
788 url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz";
1022 url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz";
789 md5 = "55a61a054aa66812daf5161a0d5d7eda";
1023 md5 = "55a61a054aa66812daf5161a0d5d7eda";
790 };
1024 };
1025 meta = {
1026 license = [ pkgs.lib.licenses.publicDomain ];
1027 };
791 };
1028 };
792 pycurl = super.buildPythonPackage {
1029 pycurl = super.buildPythonPackage {
793 name = "pycurl-7.19.5";
1030 name = "pycurl-7.19.5";
@@ -798,6 +1035,9 b''
798 url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz";
1035 url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz";
799 md5 = "47b4eac84118e2606658122104e62072";
1036 md5 = "47b4eac84118e2606658122104e62072";
800 };
1037 };
1038 meta = {
1039 license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1040 };
801 };
1041 };
802 pyflakes = super.buildPythonPackage {
1042 pyflakes = super.buildPythonPackage {
803 name = "pyflakes-0.8.1";
1043 name = "pyflakes-0.8.1";
@@ -808,6 +1048,9 b''
808 url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
1048 url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
809 md5 = "905fe91ad14b912807e8fdc2ac2e2c23";
1049 md5 = "905fe91ad14b912807e8fdc2ac2e2c23";
810 };
1050 };
1051 meta = {
1052 license = [ pkgs.lib.licenses.mit ];
1053 };
811 };
1054 };
812 pyparsing = super.buildPythonPackage {
1055 pyparsing = super.buildPythonPackage {
813 name = "pyparsing-1.5.7";
1056 name = "pyparsing-1.5.7";
@@ -818,6 +1061,9 b''
818 url = "https://pypi.python.org/packages/2e/26/e8fb5b4256a5f5036be7ce115ef8db8d06bc537becfbdc46c6af008314ee/pyparsing-1.5.7.zip";
1061 url = "https://pypi.python.org/packages/2e/26/e8fb5b4256a5f5036be7ce115ef8db8d06bc537becfbdc46c6af008314ee/pyparsing-1.5.7.zip";
819 md5 = "b86854857a368d6ccb4d5b6e76d0637f";
1062 md5 = "b86854857a368d6ccb4d5b6e76d0637f";
820 };
1063 };
1064 meta = {
1065 license = [ pkgs.lib.licenses.mit ];
1066 };
821 };
1067 };
822 pyramid = super.buildPythonPackage {
1068 pyramid = super.buildPythonPackage {
823 name = "pyramid-1.6.1";
1069 name = "pyramid-1.6.1";
@@ -828,6 +1074,9 b''
828 url = "https://pypi.python.org/packages/30/b3/fcc4a2a4800cbf21989e00454b5828cf1f7fe35c63e0810b350e56d4c475/pyramid-1.6.1.tar.gz";
1074 url = "https://pypi.python.org/packages/30/b3/fcc4a2a4800cbf21989e00454b5828cf1f7fe35c63e0810b350e56d4c475/pyramid-1.6.1.tar.gz";
829 md5 = "b18688ff3cc33efdbb098a35b45dd122";
1075 md5 = "b18688ff3cc33efdbb098a35b45dd122";
830 };
1076 };
1077 meta = {
1078 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1079 };
831 };
1080 };
832 pyramid-beaker = super.buildPythonPackage {
1081 pyramid-beaker = super.buildPythonPackage {
833 name = "pyramid-beaker-0.8";
1082 name = "pyramid-beaker-0.8";
@@ -838,6 +1087,9 b''
838 url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
1087 url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
839 md5 = "22f14be31b06549f80890e2c63a93834";
1088 md5 = "22f14be31b06549f80890e2c63a93834";
840 };
1089 };
1090 meta = {
1091 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1092 };
841 };
1093 };
842 pyramid-debugtoolbar = super.buildPythonPackage {
1094 pyramid-debugtoolbar = super.buildPythonPackage {
843 name = "pyramid-debugtoolbar-2.4.2";
1095 name = "pyramid-debugtoolbar-2.4.2";
@@ -848,6 +1100,9 b''
848 url = "https://pypi.python.org/packages/89/00/ed5426ee41ed747ba3ffd30e8230841a6878286ea67d480b1444d24f06a2/pyramid_debugtoolbar-2.4.2.tar.gz";
1100 url = "https://pypi.python.org/packages/89/00/ed5426ee41ed747ba3ffd30e8230841a6878286ea67d480b1444d24f06a2/pyramid_debugtoolbar-2.4.2.tar.gz";
849 md5 = "073ea67086cc4bd5decc3a000853642d";
1101 md5 = "073ea67086cc4bd5decc3a000853642d";
850 };
1102 };
1103 meta = {
1104 license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ];
1105 };
851 };
1106 };
852 pyramid-jinja2 = super.buildPythonPackage {
1107 pyramid-jinja2 = super.buildPythonPackage {
853 name = "pyramid-jinja2-2.5";
1108 name = "pyramid-jinja2-2.5";
@@ -858,6 +1113,9 b''
858 url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz";
1113 url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz";
859 md5 = "07cb6547204ac5e6f0b22a954ccee928";
1114 md5 = "07cb6547204ac5e6f0b22a954ccee928";
860 };
1115 };
1116 meta = {
1117 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1118 };
861 };
1119 };
862 pyramid-mako = super.buildPythonPackage {
1120 pyramid-mako = super.buildPythonPackage {
863 name = "pyramid-mako-1.0.2";
1121 name = "pyramid-mako-1.0.2";
@@ -868,6 +1126,9 b''
868 url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz";
1126 url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz";
869 md5 = "ee25343a97eb76bd90abdc2a774eb48a";
1127 md5 = "ee25343a97eb76bd90abdc2a774eb48a";
870 };
1128 };
1129 meta = {
1130 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1131 };
871 };
1132 };
872 pysqlite = super.buildPythonPackage {
1133 pysqlite = super.buildPythonPackage {
873 name = "pysqlite-2.6.3";
1134 name = "pysqlite-2.6.3";
@@ -878,6 +1139,9 b''
878 url = "https://pypi.python.org/packages/5c/a6/1c429cd4c8069cf4bfbd0eb4d592b3f4042155a8202df83d7e9b93aa3dc2/pysqlite-2.6.3.tar.gz";
1139 url = "https://pypi.python.org/packages/5c/a6/1c429cd4c8069cf4bfbd0eb4d592b3f4042155a8202df83d7e9b93aa3dc2/pysqlite-2.6.3.tar.gz";
879 md5 = "7ff1cedee74646b50117acff87aa1cfa";
1140 md5 = "7ff1cedee74646b50117acff87aa1cfa";
880 };
1141 };
1142 meta = {
1143 license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ];
1144 };
881 };
1145 };
882 pytest = super.buildPythonPackage {
1146 pytest = super.buildPythonPackage {
883 name = "pytest-2.8.5";
1147 name = "pytest-2.8.5";
@@ -888,6 +1152,9 b''
888 url = "https://pypi.python.org/packages/b1/3d/d7ea9b0c51e0cacded856e49859f0a13452747491e842c236bbab3714afe/pytest-2.8.5.zip";
1152 url = "https://pypi.python.org/packages/b1/3d/d7ea9b0c51e0cacded856e49859f0a13452747491e842c236bbab3714afe/pytest-2.8.5.zip";
889 md5 = "8493b06f700862f1294298d6c1b715a9";
1153 md5 = "8493b06f700862f1294298d6c1b715a9";
890 };
1154 };
1155 meta = {
1156 license = [ pkgs.lib.licenses.mit ];
1157 };
891 };
1158 };
892 pytest-catchlog = super.buildPythonPackage {
1159 pytest-catchlog = super.buildPythonPackage {
893 name = "pytest-catchlog-1.2.2";
1160 name = "pytest-catchlog-1.2.2";
@@ -898,6 +1165,9 b''
898 url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip";
1165 url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip";
899 md5 = "09d890c54c7456c818102b7ff8c182c8";
1166 md5 = "09d890c54c7456c818102b7ff8c182c8";
900 };
1167 };
1168 meta = {
1169 license = [ pkgs.lib.licenses.mit ];
1170 };
901 };
1171 };
902 pytest-cov = super.buildPythonPackage {
1172 pytest-cov = super.buildPythonPackage {
903 name = "pytest-cov-1.8.1";
1173 name = "pytest-cov-1.8.1";
@@ -908,6 +1178,9 b''
908 url = "https://pypi.python.org/packages/11/4b/b04646e97f1721878eb21e9f779102d84dd044d324382263b1770a3e4838/pytest-cov-1.8.1.tar.gz";
1178 url = "https://pypi.python.org/packages/11/4b/b04646e97f1721878eb21e9f779102d84dd044d324382263b1770a3e4838/pytest-cov-1.8.1.tar.gz";
909 md5 = "76c778afa2494088270348be42d759fc";
1179 md5 = "76c778afa2494088270348be42d759fc";
910 };
1180 };
1181 meta = {
1182 license = [ pkgs.lib.licenses.mit ];
1183 };
911 };
1184 };
912 pytest-profiling = super.buildPythonPackage {
1185 pytest-profiling = super.buildPythonPackage {
913 name = "pytest-profiling-1.0.1";
1186 name = "pytest-profiling-1.0.1";
@@ -918,6 +1191,9 b''
918 url = "https://pypi.python.org/packages/d8/67/8ffab73406e22870e07fa4dc8dce1d7689b26dba8efd00161c9b6fc01ec0/pytest-profiling-1.0.1.tar.gz";
1191 url = "https://pypi.python.org/packages/d8/67/8ffab73406e22870e07fa4dc8dce1d7689b26dba8efd00161c9b6fc01ec0/pytest-profiling-1.0.1.tar.gz";
919 md5 = "354404eb5b3fd4dc5eb7fffbb3d9b68b";
1192 md5 = "354404eb5b3fd4dc5eb7fffbb3d9b68b";
920 };
1193 };
1194 meta = {
1195 license = [ pkgs.lib.licenses.mit ];
1196 };
921 };
1197 };
922 pytest-runner = super.buildPythonPackage {
1198 pytest-runner = super.buildPythonPackage {
923 name = "pytest-runner-2.7.1";
1199 name = "pytest-runner-2.7.1";
@@ -928,6 +1204,9 b''
928 url = "https://pypi.python.org/packages/99/6b/c4ff4418d3424d4475b7af60724fd4a5cdd91ed8e489dc9443281f0052bc/pytest-runner-2.7.1.tar.gz";
1204 url = "https://pypi.python.org/packages/99/6b/c4ff4418d3424d4475b7af60724fd4a5cdd91ed8e489dc9443281f0052bc/pytest-runner-2.7.1.tar.gz";
929 md5 = "e56f0bc8d79a6bd91772b44ef4215c7e";
1205 md5 = "e56f0bc8d79a6bd91772b44ef4215c7e";
930 };
1206 };
1207 meta = {
1208 license = [ pkgs.lib.licenses.mit ];
1209 };
931 };
1210 };
932 pytest-timeout = super.buildPythonPackage {
1211 pytest-timeout = super.buildPythonPackage {
933 name = "pytest-timeout-0.4";
1212 name = "pytest-timeout-0.4";
@@ -938,6 +1217,9 b''
938 url = "https://pypi.python.org/packages/24/48/5f6bd4b8026a26e1dd427243d560a29a0f1b24a5c7cffca4bf049a7bb65b/pytest-timeout-0.4.tar.gz";
1217 url = "https://pypi.python.org/packages/24/48/5f6bd4b8026a26e1dd427243d560a29a0f1b24a5c7cffca4bf049a7bb65b/pytest-timeout-0.4.tar.gz";
939 md5 = "03b28aff69cbbfb959ed35ade5fde262";
1218 md5 = "03b28aff69cbbfb959ed35ade5fde262";
940 };
1219 };
1220 meta = {
1221 license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ];
1222 };
941 };
1223 };
942 python-dateutil = super.buildPythonPackage {
1224 python-dateutil = super.buildPythonPackage {
943 name = "python-dateutil-1.5";
1225 name = "python-dateutil-1.5";
@@ -948,6 +1230,9 b''
948 url = "https://pypi.python.org/packages/b4/7c/df59c89a753eb33c7c44e1dd42de0e9bc2ccdd5a4d576e0bfad97cc280cb/python-dateutil-1.5.tar.gz";
1230 url = "https://pypi.python.org/packages/b4/7c/df59c89a753eb33c7c44e1dd42de0e9bc2ccdd5a4d576e0bfad97cc280cb/python-dateutil-1.5.tar.gz";
949 md5 = "0dcb1de5e5cad69490a3b6ab63f0cfa5";
1231 md5 = "0dcb1de5e5cad69490a3b6ab63f0cfa5";
950 };
1232 };
1233 meta = {
1234 license = [ pkgs.lib.licenses.psfl ];
1235 };
951 };
1236 };
952 python-editor = super.buildPythonPackage {
1237 python-editor = super.buildPythonPackage {
953 name = "python-editor-1.0.1";
1238 name = "python-editor-1.0.1";
@@ -958,6 +1243,9 b''
958 url = "https://pypi.python.org/packages/2b/c0/df7b87d5cf016f82eab3b05cd35f53287c1178ad8c42bfb6fa61b89b22f6/python-editor-1.0.1.tar.gz";
1243 url = "https://pypi.python.org/packages/2b/c0/df7b87d5cf016f82eab3b05cd35f53287c1178ad8c42bfb6fa61b89b22f6/python-editor-1.0.1.tar.gz";
959 md5 = "e1fa63535b40e022fa4fd646fd8b511a";
1244 md5 = "e1fa63535b40e022fa4fd646fd8b511a";
960 };
1245 };
1246 meta = {
1247 license = [ pkgs.lib.licenses.asl20 ];
1248 };
961 };
1249 };
962 python-ldap = super.buildPythonPackage {
1250 python-ldap = super.buildPythonPackage {
963 name = "python-ldap-2.4.19";
1251 name = "python-ldap-2.4.19";
@@ -968,6 +1256,9 b''
968 url = "https://pypi.python.org/packages/42/81/1b64838c82e64f14d4e246ff00b52e650a35c012551b891ada2b85d40737/python-ldap-2.4.19.tar.gz";
1256 url = "https://pypi.python.org/packages/42/81/1b64838c82e64f14d4e246ff00b52e650a35c012551b891ada2b85d40737/python-ldap-2.4.19.tar.gz";
969 md5 = "b941bf31d09739492aa19ef679e94ae3";
1257 md5 = "b941bf31d09739492aa19ef679e94ae3";
970 };
1258 };
1259 meta = {
1260 license = [ pkgs.lib.licenses.psfl ];
1261 };
971 };
1262 };
972 python-memcached = super.buildPythonPackage {
1263 python-memcached = super.buildPythonPackage {
973 name = "python-memcached-1.57";
1264 name = "python-memcached-1.57";
@@ -978,6 +1269,9 b''
978 url = "https://pypi.python.org/packages/52/9d/eebc0dcbc5c7c66840ad207dfc1baa376dadb74912484bff73819cce01e6/python-memcached-1.57.tar.gz";
1269 url = "https://pypi.python.org/packages/52/9d/eebc0dcbc5c7c66840ad207dfc1baa376dadb74912484bff73819cce01e6/python-memcached-1.57.tar.gz";
979 md5 = "de21f64b42b2d961f3d4ad7beb5468a1";
1270 md5 = "de21f64b42b2d961f3d4ad7beb5468a1";
980 };
1271 };
1272 meta = {
1273 license = [ pkgs.lib.licenses.psfl ];
1274 };
981 };
1275 };
982 python-pam = super.buildPythonPackage {
1276 python-pam = super.buildPythonPackage {
983 name = "python-pam-1.8.2";
1277 name = "python-pam-1.8.2";
@@ -988,6 +1282,9 b''
988 url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz";
1282 url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz";
989 md5 = "db71b6b999246fb05d78ecfbe166629d";
1283 md5 = "db71b6b999246fb05d78ecfbe166629d";
990 };
1284 };
1285 meta = {
1286 license = [ { fullName = "License :: OSI Approved :: MIT License"; } pkgs.lib.licenses.mit ];
1287 };
991 };
1288 };
992 pytz = super.buildPythonPackage {
1289 pytz = super.buildPythonPackage {
993 name = "pytz-2015.4";
1290 name = "pytz-2015.4";
@@ -998,6 +1295,9 b''
998 url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip";
1295 url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip";
999 md5 = "233f2a2b370d03f9b5911700cc9ebf3c";
1296 md5 = "233f2a2b370d03f9b5911700cc9ebf3c";
1000 };
1297 };
1298 meta = {
1299 license = [ pkgs.lib.licenses.mit ];
1300 };
1001 };
1301 };
1002 pyzmq = super.buildPythonPackage {
1302 pyzmq = super.buildPythonPackage {
1003 name = "pyzmq-14.6.0";
1303 name = "pyzmq-14.6.0";
@@ -1008,6 +1308,9 b''
1008 url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz";
1308 url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz";
1009 md5 = "395b5de95a931afa5b14c9349a5b8024";
1309 md5 = "395b5de95a931afa5b14c9349a5b8024";
1010 };
1310 };
1311 meta = {
1312 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1313 };
1011 };
1314 };
1012 recaptcha-client = super.buildPythonPackage {
1315 recaptcha-client = super.buildPythonPackage {
1013 name = "recaptcha-client-1.0.6";
1316 name = "recaptcha-client-1.0.6";
@@ -1018,6 +1321,9 b''
1018 url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz";
1321 url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz";
1019 md5 = "74228180f7e1fb76c4d7089160b0d919";
1322 md5 = "74228180f7e1fb76c4d7089160b0d919";
1020 };
1323 };
1324 meta = {
1325 license = [ { fullName = "MIT/X11"; } ];
1326 };
1021 };
1327 };
1022 repoze.lru = super.buildPythonPackage {
1328 repoze.lru = super.buildPythonPackage {
1023 name = "repoze.lru-0.6";
1329 name = "repoze.lru-0.6";
@@ -1028,6 +1334,9 b''
1028 url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz";
1334 url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz";
1029 md5 = "2c3b64b17a8e18b405f55d46173e14dd";
1335 md5 = "2c3b64b17a8e18b405f55d46173e14dd";
1030 };
1336 };
1337 meta = {
1338 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1339 };
1031 };
1340 };
1032 requests = super.buildPythonPackage {
1341 requests = super.buildPythonPackage {
1033 name = "requests-2.9.1";
1342 name = "requests-2.9.1";
@@ -1038,13 +1347,19 b''
1038 url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz";
1347 url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz";
1039 md5 = "0b7f480d19012ec52bab78292efd976d";
1348 md5 = "0b7f480d19012ec52bab78292efd976d";
1040 };
1349 };
1350 meta = {
1351 license = [ pkgs.lib.licenses.asl20 ];
1352 };
1041 };
1353 };
1042 rhodecode-enterprise-ce = super.buildPythonPackage {
1354 rhodecode-enterprise-ce = super.buildPythonPackage {
1043 name = "rhodecode-enterprise-ce-4.1.2";
1355 name = "rhodecode-enterprise-ce-4.2.0";
1044 buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner];
1356 buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner];
1045 doCheck = true;
1357 doCheck = true;
1046 propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors psutil py-bcrypt];
1358 propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors psutil py-bcrypt];
1047 src = ./.;
1359 src = ./.;
1360 meta = {
1361 license = [ { fullName = "AGPLv3, and Commercial License"; } ];
1362 };
1048 };
1363 };
1049 rhodecode-tools = super.buildPythonPackage {
1364 rhodecode-tools = super.buildPythonPackage {
1050 name = "rhodecode-tools-0.8.3";
1365 name = "rhodecode-tools-0.8.3";
@@ -1055,6 +1370,9 b''
1055 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.8.3.zip";
1370 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.8.3.zip";
1056 md5 = "9acdfd71b8ddf4056057065f37ab9ccb";
1371 md5 = "9acdfd71b8ddf4056057065f37ab9ccb";
1057 };
1372 };
1373 meta = {
1374 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1375 };
1058 };
1376 };
1059 serpent = super.buildPythonPackage {
1377 serpent = super.buildPythonPackage {
1060 name = "serpent-1.12";
1378 name = "serpent-1.12";
@@ -1065,6 +1383,9 b''
1065 url = "https://pypi.python.org/packages/3b/19/1e0e83b47c09edaef8398655088036e7e67386b5c48770218ebb339fbbd5/serpent-1.12.tar.gz";
1383 url = "https://pypi.python.org/packages/3b/19/1e0e83b47c09edaef8398655088036e7e67386b5c48770218ebb339fbbd5/serpent-1.12.tar.gz";
1066 md5 = "05869ac7b062828b34f8f927f0457b65";
1384 md5 = "05869ac7b062828b34f8f927f0457b65";
1067 };
1385 };
1386 meta = {
1387 license = [ pkgs.lib.licenses.mit ];
1388 };
1068 };
1389 };
1069 setproctitle = super.buildPythonPackage {
1390 setproctitle = super.buildPythonPackage {
1070 name = "setproctitle-1.1.8";
1391 name = "setproctitle-1.1.8";
@@ -1075,6 +1396,9 b''
1075 url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz";
1396 url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz";
1076 md5 = "728f4c8c6031bbe56083a48594027edd";
1397 md5 = "728f4c8c6031bbe56083a48594027edd";
1077 };
1398 };
1399 meta = {
1400 license = [ pkgs.lib.licenses.bsdOriginal ];
1401 };
1078 };
1402 };
1079 setuptools = super.buildPythonPackage {
1403 setuptools = super.buildPythonPackage {
1080 name = "setuptools-20.8.1";
1404 name = "setuptools-20.8.1";
@@ -1085,6 +1409,9 b''
1085 url = "https://pypi.python.org/packages/c4/19/c1bdc88b53da654df43770f941079dbab4e4788c2dcb5658fb86259894c7/setuptools-20.8.1.zip";
1409 url = "https://pypi.python.org/packages/c4/19/c1bdc88b53da654df43770f941079dbab4e4788c2dcb5658fb86259894c7/setuptools-20.8.1.zip";
1086 md5 = "fe58a5cac0df20bb83942b252a4b0543";
1410 md5 = "fe58a5cac0df20bb83942b252a4b0543";
1087 };
1411 };
1412 meta = {
1413 license = [ pkgs.lib.licenses.mit ];
1414 };
1088 };
1415 };
1089 setuptools-scm = super.buildPythonPackage {
1416 setuptools-scm = super.buildPythonPackage {
1090 name = "setuptools-scm-1.11.0";
1417 name = "setuptools-scm-1.11.0";
@@ -1095,6 +1422,9 b''
1095 url = "https://pypi.python.org/packages/cd/5f/e3a038292358058d83d764a47d09114aa5a8003ed4529518f9e580f1a94f/setuptools_scm-1.11.0.tar.gz";
1422 url = "https://pypi.python.org/packages/cd/5f/e3a038292358058d83d764a47d09114aa5a8003ed4529518f9e580f1a94f/setuptools_scm-1.11.0.tar.gz";
1096 md5 = "4c5c896ba52e134bbc3507bac6400087";
1423 md5 = "4c5c896ba52e134bbc3507bac6400087";
1097 };
1424 };
1425 meta = {
1426 license = [ pkgs.lib.licenses.mit ];
1427 };
1098 };
1428 };
1099 simplejson = super.buildPythonPackage {
1429 simplejson = super.buildPythonPackage {
1100 name = "simplejson-3.7.2";
1430 name = "simplejson-3.7.2";
@@ -1105,6 +1435,9 b''
1105 url = "https://pypi.python.org/packages/6d/89/7f13f099344eea9d6722779a1f165087cb559598107844b1ac5dbd831fb1/simplejson-3.7.2.tar.gz";
1435 url = "https://pypi.python.org/packages/6d/89/7f13f099344eea9d6722779a1f165087cb559598107844b1ac5dbd831fb1/simplejson-3.7.2.tar.gz";
1106 md5 = "a5fc7d05d4cb38492285553def5d4b46";
1436 md5 = "a5fc7d05d4cb38492285553def5d4b46";
1107 };
1437 };
1438 meta = {
1439 license = [ pkgs.lib.licenses.mit pkgs.lib.licenses.afl21 ];
1440 };
1108 };
1441 };
1109 six = super.buildPythonPackage {
1442 six = super.buildPythonPackage {
1110 name = "six-1.9.0";
1443 name = "six-1.9.0";
@@ -1115,6 +1448,9 b''
1115 url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz";
1448 url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz";
1116 md5 = "476881ef4012262dfc8adc645ee786c4";
1449 md5 = "476881ef4012262dfc8adc645ee786c4";
1117 };
1450 };
1451 meta = {
1452 license = [ pkgs.lib.licenses.mit ];
1453 };
1118 };
1454 };
1119 subprocess32 = super.buildPythonPackage {
1455 subprocess32 = super.buildPythonPackage {
1120 name = "subprocess32-3.2.6";
1456 name = "subprocess32-3.2.6";
@@ -1125,6 +1461,9 b''
1125 url = "https://pypi.python.org/packages/28/8d/33ccbff51053f59ae6c357310cac0e79246bbed1d345ecc6188b176d72c3/subprocess32-3.2.6.tar.gz";
1461 url = "https://pypi.python.org/packages/28/8d/33ccbff51053f59ae6c357310cac0e79246bbed1d345ecc6188b176d72c3/subprocess32-3.2.6.tar.gz";
1126 md5 = "754c5ab9f533e764f931136974b618f1";
1462 md5 = "754c5ab9f533e764f931136974b618f1";
1127 };
1463 };
1464 meta = {
1465 license = [ pkgs.lib.licenses.psfl ];
1466 };
1128 };
1467 };
1129 supervisor = super.buildPythonPackage {
1468 supervisor = super.buildPythonPackage {
1130 name = "supervisor-3.1.3";
1469 name = "supervisor-3.1.3";
@@ -1135,6 +1474,9 b''
1135 url = "https://pypi.python.org/packages/a6/41/65ad5bd66230b173eb4d0b8810230f3a9c59ef52ae066e540b6b99895db7/supervisor-3.1.3.tar.gz";
1474 url = "https://pypi.python.org/packages/a6/41/65ad5bd66230b173eb4d0b8810230f3a9c59ef52ae066e540b6b99895db7/supervisor-3.1.3.tar.gz";
1136 md5 = "aad263c4fbc070de63dd354864d5e552";
1475 md5 = "aad263c4fbc070de63dd354864d5e552";
1137 };
1476 };
1477 meta = {
1478 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1479 };
1138 };
1480 };
1139 transifex-client = super.buildPythonPackage {
1481 transifex-client = super.buildPythonPackage {
1140 name = "transifex-client-0.10";
1482 name = "transifex-client-0.10";
@@ -1145,6 +1487,9 b''
1145 url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz";
1487 url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz";
1146 md5 = "5549538d84b8eede6b254cd81ae024fa";
1488 md5 = "5549538d84b8eede6b254cd81ae024fa";
1147 };
1489 };
1490 meta = {
1491 license = [ pkgs.lib.licenses.gpl2 ];
1492 };
1148 };
1493 };
1149 translationstring = super.buildPythonPackage {
1494 translationstring = super.buildPythonPackage {
1150 name = "translationstring-1.3";
1495 name = "translationstring-1.3";
@@ -1155,6 +1500,9 b''
1155 url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
1500 url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
1156 md5 = "a4b62e0f3c189c783a1685b3027f7c90";
1501 md5 = "a4b62e0f3c189c783a1685b3027f7c90";
1157 };
1502 };
1503 meta = {
1504 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
1505 };
1158 };
1506 };
1159 trollius = super.buildPythonPackage {
1507 trollius = super.buildPythonPackage {
1160 name = "trollius-1.0.4";
1508 name = "trollius-1.0.4";
@@ -1165,6 +1513,9 b''
1165 url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz";
1513 url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz";
1166 md5 = "3631a464d49d0cbfd30ab2918ef2b783";
1514 md5 = "3631a464d49d0cbfd30ab2918ef2b783";
1167 };
1515 };
1516 meta = {
1517 license = [ pkgs.lib.licenses.asl20 ];
1518 };
1168 };
1519 };
1169 uWSGI = super.buildPythonPackage {
1520 uWSGI = super.buildPythonPackage {
1170 name = "uWSGI-2.0.11.2";
1521 name = "uWSGI-2.0.11.2";
@@ -1175,6 +1526,9 b''
1175 url = "https://pypi.python.org/packages/9b/78/918db0cfab0546afa580c1e565209c49aaf1476bbfe491314eadbe47c556/uwsgi-2.0.11.2.tar.gz";
1526 url = "https://pypi.python.org/packages/9b/78/918db0cfab0546afa580c1e565209c49aaf1476bbfe491314eadbe47c556/uwsgi-2.0.11.2.tar.gz";
1176 md5 = "1f02dcbee7f6f61de4b1fd68350cf16f";
1527 md5 = "1f02dcbee7f6f61de4b1fd68350cf16f";
1177 };
1528 };
1529 meta = {
1530 license = [ pkgs.lib.licenses.gpl2 ];
1531 };
1178 };
1532 };
1179 urllib3 = super.buildPythonPackage {
1533 urllib3 = super.buildPythonPackage {
1180 name = "urllib3-1.16";
1534 name = "urllib3-1.16";
@@ -1185,6 +1539,9 b''
1185 url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz";
1539 url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz";
1186 md5 = "fcaab1c5385c57deeb7053d3d7d81d59";
1540 md5 = "fcaab1c5385c57deeb7053d3d7d81d59";
1187 };
1541 };
1542 meta = {
1543 license = [ pkgs.lib.licenses.mit ];
1544 };
1188 };
1545 };
1189 venusian = super.buildPythonPackage {
1546 venusian = super.buildPythonPackage {
1190 name = "venusian-1.0";
1547 name = "venusian-1.0";
@@ -1195,6 +1552,9 b''
1195 url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz";
1552 url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz";
1196 md5 = "dccf2eafb7113759d60c86faf5538756";
1553 md5 = "dccf2eafb7113759d60c86faf5538756";
1197 };
1554 };
1555 meta = {
1556 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1557 };
1198 };
1558 };
1199 waitress = super.buildPythonPackage {
1559 waitress = super.buildPythonPackage {
1200 name = "waitress-0.8.9";
1560 name = "waitress-0.8.9";
@@ -1205,6 +1565,9 b''
1205 url = "https://pypi.python.org/packages/ee/65/fc9dee74a909a1187ca51e4f15ad9c4d35476e4ab5813f73421505c48053/waitress-0.8.9.tar.gz";
1565 url = "https://pypi.python.org/packages/ee/65/fc9dee74a909a1187ca51e4f15ad9c4d35476e4ab5813f73421505c48053/waitress-0.8.9.tar.gz";
1206 md5 = "da3f2e62b3676be5dd630703a68e2a04";
1566 md5 = "da3f2e62b3676be5dd630703a68e2a04";
1207 };
1567 };
1568 meta = {
1569 license = [ pkgs.lib.licenses.zpt21 ];
1570 };
1208 };
1571 };
1209 wsgiref = super.buildPythonPackage {
1572 wsgiref = super.buildPythonPackage {
1210 name = "wsgiref-0.1.2";
1573 name = "wsgiref-0.1.2";
@@ -1215,6 +1578,9 b''
1215 url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip";
1578 url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip";
1216 md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb";
1579 md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb";
1217 };
1580 };
1581 meta = {
1582 license = [ { fullName = "PSF or ZPL"; } ];
1583 };
1218 };
1584 };
1219 zope.cachedescriptors = super.buildPythonPackage {
1585 zope.cachedescriptors = super.buildPythonPackage {
1220 name = "zope.cachedescriptors-4.0.0";
1586 name = "zope.cachedescriptors-4.0.0";
@@ -1225,6 +1591,9 b''
1225 url = "https://pypi.python.org/packages/40/33/694b6644c37f28553f4b9f20b3c3a20fb709a22574dff20b5bdffb09ecd5/zope.cachedescriptors-4.0.0.tar.gz";
1591 url = "https://pypi.python.org/packages/40/33/694b6644c37f28553f4b9f20b3c3a20fb709a22574dff20b5bdffb09ecd5/zope.cachedescriptors-4.0.0.tar.gz";
1226 md5 = "8d308de8c936792c8e758058fcb7d0f0";
1592 md5 = "8d308de8c936792c8e758058fcb7d0f0";
1227 };
1593 };
1594 meta = {
1595 license = [ pkgs.lib.licenses.zpt21 ];
1596 };
1228 };
1597 };
1229 zope.deprecation = super.buildPythonPackage {
1598 zope.deprecation = super.buildPythonPackage {
1230 name = "zope.deprecation-4.1.2";
1599 name = "zope.deprecation-4.1.2";
@@ -1235,6 +1604,9 b''
1235 url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz";
1604 url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz";
1236 md5 = "e9a663ded58f4f9f7881beb56cae2782";
1605 md5 = "e9a663ded58f4f9f7881beb56cae2782";
1237 };
1606 };
1607 meta = {
1608 license = [ pkgs.lib.licenses.zpt21 ];
1609 };
1238 };
1610 };
1239 zope.event = super.buildPythonPackage {
1611 zope.event = super.buildPythonPackage {
1240 name = "zope.event-4.0.3";
1612 name = "zope.event-4.0.3";
@@ -1245,6 +1617,9 b''
1245 url = "https://pypi.python.org/packages/c1/29/91ba884d7d6d96691df592e9e9c2bfa57a47040ec1ff47eff18c85137152/zope.event-4.0.3.tar.gz";
1617 url = "https://pypi.python.org/packages/c1/29/91ba884d7d6d96691df592e9e9c2bfa57a47040ec1ff47eff18c85137152/zope.event-4.0.3.tar.gz";
1246 md5 = "9a3780916332b18b8b85f522bcc3e249";
1618 md5 = "9a3780916332b18b8b85f522bcc3e249";
1247 };
1619 };
1620 meta = {
1621 license = [ pkgs.lib.licenses.zpt21 ];
1622 };
1248 };
1623 };
1249 zope.interface = super.buildPythonPackage {
1624 zope.interface = super.buildPythonPackage {
1250 name = "zope.interface-4.1.3";
1625 name = "zope.interface-4.1.3";
@@ -1255,6 +1630,9 b''
1255 url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz";
1630 url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz";
1256 md5 = "9ae3d24c0c7415deb249dd1a132f0f79";
1631 md5 = "9ae3d24c0c7415deb249dd1a132f0f79";
1257 };
1632 };
1633 meta = {
1634 license = [ pkgs.lib.licenses.zpt21 ];
1635 };
1258 };
1636 };
1259
1637
1260 ### Test requirements
1638 ### Test requirements
@@ -25,6 +25,7 b''
25 # vcsserver resides.
25 # vcsserver resides.
26
26
27 { pkgs ? import <nixpkgs> {}
27 { pkgs ? import <nixpkgs> {}
28 , doCheck ? true
28 }:
29 }:
29
30
30 let
31 let
@@ -69,7 +69,6 b' flake8==2.4.1'
69 future==0.14.3
69 future==0.14.3
70 futures==3.0.2
70 futures==3.0.2
71 gprof2dot==2015.12.1
71 gprof2dot==2015.12.1
72 greenlet==0.4.9
73 gunicorn==19.6.0
72 gunicorn==19.6.0
74
73
75 # TODO: Needs subvertpy and blows up without Subversion headers,
74 # TODO: Needs subvertpy and blows up without Subversion headers,
@@ -78,7 +77,7 b' gunicorn==19.6.0'
78
77
79 gnureadline==6.3.3
78 gnureadline==6.3.3
80 infrae.cache==1.0.1
79 infrae.cache==1.0.1
81 invoke==0.11.1
80 invoke==0.13.0
82 ipdb==0.8
81 ipdb==0.8
83 ipython==3.1.0
82 ipython==3.1.0
84 iso8601==0.1.11
83 iso8601==0.1.11
@@ -1,1 +1,1 b''
1 4.1.2 No newline at end of file
1 4.2.0 No newline at end of file
@@ -22,6 +22,7 b''
22 Authentication modules
22 Authentication modules
23 """
23 """
24
24
25 import colander
25 import logging
26 import logging
26 import time
27 import time
27 import traceback
28 import traceback
@@ -97,16 +98,18 b' class RhodeCodeAuthPluginBase(object):'
97 # Mapping of python to DB settings model types. Plugins may override or
98 # Mapping of python to DB settings model types. Plugins may override or
98 # extend this mapping.
99 # extend this mapping.
99 _settings_type_map = {
100 _settings_type_map = {
100 str: 'str',
101 colander.String: 'unicode',
101 int: 'int',
102 colander.Integer: 'int',
102 unicode: 'unicode',
103 colander.Boolean: 'bool',
103 bool: 'bool',
104 colander.List: 'list',
104 list: 'list',
105 }
105 }
106
106
107 def __init__(self, plugin_id):
107 def __init__(self, plugin_id):
108 self._plugin_id = plugin_id
108 self._plugin_id = plugin_id
109
109
110 def __str__(self):
111 return self.get_id()
112
110 def _get_setting_full_name(self, name):
113 def _get_setting_full_name(self, name):
111 """
114 """
112 Return the full setting name used for storing values in the database.
115 Return the full setting name used for storing values in the database.
@@ -116,16 +119,19 b' class RhodeCodeAuthPluginBase(object):'
116 # PluginSetting or to use the plugin id here.
119 # PluginSetting or to use the plugin id here.
117 return 'auth_{}_{}'.format(self.name, name)
120 return 'auth_{}_{}'.format(self.name, name)
118
121
119 def _get_setting_type(self, name, value):
122 def _get_setting_type(self, name):
123 """
124 Return the type of a setting. This type is defined by the SettingsModel
125 and determines how the setting is stored in DB. Optionally the suffix
126 `.encrypted` is appended to instruct SettingsModel to store it
127 encrypted.
120 """
128 """
121 Get the type as used by the SettingsModel accordingly to type of passed
129 schema_node = self.get_settings_schema().get(name)
122 value. Optionally the suffix `.encrypted` is appended to instruct
130 db_type = self._settings_type_map.get(
123 SettingsModel to store it encrypted.
131 type(schema_node.typ), 'unicode')
124 """
125 type_ = self._settings_type_map.get(type(value), 'unicode')
126 if name in self._settings_encrypted:
132 if name in self._settings_encrypted:
127 type_ = '{}.encrypted'.format(type_)
133 db_type = '{}.encrypted'.format(db_type)
128 return type_
134 return db_type
129
135
130 def is_enabled(self):
136 def is_enabled(self):
131 """
137 """
@@ -161,20 +167,20 b' class RhodeCodeAuthPluginBase(object):'
161 """
167 """
162 return AuthnPluginSettingsSchemaBase()
168 return AuthnPluginSettingsSchemaBase()
163
169
164 def get_setting_by_name(self, name):
170 def get_setting_by_name(self, name, default=None):
165 """
171 """
166 Returns a plugin setting by name.
172 Returns a plugin setting by name.
167 """
173 """
168 full_name = self._get_setting_full_name(name)
174 full_name = self._get_setting_full_name(name)
169 db_setting = SettingsModel().get_setting_by_name(full_name)
175 db_setting = SettingsModel().get_setting_by_name(full_name)
170 return db_setting.app_settings_value if db_setting else None
176 return db_setting.app_settings_value if db_setting else default
171
177
172 def create_or_update_setting(self, name, value):
178 def create_or_update_setting(self, name, value):
173 """
179 """
174 Create or update a setting for this plugin in the persistent storage.
180 Create or update a setting for this plugin in the persistent storage.
175 """
181 """
176 full_name = self._get_setting_full_name(name)
182 full_name = self._get_setting_full_name(name)
177 type_ = self._get_setting_type(name, value)
183 type_ = self._get_setting_type(name)
178 db_setting = SettingsModel().create_or_update_setting(
184 db_setting = SettingsModel().create_or_update_setting(
179 full_name, value, type_)
185 full_name, value, type_)
180 return db_setting.app_settings_value
186 return db_setting.app_settings_value
@@ -56,10 +56,12 b' class AuthnPluginViewBase(object):'
56 errors = errors or {}
56 errors = errors or {}
57 schema = self.plugin.get_settings_schema()
57 schema = self.plugin.get_settings_schema()
58
58
59 # Get default values for the form.
59 # Compute default values for the form. Priority is:
60 # 1. Passed to this method 2. DB value 3. Schema default
60 for node in schema:
61 for node in schema:
61 db_value = self.plugin.get_setting_by_name(node.name)
62 if node.name not in defaults:
62 defaults.setdefault(node.name, db_value)
63 defaults[node.name] = self.plugin.get_setting_by_name(
64 node.name, node.default)
63
65
64 template_context = {
66 template_context = {
65 'defaults': defaults,
67 'defaults': defaults,
@@ -78,15 +80,17 b' class AuthnPluginViewBase(object):'
78 View that validates and stores the plugin settings.
80 View that validates and stores the plugin settings.
79 """
81 """
80 schema = self.plugin.get_settings_schema()
82 schema = self.plugin.get_settings_schema()
83 data = self.request.params
84
81 try:
85 try:
82 valid_data = schema.deserialize(self.request.params)
86 valid_data = schema.deserialize(data)
83 except colander.Invalid, e:
87 except colander.Invalid, e:
84 # Display error message and display form again.
88 # Display error message and display form again.
85 self.request.session.flash(
89 self.request.session.flash(
86 _('Errors exist when saving plugin settings. '
90 _('Errors exist when saving plugin settings. '
87 'Please check the form inputs.'),
91 'Please check the form inputs.'),
88 queue='error')
92 queue='error')
89 defaults = schema.flatten(self.request.params)
93 defaults = {key: data[key] for key in data if key in schema}
90 return self.settings_get(errors=e.asdict(), defaults=defaults)
94 return self.settings_get(errors=e.asdict(), defaults=defaults)
91
95
92 # Store validated data.
96 # Store validated data.
@@ -82,7 +82,7 b' def load_environment(global_conf, app_co'
82
82
83 config['routes.map'] = make_map(config)
83 config['routes.map'] = make_map(config)
84
84
85 if asbool(config['debug']):
85 if asbool(config.get('generate_js_files', 'false')):
86 jsroutes = config['routes.map'].jsroutes()
86 jsroutes = config['routes.map'].jsroutes()
87 jsroutes_file_content = generate_jsroutes_content(jsroutes)
87 jsroutes_file_content = generate_jsroutes_content(jsroutes)
88 jsroutes_file_path = os.path.join(
88 jsroutes_file_path = os.path.join(
@@ -29,7 +29,8 b' def generate_jsroutes_content(jsroutes):'
29 * DO NOT CHANGE THIS FILE MANUALLY *
29 * DO NOT CHANGE THIS FILE MANUALLY *
30 * *
30 * *
31 * *
31 * *
32 * This file is automatically generated when the app starts up. *
32 * This file is automatically generated when the app starts up with *
33 * generate_js_files = true *
33 * *
34 * *
34 * To add a route here pass jsroute=True to the route definition in the app *
35 * To add a route here pass jsroute=True to the route definition in the app *
35 * *
36 * *
@@ -1,217 +1,256 b''
1 {
1 {
2 "cyrus-sasl-2.1.26": {
2 "nodejs-4.3.1": {
3 "cyrus": "http://cyrusimap.web.cmu.edu/mediawiki/index.php/Downloads#Licensing"
3 "MIT License": "http://spdx.org/licenses/MIT"
4 },
4 },
5 "openldap-2.4.41": {
5 "postgresql-9.5.1": {
6 "OLDAP-2.8": "http://spdx.org/licenses/OLDAP-2.8"
6 "PostgreSQL License": "http://spdx.org/licenses/PostgreSQL"
7 },
7 },
8 "openssl-1.0.1p": {
8 "python-2.7.11": {
9 "OpenSSL": "http://spdx.org/licenses/OpenSSL"
9 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
10 },
11 "python-2.7.10": {
12 "Python-2.0": "http://spdx.org/licenses/Python-2.0"
13 },
10 },
14 "python2.7-Babel-1.3": {
11 "python2.7-Babel-1.3": {
15 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
12 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
16 },
13 },
17 "python2.7-Beaker-1.7.0": {
14 "python2.7-Beaker-1.7.0": {
18 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
15 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
19 },
16 },
20 "python2.7-FormEncode-1.2.4": {
17 "python2.7-FormEncode-1.2.4": {
21 "Python-2.0": "http://spdx.org/licenses/Python-2.0"
18 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
22 },
19 },
23 "python2.7-Mako-1.0.1": {
20 "python2.7-Mako-1.0.1": {
24 "MIT": "http://spdx.org/licenses/MIT"
21 "MIT License": "http://spdx.org/licenses/MIT"
25 },
22 },
26 "python2.7-Markdown-2.6.2": {
23 "python2.7-Markdown-2.6.2": {
27 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
24 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
28 },
25 },
29 "python2.7-MarkupSafe-0.23": {
26 "python2.7-MarkupSafe-0.23": {
30 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
27 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
31 },
28 },
32 "python2.7-Paste-2.0.2": {
29 "python2.7-Paste-2.0.2": {
33 "MIT": "http://spdx.org/licenses/MIT"
30 "MIT License": "http://spdx.org/licenses/MIT"
34 },
31 },
35 "python2.7-PasteDeploy-1.5.2": {
32 "python2.7-PasteDeploy-1.5.2": {
36 "MIT": "http://spdx.org/licenses/MIT"
33 "MIT License": "http://spdx.org/licenses/MIT"
37 },
34 },
38 "python2.7-PasteScript-1.7.5": {
35 "python2.7-PasteScript-1.7.5": {
39 "MIT": "http://spdx.org/licenses/MIT"
36 "MIT License": "http://spdx.org/licenses/MIT"
40 },
37 },
41 "python2.7-Pygments-2.0.2": {
38 "python2.7-Pygments-2.0.2": {
42 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
39 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
43 },
40 },
44 "python2.7-Pylons-1.0.2-patch1": {
41 "python2.7-Pylons-1.0.1-patch1": {
45 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
42 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
46 },
43 },
47 "python2.7-Pyro4-4.35": {
44 "python2.7-Pyro4-4.35": {
48 "MIT": "http://spdx.org/licenses/MIT"
45 "MIT License": "http://spdx.org/licenses/MIT"
49 },
46 },
50 "python2.7-Routes-1.13": {
47 "python2.7-Routes-1.13": {
51 "MIT": "http://spdx.org/licenses/MIT"
48 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
52 },
49 },
53 "python2.7-SQLAlchemy-0.9.9": {
50 "python2.7-SQLAlchemy-0.9.9": {
54 "MIT": "http://spdx.org/licenses/MIT"
51 "MIT License": "http://spdx.org/licenses/MIT"
55 },
52 },
56 "python2.7-Tempita-0.5.2": {
53 "python2.7-Tempita-0.5.2": {
57 "MIT": "http://spdx.org/licenses/MIT"
54 "MIT License": "http://spdx.org/licenses/MIT"
58 },
55 },
59 "python2.7-URLObject-2.4.0": {
56 "python2.7-URLObject-2.4.0": {
60 "Unlicense": "http://spdx.org/licenses/Unlicense"
57 "The Unlicense": "http://unlicense.org/"
61 },
58 },
62 "python2.7-WebError-0.10.3": {
59 "python2.7-WebError-0.10.3": {
63 "MIT": "http://spdx.org/licenses/MIT"
60 "MIT License": "http://spdx.org/licenses/MIT"
64 },
61 },
65 "python2.7-WebHelpers-1.3-cust1": {
62 "python2.7-WebHelpers-1.3": {
66 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
63 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
67 },
64 },
68 "python2.7-WebHelpers2-2.0": {
65 "python2.7-WebHelpers2-2.0": {
69 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
66 "MIT License": "http://spdx.org/licenses/MIT"
70 },
67 },
71 "python2.7-WebOb-1.3.1": {
68 "python2.7-WebOb-1.3.1": {
72 "MIT": "http://spdx.org/licenses/MIT"
69 "MIT License": "http://spdx.org/licenses/MIT"
73 },
70 },
74 "python2.7-Whoosh-2.7.0-patch1": {
71 "python2.7-Whoosh-2.7.0": {
75 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
72 "BSD 2-clause \"Simplified\" License": "http://spdx.org/licenses/BSD-2-Clause",
73 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
76 },
74 },
77 "python2.7-alembic-0.8.4": {
75 "python2.7-alembic-0.8.4": {
78 "MIT": "http://spdx.org/licenses/MIT"
76 "MIT License": "http://spdx.org/licenses/MIT"
79 },
77 },
80 "python2.7-amqplib-1.0.2": {
78 "python2.7-amqplib-1.0.2": {
81 "LGPL-3.0": "http://spdx.org/licenses/LGPL-3.0"
79 "GNU Lesser General Public License v3.0 only": "http://spdx.org/licenses/LGPL-3.0"
82 },
80 },
83 "python2.7-anyjson-0.3.3": {
81 "python2.7-anyjson-0.3.3": {
84 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
82 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
83 },
84 "python2.7-appenlight-client-0.6.14": {
85 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
85 },
86 },
86 "python2.7-appenlight_client-0.6.14": {
87 "python2.7-authomatic-0.1.0.post1": {
87 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
88 "MIT License": "http://spdx.org/licenses/MIT"
88 },
89 },
89 "python2.7-backport_ipaddress-0.1": {
90 "python2.7-backport-ipaddress-0.1": {
90 "Python-2.0": "http://spdx.org/licenses/Python-2.0"
91 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
91 },
92 },
92 "python2.7-celery-2.2.10": {
93 "python2.7-celery-2.2.10": {
93 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
94 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
94 },
95 },
95 "python2.7-click-4.0": {
96 "python2.7-click-5.1": {
96 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
97 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
98 },
99 "python2.7-colander-1.2": {
100 "Repoze License": "http://www.repoze.org/LICENSE.txt"
97 },
101 },
98 "python2.7-configobj-5.0.6": {
102 "python2.7-configobj-5.0.6": {
99 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
103 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
100 },
104 },
101 "python2.7-cssselect-0.9.1": {
105 "python2.7-cssselect-0.9.1": {
102 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
106 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
103 },
107 },
104 "python2.7-decorator-3.4.2": {
108 "python2.7-decorator-3.4.2": {
105 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
109 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
106 },
110 },
107 "python2.7-docutils-0.12": {
111 "python2.7-docutils-0.12": {
108 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
112 "BSD 2-clause \"Simplified\" License": "http://spdx.org/licenses/BSD-2-Clause"
113 },
114 "python2.7-elasticsearch-2.3.0": {
115 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
116 },
117 "python2.7-elasticsearch-dsl-2.0.0": {
118 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
109 },
119 },
110 "python2.7-future-0.14.3": {
120 "python2.7-future-0.14.3": {
111 "MIT": "http://spdx.org/licenses/MIT"
121 "MIT License": "http://spdx.org/licenses/MIT"
112 },
122 },
113 "python2.7-futures-3.0.2": {
123 "python2.7-futures-3.0.2": {
114 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
124 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
125 },
126 "python2.7-gnureadline-6.3.3": {
127 "GNU General Public License v1.0 only": "http://spdx.org/licenses/GPL-1.0"
115 },
128 },
116 "python2.7-greenlet-0.4.7": {
129 "python2.7-gunicorn-19.6.0": {
117 "MIT": "http://spdx.org/licenses/MIT"
130 "MIT License": "http://spdx.org/licenses/MIT"
118 },
131 },
119 "python2.7-gunicorn-19.3.0": {
132 "python2.7-infrae.cache-1.0.1": {
120 "MIT": "http://spdx.org/licenses/MIT"
133 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
121 },
134 },
122 "python2.7-ipython-3.1.0": {
135 "python2.7-ipython-3.1.0": {
123 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
136 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
124 },
125 "python2.7-kombu-1.5.1-patch1": {
126 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
127 },
137 },
128 "python2.7-mccabe-0.3": {
138 "python2.7-iso8601-0.1.11": {
129 "expat": "http://directory.fsf.org/wiki/License:Expat"
139 "MIT License": "http://spdx.org/licenses/MIT"
130 },
140 },
131 "python2.7-meld3-1.0.2": {
141 "python2.7-kombu-1.5.1": {
132 "repoze": "http://repoze.org/license.html"
142 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
133 },
143 },
134 "python2.7-msgpack-python-0.4.6": {
144 "python2.7-msgpack-python-0.4.6": {
135 "Apache-2.0": "http://spdx.org/licenses/Apache-2.0"
145 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
136 },
137 "python2.7-objgraph-2.0.0": {
138 "MIT": "http://spdx.org/licenses/MIT"
139 },
146 },
140 "python2.7-packaging-15.2": {
147 "python2.7-packaging-15.2": {
141 "Apache-2.0": "http://spdx.org/licenses/Apache-2.0"
148 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
142 },
149 },
143 "python2.7-psutil-2.2.1": {
150 "python2.7-psutil-2.2.1": {
144 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
151 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
145 },
152 },
146 "python2.7-psycopg2-2.6": {
153 "python2.7-psycopg2-2.6": {
147 "LGPL-3.0+": "http://spdx.org/licenses/LGPL-3.0+"
154 "GNU Lesser General Public License v3.0 or later": "http://spdx.org/licenses/LGPL-3.0+"
148 },
155 },
149 "python2.7-py-1.4.29": {
156 "python2.7-py-1.4.29": {
150 "MIT": "http://spdx.org/licenses/MIT"
157 "MIT License": "http://spdx.org/licenses/MIT"
151 },
158 },
152 "python2.7-py-bcrypt-0.4": {
159 "python2.7-py-bcrypt-0.4": {
153 "BSD-4-Clause": "http://spdx.org/licenses/BSD-4-Clause"
160 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
154 },
161 },
155 "python2.7-pycrypto-2.6.1": {
162 "python2.7-pycrypto-2.6.1": {
156 "publicDomain": null
163 "Public Domain": null
164 },
165 "python2.7-pycurl-7.19.5": {
166 "MIT License": "http://spdx.org/licenses/MIT"
157 },
167 },
158 "python2.7-pyparsing-1.5.7": {
168 "python2.7-pyparsing-1.5.7": {
159 "MIT": "http://spdx.org/licenses/MIT"
169 "MIT License": "http://spdx.org/licenses/MIT"
170 },
171 "python2.7-pyramid-1.6.1": {
172 "Repoze License": "http://www.repoze.org/LICENSE.txt"
173 },
174 "python2.7-pyramid-beaker-0.8": {
175 "Repoze License": "http://www.repoze.org/LICENSE.txt"
176 },
177 "python2.7-pyramid-debugtoolbar-2.4.2": {
178 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause",
179 "Repoze License": "http://www.repoze.org/LICENSE.txt"
180 },
181 "python2.7-pyramid-mako-1.0.2": {
182 "Repoze License": "http://www.repoze.org/LICENSE.txt"
160 },
183 },
161 "python2.7-pysqlite-2.6.3": {
184 "python2.7-pysqlite-2.6.3": {
162 "Libpng": "http://spdx.org/licenses/Libpng",
185 "libpng License": "http://spdx.org/licenses/Libpng",
163 "Zlib": "http://spdx.org/licenses/Zlib"
186 "zlib License": "http://spdx.org/licenses/Zlib"
164 },
187 },
165 "python2.7-pytest-2.8.5": {
188 "python2.7-pytest-2.8.5": {
166 "MIT": "http://spdx.org/licenses/MIT"
189 "MIT License": "http://spdx.org/licenses/MIT"
190 },
191 "python2.7-pytest-runner-2.7.1": {
192 "MIT License": "http://spdx.org/licenses/MIT"
167 },
193 },
168 "python2.7-python-dateutil-1.5": {
194 "python2.7-python-dateutil-1.5": {
169 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
195 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
196 },
197 "python2.7-python-editor-1.0.1": {
198 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
170 },
199 },
171 "python2.7-python-ldap-2.4.19": {
200 "python2.7-python-ldap-2.4.19": {
172 "Python-2.0": "http://spdx.org/licenses/Python-2.0"
201 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
202 },
203 "python2.7-python-memcached-1.57": {
204 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0"
173 },
205 },
174 "python2.7-pytz-2015.4": {
206 "python2.7-pytz-2015.4": {
175 "MIT": "http://spdx.org/licenses/MIT"
207 "MIT License": "http://spdx.org/licenses/MIT"
176 },
208 },
177 "python2.7-recaptcha-client-1.0.6": {
209 "python2.7-recaptcha-client-1.0.6": {
178 "MIT": "http://spdx.org/licenses/MIT"
210 "MIT License": "http://spdx.org/licenses/MIT"
179 },
211 },
180 "python2.7-repoze.lru-0.6": {
212 "python2.7-repoze.lru-0.6": {
181 "repoze": "http://repoze.org/license.html"
213 "Repoze License": "http://www.repoze.org/LICENSE.txt"
182 },
214 },
183 "python2.7-requests-2.5.1": {
215 "python2.7-requests-2.9.1": {
184 "APSL-2.0": "http://spdx.org/licenses/APSL-2.0"
216 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
185 },
217 },
186 "python2.7-serpent-1.11": {
218 "python2.7-serpent-1.12": {
187 "MIT": "http://spdx.org/licenses/MIT"
219 "MIT License": "http://spdx.org/licenses/MIT"
188 },
220 },
189 "python2.7-setproctitle-1.1.8": {
221 "python2.7-setuptools-19.4": {
190 "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause"
222 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0",
223 "Zope Public License 2.0": "http://spdx.org/licenses/ZPL-2.0"
191 },
224 },
192 "python2.7-setuptools-18.0.1": {
225 "python2.7-setuptools-scm-1.11.0": {
193 "PSF": null,
226 "MIT License": "http://spdx.org/licenses/MIT"
194 "ZPL": null
195 },
227 },
196 "python2.7-simplejson-3.7.2": {
228 "python2.7-simplejson-3.7.2": {
197 "MIT": "http://spdx.org/licenses/MIT"
229 "Academic Free License": "http://spdx.org/licenses/AFL-2.1",
230 "MIT License": "http://spdx.org/licenses/MIT"
198 },
231 },
199 "python2.7-six-1.9.0": {
232 "python2.7-six-1.9.0": {
200 "MIT": "http://spdx.org/licenses/MIT"
233 "MIT License": "http://spdx.org/licenses/MIT"
201 },
234 },
202 "python2.7-subprocess32-3.2.6": {
235 "python2.7-translationstring-1.3": {
203 "Python-2.0": "http://spdx.org/licenses/Python-2.0"
236 "Repoze License": "http://www.repoze.org/LICENSE.txt"
204 },
237 },
205 "python2.7-supervisor-3.1.3": {
238 "python2.7-urllib3-1.16": {
206 "repoze": "http://repoze.org/license.html"
239 "MIT License": "http://spdx.org/licenses/MIT"
207 },
240 },
208 "python2.7-trollius-1.0.4": {
241 "python2.7-venusian-1.0": {
209 "APSL-2.0": "http://spdx.org/licenses/APSL-2.0"
242 "Repoze License": "http://www.repoze.org/LICENSE.txt"
210 },
243 },
211 "python2.7-waitress-0.8.9": {
244 "python2.7-waitress-0.8.9": {
212 "ZPL-2.1": "http://spdx.org/licenses/ZPL-2.1"
245 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
213 },
246 },
214 "python2.7-zope.cachedescriptors-4.0.0": {
247 "python2.7-zope.cachedescriptors-4.0.0": {
215 "ZPL-2.1": "http://spdx.org/licenses/ZPL-2.1"
248 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
249 },
250 "python2.7-zope.deprecation-4.1.2": {
251 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
252 },
253 "python2.7-zope.interface-4.1.3": {
254 "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1"
216 }
255 }
217 }
256 } No newline at end of file
@@ -25,13 +25,15 b' import logging'
25
25
26 from paste.registry import RegistryManager
26 from paste.registry import RegistryManager
27 from paste.gzipper import make_gzip_middleware
27 from paste.gzipper import make_gzip_middleware
28 from pylons.middleware import ErrorHandler, StatusCodeRedirect
29 from pylons.wsgiapp import PylonsApp
28 from pylons.wsgiapp import PylonsApp
30 from pyramid.authorization import ACLAuthorizationPolicy
29 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.config import Configurator
30 from pyramid.config import Configurator
32 from pyramid.static import static_view
31 from pyramid.static import static_view
33 from pyramid.settings import asbool, aslist
32 from pyramid.settings import asbool, aslist
34 from pyramid.wsgi import wsgiapp
33 from pyramid.wsgi import wsgiapp
34 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
35 import pyramid.httpexceptions as httpexceptions
36 from pyramid.renderers import render_to_response, render
35 from routes.middleware import RoutesMiddleware
37 from routes.middleware import RoutesMiddleware
36 import routes.util
38 import routes.util
37
39
@@ -87,38 +89,15 b' def make_app(global_conf, full_stack=Tru'
87 app = csrf.OriginChecker(app, expected_origin,
89 app = csrf.OriginChecker(app, expected_origin,
88 skip_urls=[routes.util.url_for('api')])
90 skip_urls=[routes.util.url_for('api')])
89
91
90 # Add RoutesMiddleware. Currently we have two instances in the stack. This
91 # is the lower one to make the StatusCodeRedirect middleware happy.
92 # TODO: johbo: This is not optimal, search for a better solution.
93 app = RoutesMiddleware(app, config['routes.map'])
94
95 # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
96 if asbool(config['pdebug']):
97 from rhodecode.lib.profiler import ProfilingMiddleware
98 app = ProfilingMiddleware(app)
99
100 # Protect from VCS Server error related pages when server is not available
101 vcs_server_enabled = asbool(config.get('vcs.server.enable', 'true'))
102 if not vcs_server_enabled:
103 app = DisableVCSPagesWrapper(app)
104
92
105 if asbool(full_stack):
93 if asbool(full_stack):
106
94
107 # Appenlight monitoring and error handler
95 # Appenlight monitoring and error handler
108 app, appenlight_client = wrap_in_appenlight_if_enabled(app, config)
96 app, appenlight_client = wrap_in_appenlight_if_enabled(app, config)
109
97
110 # Handle Python exceptions
111 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
112
113 # we want our low level middleware to get to the request ASAP. We don't
98 # we want our low level middleware to get to the request ASAP. We don't
114 # need any pylons stack middleware in them
99 # need any pylons stack middleware in them
115 app = VCSMiddleware(app, config, appenlight_client)
100 app = VCSMiddleware(app, config, appenlight_client)
116 # Display error documents for 401, 403, 404 status codes (and
117 # 500 when debug is disabled)
118 if asbool(config['debug']):
119 app = StatusCodeRedirect(app)
120 else:
121 app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
122
101
123 # Establish the Registry for this application
102 # Establish the Registry for this application
124 app = RegistryManager(app)
103 app = RegistryManager(app)
@@ -176,16 +155,69 b' def add_pylons_compat_data(registry, glo'
176 registry._pylons_compat_settings = settings
155 registry._pylons_compat_settings = settings
177
156
178
157
158 def webob_to_pyramid_http_response(webob_response):
159 ResponseClass = httpexceptions.status_map[webob_response.status_int]
160 pyramid_response = ResponseClass(webob_response.status)
161 pyramid_response.status = webob_response.status
162 pyramid_response.headers.update(webob_response.headers)
163 if pyramid_response.headers['content-type'] == 'text/html':
164 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
165 return pyramid_response
166
167
168 def error_handler(exception, request):
169 # TODO: dan: replace the old pylons error controller with this
170 from rhodecode.model.settings import SettingsModel
171 from rhodecode.lib.utils2 import AttributeDict
172
173 try:
174 rc_config = SettingsModel().get_all_settings()
175 except Exception:
176 log.exception('failed to fetch settings')
177 rc_config = {}
178
179 base_response = HTTPInternalServerError()
180 # prefer original exception for the response since it may have headers set
181 if isinstance(exception, HTTPError):
182 base_response = exception
183
184 c = AttributeDict()
185 c.error_message = base_response.status
186 c.error_explanation = base_response.explanation or str(base_response)
187 c.visual = AttributeDict()
188
189 c.visual.rhodecode_support_url = (
190 request.registry.settings.get('rhodecode_support_url') or
191 request.route_url('rhodecode_support')
192 )
193 c.redirect_time = 0
194 c.rhodecode_name = rc_config.get('rhodecode_title', '')
195 if not c.rhodecode_name:
196 c.rhodecode_name = 'Rhodecode'
197
198 response = render_to_response(
199 '/errors/error_document.html', {'c': c}, request=request,
200 response=base_response)
201
202 return response
203
204
179 def includeme(config):
205 def includeme(config):
180 settings = config.registry.settings
206 settings = config.registry.settings
181
207
208 if asbool(settings.get('appenlight', 'false')):
209 config.include('appenlight_client.ext.pyramid_tween')
210
182 # Includes which are required. The application would fail without them.
211 # Includes which are required. The application would fail without them.
183 config.include('pyramid_mako')
212 config.include('pyramid_mako')
184 config.include('pyramid_beaker')
213 config.include('pyramid_beaker')
214 config.include('rhodecode.admin')
185 config.include('rhodecode.authentication')
215 config.include('rhodecode.authentication')
186 config.include('rhodecode.login')
216 config.include('rhodecode.login')
187 config.include('rhodecode.tweens')
217 config.include('rhodecode.tweens')
188 config.include('rhodecode.api')
218 config.include('rhodecode.api')
219 config.add_route(
220 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
189
221
190 # Set the authorization policy.
222 # Set the authorization policy.
191 authz_policy = ACLAuthorizationPolicy()
223 authz_policy = ACLAuthorizationPolicy()
@@ -204,16 +236,52 b' def includeme(config):'
204 for inc in includes:
236 for inc in includes:
205 config.include(inc)
237 config.include(inc)
206
238
239 pylons_app = make_app(
240 config.registry._pylons_compat_global_config,
241 **config.registry._pylons_compat_settings)
242 config.registry._pylons_compat_config = pylons_app.config
243
244 pylons_app_as_view = wsgiapp(pylons_app)
245
246 # Protect from VCS Server error related pages when server is not available
247 vcs_server_enabled = asbool(settings.get('vcs.server.enable', 'true'))
248 if not vcs_server_enabled:
249 pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
250
251
252 def pylons_app_with_error_handler(context, request):
253 """
254 Handle exceptions from rc pylons app:
255
256 - old webob type exceptions get converted to pyramid exceptions
257 - pyramid exceptions are passed to the error handler view
258 """
259 try:
260 response = pylons_app_as_view(context, request)
261 if 400 <= response.status_int <= 599: # webob type error responses
262 return error_handler(
263 webob_to_pyramid_http_response(response), request)
264 except HTTPError as e: # pyramid type exceptions
265 return error_handler(e, request)
266 except Exception:
267 if settings.get('debugtoolbar.enabled', False):
268 raise
269 return error_handler(HTTPInternalServerError(), request)
270 return response
271
207 # This is the glue which allows us to migrate in chunks. By registering the
272 # This is the glue which allows us to migrate in chunks. By registering the
208 # pylons based application as the "Not Found" view in Pyramid, we will
273 # pylons based application as the "Not Found" view in Pyramid, we will
209 # fallback to the old application each time the new one does not yet know
274 # fallback to the old application each time the new one does not yet know
210 # how to handle a request.
275 # how to handle a request.
211 pylons_app = make_app(
276 config.add_notfound_view(pylons_app_with_error_handler)
212 config.registry._pylons_compat_global_config,
277
213 **config.registry._pylons_compat_settings)
278 if settings.get('debugtoolbar.enabled', False):
214 config.registry._pylons_compat_config = pylons_app.config
279 # if toolbar, then only http type exceptions get caught and rendered
215 pylons_app_as_view = wsgiapp(pylons_app)
280 ExcClass = HTTPError
216 config.add_notfound_view(pylons_app_as_view)
281 else:
282 # if no toolbar, then any exception gets caught and rendered
283 ExcClass = Exception
284 config.add_view(error_handler, context=ExcClass)
217
285
218
286
219 def includeme_last(config):
287 def includeme_last(config):
@@ -253,13 +321,16 b' def wrap_app_in_wsgi_middlewares(pyramid'
253 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
321 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
254 pyramid_app = HttpsFixup(pyramid_app, settings)
322 pyramid_app = HttpsFixup(pyramid_app, settings)
255
323
256 # Add RoutesMiddleware. Currently we have two instances in the stack. This
324 # Add RoutesMiddleware to support the pylons compatibility tween during
257 # is the upper one to support the pylons compatibility tween during
258
325
259 # migration to pyramid.
326 # migration to pyramid.
260 pyramid_app = RoutesMiddleware(
327 pyramid_app = RoutesMiddleware(
261 pyramid_app, config.registry._pylons_compat_config['routes.map'])
328 pyramid_app, config.registry._pylons_compat_config['routes.map'])
262
329
330 if asbool(settings.get('appenlight', 'false')):
331 pyramid_app, _ = wrap_in_appenlight_if_enabled(
332 pyramid_app, config.registry._pylons_compat_config)
333
263 # TODO: johbo: Don't really see why we enable the gzip middleware when
334 # TODO: johbo: Don't really see why we enable the gzip middleware when
264 # serving static files, might be something that should have its own setting
335 # serving static files, might be something that should have its own setting
265 # as well?
336 # as well?
@@ -166,10 +166,6 b' def make_map(config):'
166 def check_int(environ, match_dict):
166 def check_int(environ, match_dict):
167 return match_dict.get('id').isdigit()
167 return match_dict.get('id').isdigit()
168
168
169 # The ErrorController route (handles 404/500 error pages); it should
170 # likely stay at the top, ensuring it can always be resolved
171 rmap.connect('/error/{action}', controller='error')
172 rmap.connect('/error/{action}/{id}', controller='error')
173
169
174 #==========================================================================
170 #==========================================================================
175 # CUSTOM ROUTES HERE
171 # CUSTOM ROUTES HERE
@@ -509,10 +505,6 b' def make_map(config):'
509 m.connect('admin_settings_labs', '/settings/labs',
505 m.connect('admin_settings_labs', '/settings/labs',
510 action='settings_labs', conditions={'method': ['GET']})
506 action='settings_labs', conditions={'method': ['GET']})
511
507
512 m.connect('admin_settings_open_source', '/settings/open_source',
513 action='settings_open_source',
514 conditions={'method': ['GET']})
515
516 # ADMIN MY ACCOUNT
508 # ADMIN MY ACCOUNT
517 with rmap.submapper(path_prefix=ADMIN_PREFIX,
509 with rmap.submapper(path_prefix=ADMIN_PREFIX,
518 controller='admin/my_account') as m:
510 controller='admin/my_account') as m:
@@ -68,21 +68,25 b' def configure_vcs(config):'
68
68
69
69
70 def initialize_database(config):
70 def initialize_database(config):
71 from rhodecode.lib.utils2 import engine_from_config
71 from rhodecode.lib.utils2 import engine_from_config, get_encryption_key
72 engine = engine_from_config(config, 'sqlalchemy.db1.')
72 engine = engine_from_config(config, 'sqlalchemy.db1.')
73 init_model(engine, encryption_key=config['beaker.session.secret'])
73 init_model(engine, encryption_key=get_encryption_key(config))
74
74
75
75
76 def initialize_test_environment(settings, test_env=None):
76 def initialize_test_environment(settings, test_env=None):
77 if test_env is None:
77 if test_env is None:
78 test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0))
78 test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0))
79
79
80 from rhodecode.lib.utils import create_test_env, create_test_index
80 from rhodecode.lib.utils import (
81 create_test_directory, create_test_database, create_test_repositories,
82 create_test_index)
81 from rhodecode.tests import TESTS_TMP_PATH
83 from rhodecode.tests import TESTS_TMP_PATH
82 # test repos
84 # test repos
83 if test_env:
85 if test_env:
84 create_test_env(TESTS_TMP_PATH, settings)
86 create_test_directory(TESTS_TMP_PATH)
85 create_test_index(TESTS_TMP_PATH, settings, True)
87 create_test_database(TESTS_TMP_PATH, settings)
88 create_test_repositories(TESTS_TMP_PATH, settings)
89 create_test_index(TESTS_TMP_PATH, settings)
86
90
87
91
88 def get_vcs_server_protocol(config):
92 def get_vcs_server_protocol(config):
@@ -99,7 +99,7 b' class RepoGroupsController(BaseControlle'
99 if repo_group.user:
99 if repo_group.user:
100 data.update({'user': repo_group.user.username})
100 data.update({'user': repo_group.user.username})
101 else:
101 else:
102 replacement_user = User.get_first_admin().username
102 replacement_user = User.get_first_super_admin().username
103 data.update({'user': replacement_user})
103 data.update({'user': replacement_user})
104
104
105 # fill repository group users
105 # fill repository group users
@@ -246,11 +246,10 b' class RepoGroupsController(BaseControlle'
246 repo_group=c.repo_group)
246 repo_group=c.repo_group)
247
247
248 repo_group_form = RepoGroupForm(
248 repo_group_form = RepoGroupForm(
249 edit=True,
249 edit=True, old_data=c.repo_group.get_dict(),
250 old_data=c.repo_group.get_dict(),
251 available_groups=c.repo_groups_choices,
250 available_groups=c.repo_groups_choices,
252 can_create_in_root=can_create_in_root,
251 can_create_in_root=can_create_in_root, allow_disabled=True)()
253 )()
252
254 try:
253 try:
255 form_result = repo_group_form.to_python(dict(request.POST))
254 form_result = repo_group_form.to_python(dict(request.POST))
256 gr_name = form_result['group_name']
255 gr_name = form_result['group_name']
@@ -248,9 +248,9 b' class ReposController(BaseRepoController'
248 task_id = request.GET.get('task_id')
248 task_id = request.GET.get('task_id')
249
249
250 if task_id and task_id not in ['None']:
250 if task_id and task_id not in ['None']:
251 from rhodecode import CELERY_ENABLED
251 import rhodecode
252 from celery.result import AsyncResult
252 from celery.result import AsyncResult
253 if CELERY_ENABLED:
253 if rhodecode.CELERY_ENABLED:
254 task = AsyncResult(task_id)
254 task = AsyncResult(task_id)
255 if task.failed():
255 if task.failed():
256 msg = self._log_creation_exception(task.result, c.repo)
256 msg = self._log_creation_exception(task.result, c.repo)
@@ -307,9 +307,9 b' class ReposController(BaseRepoController'
307 'repo_group': repo.group.get_dict() if repo.group else {},
307 'repo_group': repo.group.get_dict() if repo.group else {},
308 'repo_type': repo.repo_type,
308 'repo_type': repo.repo_type,
309 }
309 }
310 _form = RepoForm(edit=True, old_data=old_data,
310 _form = RepoForm(
311 repo_groups=c.repo_groups_choices,
311 edit=True, old_data=old_data, repo_groups=c.repo_groups_choices,
312 landing_revs=c.landing_revs_choices)()
312 landing_revs=c.landing_revs_choices, allow_disabled=True)()
313
313
314 try:
314 try:
315 form_result = _form.to_python(dict(request.POST))
315 form_result = _form.to_python(dict(request.POST))
@@ -37,6 +37,7 b' from pylons.i18n.translation import _, l'
37 from webob.exc import HTTPBadRequest
37 from webob.exc import HTTPBadRequest
38
38
39 import rhodecode
39 import rhodecode
40 from rhodecode.admin.navigation import navigation_list
40 from rhodecode.lib import auth
41 from rhodecode.lib import auth
41 from rhodecode.lib import helpers as h
42 from rhodecode.lib import helpers as h
42 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
43 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
@@ -47,7 +48,7 b' from rhodecode.lib.utils2 import ('
47 str2bool, safe_unicode, AttributeDict, safe_int)
48 str2bool, safe_unicode, AttributeDict, safe_int)
48 from rhodecode.lib.compat import OrderedDict
49 from rhodecode.lib.compat import OrderedDict
49 from rhodecode.lib.ext_json import json
50 from rhodecode.lib.ext_json import json
50 from rhodecode.lib.utils import jsonify, read_opensource_licenses
51 from rhodecode.lib.utils import jsonify
51
52
52 from rhodecode.model.db import RhodeCodeUi, Repository
53 from rhodecode.model.db import RhodeCodeUi, Repository
53 from rhodecode.model.forms import ApplicationSettingsForm, \
54 from rhodecode.model.forms import ApplicationSettingsForm, \
@@ -60,8 +61,9 b' from rhodecode.model.meta import Session'
60 from rhodecode.model.settings import (
61 from rhodecode.model.settings import (
61 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
62 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
62 SettingsModel)
63 SettingsModel)
64
63 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
65 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
64 from rhodecode.model.user import UserModel
66
65
67
66 log = logging.getLogger(__name__)
68 log = logging.getLogger(__name__)
67
69
@@ -78,7 +80,7 b' class SettingsController(BaseController)'
78 super(SettingsController, self).__before__()
80 super(SettingsController, self).__before__()
79 c.labs_active = str2bool(
81 c.labs_active = str2bool(
80 rhodecode.CONFIG.get('labs_settings_active', 'false'))
82 rhodecode.CONFIG.get('labs_settings_active', 'false'))
81 c.navlist = navigation.get_navlist(request)
83 c.navlist = navigation_list(request)
82
84
83 def _get_hg_ui_settings(self):
85 def _get_hg_ui_settings(self):
84 ret = RhodeCodeUi.query().all()
86 ret = RhodeCodeUi.query().all()
@@ -257,8 +259,8 b' class SettingsController(BaseController)'
257 Session().add(sett)
259 Session().add(sett)
258
260
259 Session().commit()
261 Session().commit()
262 SettingsModel().invalidate_settings_cache()
260 h.flash(_('Updated application settings'), category='success')
263 h.flash(_('Updated application settings'), category='success')
261
262 except Exception:
264 except Exception:
263 log.exception("Exception while updating application settings")
265 log.exception("Exception while updating application settings")
264 h.flash(
266 h.flash(
@@ -321,7 +323,7 b' class SettingsController(BaseController)'
321 Session().add(sett)
323 Session().add(sett)
322
324
323 Session().commit()
325 Session().commit()
324
326 SettingsModel().invalidate_settings_cache()
325 h.flash(_('Updated visualisation settings'), category='success')
327 h.flash(_('Updated visualisation settings'), category='success')
326 except Exception:
328 except Exception:
327 log.exception("Exception updating visualization settings")
329 log.exception("Exception updating visualization settings")
@@ -403,6 +405,7 b' class SettingsController(BaseController)'
403
405
404 Session().commit()
406 Session().commit()
405
407
408 SettingsModel().invalidate_settings_cache()
406 h.flash(_('Updated issue tracker entries'), category='success')
409 h.flash(_('Updated issue tracker entries'), category='success')
407 return redirect(url('admin_settings_issuetracker'))
410 return redirect(url('admin_settings_issuetracker'))
408
411
@@ -523,6 +526,7 b' class SettingsController(BaseController)'
523 def settings_system(self):
526 def settings_system(self):
524 """GET /admin/settings/system: All items in the collection"""
527 """GET /admin/settings/system: All items in the collection"""
525 # url('admin_settings_system')
528 # url('admin_settings_system')
529 snapshot = str2bool(request.GET.get('snapshot'))
526 c.active = 'system'
530 c.active = 'system'
527
531
528 defaults = self._form_defaults()
532 defaults = self._form_defaults()
@@ -557,6 +561,35 b' class SettingsController(BaseController)'
557 except TypeError:
561 except TypeError:
558 c.system_memory = 'NOT AVAILABLE'
562 c.system_memory = 'NOT AVAILABLE'
559
563
564 rhodecode_ini_safe = rhodecode.CONFIG.copy()
565 blacklist = [
566 'rhodecode_license_key',
567 'routes.map',
568 'pylons.h',
569 'pylons.app_globals',
570 'pylons.environ_config',
571 'sqlalchemy.db1.url',
572 ('app_conf', 'sqlalchemy.db1.url')
573 ]
574 for k in blacklist:
575 if isinstance(k, tuple):
576 section, key = k
577 if section in rhodecode_ini_safe:
578 rhodecode_ini_safe[section].pop(key, None)
579 else:
580 rhodecode_ini_safe.pop(k, None)
581
582 c.rhodecode_ini_safe = rhodecode_ini_safe
583
584 # TODO: marcink, figure out how to allow only selected users to do this
585 c.allowed_to_snapshot = False
586
587 if snapshot:
588 if c.allowed_to_snapshot:
589 return render('admin/settings/settings_system_snapshot.html')
590 else:
591 h.flash('You are not allowed to do this', category='warning')
592
560 return htmlfill.render(
593 return htmlfill.render(
561 render('admin/settings/settings.html'),
594 render('admin/settings/settings.html'),
562 defaults=defaults,
595 defaults=defaults,
@@ -708,6 +741,7 b' class SettingsController(BaseController)'
708 category='error')
741 category='error')
709 else:
742 else:
710 Session().commit()
743 Session().commit()
744 SettingsModel().invalidate_settings_cache()
711 h.flash(_('Updated Labs settings'), category='success')
745 h.flash(_('Updated Labs settings'), category='success')
712 return redirect(url('admin_settings_labs'))
746 return redirect(url('admin_settings_labs'))
713
747
@@ -733,20 +767,6 b' class SettingsController(BaseController)'
733 encoding='UTF-8',
767 encoding='UTF-8',
734 force_defaults=False)
768 force_defaults=False)
735
769
736 @HasPermissionAllDecorator('hg.admin')
737 def settings_open_source(self):
738 # url('admin_settings_open_source')
739
740 c.active = 'open_source'
741 c.opensource_licenses = collections.OrderedDict(
742 sorted(read_opensource_licenses().items(), key=lambda t: t[0]))
743
744 return htmlfill.render(
745 render('admin/settings/settings.html'),
746 defaults=self._form_defaults(),
747 encoding='UTF-8',
748 force_defaults=False)
749
750 def _form_defaults(self):
770 def _form_defaults(self):
751 defaults = SettingsModel().get_all_settings()
771 defaults = SettingsModel().get_all_settings()
752 defaults.update(self._get_hg_ui_settings())
772 defaults.update(self._get_hg_ui_settings())
@@ -791,76 +811,3 b' LabSetting = collections.namedtuple('
791 help=lazy_ugettext('e.g. http://localhost:8080/')
811 help=lazy_ugettext('e.g. http://localhost:8080/')
792 ),
812 ),
793 ]
813 ]
794
795
796 NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url'])
797
798
799 class NavEntry(object):
800
801 def __init__(self, key, name, view_name, pyramid=False):
802 self.key = key
803 self.name = name
804 self.view_name = view_name
805 self.pyramid = pyramid
806
807 def generate_url(self, request):
808 if self.pyramid:
809 if hasattr(request, 'route_path'):
810 return request.route_path(self.view_name)
811 else:
812 # TODO: johbo: Remove this after migrating to pyramid.
813 # We need the pyramid request here to generate URLs to pyramid
814 # views from within pylons views.
815 from pyramid.threadlocal import get_current_request
816 pyramid_request = get_current_request()
817 return pyramid_request.route_path(self.view_name)
818 else:
819 return url(self.view_name)
820
821
822 class NavigationRegistry(object):
823
824 _base_entries = [
825 NavEntry('global', lazy_ugettext('Global'), 'admin_settings_global'),
826 NavEntry('vcs', lazy_ugettext('VCS'), 'admin_settings_vcs'),
827 NavEntry('visual', lazy_ugettext('Visual'), 'admin_settings_visual'),
828 NavEntry('mapping', lazy_ugettext('Remap and Rescan'),
829 'admin_settings_mapping'),
830 NavEntry('issuetracker', lazy_ugettext('Issue Tracker'),
831 'admin_settings_issuetracker'),
832 NavEntry('email', lazy_ugettext('Email'), 'admin_settings_email'),
833 NavEntry('hooks', lazy_ugettext('Hooks'), 'admin_settings_hooks'),
834 NavEntry('search', lazy_ugettext('Full Text Search'),
835 'admin_settings_search'),
836 NavEntry('system', lazy_ugettext('System Info'),
837 'admin_settings_system'),
838 NavEntry('open_source', lazy_ugettext('Open Source Licenses'),
839 'admin_settings_open_source'),
840 # TODO: marcink: we disable supervisor now until the supervisor stats
841 # page is fixed in the nix configuration
842 # NavEntry('supervisor', lazy_ugettext('Supervisor'),
843 # 'admin_settings_supervisor'),
844 ]
845
846 def __init__(self):
847 self._registered_entries = collections.OrderedDict([
848 (item.key, item) for item in self.__class__._base_entries
849 ])
850
851 # Add the labs entry when it's activated.
852 labs_active = str2bool(
853 rhodecode.CONFIG.get('labs_settings_active', 'false'))
854 if labs_active:
855 self.add_entry(
856 NavEntry('labs', lazy_ugettext('Labs'), 'admin_settings_labs'))
857
858 def add_entry(self, entry):
859 self._registered_entries[entry.key] = entry
860
861 def get_navlist(self, request):
862 navlist = [NavListEntry(i.key, i.name, i.generate_url(request))
863 for i in self._registered_entries.values()]
864 return navlist
865
866 navigation = NavigationRegistry()
@@ -88,7 +88,7 b' class UserGroupsController(BaseControlle'
88 if user_group.user:
88 if user_group.user:
89 data.update({'user': user_group.user.username})
89 data.update({'user': user_group.user.username})
90 else:
90 else:
91 replacement_user = User.get_first_admin().username
91 replacement_user = User.get_first_super_admin().username
92 data.update({'user': replacement_user})
92 data.update({'user': replacement_user})
93 return data
93 return data
94
94
@@ -209,9 +209,9 b' class UserGroupsController(BaseControlle'
209
209
210 available_members = [safe_unicode(x[0]) for x in c.available_members]
210 available_members = [safe_unicode(x[0]) for x in c.available_members]
211
211
212 users_group_form = UserGroupForm(edit=True,
212 users_group_form = UserGroupForm(
213 old_data=c.user_group.get_dict(),
213 edit=True, old_data=c.user_group.get_dict(),
214 available_members=available_members)()
214 available_members=available_members, allow_disabled=True)()
215
215
216 try:
216 try:
217 form_result = users_group_form.to_python(request.POST)
217 form_result = users_group_form.to_python(request.POST)
@@ -216,6 +216,8 b' class UsersController(BaseController):'
216 prefix_error=False,
216 prefix_error=False,
217 encoding="UTF-8",
217 encoding="UTF-8",
218 force_defaults=False)
218 force_defaults=False)
219 except UserCreationError as e:
220 h.flash(e, 'error')
219 except Exception:
221 except Exception:
220 log.exception("Exception updating user")
222 log.exception("Exception updating user")
221 h.flash(_('Error occurred during update of user %s')
223 h.flash(_('Error occurred during update of user %s')
@@ -401,7 +403,7 b' class UsersController(BaseController):'
401 c.active = 'advanced'
403 c.active = 'advanced'
402 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
404 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
403 c.personal_repo_group = RepoGroup.get_by_group_name(user.username)
405 c.personal_repo_group = RepoGroup.get_by_group_name(user.username)
404 c.first_admin = User.get_first_admin()
406 c.first_admin = User.get_first_super_admin()
405 defaults = user.get_dict()
407 defaults = user.get_dict()
406
408
407 # Interim workaround if the user participated on any pull requests as a
409 # Interim workaround if the user participated on any pull requests as a
@@ -37,7 +37,7 b' from rhodecode.lib.base import BaseContr'
37 from rhodecode.lib.index import searcher_from_config
37 from rhodecode.lib.index import searcher_from_config
38 from rhodecode.lib.ext_json import json
38 from rhodecode.lib.ext_json import json
39 from rhodecode.lib.utils import jsonify
39 from rhodecode.lib.utils import jsonify
40 from rhodecode.lib.utils2 import safe_unicode
40 from rhodecode.lib.utils2 import safe_unicode, str2bool
41 from rhodecode.model.db import Repository, RepoGroup
41 from rhodecode.model.db import Repository, RepoGroup
42 from rhodecode.model.repo import RepoModel
42 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.repo_group import RepoGroupModel
43 from rhodecode.model.repo_group import RepoGroupModel
@@ -259,13 +259,16 b' class HomeController(BaseController):'
259 @jsonify
259 @jsonify
260 def user_autocomplete_data(self):
260 def user_autocomplete_data(self):
261 query = request.GET.get('query')
261 query = request.GET.get('query')
262 active = str2bool(request.GET.get('active') or True)
262
263
263 repo_model = RepoModel()
264 repo_model = RepoModel()
264 _users = repo_model.get_users(name_contains=query)
265 _users = repo_model.get_users(
266 name_contains=query, only_active=active)
265
267
266 if request.GET.get('user_groups'):
268 if request.GET.get('user_groups'):
267 # extend with user groups
269 # extend with user groups
268 _user_groups = repo_model.get_user_groups(name_contains=query)
270 _user_groups = repo_model.get_user_groups(
271 name_contains=query, only_active=active)
269 _users = _users + _user_groups
272 _users = _users + _user_groups
270
273
271 return {'suggestions': _users}
274 return {'suggestions': _users}
@@ -274,4 +277,13 b' class HomeController(BaseController):'
274 @XHRRequired()
277 @XHRRequired()
275 @jsonify
278 @jsonify
276 def user_group_autocomplete_data(self):
279 def user_group_autocomplete_data(self):
277 return {'suggestions': []}
280 query = request.GET.get('query')
281 active = str2bool(request.GET.get('active') or True)
282
283 repo_model = RepoModel()
284 _user_groups = repo_model.get_user_groups(
285 name_contains=query, only_active=active)
286 _user_groups = _user_groups
287
288 return {'suggestions': _user_groups}
289
@@ -17,7 +17,8 b''
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 from zope.interface import implementer
19 from zope.interface import implementer
20 from rhodecode.interfaces import IUserRegistered
20 from rhodecode.interfaces import (
21 IUserRegistered, IUserPreCreate, IUserPreUpdate)
21
22
22
23
23 @implementer(IUserRegistered)
24 @implementer(IUserRegistered)
@@ -29,3 +30,24 b' class UserRegistered(object):'
29 def __init__(self, user, session):
30 def __init__(self, user, session):
30 self.user = user
31 self.user = user
31 self.session = session
32 self.session = session
33
34
35 @implementer(IUserPreCreate)
36 class UserPreCreate(object):
37 """
38 An instance of this class is emitted as an :term:`event` before a new user
39 object is created.
40 """
41 def __init__(self, user_data):
42 self.user_data = user_data
43
44
45 @implementer(IUserPreUpdate)
46 class UserPreUpdate(object):
47 """
48 An instance of this class is emitted as an :term:`event` before a user
49 object is updated.
50 """
51 def __init__(self, user, user_data):
52 self.user = user
53 self.user_data = user_data
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -26,3 +26,18 b' class IUserRegistered(Interface):'
26 """
26 """
27 user = Attribute('The user object.')
27 user = Attribute('The user object.')
28 session = Attribute('The session while processing the register form post.')
28 session = Attribute('The session while processing the register form post.')
29
30
31 class IUserPreCreate(Interface):
32 """
33 An event type that is emitted before a new user object is created.
34 """
35 user_data = Attribute('Data used to create the new user')
36
37
38 class IUserPreUpdate(Interface):
39 """
40 An event type that is emitted before a user object is updated.
41 """
42 user = Attribute('The not yet updated user object')
43 user_data = Attribute('Data used to update the user')
@@ -255,7 +255,7 b' class BasicAuth(AuthBasicAuthenticator):'
255
255
256
256
257 def attach_context_attributes(context):
257 def attach_context_attributes(context):
258 rc_config = SettingsModel().get_all_settings()
258 rc_config = SettingsModel().get_all_settings(cache=True)
259
259
260 context.rhodecode_version = rhodecode.__version__
260 context.rhodecode_version = rhodecode.__version__
261 context.rhodecode_edition = config.get('rhodecode.edition')
261 context.rhodecode_edition = config.get('rhodecode.edition')
@@ -425,7 +425,7 b' class BaseController(WSGIController):'
425 _route_name = '.'.join([environ['pylons.routes_dict']['controller'],
425 _route_name = '.'.join([environ['pylons.routes_dict']['controller'],
426 environ['pylons.routes_dict']['action']])
426 environ['pylons.routes_dict']['action']])
427
427
428 self.rc_config = SettingsModel().get_all_settings()
428 self.rc_config = SettingsModel().get_all_settings(cache=True)
429 self.ip_addr = get_ip_addr(environ)
429 self.ip_addr = get_ip_addr(environ)
430
430
431 # The rhodecode auth user is looked up and passed through the
431 # The rhodecode auth user is looked up and passed through the
@@ -87,6 +87,12 b' def get_cache_manager(region_name, cache'
87
87
88
88
89 def clear_cache_manager(cache_manager):
89 def clear_cache_manager(cache_manager):
90 """
91 namespace = 'foobar'
92 cache_manager = get_cache_manager('repo_cache_long', namespace)
93 clear_cache_manager(cache_manager)
94 """
95
90 log.debug('Clearing all values for cache manager %s', cache_manager)
96 log.debug('Clearing all values for cache manager %s', cache_manager)
91 cache_manager.clear()
97 cache_manager.clear()
92
98
@@ -161,7 +167,7 b' class FreshRegionCache(ActiveRegionCache'
161 class InvalidationContext(object):
167 class InvalidationContext(object):
162 def __repr__(self):
168 def __repr__(self):
163 return '<InvalidationContext:{}[{}]>'.format(
169 return '<InvalidationContext:{}[{}]>'.format(
164 self.repo_name, self.cache_type)
170 safe_str(self.repo_name), safe_str(self.cache_type))
165
171
166 def __init__(self, compute_func, repo_name, cache_type,
172 def __init__(self, compute_func, repo_name, cache_type,
167 raise_exception=False):
173 raise_exception=False):
@@ -34,7 +34,6 b' from decorator import decorator'
34
34
35 from zope.cachedescriptors.property import Lazy as LazyProperty
35 from zope.cachedescriptors.property import Lazy as LazyProperty
36
36
37 from rhodecode import CELERY_ENABLED, CELERY_EAGER
38 from rhodecode.config import utils
37 from rhodecode.config import utils
39 from rhodecode.lib.utils2 import safe_str, md5_safe, aslist
38 from rhodecode.lib.utils2 import safe_str, md5_safe, aslist
40 from rhodecode.lib.pidlock import DaemonLock, LockHeld
39 from rhodecode.lib.pidlock import DaemonLock, LockHeld
@@ -54,8 +53,7 b' class ResultWrapper(object):'
54
53
55
54
56 def run_task(task, *args, **kwargs):
55 def run_task(task, *args, **kwargs):
57 global CELERY_ENABLED
56 if rhodecode.CELERY_ENABLED:
58 if CELERY_ENABLED:
59 try:
57 try:
60 t = task.apply_async(args=args, kwargs=kwargs)
58 t = task.apply_async(args=args, kwargs=kwargs)
61 log.info('running task %s:%s', t.task_id, task)
59 log.info('running task %s:%s', t.task_id, task)
@@ -63,18 +61,18 b' def run_task(task, *args, **kwargs):'
63
61
64 except socket.error as e:
62 except socket.error as e:
65 if isinstance(e, IOError) and e.errno == 111:
63 if isinstance(e, IOError) and e.errno == 111:
66 log.debug('Unable to connect to celeryd. Sync execution')
64 log.error('Unable to connect to celeryd. Sync execution')
67 CELERY_ENABLED = False
65 rhodecode.CELERY_ENABLED = False
68 else:
66 else:
69 log.exception("Exception while connecting to celeryd.")
67 log.exception("Exception while connecting to celeryd.")
70 except KeyError as e:
68 except KeyError as e:
71 log.debug('Unable to connect to celeryd. Sync execution')
69 log.error('Unable to connect to celeryd. Sync execution')
72 except Exception as e:
70 except Exception as e:
73 log.exception(
71 log.exception(
74 "Exception while trying to run task asynchronous. "
72 "Exception while trying to run task asynchronous. "
75 "Fallback to sync execution.")
73 "Fallback to sync execution.")
76
74 else:
77 log.debug('executing task %s in sync mode', task)
75 log.debug('executing task %s in sync mode', task)
78 return ResultWrapper(task(*args, **kwargs))
76 return ResultWrapper(task(*args, **kwargs))
79
77
80
78
@@ -106,7 +104,7 b' def locked_task(func):'
106
104
107
105
108 def get_session():
106 def get_session():
109 if CELERY_ENABLED:
107 if rhodecode.CELERY_ENABLED:
110 utils.initialize_database(config)
108 utils.initialize_database(config)
111 sa = meta.Session()
109 sa = meta.Session()
112 return sa
110 return sa
@@ -118,7 +116,7 b' def dbsession(func):'
118 ret = func(*fargs, **fkwargs)
116 ret = func(*fargs, **fkwargs)
119 return ret
117 return ret
120 finally:
118 finally:
121 if CELERY_ENABLED and not CELERY_EAGER:
119 if rhodecode.CELERY_ENABLED and not rhodecode.CELERY_EAGER:
122 meta.Session.remove()
120 meta.Session.remove()
123
121
124 return decorator(__wrapper, func)
122 return decorator(__wrapper, func)
@@ -126,7 +124,7 b' def dbsession(func):'
126
124
127 def vcsconnection(func):
125 def vcsconnection(func):
128 def __wrapper(func, *fargs, **fkwargs):
126 def __wrapper(func, *fargs, **fkwargs):
129 if CELERY_ENABLED and not CELERY_EAGER:
127 if rhodecode.CELERY_ENABLED and not rhodecode.CELERY_EAGER:
130 backends = config['vcs.backends'] = aslist(
128 backends = config['vcs.backends'] = aslist(
131 config.get('vcs.backends', 'hg,git'), sep=',')
129 config.get('vcs.backends', 'hg,git'), sep=',')
132 for alias in rhodecode.BACKENDS.keys():
130 for alias in rhodecode.BACKENDS.keys():
@@ -30,7 +30,7 b' import logging'
30 from celery.task import task
30 from celery.task import task
31 from pylons import config
31 from pylons import config
32
32
33 from rhodecode import CELERY_ENABLED
33 import rhodecode
34 from rhodecode.lib.celerylib import (
34 from rhodecode.lib.celerylib import (
35 run_task, dbsession, __get_lockkey, LockHeld, DaemonLock,
35 run_task, dbsession, __get_lockkey, LockHeld, DaemonLock,
36 get_session, vcsconnection)
36 get_session, vcsconnection)
@@ -45,7 +45,7 b' add_cache(config) # pragma: no cover'
45
45
46
46
47 def get_logger(cls):
47 def get_logger(cls):
48 if CELERY_ENABLED:
48 if rhodecode.CELERY_ENABLED:
49 try:
49 try:
50 log = cls.get_logger()
50 log = cls.get_logger()
51 except Exception:
51 except Exception:
@@ -478,9 +478,9 b' class DbManage(object):'
478 elif not os.access(path, os.W_OK) and path_ok:
478 elif not os.access(path, os.W_OK) and path_ok:
479 log.warning('No write permission to given path %s' % (path,))
479 log.warning('No write permission to given path %s' % (path,))
480
480
481 q = ('Given path %s is not writeable, do you want to '
481 q = ('Given path %s is not writeable, do you want to '
482 'continue with read only mode ? [y/n]' % (path,))
482 'continue with read only mode ? [y/n]' % (path,))
483 if not self.ask_ok(q):
483 if not self.ask_ok(q):
484 log.error('Canceled by user')
484 log.error('Canceled by user')
485 sys.exit(-1)
485 sys.exit(-1)
486
486
@@ -23,31 +23,84 b''
23 Generic encryption library for RhodeCode
23 Generic encryption library for RhodeCode
24 """
24 """
25
25
26 import hashlib
27 import base64
26 import base64
28
27
29 from Crypto.Cipher import AES
28 from Crypto.Cipher import AES
30 from Crypto import Random
29 from Crypto import Random
30 from Crypto.Hash import HMAC, SHA256
31
31
32 from rhodecode.lib.utils2 import safe_str
32 from rhodecode.lib.utils2 import safe_str
33
33
34
34
35 class SignatureVerificationError(Exception):
36 pass
37
38
39 class InvalidDecryptedValue(str):
40
41 def __new__(cls, content):
42 """
43 This will generate something like this::
44 <InvalidDecryptedValue(QkWusFgLJXR6m42v...)>
45 And represent a safe indicator that encryption key is broken
46 """
47 content = '<{}({}...)>'.format(cls.__name__, content[:16])
48 return str.__new__(cls, content)
49
50
35 class AESCipher(object):
51 class AESCipher(object):
36 def __init__(self, key):
52 def __init__(self, key, hmac=False, strict_verification=True):
37 # create padding, trim to long enc key
38 if not key:
53 if not key:
39 raise ValueError('passed key variable is empty')
54 raise ValueError('passed key variable is empty')
55 self.strict_verification = strict_verification
40 self.block_size = 32
56 self.block_size = 32
41 self.key = hashlib.sha256(safe_str(key)).digest()
57 self.hmac_size = 32
58 self.hmac = hmac
59
60 self.key = SHA256.new(safe_str(key)).digest()
61 self.hmac_key = SHA256.new(self.key).digest()
62
63 def verify_hmac_signature(self, raw_data):
64 org_hmac_signature = raw_data[-self.hmac_size:]
65 data_without_sig = raw_data[:-self.hmac_size]
66 recomputed_hmac = HMAC.new(
67 self.hmac_key, data_without_sig, digestmod=SHA256).digest()
68 return org_hmac_signature == recomputed_hmac
42
69
43 def encrypt(self, raw):
70 def encrypt(self, raw):
44 raw = self._pad(raw)
71 raw = self._pad(raw)
45 iv = Random.new().read(AES.block_size)
72 iv = Random.new().read(AES.block_size)
46 cipher = AES.new(self.key, AES.MODE_CBC, iv)
73 cipher = AES.new(self.key, AES.MODE_CBC, iv)
47 return base64.b64encode(iv + cipher.encrypt(raw))
74 enc_value = cipher.encrypt(raw)
75
76 hmac_signature = ''
77 if self.hmac:
78 # compute hmac+sha256 on iv + enc text, we use
79 # encrypt then mac method to create the signature
80 hmac_signature = HMAC.new(
81 self.hmac_key, iv + enc_value, digestmod=SHA256).digest()
82
83 return base64.b64encode(iv + enc_value + hmac_signature)
48
84
49 def decrypt(self, enc):
85 def decrypt(self, enc):
86 enc_org = enc
50 enc = base64.b64decode(enc)
87 enc = base64.b64decode(enc)
88
89 if self.hmac and len(enc) > self.hmac_size:
90 if self.verify_hmac_signature(enc):
91 # cut off the HMAC verification digest
92 enc = enc[:-self.hmac_size]
93 else:
94 if self.strict_verification:
95 raise SignatureVerificationError(
96 "Encryption signature verification failed. "
97 "Please check your secret key, and/or encrypted value. "
98 "Secret key is stored as "
99 "`rhodecode.encrypted_values.secret` or "
100 "`beaker.session.secret` inside .ini file")
101
102 return InvalidDecryptedValue(enc_org)
103
51 iv = enc[:AES.block_size]
104 iv = enc[:AES.block_size]
52 cipher = AES.new(self.key, AES.MODE_CBC, iv)
105 cipher = AES.new(self.key, AES.MODE_CBC, iv)
53 return self._unpad(cipher.decrypt(enc[AES.block_size:]))
106 return self._unpad(cipher.decrypt(enc[AES.block_size:]))
@@ -438,15 +438,17 b' def get_matching_line_offsets(lines, ter'
438 :param max_lines: cut off for lines of interest
438 :param max_lines: cut off for lines of interest
439 eg.
439 eg.
440
440
441 >>> get_matching_line_offsets('''
441 text = '''
442 words words words
442 words words words
443 words words words
443 words words words
444 some text some
444 some text some
445 words words words
445 words words words
446 words words words
446 words words words
447 text here what
447 text here what
448 ''', 'text', context=1)
448 '''
449 get_matching_line_offsets(text, 'text', context=1)
449 {3: [(5, 9)], 6: [(0, 4)]]
450 {3: [(5, 9)], 6: [(0, 4)]]
451
450 """
452 """
451 matching_lines = {}
453 matching_lines = {}
452 phrases = [normalize_text_for_matching(phrase)
454 phrases = [normalize_text_for_matching(phrase)
@@ -460,6 +462,7 b' text here what'
460
462
461 return matching_lines
463 return matching_lines
462
464
465
463 def get_lexer_safe(mimetype=None, filepath=None):
466 def get_lexer_safe(mimetype=None, filepath=None):
464 """
467 """
465 Tries to return a relevant pygments lexer using mimetype/filepath name,
468 Tries to return a relevant pygments lexer using mimetype/filepath name,
@@ -470,7 +473,7 b' def get_lexer_safe(mimetype=None, filepa'
470 if mimetype:
473 if mimetype:
471 lexer = get_lexer_for_mimetype(mimetype)
474 lexer = get_lexer_for_mimetype(mimetype)
472 if not lexer:
475 if not lexer:
473 lexer = get_lexer_for_filename(path)
476 lexer = get_lexer_for_filename(filepath)
474 except pygments.util.ClassNotFound:
477 except pygments.util.ClassNotFound:
475 pass
478 pass
476
479
@@ -675,11 +678,6 b' def _shorten_commit_id(commit_id):'
675 return commit_id[:def_len]
678 return commit_id[:def_len]
676
679
677
680
678 def get_repo_id_from_name(repo_name):
679 repo = get_by_repo_name(repo_name)
680 return repo.repo_id
681
682
683 def show_id(commit):
681 def show_id(commit):
684 """
682 """
685 Configurable function that shows ID
683 Configurable function that shows ID
@@ -744,6 +742,32 b' def is_svn_without_proxy(repository):'
744 return False
742 return False
745
743
746
744
745 def discover_user(author):
746 """
747 Tries to discover RhodeCode User based on the autho string. Author string
748 is typically `FirstName LastName <email@address.com>`
749 """
750
751 # if author is already an instance use it for extraction
752 if isinstance(author, User):
753 return author
754
755 # Valid email in the attribute passed, see if they're in the system
756 _email = author_email(author)
757 if _email != '':
758 user = User.get_by_email(_email, case_insensitive=True, cache=True)
759 if user is not None:
760 return user
761
762 # Maybe it's a username, we try to extract it and fetch by username ?
763 _author = author_name(author)
764 user = User.get_by_username(_author, case_insensitive=True, cache=True)
765 if user is not None:
766 return user
767
768 return None
769
770
747 def email_or_none(author):
771 def email_or_none(author):
748 # extract email from the commit string
772 # extract email from the commit string
749 _email = author_email(author)
773 _email = author_email(author)
@@ -765,30 +789,13 b' def email_or_none(author):'
765 return None
789 return None
766
790
767
791
768 def discover_user(author):
769 # if author is already an instance use it for extraction
770 if isinstance(author, User):
771 return author
772
773 # Valid email in the attribute passed, see if they're in the system
774 _email = email(author)
775 if _email != '':
776 user = User.get_by_email(_email, case_insensitive=True, cache=True)
777 if user is not None:
778 return user
779
780 # Maybe it's a username?
781 _author = author_name(author)
782 user = User.get_by_username(_author, case_insensitive=True,
783 cache=True)
784 if user is not None:
785 return user
786
787 return None
788
789
790 def link_to_user(author, length=0, **kwargs):
792 def link_to_user(author, length=0, **kwargs):
791 user = discover_user(author)
793 user = discover_user(author)
794 # user can be None, but if we have it already it means we can re-use it
795 # in the person() function, so we save 1 intensive-query
796 if user:
797 author = user
798
792 display_person = person(author, 'username_or_name_or_email')
799 display_person = person(author, 'username_or_name_or_email')
793 if length:
800 if length:
794 display_person = shorter(display_person, length)
801 display_person = shorter(display_person, length)
@@ -803,11 +810,9 b' def link_to_user(author, length=0, **kwa'
803
810
804
811
805 def person(author, show_attr="username_and_name"):
812 def person(author, show_attr="username_and_name"):
806 # attr to return from fetched user
807 person_getter = lambda usr: getattr(usr, show_attr)
808 user = discover_user(author)
813 user = discover_user(author)
809 if user:
814 if user:
810 return person_getter(user)
815 return getattr(user, show_attr)
811 else:
816 else:
812 _author = author_name(author)
817 _author = author_name(author)
813 _email = email(author)
818 _email = email(author)
@@ -827,10 +832,10 b' def person_by_id(id_, show_attr="usernam'
827 return id_
832 return id_
828
833
829
834
830 def gravatar_with_user(author):
835 def gravatar_with_user(author, show_disabled=False):
831 from rhodecode.lib.utils import PartialRenderer
836 from rhodecode.lib.utils import PartialRenderer
832 _render = PartialRenderer('base/base.html')
837 _render = PartialRenderer('base/base.html')
833 return _render('gravatar_with_user', author)
838 return _render('gravatar_with_user', author, show_disabled=show_disabled)
834
839
835
840
836 def desc_stylize(value):
841 def desc_stylize(value):
@@ -851,7 +856,7 b' def desc_stylize(value):'
851 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
856 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
852 '<div class="metatag" tag="lang">\\2</div>', value)
857 '<div class="metatag" tag="lang">\\2</div>', value)
853 value = re.sub(r'\[([a-z]+)\]',
858 value = re.sub(r'\[([a-z]+)\]',
854 '<div class="metatag" tag="\\1">\\1</div>', value)
859 '<div class="metatag" tag="\\1">\\1</div>', value)
855
860
856 return value
861 return value
857
862
@@ -876,7 +881,7 b' def escaped_stylize(value):'
876 value = re.sub(r'\[(lang|language)\ \=\&gt;\ *([a-zA-Z\-\/\#\+]*)\]',
881 value = re.sub(r'\[(lang|language)\ \=\&gt;\ *([a-zA-Z\-\/\#\+]*)\]',
877 '<div class="metatag" tag="lang">\\2</div>', value)
882 '<div class="metatag" tag="lang">\\2</div>', value)
878 value = re.sub(r'\[([a-z]+)\]',
883 value = re.sub(r'\[([a-z]+)\]',
879 '<div class="metatag" tag="\\1">\\1</div>', value)
884 '<div class="metatag" tag="\\1">\\1</div>', value)
880
885
881 return value
886 return value
882
887
@@ -1647,10 +1652,10 b' def process_patterns(text_string, repo_n'
1647 if repo_name:
1652 if repo_name:
1648 # Retrieving repo_name to avoid invalid repo_name to explode on
1653 # Retrieving repo_name to avoid invalid repo_name to explode on
1649 # IssueTrackerSettingsModel but still passing invalid name further down
1654 # IssueTrackerSettingsModel but still passing invalid name further down
1650 repo = Repository.get_by_repo_name(repo_name)
1655 repo = Repository.get_by_repo_name(repo_name, cache=True)
1651
1656
1652 settings_model = IssueTrackerSettingsModel(repo=repo)
1657 settings_model = IssueTrackerSettingsModel(repo=repo)
1653 active_entries = settings_model.get_settings()
1658 active_entries = settings_model.get_settings(cache=True)
1654
1659
1655 newtext = text_string
1660 newtext = text_string
1656 for uid, entry in active_entries.items():
1661 for uid, entry in active_entries.items():
@@ -24,15 +24,21 b' Disable VCS pages when VCS Server is not'
24
24
25 import logging
25 import logging
26 import re
26 import re
27
27 from pyramid.httpexceptions import HTTPBadGateway
28
28
29 log = logging.getLogger(__name__)
29 log = logging.getLogger(__name__)
30
30
31
31
32 class VCSServerUnavailable(HTTPBadGateway):
33 """ HTTP Exception class for when VCS Server is unavailable """
34 code = 502
35 title = 'VCS Server Required'
36 explanation = 'A VCS Server is required for this action. There is currently no VCS Server configured.'
37
32 class DisableVCSPagesWrapper(object):
38 class DisableVCSPagesWrapper(object):
33 """
39 """
34 Wrapper to disable all pages that require VCS Server to be running,
40 Pyramid view wrapper to disable all pages that require VCS Server to be
35 avoiding that errors explode to the user.
41 running, avoiding that errors explode to the user.
36
42
37 This Wrapper should be enabled only in case VCS Server is not available
43 This Wrapper should be enabled only in case VCS Server is not available
38 for the instance.
44 for the instance.
@@ -60,11 +66,11 b' class DisableVCSPagesWrapper(object):'
60 log.debug('accessing: `%s` with VCS Server disabled', path_info)
66 log.debug('accessing: `%s` with VCS Server disabled', path_info)
61 return False
67 return False
62
68
63 def __init__(self, app):
69 def __init__(self, handler):
64 self.application = app
70 self.handler = handler
65
71
66 def __call__(self, environ, start_response):
72 def __call__(self, context, request):
67 if not self._check_vcs_requirement(environ['PATH_INFO']):
73 if not self._check_vcs_requirement(request.path):
68 environ['PATH_INFO'] = '/error/vcs_unavailable'
74 raise VCSServerUnavailable('VCS Server is not available')
69
75
70 return self.application(environ, start_response)
76 return self.handler(context, request)
@@ -33,14 +33,14 b' import tempfile'
33 import traceback
33 import traceback
34 import tarfile
34 import tarfile
35 import warnings
35 import warnings
36 from os.path import abspath
36 from os.path import join as jn
37 from os.path import dirname as dn, join as jn
38
37
39 import paste
38 import paste
40 import pkg_resources
39 import pkg_resources
41 from paste.script.command import Command, BadCommand
40 from paste.script.command import Command, BadCommand
42 from webhelpers.text import collapse, remove_formatting, strip_tags
41 from webhelpers.text import collapse, remove_formatting, strip_tags
43 from mako import exceptions
42 from mako import exceptions
43 from pyramid.threadlocal import get_current_registry
44
44
45 from rhodecode.lib.fakemod import create_module
45 from rhodecode.lib.fakemod import create_module
46 from rhodecode.lib.vcs.backends.base import Config
46 from rhodecode.lib.vcs.backends.base import Config
@@ -52,8 +52,7 b' from rhodecode.model import meta'
52 from rhodecode.model.db import (
52 from rhodecode.model.db import (
53 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
53 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
54 from rhodecode.model.meta import Session
54 from rhodecode.model.meta import Session
55 from rhodecode.model.repo_group import RepoGroupModel
55
56 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
57
56
58 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
59
58
@@ -384,6 +383,8 b' def config_data_from_db(clear_session=Tr'
384 Read the configuration data from the database and return configuration
383 Read the configuration data from the database and return configuration
385 tuples.
384 tuples.
386 """
385 """
386 from rhodecode.model.settings import VcsSettingsModel
387
387 config = []
388 config = []
388
389
389 sa = meta.Session()
390 sa = meta.Session()
@@ -467,6 +468,7 b' def set_rhodecode_config(config):'
467
468
468 :param config:
469 :param config:
469 """
470 """
471 from rhodecode.model.settings import SettingsModel
470 app_settings = SettingsModel().get_all_settings()
472 app_settings = SettingsModel().get_all_settings()
471
473
472 for k, v in app_settings.items():
474 for k, v in app_settings.items():
@@ -481,6 +483,7 b' def map_groups(path):'
481
483
482 :param paths: full path to repository
484 :param paths: full path to repository
483 """
485 """
486 from rhodecode.model.repo_group import RepoGroupModel
484 sa = meta.Session()
487 sa = meta.Session()
485 groups = path.split(Repository.NAME_SEP)
488 groups = path.split(Repository.NAME_SEP)
486 parent = None
489 parent = None
@@ -489,7 +492,7 b' def map_groups(path):'
489 # last element is repo in nested groups structure
492 # last element is repo in nested groups structure
490 groups = groups[:-1]
493 groups = groups[:-1]
491 rgm = RepoGroupModel(sa)
494 rgm = RepoGroupModel(sa)
492 owner = User.get_first_admin()
495 owner = User.get_first_super_admin()
493 for lvl, group_name in enumerate(groups):
496 for lvl, group_name in enumerate(groups):
494 group_name = '/'.join(groups[:lvl] + [group_name])
497 group_name = '/'.join(groups[:lvl] + [group_name])
495 group = RepoGroup.get_by_group_name(group_name)
498 group = RepoGroup.get_by_group_name(group_name)
@@ -525,9 +528,12 b' def repo2db_mapper(initial_repo_list, re'
525 """
528 """
526 from rhodecode.model.repo import RepoModel
529 from rhodecode.model.repo import RepoModel
527 from rhodecode.model.scm import ScmModel
530 from rhodecode.model.scm import ScmModel
531 from rhodecode.model.repo_group import RepoGroupModel
532 from rhodecode.model.settings import SettingsModel
533
528 sa = meta.Session()
534 sa = meta.Session()
529 repo_model = RepoModel()
535 repo_model = RepoModel()
530 user = User.get_first_admin()
536 user = User.get_first_super_admin()
531 added = []
537 added = []
532
538
533 # creation defaults
539 # creation defaults
@@ -701,58 +707,56 b' def get_custom_lexer(extension):'
701 #==============================================================================
707 #==============================================================================
702 # TEST FUNCTIONS AND CREATORS
708 # TEST FUNCTIONS AND CREATORS
703 #==============================================================================
709 #==============================================================================
704 def create_test_index(repo_location, config, full_index):
710 def create_test_index(repo_location, config):
705 """
711 """
706 Makes default test index
712 Makes default test index.
707
713 """
708 :param config: test config
714 import rc_testdata
709 :param full_index:
710 # start test server:
711 rcserver --with-vcsserver test.ini
712
715
713 # build index and store it in /tmp/rc/index:
716 rc_testdata.extract_search_index(
714 rhodecode-index --force --api-host=http://vps1.dev:5000 --api-key=xxx --engine-location=/tmp/rc/index
717 'vcs_search_index', os.path.dirname(config['search.location']))
715
716 # package and move new packages
717 tar -zcvf vcs_search_index.tar.gz -C /tmp/rc index
718 mv vcs_search_index.tar.gz rhodecode/tests/fixtures/
719
720 """
721 cur_dir = dn(dn(abspath(__file__)))
722 with tarfile.open(jn(cur_dir, 'tests', 'fixtures',
723 'vcs_search_index.tar.gz')) as tar:
724 tar.extractall(os.path.dirname(config['search.location']))
725
718
726
719
727 def create_test_env(repos_test_path, config):
720 def create_test_directory(test_path):
721 """
722 Create test directory if it doesn't exist.
728 """
723 """
729 Makes a fresh database and
724 if not os.path.isdir(test_path):
730 installs test repository into tmp dir
725 log.debug('Creating testdir %s', test_path)
726 os.makedirs(test_path)
727
728
729 def create_test_database(test_path, config):
730 """
731 Makes a fresh database.
731 """
732 """
732 from rhodecode.lib.db_manage import DbManage
733 from rhodecode.lib.db_manage import DbManage
733 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO, TESTS_TMP_PATH
734
734
735 # PART ONE create db
735 # PART ONE create db
736 dbconf = config['sqlalchemy.db1.url']
736 dbconf = config['sqlalchemy.db1.url']
737 log.debug('making test db %s', dbconf)
737 log.debug('making test db %s', dbconf)
738
738
739 # create test dir if it doesn't exist
740 if not os.path.isdir(repos_test_path):
741 log.debug('Creating testdir %s', repos_test_path)
742 os.makedirs(repos_test_path)
743
744 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
739 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
745 tests=True, cli_args={'force_ask': True})
740 tests=True, cli_args={'force_ask': True})
746 dbmanage.create_tables(override=True)
741 dbmanage.create_tables(override=True)
747 dbmanage.set_db_version()
742 dbmanage.set_db_version()
748 # for tests dynamically set new root paths based on generated content
743 # for tests dynamically set new root paths based on generated content
749 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
744 dbmanage.create_settings(dbmanage.config_prompt(test_path))
750 dbmanage.create_default_user()
745 dbmanage.create_default_user()
751 dbmanage.create_test_admin_and_users()
746 dbmanage.create_test_admin_and_users()
752 dbmanage.create_permissions()
747 dbmanage.create_permissions()
753 dbmanage.populate_default_permissions()
748 dbmanage.populate_default_permissions()
754 Session().commit()
749 Session().commit()
755 # PART TWO make test repo
750
751
752 def create_test_repositories(test_path, config):
753 """
754 Creates test repositories in the temporary directory. Repositories are
755 extracted from archives within the rc_testdata package.
756 """
757 import rc_testdata
758 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
759
756 log.debug('making test vcs repositories')
760 log.debug('making test vcs repositories')
757
761
758 idx_path = config['search.location']
762 idx_path = config['search.location']
@@ -767,24 +771,15 b' def create_test_env(repos_test_path, con'
767 log.debug('remove %s', data_path)
771 log.debug('remove %s', data_path)
768 shutil.rmtree(data_path)
772 shutil.rmtree(data_path)
769
773
770 # CREATE DEFAULT TEST REPOS
774 rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
771 cur_dir = dn(dn(abspath(__file__)))
775 rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
772 with tarfile.open(jn(cur_dir, 'tests', 'fixtures',
773 'vcs_test_hg.tar.gz')) as tar:
774 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
775
776 cur_dir = dn(dn(abspath(__file__)))
777 with tarfile.open(jn(cur_dir, 'tests', 'fixtures',
778 'vcs_test_git.tar.gz')) as tar:
779 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
780
776
781 # Note: Subversion is in the process of being integrated with the system,
777 # Note: Subversion is in the process of being integrated with the system,
782 # until we have a properly packed version of the test svn repository, this
778 # until we have a properly packed version of the test svn repository, this
783 # tries to copy over the repo from a package "rc_testdata"
779 # tries to copy over the repo from a package "rc_testdata"
784 import rc_testdata
785 svn_repo_path = rc_testdata.get_svn_repo_archive()
780 svn_repo_path = rc_testdata.get_svn_repo_archive()
786 with tarfile.open(svn_repo_path) as tar:
781 with tarfile.open(svn_repo_path) as tar:
787 tar.extractall(jn(TESTS_TMP_PATH, SVN_REPO))
782 tar.extractall(jn(test_path, SVN_REPO))
788
783
789
784
790 #==============================================================================
785 #==============================================================================
@@ -976,7 +971,20 b' def read_opensource_licenses():'
976
971
977 if not _license_cache:
972 if not _license_cache:
978 licenses = pkg_resources.resource_string(
973 licenses = pkg_resources.resource_string(
979 'rhodecode.config', 'licenses.json')
974 'rhodecode', 'config/licenses.json')
980 _license_cache = json.loads(licenses)
975 _license_cache = json.loads(licenses)
981
976
982 return _license_cache
977 return _license_cache
978
979
980 def get_registry(request):
981 """
982 Utility to get the pyramid registry from a request. During migration to
983 pyramid we sometimes want to use the pyramid registry from pylons context.
984 Therefore this utility returns `request.registry` for pyramid requests and
985 uses `get_current_registry()` for pylons requests.
986 """
987 try:
988 return request.registry
989 except AttributeError:
990 return get_current_registry()
@@ -321,7 +321,8 b' def engine_from_config(configuration, pr'
321 setattr(conn, 'query_start_time', time.time())
321 setattr(conn, 'query_start_time', time.time())
322 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
322 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
323 calling_context = find_calling_context(ignore_modules=[
323 calling_context = find_calling_context(ignore_modules=[
324 'rhodecode.lib.caching_query'
324 'rhodecode.lib.caching_query',
325 'rhodecode.model.settings',
325 ])
326 ])
326 if calling_context:
327 if calling_context:
327 log.info(color_sql('call context %s:%s' % (
328 log.info(color_sql('call context %s:%s' % (
@@ -341,6 +342,12 b' def engine_from_config(configuration, pr'
341 return engine
342 return engine
342
343
343
344
345 def get_encryption_key(config):
346 secret = config.get('rhodecode.encrypted_values.secret')
347 default = config['beaker.session.secret']
348 return secret or default
349
350
344 def age(prevdate, now=None, show_short_version=False, show_suffix=True,
351 def age(prevdate, now=None, show_short_version=False, show_suffix=True,
345 short_format=False):
352 short_format=False):
346 """
353 """
@@ -93,11 +93,14 b' def connect_http(server_and_port):'
93 from rhodecode.lib.vcs import connection, client_http
93 from rhodecode.lib.vcs import connection, client_http
94 from rhodecode.lib.middleware.utils import scm_app
94 from rhodecode.lib.middleware.utils import scm_app
95
95
96 session = _create_http_rpc_session()
96 session_factory = client_http.ThreadlocalSessionFactory()
97
97
98 connection.Git = client_http.RepoMaker(server_and_port, '/git', session)
98 connection.Git = client_http.RepoMaker(
99 connection.Hg = client_http.RepoMaker(server_and_port, '/hg', session)
99 server_and_port, '/git', session_factory)
100 connection.Svn = client_http.RepoMaker(server_and_port, '/svn', session)
100 connection.Hg = client_http.RepoMaker(
101 server_and_port, '/hg', session_factory)
102 connection.Svn = client_http.RepoMaker(
103 server_and_port, '/svn', session_factory)
101
104
102 scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy(
105 scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy(
103 server_and_port, '/proxy/hg')
106 server_and_port, '/proxy/hg')
@@ -31,6 +31,7 b' implementation.'
31
31
32 import copy
32 import copy
33 import logging
33 import logging
34 import threading
34 import urllib2
35 import urllib2
35 import urlparse
36 import urlparse
36 import uuid
37 import uuid
@@ -38,7 +39,7 b' import uuid'
38 import msgpack
39 import msgpack
39 import requests
40 import requests
40
41
41 from . import exceptions
42 from . import exceptions, CurlSession
42
43
43
44
44 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
@@ -54,15 +55,16 b' EXCEPTIONS_MAP = {'
54
55
55 class RepoMaker(object):
56 class RepoMaker(object):
56
57
57 def __init__(self, server_and_port, backend_endpoint, session):
58 def __init__(self, server_and_port, backend_endpoint, session_factory):
58 self.url = urlparse.urljoin(
59 self.url = urlparse.urljoin(
59 'http://%s' % server_and_port, backend_endpoint)
60 'http://%s' % server_and_port, backend_endpoint)
60 self._session = session
61 self._session_factory = session_factory
61
62
62 def __call__(self, path, config, with_wire=None):
63 def __call__(self, path, config, with_wire=None):
63 log.debug('RepoMaker call on %s', path)
64 log.debug('RepoMaker call on %s', path)
64 return RemoteRepo(
65 return RemoteRepo(
65 path, config, self.url, self._session, with_wire=with_wire)
66 path, config, self.url, self._session_factory(),
67 with_wire=with_wire)
66
68
67 def __getattr__(self, name):
69 def __getattr__(self, name):
68 def f(*args, **kwargs):
70 def f(*args, **kwargs):
@@ -76,7 +78,8 b' class RepoMaker(object):'
76 'method': name,
78 'method': name,
77 'params': {'args': args, 'kwargs': kwargs}
79 'params': {'args': args, 'kwargs': kwargs}
78 }
80 }
79 return _remote_call(self.url, payload, EXCEPTIONS_MAP, self._session)
81 return _remote_call(
82 self.url, payload, EXCEPTIONS_MAP, self._session_factory())
80
83
81
84
82 class RemoteRepo(object):
85 class RemoteRepo(object):
@@ -216,3 +219,17 b' class VcsHttpProxy(object):'
216 headers = iterator.next()
219 headers = iterator.next()
217
220
218 return iterator, status, headers
221 return iterator, status, headers
222
223
224 class ThreadlocalSessionFactory(object):
225 """
226 Creates one CurlSession per thread on demand.
227 """
228
229 def __init__(self):
230 self._thread_local = threading.local()
231
232 def __call__(self):
233 if not hasattr(self._thread_local, 'curl_session'):
234 self._thread_local.curl_session = CurlSession()
235 return self._thread_local.curl_session
@@ -43,9 +43,10 b" The application's model objects"
43 import logging
43 import logging
44
44
45 from pylons import config
45 from pylons import config
46 from pyramid.threadlocal import get_current_registry
46
47
47 from rhodecode.model import meta, db
48 from rhodecode.model import meta, db
48 from rhodecode.lib.utils2 import obfuscate_url_pw
49 from rhodecode.lib.utils2 import obfuscate_url_pw, get_encryption_key
49
50
50 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
51
52
@@ -65,8 +66,8 b' def init_model(engine, encryption_key=No'
65
66
66
67
67 def init_model_encryption(migration_models):
68 def init_model_encryption(migration_models):
68 migration_models.ENCRYPTION_KEY = config['beaker.session.secret']
69 migration_models.ENCRYPTION_KEY = get_encryption_key(config)
69 db.ENCRYPTION_KEY = config['beaker.session.secret']
70 db.ENCRYPTION_KEY = get_encryption_key(config)
70
71
71
72
72 class BaseModel(object):
73 class BaseModel(object):
@@ -144,6 +145,17 b' class BaseModel(object):'
144 return self._get_instance(
145 return self._get_instance(
145 db.Permission, permission, callback=db.Permission.get_by_key)
146 db.Permission, permission, callback=db.Permission.get_by_key)
146
147
148 def send_event(self, event):
149 """
150 Helper method to send an event. This wraps the pyramid logic to send an
151 event.
152 """
153 # For the first step we are using pyramids thread locals here. If the
154 # event mechanism works out as a good solution we should think about
155 # passing the registry into the constructor to get rid of it.
156 registry = get_current_registry()
157 registry.notify(event)
158
147 @classmethod
159 @classmethod
148 def get_all(cls):
160 def get_all(cls):
149 """
161 """
@@ -70,7 +70,8 b' log = logging.getLogger(__name__)'
70 # BASE CLASSES
70 # BASE CLASSES
71 # =============================================================================
71 # =============================================================================
72
72
73 # this is propagated from .ini file beaker.session.secret
73 # this is propagated from .ini file rhodecode.encrypted_values.secret or
74 # beaker.session.secret if first is not set.
74 # and initialized at environment.py
75 # and initialized at environment.py
75 ENCRYPTION_KEY = None
76 ENCRYPTION_KEY = None
76
77
@@ -115,14 +116,17 b' class EncryptedTextValue(TypeDecorator):'
115 def process_bind_param(self, value, dialect):
116 def process_bind_param(self, value, dialect):
116 if not value:
117 if not value:
117 return value
118 return value
118 if value.startswith('enc$aes$'):
119 if value.startswith('enc$aes$') or value.startswith('enc$aes_hmac$'):
119 # protect against double encrypting if someone manually starts
120 # protect against double encrypting if someone manually starts
120 # doing
121 # doing
121 raise ValueError('value needs to be in unencrypted format, ie. '
122 raise ValueError('value needs to be in unencrypted format, ie. '
122 'not starting with enc$aes$')
123 'not starting with enc$aes')
123 return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value)
124 return 'enc$aes_hmac$%s' % AESCipher(
125 ENCRYPTION_KEY, hmac=True).encrypt(value)
124
126
125 def process_result_value(self, value, dialect):
127 def process_result_value(self, value, dialect):
128 import rhodecode
129
126 if not value:
130 if not value:
127 return value
131 return value
128
132
@@ -134,9 +138,19 b' class EncryptedTextValue(TypeDecorator):'
134 if parts[0] != 'enc':
138 if parts[0] != 'enc':
135 # parts ok but without our header ?
139 # parts ok but without our header ?
136 return value
140 return value
137
141 enc_strict_mode = str2bool(rhodecode.CONFIG.get(
142 'rhodecode.encrypted_values.strict') or True)
138 # at that stage we know it's our encryption
143 # at that stage we know it's our encryption
139 decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2])
144 if parts[1] == 'aes':
145 decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2])
146 elif parts[1] == 'aes_hmac':
147 decrypted_data = AESCipher(
148 ENCRYPTION_KEY, hmac=True,
149 strict_verification=enc_strict_mode).decrypt(parts[2])
150 else:
151 raise ValueError(
152 'Encryption type part is wrong, must be `aes` '
153 'or `aes_hmac`, got `%s` instead' % (parts[1]))
140 return decrypted_data
154 return decrypted_data
141
155
142
156
@@ -220,6 +234,20 b' class BaseModel(object):'
220 obj = cls.query().get(id_)
234 obj = cls.query().get(id_)
221 Session().delete(obj)
235 Session().delete(obj)
222
236
237 @classmethod
238 def identity_cache(cls, session, attr_name, value):
239 exist_in_session = []
240 for (item_cls, pkey), instance in session.identity_map.items():
241 if cls == item_cls and getattr(instance, attr_name) == value:
242 exist_in_session.append(instance)
243 if exist_in_session:
244 if len(exist_in_session) == 1:
245 return exist_in_session[0]
246 log.exception(
247 'multiple objects with attr %s and '
248 'value %s found with same name: %r',
249 attr_name, value, exist_in_session)
250
223 def __repr__(self):
251 def __repr__(self):
224 if hasattr(self, '__unicode__'):
252 if hasattr(self, '__unicode__'):
225 # python repr needs to return str
253 # python repr needs to return str
@@ -639,16 +667,26 b' class User(Base, BaseModel):'
639 log.error(traceback.format_exc())
667 log.error(traceback.format_exc())
640
668
641 @classmethod
669 @classmethod
642 def get_by_username(cls, username, case_insensitive=False, cache=False):
670 def get_by_username(cls, username, case_insensitive=False,
671 cache=False, identity_cache=False):
672 session = Session()
673
643 if case_insensitive:
674 if case_insensitive:
644 q = cls.query().filter(func.lower(cls.username) == func.lower(username))
675 q = cls.query().filter(
676 func.lower(cls.username) == func.lower(username))
645 else:
677 else:
646 q = cls.query().filter(cls.username == username)
678 q = cls.query().filter(cls.username == username)
647
679
648 if cache:
680 if cache:
649 q = q.options(FromCache(
681 if identity_cache:
650 "sql_cache_short",
682 val = cls.identity_cache(session, 'username', username)
651 "get_user_%s" % _hash_key(username)))
683 if val:
684 return val
685 else:
686 q = q.options(
687 FromCache("sql_cache_short",
688 "get_user_by_name_%s" % _hash_key(username)))
689
652 return q.scalar()
690 return q.scalar()
653
691
654 @classmethod
692 @classmethod
@@ -752,10 +790,10 b' class User(Base, BaseModel):'
752 Session().add(self)
790 Session().add(self)
753
791
754 @classmethod
792 @classmethod
755 def get_first_admin(cls):
793 def get_first_super_admin(cls):
756 user = User.query().filter(User.admin == True).first()
794 user = User.query().filter(User.admin == true()).first()
757 if user is None:
795 if user is None:
758 raise Exception('Missing administrative account!')
796 raise Exception('FATAL: Missing administrative account!')
759 return user
797 return user
760
798
761 @classmethod
799 @classmethod
@@ -770,7 +808,7 b' class User(Base, BaseModel):'
770 def get_default_user(cls, cache=False):
808 def get_default_user(cls, cache=False):
771 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
809 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
772 if user is None:
810 if user is None:
773 raise Exception('Missing default account!')
811 raise Exception('FATAL: Missing default account!')
774 return user
812 return user
775
813
776 def _get_default_perms(self, user, suffix=''):
814 def _get_default_perms(self, user, suffix=''):
@@ -1264,9 +1302,9 b' class Repository(Base, BaseModel):'
1264 "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True,
1302 "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True,
1265 unique=False, default=None)
1303 unique=False, default=None)
1266
1304
1267 user = relationship('User')
1305 user = relationship('User', lazy='joined')
1268 fork = relationship('Repository', remote_side=repo_id)
1306 fork = relationship('Repository', remote_side=repo_id, lazy='joined')
1269 group = relationship('RepoGroup')
1307 group = relationship('RepoGroup', lazy='joined')
1270 repo_to_perm = relationship(
1308 repo_to_perm = relationship(
1271 'UserRepoToPerm', cascade='all',
1309 'UserRepoToPerm', cascade='all',
1272 order_by='UserRepoToPerm.repo_to_perm_id')
1310 order_by='UserRepoToPerm.repo_to_perm_id')
@@ -1364,7 +1402,7 b' class Repository(Base, BaseModel):'
1364 def normalize_repo_name(cls, repo_name):
1402 def normalize_repo_name(cls, repo_name):
1365 """
1403 """
1366 Normalizes os specific repo_name to the format internally stored inside
1404 Normalizes os specific repo_name to the format internally stored inside
1367 dabatabase using URL_SEP
1405 database using URL_SEP
1368
1406
1369 :param cls:
1407 :param cls:
1370 :param repo_name:
1408 :param repo_name:
@@ -1372,11 +1410,20 b' class Repository(Base, BaseModel):'
1372 return cls.NAME_SEP.join(repo_name.split(os.sep))
1410 return cls.NAME_SEP.join(repo_name.split(os.sep))
1373
1411
1374 @classmethod
1412 @classmethod
1375 def get_by_repo_name(cls, repo_name):
1413 def get_by_repo_name(cls, repo_name, cache=False, identity_cache=False):
1376 q = Session().query(cls).filter(cls.repo_name == repo_name)
1414 session = Session()
1377 q = q.options(joinedload(Repository.fork))\
1415 q = session.query(cls).filter(cls.repo_name == repo_name)
1378 .options(joinedload(Repository.user))\
1416
1379 .options(joinedload(Repository.group))
1417 if cache:
1418 if identity_cache:
1419 val = cls.identity_cache(session, 'repo_name', repo_name)
1420 if val:
1421 return val
1422 else:
1423 q = q.options(
1424 FromCache("sql_cache_short",
1425 "get_repo_by_name_%s" % _hash_key(repo_name)))
1426
1380 return q.scalar()
1427 return q.scalar()
1381
1428
1382 @classmethod
1429 @classmethod
@@ -1721,7 +1768,7 b' class Repository(Base, BaseModel):'
1721 clone_uri = self.clone_uri
1768 clone_uri = self.clone_uri
1722 if clone_uri:
1769 if clone_uri:
1723 import urlobject
1770 import urlobject
1724 url_obj = urlobject.URLObject(self.clone_uri)
1771 url_obj = urlobject.URLObject(clone_uri)
1725 if url_obj.password:
1772 if url_obj.password:
1726 clone_uri = url_obj.with_password('*****')
1773 clone_uri = url_obj.with_password('*****')
1727 return clone_uri
1774 return clone_uri
@@ -138,7 +138,11 b' def UserForm(edit=False, available_langu'
138 return _UserForm
138 return _UserForm
139
139
140
140
141 def UserGroupForm(edit=False, old_data={}, available_members=[]):
141 def UserGroupForm(edit=False, old_data=None, available_members=None,
142 allow_disabled=False):
143 old_data = old_data or {}
144 available_members = available_members or []
145
142 class _UserGroupForm(formencode.Schema):
146 class _UserGroupForm(formencode.Schema):
143 allow_extra_fields = True
147 allow_extra_fields = True
144 filter_extra_fields = True
148 filter_extra_fields = True
@@ -157,14 +161,18 b' def UserGroupForm(edit=False, old_data={'
157 available_members, hideList=False, testValueList=True,
161 available_members, hideList=False, testValueList=True,
158 if_missing=None, not_empty=False
162 if_missing=None, not_empty=False
159 )
163 )
160 #this is user group owner
164 # this is user group owner
161 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
165 user = All(
162
166 v.UnicodeString(not_empty=True),
167 v.ValidRepoUser(allow_disabled))
163 return _UserGroupForm
168 return _UserGroupForm
164
169
165
170
166 def RepoGroupForm(edit=False, old_data={}, available_groups=[],
171 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
167 can_create_in_root=False):
172 can_create_in_root=False, allow_disabled=False):
173 old_data = old_data or {}
174 available_groups = available_groups or []
175
168 class _RepoGroupForm(formencode.Schema):
176 class _RepoGroupForm(formencode.Schema):
169 allow_extra_fields = True
177 allow_extra_fields = True
170 filter_extra_fields = False
178 filter_extra_fields = False
@@ -178,11 +186,14 b' def RepoGroupForm(edit=False, old_data={'
178 group_parent_id = v.OneOf(available_groups, hideList=False,
186 group_parent_id = v.OneOf(available_groups, hideList=False,
179 testValueList=True, not_empty=True)
187 testValueList=True, not_empty=True)
180 enable_locking = v.StringBoolean(if_missing=False)
188 enable_locking = v.StringBoolean(if_missing=False)
181 chained_validators = [v.ValidRepoGroup(edit, old_data, can_create_in_root)]
189 chained_validators = [
190 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
182
191
183 if edit:
192 if edit:
184 #this is repo group owner
193 # this is repo group owner
185 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
194 user = All(
195 v.UnicodeString(not_empty=True),
196 v.ValidRepoUser(allow_disabled))
186
197
187 return _RepoGroupForm
198 return _RepoGroupForm
188
199
@@ -221,7 +232,8 b' def PasswordResetForm():'
221 return _PasswordResetForm
232 return _PasswordResetForm
222
233
223
234
224 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None):
235 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
236 allow_disabled=False):
225 old_data = old_data or {}
237 old_data = old_data or {}
226 repo_groups = repo_groups or []
238 repo_groups = repo_groups or []
227 landing_revs = landing_revs or []
239 landing_revs = landing_revs or []
@@ -248,7 +260,9 b' def RepoForm(edit=False, old_data=None, '
248
260
249 if edit:
261 if edit:
250 # this is repo owner
262 # this is repo owner
251 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
263 user = All(
264 v.UnicodeString(not_empty=True),
265 v.ValidRepoUser(allow_disabled))
252 clone_uri_change = v.UnicodeString(
266 clone_uri_change = v.UnicodeString(
253 not_empty=False, if_missing=v.Missing)
267 not_empty=False, if_missing=v.Missing)
254
268
@@ -140,10 +140,12 b' class RepoModel(BaseModel):'
140
140
141 return None
141 return None
142
142
143 def get_users(self, name_contains=None, limit=20):
143 def get_users(self, name_contains=None, limit=20, only_active=True):
144 # TODO: mikhail: move this method to the UserModel.
144 # TODO: mikhail: move this method to the UserModel.
145 query = self.sa.query(User)
145 query = self.sa.query(User)
146 query = query.filter(User.active == true())
146 if only_active:
147 query = query.filter(User.active == true())
148
147 if name_contains:
149 if name_contains:
148 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
150 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
149 query = query.filter(
151 query = query.filter(
@@ -165,16 +167,19 b' class RepoModel(BaseModel):'
165 'icon_link': h.gravatar_url(user.email, 14),
167 'icon_link': h.gravatar_url(user.email, 14),
166 'value_display': h.person(user.email),
168 'value_display': h.person(user.email),
167 'value': user.username,
169 'value': user.username,
168 'value_type': 'user'
170 'value_type': 'user',
171 'active': user.active,
169 }
172 }
170 for user in users
173 for user in users
171 ]
174 ]
172 return _users
175 return _users
173
176
174 def get_user_groups(self, name_contains=None, limit=20):
177 def get_user_groups(self, name_contains=None, limit=20, only_active=True):
175 # TODO: mikhail: move this method to the UserGroupModel.
178 # TODO: mikhail: move this method to the UserGroupModel.
176 query = self.sa.query(UserGroup)
179 query = self.sa.query(UserGroup)
177 query = query.filter(UserGroup.users_group_active == true())
180 if only_active:
181 query = query.filter(UserGroup.users_group_active == true())
182
178 if name_contains:
183 if name_contains:
179 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
184 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
180 query = query.filter(
185 query = query.filter(
@@ -196,7 +201,8 b' class RepoModel(BaseModel):'
196 'value_display': 'Group: %s (%d members)' % (
201 'value_display': 'Group: %s (%d members)' % (
197 group.users_group_name, len(group.members),),
202 group.users_group_name, len(group.members),),
198 'value': group.users_group_name,
203 'value': group.users_group_name,
199 'value_type': 'user_group'
204 'value_type': 'user_group',
205 'active': group.users_group_active,
200 }
206 }
201 for group in user_groups
207 for group in user_groups
202 ]
208 ]
@@ -333,7 +339,7 b' class RepoModel(BaseModel):'
333 if repo_info.user:
339 if repo_info.user:
334 defaults.update({'user': repo_info.user.username})
340 defaults.update({'user': repo_info.user.username})
335 else:
341 else:
336 replacement_user = User.get_first_admin().username
342 replacement_user = User.get_first_super_admin().username
337 defaults.update({'user': replacement_user})
343 defaults.update({'user': replacement_user})
338
344
339 # fill repository users
345 # fill repository users
@@ -23,6 +23,7 b' import logging'
23 from collections import namedtuple
23 from collections import namedtuple
24 from functools import wraps
24 from functools import wraps
25
25
26 from rhodecode.lib import caches
26 from rhodecode.lib.caching_query import FromCache
27 from rhodecode.lib.caching_query import FromCache
27 from rhodecode.lib.utils2 import (
28 from rhodecode.lib.utils2 import (
28 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
29 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
@@ -200,23 +201,37 b' class SettingsModel(BaseModel):'
200 Session.add(res)
201 Session.add(res)
201 return res
202 return res
202
203
204 def invalidate_settings_cache(self):
205 namespace = 'rhodecode_settings'
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
207 caches.clear_cache_manager(cache_manager)
208
203 def get_all_settings(self, cache=False):
209 def get_all_settings(self, cache=False):
204 q = self._get_settings_query()
210 def _compute():
205 if cache:
211 q = self._get_settings_query()
206 repo = self._get_repo(self.repo) if self.repo else None
212 if not q:
207 cache_key = (
213 raise Exception('Could not get application settings !')
208 "get_repo_{}_settings".format(repo.repo_id)
209 if repo else "get_hg_settings")
210 q = q.options(FromCache("sql_cache_short", cache_key))
211
214
212 if not q:
215 settings = {
213 raise Exception('Could not get application settings !')
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
217 for result in q
218 }
219 return settings
214
220
215 settings = {
221 if cache:
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
222 log.debug('Fetching app settings using cache')
217 for result in q
223 repo = self._get_repo(self.repo) if self.repo else None
218 }
224 namespace = 'rhodecode_settings'
219 return settings
225 cache_manager = caches.get_cache_manager(
226 'sql_cache_short', namespace)
227 _cache_key = (
228 "get_repo_{}_settings".format(repo.repo_id)
229 if repo else "get_app_settings")
230
231 return cache_manager.get(_cache_key, createfunc=_compute)
232
233 else:
234 return _compute()
220
235
221 def get_auth_settings(self):
236 def get_auth_settings(self):
222 q = self._get_settings_query()
237 q = self._get_settings_query()
@@ -26,13 +26,13 b' import logging'
26 import traceback
26 import traceback
27
27
28 import datetime
28 import datetime
29 from pylons import url
30 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
31
30
32 import ipaddress
31 import ipaddress
33 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
34 from sqlalchemy.sql.expression import true, false
33 from sqlalchemy.sql.expression import true, false
35
34
35 from rhodecode.events import UserPreCreate, UserPreUpdate
36 from rhodecode.lib.utils2 import (
36 from rhodecode.lib.utils2 import (
37 safe_unicode, get_current_rhodecode_user, action_logger_generic,
37 safe_unicode, get_current_rhodecode_user, action_logger_generic,
38 AttributeDict)
38 AttributeDict)
@@ -270,10 +270,12 b' class UserModel(BaseModel):'
270 # raises UserCreationError if it's not allowed for any reason to
270 # raises UserCreationError if it's not allowed for any reason to
271 # create new active user, this also executes pre-create hooks
271 # create new active user, this also executes pre-create hooks
272 check_allowed_create_user(user_data, cur_user, strict_check=True)
272 check_allowed_create_user(user_data, cur_user, strict_check=True)
273 self.send_event(UserPreCreate(user_data))
273 new_user = User()
274 new_user = User()
274 edit = False
275 edit = False
275 else:
276 else:
276 log.debug('updating user %s', username)
277 log.debug('updating user %s', username)
278 self.send_event(UserPreUpdate(user, user_data))
277 new_user = user
279 new_user = user
278 edit = True
280 edit = True
279
281
@@ -375,7 +377,7 b' class UserModel(BaseModel):'
375 raise
377 raise
376
378
377 def _handle_user_repos(self, username, repositories, handle_mode=None):
379 def _handle_user_repos(self, username, repositories, handle_mode=None):
378 _superadmin = self.cls.get_first_admin()
380 _superadmin = self.cls.get_first_super_admin()
379 left_overs = True
381 left_overs = True
380
382
381 from rhodecode.model.repo import RepoModel
383 from rhodecode.model.repo import RepoModel
@@ -398,7 +400,7 b' class UserModel(BaseModel):'
398
400
399 def _handle_user_repo_groups(self, username, repository_groups,
401 def _handle_user_repo_groups(self, username, repository_groups,
400 handle_mode=None):
402 handle_mode=None):
401 _superadmin = self.cls.get_first_admin()
403 _superadmin = self.cls.get_first_super_admin()
402 left_overs = True
404 left_overs = True
403
405
404 from rhodecode.model.repo_group import RepoGroupModel
406 from rhodecode.model.repo_group import RepoGroupModel
@@ -420,7 +422,7 b' class UserModel(BaseModel):'
420 return left_overs
422 return left_overs
421
423
422 def _handle_user_user_groups(self, username, user_groups, handle_mode=None):
424 def _handle_user_user_groups(self, username, user_groups, handle_mode=None):
423 _superadmin = self.cls.get_first_admin()
425 _superadmin = self.cls.get_first_super_admin()
424 left_overs = True
426 left_overs = True
425
427
426 from rhodecode.model.user_group import UserGroupModel
428 from rhodecode.model.user_group import UserGroupModel
@@ -498,7 +498,7 b' class UserGroupModel(BaseModel):'
498 self.remove_user_from_group(gr, user)
498 self.remove_user_from_group(gr, user)
499
499
500 # now we calculate in which groups user should be == groups params
500 # now we calculate in which groups user should be == groups params
501 owner = User.get_first_admin().username
501 owner = User.get_first_super_admin().username
502 for gr in set(groups):
502 for gr in set(groups):
503 existing_group = UserGroup.get_by_group_name(gr)
503 existing_group = UserGroup.get_by_group_name(gr)
504 if not existing_group:
504 if not existing_group:
@@ -193,21 +193,26 b' def ValidRegex(msg=None):'
193 return _validator
193 return _validator
194
194
195
195
196 def ValidRepoUser():
196 def ValidRepoUser(allow_disabled=False):
197 class _validator(formencode.validators.FancyValidator):
197 class _validator(formencode.validators.FancyValidator):
198 messages = {
198 messages = {
199 'invalid_username': _(u'Username %(username)s is not valid')
199 'invalid_username': _(u'Username %(username)s is not valid'),
200 'disabled_username': _(u'Username %(username)s is disabled')
200 }
201 }
201
202
202 def validate_python(self, value, state):
203 def validate_python(self, value, state):
203 try:
204 try:
204 User.query().filter(User.active == true())\
205 user = User.query().filter(User.username == value).one()
205 .filter(User.username == value).one()
206 except Exception:
206 except Exception:
207 msg = M(self, 'invalid_username', state, username=value)
207 msg = M(self, 'invalid_username', state, username=value)
208 raise formencode.Invalid(
208 raise formencode.Invalid(
209 msg, value, state, error_dict={'username': msg}
209 msg, value, state, error_dict={'username': msg}
210 )
210 )
211 if user and (not allow_disabled and not user.active):
212 msg = M(self, 'disabled_username', state, username=value)
213 raise formencode.Invalid(
214 msg, value, state, error_dict={'username': msg}
215 )
211
216
212 return _validator
217 return _validator
213
218
@@ -269,6 +269,33 b' form.rcform {'
269
269
270 }
270 }
271
271
272 .badged-field {
273 .user-badge {
274 line-height: 25px;
275 padding: 10px 5px;
276 border-radius: @border-radius;
277 border-top: 1px solid @rclightblue;
278 border-left: 1px solid @rclightblue;
279 border-bottom: 1px solid @rclightblue;
280 font-size: 14px;
281 font-style: normal;
282 color: @text-light;
283 display: inline-block;
284 vertical-align: top;
285 cursor: default;
286 margin-right: -2px;
287 }
288 .badge-input-container {
289 display: flex;
290 position: relative;
291 }
292 .user-disabled {
293 text-decoration: line-through;
294 }
295 .badge-input-wrap {
296 display: inline-block;
297 }
298 }
272
299
273 // for situations where we wish to display the form value but not the form input
300 // for situations where we wish to display the form value but not the form input
274 input.input-valuedisplay {
301 input.input-valuedisplay {
@@ -296,30 +296,30 b' ul.auth_plugins {'
296 }
296 }
297 }
297 }
298
298
299 // Pull Requests
299
300 // My Account PR list
301
302 #show_closed {
303 margin: 0 1em 0 0;
304 }
300
305
301 .pullrequestlist {
306 .pullrequestlist {
302 max-width: @pullrequest-width;
307 .closed {
303 margin-bottom: @space;
308 background-color: @grey6;
304
309 }
305 // Tweaks for "My Account" / "Pull requests"
310 .td-status {
306 .prwrapper {
311 padding-left: .5em;
307 clear: left;
312 }
313 .truncate {
314 height: 2.75em;
315 white-space: pre-line;
316 }
317 table.rctable .user {
318 padding-left: 0;
319 }
320 }
308
321
309 .pr {
322 // Pull Requests
310 margin: 0;
311 padding: 0;
312 border-bottom: none;
313 }
314
315 // TODO: johbo: Replace with something that makes up an inline form or
316 // similar.
317 .repolist_actions {
318 display: inline-block;
319 }
320 }
321
322 }
323
323
324 .pullrequests_section_head {
324 .pullrequests_section_head {
325 display: block;
325 display: block;
@@ -1086,6 +1086,7 b' table.issuetracker {'
1086 }
1086 }
1087 }
1087 }
1088
1088
1089
1089 //Permissions Settings
1090 //Permissions Settings
1090 #add_perm {
1091 #add_perm {
1091 margin: 0 0 @padding;
1092 margin: 0 0 @padding;
@@ -28,7 +28,7 b''
28 margin: 0 7px 0 .7em;
28 margin: 0 7px 0 .7em;
29 font-size: @basefontsize;
29 font-size: @basefontsize;
30 color: white;
30 color: white;
31
31
32 &.empty {
32 &.empty {
33 background-color: @grey4;
33 background-color: @grey4;
34 }
34 }
@@ -94,7 +94,7 b''
94 &:focus {
94 &:focus {
95 outline: none;
95 outline: none;
96 }
96 }
97
97
98 ul li {
98 ul li {
99 display: block;
99 display: block;
100
100
@@ -145,7 +145,7 b''
145 &:hover,
145 &:hover,
146 &.open,
146 &.open,
147 &.active {
147 &.active {
148 a {
148 a {
149 color: @grey1;
149 color: @grey1;
150 }
150 }
151 }
151 }
@@ -288,6 +288,11 b''
288 }
288 }
289 }
289 }
290
290
291 .navigation li:last-child .submenu {
292 right: -20px;
293 left: auto;
294 }
295
291 .submenu {
296 .submenu {
292 position: absolute;
297 position: absolute;
293 top: 100%;
298 top: 100%;
@@ -333,7 +338,7 b''
333 -moz-transition: background .3s;
338 -moz-transition: background .3s;
334 -o-transition: background .3s;
339 -o-transition: background .3s;
335 transition: background .3s;
340 transition: background .3s;
336
341
337 ul {
342 ul {
338 display: block;
343 display: block;
339 }
344 }
@@ -480,7 +485,7 b''
480 &.select2-result-unselectable > .select2-result-label {
485 &.select2-result-unselectable > .select2-result-label {
481 margin: 0 8px;
486 margin: 0 8px;
482 }
487 }
483
488
484 }
489 }
485 }
490 }
486
491
@@ -594,7 +599,7 b' ul#context-pages {'
594 padding: 0;
599 padding: 0;
595 border: none;
600 border: none;
596 }
601 }
597
602
598 .nav-pills {
603 .nav-pills {
599 margin: 0;
604 margin: 0;
600 }
605 }
@@ -6,7 +6,6 b''
6
6
7 width: 100%;
7 width: 100%;
8 margin: 0 0 25px 0;
8 margin: 0 0 25px 0;
9 border-color: @grey5;
10 .border-radius(@border-radius);
9 .border-radius(@border-radius);
11 .box-shadow(none);
10 .box-shadow(none);
12
11
@@ -23,7 +22,6 b''
23 position: relative;
22 position: relative;
24 min-height: 1em;
23 min-height: 1em;
25 padding: @padding @panel-padding;
24 padding: @padding @panel-padding;
26 background-color: @grey6;
27 border-bottom: none;
25 border-bottom: none;
28
26
29 .panel-title,
27 .panel-title,
@@ -19,19 +19,25 b''
19 /**
19 /**
20 * autocomplete formatter that uses gravatar
20 * autocomplete formatter that uses gravatar
21 * */
21 * */
22 var autocompleteFormatResult = function(data, value, org_formatter) {
22 var autocompleteFormatResult = function (data, value, org_formatter) {
23 var value_display = data.value_display;
23 var activeUser = data.active || true;
24 var valueDisplay = data.value_display;
25
26 if (!activeUser) {
27 valueDisplay = '<strong>(disabled)</strong> ' + valueDisplay;
28 }
29
24 var escapeRegExChars = function (value) {
30 var escapeRegExChars = function (value) {
25 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
31 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
26 };
32 };
27 var pattern = '(' + escapeRegExChars(value) + ')';
33 var pattern = '(' + escapeRegExChars(value) + ')';
28 value_display = value_display.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
34 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
29 var tmpl = '<div class="ac-container-wrap"><img class="gravatar" src="{0}"/>{1}</div>';
35 var tmpl = '<div class="ac-container-wrap"><img class="gravatar" src="{0}"/>{1}</div>';
30 if (data.icon_link === "") {
36 if (data.icon_link === "") {
31 tmpl = '<div class="ac-container-wrap">{0}</div>';
37 tmpl = '<div class="ac-container-wrap">{0}</div>';
32 return tmpl.format(value_display);
38 return tmpl.format(valueDisplay);
33 }
39 }
34 return tmpl.format(data.icon_link, value_display);
40 return tmpl.format(data.icon_link, valueDisplay);
35 };
41 };
36
42
37 /**
43 /**
@@ -1,13 +1,12 b''
1 <%namespace name="base" file="/base/base.html"/>
1
2
2 <div class="panel panel-default">
3 <div class="panel panel-default">
3 <div class="panel-body">
4 <div class="panel-body">
4 <div class="field">
5 %if c.show_closed:
5 %if c.show_closed:
6 ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))}
6 ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))}
7 %else:
7 %else:
8 ${h.checkbox('show_closed',label=_('Show Closed Pull Requests'))}
8 ${h.checkbox('show_closed',label=_('Show Closed Pull Requests'))}
9 %endif
9 %endif
10 </div>
11 </div>
10 </div>
12 </div>
11 </div>
13
12
@@ -15,29 +14,57 b''
15 <div class="panel-heading">
14 <div class="panel-heading">
16 <h3 class="panel-title">${_('Pull Requests You Opened')}</h3>
15 <h3 class="panel-title">${_('Pull Requests You Opened')}</h3>
17 </div>
16 </div>
18
19 <div class="panel-body">
17 <div class="panel-body">
20 <div class="pullrequestlist">
18 <div class="pullrequestlist">
21 %if c.my_pull_requests:
19 %if c.my_pull_requests:
20 <table class="rctable">
21 <thead>
22 <th class="td-status"></th>
23 <th>${_('Target Repo')}</th>
24 <th>${_('Author')}</th>
25 <th></th>
26 <th>${_('Title')}</th>
27 <th class="td-time">${_('Opened On')}</th>
28 <th></th>
29 </thead>
22 %for pull_request in c.my_pull_requests:
30 %for pull_request in c.my_pull_requests:
23 <div class="${'closed' if pull_request.is_closed() else ''} prwrapper">
31 <tr class="${'closed' if pull_request.is_closed() else ''} prwrapper">
24 <div class="pr">
32 <td class="td-status">
25 <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div>
33 <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div>
26 <a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
34 </td>
27 ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.format_date(pull_request.created_on))}
35 <td class="td-componentname">
28 %if pull_request.is_closed():
36 ${h.link_to(pull_request.target_repo.repo_name,h.url('summary_home',repo_name=pull_request.target_repo.repo_name))}
29 (${_('Closed')})
37 </td>
30 %endif
38 <td class="user">
31 </a>
39 ${base.gravatar_with_user(pull_request.author.email, 16)}
32 <div class="repolist_actions">
40 </td>
33 ${h.secure_form(url('pullrequest_delete', repo_name=pull_request.target_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')}
41 <td class="td-message expand_commit" data-pr-id="m${pull_request.pull_request_id}" title="${_('Expand commit message')}">
34 ${h.submit('remove_%s' % pull_request.pull_request_id, _('Delete'),
42 <div class="show_more_col">
35 class_="btn btn-link btn-danger",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
43 <i class="show_more"></i>&nbsp;
36 ${h.end_form()}
37 </div>
44 </div>
38 </div>
45 </td>
39 </div>
46 <td class="mid td-description">
47 <div class="log-container truncate-wrap">
48 <div class="message truncate" id="c-m${pull_request.pull_request_id}"><a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">#${pull_request.pull_request_id}: ${pull_request.title}</a>\
49 %if pull_request.is_closed():
50 &nbsp;(${_('Closed')})\
51 %endif
52 <br/>${pull_request.description}</div>
53 </div>
54 </td>
55
56 <td class="td-time">
57 ${h.age_component(pull_request.created_on)}
58 </td>
59 <td class="td-action repolist_actions">
60 ${h.secure_form(url('pullrequest_delete', repo_name=pull_request.target_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')}
61 ${h.submit('remove_%s' % pull_request.pull_request_id, _('Delete'),
62 class_="btn btn-link btn-danger",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
63 ${h.end_form()}
64 </td>
65 </tr>
40 %endfor
66 %endfor
67 </table>
41 %else:
68 %else:
42 <h2><span class="empty_data">${_('You currently have no open pull requests.')}</span></h2>
69 <h2><span class="empty_data">${_('You currently have no open pull requests.')}</span></h2>
43 %endif
70 %endif
@@ -53,21 +80,49 b''
53 <div class="panel-body">
80 <div class="panel-body">
54 <div class="pullrequestlist">
81 <div class="pullrequestlist">
55 %if c.participate_in_pull_requests:
82 %if c.participate_in_pull_requests:
83 <table class="rctable">
84 <thead>
85 <th class="td-status"></th>
86 <th>${_('Target Repo')}</th>
87 <th>${_('Author')}</th>
88 <th></th>
89 <th>${_('Title')}</th>
90 <th class="td-time">${_('Opened On')}</th>
91 </thead>
56 %for pull_request in c.participate_in_pull_requests:
92 %for pull_request in c.participate_in_pull_requests:
57 <div class="${'closed' if pull_request.is_closed() else ''} prwrapper">
93 <tr class="${'closed' if pull_request.is_closed() else ''} prwrapper">
58 <div class="pr">
94 <td class="td-status">
59 <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div>
95 <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div>
60 <a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
96 </td>
61 ${_('Pull request #%s opened by %s on %s') % (pull_request.pull_request_id, pull_request.author.full_name, h.format_date(pull_request.created_on))}
97 <td class="td-componentname">
62 </a>
98 ${h.link_to(pull_request.target_repo.repo_name,h.url('summary_home',repo_name=pull_request.target_repo.repo_name))}
63 %if pull_request.is_closed():
99 </td>
64 (${_('Closed')})
100 <td class="user">
65 %endif
101 ${base.gravatar_with_user(pull_request.author.email, 16)}
66 </div>
102 </td>
67 </div>
103 <td class="td-message expand_commit" data-pr-id="p${pull_request.pull_request_id}" title="${_('Expand commit message')}">
104 <div class="show_more_col">
105 <i class="show_more"></i>&nbsp;
106 </div>
107 </td>
108 <td class="mid td-description">
109 <div class="log-container truncate-wrap">
110 <div class="message truncate" id="c-p${pull_request.pull_request_id}"><a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">#${pull_request.pull_request_id}: ${pull_request.title}</a>\
111 %if pull_request.is_closed():
112 &nbsp;(${_('Closed')})\
113 %endif
114 <br/>${pull_request.description}</div>
115 </div>
116 </td>
117
118 <td class="td-time">
119 ${h.age_component(pull_request.created_on)}
120 </td>
121 </tr>
68 %endfor
122 %endfor
123 </table>
69 %else:
124 %else:
70 <li><span class="empty_data">${_('There are currently no open pull requests requiring your participation.')}</span></li>
125 <h2 class="empty_data">${_('There are currently no open pull requests requiring your participation.')}</h2>
71 %endif
126 %endif
72 </div>
127 </div>
73 </div>
128 </div>
@@ -81,5 +136,18 b''
81 else{
136 else{
82 window.location = "${h.url('my_account_pullrequests')}";
137 window.location = "${h.url('my_account_pullrequests')}";
83 }
138 }
84 })
139 });
140 $('.expand_commit').on('click',function(e){
141 var target_expand = $(this);
142 var cid = target_expand.data('prId');
143
144 if (target_expand.hasClass('open')){
145 $('#c-'+cid).css({'height': '2.75em', 'text-overflow': 'ellipsis', 'overflow':'hidden'});
146 target_expand.removeClass('open');
147 }
148 else {
149 $('#c-'+cid).css({'height': 'auto', 'text-overflow': 'initial', 'overflow':'visible'});
150 target_expand.addClass('open');
151 }
152 });
85 </script>
153 </script>
@@ -1,4 +1,6 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%namespace name="base" file="/base/base.html"/>
3
2 <div class="panel panel-default">
4 <div class="panel panel-default">
3 <div class="panel-heading">
5 <div class="panel-heading">
4 <h3 class="panel-title">${_('Settings for Repository Group: %s') % c.repo_group.name}</h3>
6 <h3 class="panel-title">${_('Settings for Repository Group: %s') % c.repo_group.name}</h3>
@@ -16,15 +18,25 b''
16 ${h.text('group_name',class_='medium')}
18 ${h.text('group_name',class_='medium')}
17 </div>
19 </div>
18 </div>
20 </div>
19 <div class="field">
21
22 <div class="field badged-field">
20 <div class="label">
23 <div class="label">
21 <label for="user">${_('Owner')}:</label>
24 <label for="user">${_('Owner')}:</label>
22 </div>
25 </div>
23 <div class="input">
26 <div class="input">
24 ${h.text('user', class_="medium", autocomplete="off")}
27 <div class="badge-input-container">
25 <span class="help-block">${_('Change Repository Group Owner.')}</span>
28 <div class="user-badge">
29 ${base.gravatar_with_user(c.repo_group.user.email, show_disabled=not c.repo_group.user.active)}
30 </div>
31 <div class="badge-input-wrap">
32 ${h.text('user', class_="medium", autocomplete="off")}
33 </div>
34 </div>
35 <form:error name="user"/>
36 <p class="help-block">${_('Change owner of this repository group.')}</p>
26 </div>
37 </div>
27 </div>
38 </div>
39
28 <div class="field">
40 <div class="field">
29 <div class="label label-textarea">
41 <div class="label label-textarea">
30 <label for="group_description">${_('Description')}:</label>
42 <label for="group_description">${_('Description')}:</label>
@@ -1,3 +1,6 b''
1 ## -*- coding: utf-8 -*-
2 <%namespace name="base" file="/base/base.html"/>
3
1 <div class="panel panel-default">
4 <div class="panel panel-default">
2 <div class="panel-heading">
5 <div class="panel-heading">
3 <h3 class="panel-title">${_('Settings for Repository: %s') % c.repo_info.repo_name}</h3>
6 <h3 class="panel-title">${_('Settings for Repository: %s') % c.repo_info.repo_name}</h3>
@@ -69,15 +72,25 b''
69 <p class="help-block">${_('Default commit for files page, downloads, whoosh and readme')}</p>
72 <p class="help-block">${_('Default commit for files page, downloads, whoosh and readme')}</p>
70 </div>
73 </div>
71 </div>
74 </div>
72 <div class="field">
75
76 <div class="field badged-field">
73 <div class="label">
77 <div class="label">
74 <label for="user">${_('Owner')}:</label>
78 <label for="user">${_('Owner')}:</label>
75 </div>
79 </div>
76 <div class="input">
80 <div class="input">
77 ${h.text('user', class_="medium", autocomplete="off")}
81 <div class="badge-input-container">
78 <p class="help-block">${_('Change owner of this repository.')}</p>
82 <div class="user-badge">
83 ${base.gravatar_with_user(c.repo_info.user.email, show_disabled=not c.repo_info.user.active)}
84 </div>
85 <div class="badge-input-wrap">
86 ${h.text('user', class_="medium", autocomplete="off")}
87 </div>
88 </div>
89 <form:error name="user"/>
90 <p class="help-block">${_('Change owner of this repository.')}</p>
79 </div>
91 </div>
80 </div>
92 </div>
93
81 <div class="field">
94 <div class="field">
82 <div class="label label-textarea">
95 <div class="label label-textarea">
83 <label for="repo_description">${_('Description')}:</label>
96 <label for="repo_description">${_('Description')}:</label>
@@ -20,6 +20,7 b''
20 <td>
20 <td>
21 ${h.literal(', '.join([
21 ${h.literal(', '.join([
22 '<a href="%(link)s" title="%(name)s">%(name)s</a>' % {'link':link, 'name':name}
22 '<a href="%(link)s" title="%(name)s">%(name)s</a>' % {'link':link, 'name':name}
23 if link else name
23 for name,link in licenses.items()]))}
24 for name,link in licenses.items()]))}
24 </td>
25 </td>
25 </tr>
26 </tr>
@@ -45,12 +45,15 b''
45 <div class="panel panel-default">
45 <div class="panel panel-default">
46 <div class="panel-heading">
46 <div class="panel-heading">
47 <h3 class="panel-title">${_('System Info')}</h3>
47 <h3 class="panel-title">${_('System Info')}</h3>
48 % if c.allowed_to_snapshot:
49 <a href="${url('admin_settings_system', snapshot=1)}" class="panel-edit">${_('create snapshot')}</a>
50 % endif
48 </div>
51 </div>
49 <div class="panel-body">
52 <div class="panel-body">
50 <dl class="dl-horizontal settings">
53 <dl class="dl-horizontal settings">
51 %for dt, dd, tt in elems:
54 %for dt, dd, tt in elems:
52 <dt >${dt}:</dt>
55 <dt>${dt}:</dt>
53 <dd title="${tt}">${dd}</dd>
56 <dd title="${tt}">${dd}</dd>
54 %endfor
57 %endfor
55 </dl>
58 </dl>
56 </div>
59 </div>
@@ -69,7 +72,7 b''
69 <tbody>
72 <tbody>
70 %for key, value in c.py_modules:
73 %for key, value in c.py_modules:
71 <tr>
74 <tr>
72 <td >${key}</td>
75 <td>${key}</td>
73 <td>${value}</td>
76 <td>${value}</td>
74 </tr>
77 </tr>
75 %endfor
78 %endfor
@@ -1,3 +1,6 b''
1 ## -*- coding: utf-8 -*-
2 <%namespace name="base" file="/base/base.html"/>
3
1 <div class="panel panel-default">
4 <div class="panel panel-default">
2 <div class="panel-heading">
5 <div class="panel-heading">
3 <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3>
6 <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3>
@@ -15,15 +18,25 b''
15 ${h.text('users_group_name',class_='medium')}
18 ${h.text('users_group_name',class_='medium')}
16 </div>
19 </div>
17 </div>
20 </div>
18 <div class="field">
21
22 <div class="field badged-field">
19 <div class="label">
23 <div class="label">
20 <label for="user">${_('Owner')}:</label>
24 <label for="user">${_('Owner')}:</label>
21 </div>
25 </div>
22 <div class="input">
26 <div class="input">
23 ${h.text('user', class_="medium", autocomplete="off")}
27 <div class="badge-input-container">
24 <span class="help-block">${_('Change owner of this user group.')}</span>
28 <div class="user-badge">
29 ${base.gravatar_with_user(c.user_group.user.email, show_disabled=not c.user_group.user.active)}
30 </div>
31 <div class="badge-input-wrap">
32 ${h.text('user', class_="medium", autocomplete="off")}
33 </div>
34 </div>
35 <form:error name="user"/>
36 <p class="help-block">${_('Change owner of this user group.')}</p>
25 </div>
37 </div>
26 </div>
38 </div>
39
27 <div class="field">
40 <div class="field">
28 <div class="label label-textarea">
41 <div class="label label-textarea">
29 <label for="user_group_description">${_('Description')}:</label>
42 <label for="user_group_description">${_('Description')}:</label>
@@ -128,7 +128,6 b''
128 </div>
128 </div>
129 ${h.end_form()}
129 ${h.end_form()}
130 </div>
130 </div>
131 </%def>
132 <script>
131 <script>
133 $(document).ready(function(){
132 $(document).ready(function(){
134 $('#username').focus();
133 $('#username').focus();
@@ -142,3 +141,4 b''
142 })
141 })
143 })
142 })
144 </script>
143 </script>
144 </%def>
@@ -134,10 +134,10 b''
134 </%def>
134 </%def>
135
135
136
136
137 <%def name="gravatar_with_user(contact, size=16)">
137 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
138 <div class="rc-user tooltip" title="${contact}">
138 <div class="rc-user tooltip" title="${contact}">
139 ${self.gravatar(h.email_or_none(contact), size)}
139 ${self.gravatar(h.email_or_none(contact), size)}
140 <span class="user"> ${h.link_to_user(contact)}</span>
140 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
141 </div>
141 </div>
142 </%def>
142 </%def>
143
143
@@ -195,7 +195,7 b''
195 %if repo_instance.clone_uri:
195 %if repo_instance.clone_uri:
196 <p>
196 <p>
197 <i class="icon-code-fork"></i> ${_('Clone from')}
197 <i class="icon-code-fork"></i> ${_('Clone from')}
198 <a href="${h.url(str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
198 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
199 </p>
199 </p>
200 %endif
200 %endif
201
201
@@ -13,9 +13,10 b' A new user `${user.username}` has regist'
13 - Username: ${user.username}
13 - Username: ${user.username}
14 - Full Name: ${user.firstname} ${user.lastname}
14 - Full Name: ${user.firstname} ${user.lastname}
15 - Email: ${user.email}
15 - Email: ${user.email}
16 - Profile link: ${h.url('user_profile', username=user.username, qualified=True)}
16 </%def>
17 </%def>
17
18
18 ## BODY GOES BELOW
19 ## BODY GOES BELOW
19 <div style="white-space: pre-wrap">
20 <div style="white-space: pre-wrap">
20 ${body_plaintext()}
21 ${body_plaintext()}
21 </div> No newline at end of file
22 </div>
@@ -27,7 +27,7 b''
27 <div class="left-column">
27 <div class="left-column">
28 <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/>
28 <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/>
29 </div>
29 </div>
30
30 <%block name="above_login_button" />
31 <div id="login" class="right-column">
31 <div id="login" class="right-column">
32 <%include file="/base/flash_msg.html"/>
32 <%include file="/base/flash_msg.html"/>
33 <!-- login -->
33 <!-- login -->
@@ -47,9 +47,9 b''
47 <ul class="nav nav-pills nav-stacked">
47 <ul class="nav nav-pills nav-stacked">
48 <li class="${'active' if c.active=='open' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0)}">${_('Opened')}</a></li>
48 <li class="${'active' if c.active=='open' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0)}">${_('Opened')}</a></li>
49 <li class="${'active' if c.active=='my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,my=1)}">${_('Opened by me')}</a></li>
49 <li class="${'active' if c.active=='my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,my=1)}">${_('Opened by me')}</a></li>
50 <li class="${'active' if c.active=='awaiting' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_review=1)}">${_('Awaiting review')}</a></li>
50 <li class="${'active' if c.active=='awaiting_my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_my_review=1)}">${_('Awaiting my review')}</a></li>
51 <li class="${'active' if c.active=='awaiting_my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_my_review=1)}">${_('Awaiting my review')}</a></li>
51 <li class="${'active' if c.active=='closed' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,closed=1)}">${_('Closed')}</a></li>
52 <li class="${'active' if c.active=='closed' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,closed=1)}">${_('Closed')}</a></li>
52 <li class="${'active' if c.active=='awaiting' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_review=1)}">${_('Awaiting review')}</a></li>
53 <li class="${'active' if c.active=='source' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=1)}">${_('From this repo')}</a></li>
53 <li class="${'active' if c.active=='source' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=1)}">${_('From this repo')}</a></li>
54 </ul>
54 </ul>
55 </div>
55 </div>
@@ -27,7 +27,7 b''
27 <div class="left-column">
27 <div class="left-column">
28 <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/>
28 <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/>
29 </div>
29 </div>
30
30 <%block name="above_register_button" />
31 <div id="register" class="right-column">
31 <div id="register" class="right-column">
32 <%include file="/base/flash_msg.html"/>
32 <%include file="/base/flash_msg.html"/>
33 <!-- login -->
33 <!-- login -->
@@ -85,9 +85,12 b' class TestMyAccountController(TestContro'
85 response = self.app.get(url('my_account_pullrequests'))
85 response = self.app.get(url('my_account_pullrequests'))
86 response.mustcontain('You currently have no open pull requests.')
86 response.mustcontain('You currently have no open pull requests.')
87
87
88 pr = pr_util.create_pull_request()
88 pr = pr_util.create_pull_request(title='TestMyAccountPR')
89 response = self.app.get(url('my_account_pullrequests'))
89 response = self.app.get(url('my_account_pullrequests'))
90 response.mustcontain('Pull request #%d opened' % pr.pull_request_id)
90 response.mustcontain('There are currently no open pull requests '
91 'requiring your participation')
92
93 response.mustcontain('#%s: TestMyAccountPR' % pr.pull_request_id)
91
94
92 def test_my_account_my_emails(self):
95 def test_my_account_my_emails(self):
93 self.log_user()
96 self.log_user()
@@ -460,6 +460,10 b' class TestLabsSettings(object):'
460
460
461 @pytest.mark.usefixtures('app')
461 @pytest.mark.usefixtures('app')
462 class TestOpenSourceLicenses(object):
462 class TestOpenSourceLicenses(object):
463
464 def _get_url(self):
465 return ADMIN_PREFIX + '/settings/open_source'
466
463 def test_records_are_displayed(self, autologin_user):
467 def test_records_are_displayed(self, autologin_user):
464 sample_licenses = {
468 sample_licenses = {
465 "python2.7-pytest-2.7.1": {
469 "python2.7-pytest-2.7.1": {
@@ -470,11 +474,10 b' class TestOpenSourceLicenses(object):'
470 }
474 }
471 }
475 }
472 read_licenses_patch = mock.patch(
476 read_licenses_patch = mock.patch(
473 'rhodecode.controllers.admin.settings.read_opensource_licenses',
477 'rhodecode.admin.views.read_opensource_licenses',
474 return_value=sample_licenses)
478 return_value=sample_licenses)
475 with read_licenses_patch:
479 with read_licenses_patch:
476 response = self.app.get(
480 response = self.app.get(self._get_url(), status=200)
477 url('admin_settings_open_source'), status=200)
478
481
479 assert_response = AssertResponse(response)
482 assert_response = AssertResponse(response)
480 assert_response.element_contains(
483 assert_response.element_contains(
@@ -485,14 +488,13 b' class TestOpenSourceLicenses(object):'
485 assert_response.element_contains('.panel-body', license)
488 assert_response.element_contains('.panel-body', license)
486
489
487 def test_records_can_be_read(self, autologin_user):
490 def test_records_can_be_read(self, autologin_user):
488 response = self.app.get(url('admin_settings_open_source'), status=200)
491 response = self.app.get(self._get_url(), status=200)
489 assert_response = AssertResponse(response)
492 assert_response = AssertResponse(response)
490 assert_response.element_contains(
493 assert_response.element_contains(
491 '.panel-heading', 'Licenses of Third Party Packages')
494 '.panel-heading', 'Licenses of Third Party Packages')
492
495
493 def test_forbidden_when_normal_user(self, autologin_regular_user):
496 def test_forbidden_when_normal_user(self, autologin_regular_user):
494 self.app.get(
497 self.app.get(self._get_url(), status=403)
495 url('admin_settings_open_source'), status=403)
496
498
497
499
498 @pytest.mark.usefixtures("app")
500 @pytest.mark.usefixtures("app")
@@ -33,7 +33,7 b' class TestFeedController(TestController)'
33 assert """<rss version="2.0">""" in response
33 assert """<rss version="2.0">""" in response
34
34
35 def test_rss_with_auth_token(self, backend):
35 def test_rss_with_auth_token(self, backend):
36 auth_token = User.get_first_admin().feed_token
36 auth_token = User.get_first_super_admin().feed_token
37 assert auth_token != ''
37 assert auth_token != ''
38 response = self.app.get(url(controller='feed', action='rss',
38 response = self.app.get(url(controller='feed', action='rss',
39 repo_name=backend.repo_name, auth_token=auth_token))
39 repo_name=backend.repo_name, auth_token=auth_token))
@@ -110,10 +110,12 b' class TestHomeController(TestController)'
110 def test_index_show_version(self, autologin_user, name, state):
110 def test_index_show_version(self, autologin_user, name, state):
111 version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__
111 version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__
112
112
113 show = SettingsModel().get_setting_by_name('show_version')
113 sett = SettingsModel().create_or_update_setting(
114 show.app_settings_value = state
114 'show_version', state, 'bool')
115 Session().add(show)
115 Session().add(sett)
116 Session().commit()
116 Session().commit()
117 SettingsModel().invalidate_settings_cache()
118
117 response = self.app.get(url(controller='home', action='index'))
119 response = self.app.get(url(controller='home', action='index'))
118 if state is True:
120 if state is True:
119 response.mustcontain(version_string)
121 response.mustcontain(version_string)
@@ -133,6 +135,18 b' class TestUserAutocompleteData(TestContr'
133 values = [suggestion['value'] for suggestion in result['suggestions']]
135 values = [suggestion['value'] for suggestion in result['suggestions']]
134 assert user_name in values
136 assert user_name in values
135
137
138 def test_returns_inactive_users_when_active_flag_sent(self, user_util):
139 self.log_user()
140 user = user_util.create_user(is_active=False)
141 user_name = user.username
142 response = self.app.get(
143 url(controller='home', action='user_autocomplete_data',
144 user_groups='true', active='0'),
145 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
146 result = json.loads(response.body)
147 values = [suggestion['value'] for suggestion in result['suggestions']]
148 assert user_name in values
149
136 def test_returns_groups_when_user_groups_sent(self, user_util):
150 def test_returns_groups_when_user_groups_sent(self, user_util):
137 self.log_user()
151 self.log_user()
138 group = user_util.create_user_group(user_groups_active=True)
152 group = user_util.create_user_group(user_groups_active=True)
@@ -173,8 +187,10 b' class TestUserAutocompleteData(TestContr'
173 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
187 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
174
188
175 result = json.loads(response.body)
189 result = json.loads(response.body)
176 users_mock.assert_called_once_with(name_contains=query)
190 users_mock.assert_called_once_with(
177 groups_mock.assert_called_once_with(name_contains=query)
191 name_contains=query, only_active=True)
192 groups_mock.assert_called_once_with(
193 name_contains=query, only_active=True)
178 assert len(result['suggestions']) == 20
194 assert len(result['suggestions']) == 20
179
195
180
196
@@ -448,7 +448,7 b' class TestLoginController:'
448 assert [] == whitelist['api_access_controllers_whitelist']
448 assert [] == whitelist['api_access_controllers_whitelist']
449 if test_name == 'proper_auth_token':
449 if test_name == 'proper_auth_token':
450 # use builtin if api_key is None
450 # use builtin if api_key is None
451 auth_token = User.get_first_admin().api_key
451 auth_token = User.get_first_super_admin().api_key
452
452
453 with fixture.anon_access(False):
453 with fixture.anon_access(False):
454 self.app.get(url(controller='changeset',
454 self.app.get(url(controller='changeset',
@@ -471,7 +471,7 b' class TestLoginController:'
471 assert ['ChangesetController:changeset_raw'] == \
471 assert ['ChangesetController:changeset_raw'] == \
472 whitelist['api_access_controllers_whitelist']
472 whitelist['api_access_controllers_whitelist']
473 if test_name == 'proper_auth_token':
473 if test_name == 'proper_auth_token':
474 auth_token = User.get_first_admin().api_key
474 auth_token = User.get_first_super_admin().api_key
475
475
476 with fixture.anon_access(False):
476 with fixture.anon_access(False):
477 self.app.get(url(controller='changeset',
477 self.app.get(url(controller='changeset',
@@ -19,36 +19,35 b''
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 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
22 from pyramid.response import Response
23 from pyramid.testing import DummyRequest
24 from rhodecode.lib.middleware.disable_vcs import (
25 DisableVCSPagesWrapper, VCSServerUnavailable)
23
26
24
27
25 @pytest.mark.parametrize('url, expected_url', [
28 @pytest.mark.parametrize('url, should_raise', [
26 ('/', '/'),
29 ('/', False),
27 ('/_admin/settings', '/_admin/settings'),
30 ('/_admin/settings', False),
28 ('/_admin/i_am_fine', '/_admin/i_am_fine'),
31 ('/_admin/i_am_fine', False),
29 ('/_admin/settings/mappings', '/error/vcs_unavailable'),
32 ('/_admin/settings/mappings', True),
30 ('/_admin/my_account/repos', '/error/vcs_unavailable'),
33 ('/_admin/my_account/repos', True),
31 ('/_admin/create_repository', '/error/vcs_unavailable'),
34 ('/_admin/create_repository', True),
32 ('/_admin/gists/1', '/error/vcs_unavailable'),
35 ('/_admin/gists/1', True),
33 ('/_admin/notifications/1', '/error/vcs_unavailable'),
36 ('/_admin/notifications/1', True),
34 ])
37 ])
35 def test_vcs_disabled(url, expected_url):
38 def test_vcs_disabled(url, should_raise):
36 app = DisableVCSPagesWrapper(app=SimpleApp())
39 wrapped_view = DisableVCSPagesWrapper(pyramid_view)
37 assert expected_url == app(get_environ(url), None)
40 request = DummyRequest(path=url)
38
39
41
40 def get_environ(url):
42 if should_raise:
41 """Construct a minimum WSGI environ based on the URL."""
43 with pytest.raises(VCSServerUnavailable):
42 environ = {
44 response = wrapped_view(None, request)
43 'PATH_INFO': url,
45 else:
44 }
46 response = wrapped_view(None, request)
45 return environ
47 assert response.status_int == 200
46
47
48
48 class SimpleApp(object):
49 def pyramid_view(context, request):
49 """
50 """
50 A mock app to be used in the wrapper that returns the modified URL
51 A mock pyramid view to be used in the wrapper
51 from the middleware
52 """
52 """
53 def __call__(self, environ, start_response):
53 return Response('success')
54 return environ['PATH_INFO']
@@ -20,7 +20,8 b''
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.lib.encrypt import AESCipher
23 from rhodecode.lib.encrypt import (
24 AESCipher, SignatureVerificationError, InvalidDecryptedValue)
24
25
25
26
26 class TestEncryptModule(object):
27 class TestEncryptModule(object):
@@ -38,3 +39,38 b' class TestEncryptModule(object):'
38 def test_encryption(self, key, text):
39 def test_encryption(self, key, text):
39 enc = AESCipher(key).encrypt(text)
40 enc = AESCipher(key).encrypt(text)
40 assert AESCipher(key).decrypt(enc) == text
41 assert AESCipher(key).decrypt(enc) == text
42
43 def test_encryption_with_hmac(self):
44 key = 'secret'
45 text = 'ihatemysql'
46 enc = AESCipher(key, hmac=True).encrypt(text)
47 assert AESCipher(key, hmac=True).decrypt(enc) == text
48
49 def test_encryption_with_hmac_with_bad_key(self):
50 key = 'secretstring'
51 text = 'ihatemysql'
52 enc = AESCipher(key, hmac=True).encrypt(text)
53
54 with pytest.raises(SignatureVerificationError) as e:
55 assert AESCipher('differentsecret', hmac=True).decrypt(enc) == ''
56
57 assert 'Encryption signature verification failed' in str(e)
58
59 def test_encryption_with_hmac_with_bad_data(self):
60 key = 'secret'
61 text = 'ihatemysql'
62 enc = AESCipher(key, hmac=True).encrypt(text)
63 enc = 'xyz' + enc[3:]
64 with pytest.raises(SignatureVerificationError) as e:
65 assert AESCipher(key, hmac=True).decrypt(enc) == text
66
67 assert 'Encryption signature verification failed' in str(e)
68
69 def test_encryption_with_hmac_with_bad_key_not_strict(self):
70 key = 'secretstring'
71 text = 'ihatemysql'
72 enc = AESCipher(key, hmac=True).encrypt(text)
73
74 assert isinstance(AESCipher(
75 'differentsecret', hmac=True, strict_verification=False
76 ).decrypt(enc), InvalidDecryptedValue)
@@ -84,8 +84,12 b' def test_process_patterns_repo(backend, '
84 'pref': '#',
84 'pref': '#',
85 }
85 }
86 }
86 }
87
88 def get_settings_mock(self, cache=True):
89 return config
90
87 with mock.patch.object(IssueTrackerSettingsModel,
91 with mock.patch.object(IssueTrackerSettingsModel,
88 'get_settings', lambda s: config):
92 'get_settings', get_settings_mock):
89 processed_text = helpers.process_patterns(
93 processed_text = helpers.process_patterns(
90 text_string, repo.repo_name, config)
94 text_string, repo.repo_name, config)
91
95
@@ -106,8 +110,12 b' def test_process_patterns_no_repo(text_s'
106 'pref': '#',
110 'pref': '#',
107 }
111 }
108 }
112 }
113
114 def get_settings_mock(self, cache=True):
115 return config
116
109 with mock.patch.object(IssueTrackerSettingsModel,
117 with mock.patch.object(IssueTrackerSettingsModel,
110 'get_global_settings', lambda s, cache: config):
118 'get_global_settings', get_settings_mock):
111 processed_text = helpers.process_patterns(
119 processed_text = helpers.process_patterns(
112 text_string, '', config)
120 text_string, '', config)
113
121
@@ -126,8 +134,12 b' def test_process_patterns_non_existent_r'
126 'pref': '#',
134 'pref': '#',
127 }
135 }
128 }
136 }
137
138 def get_settings_mock(self, cache=True):
139 return config
140
129 with mock.patch.object(IssueTrackerSettingsModel,
141 with mock.patch.object(IssueTrackerSettingsModel,
130 'get_global_settings', lambda s, cache: config):
142 'get_global_settings', get_settings_mock):
131 processed_text = helpers.process_patterns(
143 processed_text = helpers.process_patterns(
132 text_string, 'do-not-exist', config)
144 text_string, 'do-not-exist', config)
133
145
@@ -182,10 +194,12 b' def test_get_matching_offsets(test_text,'
182 assert helpers.get_matching_offsets(
194 assert helpers.get_matching_offsets(
183 test_text, text_phrases) == expected_output
195 test_text, text_phrases) == expected_output
184
196
197
185 def test_normalize_text_for_matching():
198 def test_normalize_text_for_matching():
186 assert helpers.normalize_text_for_matching(
199 assert helpers.normalize_text_for_matching(
187 'OJjfe)*#$*@)$JF*)3r2f80h') == 'ojjfe jf 3r2f80h'
200 'OJjfe)*#$*@)$JF*)3r2f80h') == 'ojjfe jf 3r2f80h'
188
201
202
189 def test_get_matching_line_offsets():
203 def test_get_matching_line_offsets():
190 assert helpers.get_matching_line_offsets([
204 assert helpers.get_matching_line_offsets([
191 'words words words',
205 'words words words',
@@ -193,4 +207,4 b' def test_get_matching_line_offsets():'
193 'some text some',
207 'some text some',
194 'words words words',
208 'words words words',
195 'words words words',
209 'words words words',
196 'text here what'], 'text') == {3: [(5, 9)], 6: [(0, 4)]} No newline at end of file
210 'text here what'], 'text') == {3: [(5, 9)], 6: [(0, 4)]}
@@ -29,6 +29,7 b' import pytest'
29 from rhodecode.lib import caching_query
29 from rhodecode.lib import caching_query
30 from rhodecode.lib import utils
30 from rhodecode.lib import utils
31 from rhodecode.lib.utils2 import md5
31 from rhodecode.lib.utils2 import md5
32 from rhodecode.model import settings
32 from rhodecode.model import db
33 from rhodecode.model import db
33 from rhodecode.model import meta
34 from rhodecode.model import meta
34 from rhodecode.model.repo import RepoModel
35 from rhodecode.model.repo import RepoModel
@@ -402,7 +403,7 b' class TestConfigDataFromDb(object):'
402 ]
403 ]
403 repo_name = 'test_repo'
404 repo_name = 'test_repo'
404
405
405 model_patch = mock.patch.object(utils, 'VcsSettingsModel')
406 model_patch = mock.patch.object(settings, 'VcsSettingsModel')
406 hooks_patch = mock.patch.object(
407 hooks_patch = mock.patch.object(
407 utils, 'get_enabled_hook_classes',
408 utils, 'get_enabled_hook_classes',
408 return_value=['pull', 'push', 'repo_size'])
409 return_value=['pull', 'push', 'repo_size'])
@@ -432,7 +432,13 b' def test_get_repo_by_id(test, expected):'
432 assert _test == expected
432 assert _test == expected
433
433
434
434
435 def test_invalidation_context(pylonsapp):
435 @pytest.mark.parametrize("test_repo_name, repo_type", [
436 ("test_repo_1", None),
437 ("repo_group/foobar", None),
438 ("test_non_asci_ąćę", None),
439 (u"test_non_asci_unicode_ąćę", None),
440 ])
441 def test_invalidation_context(pylonsapp, test_repo_name, repo_type):
436 from beaker.cache import cache_region
442 from beaker.cache import cache_region
437 from rhodecode.lib import caches
443 from rhodecode.lib import caches
438 from rhodecode.model.db import CacheKey
444 from rhodecode.model.db import CacheKey
@@ -442,7 +448,7 b' def test_invalidation_context(pylonsapp)'
442 return 'result'
448 return 'result'
443
449
444 invalidator_context = CacheKey.repo_context_cache(
450 invalidator_context = CacheKey.repo_context_cache(
445 _dummy_func, 'test_repo_1', 'repo')
451 _dummy_func, test_repo_name, 'repo')
446
452
447 with invalidator_context as context:
453 with invalidator_context as context:
448 invalidated = context.invalidate()
454 invalidated = context.invalidate()
@@ -452,6 +458,8 b' def test_invalidation_context(pylonsapp)'
452 assert 'result' == result
458 assert 'result' == result
453 assert isinstance(context, caches.FreshRegionCache)
459 assert isinstance(context, caches.FreshRegionCache)
454
460
461 assert 'InvalidationContext' in repr(invalidator_context)
462
455 with invalidator_context as context:
463 with invalidator_context as context:
456 context.invalidate()
464 context.invalidate()
457 result = context.compute()
465 result = context.compute()
@@ -58,30 +58,43 b' def stub_session():'
58 return session
58 return session
59
59
60
60
61 def test_repo_maker_uses_session_for_classmethods(stub_session):
61 @pytest.fixture
62 def stub_session_factory(stub_session):
63 """
64 Stub of `rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory`.
65 """
66 session_factory = mock.Mock()
67 session_factory.return_value = stub_session
68 return session_factory
69
70
71 def test_repo_maker_uses_session_for_classmethods(stub_session_factory):
62 repo_maker = client_http.RepoMaker(
72 repo_maker = client_http.RepoMaker(
63 'server_and_port', 'endpoint', stub_session)
73 'server_and_port', 'endpoint', stub_session_factory)
64 repo_maker.example_call()
74 repo_maker.example_call()
65 stub_session.post.assert_called_with(
75 stub_session_factory().post.assert_called_with(
66 'http://server_and_port/endpoint', data=mock.ANY)
76 'http://server_and_port/endpoint', data=mock.ANY)
67
77
68
78
69 def test_repo_maker_uses_session_for_instance_methods(
79 def test_repo_maker_uses_session_for_instance_methods(
70 stub_session, config):
80 stub_session_factory, config):
71 repo_maker = client_http.RepoMaker(
81 repo_maker = client_http.RepoMaker(
72 'server_and_port', 'endpoint', stub_session)
82 'server_and_port', 'endpoint', stub_session_factory)
73 repo = repo_maker('stub_path', config)
83 repo = repo_maker('stub_path', config)
74 repo.example_call()
84 repo.example_call()
75 stub_session.post.assert_called_with(
85 stub_session_factory().post.assert_called_with(
76 'http://server_and_port/endpoint', data=mock.ANY)
86 'http://server_and_port/endpoint', data=mock.ANY)
77
87
78
88
89 @mock.patch('rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory')
79 @mock.patch('rhodecode.lib.vcs.connection')
90 @mock.patch('rhodecode.lib.vcs.connection')
80 def test_connect_passes_in_the_same_session(connection, stub_session):
91 def test_connect_passes_in_the_same_session(
81 session_factory_patcher = mock.patch.object(
92 connection, session_factory_class, stub_session):
82 vcs, '_create_http_rpc_session', return_value=stub_session)
93 session_factory = session_factory_class.return_value
83 with session_factory_patcher:
94 session_factory.return_value = stub_session
84 vcs.connect_http('server_and_port')
95
85 assert connection.Hg._session == stub_session
96 vcs.connect_http('server_and_port')
86 assert connection.Svn._session == stub_session
97
87 assert connection.Git._session == stub_session
98 assert connection.Hg._session_factory() == stub_session
99 assert connection.Svn._session_factory() == stub_session
100 assert connection.Git._session_factory() == stub_session
@@ -69,7 +69,6 b' def pylons_compatibility_tween_factory(h'
69 context.rhodecode_user = auth_user
69 context.rhodecode_user = auth_user
70 attach_context_attributes(context)
70 attach_context_attributes(context)
71 pylons.tmpl_context._push_object(context)
71 pylons.tmpl_context._push_object(context)
72
73 return handler(request)
72 return handler(request)
74 finally:
73 finally:
75 # Dispose current database session and rollback uncommitted
74 # Dispose current database session and rollback uncommitted
@@ -518,7 +518,7 b' vcs.connection_timeout = 3600'
518 ### LOGGING CONFIGURATION ####
518 ### LOGGING CONFIGURATION ####
519 ################################
519 ################################
520 [loggers]
520 [loggers]
521 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates, whoosh_indexer
521 keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates
522
522
523 [handlers]
523 [handlers]
524 keys = console, console_sql
524 keys = console, console_sql
@@ -570,12 +570,6 b' handlers = console_sql'
570 qualname = sqlalchemy.engine
570 qualname = sqlalchemy.engine
571 propagate = 0
571 propagate = 0
572
572
573 [logger_whoosh_indexer]
574 level = DEBUG
575 handlers =
576 qualname = whoosh_indexer
577 propagate = 1
578
579 ##############
573 ##############
580 ## HANDLERS ##
574 ## HANDLERS ##
581 ##############
575 ##############
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
General Comments 0
You need to be logged in to leave comments. Login now