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 |
@@ -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 |
@@ -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 | 1 | [bumpversion] |
|
2 |
current_version = 4. |
|
|
2 | current_version = 4.2.0 | |
|
3 | 3 | message = release: Bump version {current_version} to {new_version} |
|
4 | 4 | |
|
5 | 5 | [bumpversion:file:rhodecode/VERSION] |
@@ -1,32 +1,26 b'' | |||
|
1 | 1 | [DEFAULT] |
|
2 | 2 | done = false |
|
3 | 3 | |
|
4 | [task:fixes_on_stable] | |
|
5 | ||
|
6 | [task:changelog_updated] | |
|
7 | ||
|
4 | 8 | [task:bump_version] |
|
5 | 9 | done = true |
|
6 | 10 | |
|
7 | [task:rc_tools_pinned] | |
|
8 | done = true | |
|
11 | [task:generate_api_docs] | |
|
12 | ||
|
13 | [task:updated_translation] | |
|
9 | 14 | |
|
10 | [task:fixes_on_stable] | |
|
11 | done = true | |
|
15 | [release] | |
|
16 | state = in_progress | |
|
17 | version = 4.2.0 | |
|
18 | ||
|
19 | [task:rc_tools_pinned] | |
|
12 | 20 | |
|
13 | 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 | 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 | 25 | [task:updated_trial_license] |
|
32 | 26 |
@@ -41,6 +41,19 b' The latest sources can be obtained from ' | |||
|
41 | 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 | 57 | RhodeCode Features |
|
45 | 58 | ------------------ |
|
46 | 59 |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | README - Quickstart |
|
2 | 2 | =================== |
|
3 | 3 | |
|
4 |
This folder contains functional tests and |
|
|
4 | This folder contains the functional tests and automation of specification | |
|
5 | 5 | examples. Details about testing can be found in |
|
6 | 6 | `/docs-internal/testing/index.rst`. |
|
7 | 7 | |
@@ -21,7 +21,7 b' Use the following example call for the d' | |||
|
21 | 21 | --api-key=9999999999999999999999999999999999999999 \ |
|
22 | 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 | 25 | defaults from the test run. |
|
26 | 26 | |
|
27 | 27 | |
@@ -34,7 +34,7 b' 1. Make sure your Rhodecode Enterprise i' | |||
|
34 | 34 | 2. Enter `nix-shell` from the acceptance_tests folder:: |
|
35 | 35 | |
|
36 | 36 | cd acceptance_tests |
|
37 |
nix-shell |
|
|
37 | nix-shell | |
|
38 | 38 | |
|
39 | 39 | Make sure that `rcpkgs` and `rcnixpkgs` are available on the nix path. |
|
40 | 40 |
@@ -8,7 +8,6 b'' | |||
|
8 | 8 | |
|
9 | 9 | [DEFAULT] |
|
10 | 10 | debug = true |
|
11 | pdebug = false | |
|
12 | 11 | ################################################################################ |
|
13 | 12 | ## Uncomment and replace with the email address which should receive ## |
|
14 | 13 | ## any error reports after an application crash ## |
@@ -115,11 +114,23 b' rhodecode.api.url = /_admin/api' | |||
|
115 | 114 | |
|
116 | 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 | 126 | full_stack = true |
|
119 | 127 | |
|
120 | 128 | ## Serve static files via RhodeCode, disable to serve them via HTTP server |
|
121 | 129 | static_files = true |
|
122 | 130 | |
|
131 | # autogenerate javascript routes file on startup | |
|
132 | generate_js_files = false | |
|
133 | ||
|
123 | 134 | ## Optional Languages |
|
124 | 135 | ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh |
|
125 | 136 | lang = en |
@@ -380,7 +391,6 b' beaker.session.auto = false' | |||
|
380 | 391 | search.module = rhodecode.lib.index.whoosh |
|
381 | 392 | search.location = %(here)s/data/index |
|
382 | 393 | |
|
383 | ||
|
384 | 394 | ################################### |
|
385 | 395 | ## APPENLIGHT CONFIG ## |
|
386 | 396 | ################################### |
@@ -514,7 +524,7 b' vcs.connection_timeout = 3600' | |||
|
514 | 524 | ### LOGGING CONFIGURATION #### |
|
515 | 525 | ################################ |
|
516 | 526 | [loggers] |
|
517 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
|
527 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
|
518 | 528 | |
|
519 | 529 | [handlers] |
|
520 | 530 | keys = console, console_sql |
@@ -566,12 +576,6 b' handlers = console_sql' | |||
|
566 | 576 | qualname = sqlalchemy.engine |
|
567 | 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 | 580 | ## HANDLERS ## |
|
577 | 581 | ############## |
@@ -8,7 +8,6 b'' | |||
|
8 | 8 | |
|
9 | 9 | [DEFAULT] |
|
10 | 10 | debug = true |
|
11 | pdebug = false | |
|
12 | 11 | ################################################################################ |
|
13 | 12 | ## Uncomment and replace with the email address which should receive ## |
|
14 | 13 | ## any error reports after an application crash ## |
@@ -89,11 +88,23 b' use = egg:rhodecode-enterprise-ce' | |||
|
89 | 88 | ## enable proxy prefix middleware, defined below |
|
90 | 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 | 100 | full_stack = true |
|
93 | 101 | |
|
94 | 102 | ## Serve static files via RhodeCode, disable to serve them via HTTP server |
|
95 | 103 | static_files = true |
|
96 | 104 | |
|
105 | # autogenerate javascript routes file on startup | |
|
106 | generate_js_files = false | |
|
107 | ||
|
97 | 108 | ## Optional Languages |
|
98 | 109 | ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh |
|
99 | 110 | lang = en |
@@ -354,7 +365,6 b' beaker.session.auto = false' | |||
|
354 | 365 | search.module = rhodecode.lib.index.whoosh |
|
355 | 366 | search.location = %(here)s/data/index |
|
356 | 367 | |
|
357 | ||
|
358 | 368 | ################################### |
|
359 | 369 | ## APPENLIGHT CONFIG ## |
|
360 | 370 | ################################### |
@@ -483,7 +493,7 b' vcs.connection_timeout = 3600' | |||
|
483 | 493 | ### LOGGING CONFIGURATION #### |
|
484 | 494 | ################################ |
|
485 | 495 | [loggers] |
|
486 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
|
496 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
|
487 | 497 | |
|
488 | 498 | [handlers] |
|
489 | 499 | keys = console, console_sql |
@@ -535,12 +545,6 b' handlers = console_sql' | |||
|
535 | 545 | qualname = sqlalchemy.engine |
|
536 | 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 | 549 | ## HANDLERS ## |
|
546 | 550 | ############## |
@@ -46,6 +46,7 b' let' | |||
|
46 | 46 | !elem ext ["egg-info" "pyc"] && |
|
47 | 47 | !startsWith "result" path; |
|
48 | 48 | |
|
49 | sources = pkgs.config.rc.sources or {}; | |
|
49 | 50 | rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.; |
|
50 | 51 | |
|
51 | 52 | # Load the generated node packages |
@@ -98,9 +99,11 b' let' | |||
|
98 | 99 | ''; |
|
99 | 100 | in super.rhodecode-enterprise-ce.override (attrs: { |
|
100 | 101 | |
|
101 |
inherit |
|
|
102 | inherit | |
|
103 | doCheck | |
|
104 | version; | |
|
102 | 105 | name = "rhodecode-enterprise-ce-${version}"; |
|
103 | version = version; | |
|
106 | releaseName = "RhodeCodeEnterpriseCE-${version}"; | |
|
104 | 107 | src = rhodecode-enterprise-ce-src; |
|
105 | 108 | |
|
106 | 109 | buildInputs = |
@@ -109,7 +112,7 b' let' | |||
|
109 | 112 | pkgs.nodePackages.grunt-cli |
|
110 | 113 | pkgs.subversion |
|
111 | 114 | pytest-catchlog |
|
112 |
r |
|
|
115 | rhodecode-testdata | |
|
113 | 116 | ]); |
|
114 | 117 | |
|
115 | 118 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [ |
@@ -197,17 +200,22 b' let' | |||
|
197 | 200 | |
|
198 | 201 | }); |
|
199 | 202 | |
|
200 | rc_testdata = self.buildPythonPackage rec { | |
|
201 | name = "rc_testdata-0.7.0"; | |
|
202 | src = pkgs.fetchhg { | |
|
203 | url = "https://code.rhodecode.com/upstream/rc_testdata"; | |
|
204 | rev = "v0.7.0"; | |
|
205 | sha256 = "0w3z0zn8lagr707v67lgys23sl6pbi4xg7pfvdbw58h3q384h6rx"; | |
|
206 | }; | |
|
203 | rhodecode-testdata = import "${rhodecode-testdata-src}/default.nix" { | |
|
204 | inherit | |
|
205 | doCheck | |
|
206 | pkgs | |
|
207 | pythonPackages; | |
|
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 | 219 | # Apply all overrides and fix the final package set |
|
212 | 220 | myPythonPackagesUnfix = |
|
213 | 221 | (extends pythonExternalOverrides |
@@ -47,7 +47,7 b' the ``debug`` level.' | |||
|
47 | 47 | ### LOGGING CONFIGURATION #### |
|
48 | 48 | ################################ |
|
49 | 49 | [loggers] |
|
50 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
|
50 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
|
51 | 51 | |
|
52 | 52 | [handlers] |
|
53 | 53 | keys = console, console_sql, file, file_rotating |
@@ -99,12 +99,6 b' the ``debug`` level.' | |||
|
99 | 99 | qualname = sqlalchemy.engine |
|
100 | 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 | 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 | 12 | .. toctree:: |
|
13 | 13 | :maxdepth: 1 |
|
14 | 14 | |
|
15 | overview | |
|
15 | 16 | testing/index |
|
16 | 17 | dev-setup |
|
17 | 18 | db-schema |
@@ -2,7 +2,7 b'' | |||
|
2 | 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 | 6 | files, apart from configuring the settings pointing to the latest database |
|
7 | 7 | schema. |
|
8 | 8 | |
@@ -11,11 +11,11 b' Database Model and ORM' | |||
|
11 | 11 | ---------------------- |
|
12 | 12 | |
|
13 | 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 | |
|
15 |
here. So, any change to this file |
|
|
14 | fields. Any freshly installed database will be correctly created by the definitions | |
|
15 | here. So, any change to this file will affect the tests without having to change | |
|
16 | 16 | any other file. |
|
17 | 17 | |
|
18 |
A second layer are the busin |
|
|
18 | A second layer are the business classes inside ``rhodecode.model``. | |
|
19 | 19 | |
|
20 | 20 | |
|
21 | 21 | Database Migration |
@@ -30,7 +30,7 b' Three files play a role when creating da' | |||
|
30 | 30 | |
|
31 | 31 | Schema is a snapshot of the database version BEFORE the migration. So, it's |
|
32 | 32 | the initial state before any changes were added. The name convention is |
|
33 |
the latest release version where the snapshot w |
|
|
33 | the latest release version where the snapshot was created, and not the | |
|
34 | 34 | target version of this code. |
|
35 | 35 | |
|
36 | 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 | 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 | 50 | paster upgrade-db <ini-file> |
|
51 | 51 | |
|
52 |
|
|
|
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 | 15 | Enables the section "Style" in the application. This section provides an |
|
16 |
overview of all components which are found in the frontend |
|
|
16 | overview of all components which are found in the frontend of the | |
|
17 | 17 | application. |
|
18 | 18 | |
|
19 | 19 | |
@@ -29,9 +29,9 b' to ease development.' | |||
|
29 | 29 | `[logging]` |
|
30 | 30 | =========== |
|
31 | 31 | |
|
32 | Use this to configure loggig to your current needs. The documentation of | |
|
33 |
Python's `logging` module explains all details. The following snippets |
|
|
34 | useful for day to day development work. | |
|
32 | Use this to configure logging to your current needs. The documentation of | |
|
33 | Python's `logging` module explains all of the details. The following snippets | |
|
34 | are useful for day to day development work. | |
|
35 | 35 | |
|
36 | 36 | |
|
37 | 37 | Mute SQL output |
@@ -1,3 +1,4 b'' | |||
|
1 | .. _dev-setup: | |
|
1 | 2 | |
|
2 | 3 | =================== |
|
3 | 4 | Development setup |
@@ -7,21 +8,21 b'' | |||
|
7 | 8 | RhodeCode Enterprise runs inside a Nix managed environment. This ensures build |
|
8 | 9 | environment dependencies are correctly declared and installed during setup. |
|
9 | 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 | 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 | 22 | $ curl https://nixos.org/nix/install | sh |
|
22 | 23 | |
|
23 |
or go to https://nixos.org/nix/ and follow the |
|
|
24 | Once this is correctly set up on your system you should be able to use the | |
|
24 | or go to https://nixos.org/nix/ and follow the installation instructions. | |
|
25 | Once this is correctly set up on your system, you should be able to use the | |
|
25 | 26 | following commands: |
|
26 | 27 | |
|
27 | 28 | * `nix-env` |
@@ -34,8 +35,8 b' following commands:' | |||
|
34 | 35 | Update your channels frequently by running ``nix-channel --upgrade``. |
|
35 | 36 | |
|
36 | 37 | |
|
37 | Switch nix to latest STABLE channel | |
|
38 | ----------------------------------- | |
|
38 | Switch nix to the latest STABLE channel | |
|
39 | --------------------------------------- | |
|
39 | 40 | |
|
40 | 41 | run:: |
|
41 | 42 | |
@@ -49,7 +50,7 b' Followed by::' | |||
|
49 | 50 | Clone the required repositories |
|
50 | 51 | ------------------------------- |
|
51 | 52 | |
|
52 |
After Nix is set up, clone the RhodeCode Enterprise Community Edition |
|
|
53 | After Nix is set up, clone the RhodeCode Enterprise Community Edition and | |
|
53 | 54 | RhodeCode VCSServer repositories into the same directory. |
|
54 | 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 | 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 | 68 | Enter the Development Shell |
|
67 | 69 | --------------------------- |
|
68 | 70 | |
|
69 |
The final step is to start |
|
|
71 | The final step is to start the development shell. To do this, run the | |
|
70 | 72 | following command from inside the cloned repository:: |
|
71 | 73 | |
|
72 | 74 | cd ~/rhodecode-enterprise-ce |
|
73 |
nix-shell |
|
|
75 | nix-shell | |
|
74 | 76 | |
|
75 | 77 | .. note:: |
|
76 | 78 | |
|
77 | 79 | On the first run, this will take a while to download and optionally compile |
|
78 |
a few things. The |
|
|
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 | 94 | .. note:: |
|
92 | 95 | |
|
93 |
It is recommended to |
|
|
96 | It is recommended to use the name `dev.ini`. | |
|
94 | 97 | |
|
95 | 98 | |
|
96 | 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 | 103 | time operation:: |
|
101 | 104 | |
|
102 | 105 | paster setup-rhodecode dev.ini \ |
@@ -109,7 +112,7 b' Start the Development Server' | |||
|
109 | 112 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
110 | 113 | |
|
111 | 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 | 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 | 139 | Run the Environment Tests |
|
137 | 140 | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
138 | 141 | |
|
139 | Please make sure that the test are passing to verify that your environment is | |
|
140 | set up correctly. More details about the tests are described in: | |
|
141 | :file:`/docs/dev/testing`. | |
|
142 | Please make sure that the tests are passing to verify that your environment is | |
|
143 | set up correctly. RhodeCode uses py.test to run tests. | |
|
144 | Please simply run ``make test`` to run the basic test suite. |
@@ -17,12 +17,12 b'' | |||
|
17 | 17 | Overview |
|
18 | 18 | ======== |
|
19 | 19 | |
|
20 |
We have a quite |
|
|
20 | We have a quite large test suite inside of :file:`rhodecode/tests` which is a mix | |
|
21 | 21 | of unit tests and functional or integration tests. More details are in |
|
22 | 22 | :ref:`test-unit-and-functional`. |
|
23 | 23 | |
|
24 | 24 | |
|
25 |
Apart from that we start to apply "Specification by Example" and maintain |
|
|
26 |
collection of such specifications together with an implementation so that it |
|
|
27 | be validated in an automatic way. The files can be found in | |
|
25 | Apart from that, we are starting to apply "Specification by Example" and maintain | |
|
26 | a collection of such specifications together with an implementation so that it | |
|
27 | can be validated in an automatic way. The files can be found in | |
|
28 | 28 | :file:`acceptance_tests`. More details are in :ref:`test-spec-by-example`. |
@@ -66,10 +66,10 b' Locators' | |||
|
66 | 66 | -------- |
|
67 | 67 | |
|
68 | 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 | 70 | it shall not contain any logic. |
|
71 | 71 | |
|
72 | 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 | |
|
74 |
efficient to have all locators together and update them there instead of |
|
|
75 |
to find |
|
|
73 | for change whenever we work on our templates. In such a case, it is more | |
|
74 | efficient to have all of thelocators together and update them there instead of | |
|
75 | having to find every locator inside of the logic of a page object. |
@@ -27,7 +27,7 b' py.test integration' | |||
|
27 | 27 | The integration with the test runner is based on the following three parts: |
|
28 | 28 | |
|
29 | 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 |
|
|
30 | Pylons web framework. It sets up the Pylons environment based on the given ini | |
|
31 | 31 | file. |
|
32 | 32 | |
|
33 | 33 | Tests which depend on the Pylons environment to be set up must request the |
@@ -9,6 +9,7 b' Release Notes' | |||
|
9 | 9 | .. toctree:: |
|
10 | 10 | :maxdepth: 1 |
|
11 | 11 | |
|
12 | release-notes-4.2.0.rst | |
|
12 | 13 | release-notes-4.1.2.rst |
|
13 | 14 | release-notes-4.1.1.rst |
|
14 | 15 | release-notes-4.1.0.rst |
@@ -34,9 +34,6 b' let' | |||
|
34 | 34 | # figure it out without calling into nix-store. |
|
35 | 35 | enterprise = import ./default.nix { |
|
36 | 36 | doCheck = false; |
|
37 | with_vcsserver = false; | |
|
38 | with_pyramid = false; | |
|
39 | cythonize = false; | |
|
40 | 37 | }; |
|
41 | 38 | |
|
42 | 39 | # For a given derivation, return the list of all dependencies |
@@ -8,10 +8,28 b'' | |||
|
8 | 8 | |
|
9 | 9 | let |
|
10 | 10 | sed = "sed -i"; |
|
11 | localLicenses = { | |
|
12 | repoze = { | |
|
13 | fullName = "Repoze License"; | |
|
14 | url = http://www.repoze.org/LICENSE.txt; | |
|
15 | }; | |
|
16 | }; | |
|
11 | 17 | in |
|
12 | 18 | |
|
13 | 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 | 33 | gnureadline = super.gnureadline.override (attrs: { |
|
16 | 34 | buildInputs = attrs.buildInputs ++ [ |
|
17 | 35 | pkgs.ncurses |
@@ -72,6 +90,9 b' self: super: {' | |||
|
72 | 90 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ |
|
73 | 91 | pkgs.postgresql |
|
74 | 92 | ]; |
|
93 | meta = { | |
|
94 | license = pkgs.lib.licenses.lgpl3Plus; | |
|
95 | }; | |
|
75 | 96 | }); |
|
76 | 97 | |
|
77 | 98 | pycurl = super.pycurl.override (attrs: { |
@@ -83,6 +104,10 b' self: super: {' | |||
|
83 | 104 | substituteInPlace setup.py --replace '--static-libs' '--libs' |
|
84 | 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 | 113 | Pylons = super.Pylons.override (attrs: { |
@@ -101,6 +126,15 b' self: super: {' | |||
|
101 | 126 | # confuses pserve. |
|
102 | 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 | 140 | Pyro4 = super.Pyro4.override (attrs: { |
@@ -117,6 +151,9 b' self: super: {' | |||
|
117 | 151 | propagatedBuildInputs = [ |
|
118 | 152 | pkgs.sqlite |
|
119 | 153 | ]; |
|
154 | meta = { | |
|
155 | license = [ pkgs.lib.licenses.zlib pkgs.lib.licenses.libpng ]; | |
|
156 | }; | |
|
120 | 157 | }); |
|
121 | 158 | |
|
122 | 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 | 269 | # Avoid that setuptools is replaced, this leads to trouble |
|
162 | 270 | # with buildPythonPackage. |
|
163 | 271 | setuptools = basePythonPackages.setuptools; |
@@ -8,6 +8,9 b'' | |||
|
8 | 8 | url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz"; |
|
9 | 9 | md5 = "5264ceb02717843cbc9ffce8e6e06bdb"; |
|
10 | 10 | }; |
|
11 | meta = { | |
|
12 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
13 | }; | |
|
11 | 14 | }; |
|
12 | 15 | Beaker = super.buildPythonPackage { |
|
13 | 16 | name = "Beaker-1.7.0"; |
@@ -18,6 +21,9 b'' | |||
|
18 | 21 | url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz"; |
|
19 | 22 | md5 = "386be3f7fe427358881eee4622b428b3"; |
|
20 | 23 | }; |
|
24 | meta = { | |
|
25 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
26 | }; | |
|
21 | 27 | }; |
|
22 | 28 | CProfileV = super.buildPythonPackage { |
|
23 | 29 | name = "CProfileV-1.0.6"; |
@@ -28,6 +34,9 b'' | |||
|
28 | 34 | url = "https://pypi.python.org/packages/eb/df/983a0b6cfd3ac94abf023f5011cb04f33613ace196e33f53c86cf91850d5/CProfileV-1.0.6.tar.gz"; |
|
29 | 35 | md5 = "08c7c242b6e64237bc53c5d13537e03d"; |
|
30 | 36 | }; |
|
37 | meta = { | |
|
38 | license = [ pkgs.lib.licenses.mit ]; | |
|
39 | }; | |
|
31 | 40 | }; |
|
32 | 41 | Fabric = super.buildPythonPackage { |
|
33 | 42 | name = "Fabric-1.10.0"; |
@@ -38,6 +47,9 b'' | |||
|
38 | 47 | url = "https://pypi.python.org/packages/e3/5f/b6ebdb5241d5ec9eab582a5c8a01255c1107da396f849e538801d2fe64a5/Fabric-1.10.0.tar.gz"; |
|
39 | 48 | md5 = "2cb96473387f0e7aa035210892352f4a"; |
|
40 | 49 | }; |
|
50 | meta = { | |
|
51 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
52 | }; | |
|
41 | 53 | }; |
|
42 | 54 | FormEncode = super.buildPythonPackage { |
|
43 | 55 | name = "FormEncode-1.2.4"; |
@@ -48,6 +60,9 b'' | |||
|
48 | 60 | url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz"; |
|
49 | 61 | md5 = "6bc17fb9aed8aea198975e888e2077f4"; |
|
50 | 62 | }; |
|
63 | meta = { | |
|
64 | license = [ pkgs.lib.licenses.psfl ]; | |
|
65 | }; | |
|
51 | 66 | }; |
|
52 | 67 | Jinja2 = super.buildPythonPackage { |
|
53 | 68 | name = "Jinja2-2.7.3"; |
@@ -58,6 +73,9 b'' | |||
|
58 | 73 | url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz"; |
|
59 | 74 | md5 = "b9dffd2f3b43d673802fe857c8445b1a"; |
|
60 | 75 | }; |
|
76 | meta = { | |
|
77 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
78 | }; | |
|
61 | 79 | }; |
|
62 | 80 | Mako = super.buildPythonPackage { |
|
63 | 81 | name = "Mako-1.0.1"; |
@@ -68,6 +86,9 b'' | |||
|
68 | 86 | url = "https://pypi.python.org/packages/8e/a4/aa56533ecaa5f22ca92428f74e074d0c9337282933c722391902c8f9e0f8/Mako-1.0.1.tar.gz"; |
|
69 | 87 | md5 = "9f0aafd177b039ef67b90ea350497a54"; |
|
70 | 88 | }; |
|
89 | meta = { | |
|
90 | license = [ pkgs.lib.licenses.mit ]; | |
|
91 | }; | |
|
71 | 92 | }; |
|
72 | 93 | Markdown = super.buildPythonPackage { |
|
73 | 94 | name = "Markdown-2.6.2"; |
@@ -78,6 +99,9 b'' | |||
|
78 | 99 | url = "https://pypi.python.org/packages/62/8b/83658b5f6c220d5fcde9f9852d46ea54765d734cfbc5a9f4c05bfc36db4d/Markdown-2.6.2.tar.gz"; |
|
79 | 100 | md5 = "256d19afcc564dc4ce4c229bb762f7ae"; |
|
80 | 101 | }; |
|
102 | meta = { | |
|
103 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
104 | }; | |
|
81 | 105 | }; |
|
82 | 106 | MarkupSafe = super.buildPythonPackage { |
|
83 | 107 | name = "MarkupSafe-0.23"; |
@@ -88,6 +112,9 b'' | |||
|
88 | 112 | url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz"; |
|
89 | 113 | md5 = "f5ab3deee4c37cd6a922fb81e730da6e"; |
|
90 | 114 | }; |
|
115 | meta = { | |
|
116 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
117 | }; | |
|
91 | 118 | }; |
|
92 | 119 | MySQL-python = super.buildPythonPackage { |
|
93 | 120 | name = "MySQL-python-1.2.5"; |
@@ -98,6 +125,9 b'' | |||
|
98 | 125 | url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip"; |
|
99 | 126 | md5 = "654f75b302db6ed8dc5a898c625e030c"; |
|
100 | 127 | }; |
|
128 | meta = { | |
|
129 | license = [ pkgs.lib.licenses.gpl1 ]; | |
|
130 | }; | |
|
101 | 131 | }; |
|
102 | 132 | Paste = super.buildPythonPackage { |
|
103 | 133 | name = "Paste-2.0.2"; |
@@ -108,6 +138,9 b'' | |||
|
108 | 138 | url = "https://pypi.python.org/packages/d5/8d/0f8ac40687b97ff3e07ebd1369be20bdb3f93864d2dc3c2ff542edb4ce50/Paste-2.0.2.tar.gz"; |
|
109 | 139 | md5 = "4bfc8a7eaf858f6309d2ac0f40fc951c"; |
|
110 | 140 | }; |
|
141 | meta = { | |
|
142 | license = [ pkgs.lib.licenses.mit ]; | |
|
143 | }; | |
|
111 | 144 | }; |
|
112 | 145 | PasteDeploy = super.buildPythonPackage { |
|
113 | 146 | name = "PasteDeploy-1.5.2"; |
@@ -118,6 +151,9 b'' | |||
|
118 | 151 | url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz"; |
|
119 | 152 | md5 = "352b7205c78c8de4987578d19431af3b"; |
|
120 | 153 | }; |
|
154 | meta = { | |
|
155 | license = [ pkgs.lib.licenses.mit ]; | |
|
156 | }; | |
|
121 | 157 | }; |
|
122 | 158 | PasteScript = super.buildPythonPackage { |
|
123 | 159 | name = "PasteScript-1.7.5"; |
@@ -128,6 +164,9 b'' | |||
|
128 | 164 | url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz"; |
|
129 | 165 | md5 = "4c72d78dcb6bb993f30536842c16af4d"; |
|
130 | 166 | }; |
|
167 | meta = { | |
|
168 | license = [ pkgs.lib.licenses.mit ]; | |
|
169 | }; | |
|
131 | 170 | }; |
|
132 | 171 | Pygments = super.buildPythonPackage { |
|
133 | 172 | name = "Pygments-2.0.2"; |
@@ -138,6 +177,9 b'' | |||
|
138 | 177 | url = "https://pypi.python.org/packages/f4/c6/bdbc5a8a112256b2b6136af304dbae93d8b1ef8738ff2d12a51018800e46/Pygments-2.0.2.tar.gz"; |
|
139 | 178 | md5 = "238587a1370d62405edabd0794b3ec4a"; |
|
140 | 179 | }; |
|
180 | meta = { | |
|
181 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
182 | }; | |
|
141 | 183 | }; |
|
142 | 184 | Pylons = super.buildPythonPackage { |
|
143 | 185 | name = "Pylons-1.0.1"; |
@@ -148,6 +190,9 b'' | |||
|
148 | 190 | url = "https://pypi.python.org/packages/a2/69/b835a6bad00acbfeed3f33c6e44fa3f936efc998c795bfb15c61a79ecf62/Pylons-1.0.1.tar.gz"; |
|
149 | 191 | md5 = "6cb880d75fa81213192142b07a6e4915"; |
|
150 | 192 | }; |
|
193 | meta = { | |
|
194 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
195 | }; | |
|
151 | 196 | }; |
|
152 | 197 | Pyro4 = super.buildPythonPackage { |
|
153 | 198 | name = "Pyro4-4.41"; |
@@ -158,6 +203,9 b'' | |||
|
158 | 203 | url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz"; |
|
159 | 204 | md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c"; |
|
160 | 205 | }; |
|
206 | meta = { | |
|
207 | license = [ pkgs.lib.licenses.mit ]; | |
|
208 | }; | |
|
161 | 209 | }; |
|
162 | 210 | Routes = super.buildPythonPackage { |
|
163 | 211 | name = "Routes-1.13"; |
@@ -168,6 +216,9 b'' | |||
|
168 | 216 | url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz"; |
|
169 | 217 | md5 = "d527b0ab7dd9172b1275a41f97448783"; |
|
170 | 218 | }; |
|
219 | meta = { | |
|
220 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
221 | }; | |
|
171 | 222 | }; |
|
172 | 223 | SQLAlchemy = super.buildPythonPackage { |
|
173 | 224 | name = "SQLAlchemy-0.9.9"; |
@@ -178,6 +229,9 b'' | |||
|
178 | 229 | url = "https://pypi.python.org/packages/28/f7/1bbfd0d8597e8c358d5e15a166a486ad82fc5579b4e67b6ef7c05b1d182b/SQLAlchemy-0.9.9.tar.gz"; |
|
179 | 230 | md5 = "8a10a9bd13ed3336ef7333ac2cc679ff"; |
|
180 | 231 | }; |
|
232 | meta = { | |
|
233 | license = [ pkgs.lib.licenses.mit ]; | |
|
234 | }; | |
|
181 | 235 | }; |
|
182 | 236 | Sphinx = super.buildPythonPackage { |
|
183 | 237 | name = "Sphinx-1.2.2"; |
@@ -188,6 +242,9 b'' | |||
|
188 | 242 | url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz"; |
|
189 | 243 | md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4"; |
|
190 | 244 | }; |
|
245 | meta = { | |
|
246 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
247 | }; | |
|
191 | 248 | }; |
|
192 | 249 | Tempita = super.buildPythonPackage { |
|
193 | 250 | name = "Tempita-0.5.2"; |
@@ -198,6 +255,9 b'' | |||
|
198 | 255 | url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz"; |
|
199 | 256 | md5 = "4c2f17bb9d481821c41b6fbee904cea1"; |
|
200 | 257 | }; |
|
258 | meta = { | |
|
259 | license = [ pkgs.lib.licenses.mit ]; | |
|
260 | }; | |
|
201 | 261 | }; |
|
202 | 262 | URLObject = super.buildPythonPackage { |
|
203 | 263 | name = "URLObject-2.4.0"; |
@@ -208,6 +268,9 b'' | |||
|
208 | 268 | url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz"; |
|
209 | 269 | md5 = "2ed819738a9f0a3051f31dc9924e3065"; |
|
210 | 270 | }; |
|
271 | meta = { | |
|
272 | license = [ ]; | |
|
273 | }; | |
|
211 | 274 | }; |
|
212 | 275 | WebError = super.buildPythonPackage { |
|
213 | 276 | name = "WebError-0.10.3"; |
@@ -218,6 +281,9 b'' | |||
|
218 | 281 | url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz"; |
|
219 | 282 | md5 = "84b9990b0baae6fd440b1e60cdd06f9a"; |
|
220 | 283 | }; |
|
284 | meta = { | |
|
285 | license = [ pkgs.lib.licenses.mit ]; | |
|
286 | }; | |
|
221 | 287 | }; |
|
222 | 288 | WebHelpers = super.buildPythonPackage { |
|
223 | 289 | name = "WebHelpers-1.3"; |
@@ -228,6 +294,9 b'' | |||
|
228 | 294 | url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz"; |
|
229 | 295 | md5 = "32749ffadfc40fea51075a7def32588b"; |
|
230 | 296 | }; |
|
297 | meta = { | |
|
298 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
299 | }; | |
|
231 | 300 | }; |
|
232 | 301 | WebHelpers2 = super.buildPythonPackage { |
|
233 | 302 | name = "WebHelpers2-2.0"; |
@@ -238,6 +307,9 b'' | |||
|
238 | 307 | url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz"; |
|
239 | 308 | md5 = "0f6b68d70c12ee0aed48c00b24da13d3"; |
|
240 | 309 | }; |
|
310 | meta = { | |
|
311 | license = [ pkgs.lib.licenses.mit ]; | |
|
312 | }; | |
|
241 | 313 | }; |
|
242 | 314 | WebOb = super.buildPythonPackage { |
|
243 | 315 | name = "WebOb-1.3.1"; |
@@ -248,6 +320,9 b'' | |||
|
248 | 320 | url = "https://pypi.python.org/packages/16/78/adfc0380b8a0d75b2d543fa7085ba98a573b1ae486d9def88d172b81b9fa/WebOb-1.3.1.tar.gz"; |
|
249 | 321 | md5 = "20918251c5726956ba8fef22d1556177"; |
|
250 | 322 | }; |
|
323 | meta = { | |
|
324 | license = [ pkgs.lib.licenses.mit ]; | |
|
325 | }; | |
|
251 | 326 | }; |
|
252 | 327 | WebTest = super.buildPythonPackage { |
|
253 | 328 | name = "WebTest-1.4.3"; |
@@ -258,6 +333,9 b'' | |||
|
258 | 333 | url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip"; |
|
259 | 334 | md5 = "631ce728bed92c681a4020a36adbc353"; |
|
260 | 335 | }; |
|
336 | meta = { | |
|
337 | license = [ pkgs.lib.licenses.mit ]; | |
|
338 | }; | |
|
261 | 339 | }; |
|
262 | 340 | Whoosh = super.buildPythonPackage { |
|
263 | 341 | name = "Whoosh-2.7.0"; |
@@ -268,6 +346,9 b'' | |||
|
268 | 346 | url = "https://pypi.python.org/packages/1c/dc/2f0231ff3875ded36df8c1ab851451e51a237dc0e5a86d3d96036158da94/Whoosh-2.7.0.zip"; |
|
269 | 347 | md5 = "7abfd970f16fadc7311960f3fa0bc7a9"; |
|
270 | 348 | }; |
|
349 | meta = { | |
|
350 | license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ]; | |
|
351 | }; | |
|
271 | 352 | }; |
|
272 | 353 | alembic = super.buildPythonPackage { |
|
273 | 354 | name = "alembic-0.8.4"; |
@@ -278,6 +359,9 b'' | |||
|
278 | 359 | url = "https://pypi.python.org/packages/ca/7e/299b4499b5c75e5a38c5845145ad24755bebfb8eec07a2e1c366b7181eeb/alembic-0.8.4.tar.gz"; |
|
279 | 360 | md5 = "5f95d8ee62b443f9b37eb5bee76c582d"; |
|
280 | 361 | }; |
|
362 | meta = { | |
|
363 | license = [ pkgs.lib.licenses.mit ]; | |
|
364 | }; | |
|
281 | 365 | }; |
|
282 | 366 | amqplib = super.buildPythonPackage { |
|
283 | 367 | name = "amqplib-1.0.2"; |
@@ -288,6 +372,9 b'' | |||
|
288 | 372 | url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz"; |
|
289 | 373 | md5 = "5c92f17fbedd99b2b4a836d4352d1e2f"; |
|
290 | 374 | }; |
|
375 | meta = { | |
|
376 | license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; | |
|
377 | }; | |
|
291 | 378 | }; |
|
292 | 379 | anyjson = super.buildPythonPackage { |
|
293 | 380 | name = "anyjson-0.3.3"; |
@@ -298,6 +385,9 b'' | |||
|
298 | 385 | url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz"; |
|
299 | 386 | md5 = "2ea28d6ec311aeeebaf993cb3008b27c"; |
|
300 | 387 | }; |
|
388 | meta = { | |
|
389 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
390 | }; | |
|
301 | 391 | }; |
|
302 | 392 | appenlight-client = super.buildPythonPackage { |
|
303 | 393 | name = "appenlight-client-0.6.14"; |
@@ -308,6 +398,9 b'' | |||
|
308 | 398 | url = "https://pypi.python.org/packages/4d/e0/23fee3ebada8143f707e65c06bcb82992040ee64ea8355e044ed55ebf0c1/appenlight_client-0.6.14.tar.gz"; |
|
309 | 399 | md5 = "578c69b09f4356d898fff1199b98a95c"; |
|
310 | 400 | }; |
|
401 | meta = { | |
|
402 | license = [ pkgs.lib.licenses.bsdOriginal { fullName = "DFSG approved"; } ]; | |
|
403 | }; | |
|
311 | 404 | }; |
|
312 | 405 | authomatic = super.buildPythonPackage { |
|
313 | 406 | name = "authomatic-0.1.0.post1"; |
@@ -318,6 +411,9 b'' | |||
|
318 | 411 | url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz"; |
|
319 | 412 | md5 = "be3f3ce08747d776aae6d6cc8dcb49a9"; |
|
320 | 413 | }; |
|
414 | meta = { | |
|
415 | license = [ pkgs.lib.licenses.mit ]; | |
|
416 | }; | |
|
321 | 417 | }; |
|
322 | 418 | backport-ipaddress = super.buildPythonPackage { |
|
323 | 419 | name = "backport-ipaddress-0.1"; |
@@ -328,6 +424,9 b'' | |||
|
328 | 424 | url = "https://pypi.python.org/packages/d3/30/54c6dab05a4dec44db25ff309f1fbb6b7a8bde3f2bade38bb9da67bbab8f/backport_ipaddress-0.1.tar.gz"; |
|
329 | 425 | md5 = "9c1f45f4361f71b124d7293a60006c05"; |
|
330 | 426 | }; |
|
427 | meta = { | |
|
428 | license = [ pkgs.lib.licenses.psfl ]; | |
|
429 | }; | |
|
331 | 430 | }; |
|
332 | 431 | bottle = super.buildPythonPackage { |
|
333 | 432 | name = "bottle-0.12.8"; |
@@ -338,6 +437,9 b'' | |||
|
338 | 437 | url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz"; |
|
339 | 438 | md5 = "13132c0a8f607bf860810a6ee9064c5b"; |
|
340 | 439 | }; |
|
440 | meta = { | |
|
441 | license = [ pkgs.lib.licenses.mit ]; | |
|
442 | }; | |
|
341 | 443 | }; |
|
342 | 444 | bumpversion = super.buildPythonPackage { |
|
343 | 445 | name = "bumpversion-0.5.3"; |
@@ -348,6 +450,9 b'' | |||
|
348 | 450 | url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz"; |
|
349 | 451 | md5 = "c66a3492eafcf5ad4b024be9fca29820"; |
|
350 | 452 | }; |
|
453 | meta = { | |
|
454 | license = [ pkgs.lib.licenses.mit ]; | |
|
455 | }; | |
|
351 | 456 | }; |
|
352 | 457 | celery = super.buildPythonPackage { |
|
353 | 458 | name = "celery-2.2.10"; |
@@ -358,6 +463,9 b'' | |||
|
358 | 463 | url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz"; |
|
359 | 464 | md5 = "898bc87e54f278055b561316ba73e222"; |
|
360 | 465 | }; |
|
466 | meta = { | |
|
467 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
468 | }; | |
|
361 | 469 | }; |
|
362 | 470 | click = super.buildPythonPackage { |
|
363 | 471 | name = "click-5.1"; |
@@ -368,6 +476,9 b'' | |||
|
368 | 476 | url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz"; |
|
369 | 477 | md5 = "9c5323008cccfe232a8b161fc8196d41"; |
|
370 | 478 | }; |
|
479 | meta = { | |
|
480 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
481 | }; | |
|
371 | 482 | }; |
|
372 | 483 | colander = super.buildPythonPackage { |
|
373 | 484 | name = "colander-1.2"; |
@@ -378,6 +489,9 b'' | |||
|
378 | 489 | url = "https://pypi.python.org/packages/14/23/c9ceba07a6a1dc0eefbb215fc0dc64aabc2b22ee756bc0f0c13278fa0887/colander-1.2.tar.gz"; |
|
379 | 490 | md5 = "83db21b07936a0726e588dae1914b9ed"; |
|
380 | 491 | }; |
|
492 | meta = { | |
|
493 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
|
494 | }; | |
|
381 | 495 | }; |
|
382 | 496 | configobj = super.buildPythonPackage { |
|
383 | 497 | name = "configobj-5.0.6"; |
@@ -388,6 +502,9 b'' | |||
|
388 | 502 | url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz"; |
|
389 | 503 | md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6"; |
|
390 | 504 | }; |
|
505 | meta = { | |
|
506 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
507 | }; | |
|
391 | 508 | }; |
|
392 | 509 | cov-core = super.buildPythonPackage { |
|
393 | 510 | name = "cov-core-1.15.0"; |
@@ -398,6 +515,9 b'' | |||
|
398 | 515 | url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz"; |
|
399 | 516 | md5 = "f519d4cb4c4e52856afb14af52919fe6"; |
|
400 | 517 | }; |
|
518 | meta = { | |
|
519 | license = [ pkgs.lib.licenses.mit ]; | |
|
520 | }; | |
|
401 | 521 | }; |
|
402 | 522 | coverage = super.buildPythonPackage { |
|
403 | 523 | name = "coverage-3.7.1"; |
@@ -408,6 +528,9 b'' | |||
|
408 | 528 | url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz"; |
|
409 | 529 | md5 = "c47b36ceb17eaff3ecfab3bcd347d0df"; |
|
410 | 530 | }; |
|
531 | meta = { | |
|
532 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
533 | }; | |
|
411 | 534 | }; |
|
412 | 535 | cssselect = super.buildPythonPackage { |
|
413 | 536 | name = "cssselect-0.9.1"; |
@@ -418,6 +541,9 b'' | |||
|
418 | 541 | url = "https://pypi.python.org/packages/aa/e5/9ee1460d485b94a6d55732eb7ad5b6c084caf73dd6f9cb0bb7d2a78fafe8/cssselect-0.9.1.tar.gz"; |
|
419 | 542 | md5 = "c74f45966277dc7a0f768b9b0f3522ac"; |
|
420 | 543 | }; |
|
544 | meta = { | |
|
545 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
546 | }; | |
|
421 | 547 | }; |
|
422 | 548 | decorator = super.buildPythonPackage { |
|
423 | 549 | name = "decorator-3.4.2"; |
@@ -428,6 +554,9 b'' | |||
|
428 | 554 | url = "https://pypi.python.org/packages/35/3a/42566eb7a2cbac774399871af04e11d7ae3fc2579e7dae85213b8d1d1c57/decorator-3.4.2.tar.gz"; |
|
429 | 555 | md5 = "9e0536870d2b83ae27d58dbf22582f4d"; |
|
430 | 556 | }; |
|
557 | meta = { | |
|
558 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
559 | }; | |
|
431 | 560 | }; |
|
432 | 561 | docutils = super.buildPythonPackage { |
|
433 | 562 | name = "docutils-0.12"; |
@@ -438,6 +567,9 b'' | |||
|
438 | 567 | url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz"; |
|
439 | 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 | 574 | dogpile.cache = super.buildPythonPackage { |
|
443 | 575 | name = "dogpile.cache-0.5.7"; |
@@ -448,6 +580,9 b'' | |||
|
448 | 580 | url = "https://pypi.python.org/packages/07/74/2a83bedf758156d9c95d112691bbad870d3b77ccbcfb781b4ef836ea7d96/dogpile.cache-0.5.7.tar.gz"; |
|
449 | 581 | md5 = "3e58ce41af574aab41d78e9c4190f194"; |
|
450 | 582 | }; |
|
583 | meta = { | |
|
584 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
585 | }; | |
|
451 | 586 | }; |
|
452 | 587 | dogpile.core = super.buildPythonPackage { |
|
453 | 588 | name = "dogpile.core-0.4.1"; |
@@ -458,6 +593,9 b'' | |||
|
458 | 593 | url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz"; |
|
459 | 594 | md5 = "01cb19f52bba3e95c9b560f39341f045"; |
|
460 | 595 | }; |
|
596 | meta = { | |
|
597 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
598 | }; | |
|
461 | 599 | }; |
|
462 | 600 | dulwich = super.buildPythonPackage { |
|
463 | 601 | name = "dulwich-0.12.0"; |
@@ -468,6 +606,9 b'' | |||
|
468 | 606 | url = "https://pypi.python.org/packages/6f/04/fbe561b6d45c0ec758330d5b7f5ba4b6cb4f1ca1ab49859d2fc16320da75/dulwich-0.12.0.tar.gz"; |
|
469 | 607 | md5 = "f3a8a12bd9f9dd8c233e18f3d49436fa"; |
|
470 | 608 | }; |
|
609 | meta = { | |
|
610 | license = [ pkgs.lib.licenses.gpl2Plus ]; | |
|
611 | }; | |
|
471 | 612 | }; |
|
472 | 613 | ecdsa = super.buildPythonPackage { |
|
473 | 614 | name = "ecdsa-0.11"; |
@@ -478,6 +619,9 b'' | |||
|
478 | 619 | url = "https://pypi.python.org/packages/6c/3f/92fe5dcdcaa7bd117be21e5520c9a54375112b66ec000d209e9e9519fad1/ecdsa-0.11.tar.gz"; |
|
479 | 620 | md5 = "8ef586fe4dbb156697d756900cb41d7c"; |
|
480 | 621 | }; |
|
622 | meta = { | |
|
623 | license = [ pkgs.lib.licenses.mit ]; | |
|
624 | }; | |
|
481 | 625 | }; |
|
482 | 626 | elasticsearch = super.buildPythonPackage { |
|
483 | 627 | name = "elasticsearch-2.3.0"; |
@@ -488,6 +632,9 b'' | |||
|
488 | 632 | url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz"; |
|
489 | 633 | md5 = "2550f3b51629cf1ef9636608af92c340"; |
|
490 | 634 | }; |
|
635 | meta = { | |
|
636 | license = [ pkgs.lib.licenses.asl20 ]; | |
|
637 | }; | |
|
491 | 638 | }; |
|
492 | 639 | elasticsearch-dsl = super.buildPythonPackage { |
|
493 | 640 | name = "elasticsearch-dsl-2.0.0"; |
@@ -498,6 +645,9 b'' | |||
|
498 | 645 | url = "https://pypi.python.org/packages/4e/5d/e788ae8dbe2ff4d13426db0a027533386a5c276c77a2654dc0e2007ce04a/elasticsearch-dsl-2.0.0.tar.gz"; |
|
499 | 646 | md5 = "4cdfec81bb35383dd3b7d02d7dc5ee68"; |
|
500 | 647 | }; |
|
648 | meta = { | |
|
649 | license = [ pkgs.lib.licenses.asl20 ]; | |
|
650 | }; | |
|
501 | 651 | }; |
|
502 | 652 | flake8 = super.buildPythonPackage { |
|
503 | 653 | name = "flake8-2.4.1"; |
@@ -508,6 +658,9 b'' | |||
|
508 | 658 | url = "https://pypi.python.org/packages/8f/b5/9a73c66c7dba273bac8758398f060c008a25f3e84531063b42503b5d0a95/flake8-2.4.1.tar.gz"; |
|
509 | 659 | md5 = "ed45d3db81a3b7c88bd63c6e37ca1d65"; |
|
510 | 660 | }; |
|
661 | meta = { | |
|
662 | license = [ pkgs.lib.licenses.mit ]; | |
|
663 | }; | |
|
511 | 664 | }; |
|
512 | 665 | future = super.buildPythonPackage { |
|
513 | 666 | name = "future-0.14.3"; |
@@ -518,6 +671,9 b'' | |||
|
518 | 671 | url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz"; |
|
519 | 672 | md5 = "e94079b0bd1fc054929e8769fc0f6083"; |
|
520 | 673 | }; |
|
674 | meta = { | |
|
675 | license = [ { fullName = "OSI Approved"; } pkgs.lib.licenses.mit ]; | |
|
676 | }; | |
|
521 | 677 | }; |
|
522 | 678 | futures = super.buildPythonPackage { |
|
523 | 679 | name = "futures-3.0.2"; |
@@ -528,6 +684,9 b'' | |||
|
528 | 684 | url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz"; |
|
529 | 685 | md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a"; |
|
530 | 686 | }; |
|
687 | meta = { | |
|
688 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
689 | }; | |
|
531 | 690 | }; |
|
532 | 691 | gnureadline = super.buildPythonPackage { |
|
533 | 692 | name = "gnureadline-6.3.3"; |
@@ -538,9 +697,12 b'' | |||
|
538 | 697 | url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz"; |
|
539 | 698 | md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c"; |
|
540 | 699 | }; |
|
700 | meta = { | |
|
701 | license = [ pkgs.lib.licenses.gpl1 ]; | |
|
702 | }; | |
|
541 | 703 | }; |
|
542 | 704 | gprof2dot = super.buildPythonPackage { |
|
543 |
name = "gprof2dot-2015.12. |
|
|
705 | name = "gprof2dot-2015.12.1"; | |
|
544 | 706 | buildInputs = with self; []; |
|
545 | 707 | doCheck = false; |
|
546 | 708 | propagatedBuildInputs = with self; []; |
@@ -548,6 +710,9 b'' | |||
|
548 | 710 | url = "https://pypi.python.org/packages/b9/34/7bf93c1952d40fa5c95ad963f4d8344b61ef58558632402eca18e6c14127/gprof2dot-2015.12.1.tar.gz"; |
|
549 | 711 | md5 = "e23bf4e2f94db032750c193384b4165b"; |
|
550 | 712 | }; |
|
713 | meta = { | |
|
714 | license = [ { fullName = "LGPL"; } ]; | |
|
715 | }; | |
|
551 | 716 | }; |
|
552 | 717 | greenlet = super.buildPythonPackage { |
|
553 | 718 | name = "greenlet-0.4.9"; |
@@ -558,6 +723,9 b'' | |||
|
558 | 723 | url = "https://pypi.python.org/packages/4e/3d/9d421539b74e33608b245092870156b2e171fb49f2b51390aa4641eecb4a/greenlet-0.4.9.zip"; |
|
559 | 724 | md5 = "c6659cdb2a5e591723e629d2eef22e82"; |
|
560 | 725 | }; |
|
726 | meta = { | |
|
727 | license = [ pkgs.lib.licenses.mit ]; | |
|
728 | }; | |
|
561 | 729 | }; |
|
562 | 730 | gunicorn = super.buildPythonPackage { |
|
563 | 731 | name = "gunicorn-19.6.0"; |
@@ -568,6 +736,9 b'' | |||
|
568 | 736 | url = "https://pypi.python.org/packages/84/ce/7ea5396efad1cef682bbc4068e72a0276341d9d9d0f501da609fab9fcb80/gunicorn-19.6.0.tar.gz"; |
|
569 | 737 | md5 = "338e5e8a83ea0f0625f768dba4597530"; |
|
570 | 738 | }; |
|
739 | meta = { | |
|
740 | license = [ pkgs.lib.licenses.mit ]; | |
|
741 | }; | |
|
571 | 742 | }; |
|
572 | 743 | infrae.cache = super.buildPythonPackage { |
|
573 | 744 | name = "infrae.cache-1.0.1"; |
@@ -578,15 +749,21 b'' | |||
|
578 | 749 | url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz"; |
|
579 | 750 | md5 = "b09076a766747e6ed2a755cc62088e32"; |
|
580 | 751 | }; |
|
752 | meta = { | |
|
753 | license = [ pkgs.lib.licenses.zpt21 ]; | |
|
754 | }; | |
|
581 | 755 | }; |
|
582 | 756 | invoke = super.buildPythonPackage { |
|
583 |
name = "invoke-0.1 |
|
|
757 | name = "invoke-0.13.0"; | |
|
584 | 758 | buildInputs = with self; []; |
|
585 | 759 | doCheck = false; |
|
586 | 760 | propagatedBuildInputs = with self; []; |
|
587 | 761 | src = fetchurl { |
|
588 | url = "https://pypi.python.org/packages/d3/bb/36a5558ea19882073def7b0edeef4a0e6282056fed96506dd10b1d532bd4/invoke-0.11.1.tar.gz"; | |
|
589 | md5 = "3d4ecbe26779ceef1046ecf702c9c4a8"; | |
|
762 | url = "https://pypi.python.org/packages/47/bf/d07ef52fa1ac645468858bbac7cb95b246a972a045e821493d17d89c81be/invoke-0.13.0.tar.gz"; | |
|
763 | md5 = "c0d1ed4bfb34eaab551662d8cfee6540"; | |
|
764 | }; | |
|
765 | meta = { | |
|
766 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
590 | 767 | }; |
|
591 | 768 | }; |
|
592 | 769 | ipdb = super.buildPythonPackage { |
@@ -598,6 +775,9 b'' | |||
|
598 | 775 | url = "https://pypi.python.org/packages/f0/25/d7dd430ced6cd8dc242a933c8682b5dbf32eb4011d82f87e34209e5ec845/ipdb-0.8.zip"; |
|
599 | 776 | md5 = "96dca0712efa01aa5eaf6b22071dd3ed"; |
|
600 | 777 | }; |
|
778 | meta = { | |
|
779 | license = [ pkgs.lib.licenses.gpl1 ]; | |
|
780 | }; | |
|
601 | 781 | }; |
|
602 | 782 | ipython = super.buildPythonPackage { |
|
603 | 783 | name = "ipython-3.1.0"; |
@@ -608,6 +788,9 b'' | |||
|
608 | 788 | url = "https://pypi.python.org/packages/06/91/120c0835254c120af89f066afaabf81289bc2726c1fc3ca0555df6882f58/ipython-3.1.0.tar.gz"; |
|
609 | 789 | md5 = "a749d90c16068687b0ec45a27e72ef8f"; |
|
610 | 790 | }; |
|
791 | meta = { | |
|
792 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
793 | }; | |
|
611 | 794 | }; |
|
612 | 795 | iso8601 = super.buildPythonPackage { |
|
613 | 796 | name = "iso8601-0.1.11"; |
@@ -618,6 +801,9 b'' | |||
|
618 | 801 | url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz"; |
|
619 | 802 | md5 = "b06d11cd14a64096f907086044f0fe38"; |
|
620 | 803 | }; |
|
804 | meta = { | |
|
805 | license = [ pkgs.lib.licenses.mit ]; | |
|
806 | }; | |
|
621 | 807 | }; |
|
622 | 808 | itsdangerous = super.buildPythonPackage { |
|
623 | 809 | name = "itsdangerous-0.24"; |
@@ -628,6 +814,9 b'' | |||
|
628 | 814 | url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz"; |
|
629 | 815 | md5 = "a3d55aa79369aef5345c036a8a26307f"; |
|
630 | 816 | }; |
|
817 | meta = { | |
|
818 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
819 | }; | |
|
631 | 820 | }; |
|
632 | 821 | kombu = super.buildPythonPackage { |
|
633 | 822 | name = "kombu-1.5.1"; |
@@ -638,6 +827,9 b'' | |||
|
638 | 827 | url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz"; |
|
639 | 828 | md5 = "50662f3c7e9395b3d0721fb75d100b63"; |
|
640 | 829 | }; |
|
830 | meta = { | |
|
831 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
832 | }; | |
|
641 | 833 | }; |
|
642 | 834 | lxml = super.buildPythonPackage { |
|
643 | 835 | name = "lxml-3.4.4"; |
@@ -648,6 +840,9 b'' | |||
|
648 | 840 | url = "https://pypi.python.org/packages/63/c7/4f2a2a4ad6c6fa99b14be6b3c1cece9142e2d915aa7c43c908677afc8fa4/lxml-3.4.4.tar.gz"; |
|
649 | 841 | md5 = "a9a65972afc173ec7a39c585f4eea69c"; |
|
650 | 842 | }; |
|
843 | meta = { | |
|
844 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
845 | }; | |
|
651 | 846 | }; |
|
652 | 847 | mccabe = super.buildPythonPackage { |
|
653 | 848 | name = "mccabe-0.3"; |
@@ -658,6 +853,9 b'' | |||
|
658 | 853 | url = "https://pypi.python.org/packages/c9/2e/75231479e11a906b64ac43bad9d0bb534d00080b18bdca8db9da46e1faf7/mccabe-0.3.tar.gz"; |
|
659 | 854 | md5 = "81640948ff226f8c12b3277059489157"; |
|
660 | 855 | }; |
|
856 | meta = { | |
|
857 | license = [ { fullName = "Expat license"; } pkgs.lib.licenses.mit ]; | |
|
858 | }; | |
|
661 | 859 | }; |
|
662 | 860 | meld3 = super.buildPythonPackage { |
|
663 | 861 | name = "meld3-1.0.2"; |
@@ -668,6 +866,9 b'' | |||
|
668 | 866 | url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz"; |
|
669 | 867 | md5 = "3ccc78cd79cffd63a751ad7684c02c91"; |
|
670 | 868 | }; |
|
869 | meta = { | |
|
870 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
|
871 | }; | |
|
671 | 872 | }; |
|
672 | 873 | mock = super.buildPythonPackage { |
|
673 | 874 | name = "mock-1.0.1"; |
@@ -678,6 +879,9 b'' | |||
|
678 | 879 | url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip"; |
|
679 | 880 | md5 = "869f08d003c289a97c1a6610faf5e913"; |
|
680 | 881 | }; |
|
882 | meta = { | |
|
883 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
884 | }; | |
|
681 | 885 | }; |
|
682 | 886 | msgpack-python = super.buildPythonPackage { |
|
683 | 887 | name = "msgpack-python-0.4.6"; |
@@ -688,6 +892,9 b'' | |||
|
688 | 892 | url = "https://pypi.python.org/packages/15/ce/ff2840885789ef8035f66cd506ea05bdb228340307d5e71a7b1e3f82224c/msgpack-python-0.4.6.tar.gz"; |
|
689 | 893 | md5 = "8b317669314cf1bc881716cccdaccb30"; |
|
690 | 894 | }; |
|
895 | meta = { | |
|
896 | license = [ pkgs.lib.licenses.asl20 ]; | |
|
897 | }; | |
|
691 | 898 | }; |
|
692 | 899 | nose = super.buildPythonPackage { |
|
693 | 900 | name = "nose-1.3.6"; |
@@ -698,6 +905,9 b'' | |||
|
698 | 905 | url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz"; |
|
699 | 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 | 912 | objgraph = super.buildPythonPackage { |
|
703 | 913 | name = "objgraph-2.0.0"; |
@@ -708,6 +918,9 b'' | |||
|
708 | 918 | url = "https://pypi.python.org/packages/d7/33/ace750b59247496ed769b170586c5def7202683f3d98e737b75b767ff29e/objgraph-2.0.0.tar.gz"; |
|
709 | 919 | md5 = "25b0d5e5adc74aa63ead15699614159c"; |
|
710 | 920 | }; |
|
921 | meta = { | |
|
922 | license = [ pkgs.lib.licenses.mit ]; | |
|
923 | }; | |
|
711 | 924 | }; |
|
712 | 925 | packaging = super.buildPythonPackage { |
|
713 | 926 | name = "packaging-15.2"; |
@@ -718,6 +931,9 b'' | |||
|
718 | 931 | url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz"; |
|
719 | 932 | md5 = "c16093476f6ced42128bf610e5db3784"; |
|
720 | 933 | }; |
|
934 | meta = { | |
|
935 | license = [ pkgs.lib.licenses.asl20 ]; | |
|
936 | }; | |
|
721 | 937 | }; |
|
722 | 938 | paramiko = super.buildPythonPackage { |
|
723 | 939 | name = "paramiko-1.15.1"; |
@@ -728,6 +944,9 b'' | |||
|
728 | 944 | url = "https://pypi.python.org/packages/04/2b/a22d2a560c1951abbbf95a0628e245945565f70dc082d9e784666887222c/paramiko-1.15.1.tar.gz"; |
|
729 | 945 | md5 = "48c274c3f9b1282932567b21f6acf3b5"; |
|
730 | 946 | }; |
|
947 | meta = { | |
|
948 | license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; | |
|
949 | }; | |
|
731 | 950 | }; |
|
732 | 951 | pep8 = super.buildPythonPackage { |
|
733 | 952 | name = "pep8-1.5.7"; |
@@ -738,6 +957,9 b'' | |||
|
738 | 957 | url = "https://pypi.python.org/packages/8b/de/259f5e735897ada1683489dd514b2a1c91aaa74e5e6b68f80acf128a6368/pep8-1.5.7.tar.gz"; |
|
739 | 958 | md5 = "f6adbdd69365ecca20513c709f9b7c93"; |
|
740 | 959 | }; |
|
960 | meta = { | |
|
961 | license = [ { fullName = "Expat license"; } pkgs.lib.licenses.mit ]; | |
|
962 | }; | |
|
741 | 963 | }; |
|
742 | 964 | psutil = super.buildPythonPackage { |
|
743 | 965 | name = "psutil-2.2.1"; |
@@ -748,6 +970,9 b'' | |||
|
748 | 970 | url = "https://pypi.python.org/packages/df/47/ee54ef14dd40f8ce831a7581001a5096494dc99fe71586260ca6b531fe86/psutil-2.2.1.tar.gz"; |
|
749 | 971 | md5 = "1a2b58cd9e3a53528bb6148f0c4d5244"; |
|
750 | 972 | }; |
|
973 | meta = { | |
|
974 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
975 | }; | |
|
751 | 976 | }; |
|
752 | 977 | psycopg2 = super.buildPythonPackage { |
|
753 | 978 | name = "psycopg2-2.6"; |
@@ -758,6 +983,9 b'' | |||
|
758 | 983 | url = "https://pypi.python.org/packages/dd/c7/9016ff8ff69da269b1848276eebfb264af5badf6b38caad805426771f04d/psycopg2-2.6.tar.gz"; |
|
759 | 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 | 990 | py = super.buildPythonPackage { |
|
763 | 991 | name = "py-1.4.29"; |
@@ -768,6 +996,9 b'' | |||
|
768 | 996 | url = "https://pypi.python.org/packages/2a/bc/a1a4a332ac10069b8e5e25136a35e08a03f01fd6ab03d819889d79a1fd65/py-1.4.29.tar.gz"; |
|
769 | 997 | md5 = "c28e0accba523a29b35a48bb703fb96c"; |
|
770 | 998 | }; |
|
999 | meta = { | |
|
1000 | license = [ pkgs.lib.licenses.mit ]; | |
|
1001 | }; | |
|
771 | 1002 | }; |
|
772 | 1003 | py-bcrypt = super.buildPythonPackage { |
|
773 | 1004 | name = "py-bcrypt-0.4"; |
@@ -778,6 +1009,9 b'' | |||
|
778 | 1009 | url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz"; |
|
779 | 1010 | md5 = "dd8b367d6b716a2ea2e72392525f4e36"; |
|
780 | 1011 | }; |
|
1012 | meta = { | |
|
1013 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
1014 | }; | |
|
781 | 1015 | }; |
|
782 | 1016 | pycrypto = super.buildPythonPackage { |
|
783 | 1017 | name = "pycrypto-2.6.1"; |
@@ -788,6 +1022,9 b'' | |||
|
788 | 1022 | url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz"; |
|
789 | 1023 | md5 = "55a61a054aa66812daf5161a0d5d7eda"; |
|
790 | 1024 | }; |
|
1025 | meta = { | |
|
1026 | license = [ pkgs.lib.licenses.publicDomain ]; | |
|
1027 | }; | |
|
791 | 1028 | }; |
|
792 | 1029 | pycurl = super.buildPythonPackage { |
|
793 | 1030 | name = "pycurl-7.19.5"; |
@@ -798,6 +1035,9 b'' | |||
|
798 | 1035 | url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz"; |
|
799 | 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 | 1042 | pyflakes = super.buildPythonPackage { |
|
803 | 1043 | name = "pyflakes-0.8.1"; |
@@ -808,6 +1048,9 b'' | |||
|
808 | 1048 | url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz"; |
|
809 | 1049 | md5 = "905fe91ad14b912807e8fdc2ac2e2c23"; |
|
810 | 1050 | }; |
|
1051 | meta = { | |
|
1052 | license = [ pkgs.lib.licenses.mit ]; | |
|
1053 | }; | |
|
811 | 1054 | }; |
|
812 | 1055 | pyparsing = super.buildPythonPackage { |
|
813 | 1056 | name = "pyparsing-1.5.7"; |
@@ -818,6 +1061,9 b'' | |||
|
818 | 1061 | url = "https://pypi.python.org/packages/2e/26/e8fb5b4256a5f5036be7ce115ef8db8d06bc537becfbdc46c6af008314ee/pyparsing-1.5.7.zip"; |
|
819 | 1062 | md5 = "b86854857a368d6ccb4d5b6e76d0637f"; |
|
820 | 1063 | }; |
|
1064 | meta = { | |
|
1065 | license = [ pkgs.lib.licenses.mit ]; | |
|
1066 | }; | |
|
821 | 1067 | }; |
|
822 | 1068 | pyramid = super.buildPythonPackage { |
|
823 | 1069 | name = "pyramid-1.6.1"; |
@@ -828,6 +1074,9 b'' | |||
|
828 | 1074 | url = "https://pypi.python.org/packages/30/b3/fcc4a2a4800cbf21989e00454b5828cf1f7fe35c63e0810b350e56d4c475/pyramid-1.6.1.tar.gz"; |
|
829 | 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 | 1081 | pyramid-beaker = super.buildPythonPackage { |
|
833 | 1082 | name = "pyramid-beaker-0.8"; |
@@ -838,6 +1087,9 b'' | |||
|
838 | 1087 | url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz"; |
|
839 | 1088 | md5 = "22f14be31b06549f80890e2c63a93834"; |
|
840 | 1089 | }; |
|
1090 | meta = { | |
|
1091 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
|
1092 | }; | |
|
841 | 1093 | }; |
|
842 | 1094 | pyramid-debugtoolbar = super.buildPythonPackage { |
|
843 | 1095 | name = "pyramid-debugtoolbar-2.4.2"; |
@@ -848,6 +1100,9 b'' | |||
|
848 | 1100 | url = "https://pypi.python.org/packages/89/00/ed5426ee41ed747ba3ffd30e8230841a6878286ea67d480b1444d24f06a2/pyramid_debugtoolbar-2.4.2.tar.gz"; |
|
849 | 1101 | md5 = "073ea67086cc4bd5decc3a000853642d"; |
|
850 | 1102 | }; |
|
1103 | meta = { | |
|
1104 | license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ]; | |
|
1105 | }; | |
|
851 | 1106 | }; |
|
852 | 1107 | pyramid-jinja2 = super.buildPythonPackage { |
|
853 | 1108 | name = "pyramid-jinja2-2.5"; |
@@ -858,6 +1113,9 b'' | |||
|
858 | 1113 | url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz"; |
|
859 | 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 | 1120 | pyramid-mako = super.buildPythonPackage { |
|
863 | 1121 | name = "pyramid-mako-1.0.2"; |
@@ -868,6 +1126,9 b'' | |||
|
868 | 1126 | url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz"; |
|
869 | 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 | 1133 | pysqlite = super.buildPythonPackage { |
|
873 | 1134 | name = "pysqlite-2.6.3"; |
@@ -878,6 +1139,9 b'' | |||
|
878 | 1139 | url = "https://pypi.python.org/packages/5c/a6/1c429cd4c8069cf4bfbd0eb4d592b3f4042155a8202df83d7e9b93aa3dc2/pysqlite-2.6.3.tar.gz"; |
|
879 | 1140 | md5 = "7ff1cedee74646b50117acff87aa1cfa"; |
|
880 | 1141 | }; |
|
1142 | meta = { | |
|
1143 | license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ]; | |
|
1144 | }; | |
|
881 | 1145 | }; |
|
882 | 1146 | pytest = super.buildPythonPackage { |
|
883 | 1147 | name = "pytest-2.8.5"; |
@@ -888,6 +1152,9 b'' | |||
|
888 | 1152 | url = "https://pypi.python.org/packages/b1/3d/d7ea9b0c51e0cacded856e49859f0a13452747491e842c236bbab3714afe/pytest-2.8.5.zip"; |
|
889 | 1153 | md5 = "8493b06f700862f1294298d6c1b715a9"; |
|
890 | 1154 | }; |
|
1155 | meta = { | |
|
1156 | license = [ pkgs.lib.licenses.mit ]; | |
|
1157 | }; | |
|
891 | 1158 | }; |
|
892 | 1159 | pytest-catchlog = super.buildPythonPackage { |
|
893 | 1160 | name = "pytest-catchlog-1.2.2"; |
@@ -898,6 +1165,9 b'' | |||
|
898 | 1165 | url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip"; |
|
899 | 1166 | md5 = "09d890c54c7456c818102b7ff8c182c8"; |
|
900 | 1167 | }; |
|
1168 | meta = { | |
|
1169 | license = [ pkgs.lib.licenses.mit ]; | |
|
1170 | }; | |
|
901 | 1171 | }; |
|
902 | 1172 | pytest-cov = super.buildPythonPackage { |
|
903 | 1173 | name = "pytest-cov-1.8.1"; |
@@ -908,6 +1178,9 b'' | |||
|
908 | 1178 | url = "https://pypi.python.org/packages/11/4b/b04646e97f1721878eb21e9f779102d84dd044d324382263b1770a3e4838/pytest-cov-1.8.1.tar.gz"; |
|
909 | 1179 | md5 = "76c778afa2494088270348be42d759fc"; |
|
910 | 1180 | }; |
|
1181 | meta = { | |
|
1182 | license = [ pkgs.lib.licenses.mit ]; | |
|
1183 | }; | |
|
911 | 1184 | }; |
|
912 | 1185 | pytest-profiling = super.buildPythonPackage { |
|
913 | 1186 | name = "pytest-profiling-1.0.1"; |
@@ -918,6 +1191,9 b'' | |||
|
918 | 1191 | url = "https://pypi.python.org/packages/d8/67/8ffab73406e22870e07fa4dc8dce1d7689b26dba8efd00161c9b6fc01ec0/pytest-profiling-1.0.1.tar.gz"; |
|
919 | 1192 | md5 = "354404eb5b3fd4dc5eb7fffbb3d9b68b"; |
|
920 | 1193 | }; |
|
1194 | meta = { | |
|
1195 | license = [ pkgs.lib.licenses.mit ]; | |
|
1196 | }; | |
|
921 | 1197 | }; |
|
922 | 1198 | pytest-runner = super.buildPythonPackage { |
|
923 | 1199 | name = "pytest-runner-2.7.1"; |
@@ -928,6 +1204,9 b'' | |||
|
928 | 1204 | url = "https://pypi.python.org/packages/99/6b/c4ff4418d3424d4475b7af60724fd4a5cdd91ed8e489dc9443281f0052bc/pytest-runner-2.7.1.tar.gz"; |
|
929 | 1205 | md5 = "e56f0bc8d79a6bd91772b44ef4215c7e"; |
|
930 | 1206 | }; |
|
1207 | meta = { | |
|
1208 | license = [ pkgs.lib.licenses.mit ]; | |
|
1209 | }; | |
|
931 | 1210 | }; |
|
932 | 1211 | pytest-timeout = super.buildPythonPackage { |
|
933 | 1212 | name = "pytest-timeout-0.4"; |
@@ -938,6 +1217,9 b'' | |||
|
938 | 1217 | url = "https://pypi.python.org/packages/24/48/5f6bd4b8026a26e1dd427243d560a29a0f1b24a5c7cffca4bf049a7bb65b/pytest-timeout-0.4.tar.gz"; |
|
939 | 1218 | md5 = "03b28aff69cbbfb959ed35ade5fde262"; |
|
940 | 1219 | }; |
|
1220 | meta = { | |
|
1221 | license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ]; | |
|
1222 | }; | |
|
941 | 1223 | }; |
|
942 | 1224 | python-dateutil = super.buildPythonPackage { |
|
943 | 1225 | name = "python-dateutil-1.5"; |
@@ -948,6 +1230,9 b'' | |||
|
948 | 1230 | url = "https://pypi.python.org/packages/b4/7c/df59c89a753eb33c7c44e1dd42de0e9bc2ccdd5a4d576e0bfad97cc280cb/python-dateutil-1.5.tar.gz"; |
|
949 | 1231 | md5 = "0dcb1de5e5cad69490a3b6ab63f0cfa5"; |
|
950 | 1232 | }; |
|
1233 | meta = { | |
|
1234 | license = [ pkgs.lib.licenses.psfl ]; | |
|
1235 | }; | |
|
951 | 1236 | }; |
|
952 | 1237 | python-editor = super.buildPythonPackage { |
|
953 | 1238 | name = "python-editor-1.0.1"; |
@@ -958,6 +1243,9 b'' | |||
|
958 | 1243 | url = "https://pypi.python.org/packages/2b/c0/df7b87d5cf016f82eab3b05cd35f53287c1178ad8c42bfb6fa61b89b22f6/python-editor-1.0.1.tar.gz"; |
|
959 | 1244 | md5 = "e1fa63535b40e022fa4fd646fd8b511a"; |
|
960 | 1245 | }; |
|
1246 | meta = { | |
|
1247 | license = [ pkgs.lib.licenses.asl20 ]; | |
|
1248 | }; | |
|
961 | 1249 | }; |
|
962 | 1250 | python-ldap = super.buildPythonPackage { |
|
963 | 1251 | name = "python-ldap-2.4.19"; |
@@ -968,6 +1256,9 b'' | |||
|
968 | 1256 | url = "https://pypi.python.org/packages/42/81/1b64838c82e64f14d4e246ff00b52e650a35c012551b891ada2b85d40737/python-ldap-2.4.19.tar.gz"; |
|
969 | 1257 | md5 = "b941bf31d09739492aa19ef679e94ae3"; |
|
970 | 1258 | }; |
|
1259 | meta = { | |
|
1260 | license = [ pkgs.lib.licenses.psfl ]; | |
|
1261 | }; | |
|
971 | 1262 | }; |
|
972 | 1263 | python-memcached = super.buildPythonPackage { |
|
973 | 1264 | name = "python-memcached-1.57"; |
@@ -978,6 +1269,9 b'' | |||
|
978 | 1269 | url = "https://pypi.python.org/packages/52/9d/eebc0dcbc5c7c66840ad207dfc1baa376dadb74912484bff73819cce01e6/python-memcached-1.57.tar.gz"; |
|
979 | 1270 | md5 = "de21f64b42b2d961f3d4ad7beb5468a1"; |
|
980 | 1271 | }; |
|
1272 | meta = { | |
|
1273 | license = [ pkgs.lib.licenses.psfl ]; | |
|
1274 | }; | |
|
981 | 1275 | }; |
|
982 | 1276 | python-pam = super.buildPythonPackage { |
|
983 | 1277 | name = "python-pam-1.8.2"; |
@@ -988,6 +1282,9 b'' | |||
|
988 | 1282 | url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz"; |
|
989 | 1283 | md5 = "db71b6b999246fb05d78ecfbe166629d"; |
|
990 | 1284 | }; |
|
1285 | meta = { | |
|
1286 | license = [ { fullName = "License :: OSI Approved :: MIT License"; } pkgs.lib.licenses.mit ]; | |
|
1287 | }; | |
|
991 | 1288 | }; |
|
992 | 1289 | pytz = super.buildPythonPackage { |
|
993 | 1290 | name = "pytz-2015.4"; |
@@ -998,6 +1295,9 b'' | |||
|
998 | 1295 | url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip"; |
|
999 | 1296 | md5 = "233f2a2b370d03f9b5911700cc9ebf3c"; |
|
1000 | 1297 | }; |
|
1298 | meta = { | |
|
1299 | license = [ pkgs.lib.licenses.mit ]; | |
|
1300 | }; | |
|
1001 | 1301 | }; |
|
1002 | 1302 | pyzmq = super.buildPythonPackage { |
|
1003 | 1303 | name = "pyzmq-14.6.0"; |
@@ -1008,6 +1308,9 b'' | |||
|
1008 | 1308 | url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz"; |
|
1009 | 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 | 1315 | recaptcha-client = super.buildPythonPackage { |
|
1013 | 1316 | name = "recaptcha-client-1.0.6"; |
@@ -1018,6 +1321,9 b'' | |||
|
1018 | 1321 | url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz"; |
|
1019 | 1322 | md5 = "74228180f7e1fb76c4d7089160b0d919"; |
|
1020 | 1323 | }; |
|
1324 | meta = { | |
|
1325 | license = [ { fullName = "MIT/X11"; } ]; | |
|
1326 | }; | |
|
1021 | 1327 | }; |
|
1022 | 1328 | repoze.lru = super.buildPythonPackage { |
|
1023 | 1329 | name = "repoze.lru-0.6"; |
@@ -1028,6 +1334,9 b'' | |||
|
1028 | 1334 | url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz"; |
|
1029 | 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 | 1341 | requests = super.buildPythonPackage { |
|
1033 | 1342 | name = "requests-2.9.1"; |
@@ -1038,13 +1347,19 b'' | |||
|
1038 | 1347 | url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz"; |
|
1039 | 1348 | md5 = "0b7f480d19012ec52bab78292efd976d"; |
|
1040 | 1349 | }; |
|
1350 | meta = { | |
|
1351 | license = [ pkgs.lib.licenses.asl20 ]; | |
|
1352 | }; | |
|
1041 | 1353 | }; |
|
1042 | 1354 | rhodecode-enterprise-ce = super.buildPythonPackage { |
|
1043 |
name = "rhodecode-enterprise-ce-4. |
|
|
1355 | name = "rhodecode-enterprise-ce-4.2.0"; | |
|
1044 | 1356 | buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner]; |
|
1045 | 1357 | doCheck = true; |
|
1046 | 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 | 1359 | src = ./.; |
|
1360 | meta = { | |
|
1361 | license = [ { fullName = "AGPLv3, and Commercial License"; } ]; | |
|
1362 | }; | |
|
1048 | 1363 | }; |
|
1049 | 1364 | rhodecode-tools = super.buildPythonPackage { |
|
1050 | 1365 | name = "rhodecode-tools-0.8.3"; |
@@ -1055,6 +1370,9 b'' | |||
|
1055 | 1370 | url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.8.3.zip"; |
|
1056 | 1371 | md5 = "9acdfd71b8ddf4056057065f37ab9ccb"; |
|
1057 | 1372 | }; |
|
1373 | meta = { | |
|
1374 | license = [ { fullName = "AGPLv3 and Proprietary"; } ]; | |
|
1375 | }; | |
|
1058 | 1376 | }; |
|
1059 | 1377 | serpent = super.buildPythonPackage { |
|
1060 | 1378 | name = "serpent-1.12"; |
@@ -1065,6 +1383,9 b'' | |||
|
1065 | 1383 | url = "https://pypi.python.org/packages/3b/19/1e0e83b47c09edaef8398655088036e7e67386b5c48770218ebb339fbbd5/serpent-1.12.tar.gz"; |
|
1066 | 1384 | md5 = "05869ac7b062828b34f8f927f0457b65"; |
|
1067 | 1385 | }; |
|
1386 | meta = { | |
|
1387 | license = [ pkgs.lib.licenses.mit ]; | |
|
1388 | }; | |
|
1068 | 1389 | }; |
|
1069 | 1390 | setproctitle = super.buildPythonPackage { |
|
1070 | 1391 | name = "setproctitle-1.1.8"; |
@@ -1075,6 +1396,9 b'' | |||
|
1075 | 1396 | url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz"; |
|
1076 | 1397 | md5 = "728f4c8c6031bbe56083a48594027edd"; |
|
1077 | 1398 | }; |
|
1399 | meta = { | |
|
1400 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
|
1401 | }; | |
|
1078 | 1402 | }; |
|
1079 | 1403 | setuptools = super.buildPythonPackage { |
|
1080 | 1404 | name = "setuptools-20.8.1"; |
@@ -1085,6 +1409,9 b'' | |||
|
1085 | 1409 | url = "https://pypi.python.org/packages/c4/19/c1bdc88b53da654df43770f941079dbab4e4788c2dcb5658fb86259894c7/setuptools-20.8.1.zip"; |
|
1086 | 1410 | md5 = "fe58a5cac0df20bb83942b252a4b0543"; |
|
1087 | 1411 | }; |
|
1412 | meta = { | |
|
1413 | license = [ pkgs.lib.licenses.mit ]; | |
|
1414 | }; | |
|
1088 | 1415 | }; |
|
1089 | 1416 | setuptools-scm = super.buildPythonPackage { |
|
1090 | 1417 | name = "setuptools-scm-1.11.0"; |
@@ -1095,6 +1422,9 b'' | |||
|
1095 | 1422 | url = "https://pypi.python.org/packages/cd/5f/e3a038292358058d83d764a47d09114aa5a8003ed4529518f9e580f1a94f/setuptools_scm-1.11.0.tar.gz"; |
|
1096 | 1423 | md5 = "4c5c896ba52e134bbc3507bac6400087"; |
|
1097 | 1424 | }; |
|
1425 | meta = { | |
|
1426 | license = [ pkgs.lib.licenses.mit ]; | |
|
1427 | }; | |
|
1098 | 1428 | }; |
|
1099 | 1429 | simplejson = super.buildPythonPackage { |
|
1100 | 1430 | name = "simplejson-3.7.2"; |
@@ -1105,6 +1435,9 b'' | |||
|
1105 | 1435 | url = "https://pypi.python.org/packages/6d/89/7f13f099344eea9d6722779a1f165087cb559598107844b1ac5dbd831fb1/simplejson-3.7.2.tar.gz"; |
|
1106 | 1436 | md5 = "a5fc7d05d4cb38492285553def5d4b46"; |
|
1107 | 1437 | }; |
|
1438 | meta = { | |
|
1439 | license = [ pkgs.lib.licenses.mit pkgs.lib.licenses.afl21 ]; | |
|
1440 | }; | |
|
1108 | 1441 | }; |
|
1109 | 1442 | six = super.buildPythonPackage { |
|
1110 | 1443 | name = "six-1.9.0"; |
@@ -1115,6 +1448,9 b'' | |||
|
1115 | 1448 | url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz"; |
|
1116 | 1449 | md5 = "476881ef4012262dfc8adc645ee786c4"; |
|
1117 | 1450 | }; |
|
1451 | meta = { | |
|
1452 | license = [ pkgs.lib.licenses.mit ]; | |
|
1453 | }; | |
|
1118 | 1454 | }; |
|
1119 | 1455 | subprocess32 = super.buildPythonPackage { |
|
1120 | 1456 | name = "subprocess32-3.2.6"; |
@@ -1125,6 +1461,9 b'' | |||
|
1125 | 1461 | url = "https://pypi.python.org/packages/28/8d/33ccbff51053f59ae6c357310cac0e79246bbed1d345ecc6188b176d72c3/subprocess32-3.2.6.tar.gz"; |
|
1126 | 1462 | md5 = "754c5ab9f533e764f931136974b618f1"; |
|
1127 | 1463 | }; |
|
1464 | meta = { | |
|
1465 | license = [ pkgs.lib.licenses.psfl ]; | |
|
1466 | }; | |
|
1128 | 1467 | }; |
|
1129 | 1468 | supervisor = super.buildPythonPackage { |
|
1130 | 1469 | name = "supervisor-3.1.3"; |
@@ -1135,6 +1474,9 b'' | |||
|
1135 | 1474 | url = "https://pypi.python.org/packages/a6/41/65ad5bd66230b173eb4d0b8810230f3a9c59ef52ae066e540b6b99895db7/supervisor-3.1.3.tar.gz"; |
|
1136 | 1475 | md5 = "aad263c4fbc070de63dd354864d5e552"; |
|
1137 | 1476 | }; |
|
1477 | meta = { | |
|
1478 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
|
1479 | }; | |
|
1138 | 1480 | }; |
|
1139 | 1481 | transifex-client = super.buildPythonPackage { |
|
1140 | 1482 | name = "transifex-client-0.10"; |
@@ -1145,6 +1487,9 b'' | |||
|
1145 | 1487 | url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz"; |
|
1146 | 1488 | md5 = "5549538d84b8eede6b254cd81ae024fa"; |
|
1147 | 1489 | }; |
|
1490 | meta = { | |
|
1491 | license = [ pkgs.lib.licenses.gpl2 ]; | |
|
1492 | }; | |
|
1148 | 1493 | }; |
|
1149 | 1494 | translationstring = super.buildPythonPackage { |
|
1150 | 1495 | name = "translationstring-1.3"; |
@@ -1155,6 +1500,9 b'' | |||
|
1155 | 1500 | url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz"; |
|
1156 | 1501 | md5 = "a4b62e0f3c189c783a1685b3027f7c90"; |
|
1157 | 1502 | }; |
|
1503 | meta = { | |
|
1504 | license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ]; | |
|
1505 | }; | |
|
1158 | 1506 | }; |
|
1159 | 1507 | trollius = super.buildPythonPackage { |
|
1160 | 1508 | name = "trollius-1.0.4"; |
@@ -1165,6 +1513,9 b'' | |||
|
1165 | 1513 | url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz"; |
|
1166 | 1514 | md5 = "3631a464d49d0cbfd30ab2918ef2b783"; |
|
1167 | 1515 | }; |
|
1516 | meta = { | |
|
1517 | license = [ pkgs.lib.licenses.asl20 ]; | |
|
1518 | }; | |
|
1168 | 1519 | }; |
|
1169 | 1520 | uWSGI = super.buildPythonPackage { |
|
1170 | 1521 | name = "uWSGI-2.0.11.2"; |
@@ -1175,6 +1526,9 b'' | |||
|
1175 | 1526 | url = "https://pypi.python.org/packages/9b/78/918db0cfab0546afa580c1e565209c49aaf1476bbfe491314eadbe47c556/uwsgi-2.0.11.2.tar.gz"; |
|
1176 | 1527 | md5 = "1f02dcbee7f6f61de4b1fd68350cf16f"; |
|
1177 | 1528 | }; |
|
1529 | meta = { | |
|
1530 | license = [ pkgs.lib.licenses.gpl2 ]; | |
|
1531 | }; | |
|
1178 | 1532 | }; |
|
1179 | 1533 | urllib3 = super.buildPythonPackage { |
|
1180 | 1534 | name = "urllib3-1.16"; |
@@ -1185,6 +1539,9 b'' | |||
|
1185 | 1539 | url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz"; |
|
1186 | 1540 | md5 = "fcaab1c5385c57deeb7053d3d7d81d59"; |
|
1187 | 1541 | }; |
|
1542 | meta = { | |
|
1543 | license = [ pkgs.lib.licenses.mit ]; | |
|
1544 | }; | |
|
1188 | 1545 | }; |
|
1189 | 1546 | venusian = super.buildPythonPackage { |
|
1190 | 1547 | name = "venusian-1.0"; |
@@ -1195,6 +1552,9 b'' | |||
|
1195 | 1552 | url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz"; |
|
1196 | 1553 | md5 = "dccf2eafb7113759d60c86faf5538756"; |
|
1197 | 1554 | }; |
|
1555 | meta = { | |
|
1556 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
|
1557 | }; | |
|
1198 | 1558 | }; |
|
1199 | 1559 | waitress = super.buildPythonPackage { |
|
1200 | 1560 | name = "waitress-0.8.9"; |
@@ -1205,6 +1565,9 b'' | |||
|
1205 | 1565 | url = "https://pypi.python.org/packages/ee/65/fc9dee74a909a1187ca51e4f15ad9c4d35476e4ab5813f73421505c48053/waitress-0.8.9.tar.gz"; |
|
1206 | 1566 | md5 = "da3f2e62b3676be5dd630703a68e2a04"; |
|
1207 | 1567 | }; |
|
1568 | meta = { | |
|
1569 | license = [ pkgs.lib.licenses.zpt21 ]; | |
|
1570 | }; | |
|
1208 | 1571 | }; |
|
1209 | 1572 | wsgiref = super.buildPythonPackage { |
|
1210 | 1573 | name = "wsgiref-0.1.2"; |
@@ -1215,6 +1578,9 b'' | |||
|
1215 | 1578 | url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip"; |
|
1216 | 1579 | md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb"; |
|
1217 | 1580 | }; |
|
1581 | meta = { | |
|
1582 | license = [ { fullName = "PSF or ZPL"; } ]; | |
|
1583 | }; | |
|
1218 | 1584 | }; |
|
1219 | 1585 | zope.cachedescriptors = super.buildPythonPackage { |
|
1220 | 1586 | name = "zope.cachedescriptors-4.0.0"; |
@@ -1225,6 +1591,9 b'' | |||
|
1225 | 1591 | url = "https://pypi.python.org/packages/40/33/694b6644c37f28553f4b9f20b3c3a20fb709a22574dff20b5bdffb09ecd5/zope.cachedescriptors-4.0.0.tar.gz"; |
|
1226 | 1592 | md5 = "8d308de8c936792c8e758058fcb7d0f0"; |
|
1227 | 1593 | }; |
|
1594 | meta = { | |
|
1595 | license = [ pkgs.lib.licenses.zpt21 ]; | |
|
1596 | }; | |
|
1228 | 1597 | }; |
|
1229 | 1598 | zope.deprecation = super.buildPythonPackage { |
|
1230 | 1599 | name = "zope.deprecation-4.1.2"; |
@@ -1235,6 +1604,9 b'' | |||
|
1235 | 1604 | url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz"; |
|
1236 | 1605 | md5 = "e9a663ded58f4f9f7881beb56cae2782"; |
|
1237 | 1606 | }; |
|
1607 | meta = { | |
|
1608 | license = [ pkgs.lib.licenses.zpt21 ]; | |
|
1609 | }; | |
|
1238 | 1610 | }; |
|
1239 | 1611 | zope.event = super.buildPythonPackage { |
|
1240 | 1612 | name = "zope.event-4.0.3"; |
@@ -1245,6 +1617,9 b'' | |||
|
1245 | 1617 | url = "https://pypi.python.org/packages/c1/29/91ba884d7d6d96691df592e9e9c2bfa57a47040ec1ff47eff18c85137152/zope.event-4.0.3.tar.gz"; |
|
1246 | 1618 | md5 = "9a3780916332b18b8b85f522bcc3e249"; |
|
1247 | 1619 | }; |
|
1620 | meta = { | |
|
1621 | license = [ pkgs.lib.licenses.zpt21 ]; | |
|
1622 | }; | |
|
1248 | 1623 | }; |
|
1249 | 1624 | zope.interface = super.buildPythonPackage { |
|
1250 | 1625 | name = "zope.interface-4.1.3"; |
@@ -1255,6 +1630,9 b'' | |||
|
1255 | 1630 | url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz"; |
|
1256 | 1631 | md5 = "9ae3d24c0c7415deb249dd1a132f0f79"; |
|
1257 | 1632 | }; |
|
1633 | meta = { | |
|
1634 | license = [ pkgs.lib.licenses.zpt21 ]; | |
|
1635 | }; | |
|
1258 | 1636 | }; |
|
1259 | 1637 | |
|
1260 | 1638 | ### Test requirements |
@@ -25,6 +25,7 b'' | |||
|
25 | 25 | # vcsserver resides. |
|
26 | 26 | |
|
27 | 27 | { pkgs ? import <nixpkgs> {} |
|
28 | , doCheck ? true | |
|
28 | 29 | }: |
|
29 | 30 | |
|
30 | 31 | let |
@@ -69,7 +69,6 b' flake8==2.4.1' | |||
|
69 | 69 | future==0.14.3 |
|
70 | 70 | futures==3.0.2 |
|
71 | 71 | gprof2dot==2015.12.1 |
|
72 | greenlet==0.4.9 | |
|
73 | 72 | gunicorn==19.6.0 |
|
74 | 73 | |
|
75 | 74 | # TODO: Needs subvertpy and blows up without Subversion headers, |
@@ -78,7 +77,7 b' gunicorn==19.6.0' | |||
|
78 | 77 | |
|
79 | 78 | gnureadline==6.3.3 |
|
80 | 79 | infrae.cache==1.0.1 |
|
81 |
invoke==0.1 |
|
|
80 | invoke==0.13.0 | |
|
82 | 81 | ipdb==0.8 |
|
83 | 82 | ipython==3.1.0 |
|
84 | 83 | iso8601==0.1.11 |
@@ -22,6 +22,7 b'' | |||
|
22 | 22 | Authentication modules |
|
23 | 23 | """ |
|
24 | 24 | |
|
25 | import colander | |
|
25 | 26 | import logging |
|
26 | 27 | import time |
|
27 | 28 | import traceback |
@@ -97,16 +98,18 b' class RhodeCodeAuthPluginBase(object):' | |||
|
97 | 98 | # Mapping of python to DB settings model types. Plugins may override or |
|
98 | 99 | # extend this mapping. |
|
99 | 100 | _settings_type_map = { |
|
100 | str: 'str', | |
|
101 |
|
|
|
102 |
|
|
|
103 |
|
|
|
104 | list: 'list', | |
|
101 | colander.String: 'unicode', | |
|
102 | colander.Integer: 'int', | |
|
103 | colander.Boolean: 'bool', | |
|
104 | colander.List: 'list', | |
|
105 | 105 | } |
|
106 | 106 | |
|
107 | 107 | def __init__(self, plugin_id): |
|
108 | 108 | self._plugin_id = plugin_id |
|
109 | 109 | |
|
110 | def __str__(self): | |
|
111 | return self.get_id() | |
|
112 | ||
|
110 | 113 | def _get_setting_full_name(self, name): |
|
111 | 114 | """ |
|
112 | 115 | Return the full setting name used for storing values in the database. |
@@ -116,16 +119,19 b' class RhodeCodeAuthPluginBase(object):' | |||
|
116 | 119 | # PluginSetting or to use the plugin id here. |
|
117 | 120 | return 'auth_{}_{}'.format(self.name, name) |
|
118 | 121 | |
|
119 |
def _get_setting_type(self, name |
|
|
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 | |
|
122 | value. Optionally the suffix `.encrypted` is appended to instruct | |
|
123 | SettingsModel to store it encrypted. | |
|
124 | """ | |
|
125 | type_ = self._settings_type_map.get(type(value), 'unicode') | |
|
129 | schema_node = self.get_settings_schema().get(name) | |
|
130 | db_type = self._settings_type_map.get( | |
|
131 | type(schema_node.typ), 'unicode') | |
|
126 | 132 | if name in self._settings_encrypted: |
|
127 |
type |
|
|
128 |
return type |
|
|
133 | db_type = '{}.encrypted'.format(db_type) | |
|
134 | return db_type | |
|
129 | 135 | |
|
130 | 136 | def is_enabled(self): |
|
131 | 137 | """ |
@@ -161,20 +167,20 b' class RhodeCodeAuthPluginBase(object):' | |||
|
161 | 167 | """ |
|
162 | 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 | 172 | Returns a plugin setting by name. |
|
167 | 173 | """ |
|
168 | 174 | full_name = self._get_setting_full_name(name) |
|
169 | 175 | db_setting = SettingsModel().get_setting_by_name(full_name) |
|
170 |
return db_setting.app_settings_value if db_setting else |
|
|
176 | return db_setting.app_settings_value if db_setting else default | |
|
171 | 177 | |
|
172 | 178 | def create_or_update_setting(self, name, value): |
|
173 | 179 | """ |
|
174 | 180 | Create or update a setting for this plugin in the persistent storage. |
|
175 | 181 | """ |
|
176 | 182 | full_name = self._get_setting_full_name(name) |
|
177 |
type_ = self._get_setting_type(name |
|
|
183 | type_ = self._get_setting_type(name) | |
|
178 | 184 | db_setting = SettingsModel().create_or_update_setting( |
|
179 | 185 | full_name, value, type_) |
|
180 | 186 | return db_setting.app_settings_value |
@@ -56,10 +56,12 b' class AuthnPluginViewBase(object):' | |||
|
56 | 56 | errors = errors or {} |
|
57 | 57 | schema = self.plugin.get_settings_schema() |
|
58 | 58 | |
|
59 |
# |
|
|
59 | # Compute default values for the form. Priority is: | |
|
60 | # 1. Passed to this method 2. DB value 3. Schema default | |
|
60 | 61 | for node in schema: |
|
61 | db_value = self.plugin.get_setting_by_name(node.name) | |
|
62 | defaults.setdefault(node.name, db_value) | |
|
62 | if node.name not in defaults: | |
|
63 | defaults[node.name] = self.plugin.get_setting_by_name( | |
|
64 | node.name, node.default) | |
|
63 | 65 | |
|
64 | 66 | template_context = { |
|
65 | 67 | 'defaults': defaults, |
@@ -78,15 +80,17 b' class AuthnPluginViewBase(object):' | |||
|
78 | 80 | View that validates and stores the plugin settings. |
|
79 | 81 | """ |
|
80 | 82 | schema = self.plugin.get_settings_schema() |
|
83 | data = self.request.params | |
|
84 | ||
|
81 | 85 | try: |
|
82 |
valid_data = schema.deserialize( |
|
|
86 | valid_data = schema.deserialize(data) | |
|
83 | 87 | except colander.Invalid, e: |
|
84 | 88 | # Display error message and display form again. |
|
85 | 89 | self.request.session.flash( |
|
86 | 90 | _('Errors exist when saving plugin settings. ' |
|
87 | 91 | 'Please check the form inputs.'), |
|
88 | 92 | queue='error') |
|
89 | defaults = schema.flatten(self.request.params) | |
|
93 | defaults = {key: data[key] for key in data if key in schema} | |
|
90 | 94 | return self.settings_get(errors=e.asdict(), defaults=defaults) |
|
91 | 95 | |
|
92 | 96 | # Store validated data. |
@@ -82,7 +82,7 b' def load_environment(global_conf, app_co' | |||
|
82 | 82 | |
|
83 | 83 | config['routes.map'] = make_map(config) |
|
84 | 84 | |
|
85 | if asbool(config['debug']): | |
|
85 | if asbool(config.get('generate_js_files', 'false')): | |
|
86 | 86 | jsroutes = config['routes.map'].jsroutes() |
|
87 | 87 | jsroutes_file_content = generate_jsroutes_content(jsroutes) |
|
88 | 88 | jsroutes_file_path = os.path.join( |
@@ -29,7 +29,8 b' def generate_jsroutes_content(jsroutes):' | |||
|
29 | 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 | 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": { | |
|
3 | "cyrus": "http://cyrusimap.web.cmu.edu/mediawiki/index.php/Downloads#Licensing" | |
|
2 | "nodejs-4.3.1": { | |
|
3 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
4 | 4 | }, |
|
5 |
" |
|
|
6 |
" |
|
|
5 | "postgresql-9.5.1": { | |
|
6 | "PostgreSQL License": "http://spdx.org/licenses/PostgreSQL" | |
|
7 | 7 | }, |
|
8 |
" |
|
|
9 | "OpenSSL": "http://spdx.org/licenses/OpenSSL" | |
|
10 | }, | |
|
11 | "python-2.7.10": { | |
|
12 | "Python-2.0": "http://spdx.org/licenses/Python-2.0" | |
|
8 | "python-2.7.11": { | |
|
9 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
|
13 | 10 | }, |
|
14 | 11 | "python2.7-Babel-1.3": { |
|
15 |
"BSD |
|
|
12 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
16 | 13 | }, |
|
17 | 14 | "python2.7-Beaker-1.7.0": { |
|
18 |
"BSD |
|
|
15 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
19 | 16 | }, |
|
20 | 17 | "python2.7-FormEncode-1.2.4": { |
|
21 |
"Python |
|
|
18 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
|
22 | 19 | }, |
|
23 | 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 | 23 | "python2.7-Markdown-2.6.2": { |
|
27 |
"BSD |
|
|
24 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
28 | 25 | }, |
|
29 | 26 | "python2.7-MarkupSafe-0.23": { |
|
30 |
"BSD |
|
|
27 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
31 | 28 | }, |
|
32 | 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 | 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 | 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 | 38 | "python2.7-Pygments-2.0.2": { |
|
42 |
"BSD |
|
|
39 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
43 | 40 | }, |
|
44 |
"python2.7-Pylons-1.0. |
|
|
45 |
"BSD |
|
|
41 | "python2.7-Pylons-1.0.1-patch1": { | |
|
42 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
46 | 43 | }, |
|
47 | 44 | "python2.7-Pyro4-4.35": { |
|
48 | "MIT": "http://spdx.org/licenses/MIT" | |
|
45 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
49 | 46 | }, |
|
50 | 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 | 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 | 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 | 56 | "python2.7-URLObject-2.4.0": { |
|
60 |
"Unlicense": "http:// |
|
|
57 | "The Unlicense": "http://unlicense.org/" | |
|
61 | 58 | }, |
|
62 | 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 |
|
|
66 |
"BSD |
|
|
62 | "python2.7-WebHelpers-1.3": { | |
|
63 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
67 | 64 | }, |
|
68 | 65 | "python2.7-WebHelpers2-2.0": { |
|
69 |
" |
|
|
66 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
70 | 67 | }, |
|
71 | 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 |
|
|
75 |
"BSD |
|
|
71 | "python2.7-Whoosh-2.7.0": { | |
|
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 | 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 | 78 | "python2.7-amqplib-1.0.2": { |
|
81 |
" |
|
|
79 | "GNU Lesser General Public License v3.0 only": "http://spdx.org/licenses/LGPL-3.0" | |
|
82 | 80 | }, |
|
83 | 81 | "python2.7-anyjson-0.3.3": { |
|
84 |
"BSD |
|
|
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-a |
|
|
87 |
" |
|
|
87 | "python2.7-authomatic-0.1.0.post1": { | |
|
88 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
88 | 89 | }, |
|
89 |
"python2.7-backport |
|
|
90 |
"Python |
|
|
90 | "python2.7-backport-ipaddress-0.1": { | |
|
91 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
|
91 | 92 | }, |
|
92 | 93 | "python2.7-celery-2.2.10": { |
|
93 |
"BSD |
|
|
94 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
94 | 95 | }, |
|
95 |
"python2.7-click- |
|
|
96 |
"BSD |
|
|
96 | "python2.7-click-5.1": { | |
|
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 | 102 | "python2.7-configobj-5.0.6": { |
|
99 |
"BSD |
|
|
103 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
100 | 104 | }, |
|
101 | 105 | "python2.7-cssselect-0.9.1": { |
|
102 |
"BSD |
|
|
106 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
103 | 107 | }, |
|
104 | 108 | "python2.7-decorator-3.4.2": { |
|
105 |
"BSD |
|
|
109 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
106 | 110 | }, |
|
107 | 111 | "python2.7-docutils-0.12": { |
|
108 |
"BSD |
|
|
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 | 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 | 123 | "python2.7-futures-3.0.2": { |
|
114 |
"BSD |
|
|
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-g |
|
|
117 | "MIT": "http://spdx.org/licenses/MIT" | |
|
129 | "python2.7-gunicorn-19.6.0": { | |
|
130 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
118 | 131 | }, |
|
119 |
"python2.7- |
|
|
120 |
" |
|
|
132 | "python2.7-infrae.cache-1.0.1": { | |
|
133 | "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1" | |
|
121 | 134 | }, |
|
122 | 135 | "python2.7-ipython-3.1.0": { |
|
123 |
"BSD |
|
|
124 | }, | |
|
125 | "python2.7-kombu-1.5.1-patch1": { | |
|
126 | "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" | |
|
127 | 137 | }, |
|
128 |
"python2.7- |
|
|
129 | "expat": "http://directory.fsf.org/wiki/License:Expat" | |
|
138 | "python2.7-iso8601-0.1.11": { | |
|
139 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
130 | 140 | }, |
|
131 |
"python2.7- |
|
|
132 | "repoze": "http://repoze.org/license.html" | |
|
141 | "python2.7-kombu-1.5.1": { | |
|
142 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
133 | 143 | }, |
|
134 | 144 | "python2.7-msgpack-python-0.4.6": { |
|
135 |
"Apache |
|
|
136 | }, | |
|
137 | "python2.7-objgraph-2.0.0": { | |
|
138 | "MIT": "http://spdx.org/licenses/MIT" | |
|
145 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |
|
139 | 146 | }, |
|
140 | 147 | "python2.7-packaging-15.2": { |
|
141 |
"Apache |
|
|
148 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |
|
142 | 149 | }, |
|
143 | 150 | "python2.7-psutil-2.2.1": { |
|
144 |
"BSD |
|
|
151 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
145 | 152 | }, |
|
146 | 153 | "python2.7-psycopg2-2.6": { |
|
147 |
" |
|
|
154 | "GNU Lesser General Public License v3.0 or later": "http://spdx.org/licenses/LGPL-3.0+" | |
|
148 | 155 | }, |
|
149 | 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 | 159 | "python2.7-py-bcrypt-0.4": { |
|
153 |
"BSD |
|
|
160 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
154 | 161 | }, |
|
155 | 162 | "python2.7-pycrypto-2.6.1": { |
|
156 |
" |
|
|
163 | "Public Domain": null | |
|
164 | }, | |
|
165 | "python2.7-pycurl-7.19.5": { | |
|
166 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
157 | 167 | }, |
|
158 | 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 | 184 | "python2.7-pysqlite-2.6.3": { |
|
162 |
" |
|
|
163 |
" |
|
|
185 | "libpng License": "http://spdx.org/licenses/Libpng", | |
|
186 | "zlib License": "http://spdx.org/licenses/Zlib" | |
|
164 | 187 | }, |
|
165 | 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 | 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 | 200 | "python2.7-python-ldap-2.4.19": { |
|
172 |
"Python |
|
|
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 | 206 | "python2.7-pytz-2015.4": { |
|
175 | "MIT": "http://spdx.org/licenses/MIT" | |
|
207 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
176 | 208 | }, |
|
177 | 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 | 212 | "python2.7-repoze.lru-0.6": { |
|
181 |
" |
|
|
213 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |
|
182 | 214 | }, |
|
183 |
"python2.7-requests-2. |
|
|
184 |
"A |
|
|
215 | "python2.7-requests-2.9.1": { | |
|
216 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |
|
185 | 217 | }, |
|
186 |
"python2.7-serpent-1.1 |
|
|
187 | "MIT": "http://spdx.org/licenses/MIT" | |
|
218 | "python2.7-serpent-1.12": { | |
|
219 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
188 | 220 | }, |
|
189 |
"python2.7-set |
|
|
190 | "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" | |
|
221 | "python2.7-setuptools-19.4": { | |
|
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- |
|
|
193 | "PSF": null, | |
|
194 | "ZPL": null | |
|
225 | "python2.7-setuptools-scm-1.11.0": { | |
|
226 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
195 | 227 | }, |
|
196 | 228 | "python2.7-simplejson-3.7.2": { |
|
197 |
" |
|
|
229 | "Academic Free License": "http://spdx.org/licenses/AFL-2.1", | |
|
230 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
198 | 231 | }, |
|
199 | 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": { | |
|
203 | "Python-2.0": "http://spdx.org/licenses/Python-2.0" | |
|
235 | "python2.7-translationstring-1.3": { | |
|
236 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |
|
204 | 237 | }, |
|
205 |
"python2.7- |
|
|
206 |
" |
|
|
238 | "python2.7-urllib3-1.16": { | |
|
239 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
207 | 240 | }, |
|
208 |
"python2.7- |
|
|
209 | "APSL-2.0": "http://spdx.org/licenses/APSL-2.0" | |
|
241 | "python2.7-venusian-1.0": { | |
|
242 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |
|
210 | 243 | }, |
|
211 | 244 | "python2.7-waitress-0.8.9": { |
|
212 |
"Z |
|
|
245 | "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1" | |
|
213 | 246 | }, |
|
214 | 247 | "python2.7-zope.cachedescriptors-4.0.0": { |
|
215 |
"Z |
|
|
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 | 26 | from paste.registry import RegistryManager |
|
27 | 27 | from paste.gzipper import make_gzip_middleware |
|
28 | from pylons.middleware import ErrorHandler, StatusCodeRedirect | |
|
29 | 28 | from pylons.wsgiapp import PylonsApp |
|
30 | 29 | from pyramid.authorization import ACLAuthorizationPolicy |
|
31 | 30 | from pyramid.config import Configurator |
|
32 | 31 | from pyramid.static import static_view |
|
33 | 32 | from pyramid.settings import asbool, aslist |
|
34 | 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 | 37 | from routes.middleware import RoutesMiddleware |
|
36 | 38 | import routes.util |
|
37 | 39 | |
@@ -87,38 +89,15 b' def make_app(global_conf, full_stack=Tru' | |||
|
87 | 89 | app = csrf.OriginChecker(app, expected_origin, |
|
88 | 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 | 93 | if asbool(full_stack): |
|
106 | 94 | |
|
107 | 95 | # Appenlight monitoring and error handler |
|
108 | 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 | 98 | # we want our low level middleware to get to the request ASAP. We don't |
|
114 | 99 | # need any pylons stack middleware in them |
|
115 | 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 | 102 | # Establish the Registry for this application |
|
124 | 103 | app = RegistryManager(app) |
@@ -176,16 +155,69 b' def add_pylons_compat_data(registry, glo' | |||
|
176 | 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 | 205 | def includeme(config): |
|
180 | 206 | settings = config.registry.settings |
|
181 | 207 | |
|
208 | if asbool(settings.get('appenlight', 'false')): | |
|
209 | config.include('appenlight_client.ext.pyramid_tween') | |
|
210 | ||
|
182 | 211 | # Includes which are required. The application would fail without them. |
|
183 | 212 | config.include('pyramid_mako') |
|
184 | 213 | config.include('pyramid_beaker') |
|
214 | config.include('rhodecode.admin') | |
|
185 | 215 | config.include('rhodecode.authentication') |
|
186 | 216 | config.include('rhodecode.login') |
|
187 | 217 | config.include('rhodecode.tweens') |
|
188 | 218 | config.include('rhodecode.api') |
|
219 | config.add_route( | |
|
220 | 'rhodecode_support', 'https://rhodecode.com/help/', static=True) | |
|
189 | 221 | |
|
190 | 222 | # Set the authorization policy. |
|
191 | 223 | authz_policy = ACLAuthorizationPolicy() |
@@ -204,16 +236,52 b' def includeme(config):' | |||
|
204 | 236 | for inc in includes: |
|
205 | 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 | 272 | # This is the glue which allows us to migrate in chunks. By registering the |
|
208 | 273 | # pylons based application as the "Not Found" view in Pyramid, we will |
|
209 | 274 | # fallback to the old application each time the new one does not yet know |
|
210 | 275 | # how to handle a request. |
|
211 | pylons_app = make_app( | |
|
212 | config.registry._pylons_compat_global_config, | |
|
213 | **config.registry._pylons_compat_settings) | |
|
214 | config.registry._pylons_compat_config = pylons_app.config | |
|
215 | pylons_app_as_view = wsgiapp(pylons_app) | |
|
216 | config.add_notfound_view(pylons_app_as_view) | |
|
276 | config.add_notfound_view(pylons_app_with_error_handler) | |
|
277 | ||
|
278 | if settings.get('debugtoolbar.enabled', False): | |
|
279 | # if toolbar, then only http type exceptions get caught and rendered | |
|
280 | ExcClass = HTTPError | |
|
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 | 287 | def includeme_last(config): |
@@ -253,13 +321,16 b' def wrap_app_in_wsgi_middlewares(pyramid' | |||
|
253 | 321 | # enable https redirects based on HTTP_X_URL_SCHEME set by proxy |
|
254 | 322 | pyramid_app = HttpsFixup(pyramid_app, settings) |
|
255 | 323 | |
|
256 | # Add RoutesMiddleware. Currently we have two instances in the stack. This | |
|
257 | # is the upper one to support the pylons compatibility tween during | |
|
324 | # Add RoutesMiddleware to support the pylons compatibility tween during | |
|
258 | 325 | |
|
259 | 326 | # migration to pyramid. |
|
260 | 327 | pyramid_app = RoutesMiddleware( |
|
261 | 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 | 334 | # TODO: johbo: Don't really see why we enable the gzip middleware when |
|
264 | 335 | # serving static files, might be something that should have its own setting |
|
265 | 336 | # as well? |
@@ -166,10 +166,6 b' def make_map(config):' | |||
|
166 | 166 | def check_int(environ, match_dict): |
|
167 | 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 | 171 | # CUSTOM ROUTES HERE |
@@ -509,10 +505,6 b' def make_map(config):' | |||
|
509 | 505 | m.connect('admin_settings_labs', '/settings/labs', |
|
510 | 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 | 508 | # ADMIN MY ACCOUNT |
|
517 | 509 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
518 | 510 | controller='admin/my_account') as m: |
@@ -68,21 +68,25 b' def configure_vcs(config):' | |||
|
68 | 68 | |
|
69 | 69 | |
|
70 | 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 | 72 | engine = engine_from_config(config, 'sqlalchemy.db1.') |
|
73 |
init_model(engine, encryption_key=config |
|
|
73 | init_model(engine, encryption_key=get_encryption_key(config)) | |
|
74 | 74 | |
|
75 | 75 | |
|
76 | 76 | def initialize_test_environment(settings, test_env=None): |
|
77 | 77 | if test_env is None: |
|
78 | 78 | test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0)) |
|
79 | 79 | |
|
80 |
from rhodecode.lib.utils import |
|
|
80 | from rhodecode.lib.utils import ( | |
|
81 | create_test_directory, create_test_database, create_test_repositories, | |
|
82 | create_test_index) | |
|
81 | 83 | from rhodecode.tests import TESTS_TMP_PATH |
|
82 | 84 | # test repos |
|
83 | 85 | if test_env: |
|
84 |
create_test_ |
|
|
85 |
create_test_ |
|
|
86 | create_test_directory(TESTS_TMP_PATH) | |
|
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 | 92 | def get_vcs_server_protocol(config): |
@@ -99,7 +99,7 b' class RepoGroupsController(BaseControlle' | |||
|
99 | 99 | if repo_group.user: |
|
100 | 100 | data.update({'user': repo_group.user.username}) |
|
101 | 101 | else: |
|
102 | replacement_user = User.get_first_admin().username | |
|
102 | replacement_user = User.get_first_super_admin().username | |
|
103 | 103 | data.update({'user': replacement_user}) |
|
104 | 104 | |
|
105 | 105 | # fill repository group users |
@@ -246,11 +246,10 b' class RepoGroupsController(BaseControlle' | |||
|
246 | 246 | repo_group=c.repo_group) |
|
247 | 247 | |
|
248 | 248 | repo_group_form = RepoGroupForm( |
|
249 | edit=True, | |
|
250 | old_data=c.repo_group.get_dict(), | |
|
249 | edit=True, old_data=c.repo_group.get_dict(), | |
|
251 | 250 | available_groups=c.repo_groups_choices, |
|
252 | can_create_in_root=can_create_in_root, | |
|
253 | )() | |
|
251 | can_create_in_root=can_create_in_root, allow_disabled=True)() | |
|
252 | ||
|
254 | 253 | try: |
|
255 | 254 | form_result = repo_group_form.to_python(dict(request.POST)) |
|
256 | 255 | gr_name = form_result['group_name'] |
@@ -248,9 +248,9 b' class ReposController(BaseRepoController' | |||
|
248 | 248 | task_id = request.GET.get('task_id') |
|
249 | 249 | |
|
250 | 250 | if task_id and task_id not in ['None']: |
|
251 |
|
|
|
251 | import rhodecode | |
|
252 | 252 | from celery.result import AsyncResult |
|
253 | if CELERY_ENABLED: | |
|
253 | if rhodecode.CELERY_ENABLED: | |
|
254 | 254 | task = AsyncResult(task_id) |
|
255 | 255 | if task.failed(): |
|
256 | 256 | msg = self._log_creation_exception(task.result, c.repo) |
@@ -307,9 +307,9 b' class ReposController(BaseRepoController' | |||
|
307 | 307 | 'repo_group': repo.group.get_dict() if repo.group else {}, |
|
308 | 308 | 'repo_type': repo.repo_type, |
|
309 | 309 | } |
|
310 |
_form = RepoForm( |
|
|
311 |
|
|
|
312 |
|
|
|
310 | _form = RepoForm( | |
|
311 | edit=True, old_data=old_data, repo_groups=c.repo_groups_choices, | |
|
312 | landing_revs=c.landing_revs_choices, allow_disabled=True)() | |
|
313 | 313 | |
|
314 | 314 | try: |
|
315 | 315 | form_result = _form.to_python(dict(request.POST)) |
@@ -37,6 +37,7 b' from pylons.i18n.translation import _, l' | |||
|
37 | 37 | from webob.exc import HTTPBadRequest |
|
38 | 38 | |
|
39 | 39 | import rhodecode |
|
40 | from rhodecode.admin.navigation import navigation_list | |
|
40 | 41 | from rhodecode.lib import auth |
|
41 | 42 | from rhodecode.lib import helpers as h |
|
42 | 43 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
@@ -47,7 +48,7 b' from rhodecode.lib.utils2 import (' | |||
|
47 | 48 | str2bool, safe_unicode, AttributeDict, safe_int) |
|
48 | 49 | from rhodecode.lib.compat import OrderedDict |
|
49 | 50 | from rhodecode.lib.ext_json import json |
|
50 |
from rhodecode.lib.utils import jsonify |
|
|
51 | from rhodecode.lib.utils import jsonify | |
|
51 | 52 | |
|
52 | 53 | from rhodecode.model.db import RhodeCodeUi, Repository |
|
53 | 54 | from rhodecode.model.forms import ApplicationSettingsForm, \ |
@@ -60,8 +61,9 b' from rhodecode.model.meta import Session' | |||
|
60 | 61 | from rhodecode.model.settings import ( |
|
61 | 62 | IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound, |
|
62 | 63 | SettingsModel) |
|
64 | ||
|
63 | 65 | from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER |
|
64 | from rhodecode.model.user import UserModel | |
|
66 | ||
|
65 | 67 | |
|
66 | 68 | log = logging.getLogger(__name__) |
|
67 | 69 | |
@@ -78,7 +80,7 b' class SettingsController(BaseController)' | |||
|
78 | 80 | super(SettingsController, self).__before__() |
|
79 | 81 | c.labs_active = str2bool( |
|
80 | 82 | rhodecode.CONFIG.get('labs_settings_active', 'false')) |
|
81 |
c.navlist = navigation |
|
|
83 | c.navlist = navigation_list(request) | |
|
82 | 84 | |
|
83 | 85 | def _get_hg_ui_settings(self): |
|
84 | 86 | ret = RhodeCodeUi.query().all() |
@@ -257,8 +259,8 b' class SettingsController(BaseController)' | |||
|
257 | 259 | Session().add(sett) |
|
258 | 260 | |
|
259 | 261 | Session().commit() |
|
262 | SettingsModel().invalidate_settings_cache() | |
|
260 | 263 | h.flash(_('Updated application settings'), category='success') |
|
261 | ||
|
262 | 264 | except Exception: |
|
263 | 265 | log.exception("Exception while updating application settings") |
|
264 | 266 | h.flash( |
@@ -321,7 +323,7 b' class SettingsController(BaseController)' | |||
|
321 | 323 | Session().add(sett) |
|
322 | 324 | |
|
323 | 325 | Session().commit() |
|
324 | ||
|
326 | SettingsModel().invalidate_settings_cache() | |
|
325 | 327 | h.flash(_('Updated visualisation settings'), category='success') |
|
326 | 328 | except Exception: |
|
327 | 329 | log.exception("Exception updating visualization settings") |
@@ -403,6 +405,7 b' class SettingsController(BaseController)' | |||
|
403 | 405 | |
|
404 | 406 | Session().commit() |
|
405 | 407 | |
|
408 | SettingsModel().invalidate_settings_cache() | |
|
406 | 409 | h.flash(_('Updated issue tracker entries'), category='success') |
|
407 | 410 | return redirect(url('admin_settings_issuetracker')) |
|
408 | 411 | |
@@ -523,6 +526,7 b' class SettingsController(BaseController)' | |||
|
523 | 526 | def settings_system(self): |
|
524 | 527 | """GET /admin/settings/system: All items in the collection""" |
|
525 | 528 | # url('admin_settings_system') |
|
529 | snapshot = str2bool(request.GET.get('snapshot')) | |
|
526 | 530 | c.active = 'system' |
|
527 | 531 | |
|
528 | 532 | defaults = self._form_defaults() |
@@ -557,6 +561,35 b' class SettingsController(BaseController)' | |||
|
557 | 561 | except TypeError: |
|
558 | 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 | 593 | return htmlfill.render( |
|
561 | 594 | render('admin/settings/settings.html'), |
|
562 | 595 | defaults=defaults, |
@@ -708,6 +741,7 b' class SettingsController(BaseController)' | |||
|
708 | 741 | category='error') |
|
709 | 742 | else: |
|
710 | 743 | Session().commit() |
|
744 | SettingsModel().invalidate_settings_cache() | |
|
711 | 745 | h.flash(_('Updated Labs settings'), category='success') |
|
712 | 746 | return redirect(url('admin_settings_labs')) |
|
713 | 747 | |
@@ -733,20 +767,6 b' class SettingsController(BaseController)' | |||
|
733 | 767 | encoding='UTF-8', |
|
734 | 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 | 770 | def _form_defaults(self): |
|
751 | 771 | defaults = SettingsModel().get_all_settings() |
|
752 | 772 | defaults.update(self._get_hg_ui_settings()) |
@@ -791,76 +811,3 b' LabSetting = collections.namedtuple(' | |||
|
791 | 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 | 88 | if user_group.user: |
|
89 | 89 | data.update({'user': user_group.user.username}) |
|
90 | 90 | else: |
|
91 | replacement_user = User.get_first_admin().username | |
|
91 | replacement_user = User.get_first_super_admin().username | |
|
92 | 92 | data.update({'user': replacement_user}) |
|
93 | 93 | return data |
|
94 | 94 | |
@@ -209,9 +209,9 b' class UserGroupsController(BaseControlle' | |||
|
209 | 209 | |
|
210 | 210 | available_members = [safe_unicode(x[0]) for x in c.available_members] |
|
211 | 211 | |
|
212 |
users_group_form = UserGroupForm( |
|
|
213 |
|
|
|
214 |
|
|
|
212 | users_group_form = UserGroupForm( | |
|
213 | edit=True, old_data=c.user_group.get_dict(), | |
|
214 | available_members=available_members, allow_disabled=True)() | |
|
215 | 215 | |
|
216 | 216 | try: |
|
217 | 217 | form_result = users_group_form.to_python(request.POST) |
@@ -216,6 +216,8 b' class UsersController(BaseController):' | |||
|
216 | 216 | prefix_error=False, |
|
217 | 217 | encoding="UTF-8", |
|
218 | 218 | force_defaults=False) |
|
219 | except UserCreationError as e: | |
|
220 | h.flash(e, 'error') | |
|
219 | 221 | except Exception: |
|
220 | 222 | log.exception("Exception updating user") |
|
221 | 223 | h.flash(_('Error occurred during update of user %s') |
@@ -401,7 +403,7 b' class UsersController(BaseController):' | |||
|
401 | 403 | c.active = 'advanced' |
|
402 | 404 | c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) |
|
403 | 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 | 407 | defaults = user.get_dict() |
|
406 | 408 | |
|
407 | 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 | 37 | from rhodecode.lib.index import searcher_from_config |
|
38 | 38 | from rhodecode.lib.ext_json import json |
|
39 | 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 | 41 | from rhodecode.model.db import Repository, RepoGroup |
|
42 | 42 | from rhodecode.model.repo import RepoModel |
|
43 | 43 | from rhodecode.model.repo_group import RepoGroupModel |
@@ -259,13 +259,16 b' class HomeController(BaseController):' | |||
|
259 | 259 | @jsonify |
|
260 | 260 | def user_autocomplete_data(self): |
|
261 | 261 | query = request.GET.get('query') |
|
262 | active = str2bool(request.GET.get('active') or True) | |
|
262 | 263 | |
|
263 | 264 | repo_model = RepoModel() |
|
264 |
_users = repo_model.get_users( |
|
|
265 | _users = repo_model.get_users( | |
|
266 | name_contains=query, only_active=active) | |
|
265 | 267 | |
|
266 | 268 | if request.GET.get('user_groups'): |
|
267 | 269 | # extend with user groups |
|
268 |
_user_groups = repo_model.get_user_groups( |
|
|
270 | _user_groups = repo_model.get_user_groups( | |
|
271 | name_contains=query, only_active=active) | |
|
269 | 272 | _users = _users + _user_groups |
|
270 | 273 | |
|
271 | 274 | return {'suggestions': _users} |
@@ -274,4 +277,13 b' class HomeController(BaseController):' | |||
|
274 | 277 | @XHRRequired() |
|
275 | 278 | @jsonify |
|
276 | 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 | 17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
18 | 18 | |
|
19 | 19 | from zope.interface import implementer |
|
20 |
from rhodecode.interfaces import |
|
|
20 | from rhodecode.interfaces import ( | |
|
21 | IUserRegistered, IUserPreCreate, IUserPreUpdate) | |
|
21 | 22 | |
|
22 | 23 | |
|
23 | 24 | @implementer(IUserRegistered) |
@@ -29,3 +30,24 b' class UserRegistered(object):' | |||
|
29 | 30 | def __init__(self, user, session): |
|
30 | 31 | self.user = user |
|
31 | 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 | |
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 | 27 | user = Attribute('The user object.') |
|
28 | 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 | 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 | 260 | context.rhodecode_version = rhodecode.__version__ |
|
261 | 261 | context.rhodecode_edition = config.get('rhodecode.edition') |
@@ -425,7 +425,7 b' class BaseController(WSGIController):' | |||
|
425 | 425 | _route_name = '.'.join([environ['pylons.routes_dict']['controller'], |
|
426 | 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 | 429 | self.ip_addr = get_ip_addr(environ) |
|
430 | 430 | |
|
431 | 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 | 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 | 96 | log.debug('Clearing all values for cache manager %s', cache_manager) |
|
91 | 97 | cache_manager.clear() |
|
92 | 98 | |
@@ -161,7 +167,7 b' class FreshRegionCache(ActiveRegionCache' | |||
|
161 | 167 | class InvalidationContext(object): |
|
162 | 168 | def __repr__(self): |
|
163 | 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 | 172 | def __init__(self, compute_func, repo_name, cache_type, |
|
167 | 173 | raise_exception=False): |
@@ -34,7 +34,6 b' from decorator import decorator' | |||
|
34 | 34 | |
|
35 | 35 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
36 | 36 | |
|
37 | from rhodecode import CELERY_ENABLED, CELERY_EAGER | |
|
38 | 37 | from rhodecode.config import utils |
|
39 | 38 | from rhodecode.lib.utils2 import safe_str, md5_safe, aslist |
|
40 | 39 | from rhodecode.lib.pidlock import DaemonLock, LockHeld |
@@ -54,8 +53,7 b' class ResultWrapper(object):' | |||
|
54 | 53 | |
|
55 | 54 | |
|
56 | 55 | def run_task(task, *args, **kwargs): |
|
57 |
|
|
|
58 | if CELERY_ENABLED: | |
|
56 | if rhodecode.CELERY_ENABLED: | |
|
59 | 57 | try: |
|
60 | 58 | t = task.apply_async(args=args, kwargs=kwargs) |
|
61 | 59 | log.info('running task %s:%s', t.task_id, task) |
@@ -63,17 +61,17 b' def run_task(task, *args, **kwargs):' | |||
|
63 | 61 | |
|
64 | 62 | except socket.error as e: |
|
65 | 63 | if isinstance(e, IOError) and e.errno == 111: |
|
66 |
log. |
|
|
67 | CELERY_ENABLED = False | |
|
64 | log.error('Unable to connect to celeryd. Sync execution') | |
|
65 | rhodecode.CELERY_ENABLED = False | |
|
68 | 66 | else: |
|
69 | 67 | log.exception("Exception while connecting to celeryd.") |
|
70 | 68 | except KeyError as e: |
|
71 |
|
|
|
69 | log.error('Unable to connect to celeryd. Sync execution') | |
|
72 | 70 | except Exception as e: |
|
73 | 71 | log.exception( |
|
74 | 72 | "Exception while trying to run task asynchronous. " |
|
75 | 73 | "Fallback to sync execution.") |
|
76 | ||
|
74 | else: | |
|
77 | 75 | log.debug('executing task %s in sync mode', task) |
|
78 | 76 | return ResultWrapper(task(*args, **kwargs)) |
|
79 | 77 | |
@@ -106,7 +104,7 b' def locked_task(func):' | |||
|
106 | 104 | |
|
107 | 105 | |
|
108 | 106 | def get_session(): |
|
109 | if CELERY_ENABLED: | |
|
107 | if rhodecode.CELERY_ENABLED: | |
|
110 | 108 | utils.initialize_database(config) |
|
111 | 109 | sa = meta.Session() |
|
112 | 110 | return sa |
@@ -118,7 +116,7 b' def dbsession(func):' | |||
|
118 | 116 | ret = func(*fargs, **fkwargs) |
|
119 | 117 | return ret |
|
120 | 118 | finally: |
|
121 | if CELERY_ENABLED and not CELERY_EAGER: | |
|
119 | if rhodecode.CELERY_ENABLED and not rhodecode.CELERY_EAGER: | |
|
122 | 120 | meta.Session.remove() |
|
123 | 121 | |
|
124 | 122 | return decorator(__wrapper, func) |
@@ -126,7 +124,7 b' def dbsession(func):' | |||
|
126 | 124 | |
|
127 | 125 | def vcsconnection(func): |
|
128 | 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 | 128 | backends = config['vcs.backends'] = aslist( |
|
131 | 129 | config.get('vcs.backends', 'hg,git'), sep=',') |
|
132 | 130 | for alias in rhodecode.BACKENDS.keys(): |
@@ -30,7 +30,7 b' import logging' | |||
|
30 | 30 | from celery.task import task |
|
31 | 31 | from pylons import config |
|
32 | 32 | |
|
33 | from rhodecode import CELERY_ENABLED | |
|
33 | import rhodecode | |
|
34 | 34 | from rhodecode.lib.celerylib import ( |
|
35 | 35 | run_task, dbsession, __get_lockkey, LockHeld, DaemonLock, |
|
36 | 36 | get_session, vcsconnection) |
@@ -45,7 +45,7 b' add_cache(config) # pragma: no cover' | |||
|
45 | 45 | |
|
46 | 46 | |
|
47 | 47 | def get_logger(cls): |
|
48 | if CELERY_ENABLED: | |
|
48 | if rhodecode.CELERY_ENABLED: | |
|
49 | 49 | try: |
|
50 | 50 | log = cls.get_logger() |
|
51 | 51 | except Exception: |
@@ -23,31 +23,84 b'' | |||
|
23 | 23 | Generic encryption library for RhodeCode |
|
24 | 24 | """ |
|
25 | 25 | |
|
26 | import hashlib | |
|
27 | 26 | import base64 |
|
28 | 27 | |
|
29 | 28 | from Crypto.Cipher import AES |
|
30 | 29 | from Crypto import Random |
|
30 | from Crypto.Hash import HMAC, SHA256 | |
|
31 | 31 | |
|
32 | 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 | 51 | class AESCipher(object): |
|
36 | def __init__(self, key): | |
|
37 | # create padding, trim to long enc key | |
|
52 | def __init__(self, key, hmac=False, strict_verification=True): | |
|
38 | 53 | if not key: |
|
39 | 54 | raise ValueError('passed key variable is empty') |
|
55 | self.strict_verification = strict_verification | |
|
40 | 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 | 70 | def encrypt(self, raw): |
|
44 | 71 | raw = self._pad(raw) |
|
45 | 72 | iv = Random.new().read(AES.block_size) |
|
46 | 73 | cipher = AES.new(self.key, AES.MODE_CBC, iv) |
|
47 |
|
|
|
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 | 85 | def decrypt(self, enc): |
|
86 | enc_org = enc | |
|
50 | 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 | 104 | iv = enc[:AES.block_size] |
|
52 | 105 | cipher = AES.new(self.key, AES.MODE_CBC, iv) |
|
53 | 106 | return self._unpad(cipher.decrypt(enc[AES.block_size:])) |
@@ -438,15 +438,17 b' def get_matching_line_offsets(lines, ter' | |||
|
438 | 438 | :param max_lines: cut off for lines of interest |
|
439 | 439 | eg. |
|
440 | 440 | |
|
441 | >>> get_matching_line_offsets(''' | |
|
441 | text = ''' | |
|
442 | 442 | words words words |
|
443 | 443 | words words words |
|
444 | 444 | some text some |
|
445 | 445 | words words words |
|
446 | 446 | words words words |
|
447 | 447 | text here what |
|
448 | ''', 'text', context=1) | |
|
448 | ''' | |
|
449 | get_matching_line_offsets(text, 'text', context=1) | |
|
449 | 450 | {3: [(5, 9)], 6: [(0, 4)]] |
|
451 | ||
|
450 | 452 | """ |
|
451 | 453 | matching_lines = {} |
|
452 | 454 | phrases = [normalize_text_for_matching(phrase) |
@@ -460,6 +462,7 b' text here what' | |||
|
460 | 462 | |
|
461 | 463 | return matching_lines |
|
462 | 464 | |
|
465 | ||
|
463 | 466 | def get_lexer_safe(mimetype=None, filepath=None): |
|
464 | 467 | """ |
|
465 | 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 | 473 | if mimetype: |
|
471 | 474 | lexer = get_lexer_for_mimetype(mimetype) |
|
472 | 475 | if not lexer: |
|
473 | lexer = get_lexer_for_filename(path) | |
|
476 | lexer = get_lexer_for_filename(filepath) | |
|
474 | 477 | except pygments.util.ClassNotFound: |
|
475 | 478 | pass |
|
476 | 479 | |
@@ -675,11 +678,6 b' def _shorten_commit_id(commit_id):' | |||
|
675 | 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 | 681 | def show_id(commit): |
|
684 | 682 | """ |
|
685 | 683 | Configurable function that shows ID |
@@ -744,6 +742,32 b' def is_svn_without_proxy(repository):' | |||
|
744 | 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 | 771 | def email_or_none(author): |
|
748 | 772 | # extract email from the commit string |
|
749 | 773 | _email = author_email(author) |
@@ -765,30 +789,13 b' def email_or_none(author):' | |||
|
765 | 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 | 792 | def link_to_user(author, length=0, **kwargs): |
|
791 | 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 | 799 | display_person = person(author, 'username_or_name_or_email') |
|
793 | 800 | if length: |
|
794 | 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 | 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 | 813 | user = discover_user(author) |
|
809 | 814 | if user: |
|
810 |
return |
|
|
815 | return getattr(user, show_attr) | |
|
811 | 816 | else: |
|
812 | 817 | _author = author_name(author) |
|
813 | 818 | _email = email(author) |
@@ -827,10 +832,10 b' def person_by_id(id_, show_attr="usernam' | |||
|
827 | 832 | return id_ |
|
828 | 833 | |
|
829 | 834 | |
|
830 | def gravatar_with_user(author): | |
|
835 | def gravatar_with_user(author, show_disabled=False): | |
|
831 | 836 | from rhodecode.lib.utils import PartialRenderer |
|
832 | 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 | 841 | def desc_stylize(value): |
@@ -1647,10 +1652,10 b' def process_patterns(text_string, repo_n' | |||
|
1647 | 1652 | if repo_name: |
|
1648 | 1653 | # Retrieving repo_name to avoid invalid repo_name to explode on |
|
1649 | 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 | 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 | 1660 | newtext = text_string |
|
1656 | 1661 | for uid, entry in active_entries.items(): |
@@ -24,15 +24,21 b' Disable VCS pages when VCS Server is not' | |||
|
24 | 24 | |
|
25 | 25 | import logging |
|
26 | 26 | import re |
|
27 | ||
|
27 | from pyramid.httpexceptions import HTTPBadGateway | |
|
28 | 28 | |
|
29 | 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 | 38 | class DisableVCSPagesWrapper(object): |
|
33 | 39 | """ |
|
34 |
|
|
|
35 | avoiding that errors explode to the user. | |
|
40 | Pyramid view wrapper to disable all pages that require VCS Server to be | |
|
41 | running, avoiding that errors explode to the user. | |
|
36 | 42 | |
|
37 | 43 | This Wrapper should be enabled only in case VCS Server is not available |
|
38 | 44 | for the instance. |
@@ -60,11 +66,11 b' class DisableVCSPagesWrapper(object):' | |||
|
60 | 66 | log.debug('accessing: `%s` with VCS Server disabled', path_info) |
|
61 | 67 | return False |
|
62 | 68 | |
|
63 |
def __init__(self, |
|
|
64 |
self. |
|
|
69 | def __init__(self, handler): | |
|
70 | self.handler = handler | |
|
65 | 71 | |
|
66 |
def __call__(self, |
|
|
67 |
if not self._check_vcs_requirement( |
|
|
68 | environ['PATH_INFO'] = '/error/vcs_unavailable' | |
|
72 | def __call__(self, context, request): | |
|
73 | if not self._check_vcs_requirement(request.path): | |
|
74 | raise VCSServerUnavailable('VCS Server is not available') | |
|
69 | 75 | |
|
70 |
return self. |
|
|
76 | return self.handler(context, request) |
@@ -33,14 +33,14 b' import tempfile' | |||
|
33 | 33 | import traceback |
|
34 | 34 | import tarfile |
|
35 | 35 | import warnings |
|
36 |
from os.path import |
|
|
37 | from os.path import dirname as dn, join as jn | |
|
36 | from os.path import join as jn | |
|
38 | 37 | |
|
39 | 38 | import paste |
|
40 | 39 | import pkg_resources |
|
41 | 40 | from paste.script.command import Command, BadCommand |
|
42 | 41 | from webhelpers.text import collapse, remove_formatting, strip_tags |
|
43 | 42 | from mako import exceptions |
|
43 | from pyramid.threadlocal import get_current_registry | |
|
44 | 44 | |
|
45 | 45 | from rhodecode.lib.fakemod import create_module |
|
46 | 46 | from rhodecode.lib.vcs.backends.base import Config |
@@ -52,8 +52,7 b' from rhodecode.model import meta' | |||
|
52 | 52 | from rhodecode.model.db import ( |
|
53 | 53 | Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup) |
|
54 | 54 | from rhodecode.model.meta import Session |
|
55 | from rhodecode.model.repo_group import RepoGroupModel | |
|
56 | from rhodecode.model.settings import VcsSettingsModel, SettingsModel | |
|
55 | ||
|
57 | 56 | |
|
58 | 57 | log = logging.getLogger(__name__) |
|
59 | 58 | |
@@ -384,6 +383,8 b' def config_data_from_db(clear_session=Tr' | |||
|
384 | 383 | Read the configuration data from the database and return configuration |
|
385 | 384 | tuples. |
|
386 | 385 | """ |
|
386 | from rhodecode.model.settings import VcsSettingsModel | |
|
387 | ||
|
387 | 388 | config = [] |
|
388 | 389 | |
|
389 | 390 | sa = meta.Session() |
@@ -467,6 +468,7 b' def set_rhodecode_config(config):' | |||
|
467 | 468 | |
|
468 | 469 | :param config: |
|
469 | 470 | """ |
|
471 | from rhodecode.model.settings import SettingsModel | |
|
470 | 472 | app_settings = SettingsModel().get_all_settings() |
|
471 | 473 | |
|
472 | 474 | for k, v in app_settings.items(): |
@@ -481,6 +483,7 b' def map_groups(path):' | |||
|
481 | 483 | |
|
482 | 484 | :param paths: full path to repository |
|
483 | 485 | """ |
|
486 | from rhodecode.model.repo_group import RepoGroupModel | |
|
484 | 487 | sa = meta.Session() |
|
485 | 488 | groups = path.split(Repository.NAME_SEP) |
|
486 | 489 | parent = None |
@@ -489,7 +492,7 b' def map_groups(path):' | |||
|
489 | 492 | # last element is repo in nested groups structure |
|
490 | 493 | groups = groups[:-1] |
|
491 | 494 | rgm = RepoGroupModel(sa) |
|
492 | owner = User.get_first_admin() | |
|
495 | owner = User.get_first_super_admin() | |
|
493 | 496 | for lvl, group_name in enumerate(groups): |
|
494 | 497 | group_name = '/'.join(groups[:lvl] + [group_name]) |
|
495 | 498 | group = RepoGroup.get_by_group_name(group_name) |
@@ -525,9 +528,12 b' def repo2db_mapper(initial_repo_list, re' | |||
|
525 | 528 | """ |
|
526 | 529 | from rhodecode.model.repo import RepoModel |
|
527 | 530 | from rhodecode.model.scm import ScmModel |
|
531 | from rhodecode.model.repo_group import RepoGroupModel | |
|
532 | from rhodecode.model.settings import SettingsModel | |
|
533 | ||
|
528 | 534 | sa = meta.Session() |
|
529 | 535 | repo_model = RepoModel() |
|
530 | user = User.get_first_admin() | |
|
536 | user = User.get_first_super_admin() | |
|
531 | 537 | added = [] |
|
532 | 538 | |
|
533 | 539 | # creation defaults |
@@ -701,58 +707,56 b' def get_custom_lexer(extension):' | |||
|
701 | 707 | #============================================================================== |
|
702 | 708 | # TEST FUNCTIONS AND CREATORS |
|
703 | 709 | #============================================================================== |
|
704 |
def create_test_index(repo_location, config |
|
|
710 | def create_test_index(repo_location, config): | |
|
705 | 711 | """ |
|
706 | Makes default test index | |
|
707 | ||
|
708 | :param config: test config | |
|
709 | :param full_index: | |
|
710 | # start test server: | |
|
711 | rcserver --with-vcsserver test.ini | |
|
712 | Makes default test index. | |
|
713 | """ | |
|
714 | import rc_testdata | |
|
712 | 715 | |
|
713 | # build index and store it in /tmp/rc/index: | |
|
714 | rhodecode-index --force --api-host=http://vps1.dev:5000 --api-key=xxx --engine-location=/tmp/rc/index | |
|
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'])) | |
|
716 | rc_testdata.extract_search_index( | |
|
717 | 'vcs_search_index', os.path.dirname(config['search.location'])) | |
|
725 | 718 | |
|
726 | 719 | |
|
727 |
def create_test_ |
|
|
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 | |
|
730 | installs test repository into tmp dir | |
|
724 | if not os.path.isdir(test_path): | |
|
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 | 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 | 735 | # PART ONE create db |
|
736 | 736 | dbconf = config['sqlalchemy.db1.url'] |
|
737 | 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 | 739 | dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'], |
|
745 | 740 | tests=True, cli_args={'force_ask': True}) |
|
746 | 741 | dbmanage.create_tables(override=True) |
|
747 | 742 | dbmanage.set_db_version() |
|
748 | 743 | # for tests dynamically set new root paths based on generated content |
|
749 |
dbmanage.create_settings(dbmanage.config_prompt( |
|
|
744 | dbmanage.create_settings(dbmanage.config_prompt(test_path)) | |
|
750 | 745 | dbmanage.create_default_user() |
|
751 | 746 | dbmanage.create_test_admin_and_users() |
|
752 | 747 | dbmanage.create_permissions() |
|
753 | 748 | dbmanage.populate_default_permissions() |
|
754 | 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 | 760 | log.debug('making test vcs repositories') |
|
757 | 761 | |
|
758 | 762 | idx_path = config['search.location'] |
@@ -767,24 +771,15 b' def create_test_env(repos_test_path, con' | |||
|
767 | 771 | log.debug('remove %s', data_path) |
|
768 | 772 | shutil.rmtree(data_path) |
|
769 | 773 | |
|
770 | # CREATE DEFAULT TEST REPOS | |
|
771 | cur_dir = dn(dn(abspath(__file__))) | |
|
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)) | |
|
774 | rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO)) | |
|
775 | rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO)) | |
|
780 | 776 | |
|
781 | 777 | # Note: Subversion is in the process of being integrated with the system, |
|
782 | 778 | # until we have a properly packed version of the test svn repository, this |
|
783 | 779 | # tries to copy over the repo from a package "rc_testdata" |
|
784 | import rc_testdata | |
|
785 | 780 | svn_repo_path = rc_testdata.get_svn_repo_archive() |
|
786 | 781 | with tarfile.open(svn_repo_path) as tar: |
|
787 |
tar.extractall(jn( |
|
|
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 | 972 | if not _license_cache: |
|
978 | 973 | licenses = pkg_resources.resource_string( |
|
979 |
'rhodecode |
|
|
974 | 'rhodecode', 'config/licenses.json') | |
|
980 | 975 | _license_cache = json.loads(licenses) |
|
981 | 976 | |
|
982 | 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 | 321 | setattr(conn, 'query_start_time', time.time()) |
|
322 | 322 | log.info(color_sql(">>>>> STARTING QUERY >>>>>")) |
|
323 | 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 | 327 | if calling_context: |
|
327 | 328 | log.info(color_sql('call context %s:%s' % ( |
@@ -341,6 +342,12 b' def engine_from_config(configuration, pr' | |||
|
341 | 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 | 351 | def age(prevdate, now=None, show_short_version=False, show_suffix=True, |
|
345 | 352 | short_format=False): |
|
346 | 353 | """ |
@@ -93,11 +93,14 b' def connect_http(server_and_port):' | |||
|
93 | 93 | from rhodecode.lib.vcs import connection, client_http |
|
94 | 94 | from rhodecode.lib.middleware.utils import scm_app |
|
95 | 95 | |
|
96 |
session = |
|
|
96 | session_factory = client_http.ThreadlocalSessionFactory() | |
|
97 | 97 | |
|
98 |
connection.Git = client_http.RepoMaker( |
|
|
99 |
|
|
|
100 |
connection. |
|
|
98 | connection.Git = client_http.RepoMaker( | |
|
99 | server_and_port, '/git', session_factory) | |
|
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 | 105 | scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy( |
|
103 | 106 | server_and_port, '/proxy/hg') |
@@ -31,6 +31,7 b' implementation.' | |||
|
31 | 31 | |
|
32 | 32 | import copy |
|
33 | 33 | import logging |
|
34 | import threading | |
|
34 | 35 | import urllib2 |
|
35 | 36 | import urlparse |
|
36 | 37 | import uuid |
@@ -38,7 +39,7 b' import uuid' | |||
|
38 | 39 | import msgpack |
|
39 | 40 | import requests |
|
40 | 41 | |
|
41 | from . import exceptions | |
|
42 | from . import exceptions, CurlSession | |
|
42 | 43 | |
|
43 | 44 | |
|
44 | 45 | log = logging.getLogger(__name__) |
@@ -54,15 +55,16 b' EXCEPTIONS_MAP = {' | |||
|
54 | 55 | |
|
55 | 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 | 59 | self.url = urlparse.urljoin( |
|
59 | 60 | 'http://%s' % server_and_port, backend_endpoint) |
|
60 | self._session = session | |
|
61 | self._session_factory = session_factory | |
|
61 | 62 | |
|
62 | 63 | def __call__(self, path, config, with_wire=None): |
|
63 | 64 | log.debug('RepoMaker call on %s', path) |
|
64 | 65 | return RemoteRepo( |
|
65 |
path, config, self.url, self._session, |
|
|
66 | path, config, self.url, self._session_factory(), | |
|
67 | with_wire=with_wire) | |
|
66 | 68 | |
|
67 | 69 | def __getattr__(self, name): |
|
68 | 70 | def f(*args, **kwargs): |
@@ -76,7 +78,8 b' class RepoMaker(object):' | |||
|
76 | 78 | 'method': name, |
|
77 | 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 | 85 | class RemoteRepo(object): |
@@ -216,3 +219,17 b' class VcsHttpProxy(object):' | |||
|
216 | 219 | headers = iterator.next() |
|
217 | 220 | |
|
218 | 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 | 43 | import logging |
|
44 | 44 | |
|
45 | 45 | from pylons import config |
|
46 | from pyramid.threadlocal import get_current_registry | |
|
46 | 47 | |
|
47 | 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 | 51 | log = logging.getLogger(__name__) |
|
51 | 52 | |
@@ -65,8 +66,8 b' def init_model(engine, encryption_key=No' | |||
|
65 | 66 | |
|
66 | 67 | |
|
67 | 68 | def init_model_encryption(migration_models): |
|
68 |
migration_models.ENCRYPTION_KEY = config |
|
|
69 | db.ENCRYPTION_KEY = config['beaker.session.secret'] | |
|
69 | migration_models.ENCRYPTION_KEY = get_encryption_key(config) | |
|
70 | db.ENCRYPTION_KEY = get_encryption_key(config) | |
|
70 | 71 | |
|
71 | 72 | |
|
72 | 73 | class BaseModel(object): |
@@ -144,6 +145,17 b' class BaseModel(object):' | |||
|
144 | 145 | return self._get_instance( |
|
145 | 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 | 159 | @classmethod |
|
148 | 160 | def get_all(cls): |
|
149 | 161 | """ |
@@ -70,7 +70,8 b' log = logging.getLogger(__name__)' | |||
|
70 | 70 | # BASE CLASSES |
|
71 | 71 | # ============================================================================= |
|
72 | 72 | |
|
73 |
# this is propagated from .ini file |
|
|
73 | # this is propagated from .ini file rhodecode.encrypted_values.secret or | |
|
74 | # beaker.session.secret if first is not set. | |
|
74 | 75 | # and initialized at environment.py |
|
75 | 76 | ENCRYPTION_KEY = None |
|
76 | 77 | |
@@ -115,14 +116,17 b' class EncryptedTextValue(TypeDecorator):' | |||
|
115 | 116 | def process_bind_param(self, value, dialect): |
|
116 | 117 | if not value: |
|
117 | 118 | return value |
|
118 | if value.startswith('enc$aes$'): | |
|
119 | if value.startswith('enc$aes$') or value.startswith('enc$aes_hmac$'): | |
|
119 | 120 | # protect against double encrypting if someone manually starts |
|
120 | 121 | # doing |
|
121 | 122 | raise ValueError('value needs to be in unencrypted format, ie. ' |
|
122 |
'not starting with enc$aes |
|
|
123 |
return 'enc$aes$%s' % AESCipher( |
|
|
123 | 'not starting with enc$aes') | |
|
124 | return 'enc$aes_hmac$%s' % AESCipher( | |
|
125 | ENCRYPTION_KEY, hmac=True).encrypt(value) | |
|
124 | 126 | |
|
125 | 127 | def process_result_value(self, value, dialect): |
|
128 | import rhodecode | |
|
129 | ||
|
126 | 130 | if not value: |
|
127 | 131 | return value |
|
128 | 132 | |
@@ -134,9 +138,19 b' class EncryptedTextValue(TypeDecorator):' | |||
|
134 | 138 | if parts[0] != 'enc': |
|
135 | 139 | # parts ok but without our header ? |
|
136 | 140 | return value |
|
137 | ||
|
141 | enc_strict_mode = str2bool(rhodecode.CONFIG.get( | |
|
142 | 'rhodecode.encrypted_values.strict') or True) | |
|
138 | 143 | # at that stage we know it's our encryption |
|
144 | if parts[1] == 'aes': | |
|
139 | 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 | 154 | return decrypted_data |
|
141 | 155 | |
|
142 | 156 | |
@@ -220,6 +234,20 b' class BaseModel(object):' | |||
|
220 | 234 | obj = cls.query().get(id_) |
|
221 | 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 | 251 | def __repr__(self): |
|
224 | 252 | if hasattr(self, '__unicode__'): |
|
225 | 253 | # python repr needs to return str |
@@ -639,16 +667,26 b' class User(Base, BaseModel):' | |||
|
639 | 667 | log.error(traceback.format_exc()) |
|
640 | 668 | |
|
641 | 669 | @classmethod |
|
642 |
def get_by_username(cls, username, case_insensitive=False, |
|
|
670 | def get_by_username(cls, username, case_insensitive=False, | |
|
671 | cache=False, identity_cache=False): | |
|
672 | session = Session() | |
|
673 | ||
|
643 | 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 | 677 | else: |
|
646 | 678 | q = cls.query().filter(cls.username == username) |
|
647 | 679 | |
|
648 | 680 | if cache: |
|
649 | q = q.options(FromCache( | |
|
650 | "sql_cache_short", | |
|
651 | "get_user_%s" % _hash_key(username))) | |
|
681 | if identity_cache: | |
|
682 | val = cls.identity_cache(session, 'username', 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 | 690 | return q.scalar() |
|
653 | 691 | |
|
654 | 692 | @classmethod |
@@ -752,10 +790,10 b' class User(Base, BaseModel):' | |||
|
752 | 790 | Session().add(self) |
|
753 | 791 | |
|
754 | 792 | @classmethod |
|
755 | def get_first_admin(cls): | |
|
756 |
user = User.query().filter(User.admin == |
|
|
793 | def get_first_super_admin(cls): | |
|
794 | user = User.query().filter(User.admin == true()).first() | |
|
757 | 795 | if user is None: |
|
758 | raise Exception('Missing administrative account!') | |
|
796 | raise Exception('FATAL: Missing administrative account!') | |
|
759 | 797 | return user |
|
760 | 798 | |
|
761 | 799 | @classmethod |
@@ -770,7 +808,7 b' class User(Base, BaseModel):' | |||
|
770 | 808 | def get_default_user(cls, cache=False): |
|
771 | 809 | user = User.get_by_username(User.DEFAULT_USER, cache=cache) |
|
772 | 810 | if user is None: |
|
773 | raise Exception('Missing default account!') | |
|
811 | raise Exception('FATAL: Missing default account!') | |
|
774 | 812 | return user |
|
775 | 813 | |
|
776 | 814 | def _get_default_perms(self, user, suffix=''): |
@@ -1264,9 +1302,9 b' class Repository(Base, BaseModel):' | |||
|
1264 | 1302 | "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, |
|
1265 | 1303 | unique=False, default=None) |
|
1266 | 1304 | |
|
1267 | user = relationship('User') | |
|
1268 | fork = relationship('Repository', remote_side=repo_id) | |
|
1269 | group = relationship('RepoGroup') | |
|
1305 | user = relationship('User', lazy='joined') | |
|
1306 | fork = relationship('Repository', remote_side=repo_id, lazy='joined') | |
|
1307 | group = relationship('RepoGroup', lazy='joined') | |
|
1270 | 1308 | repo_to_perm = relationship( |
|
1271 | 1309 | 'UserRepoToPerm', cascade='all', |
|
1272 | 1310 | order_by='UserRepoToPerm.repo_to_perm_id') |
@@ -1364,7 +1402,7 b' class Repository(Base, BaseModel):' | |||
|
1364 | 1402 | def normalize_repo_name(cls, repo_name): |
|
1365 | 1403 | """ |
|
1366 | 1404 | Normalizes os specific repo_name to the format internally stored inside |
|
1367 |
da |
|
|
1405 | database using URL_SEP | |
|
1368 | 1406 | |
|
1369 | 1407 | :param cls: |
|
1370 | 1408 | :param repo_name: |
@@ -1372,11 +1410,20 b' class Repository(Base, BaseModel):' | |||
|
1372 | 1410 | return cls.NAME_SEP.join(repo_name.split(os.sep)) |
|
1373 | 1411 | |
|
1374 | 1412 | @classmethod |
|
1375 | def get_by_repo_name(cls, repo_name): | |
|
1376 | q = Session().query(cls).filter(cls.repo_name == repo_name) | |
|
1377 | q = q.options(joinedload(Repository.fork))\ | |
|
1378 | .options(joinedload(Repository.user))\ | |
|
1379 | .options(joinedload(Repository.group)) | |
|
1413 | def get_by_repo_name(cls, repo_name, cache=False, identity_cache=False): | |
|
1414 | session = Session() | |
|
1415 | q = session.query(cls).filter(cls.repo_name == repo_name) | |
|
1416 | ||
|
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 | 1427 | return q.scalar() |
|
1381 | 1428 | |
|
1382 | 1429 | @classmethod |
@@ -1721,7 +1768,7 b' class Repository(Base, BaseModel):' | |||
|
1721 | 1768 | clone_uri = self.clone_uri |
|
1722 | 1769 | if clone_uri: |
|
1723 | 1770 | import urlobject |
|
1724 |
url_obj = urlobject.URLObject( |
|
|
1771 | url_obj = urlobject.URLObject(clone_uri) | |
|
1725 | 1772 | if url_obj.password: |
|
1726 | 1773 | clone_uri = url_obj.with_password('*****') |
|
1727 | 1774 | return clone_uri |
@@ -138,7 +138,11 b' def UserForm(edit=False, available_langu' | |||
|
138 | 138 | return _UserForm |
|
139 | 139 | |
|
140 | 140 | |
|
141 |
def UserGroupForm(edit=False, old_data= |
|
|
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 | 146 | class _UserGroupForm(formencode.Schema): |
|
143 | 147 | allow_extra_fields = True |
|
144 | 148 | filter_extra_fields = True |
@@ -158,13 +162,17 b' def UserGroupForm(edit=False, old_data={' | |||
|
158 | 162 | if_missing=None, not_empty=False |
|
159 | 163 | ) |
|
160 | 164 | #this is user group owner |
|
161 | user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) | |
|
162 | ||
|
165 | user = All( | |
|
166 | v.UnicodeString(not_empty=True), | |
|
167 | v.ValidRepoUser(allow_disabled)) | |
|
163 | 168 | return _UserGroupForm |
|
164 | 169 | |
|
165 | 170 | |
|
166 |
def RepoGroupForm(edit=False, old_data= |
|
|
167 | can_create_in_root=False): | |
|
171 | def RepoGroupForm(edit=False, old_data=None, available_groups=None, | |
|
172 | can_create_in_root=False, allow_disabled=False): | |
|
173 | old_data = old_data or {} | |
|
174 | available_groups = available_groups or [] | |
|
175 | ||
|
168 | 176 | class _RepoGroupForm(formencode.Schema): |
|
169 | 177 | allow_extra_fields = True |
|
170 | 178 | filter_extra_fields = False |
@@ -178,11 +186,14 b' def RepoGroupForm(edit=False, old_data={' | |||
|
178 | 186 | group_parent_id = v.OneOf(available_groups, hideList=False, |
|
179 | 187 | testValueList=True, not_empty=True) |
|
180 | 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 | 192 | if edit: |
|
184 | 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 | 198 | return _RepoGroupForm |
|
188 | 199 | |
@@ -221,7 +232,8 b' def PasswordResetForm():' | |||
|
221 | 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 | 237 | old_data = old_data or {} |
|
226 | 238 | repo_groups = repo_groups or [] |
|
227 | 239 | landing_revs = landing_revs or [] |
@@ -248,7 +260,9 b' def RepoForm(edit=False, old_data=None, ' | |||
|
248 | 260 | |
|
249 | 261 | if edit: |
|
250 | 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 | 266 | clone_uri_change = v.UnicodeString( |
|
253 | 267 | not_empty=False, if_missing=v.Missing) |
|
254 | 268 |
@@ -140,10 +140,12 b' class RepoModel(BaseModel):' | |||
|
140 | 140 | |
|
141 | 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 | 144 | # TODO: mikhail: move this method to the UserModel. |
|
145 | 145 | query = self.sa.query(User) |
|
146 | if only_active: | |
|
146 | 147 | query = query.filter(User.active == true()) |
|
148 | ||
|
147 | 149 | if name_contains: |
|
148 | 150 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) |
|
149 | 151 | query = query.filter( |
@@ -165,16 +167,19 b' class RepoModel(BaseModel):' | |||
|
165 | 167 | 'icon_link': h.gravatar_url(user.email, 14), |
|
166 | 168 | 'value_display': h.person(user.email), |
|
167 | 169 | 'value': user.username, |
|
168 | 'value_type': 'user' | |
|
170 | 'value_type': 'user', | |
|
171 | 'active': user.active, | |
|
169 | 172 | } |
|
170 | 173 | for user in users |
|
171 | 174 | ] |
|
172 | 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 | 178 | # TODO: mikhail: move this method to the UserGroupModel. |
|
176 | 179 | query = self.sa.query(UserGroup) |
|
180 | if only_active: | |
|
177 | 181 | query = query.filter(UserGroup.users_group_active == true()) |
|
182 | ||
|
178 | 183 | if name_contains: |
|
179 | 184 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) |
|
180 | 185 | query = query.filter( |
@@ -196,7 +201,8 b' class RepoModel(BaseModel):' | |||
|
196 | 201 | 'value_display': 'Group: %s (%d members)' % ( |
|
197 | 202 | group.users_group_name, len(group.members),), |
|
198 | 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 | 207 | for group in user_groups |
|
202 | 208 | ] |
@@ -333,7 +339,7 b' class RepoModel(BaseModel):' | |||
|
333 | 339 | if repo_info.user: |
|
334 | 340 | defaults.update({'user': repo_info.user.username}) |
|
335 | 341 | else: |
|
336 | replacement_user = User.get_first_admin().username | |
|
342 | replacement_user = User.get_first_super_admin().username | |
|
337 | 343 | defaults.update({'user': replacement_user}) |
|
338 | 344 | |
|
339 | 345 | # fill repository users |
@@ -23,6 +23,7 b' import logging' | |||
|
23 | 23 | from collections import namedtuple |
|
24 | 24 | from functools import wraps |
|
25 | 25 | |
|
26 | from rhodecode.lib import caches | |
|
26 | 27 | from rhodecode.lib.caching_query import FromCache |
|
27 | 28 | from rhodecode.lib.utils2 import ( |
|
28 | 29 | Optional, AttributeDict, safe_str, remove_prefix, str2bool) |
@@ -200,15 +201,14 b' class SettingsModel(BaseModel):' | |||
|
200 | 201 | Session.add(res) |
|
201 | 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 | 209 | def get_all_settings(self, cache=False): |
|
210 | def _compute(): | |
|
204 | 211 | q = self._get_settings_query() |
|
205 | if cache: | |
|
206 | repo = self._get_repo(self.repo) if self.repo else None | |
|
207 | cache_key = ( | |
|
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 | ||
|
212 | 212 | if not q: |
|
213 | 213 | raise Exception('Could not get application settings !') |
|
214 | 214 | |
@@ -218,6 +218,21 b' class SettingsModel(BaseModel):' | |||
|
218 | 218 | } |
|
219 | 219 | return settings |
|
220 | 220 | |
|
221 | if cache: | |
|
222 | log.debug('Fetching app settings using cache') | |
|
223 | repo = self._get_repo(self.repo) if self.repo else None | |
|
224 | namespace = 'rhodecode_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() | |
|
235 | ||
|
221 | 236 | def get_auth_settings(self): |
|
222 | 237 | q = self._get_settings_query() |
|
223 | 238 | q = q.filter( |
@@ -26,13 +26,13 b' import logging' | |||
|
26 | 26 | import traceback |
|
27 | 27 | |
|
28 | 28 | import datetime |
|
29 | from pylons import url | |
|
30 | 29 | from pylons.i18n.translation import _ |
|
31 | 30 | |
|
32 | 31 | import ipaddress |
|
33 | 32 | from sqlalchemy.exc import DatabaseError |
|
34 | 33 | from sqlalchemy.sql.expression import true, false |
|
35 | 34 | |
|
35 | from rhodecode.events import UserPreCreate, UserPreUpdate | |
|
36 | 36 | from rhodecode.lib.utils2 import ( |
|
37 | 37 | safe_unicode, get_current_rhodecode_user, action_logger_generic, |
|
38 | 38 | AttributeDict) |
@@ -270,10 +270,12 b' class UserModel(BaseModel):' | |||
|
270 | 270 | # raises UserCreationError if it's not allowed for any reason to |
|
271 | 271 | # create new active user, this also executes pre-create hooks |
|
272 | 272 | check_allowed_create_user(user_data, cur_user, strict_check=True) |
|
273 | self.send_event(UserPreCreate(user_data)) | |
|
273 | 274 | new_user = User() |
|
274 | 275 | edit = False |
|
275 | 276 | else: |
|
276 | 277 | log.debug('updating user %s', username) |
|
278 | self.send_event(UserPreUpdate(user, user_data)) | |
|
277 | 279 | new_user = user |
|
278 | 280 | edit = True |
|
279 | 281 | |
@@ -375,7 +377,7 b' class UserModel(BaseModel):' | |||
|
375 | 377 | raise |
|
376 | 378 | |
|
377 | 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 | 381 | left_overs = True |
|
380 | 382 | |
|
381 | 383 | from rhodecode.model.repo import RepoModel |
@@ -398,7 +400,7 b' class UserModel(BaseModel):' | |||
|
398 | 400 | |
|
399 | 401 | def _handle_user_repo_groups(self, username, repository_groups, |
|
400 | 402 | handle_mode=None): |
|
401 | _superadmin = self.cls.get_first_admin() | |
|
403 | _superadmin = self.cls.get_first_super_admin() | |
|
402 | 404 | left_overs = True |
|
403 | 405 | |
|
404 | 406 | from rhodecode.model.repo_group import RepoGroupModel |
@@ -420,7 +422,7 b' class UserModel(BaseModel):' | |||
|
420 | 422 | return left_overs |
|
421 | 423 | |
|
422 | 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 | 426 | left_overs = True |
|
425 | 427 | |
|
426 | 428 | from rhodecode.model.user_group import UserGroupModel |
@@ -498,7 +498,7 b' class UserGroupModel(BaseModel):' | |||
|
498 | 498 | self.remove_user_from_group(gr, user) |
|
499 | 499 | |
|
500 | 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 | 502 | for gr in set(groups): |
|
503 | 503 | existing_group = UserGroup.get_by_group_name(gr) |
|
504 | 504 | if not existing_group: |
@@ -193,21 +193,26 b' def ValidRegex(msg=None):' | |||
|
193 | 193 | return _validator |
|
194 | 194 | |
|
195 | 195 | |
|
196 | def ValidRepoUser(): | |
|
196 | def ValidRepoUser(allow_disabled=False): | |
|
197 | 197 | class _validator(formencode.validators.FancyValidator): |
|
198 | 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 | 203 | def validate_python(self, value, state): |
|
203 | 204 | try: |
|
204 |
User.query().filter(User. |
|
|
205 | .filter(User.username == value).one() | |
|
205 | user = User.query().filter(User.username == value).one() | |
|
206 | 206 | except Exception: |
|
207 | 207 | msg = M(self, 'invalid_username', state, username=value) |
|
208 | 208 | raise formencode.Invalid( |
|
209 | 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 | 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 | 300 | // for situations where we wish to display the form value but not the form input |
|
274 | 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 | 306 | .pullrequestlist { |
|
302 | max-width: @pullrequest-width; | |
|
303 | margin-bottom: @space; | |
|
304 | ||
|
305 | // Tweaks for "My Account" / "Pull requests" | |
|
306 | .prwrapper { | |
|
307 | clear: left; | |
|
308 | ||
|
309 | .pr { | |
|
310 | margin: 0; | |
|
311 | padding: 0; | |
|
312 | border-bottom: none; | |
|
307 | .closed { | |
|
308 | background-color: @grey6; | |
|
309 | } | |
|
310 | .td-status { | |
|
311 | padding-left: .5em; | |
|
313 | 312 |
|
|
314 | ||
|
315 | // TODO: johbo: Replace with something that makes up an inline form or | |
|
316 | // similar. | |
|
317 | .repolist_actions { | |
|
318 | display: inline-block; | |
|
313 | .truncate { | |
|
314 | height: 2.75em; | |
|
315 | white-space: pre-line; | |
|
316 | } | |
|
317 | table.rctable .user { | |
|
318 | padding-left: 0; | |
|
319 | 319 |
|
|
320 | 320 | } |
|
321 | 321 | |
|
322 | } | |
|
322 | // Pull Requests | |
|
323 | 323 | |
|
324 | 324 | .pullrequests_section_head { |
|
325 | 325 | display: block; |
@@ -1086,6 +1086,7 b' table.issuetracker {' | |||
|
1086 | 1086 | } |
|
1087 | 1087 | } |
|
1088 | 1088 | |
|
1089 | ||
|
1089 | 1090 | //Permissions Settings |
|
1090 | 1091 | #add_perm { |
|
1091 | 1092 | margin: 0 0 @padding; |
@@ -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 | 296 | .submenu { |
|
292 | 297 | position: absolute; |
|
293 | 298 | top: 100%; |
@@ -6,7 +6,6 b'' | |||
|
6 | 6 | |
|
7 | 7 | width: 100%; |
|
8 | 8 | margin: 0 0 25px 0; |
|
9 | border-color: @grey5; | |
|
10 | 9 | .border-radius(@border-radius); |
|
11 | 10 | .box-shadow(none); |
|
12 | 11 | |
@@ -23,7 +22,6 b'' | |||
|
23 | 22 | position: relative; |
|
24 | 23 | min-height: 1em; |
|
25 | 24 | padding: @padding @panel-padding; |
|
26 | background-color: @grey6; | |
|
27 | 25 | border-bottom: none; |
|
28 | 26 | |
|
29 | 27 | .panel-title, |
@@ -20,18 +20,24 b'' | |||
|
20 | 20 | * autocomplete formatter that uses gravatar |
|
21 | 21 | * */ |
|
22 | 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 | 30 | var escapeRegExChars = function (value) { |
|
25 | 31 | return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); |
|
26 | 32 | }; |
|
27 | 33 | var pattern = '(' + escapeRegExChars(value) + ')'; |
|
28 |
value |
|
|
34 | valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); | |
|
29 | 35 | var tmpl = '<div class="ac-container-wrap"><img class="gravatar" src="{0}"/>{1}</div>'; |
|
30 | 36 | if (data.icon_link === "") { |
|
31 | 37 | tmpl = '<div class="ac-container-wrap">{0}</div>'; |
|
32 |
return tmpl.format(value |
|
|
38 | return tmpl.format(valueDisplay); | |
|
33 | 39 | } |
|
34 |
return tmpl.format(data.icon_link, value |
|
|
40 | return tmpl.format(data.icon_link, valueDisplay); | |
|
35 | 41 | }; |
|
36 | 42 | |
|
37 | 43 | /** |
@@ -1,7 +1,7 b'' | |||
|
1 | <%namespace name="base" file="/base/base.html"/> | |
|
1 | 2 | |
|
2 | 3 | <div class="panel panel-default"> |
|
3 | 4 | <div class="panel-body"> |
|
4 | <div class="field"> | |
|
5 | 5 | %if c.show_closed: |
|
6 | 6 | ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))} |
|
7 | 7 | %else: |
@@ -9,35 +9,62 b'' | |||
|
9 | 9 | %endif |
|
10 | 10 |
|
|
11 | 11 |
|
|
12 | </div> | |
|
13 | 12 | |
|
14 | 13 | <div class="panel panel-default"> |
|
15 | 14 | <div class="panel-heading"> |
|
16 | 15 | <h3 class="panel-title">${_('Pull Requests You Opened')}</h3> |
|
17 | 16 | </div> |
|
18 | ||
|
19 | 17 | <div class="panel-body"> |
|
20 | 18 | <div class="pullrequestlist"> |
|
21 | 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 | 30 | %for pull_request in c.my_pull_requests: |
|
23 |
< |
|
|
24 |
<d |
|
|
31 | <tr class="${'closed' if pull_request.is_closed() else ''} prwrapper"> | |
|
32 | <td class="td-status"> | |
|
25 | 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)}"> | |
|
27 | ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.format_date(pull_request.created_on))} | |
|
34 | </td> | |
|
35 | <td class="td-componentname"> | |
|
36 | ${h.link_to(pull_request.target_repo.repo_name,h.url('summary_home',repo_name=pull_request.target_repo.repo_name))} | |
|
37 | </td> | |
|
38 | <td class="user"> | |
|
39 | ${base.gravatar_with_user(pull_request.author.email, 16)} | |
|
40 | </td> | |
|
41 | <td class="td-message expand_commit" data-pr-id="m${pull_request.pull_request_id}" title="${_('Expand commit message')}"> | |
|
42 | <div class="show_more_col"> | |
|
43 | <i class="show_more"></i> | |
|
44 | </div> | |
|
45 | </td> | |
|
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>\ | |
|
28 | 49 | %if pull_request.is_closed(): |
|
29 | (${_('Closed')}) | |
|
50 | (${_('Closed')})\ | |
|
30 | 51 | %endif |
|
31 | </a> | |
|
32 |
<div |
|
|
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"> | |
|
33 | 60 |
|
|
34 | 61 |
|
|
35 | 62 |
|
|
36 | 63 |
|
|
37 |
|
|
|
38 |
|
|
|
39 | </div> | |
|
64 | </td> | |
|
65 | </tr> | |
|
40 | 66 | %endfor |
|
67 | </table> | |
|
41 | 68 | %else: |
|
42 | 69 | <h2><span class="empty_data">${_('You currently have no open pull requests.')}</span></h2> |
|
43 | 70 | %endif |
@@ -53,21 +80,49 b'' | |||
|
53 | 80 | <div class="panel-body"> |
|
54 | 81 | <div class="pullrequestlist"> |
|
55 | 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 | 92 | %for pull_request in c.participate_in_pull_requests: |
|
57 |
< |
|
|
58 |
<d |
|
|
93 | <tr class="${'closed' if pull_request.is_closed() else ''} prwrapper"> | |
|
94 | <td class="td-status"> | |
|
59 | 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)}"> | |
|
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))} | |
|
62 | </a> | |
|
96 | </td> | |
|
97 | <td class="td-componentname"> | |
|
98 | ${h.link_to(pull_request.target_repo.repo_name,h.url('summary_home',repo_name=pull_request.target_repo.repo_name))} | |
|
99 | </td> | |
|
100 | <td class="user"> | |
|
101 | ${base.gravatar_with_user(pull_request.author.email, 16)} | |
|
102 | </td> | |
|
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> | |
|
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>\ | |
|
63 | 111 | %if pull_request.is_closed(): |
|
64 | (${_('Closed')}) | |
|
112 | (${_('Closed')})\ | |
|
65 | 113 | %endif |
|
66 | </div> | |
|
114 | <br/>${pull_request.description}</div> | |
|
67 | 115 | </div> |
|
116 | </td> | |
|
117 | ||
|
118 | <td class="td-time"> | |
|
119 | ${h.age_component(pull_request.created_on)} | |
|
120 | </td> | |
|
121 | </tr> | |
|
68 | 122 | %endfor |
|
123 | </table> | |
|
69 | 124 | %else: |
|
70 |
< |
|
|
125 | <h2 class="empty_data">${_('There are currently no open pull requests requiring your participation.')}</h2> | |
|
71 | 126 | %endif |
|
72 | 127 | </div> |
|
73 | 128 | </div> |
@@ -81,5 +136,18 b'' | |||
|
81 | 136 | else{ |
|
82 | 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 | 153 | </script> |
@@ -1,4 +1,6 b'' | |||
|
1 | 1 | ## -*- coding: utf-8 -*- |
|
2 | <%namespace name="base" file="/base/base.html"/> | |
|
3 | ||
|
2 | 4 | <div class="panel panel-default"> |
|
3 | 5 | <div class="panel-heading"> |
|
4 | 6 | <h3 class="panel-title">${_('Settings for Repository Group: %s') % c.repo_group.name}</h3> |
@@ -16,15 +18,25 b'' | |||
|
16 | 18 | ${h.text('group_name',class_='medium')} |
|
17 | 19 | </div> |
|
18 | 20 | </div> |
|
19 | <div class="field"> | |
|
21 | ||
|
22 | <div class="field badged-field"> | |
|
20 | 23 | <div class="label"> |
|
21 | 24 | <label for="user">${_('Owner')}:</label> |
|
22 | 25 | </div> |
|
23 | 26 | <div class="input"> |
|
27 | <div class="badge-input-container"> | |
|
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"> | |
|
24 | 32 | ${h.text('user', class_="medium", autocomplete="off")} |
|
25 | <span class="help-block">${_('Change Repository Group Owner.')}</span> | |
|
26 | 33 | </div> |
|
27 | 34 | </div> |
|
35 | <form:error name="user"/> | |
|
36 | <p class="help-block">${_('Change owner of this repository group.')}</p> | |
|
37 | </div> | |
|
38 | </div> | |
|
39 | ||
|
28 | 40 | <div class="field"> |
|
29 | 41 | <div class="label label-textarea"> |
|
30 | 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 | 4 | <div class="panel panel-default"> |
|
2 | 5 | <div class="panel-heading"> |
|
3 | 6 | <h3 class="panel-title">${_('Settings for Repository: %s') % c.repo_info.repo_name}</h3> |
@@ -69,15 +72,25 b'' | |||
|
69 | 72 | <p class="help-block">${_('Default commit for files page, downloads, whoosh and readme')}</p> |
|
70 | 73 | </div> |
|
71 | 74 | </div> |
|
72 | <div class="field"> | |
|
75 | ||
|
76 | <div class="field badged-field"> | |
|
73 | 77 | <div class="label"> |
|
74 | 78 | <label for="user">${_('Owner')}:</label> |
|
75 | 79 | </div> |
|
76 | 80 | <div class="input"> |
|
81 | <div class="badge-input-container"> | |
|
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"> | |
|
77 | 86 | ${h.text('user', class_="medium", autocomplete="off")} |
|
87 | </div> | |
|
88 | </div> | |
|
89 | <form:error name="user"/> | |
|
78 | 90 |
|
|
79 | 91 | </div> |
|
80 | 92 |
|
|
93 | ||
|
81 | 94 | <div class="field"> |
|
82 | 95 | <div class="label label-textarea"> |
|
83 | 96 | <label for="repo_description">${_('Description')}:</label> |
@@ -20,6 +20,7 b'' | |||
|
20 | 20 | <td> |
|
21 | 21 | ${h.literal(', '.join([ |
|
22 | 22 | '<a href="%(link)s" title="%(name)s">%(name)s</a>' % {'link':link, 'name':name} |
|
23 | if link else name | |
|
23 | 24 | for name,link in licenses.items()]))} |
|
24 | 25 | </td> |
|
25 | 26 | </tr> |
@@ -45,6 +45,9 b'' | |||
|
45 | 45 | <div class="panel panel-default"> |
|
46 | 46 | <div class="panel-heading"> |
|
47 | 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 | 51 | </div> |
|
49 | 52 | <div class="panel-body"> |
|
50 | 53 | <dl class="dl-horizontal settings"> |
@@ -1,3 +1,6 b'' | |||
|
1 | ## -*- coding: utf-8 -*- | |
|
2 | <%namespace name="base" file="/base/base.html"/> | |
|
3 | ||
|
1 | 4 | <div class="panel panel-default"> |
|
2 | 5 | <div class="panel-heading"> |
|
3 | 6 | <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3> |
@@ -15,15 +18,25 b'' | |||
|
15 | 18 | ${h.text('users_group_name',class_='medium')} |
|
16 | 19 | </div> |
|
17 | 20 | </div> |
|
18 | <div class="field"> | |
|
21 | ||
|
22 | <div class="field badged-field"> | |
|
19 | 23 | <div class="label"> |
|
20 | 24 | <label for="user">${_('Owner')}:</label> |
|
21 | 25 | </div> |
|
22 | 26 | <div class="input"> |
|
27 | <div class="badge-input-container"> | |
|
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"> | |
|
23 | 32 | ${h.text('user', class_="medium", autocomplete="off")} |
|
24 | <span class="help-block">${_('Change owner of this user group.')}</span> | |
|
25 | 33 | </div> |
|
26 | 34 | </div> |
|
35 | <form:error name="user"/> | |
|
36 | <p class="help-block">${_('Change owner of this user group.')}</p> | |
|
37 | </div> | |
|
38 | </div> | |
|
39 | ||
|
27 | 40 | <div class="field"> |
|
28 | 41 | <div class="label label-textarea"> |
|
29 | 42 | <label for="user_group_description">${_('Description')}:</label> |
@@ -128,7 +128,6 b'' | |||
|
128 | 128 | </div> |
|
129 | 129 | ${h.end_form()} |
|
130 | 130 | </div> |
|
131 | </%def> | |
|
132 | 131 | <script> |
|
133 | 132 | $(document).ready(function(){ |
|
134 | 133 | $('#username').focus(); |
@@ -142,3 +141,4 b'' | |||
|
142 | 141 | }) |
|
143 | 142 | }) |
|
144 | 143 | </script> |
|
144 | </%def> |
@@ -134,10 +134,10 b'' | |||
|
134 | 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 | 138 | <div class="rc-user tooltip" title="${contact}"> |
|
139 | 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 | 141 | </div> |
|
142 | 142 | </%def> |
|
143 | 143 | |
@@ -195,7 +195,7 b'' | |||
|
195 | 195 | %if repo_instance.clone_uri: |
|
196 | 196 | <p> |
|
197 | 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 | 199 | </p> |
|
200 | 200 | %endif |
|
201 | 201 |
@@ -13,9 +13,10 b' A new user `${user.username}` has regist' | |||
|
13 | 13 | - Username: ${user.username} |
|
14 | 14 | - Full Name: ${user.firstname} ${user.lastname} |
|
15 | 15 | - Email: ${user.email} |
|
16 | - Profile link: ${h.url('user_profile', username=user.username, qualified=True)} | |
|
16 | 17 | </%def> |
|
17 | 18 | |
|
18 | 19 | ## BODY GOES BELOW |
|
19 | 20 | <div style="white-space: pre-wrap"> |
|
20 | 21 | ${body_plaintext()} |
|
21 | </div> No newline at end of file | |
|
22 | </div> |
@@ -27,7 +27,7 b'' | |||
|
27 | 27 | <div class="left-column"> |
|
28 | 28 | <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/> |
|
29 | 29 | </div> |
|
30 | ||
|
30 | <%block name="above_login_button" /> | |
|
31 | 31 | <div id="login" class="right-column"> |
|
32 | 32 | <%include file="/base/flash_msg.html"/> |
|
33 | 33 | <!-- login --> |
@@ -47,9 +47,9 b'' | |||
|
47 | 47 | <ul class="nav nav-pills nav-stacked"> |
|
48 | 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 | 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 | 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 | 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 | 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 | 54 | </ul> |
|
55 | 55 | </div> |
@@ -27,7 +27,7 b'' | |||
|
27 | 27 | <div class="left-column"> |
|
28 | 28 | <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/> |
|
29 | 29 | </div> |
|
30 | ||
|
30 | <%block name="above_register_button" /> | |
|
31 | 31 | <div id="register" class="right-column"> |
|
32 | 32 | <%include file="/base/flash_msg.html"/> |
|
33 | 33 | <!-- login --> |
@@ -85,9 +85,12 b' class TestMyAccountController(TestContro' | |||
|
85 | 85 | response = self.app.get(url('my_account_pullrequests')) |
|
86 | 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 | 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 | 95 | def test_my_account_my_emails(self): |
|
93 | 96 | self.log_user() |
@@ -460,6 +460,10 b' class TestLabsSettings(object):' | |||
|
460 | 460 | |
|
461 | 461 | @pytest.mark.usefixtures('app') |
|
462 | 462 | class TestOpenSourceLicenses(object): |
|
463 | ||
|
464 | def _get_url(self): | |
|
465 | return ADMIN_PREFIX + '/settings/open_source' | |
|
466 | ||
|
463 | 467 | def test_records_are_displayed(self, autologin_user): |
|
464 | 468 | sample_licenses = { |
|
465 | 469 | "python2.7-pytest-2.7.1": { |
@@ -470,11 +474,10 b' class TestOpenSourceLicenses(object):' | |||
|
470 | 474 | } |
|
471 | 475 | } |
|
472 | 476 | read_licenses_patch = mock.patch( |
|
473 |
'rhodecode. |
|
|
477 | 'rhodecode.admin.views.read_opensource_licenses', | |
|
474 | 478 | return_value=sample_licenses) |
|
475 | 479 | with read_licenses_patch: |
|
476 | response = self.app.get( | |
|
477 | url('admin_settings_open_source'), status=200) | |
|
480 | response = self.app.get(self._get_url(), status=200) | |
|
478 | 481 | |
|
479 | 482 | assert_response = AssertResponse(response) |
|
480 | 483 | assert_response.element_contains( |
@@ -485,14 +488,13 b' class TestOpenSourceLicenses(object):' | |||
|
485 | 488 | assert_response.element_contains('.panel-body', license) |
|
486 | 489 | |
|
487 | 490 | def test_records_can_be_read(self, autologin_user): |
|
488 |
response = self.app.get(url( |
|
|
491 | response = self.app.get(self._get_url(), status=200) | |
|
489 | 492 | assert_response = AssertResponse(response) |
|
490 | 493 | assert_response.element_contains( |
|
491 | 494 | '.panel-heading', 'Licenses of Third Party Packages') |
|
492 | 495 | |
|
493 | 496 | def test_forbidden_when_normal_user(self, autologin_regular_user): |
|
494 | self.app.get( | |
|
495 | url('admin_settings_open_source'), status=403) | |
|
497 | self.app.get(self._get_url(), status=403) | |
|
496 | 498 | |
|
497 | 499 | |
|
498 | 500 | @pytest.mark.usefixtures("app") |
@@ -33,7 +33,7 b' class TestFeedController(TestController)' | |||
|
33 | 33 | assert """<rss version="2.0">""" in response |
|
34 | 34 | |
|
35 | 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 | 37 | assert auth_token != '' |
|
38 | 38 | response = self.app.get(url(controller='feed', action='rss', |
|
39 | 39 | repo_name=backend.repo_name, auth_token=auth_token)) |
@@ -110,10 +110,12 b' class TestHomeController(TestController)' | |||
|
110 | 110 | def test_index_show_version(self, autologin_user, name, state): |
|
111 | 111 | version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__ |
|
112 | 112 | |
|
113 |
s |
|
|
114 | show.app_settings_value = state | |
|
115 |
Session().add(s |
|
|
113 | sett = SettingsModel().create_or_update_setting( | |
|
114 | 'show_version', state, 'bool') | |
|
115 | Session().add(sett) | |
|
116 | 116 | Session().commit() |
|
117 | SettingsModel().invalidate_settings_cache() | |
|
118 | ||
|
117 | 119 | response = self.app.get(url(controller='home', action='index')) |
|
118 | 120 | if state is True: |
|
119 | 121 | response.mustcontain(version_string) |
@@ -133,6 +135,18 b' class TestUserAutocompleteData(TestContr' | |||
|
133 | 135 | values = [suggestion['value'] for suggestion in result['suggestions']] |
|
134 | 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 | 150 | def test_returns_groups_when_user_groups_sent(self, user_util): |
|
137 | 151 | self.log_user() |
|
138 | 152 | group = user_util.create_user_group(user_groups_active=True) |
@@ -173,8 +187,10 b' class TestUserAutocompleteData(TestContr' | |||
|
173 | 187 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) |
|
174 | 188 | |
|
175 | 189 | result = json.loads(response.body) |
|
176 |
users_mock.assert_called_once_with( |
|
|
177 | groups_mock.assert_called_once_with(name_contains=query) | |
|
190 | users_mock.assert_called_once_with( | |
|
191 | name_contains=query, only_active=True) | |
|
192 | groups_mock.assert_called_once_with( | |
|
193 | name_contains=query, only_active=True) | |
|
178 | 194 | assert len(result['suggestions']) == 20 |
|
179 | 195 | |
|
180 | 196 |
@@ -448,7 +448,7 b' class TestLoginController:' | |||
|
448 | 448 | assert [] == whitelist['api_access_controllers_whitelist'] |
|
449 | 449 | if test_name == 'proper_auth_token': |
|
450 | 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 | 453 | with fixture.anon_access(False): |
|
454 | 454 | self.app.get(url(controller='changeset', |
@@ -471,7 +471,7 b' class TestLoginController:' | |||
|
471 | 471 | assert ['ChangesetController:changeset_raw'] == \ |
|
472 | 472 | whitelist['api_access_controllers_whitelist'] |
|
473 | 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 | 476 | with fixture.anon_access(False): |
|
477 | 477 | self.app.get(url(controller='changeset', |
@@ -19,36 +19,35 b'' | |||
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 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, |
|
|
26 |
('/', |
|
|
27 |
('/_admin/settings', |
|
|
28 |
('/_admin/i_am_fine', |
|
|
29 |
('/_admin/settings/mappings', |
|
|
30 |
('/_admin/my_account/repos', |
|
|
31 |
('/_admin/create_repository', |
|
|
32 |
('/_admin/gists/1', |
|
|
33 |
('/_admin/notifications/1', |
|
|
28 | @pytest.mark.parametrize('url, should_raise', [ | |
|
29 | ('/', False), | |
|
30 | ('/_admin/settings', False), | |
|
31 | ('/_admin/i_am_fine', False), | |
|
32 | ('/_admin/settings/mappings', True), | |
|
33 | ('/_admin/my_account/repos', True), | |
|
34 | ('/_admin/create_repository', True), | |
|
35 | ('/_admin/gists/1', True), | |
|
36 | ('/_admin/notifications/1', True), | |
|
34 | 37 | ]) |
|
35 |
def test_vcs_disabled(url, |
|
|
36 |
app = DisableVCSPagesWrapper( |
|
|
37 | assert expected_url == app(get_environ(url), None) | |
|
38 | ||
|
38 | def test_vcs_disabled(url, should_raise): | |
|
39 | wrapped_view = DisableVCSPagesWrapper(pyramid_view) | |
|
40 | request = DummyRequest(path=url) | |
|
39 | 41 | |
|
40 | def get_environ(url): | |
|
41 | """Construct a minimum WSGI environ based on the URL.""" | |
|
42 | environ = { | |
|
43 | 'PATH_INFO': url, | |
|
44 | } | |
|
45 | return environ | |
|
46 | ||
|
42 | if should_raise: | |
|
43 | with pytest.raises(VCSServerUnavailable): | |
|
44 | response = wrapped_view(None, request) | |
|
45 | else: | |
|
46 | response = wrapped_view(None, request) | |
|
47 | assert response.status_int == 200 | |
|
47 | 48 | |
|
48 | class SimpleApp(object): | |
|
49 | def pyramid_view(context, request): | |
|
49 | 50 | """ |
|
50 |
A mock |
|
|
51 | from the middleware | |
|
51 | A mock pyramid view to be used in the wrapper | |
|
52 | 52 | """ |
|
53 | def __call__(self, environ, start_response): | |
|
54 | return environ['PATH_INFO'] | |
|
53 | return Response('success') |
@@ -20,7 +20,8 b'' | |||
|
20 | 20 | |
|
21 | 21 | import pytest |
|
22 | 22 | |
|
23 |
from rhodecode.lib.encrypt import |
|
|
23 | from rhodecode.lib.encrypt import ( | |
|
24 | AESCipher, SignatureVerificationError, InvalidDecryptedValue) | |
|
24 | 25 | |
|
25 | 26 | |
|
26 | 27 | class TestEncryptModule(object): |
@@ -38,3 +39,38 b' class TestEncryptModule(object):' | |||
|
38 | 39 | def test_encryption(self, key, text): |
|
39 | 40 | enc = AESCipher(key).encrypt(text) |
|
40 | 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 | 84 | 'pref': '#', |
|
85 | 85 | } |
|
86 | 86 | } |
|
87 | ||
|
88 | def get_settings_mock(self, cache=True): | |
|
89 | return config | |
|
90 | ||
|
87 | 91 | with mock.patch.object(IssueTrackerSettingsModel, |
|
88 |
'get_settings', |
|
|
92 | 'get_settings', get_settings_mock): | |
|
89 | 93 | processed_text = helpers.process_patterns( |
|
90 | 94 | text_string, repo.repo_name, config) |
|
91 | 95 | |
@@ -106,8 +110,12 b' def test_process_patterns_no_repo(text_s' | |||
|
106 | 110 | 'pref': '#', |
|
107 | 111 | } |
|
108 | 112 | } |
|
113 | ||
|
114 | def get_settings_mock(self, cache=True): | |
|
115 | return config | |
|
116 | ||
|
109 | 117 | with mock.patch.object(IssueTrackerSettingsModel, |
|
110 |
'get_global_settings', |
|
|
118 | 'get_global_settings', get_settings_mock): | |
|
111 | 119 | processed_text = helpers.process_patterns( |
|
112 | 120 | text_string, '', config) |
|
113 | 121 | |
@@ -126,8 +134,12 b' def test_process_patterns_non_existent_r' | |||
|
126 | 134 | 'pref': '#', |
|
127 | 135 | } |
|
128 | 136 | } |
|
137 | ||
|
138 | def get_settings_mock(self, cache=True): | |
|
139 | return config | |
|
140 | ||
|
129 | 141 | with mock.patch.object(IssueTrackerSettingsModel, |
|
130 |
'get_global_settings', |
|
|
142 | 'get_global_settings', get_settings_mock): | |
|
131 | 143 | processed_text = helpers.process_patterns( |
|
132 | 144 | text_string, 'do-not-exist', config) |
|
133 | 145 | |
@@ -182,10 +194,12 b' def test_get_matching_offsets(test_text,' | |||
|
182 | 194 | assert helpers.get_matching_offsets( |
|
183 | 195 | test_text, text_phrases) == expected_output |
|
184 | 196 | |
|
197 | ||
|
185 | 198 | def test_normalize_text_for_matching(): |
|
186 | 199 | assert helpers.normalize_text_for_matching( |
|
187 | 200 | 'OJjfe)*#$*@)$JF*)3r2f80h') == 'ojjfe jf 3r2f80h' |
|
188 | 201 | |
|
202 | ||
|
189 | 203 | def test_get_matching_line_offsets(): |
|
190 | 204 | assert helpers.get_matching_line_offsets([ |
|
191 | 205 | 'words words words', |
@@ -193,4 +207,4 b' def test_get_matching_line_offsets():' | |||
|
193 | 207 | 'some text some', |
|
194 | 208 | 'words words words', |
|
195 | 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 | 29 | from rhodecode.lib import caching_query |
|
30 | 30 | from rhodecode.lib import utils |
|
31 | 31 | from rhodecode.lib.utils2 import md5 |
|
32 | from rhodecode.model import settings | |
|
32 | 33 | from rhodecode.model import db |
|
33 | 34 | from rhodecode.model import meta |
|
34 | 35 | from rhodecode.model.repo import RepoModel |
@@ -402,7 +403,7 b' class TestConfigDataFromDb(object):' | |||
|
402 | 403 | ] |
|
403 | 404 | repo_name = 'test_repo' |
|
404 | 405 | |
|
405 |
model_patch = mock.patch.object( |
|
|
406 | model_patch = mock.patch.object(settings, 'VcsSettingsModel') | |
|
406 | 407 | hooks_patch = mock.patch.object( |
|
407 | 408 | utils, 'get_enabled_hook_classes', |
|
408 | 409 | return_value=['pull', 'push', 'repo_size']) |
@@ -432,7 +432,13 b' def test_get_repo_by_id(test, expected):' | |||
|
432 | 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 | 442 | from beaker.cache import cache_region |
|
437 | 443 | from rhodecode.lib import caches |
|
438 | 444 | from rhodecode.model.db import CacheKey |
@@ -442,7 +448,7 b' def test_invalidation_context(pylonsapp)' | |||
|
442 | 448 | return 'result' |
|
443 | 449 | |
|
444 | 450 | invalidator_context = CacheKey.repo_context_cache( |
|
445 |
_dummy_func, |
|
|
451 | _dummy_func, test_repo_name, 'repo') | |
|
446 | 452 | |
|
447 | 453 | with invalidator_context as context: |
|
448 | 454 | invalidated = context.invalidate() |
@@ -452,6 +458,8 b' def test_invalidation_context(pylonsapp)' | |||
|
452 | 458 | assert 'result' == result |
|
453 | 459 | assert isinstance(context, caches.FreshRegionCache) |
|
454 | 460 | |
|
461 | assert 'InvalidationContext' in repr(invalidator_context) | |
|
462 | ||
|
455 | 463 | with invalidator_context as context: |
|
456 | 464 | context.invalidate() |
|
457 | 465 | result = context.compute() |
@@ -58,30 +58,43 b' def stub_session():' | |||
|
58 | 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 | 72 | repo_maker = client_http.RepoMaker( |
|
63 | 'server_and_port', 'endpoint', stub_session) | |
|
73 | 'server_and_port', 'endpoint', stub_session_factory) | |
|
64 | 74 | repo_maker.example_call() |
|
65 | stub_session.post.assert_called_with( | |
|
75 | stub_session_factory().post.assert_called_with( | |
|
66 | 76 | 'http://server_and_port/endpoint', data=mock.ANY) |
|
67 | 77 | |
|
68 | 78 | |
|
69 | 79 | def test_repo_maker_uses_session_for_instance_methods( |
|
70 | stub_session, config): | |
|
80 | stub_session_factory, config): | |
|
71 | 81 | repo_maker = client_http.RepoMaker( |
|
72 | 'server_and_port', 'endpoint', stub_session) | |
|
82 | 'server_and_port', 'endpoint', stub_session_factory) | |
|
73 | 83 | repo = repo_maker('stub_path', config) |
|
74 | 84 | repo.example_call() |
|
75 | stub_session.post.assert_called_with( | |
|
85 | stub_session_factory().post.assert_called_with( | |
|
76 | 86 | 'http://server_and_port/endpoint', data=mock.ANY) |
|
77 | 87 | |
|
78 | 88 | |
|
89 | @mock.patch('rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory') | |
|
79 | 90 | @mock.patch('rhodecode.lib.vcs.connection') |
|
80 |
def test_connect_passes_in_the_same_session( |
|
|
81 | session_factory_patcher = mock.patch.object( | |
|
82 | vcs, '_create_http_rpc_session', return_value=stub_session) | |
|
83 | with session_factory_patcher: | |
|
91 | def test_connect_passes_in_the_same_session( | |
|
92 | connection, session_factory_class, stub_session): | |
|
93 | session_factory = session_factory_class.return_value | |
|
94 | session_factory.return_value = stub_session | |
|
95 | ||
|
84 | 96 |
|
|
85 | assert connection.Hg._session == stub_session | |
|
86 |
assert connection. |
|
|
87 |
assert connection. |
|
|
97 | ||
|
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 | 69 | context.rhodecode_user = auth_user |
|
70 | 70 | attach_context_attributes(context) |
|
71 | 71 | pylons.tmpl_context._push_object(context) |
|
72 | ||
|
73 | 72 | return handler(request) |
|
74 | 73 | finally: |
|
75 | 74 | # Dispose current database session and rollback uncommitted |
@@ -518,7 +518,7 b' vcs.connection_timeout = 3600' | |||
|
518 | 518 | ### LOGGING CONFIGURATION #### |
|
519 | 519 | ################################ |
|
520 | 520 | [loggers] |
|
521 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
|
521 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
|
522 | 522 | |
|
523 | 523 | [handlers] |
|
524 | 524 | keys = console, console_sql |
@@ -570,12 +570,6 b' handlers = console_sql' | |||
|
570 | 570 | qualname = sqlalchemy.engine |
|
571 | 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 | 574 | ## HANDLERS ## |
|
581 | 575 | ############## |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed, binary diff hidden |
|
1 | NO CONTENT: file was removed, binary diff hidden |
|
1 | NO CONTENT: file was removed, binary diff hidden |
General Comments 0
You need to be logged in to leave comments.
Login now