Show More
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,137 b'' | |||||
|
1 | .. _checklist-tickets: | |||
|
2 | ||||
|
3 | ================= | |||
|
4 | Ticket Checklists | |||
|
5 | ================= | |||
|
6 | ||||
|
7 | ||||
|
8 | Ticket Description | |||
|
9 | ================== | |||
|
10 | ||||
|
11 | In general these things really matter in the description: | |||
|
12 | ||||
|
13 | - Reasoning / Rationale. Explain "WHY" it makes sense and is important. | |||
|
14 | ||||
|
15 | - How to reproduce. Easy to follow steps, that’s important. | |||
|
16 | ||||
|
17 | - Observation: The problem (short) | |||
|
18 | ||||
|
19 | - Expectation: How it should be (short) | |||
|
20 | ||||
|
21 | - Specs: It is fine to draft them as good as it works. | |||
|
22 | ||||
|
23 | If anything is unclear, please ask for a review or help on this via the | |||
|
24 | Community Portal or Slack channel. | |||
|
25 | ||||
|
26 | ||||
|
27 | Checklists for Tickets | |||
|
28 | ====================== | |||
|
29 | ||||
|
30 | BUG | |||
|
31 | --- | |||
|
32 | ||||
|
33 | Definition: An existing function that does not work as expected for the user. | |||
|
34 | ||||
|
35 | - Problem description | |||
|
36 | - Steps needed to recreate (gherkin) | |||
|
37 | - Link to the screen in question and/or description of how to find it via | |||
|
38 | navigation | |||
|
39 | - Explanation of what the expected outcome is | |||
|
40 | - Any hints into the source of the problem | |||
|
41 | - Information about platform/browser/db/etc. where applicable | |||
|
42 | - Examples of other similar cases which have different behaviour | |||
|
43 | ||||
|
44 | DESIGN | |||
|
45 | ------ | |||
|
46 | ||||
|
47 | Definition: Styling and user interface issues, including cosmetic improvements | |||
|
48 | or appearance and behaviour of frontend functionality. | |||
|
49 | ||||
|
50 | - Screenshot/animation of existing page/behaviour | |||
|
51 | - Sketches or wireframes if available | |||
|
52 | - Link to the screen in question and/or description of how to find it via | |||
|
53 | navigation | |||
|
54 | - Problem description | |||
|
55 | - Explanation of what the expected outcome is | |||
|
56 | - Since this may be examined by a designer; it should be written in a way that a | |||
|
57 | non-developer can understand | |||
|
58 | ||||
|
59 | EPIC | |||
|
60 | ---- | |||
|
61 | ||||
|
62 | Definition: A collection of tickets which together complete a larger overall | |||
|
63 | project. | |||
|
64 | ||||
|
65 | - Benefit explanation | |||
|
66 | - Clear objective - when is this complete? | |||
|
67 | - Explanations of exceptions/corner cases | |||
|
68 | - Documentation subtask | |||
|
69 | - Comprehensive wireframes and/or design subtasks | |||
|
70 | - Links to subtasks | |||
|
71 | ||||
|
72 | FEATURE | |||
|
73 | ------- | |||
|
74 | ||||
|
75 | Definition: A new function in the software which previously did not exist. | |||
|
76 | ||||
|
77 | - Benefit explanation | |||
|
78 | - Clear objective | |||
|
79 | - Explanations of exceptions/corner cases | |||
|
80 | - Documentation subtask | |||
|
81 | - Comprehensive wireframes and/or design subtasks | |||
|
82 | ||||
|
83 | SUPPORT | |||
|
84 | ------- | |||
|
85 | ||||
|
86 | Definition: An issue related to a customer report. | |||
|
87 | ||||
|
88 | - Link to support ticket, if available | |||
|
89 | - Problem description | |||
|
90 | - Steps needed to recreate (gherkin) | |||
|
91 | - Link to the screen in question and/or description of how to find it via | |||
|
92 | navigation | |||
|
93 | - Explanation of what the expected outcome is | |||
|
94 | - Any hints into the source of the problem | |||
|
95 | - Information about platform/browser/db/etc. where applicable | |||
|
96 | - Examples of other similar cases which have different behaviour | |||
|
97 | ||||
|
98 | TASK | |||
|
99 | ---- | |||
|
100 | ||||
|
101 | Definition: An improvement or step towards implementing a feature or fixing | |||
|
102 | a bug. Includes refactoring and other tech debt. | |||
|
103 | ||||
|
104 | - Clear objective | |||
|
105 | - Benefit explanation | |||
|
106 | - Links to parent/related tickets | |||
|
107 | ||||
|
108 | ||||
|
109 | All details below. | |||
|
110 | ||||
|
111 | ||||
|
112 | External links: | |||
|
113 | ||||
|
114 | - Avoid linking to external images; they disappear over time. Please attach any | |||
|
115 | relevant images to the ticket itself. | |||
|
116 | ||||
|
117 | - External links in general: They also disappear over time, consider copying the | |||
|
118 | relevant bit of information into a comment or write a paragraph to sum up the | |||
|
119 | general idea. | |||
|
120 | ||||
|
121 | ||||
|
122 | Hints | |||
|
123 | ===== | |||
|
124 | ||||
|
125 | Change Description | |||
|
126 | ------------------ | |||
|
127 | ||||
|
128 | It can be tricky to figure out how to change the description of a ticket. There | |||
|
129 | is a very small pencil which has to be clicked once you see the edit form of a | |||
|
130 | ticket. | |||
|
131 | ||||
|
132 | ||||
|
133 | .. figure:: images/redmine-description.png | |||
|
134 | :alt: Example of pencil to change the ticket description | |||
|
135 | ||||
|
136 | Shows an example of the pencil which lets you change the description. | |||
|
137 |
@@ -0,0 +1,153 b'' | |||||
|
1 | ||||
|
2 | ================================================== | |||
|
3 | Code style and structure guide for frontend work | |||
|
4 | ================================================== | |||
|
5 | ||||
|
6 | About: Outline of frontend development practices. | |||
|
7 | ||||
|
8 | ||||
|
9 | ||||
|
10 | ||||
|
11 | Templates | |||
|
12 | ========= | |||
|
13 | ||||
|
14 | - Indent with 4 spaces in general. | |||
|
15 | - Embedded Python code follows the same conventions as in the backend. | |||
|
16 | ||||
|
17 | A common problem is missed spaces around operators. | |||
|
18 | ||||
|
19 | ||||
|
20 | ||||
|
21 | ||||
|
22 | Grunt | |||
|
23 | ===== | |||
|
24 | ||||
|
25 | We use Grunt to compile our JavaScript and LESS files. This is done automatically | |||
|
26 | when you start an instance. If you are changing these files, however, it is | |||
|
27 | recommended to amend `--reload` to the `runserver` command, or use `grunt watch` | |||
|
28 | - the Gruntfile is located in the base directory. For more info on Grunt, see | |||
|
29 | http://gruntjs.com/ | |||
|
30 | ||||
|
31 | ||||
|
32 | ||||
|
33 | ||||
|
34 | LESS CSS | |||
|
35 | ======== | |||
|
36 | ||||
|
37 | ||||
|
38 | Style | |||
|
39 | ----- | |||
|
40 | ||||
|
41 | - Use 4 spaces instead of tabs. | |||
|
42 | - Avoid ``!important``; it is very often an indicator for a problem. | |||
|
43 | ||||
|
44 | ||||
|
45 | ||||
|
46 | ||||
|
47 | Structure | |||
|
48 | --------- | |||
|
49 | ||||
|
50 | It is important that we maintain consistency in the LESS files so that things | |||
|
51 | scale properly. CSS is organized using LESS and then compiled into a CSS file | |||
|
52 | to be used in production. Find the class you need to change and change it | |||
|
53 | there. Do not add overriding styles at the end of the file. The LESS file will | |||
|
54 | be minified; use plenty of spacing and comments for readability. | |||
|
55 | ||||
|
56 | These will be kept in auxillary LESS files to be imported (in this order) at the top: | |||
|
57 | ||||
|
58 | - `fonts.less` (font-face declarations) | |||
|
59 | - `mixins` (place all LESS mixins here) | |||
|
60 | - `helpers` (basic classes for hiding mobile elements, centering, etc) | |||
|
61 | - `variables` (theme-specific colors, spacing, and fonts which might change later) | |||
|
62 | ||||
|
63 | ||||
|
64 | Sections of the primary LESS file are as follows. Add comments describing | |||
|
65 | layout and modules. | |||
|
66 | ||||
|
67 | .. code-block:: css | |||
|
68 | ||||
|
69 | //--- BASE ------------------// | |||
|
70 | Very basic, sitewide styles. | |||
|
71 | ||||
|
72 | //--- LAYOUT ------------------// | |||
|
73 | Essential layout, ex. containers and wrappers. | |||
|
74 | Do not put type styles in here. | |||
|
75 | ||||
|
76 | //--- MODULES ------------------// | |||
|
77 | Reusable sections, such as sidebars and menus. | |||
|
78 | ||||
|
79 | //--- THEME ------------------// | |||
|
80 | Theme styles, typography, etc. | |||
|
81 | ||||
|
82 | ||||
|
83 | ||||
|
84 | Formatting rules | |||
|
85 | ~~~~~~~~~~~~~~~~ | |||
|
86 | ||||
|
87 | - Each rule should be indented on a separate line (this is helpful for diff | |||
|
88 | checking). | |||
|
89 | ||||
|
90 | - Use a space after each colon and a semicolon after each last rule. | |||
|
91 | ||||
|
92 | - Put a blank line between each class. | |||
|
93 | ||||
|
94 | - Nested classes should be listed after the parent class' rules, separated with a | |||
|
95 | blank line, and indented. | |||
|
96 | ||||
|
97 | - Using the below as a guide, place each rule in order of its effect on content, | |||
|
98 | layout, sizing, and last listing minor style changes such as font color and | |||
|
99 | backgrounds. Not every possible rule is listed here; when adding new ones, | |||
|
100 | judge where it should go in the list based on that hierarchy. | |||
|
101 | ||||
|
102 | .. code-block:: scss | |||
|
103 | ||||
|
104 | .class { | |||
|
105 | content | |||
|
106 | list-style-type | |||
|
107 | position | |||
|
108 | float | |||
|
109 | top | |||
|
110 | right | |||
|
111 | bottom | |||
|
112 | left | |||
|
113 | height | |||
|
114 | max-height | |||
|
115 | min-height | |||
|
116 | width | |||
|
117 | max-width | |||
|
118 | min-width | |||
|
119 | margin | |||
|
120 | padding | |||
|
121 | indent | |||
|
122 | vertical-align | |||
|
123 | text-align | |||
|
124 | border | |||
|
125 | border-radius | |||
|
126 | font-size | |||
|
127 | line-height | |||
|
128 | font | |||
|
129 | font-style | |||
|
130 | font-variant | |||
|
131 | font-weight | |||
|
132 | color | |||
|
133 | text-shadow | |||
|
134 | background | |||
|
135 | background-color | |||
|
136 | box-shadow | |||
|
137 | background-url | |||
|
138 | background-position | |||
|
139 | background-repeat | |||
|
140 | background-cover | |||
|
141 | transitions | |||
|
142 | cursor | |||
|
143 | pointer-events | |||
|
144 | ||||
|
145 | .nested-class { | |||
|
146 | position | |||
|
147 | background-color | |||
|
148 | ||||
|
149 | &:hover { | |||
|
150 | color | |||
|
151 | } | |||
|
152 | } | |||
|
153 | } |
@@ -0,0 +1,111 b'' | |||||
|
1 | ||||
|
2 | ======================= | |||
|
3 | Contributing Overview | |||
|
4 | ======================= | |||
|
5 | ||||
|
6 | ||||
|
7 | RhodeCode Community Edition is an open source code management platform. We | |||
|
8 | encourage contributions to our project from the community. This is a basic | |||
|
9 | overview of the procedures for adding your contribution to RhodeCode. | |||
|
10 | ||||
|
11 | ||||
|
12 | ||||
|
13 | Check the Issue Tracker | |||
|
14 | ======================= | |||
|
15 | ||||
|
16 | Make an account at https://issues.rhodecode.com/account/register and browse the | |||
|
17 | current tickets for bugs to fix and tasks to do. Have a bug or feature that you | |||
|
18 | can't find in the tracker? Create a new issue for it. When you select a ticket, | |||
|
19 | make sure to assign it to yourself and mark it "in progress" to avoid duplicated | |||
|
20 | work. | |||
|
21 | ||||
|
22 | ||||
|
23 | ||||
|
24 | Sign Up at code.rhodecode.com | |||
|
25 | ============================= | |||
|
26 | ||||
|
27 | Make an account at https://code.rhodecode.com/ using an email or your existing | |||
|
28 | GitHub, Bitbucket, Google, or Twitter account. Fork the repo you'd like to | |||
|
29 | contribute to; we suggest adding your username to the fork name. Clone your fork | |||
|
30 | to your computer. We use Mercurial for source control management; see | |||
|
31 | https://www.mercurial-scm.org/guide to get started quickly. | |||
|
32 | ||||
|
33 | ||||
|
34 | ||||
|
35 | Set Up A Local Instance | |||
|
36 | ======================= | |||
|
37 | ||||
|
38 | You will need to set up an instance of RhodeCode CE using VCSServer so that you | |||
|
39 | can see your work locally as you make changes. We recommend using Linux for this | |||
|
40 | but it can also be built on OSX. | |||
|
41 | ||||
|
42 | See :doc:`dev-setup` for instructions. | |||
|
43 | ||||
|
44 | ||||
|
45 | ||||
|
46 | Code! | |||
|
47 | ===== | |||
|
48 | ||||
|
49 | You can now make, see, and test your changes locally. We are always improving to | |||
|
50 | keep our code clean and the cost of maintaining it low. This applies in the same | |||
|
51 | way for contributions. We run automated checks on our pull requests, and expect | |||
|
52 | understandable code. We also aim to provide test coverage for as much of our | |||
|
53 | codebase as possible; any new features should be augmented with tests. | |||
|
54 | ||||
|
55 | Keep in mind that when we accept your contribution, we also take responsibility | |||
|
56 | for it; we must understand it to take on that responsibility. | |||
|
57 | ||||
|
58 | See :doc:`standards` for more detailed information. | |||
|
59 | ||||
|
60 | ||||
|
61 | ||||
|
62 | Commit And Push Your Changes | |||
|
63 | ============================ | |||
|
64 | ||||
|
65 | We highly recommend making a new bookmark for each feature, bug, or set of | |||
|
66 | commits you make so that you can point to it when creating your pull request. | |||
|
67 | Please also reference the ticket number in your commit messages. Don't forget to | |||
|
68 | push the bookmark! | |||
|
69 | ||||
|
70 | ||||
|
71 | ||||
|
72 | Submit a Pull Request | |||
|
73 | ===================== | |||
|
74 | ||||
|
75 | Go to your fork, and choose "Create Pull Request" from the Options menu. Use | |||
|
76 | your bookmark as the source, and choose someone to review it. Don't worry about | |||
|
77 | chosing the right person; we'll assign the best contributor for the job. You'll | |||
|
78 | get feedback and an assigned status. | |||
|
79 | ||||
|
80 | Be prepared to make updates to your pull request after some feedback. | |||
|
81 | Collaboration is part of the process and improvements can often be made. | |||
|
82 | ||||
|
83 | ||||
|
84 | ||||
|
85 | Sign the Contributor License Agreement | |||
|
86 | ====================================== | |||
|
87 | ||||
|
88 | If your contribution is approved, you will need to virtually sign the license | |||
|
89 | agreement in order for it to be merged into the project's codebase. You can read | |||
|
90 | it on our website here: https://rhodecode.com/static/pdf/RhodeCode-CLA.pdf | |||
|
91 | ||||
|
92 | To sign, go to code.rhodecode.com | |||
|
93 | and clone the CLA repository. Add your name and make a pull request to add it to | |||
|
94 | the contributor agreement; this serves as your virtual signature. Once your | |||
|
95 | signature is merged, add a link to the relevant commit to your contribution | |||
|
96 | pull request. | |||
|
97 | ||||
|
98 | ||||
|
99 | ||||
|
100 | That's it! We'll take it from there. Thanks for your contribution! | |||
|
101 | ------------------------------------------------------------------ | |||
|
102 | ||||
|
103 | .. note:: If you have any questions or comments, feel free to contact us through | |||
|
104 | either the community portal(community.rhodecode.com), IRC | |||
|
105 | (irc.freenode.net), or Slack (rhodecode.com/join). | |||
|
106 | ||||
|
107 | ||||
|
108 | ||||
|
109 | ||||
|
110 | ||||
|
111 |
@@ -0,0 +1,177 b'' | |||||
|
1 | ||||
|
2 | ====================== | |||
|
3 | Contribution Standards | |||
|
4 | ====================== | |||
|
5 | ||||
|
6 | Standards help to improve the quality of our product and its development. Herein | |||
|
7 | we define our standards for processes and development to maintain consistency | |||
|
8 | and function well as a community. It is a work in progress; modifications to this | |||
|
9 | document should be discussed and agreed upon by the community. | |||
|
10 | ||||
|
11 | ||||
|
12 | -------------------------------------------------------------------------------- | |||
|
13 | ||||
|
14 | Code | |||
|
15 | ==== | |||
|
16 | ||||
|
17 | This provides an outline for standards we use in our codebase to keep our code | |||
|
18 | easy to read and easy to maintain. Much of our code guidelines are based on the | |||
|
19 | book `Clean Code <http://www.pearsonhighered.com/educator/product/Clean-Code-A-Handbook-of-Agile-Software-Craftsmanship/9780132350884.page>`_ | |||
|
20 | by Robert Martin. | |||
|
21 | ||||
|
22 | We maintain a Tech Glossary to provide consistency in terms and symbolic names | |||
|
23 | used for items and concepts within the application. This is found in the CE | |||
|
24 | project in /docs-internal/glossary.rst | |||
|
25 | ||||
|
26 | ||||
|
27 | Refactoring | |||
|
28 | ----------- | |||
|
29 | Make it better than you found it! | |||
|
30 | ||||
|
31 | Our codebase can always use improvement and often benefits from refactoring. | |||
|
32 | New code should be refactored as it is being written, and old code should be | |||
|
33 | treated with the same care as if it was new. Before doing any refactoring, | |||
|
34 | ensure that there is test coverage on the affected code; this will help | |||
|
35 | minimize issues. | |||
|
36 | ||||
|
37 | ||||
|
38 | Python | |||
|
39 | ------ | |||
|
40 | For Python, we use `PEP8 <https://www.python.org/dev/peps/pep-0008/>`_. | |||
|
41 | We adjust lines of code to under 80 characters and use 4 spaces for indentation. | |||
|
42 | ||||
|
43 | ||||
|
44 | JavaScript | |||
|
45 | ---------- | |||
|
46 | This currently remains undefined. Suggestions welcome! | |||
|
47 | ||||
|
48 | ||||
|
49 | HTML | |||
|
50 | ---- | |||
|
51 | Unfortunately, we currently have no strict HTML standards, but there are a few | |||
|
52 | guidelines we do follow. Templates must work in all modern browsers. HTML should | |||
|
53 | be clean and easy to read, and additionally should be free of inline CSS or | |||
|
54 | JavaScript. It is recommended to use data attributes for JS actions where | |||
|
55 | possible in order to separate it from styling and prevent unintentional changes. | |||
|
56 | ||||
|
57 | ||||
|
58 | LESS/CSS | |||
|
59 | -------- | |||
|
60 | We use LESS for our CSS; see :doc:`frontend` for structure and formatting | |||
|
61 | guidelines. | |||
|
62 | ||||
|
63 | ||||
|
64 | Linters | |||
|
65 | ------- | |||
|
66 | Currently, we have a linter for pull requests which checks code against PEP8. | |||
|
67 | We intend to add more in the future as we clarify standards. | |||
|
68 | ||||
|
69 | ||||
|
70 | -------------------------------------------------------------------------------- | |||
|
71 | ||||
|
72 | Naming Conventions | |||
|
73 | ================== | |||
|
74 | ||||
|
75 | These still need to be defined for naming everything from Python variables to | |||
|
76 | HTML classes to files and folders. | |||
|
77 | ||||
|
78 | ||||
|
79 | -------------------------------------------------------------------------------- | |||
|
80 | ||||
|
81 | Testing | |||
|
82 | ======= | |||
|
83 | ||||
|
84 | Testing is a very important aspect of our process, especially as we are our own | |||
|
85 | quality control team. While it is of course unrealistic to hit every potential | |||
|
86 | combination, our goal is to cover every line of Python code with a test. | |||
|
87 | ||||
|
88 | The following is a brief introduction to our test suite. Our tests are primarily | |||
|
89 | written using `py.test <http://pytest.org/>`_ | |||
|
90 | ||||
|
91 | ||||
|
92 | Acceptance Tests | |||
|
93 | ---------------- | |||
|
94 | Also known as "ac tests", these test from the user and business perspective to | |||
|
95 | check if the requirements of a feature are met. Scenarios are created at a | |||
|
96 | feature's inception and help to define its value. | |||
|
97 | ||||
|
98 | py.test is used for ac tests; they are located in a repo separate from the | |||
|
99 | other tests which follow. Each feature has a .feature file which contains a | |||
|
100 | brief description and the scenarios to be tested. | |||
|
101 | ||||
|
102 | ||||
|
103 | Functional Tests | |||
|
104 | ---------------- | |||
|
105 | These test specific functionality in the application which checks through the | |||
|
106 | entire stack. Typically these are user actions or permissions which go through | |||
|
107 | the web browser. They are located in rhodecode/tests. | |||
|
108 | ||||
|
109 | ||||
|
110 | Unit Tests | |||
|
111 | ---------- | |||
|
112 | These test isolated, individual modules to ensure that they function correctly. | |||
|
113 | They are located in rhodecode/tests. | |||
|
114 | ||||
|
115 | ||||
|
116 | Integration Tests | |||
|
117 | ----------------- | |||
|
118 | These are used for testing performance of larger systems than the unit tests. | |||
|
119 | They are located in rhodecode/tests. | |||
|
120 | ||||
|
121 | ||||
|
122 | JavaScript Testing | |||
|
123 | ------------------ | |||
|
124 | Currently, we have not defined how to test our JavaScript code. | |||
|
125 | ||||
|
126 | ||||
|
127 | -------------------------------------------------------------------------------- | |||
|
128 | ||||
|
129 | Pull Requests | |||
|
130 | ============= | |||
|
131 | ||||
|
132 | Pull requests should generally contain only one thing: a single feature, one bug | |||
|
133 | fix, etc.. The commit history should be concise and clean, and the pull request | |||
|
134 | should contain the ticket number (also a good idea for the commits themselves) | |||
|
135 | to provide context for the reviewer. | |||
|
136 | ||||
|
137 | See also: :doc:`checklist-pull-request` | |||
|
138 | ||||
|
139 | ||||
|
140 | Reviewers | |||
|
141 | --------- | |||
|
142 | Each pull request must be approved by at least one member of the RhodeCode | |||
|
143 | team. Assignments may be based on expertise or familiarity with a particular | |||
|
144 | area of code, or simply availability. Switching up or adding extra community | |||
|
145 | members for different pull requests helps to share knowledge as well as provide | |||
|
146 | other perspectives. | |||
|
147 | ||||
|
148 | ||||
|
149 | Responsibility | |||
|
150 | -------------- | |||
|
151 | The community is responsible for maintaining features and this must be taken | |||
|
152 | into consideration. External contributions must be held to the same standards | |||
|
153 | as internal contributions. | |||
|
154 | ||||
|
155 | ||||
|
156 | Feature Switch | |||
|
157 | -------------- | |||
|
158 | Experimental and work-in-progress features can be hidden behind one of two | |||
|
159 | switches: | |||
|
160 | ||||
|
161 | * A setting can be added to the Labs page in the Admin section which may allow | |||
|
162 | customers to access and toggle additional features. | |||
|
163 | * For work-in-progress or other features where customer access is not desired, | |||
|
164 | use a custom setting in the .ini file as a trigger. | |||
|
165 | ||||
|
166 | ||||
|
167 | -------------------------------------------------------------------------------- | |||
|
168 | ||||
|
169 | Tickets | |||
|
170 | ======= | |||
|
171 | ||||
|
172 | Redmine tickets are a crucial part of our development process. Any code added or | |||
|
173 | changed in our codebase should have a corresponding ticket to document it. With | |||
|
174 | this in mind, it is important that tickets be as clear and concise as possible, | |||
|
175 | including what the expected outcome is. | |||
|
176 | ||||
|
177 | See also: :doc:`checklist-tickets` |
@@ -0,0 +1,70 b'' | |||||
|
1 | |RCE| 4.2.0 |RNS| | |||
|
2 | ----------------- | |||
|
3 | ||||
|
4 | Release Date | |||
|
5 | ^^^^^^^^^^^^ | |||
|
6 | ||||
|
7 | - 2016-06-30 | |||
|
8 | ||||
|
9 | ||||
|
10 | General | |||
|
11 | ^^^^^^^ | |||
|
12 | ||||
|
13 | - Autocomplete: add GET flag support to show/hide active users on autocomplete, | |||
|
14 | also display this information in autocomplete data. ref #3374 | |||
|
15 | - Gravatar: add flag to show current gravatar + user as disabled user (non-active) | |||
|
16 | - Repos, repo groups, user groups: allow to use disabled users in owner field. | |||
|
17 | This fixes #3374. | |||
|
18 | - Repos, repo groups, user groups: visually show what user is an owner of a | |||
|
19 | resource, and if potentially he is disabled in the system. | |||
|
20 | - Pull requests: reorder navigation on repo pull requests, fixes #2995 | |||
|
21 | - Dependencies: bump dulwich to 0.13.0 | |||
|
22 | ||||
|
23 | New Features | |||
|
24 | ^^^^^^^^^^^^ | |||
|
25 | ||||
|
26 | - My account: made pull requests aggregate view for users look like not | |||
|
27 | created in 1995. Now uses a consistent look with repo one. | |||
|
28 | - emails: expose profile link on registation email that super-admins receive. | |||
|
29 | Implements #3999. | |||
|
30 | - Social auth: move the buttons to the top of nav so they are easier to reach. | |||
|
31 | ||||
|
32 | ||||
|
33 | Security | |||
|
34 | ^^^^^^^^ | |||
|
35 | ||||
|
36 | - Encryption: allow to pass in alternative key for encryption values. Now | |||
|
37 | users can use `rhodecode.encrypted_values.secret` that is alternative key, | |||
|
38 | de-coupled from `beaker.session` key. | |||
|
39 | - Encryption: Implement a slightly improved AesCipher encryption. | |||
|
40 | This addresses issues from #4036. | |||
|
41 | - Encryption: encrypted values now by default uses HMAC signatures to detect | |||
|
42 | if data or secret key is incorrect. The strict checks can be disabled using | |||
|
43 | `rhodecode.encrypted_values.strict = false` .ini setting | |||
|
44 | ||||
|
45 | ||||
|
46 | Performance | |||
|
47 | ^^^^^^^^^^^ | |||
|
48 | ||||
|
49 | - Sql: use smarter JOINs when fetching repository information | |||
|
50 | - Helpers: optimize slight calls for link_to_user to save some intense queries. | |||
|
51 | - App settings: use computed caches for repository settings, this in some cases | |||
|
52 | brings almost 4x performance increase for large repos with a lot of issue | |||
|
53 | tracker patterns. | |||
|
54 | ||||
|
55 | ||||
|
56 | Fixes | |||
|
57 | ^^^^^ | |||
|
58 | ||||
|
59 | - Fixed events on user pre/post create actions | |||
|
60 | - Authentication: fixed problem with saving forms with errors on auth plugins | |||
|
61 | - Svn: Avoid chunked transfer for Subversion that caused checkout issues in some cases. | |||
|
62 | - Users: fix generate new user password helper. | |||
|
63 | - Celery: fixed problem with workers running action in sync mode in some cases. | |||
|
64 | - Setup-db: fix redundant question on writable dir. The question needs to be | |||
|
65 | asked only when the dir is actually not writable. | |||
|
66 | - Elasticsearch: fixed issues when searching single repo using elastic search | |||
|
67 | - Social auth: fix issues with non-active users using social authentication | |||
|
68 | causing a 500 error. | |||
|
69 | - Fixed problem with largefiles extensions on per-repo settings using local | |||
|
70 | .hgrc files present inside the repo directory. |
@@ -0,0 +1,40 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | from rhodecode.admin.navigation import NavigationRegistry | |||
|
23 | from rhodecode.config.routing import ADMIN_PREFIX | |||
|
24 | from rhodecode.lib.utils2 import str2bool | |||
|
25 | ||||
|
26 | ||||
|
27 | def includeme(config): | |||
|
28 | settings = config.get_settings() | |||
|
29 | ||||
|
30 | # Create admin navigation registry and add it to the pyramid registry. | |||
|
31 | labs_active = str2bool(settings.get('labs_settings_active', False)) | |||
|
32 | navigation_registry = NavigationRegistry(labs_active=labs_active) | |||
|
33 | config.registry.registerUtility(navigation_registry) | |||
|
34 | ||||
|
35 | config.add_route( | |||
|
36 | name='admin_settings_open_source', | |||
|
37 | pattern=ADMIN_PREFIX + '/settings/open_source') | |||
|
38 | ||||
|
39 | # Scan module for configuration decorators. | |||
|
40 | config.scan() |
@@ -0,0 +1,29 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | from zope.interface import Interface | |||
|
22 | ||||
|
23 | ||||
|
24 | class IAdminNavigationRegistry(Interface): | |||
|
25 | """ | |||
|
26 | Interface for the admin navigation registry. Currently this is only | |||
|
27 | used to register and retrieve it via pyramids registry. | |||
|
28 | """ | |||
|
29 | pass |
@@ -0,0 +1,124 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | import logging | |||
|
23 | import collections | |||
|
24 | ||||
|
25 | from pylons import url | |||
|
26 | from zope.interface import implementer | |||
|
27 | ||||
|
28 | from rhodecode.admin.interfaces import IAdminNavigationRegistry | |||
|
29 | from rhodecode.lib.utils import get_registry | |||
|
30 | from rhodecode.translation import _ | |||
|
31 | ||||
|
32 | ||||
|
33 | log = logging.getLogger(__name__) | |||
|
34 | ||||
|
35 | NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url']) | |||
|
36 | ||||
|
37 | ||||
|
38 | class NavEntry(object): | |||
|
39 | """ | |||
|
40 | Represents an entry in the admin navigation. | |||
|
41 | ||||
|
42 | :param key: Unique identifier used to store reference in an OrderedDict. | |||
|
43 | :param name: Display name, usually a translation string. | |||
|
44 | :param view_name: Name of the view, used generate the URL. | |||
|
45 | :param pyramid: Indicator to use pyramid for URL generation. This should | |||
|
46 | be removed as soon as we are fully migrated to pyramid. | |||
|
47 | """ | |||
|
48 | ||||
|
49 | def __init__(self, key, name, view_name, pyramid=False): | |||
|
50 | self.key = key | |||
|
51 | self.name = name | |||
|
52 | self.view_name = view_name | |||
|
53 | self.pyramid = pyramid | |||
|
54 | ||||
|
55 | def generate_url(self, request): | |||
|
56 | if self.pyramid: | |||
|
57 | if hasattr(request, 'route_path'): | |||
|
58 | return request.route_path(self.view_name) | |||
|
59 | else: | |||
|
60 | # TODO: johbo: Remove this after migrating to pyramid. | |||
|
61 | # We need the pyramid request here to generate URLs to pyramid | |||
|
62 | # views from within pylons views. | |||
|
63 | from pyramid.threadlocal import get_current_request | |||
|
64 | pyramid_request = get_current_request() | |||
|
65 | return pyramid_request.route_path(self.view_name) | |||
|
66 | else: | |||
|
67 | return url(self.view_name) | |||
|
68 | ||||
|
69 | ||||
|
70 | @implementer(IAdminNavigationRegistry) | |||
|
71 | class NavigationRegistry(object): | |||
|
72 | ||||
|
73 | _base_entries = [ | |||
|
74 | NavEntry('global', _('Global'), 'admin_settings_global'), | |||
|
75 | NavEntry('vcs', _('VCS'), 'admin_settings_vcs'), | |||
|
76 | NavEntry('visual', _('Visual'), 'admin_settings_visual'), | |||
|
77 | NavEntry('mapping', _('Remap and Rescan'), 'admin_settings_mapping'), | |||
|
78 | NavEntry('issuetracker', _('Issue Tracker'), | |||
|
79 | 'admin_settings_issuetracker'), | |||
|
80 | NavEntry('email', _('Email'), 'admin_settings_email'), | |||
|
81 | NavEntry('hooks', _('Hooks'), 'admin_settings_hooks'), | |||
|
82 | NavEntry('search', _('Full Text Search'), 'admin_settings_search'), | |||
|
83 | NavEntry('system', _('System Info'), 'admin_settings_system'), | |||
|
84 | NavEntry('open_source', _('Open Source Licenses'), | |||
|
85 | 'admin_settings_open_source', pyramid=True), | |||
|
86 | # TODO: marcink: we disable supervisor now until the supervisor stats | |||
|
87 | # page is fixed in the nix configuration | |||
|
88 | # NavEntry('supervisor', _('Supervisor'), 'admin_settings_supervisor'), | |||
|
89 | ] | |||
|
90 | ||||
|
91 | _labs_entry = NavEntry('labs', _('Labs'), | |||
|
92 | 'admin_settings_labs') | |||
|
93 | ||||
|
94 | def __init__(self, labs_active=False): | |||
|
95 | self._registered_entries = collections.OrderedDict([ | |||
|
96 | (item.key, item) for item in self.__class__._base_entries | |||
|
97 | ]) | |||
|
98 | ||||
|
99 | if labs_active: | |||
|
100 | self.add_entry(self._labs_entry) | |||
|
101 | ||||
|
102 | def add_entry(self, entry): | |||
|
103 | self._registered_entries[entry.key] = entry | |||
|
104 | ||||
|
105 | def get_navlist(self, request): | |||
|
106 | navlist = [NavListEntry(i.key, i.name, i.generate_url(request)) | |||
|
107 | for i in self._registered_entries.values()] | |||
|
108 | return navlist | |||
|
109 | ||||
|
110 | ||||
|
111 | def navigation_registry(request): | |||
|
112 | """ | |||
|
113 | Helper that returns the admin navigation registry. | |||
|
114 | """ | |||
|
115 | pyramid_registry = get_registry(request) | |||
|
116 | nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry) | |||
|
117 | return nav_registry | |||
|
118 | ||||
|
119 | ||||
|
120 | def navigation_list(request): | |||
|
121 | """ | |||
|
122 | Helper that returns the admin navigation as list of NavListEntry objects. | |||
|
123 | """ | |||
|
124 | return navigation_registry(request).get_navlist(request) |
@@ -0,0 +1,55 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import collections | |||
|
22 | import logging | |||
|
23 | ||||
|
24 | from pylons import tmpl_context as c | |||
|
25 | from pyramid.view import view_config | |||
|
26 | ||||
|
27 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |||
|
28 | from rhodecode.lib.utils import read_opensource_licenses | |||
|
29 | ||||
|
30 | from .navigation import navigation_list | |||
|
31 | ||||
|
32 | ||||
|
33 | log = logging.getLogger(__name__) | |||
|
34 | ||||
|
35 | ||||
|
36 | class AdminSettingsView(object): | |||
|
37 | ||||
|
38 | def __init__(self, context, request): | |||
|
39 | self.request = request | |||
|
40 | self.context = context | |||
|
41 | self.session = request.session | |||
|
42 | self._rhodecode_user = request.user | |||
|
43 | ||||
|
44 | @LoginRequired() | |||
|
45 | @HasPermissionAllDecorator('hg.admin') | |||
|
46 | @view_config( | |||
|
47 | route_name='admin_settings_open_source', request_method='GET', | |||
|
48 | renderer='rhodecode:templates/admin/settings/settings.html') | |||
|
49 | def open_source_licenses(self): | |||
|
50 | c.active = 'open_source' | |||
|
51 | c.navlist = navigation_list(self.request) | |||
|
52 | c.opensource_licenses = collections.OrderedDict( | |||
|
53 | sorted(read_opensource_licenses().items(), key=lambda t: t[0])) | |||
|
54 | ||||
|
55 | return {} |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,92 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | import pytest | |||
|
23 | ||||
|
24 | ||||
|
25 | class EnabledAuthPlugin(): | |||
|
26 | """ | |||
|
27 | Context manager that updates the 'auth_plugins' setting in DB to enable | |||
|
28 | a plugin. Previous setting is restored on exit. The rhodecode auth plugin | |||
|
29 | is also enabled because it is needed to login the test users. | |||
|
30 | """ | |||
|
31 | ||||
|
32 | def __init__(self, plugin): | |||
|
33 | self.new_value = set([ | |||
|
34 | 'egg:rhodecode-enterprise-ce#rhodecode', | |||
|
35 | plugin.get_id() | |||
|
36 | ]) | |||
|
37 | ||||
|
38 | def __enter__(self): | |||
|
39 | from rhodecode.model.settings import SettingsModel | |||
|
40 | self._old_value = SettingsModel().get_auth_plugins() | |||
|
41 | SettingsModel().create_or_update_setting( | |||
|
42 | 'auth_plugins', ','.join(self.new_value)) | |||
|
43 | ||||
|
44 | def __exit__(self, type, value, traceback): | |||
|
45 | from rhodecode.model.settings import SettingsModel | |||
|
46 | SettingsModel().create_or_update_setting( | |||
|
47 | 'auth_plugins', ','.join(self._old_value)) | |||
|
48 | ||||
|
49 | ||||
|
50 | class DisabledAuthPlugin(): | |||
|
51 | """ | |||
|
52 | Context manager that updates the 'auth_plugins' setting in DB to disable | |||
|
53 | a plugin. Previous setting is restored on exit. | |||
|
54 | """ | |||
|
55 | ||||
|
56 | def __init__(self, plugin): | |||
|
57 | self.plugin_id = plugin.get_id() | |||
|
58 | ||||
|
59 | def __enter__(self): | |||
|
60 | from rhodecode.model.settings import SettingsModel | |||
|
61 | self._old_value = SettingsModel().get_auth_plugins() | |||
|
62 | new_value = [id_ for id_ in self._old_value if id_ != self.plugin_id] | |||
|
63 | SettingsModel().create_or_update_setting( | |||
|
64 | 'auth_plugins', ','.join(new_value)) | |||
|
65 | ||||
|
66 | def __exit__(self, type, value, traceback): | |||
|
67 | from rhodecode.model.settings import SettingsModel | |||
|
68 | SettingsModel().create_or_update_setting( | |||
|
69 | 'auth_plugins', ','.join(self._old_value)) | |||
|
70 | ||||
|
71 | ||||
|
72 | @pytest.fixture(params=[ | |||
|
73 | ('rhodecode.authentication.plugins.auth_crowd', 'egg:rhodecode-enterprise-ce#crowd'), | |||
|
74 | ('rhodecode.authentication.plugins.auth_headers', 'egg:rhodecode-enterprise-ce#headers'), | |||
|
75 | ('rhodecode.authentication.plugins.auth_jasig_cas', 'egg:rhodecode-enterprise-ce#jasig_cas'), | |||
|
76 | ('rhodecode.authentication.plugins.auth_ldap', 'egg:rhodecode-enterprise-ce#ldap'), | |||
|
77 | ('rhodecode.authentication.plugins.auth_pam', 'egg:rhodecode-enterprise-ce#pam'), | |||
|
78 | ('rhodecode.authentication.plugins.auth_rhodecode', 'egg:rhodecode-enterprise-ce#rhodecode'), | |||
|
79 | ('rhodecode.authentication.plugins.auth_token', 'egg:rhodecode-enterprise-ce#token'), | |||
|
80 | ]) | |||
|
81 | def auth_plugin(request): | |||
|
82 | """ | |||
|
83 | Fixture that provides instance for each authentication plugin. These | |||
|
84 | instances are NOT the instances which are registered to the authentication | |||
|
85 | registry. | |||
|
86 | """ | |||
|
87 | from importlib import import_module | |||
|
88 | ||||
|
89 | # Create plugin instance. | |||
|
90 | module, plugin_id = request.param | |||
|
91 | plugin_module = import_module(module) | |||
|
92 | return plugin_module.plugin_factory(plugin_id) |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,77 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2016 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | import pytest | |||
|
23 | ||||
|
24 | from rhodecode.authentication.tests.conftest import ( | |||
|
25 | EnabledAuthPlugin, DisabledAuthPlugin) | |||
|
26 | from rhodecode.config.routing import ADMIN_PREFIX | |||
|
27 | ||||
|
28 | ||||
|
29 | @pytest.mark.usefixtures('autologin_user', 'app') | |||
|
30 | class TestAuthenticationSettings: | |||
|
31 | ||||
|
32 | def test_auth_settings_global_view_get(self, app): | |||
|
33 | url = '{prefix}/auth/'.format(prefix=ADMIN_PREFIX) | |||
|
34 | response = app.get(url) | |||
|
35 | assert response.status_code == 200 | |||
|
36 | ||||
|
37 | def test_plugin_settings_view_get(self, app, auth_plugin): | |||
|
38 | url = '{prefix}/auth/{name}'.format( | |||
|
39 | prefix=ADMIN_PREFIX, | |||
|
40 | name=auth_plugin.name) | |||
|
41 | with EnabledAuthPlugin(auth_plugin): | |||
|
42 | response = app.get(url) | |||
|
43 | assert response.status_code == 200 | |||
|
44 | ||||
|
45 | def test_plugin_settings_view_post(self, app, auth_plugin, csrf_token): | |||
|
46 | url = '{prefix}/auth/{name}'.format( | |||
|
47 | prefix=ADMIN_PREFIX, | |||
|
48 | name=auth_plugin.name) | |||
|
49 | params = { | |||
|
50 | 'enabled': True, | |||
|
51 | 'cache_ttl': 0, | |||
|
52 | 'csrf_token': csrf_token, | |||
|
53 | } | |||
|
54 | with EnabledAuthPlugin(auth_plugin): | |||
|
55 | response = app.post(url, params=params) | |||
|
56 | assert response.status_code in [200, 302] | |||
|
57 | ||||
|
58 | def test_plugin_settings_view_get_404(self, app, auth_plugin): | |||
|
59 | url = '{prefix}/auth/{name}'.format( | |||
|
60 | prefix=ADMIN_PREFIX, | |||
|
61 | name=auth_plugin.name) | |||
|
62 | with DisabledAuthPlugin(auth_plugin): | |||
|
63 | response = app.get(url, status=404) | |||
|
64 | assert response.status_code == 404 | |||
|
65 | ||||
|
66 | def test_plugin_settings_view_post_404(self, app, auth_plugin, csrf_token): | |||
|
67 | url = '{prefix}/auth/{name}'.format( | |||
|
68 | prefix=ADMIN_PREFIX, | |||
|
69 | name=auth_plugin.name) | |||
|
70 | params = { | |||
|
71 | 'enabled': True, | |||
|
72 | 'cache_ttl': 0, | |||
|
73 | 'csrf_token': csrf_token, | |||
|
74 | } | |||
|
75 | with DisabledAuthPlugin(auth_plugin): | |||
|
76 | response = app.post(url, params=params, status=404) | |||
|
77 | assert response.status_code == 404 |
@@ -0,0 +1,28 b'' | |||||
|
1 | # Copyright (C) 2016 RhodeCode GmbH | |||
|
2 | # | |||
|
3 | # This program is free software: you can redistribute it and/or modify | |||
|
4 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
5 | # (only), as published by the Free Software Foundation. | |||
|
6 | # | |||
|
7 | # This program is distributed in the hope that it will be useful, | |||
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
10 | # GNU General Public License for more details. | |||
|
11 | # | |||
|
12 | # You should have received a copy of the GNU Affero General Public License | |||
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
14 | # | |||
|
15 | # This program is dual-licensed. If you wish to learn more about the | |||
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
18 | ||||
|
19 | """ | |||
|
20 | Checks around the API of the class RhodeCodeAuthPluginBase. | |||
|
21 | """ | |||
|
22 | ||||
|
23 | from rhodecode.authentication.base import RhodeCodeAuthPluginBase | |||
|
24 | ||||
|
25 | ||||
|
26 | def test_str_returns_plugin_id(): | |||
|
27 | plugin = RhodeCodeAuthPluginBase(plugin_id='stub_plugin_id') | |||
|
28 | assert str(plugin) == 'stub_plugin_id' |
@@ -0,0 +1,75 b'' | |||||
|
1 | <% | |||
|
2 | elems = [ | |||
|
3 | ## general | |||
|
4 | (_('RhodeCode Enterprise version'), c.rhodecode_version, ''), | |||
|
5 | (_('Upgrade info endpoint'), c.rhodecode_update_url, ''), | |||
|
6 | (_('Configuration INI file'), c.rhodecode_config_ini, ''), | |||
|
7 | ## systems stats | |||
|
8 | (_('RhodeCode Enterprise Server IP'), c.server_ip, ''), | |||
|
9 | (_('RhodeCode Enterprise Server ID'), c.server_id, ''), | |||
|
10 | (_('Platform'), c.platform, ''), | |||
|
11 | (_('Uptime'), c.uptime_age, ''), | |||
|
12 | (_('Storage location'), c.storage, ''), | |||
|
13 | (_('Storage disk space'), "%s/%s, %s%% used%s" % (h.format_byte_size_binary(c.disk['used']), h.format_byte_size_binary(c.disk['total']),(c.disk['percent']), ' %s' % c.disk['error'] if 'error' in c.disk else ''), ''), | |||
|
14 | ||||
|
15 | (_('Search index storage'), c.index_storage, ''), | |||
|
16 | (_('Search index size'), "%s %s" % (h.format_byte_size_binary(c.disk_index['used']), ' %s' % c.disk_index['error'] if 'error' in c.disk_index else ''), ''), | |||
|
17 | ||||
|
18 | (_('Gist storage'), c.gist_storage, ''), | |||
|
19 | (_('Gist storage size'), "%s (%s items)%s" % (h.format_byte_size_binary(c.disk_gist['used']),c.disk_gist['items'], ' %s' % c.disk_gist['error'] if 'error' in c.disk_gist else ''), ''), | |||
|
20 | ||||
|
21 | (_('Archive cache'), c.archive_storage, ''), | |||
|
22 | (_('Archive cache size'), "%s%s" % (h.format_byte_size_binary(c.disk_archive['used']), ' %s' % c.disk_archive['error'] if 'error' in c.disk_archive else ''), ''), | |||
|
23 | ||||
|
24 | (_('System memory'), c.system_memory, ''), | |||
|
25 | (_('CPU'), '%s %%' %(c.cpu), ''), | |||
|
26 | (_('Load'), '1min: %s, 5min: %s, 15min: %s' %(c.load['1_min'],c.load['5_min'],c.load['15_min']), ''), | |||
|
27 | ||||
|
28 | ## rhodecode stuff | |||
|
29 | (_('Python version'), c.py_version, ''), | |||
|
30 | (_('Python path'), c.py_path, ''), | |||
|
31 | (_('GIT version'), c.git_version, ''), | |||
|
32 | (_('HG version'), c.hg_version, ''), | |||
|
33 | (_('SVN version'), c.svn_version, ''), | |||
|
34 | (_('Database'), "%s @ version: %s" % (c.db_type, c.db_migrate_version), ''), | |||
|
35 | (_('Database version'), c.db_version, ''), | |||
|
36 | ||||
|
37 | ] | |||
|
38 | %> | |||
|
39 | ||||
|
40 | <pre> | |||
|
41 | SYSTEM INFO | |||
|
42 | ----------- | |||
|
43 | ||||
|
44 | % for dt, dd, tt in elems: | |||
|
45 | ${dt}: ${dd} | |||
|
46 | % endfor | |||
|
47 | ||||
|
48 | PYTHON PACKAGES | |||
|
49 | --------------- | |||
|
50 | ||||
|
51 | % for key, value in c.py_modules: | |||
|
52 | ${key}: ${value} | |||
|
53 | % endfor | |||
|
54 | ||||
|
55 | SYSTEM SETTINGS | |||
|
56 | --------------- | |||
|
57 | ||||
|
58 | % for key, value in sorted(c.rhodecode_ini_safe.items()): | |||
|
59 | % if isinstance(value, dict): | |||
|
60 | ||||
|
61 | % for key2, value2 in value.items(): | |||
|
62 | [${key}]${key2}: ${value2} | |||
|
63 | % endfor | |||
|
64 | ||||
|
65 | % else: | |||
|
66 | ${key}: ${value} | |||
|
67 | % endif | |||
|
68 | % endfor | |||
|
69 | ||||
|
70 | </pre> | |||
|
71 | ||||
|
72 | ||||
|
73 | ||||
|
74 | ||||
|
75 |
@@ -1,5 +1,5 b'' | |||||
1 | [bumpversion] |
|
1 | [bumpversion] | |
2 |
current_version = 4. |
|
2 | current_version = 4.2.0 | |
3 | message = release: Bump version {current_version} to {new_version} |
|
3 | message = release: Bump version {current_version} to {new_version} | |
4 |
|
4 | |||
5 | [bumpversion:file:rhodecode/VERSION] |
|
5 | [bumpversion:file:rhodecode/VERSION] |
@@ -1,32 +1,26 b'' | |||||
1 | [DEFAULT] |
|
1 | [DEFAULT] | |
2 | done = false |
|
2 | done = false | |
3 |
|
3 | |||
|
4 | [task:fixes_on_stable] | |||
|
5 | ||||
|
6 | [task:changelog_updated] | |||
|
7 | ||||
4 | [task:bump_version] |
|
8 | [task:bump_version] | |
5 | done = true |
|
9 | done = true | |
6 |
|
10 | |||
7 | [task:rc_tools_pinned] |
|
11 | [task:generate_api_docs] | |
8 | done = true |
|
12 | ||
|
13 | [task:updated_translation] | |||
9 |
|
14 | |||
10 | [task:fixes_on_stable] |
|
15 | [release] | |
11 | done = true |
|
16 | state = in_progress | |
|
17 | version = 4.2.0 | |||
|
18 | ||||
|
19 | [task:rc_tools_pinned] | |||
12 |
|
20 | |||
13 | [task:pip2nix_generated] |
|
21 | [task:pip2nix_generated] | |
14 | done = true |
|
|||
15 |
|
||||
16 | [task:changelog_updated] |
|
|||
17 | done = true |
|
|||
18 |
|
||||
19 | [task:generate_api_docs] |
|
|||
20 | done = true |
|
|||
21 |
|
22 | |||
22 | [task:generate_js_routes] |
|
23 | [task:generate_js_routes] | |
23 | done = true |
|
|||
24 |
|
||||
25 | [release] |
|
|||
26 | state = prepared |
|
|||
27 | version = 4.1.2 |
|
|||
28 |
|
||||
29 | [task:updated_translation] |
|
|||
30 |
|
24 | |||
31 | [task:updated_trial_license] |
|
25 | [task:updated_trial_license] | |
32 |
|
26 |
@@ -41,6 +41,19 b' The latest sources can be obtained from ' | |||||
41 | https://code.rhodecode.com |
|
41 | https://code.rhodecode.com | |
42 |
|
42 | |||
43 |
|
43 | |||
|
44 | Contributions | |||
|
45 | ------------- | |||
|
46 | ||||
|
47 | RhodeCode is open-source; contributions are welcome! | |||
|
48 | ||||
|
49 | Please see the contribution documentation inside of the docs folder, which is | |||
|
50 | also available at | |||
|
51 | https://docs.rhodecode.com/RhodeCode-Enterprise/contributing/contributing.html | |||
|
52 | ||||
|
53 | For additional information about collaboration tools, our issue tracker, | |||
|
54 | licensing, and contribution credit, visit https://rhodecode.com/open-source | |||
|
55 | ||||
|
56 | ||||
44 | RhodeCode Features |
|
57 | RhodeCode Features | |
45 | ------------------ |
|
58 | ------------------ | |
46 |
|
59 |
@@ -1,7 +1,7 b'' | |||||
1 | README - Quickstart |
|
1 | README - Quickstart | |
2 | =================== |
|
2 | =================== | |
3 |
|
3 | |||
4 |
This folder contains functional tests and |
|
4 | This folder contains the functional tests and automation of specification | |
5 | examples. Details about testing can be found in |
|
5 | examples. Details about testing can be found in | |
6 | `/docs-internal/testing/index.rst`. |
|
6 | `/docs-internal/testing/index.rst`. | |
7 |
|
7 | |||
@@ -21,7 +21,7 b' Use the following example call for the d' | |||||
21 | --api-key=9999999999999999999999999999999999999999 \ |
|
21 | --api-key=9999999999999999999999999999999999999999 \ | |
22 | your-enterprise-config.ini |
|
22 | your-enterprise-config.ini | |
23 |
|
23 | |||
24 | This way the username, password and auth token of the admin user will match the |
|
24 | This way the username, password, and auth token of the admin user will match the | |
25 | defaults from the test run. |
|
25 | defaults from the test run. | |
26 |
|
26 | |||
27 |
|
27 | |||
@@ -34,7 +34,7 b' 1. Make sure your Rhodecode Enterprise i' | |||||
34 | 2. Enter `nix-shell` from the acceptance_tests folder:: |
|
34 | 2. Enter `nix-shell` from the acceptance_tests folder:: | |
35 |
|
35 | |||
36 | cd acceptance_tests |
|
36 | cd acceptance_tests | |
37 |
nix-shell |
|
37 | nix-shell | |
38 |
|
38 | |||
39 | Make sure that `rcpkgs` and `rcnixpkgs` are available on the nix path. |
|
39 | Make sure that `rcpkgs` and `rcnixpkgs` are available on the nix path. | |
40 |
|
40 |
@@ -8,7 +8,6 b'' | |||||
8 |
|
8 | |||
9 | [DEFAULT] |
|
9 | [DEFAULT] | |
10 | debug = true |
|
10 | debug = true | |
11 | pdebug = false |
|
|||
12 | ################################################################################ |
|
11 | ################################################################################ | |
13 | ## Uncomment and replace with the email address which should receive ## |
|
12 | ## Uncomment and replace with the email address which should receive ## | |
14 | ## any error reports after an application crash ## |
|
13 | ## any error reports after an application crash ## | |
@@ -115,11 +114,23 b' rhodecode.api.url = /_admin/api' | |||||
115 |
|
114 | |||
116 | ## END RHODECODE PLUGINS ## |
|
115 | ## END RHODECODE PLUGINS ## | |
117 |
|
116 | |||
|
117 | ## encryption key used to encrypt social plugin tokens, | |||
|
118 | ## remote_urls with credentials etc, if not set it defaults to | |||
|
119 | ## `beaker.session.secret` | |||
|
120 | #rhodecode.encrypted_values.secret = | |||
|
121 | ||||
|
122 | ## decryption strict mode (enabled by default). It controls if decryption raises | |||
|
123 | ## `SignatureVerificationError` in case of wrong key, or damaged encryption data. | |||
|
124 | #rhodecode.encrypted_values.strict = false | |||
|
125 | ||||
118 | full_stack = true |
|
126 | full_stack = true | |
119 |
|
127 | |||
120 | ## Serve static files via RhodeCode, disable to serve them via HTTP server |
|
128 | ## Serve static files via RhodeCode, disable to serve them via HTTP server | |
121 | static_files = true |
|
129 | static_files = true | |
122 |
|
130 | |||
|
131 | # autogenerate javascript routes file on startup | |||
|
132 | generate_js_files = false | |||
|
133 | ||||
123 | ## Optional Languages |
|
134 | ## Optional Languages | |
124 | ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh |
|
135 | ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh | |
125 | lang = en |
|
136 | lang = en | |
@@ -380,7 +391,6 b' beaker.session.auto = false' | |||||
380 | search.module = rhodecode.lib.index.whoosh |
|
391 | search.module = rhodecode.lib.index.whoosh | |
381 | search.location = %(here)s/data/index |
|
392 | search.location = %(here)s/data/index | |
382 |
|
393 | |||
383 |
|
||||
384 | ################################### |
|
394 | ################################### | |
385 | ## APPENLIGHT CONFIG ## |
|
395 | ## APPENLIGHT CONFIG ## | |
386 | ################################### |
|
396 | ################################### | |
@@ -514,7 +524,7 b' vcs.connection_timeout = 3600' | |||||
514 | ### LOGGING CONFIGURATION #### |
|
524 | ### LOGGING CONFIGURATION #### | |
515 | ################################ |
|
525 | ################################ | |
516 | [loggers] |
|
526 | [loggers] | |
517 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
527 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
518 |
|
528 | |||
519 | [handlers] |
|
529 | [handlers] | |
520 | keys = console, console_sql |
|
530 | keys = console, console_sql | |
@@ -566,12 +576,6 b' handlers = console_sql' | |||||
566 | qualname = sqlalchemy.engine |
|
576 | qualname = sqlalchemy.engine | |
567 | propagate = 0 |
|
577 | propagate = 0 | |
568 |
|
578 | |||
569 | [logger_whoosh_indexer] |
|
|||
570 | level = DEBUG |
|
|||
571 | handlers = |
|
|||
572 | qualname = whoosh_indexer |
|
|||
573 | propagate = 1 |
|
|||
574 |
|
||||
575 | ############## |
|
579 | ############## | |
576 | ## HANDLERS ## |
|
580 | ## HANDLERS ## | |
577 | ############## |
|
581 | ############## |
@@ -8,7 +8,6 b'' | |||||
8 |
|
8 | |||
9 | [DEFAULT] |
|
9 | [DEFAULT] | |
10 | debug = true |
|
10 | debug = true | |
11 | pdebug = false |
|
|||
12 | ################################################################################ |
|
11 | ################################################################################ | |
13 | ## Uncomment and replace with the email address which should receive ## |
|
12 | ## Uncomment and replace with the email address which should receive ## | |
14 | ## any error reports after an application crash ## |
|
13 | ## any error reports after an application crash ## | |
@@ -89,11 +88,23 b' use = egg:rhodecode-enterprise-ce' | |||||
89 | ## enable proxy prefix middleware, defined below |
|
88 | ## enable proxy prefix middleware, defined below | |
90 | #filter-with = proxy-prefix |
|
89 | #filter-with = proxy-prefix | |
91 |
|
90 | |||
|
91 | ## encryption key used to encrypt social plugin tokens, | |||
|
92 | ## remote_urls with credentials etc, if not set it defaults to | |||
|
93 | ## `beaker.session.secret` | |||
|
94 | #rhodecode.encrypted_values.secret = | |||
|
95 | ||||
|
96 | ## decryption strict mode (enabled by default). It controls if decryption raises | |||
|
97 | ## `SignatureVerificationError` in case of wrong key, or damaged encryption data. | |||
|
98 | #rhodecode.encrypted_values.strict = false | |||
|
99 | ||||
92 | full_stack = true |
|
100 | full_stack = true | |
93 |
|
101 | |||
94 | ## Serve static files via RhodeCode, disable to serve them via HTTP server |
|
102 | ## Serve static files via RhodeCode, disable to serve them via HTTP server | |
95 | static_files = true |
|
103 | static_files = true | |
96 |
|
104 | |||
|
105 | # autogenerate javascript routes file on startup | |||
|
106 | generate_js_files = false | |||
|
107 | ||||
97 | ## Optional Languages |
|
108 | ## Optional Languages | |
98 | ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh |
|
109 | ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh | |
99 | lang = en |
|
110 | lang = en | |
@@ -354,7 +365,6 b' beaker.session.auto = false' | |||||
354 | search.module = rhodecode.lib.index.whoosh |
|
365 | search.module = rhodecode.lib.index.whoosh | |
355 | search.location = %(here)s/data/index |
|
366 | search.location = %(here)s/data/index | |
356 |
|
367 | |||
357 |
|
||||
358 | ################################### |
|
368 | ################################### | |
359 | ## APPENLIGHT CONFIG ## |
|
369 | ## APPENLIGHT CONFIG ## | |
360 | ################################### |
|
370 | ################################### | |
@@ -483,7 +493,7 b' vcs.connection_timeout = 3600' | |||||
483 | ### LOGGING CONFIGURATION #### |
|
493 | ### LOGGING CONFIGURATION #### | |
484 | ################################ |
|
494 | ################################ | |
485 | [loggers] |
|
495 | [loggers] | |
486 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
496 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
487 |
|
497 | |||
488 | [handlers] |
|
498 | [handlers] | |
489 | keys = console, console_sql |
|
499 | keys = console, console_sql | |
@@ -535,12 +545,6 b' handlers = console_sql' | |||||
535 | qualname = sqlalchemy.engine |
|
545 | qualname = sqlalchemy.engine | |
536 | propagate = 0 |
|
546 | propagate = 0 | |
537 |
|
547 | |||
538 | [logger_whoosh_indexer] |
|
|||
539 | level = DEBUG |
|
|||
540 | handlers = |
|
|||
541 | qualname = whoosh_indexer |
|
|||
542 | propagate = 1 |
|
|||
543 |
|
||||
544 | ############## |
|
548 | ############## | |
545 | ## HANDLERS ## |
|
549 | ## HANDLERS ## | |
546 | ############## |
|
550 | ############## |
@@ -46,6 +46,7 b' let' | |||||
46 | !elem ext ["egg-info" "pyc"] && |
|
46 | !elem ext ["egg-info" "pyc"] && | |
47 | !startsWith "result" path; |
|
47 | !startsWith "result" path; | |
48 |
|
48 | |||
|
49 | sources = pkgs.config.rc.sources or {}; | |||
49 | rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.; |
|
50 | rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.; | |
50 |
|
51 | |||
51 | # Load the generated node packages |
|
52 | # Load the generated node packages | |
@@ -98,9 +99,11 b' let' | |||||
98 | ''; |
|
99 | ''; | |
99 | in super.rhodecode-enterprise-ce.override (attrs: { |
|
100 | in super.rhodecode-enterprise-ce.override (attrs: { | |
100 |
|
101 | |||
101 |
inherit |
|
102 | inherit | |
|
103 | doCheck | |||
|
104 | version; | |||
102 | name = "rhodecode-enterprise-ce-${version}"; |
|
105 | name = "rhodecode-enterprise-ce-${version}"; | |
103 | version = version; |
|
106 | releaseName = "RhodeCodeEnterpriseCE-${version}"; | |
104 | src = rhodecode-enterprise-ce-src; |
|
107 | src = rhodecode-enterprise-ce-src; | |
105 |
|
108 | |||
106 | buildInputs = |
|
109 | buildInputs = | |
@@ -109,7 +112,7 b' let' | |||||
109 | pkgs.nodePackages.grunt-cli |
|
112 | pkgs.nodePackages.grunt-cli | |
110 | pkgs.subversion |
|
113 | pkgs.subversion | |
111 | pytest-catchlog |
|
114 | pytest-catchlog | |
112 |
r |
|
115 | rhodecode-testdata | |
113 | ]); |
|
116 | ]); | |
114 |
|
117 | |||
115 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [ |
|
118 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [ | |
@@ -197,17 +200,22 b' let' | |||||
197 |
|
200 | |||
198 | }); |
|
201 | }); | |
199 |
|
202 | |||
200 | rc_testdata = self.buildPythonPackage rec { |
|
203 | rhodecode-testdata = import "${rhodecode-testdata-src}/default.nix" { | |
201 | name = "rc_testdata-0.7.0"; |
|
204 | inherit | |
202 | src = pkgs.fetchhg { |
|
205 | doCheck | |
203 | url = "https://code.rhodecode.com/upstream/rc_testdata"; |
|
206 | pkgs | |
204 | rev = "v0.7.0"; |
|
207 | pythonPackages; | |
205 | sha256 = "0w3z0zn8lagr707v67lgys23sl6pbi4xg7pfvdbw58h3q384h6rx"; |
|
|||
206 | }; |
|
|||
207 | }; |
|
208 | }; | |
208 |
|
209 | |||
209 | }; |
|
210 | }; | |
210 |
|
211 | |||
|
212 | rhodecode-testdata-src = sources.rhodecode-testdata or ( | |||
|
213 | pkgs.fetchhg { | |||
|
214 | url = "https://code.rhodecode.com/upstream/rc_testdata"; | |||
|
215 | rev = "v0.8.0"; | |||
|
216 | sha256 = "0hy1ba134rq2f9si85yx7j4qhc9ky0hjzdk553s3q026i7km809m"; | |||
|
217 | }); | |||
|
218 | ||||
211 | # Apply all overrides and fix the final package set |
|
219 | # Apply all overrides and fix the final package set | |
212 | myPythonPackagesUnfix = |
|
220 | myPythonPackagesUnfix = | |
213 | (extends pythonExternalOverrides |
|
221 | (extends pythonExternalOverrides |
@@ -47,7 +47,7 b' the ``debug`` level.' | |||||
47 | ### LOGGING CONFIGURATION #### |
|
47 | ### LOGGING CONFIGURATION #### | |
48 | ################################ |
|
48 | ################################ | |
49 | [loggers] |
|
49 | [loggers] | |
50 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
50 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
51 |
|
51 | |||
52 | [handlers] |
|
52 | [handlers] | |
53 | keys = console, console_sql, file, file_rotating |
|
53 | keys = console, console_sql, file, file_rotating | |
@@ -99,12 +99,6 b' the ``debug`` level.' | |||||
99 | qualname = sqlalchemy.engine |
|
99 | qualname = sqlalchemy.engine | |
100 | propagate = 0 |
|
100 | propagate = 0 | |
101 |
|
101 | |||
102 | [logger_whoosh_indexer] |
|
|||
103 | level = DEBUG |
|
|||
104 | handlers = |
|
|||
105 | qualname = whoosh_indexer |
|
|||
106 | propagate = 1 |
|
|||
107 |
|
||||
108 | ############## |
|
102 | ############## | |
109 | ## HANDLERS ## |
|
103 | ## HANDLERS ## | |
110 | ############## |
|
104 | ############## |
@@ -5,13 +5,14 b' Contributing to RhodeCode' | |||||
5 |
|
5 | |||
6 |
|
6 | |||
7 |
|
7 | |||
8 | Welcome to contribution guides and development docs of RhodeCode. |
|
8 | Welcome to the contribution guides and development docs of RhodeCode. | |
9 |
|
9 | |||
10 |
|
10 | |||
11 |
|
11 | |||
12 | .. toctree:: |
|
12 | .. toctree:: | |
13 | :maxdepth: 1 |
|
13 | :maxdepth: 1 | |
14 |
|
14 | |||
|
15 | overview | |||
15 | testing/index |
|
16 | testing/index | |
16 | dev-setup |
|
17 | dev-setup | |
17 | db-schema |
|
18 | db-schema |
@@ -2,7 +2,7 b'' | |||||
2 | DB Schema and Migration |
|
2 | DB Schema and Migration | |
3 | ======================= |
|
3 | ======================= | |
4 |
|
4 | |||
5 | To create or alter tables in the database it's necessary to change a couple of |
|
5 | To create or alter tables in the database, it's necessary to change a couple of | |
6 | files, apart from configuring the settings pointing to the latest database |
|
6 | files, apart from configuring the settings pointing to the latest database | |
7 | schema. |
|
7 | schema. | |
8 |
|
8 | |||
@@ -11,11 +11,11 b' Database Model and ORM' | |||||
11 | ---------------------- |
|
11 | ---------------------- | |
12 |
|
12 | |||
13 | On ``rhodecode.model.db`` you will find the database definition of all tables and |
|
13 | On ``rhodecode.model.db`` you will find the database definition of all tables and | |
14 | fields. Any fresh install database will be correctly created by the definitions |
|
14 | fields. Any freshly installed database will be correctly created by the definitions | |
15 |
here. So, any change to this file |
|
15 | here. So, any change to this file will affect the tests without having to change | |
16 | any other file. |
|
16 | any other file. | |
17 |
|
17 | |||
18 |
A second layer are the busin |
|
18 | A second layer are the business classes inside ``rhodecode.model``. | |
19 |
|
19 | |||
20 |
|
20 | |||
21 | Database Migration |
|
21 | Database Migration | |
@@ -30,7 +30,7 b' Three files play a role when creating da' | |||||
30 |
|
30 | |||
31 | Schema is a snapshot of the database version BEFORE the migration. So, it's |
|
31 | Schema is a snapshot of the database version BEFORE the migration. So, it's | |
32 | the initial state before any changes were added. The name convention is |
|
32 | the initial state before any changes were added. The name convention is | |
33 |
the latest release version where the snapshot w |
|
33 | the latest release version where the snapshot was created, and not the | |
34 | target version of this code. |
|
34 | target version of this code. | |
35 |
|
35 | |||
36 | Version is the method that will define how to UPGRADE/DOWNGRADE the database. |
|
36 | Version is the method that will define how to UPGRADE/DOWNGRADE the database. | |
@@ -45,8 +45,8 b' For examples on how to create those file' | |||||
45 | Migration Command |
|
45 | Migration Command | |
46 | ^^^^^^^^^^^^^^^^^ |
|
46 | ^^^^^^^^^^^^^^^^^ | |
47 |
|
47 | |||
48 | After you changed the database ORM and migration files, you can run:: |
|
48 | After you've changed the database ORM and migration files, you can run:: | |
49 |
|
49 | |||
50 | paster upgrade-db <ini-file> |
|
50 | paster upgrade-db <ini-file> | |
51 |
|
51 | |||
52 |
|
|
52 | The database will be upgraded up to the version defined in the ``__init__`` file. No newline at end of file |
@@ -13,7 +13,7 b' purposes. This section contains an overv' | |||||
13 | ============= |
|
13 | ============= | |
14 |
|
14 | |||
15 | Enables the section "Style" in the application. This section provides an |
|
15 | Enables the section "Style" in the application. This section provides an | |
16 |
overview of all components which are found in the frontend |
|
16 | overview of all components which are found in the frontend of the | |
17 | application. |
|
17 | application. | |
18 |
|
18 | |||
19 |
|
19 | |||
@@ -29,9 +29,9 b' to ease development.' | |||||
29 | `[logging]` |
|
29 | `[logging]` | |
30 | =========== |
|
30 | =========== | |
31 |
|
31 | |||
32 | Use this to configure loggig to your current needs. The documentation of |
|
32 | Use this to configure logging to your current needs. The documentation of | |
33 |
Python's `logging` module explains all details. The following snippets |
|
33 | Python's `logging` module explains all of the details. The following snippets | |
34 | useful for day to day development work. |
|
34 | are useful for day to day development work. | |
35 |
|
35 | |||
36 |
|
36 | |||
37 | Mute SQL output |
|
37 | Mute SQL output |
@@ -1,3 +1,4 b'' | |||||
|
1 | .. _dev-setup: | |||
1 |
|
2 | |||
2 | =================== |
|
3 | =================== | |
3 | Development setup |
|
4 | Development setup | |
@@ -7,21 +8,21 b'' | |||||
7 | RhodeCode Enterprise runs inside a Nix managed environment. This ensures build |
|
8 | RhodeCode Enterprise runs inside a Nix managed environment. This ensures build | |
8 | environment dependencies are correctly declared and installed during setup. |
|
9 | environment dependencies are correctly declared and installed during setup. | |
9 | It also enables atomic upgrades, rollbacks, and multiple instances of RhodeCode |
|
10 | It also enables atomic upgrades, rollbacks, and multiple instances of RhodeCode | |
10 | Enterprise for efficient cluster management. |
|
11 | Enterprise running with isolation. | |
11 |
|
12 | |||
12 | To set up RhodeCode Enterprise inside the Nix environment use the following steps: |
|
13 | To set up RhodeCode Enterprise inside the Nix environment, use the following steps: | |
13 |
|
14 | |||
14 |
|
15 | |||
15 |
|
16 | |||
16 | Setup Nix Package Manager |
|
17 | Setup Nix Package Manager | |
17 | ------------------------- |
|
18 | ------------------------- | |
18 |
|
19 | |||
19 | To install the Nix Package Manager please run:: |
|
20 | To install the Nix Package Manager, please run:: | |
20 |
|
21 | |||
21 | $ curl https://nixos.org/nix/install | sh |
|
22 | $ curl https://nixos.org/nix/install | sh | |
22 |
|
23 | |||
23 |
or go to https://nixos.org/nix/ and follow the |
|
24 | or go to https://nixos.org/nix/ and follow the installation instructions. | |
24 | Once this is correctly set up on your system you should be able to use the |
|
25 | Once this is correctly set up on your system, you should be able to use the | |
25 | following commands: |
|
26 | following commands: | |
26 |
|
27 | |||
27 | * `nix-env` |
|
28 | * `nix-env` | |
@@ -34,8 +35,8 b' following commands:' | |||||
34 | Update your channels frequently by running ``nix-channel --upgrade``. |
|
35 | Update your channels frequently by running ``nix-channel --upgrade``. | |
35 |
|
36 | |||
36 |
|
37 | |||
37 | Switch nix to latest STABLE channel |
|
38 | Switch nix to the latest STABLE channel | |
38 | ----------------------------------- |
|
39 | --------------------------------------- | |
39 |
|
40 | |||
40 | run:: |
|
41 | run:: | |
41 |
|
42 | |||
@@ -49,7 +50,7 b' Followed by::' | |||||
49 | Clone the required repositories |
|
50 | Clone the required repositories | |
50 | ------------------------------- |
|
51 | ------------------------------- | |
51 |
|
52 | |||
52 |
After Nix is set up, clone the RhodeCode Enterprise Community Edition |
|
53 | After Nix is set up, clone the RhodeCode Enterprise Community Edition and | |
53 | RhodeCode VCSServer repositories into the same directory. |
|
54 | RhodeCode VCSServer repositories into the same directory. | |
54 | To do this, use the following example:: |
|
55 | To do this, use the following example:: | |
55 |
|
56 | |||
@@ -59,23 +60,25 b' To do this, use the following example::' | |||||
59 |
|
60 | |||
60 | .. note:: |
|
61 | .. note:: | |
61 |
|
62 | |||
62 |
If you cannot clone the repository, please request read permissions |
|
63 | If you cannot clone the repository, please request read permissions | |
|
64 | via support@rhodecode.com | |||
63 |
|
65 | |||
64 |
|
66 | |||
65 |
|
67 | |||
66 | Enter the Development Shell |
|
68 | Enter the Development Shell | |
67 | --------------------------- |
|
69 | --------------------------- | |
68 |
|
70 | |||
69 |
The final step is to start |
|
71 | The final step is to start the development shell. To do this, run the | |
70 | following command from inside the cloned repository:: |
|
72 | following command from inside the cloned repository:: | |
71 |
|
73 | |||
72 | cd ~/rhodecode-enterprise-ce |
|
74 | cd ~/rhodecode-enterprise-ce | |
73 |
nix-shell |
|
75 | nix-shell | |
74 |
|
76 | |||
75 | .. note:: |
|
77 | .. note:: | |
76 |
|
78 | |||
77 | On the first run, this will take a while to download and optionally compile |
|
79 | On the first run, this will take a while to download and optionally compile | |
78 |
a few things. The |
|
80 | a few things. The following runs will be faster. The development shell works | |
|
81 | fine on MacOS and Linux platforms. | |||
79 |
|
82 | |||
80 |
|
83 | |||
81 |
|
84 | |||
@@ -90,13 +93,13 b' 2. Adjust the configuration settings to ' | |||||
90 |
|
93 | |||
91 | .. note:: |
|
94 | .. note:: | |
92 |
|
95 | |||
93 |
It is recommended to |
|
96 | It is recommended to use the name `dev.ini`. | |
94 |
|
97 | |||
95 |
|
98 | |||
96 | Setup the Development Database |
|
99 | Setup the Development Database | |
97 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
100 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
98 |
|
101 | |||
99 | To create a development database use the following example. This is a one |
|
102 | To create a development database, use the following example. This is a one | |
100 | time operation:: |
|
103 | time operation:: | |
101 |
|
104 | |||
102 | paster setup-rhodecode dev.ini \ |
|
105 | paster setup-rhodecode dev.ini \ | |
@@ -109,7 +112,7 b' Start the Development Server' | |||||
109 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
112 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
110 |
|
113 | |||
111 | When starting the development server, you should start the vcsserver as a |
|
114 | When starting the development server, you should start the vcsserver as a | |
112 | separate process. To do this use one of the following examples: |
|
115 | separate process. To do this, use one of the following examples: | |
113 |
|
116 | |||
114 | 1. Set the `start.vcs_server` flag in the ``dev.ini`` file to true. For example: |
|
117 | 1. Set the `start.vcs_server` flag in the ``dev.ini`` file to true. For example: | |
115 |
|
118 | |||
@@ -136,6 +139,6 b' 3. Start the development server in a dif' | |||||
136 | Run the Environment Tests |
|
139 | Run the Environment Tests | |
137 | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
140 | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
138 |
|
141 | |||
139 | Please make sure that the test are passing to verify that your environment is |
|
142 | Please make sure that the tests are passing to verify that your environment is | |
140 | set up correctly. More details about the tests are described in: |
|
143 | set up correctly. RhodeCode uses py.test to run tests. | |
141 | :file:`/docs/dev/testing`. |
|
144 | Please simply run ``make test`` to run the basic test suite. |
@@ -17,12 +17,12 b'' | |||||
17 | Overview |
|
17 | Overview | |
18 | ======== |
|
18 | ======== | |
19 |
|
19 | |||
20 |
We have a quite |
|
20 | We have a quite large test suite inside of :file:`rhodecode/tests` which is a mix | |
21 | of unit tests and functional or integration tests. More details are in |
|
21 | of unit tests and functional or integration tests. More details are in | |
22 | :ref:`test-unit-and-functional`. |
|
22 | :ref:`test-unit-and-functional`. | |
23 |
|
23 | |||
24 |
|
24 | |||
25 |
Apart from that we start to apply "Specification by Example" and maintain |
|
25 | Apart from that, we are starting to apply "Specification by Example" and maintain | |
26 |
collection of such specifications together with an implementation so that it |
|
26 | a collection of such specifications together with an implementation so that it | |
27 | be validated in an automatic way. The files can be found in |
|
27 | can be validated in an automatic way. The files can be found in | |
28 | :file:`acceptance_tests`. More details are in :ref:`test-spec-by-example`. |
|
28 | :file:`acceptance_tests`. More details are in :ref:`test-spec-by-example`. |
@@ -66,10 +66,10 b' Locators' | |||||
66 | -------- |
|
66 | -------- | |
67 |
|
67 | |||
68 | The specific information how to locate an element inside of the DOM tree of a |
|
68 | The specific information how to locate an element inside of the DOM tree of a | |
69 |
page is kept in a separate class. This class serves mainly as a data container |
|
69 | page is kept in a separate class. This class serves mainly as a data container; | |
70 | it shall not contain any logic. |
|
70 | it shall not contain any logic. | |
71 |
|
71 | |||
72 | The reason for keeping the locators separate is that we expect a frequent need |
|
72 | The reason for keeping the locators separate is that we expect a frequent need | |
73 | for change whenever we work on our templates. In such a case it is more |
|
73 | for change whenever we work on our templates. In such a case, it is more | |
74 |
efficient to have all locators together and update them there instead of |
|
74 | efficient to have all of thelocators together and update them there instead of | |
75 |
to find |
|
75 | having to find every locator inside of the logic of a page object. |
@@ -27,7 +27,7 b' py.test integration' | |||||
27 | The integration with the test runner is based on the following three parts: |
|
27 | The integration with the test runner is based on the following three parts: | |
28 |
|
28 | |||
29 | - `pytest_pylons` is a py.test plugin which does the integration with the |
|
29 | - `pytest_pylons` is a py.test plugin which does the integration with the | |
30 |
Pylons web framework. It sets up the Pylons environment based on |
|
30 | Pylons web framework. It sets up the Pylons environment based on the given ini | |
31 | file. |
|
31 | file. | |
32 |
|
32 | |||
33 | Tests which depend on the Pylons environment to be set up must request the |
|
33 | Tests which depend on the Pylons environment to be set up must request the |
@@ -9,6 +9,7 b' Release Notes' | |||||
9 | .. toctree:: |
|
9 | .. toctree:: | |
10 | :maxdepth: 1 |
|
10 | :maxdepth: 1 | |
11 |
|
11 | |||
|
12 | release-notes-4.2.0.rst | |||
12 | release-notes-4.1.2.rst |
|
13 | release-notes-4.1.2.rst | |
13 | release-notes-4.1.1.rst |
|
14 | release-notes-4.1.1.rst | |
14 | release-notes-4.1.0.rst |
|
15 | release-notes-4.1.0.rst |
@@ -34,9 +34,6 b' let' | |||||
34 | # figure it out without calling into nix-store. |
|
34 | # figure it out without calling into nix-store. | |
35 | enterprise = import ./default.nix { |
|
35 | enterprise = import ./default.nix { | |
36 | doCheck = false; |
|
36 | doCheck = false; | |
37 | with_vcsserver = false; |
|
|||
38 | with_pyramid = false; |
|
|||
39 | cythonize = false; |
|
|||
40 | }; |
|
37 | }; | |
41 |
|
38 | |||
42 | # For a given derivation, return the list of all dependencies |
|
39 | # For a given derivation, return the list of all dependencies |
@@ -8,10 +8,28 b'' | |||||
8 |
|
8 | |||
9 | let |
|
9 | let | |
10 | sed = "sed -i"; |
|
10 | sed = "sed -i"; | |
|
11 | localLicenses = { | |||
|
12 | repoze = { | |||
|
13 | fullName = "Repoze License"; | |||
|
14 | url = http://www.repoze.org/LICENSE.txt; | |||
|
15 | }; | |||
|
16 | }; | |||
11 | in |
|
17 | in | |
12 |
|
18 | |||
13 | self: super: { |
|
19 | self: super: { | |
14 |
|
20 | |||
|
21 | appenlight-client = super.appenlight-client.override (attrs: { | |||
|
22 | meta = { | |||
|
23 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
24 | }; | |||
|
25 | }); | |||
|
26 | ||||
|
27 | future = super.future.override (attrs: { | |||
|
28 | meta = { | |||
|
29 | license = [ pkgs.lib.licenses.mit ]; | |||
|
30 | }; | |||
|
31 | }); | |||
|
32 | ||||
15 | gnureadline = super.gnureadline.override (attrs: { |
|
33 | gnureadline = super.gnureadline.override (attrs: { | |
16 | buildInputs = attrs.buildInputs ++ [ |
|
34 | buildInputs = attrs.buildInputs ++ [ | |
17 | pkgs.ncurses |
|
35 | pkgs.ncurses | |
@@ -72,6 +90,9 b' self: super: {' | |||||
72 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ |
|
90 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ | |
73 | pkgs.postgresql |
|
91 | pkgs.postgresql | |
74 | ]; |
|
92 | ]; | |
|
93 | meta = { | |||
|
94 | license = pkgs.lib.licenses.lgpl3Plus; | |||
|
95 | }; | |||
75 | }); |
|
96 | }); | |
76 |
|
97 | |||
77 | pycurl = super.pycurl.override (attrs: { |
|
98 | pycurl = super.pycurl.override (attrs: { | |
@@ -83,6 +104,10 b' self: super: {' | |||||
83 | substituteInPlace setup.py --replace '--static-libs' '--libs' |
|
104 | substituteInPlace setup.py --replace '--static-libs' '--libs' | |
84 | export PYCURL_SSL_LIBRARY=openssl |
|
105 | export PYCURL_SSL_LIBRARY=openssl | |
85 | ''; |
|
106 | ''; | |
|
107 | meta = { | |||
|
108 | # TODO: It is LGPL and MIT | |||
|
109 | license = pkgs.lib.licenses.mit; | |||
|
110 | }; | |||
86 | }); |
|
111 | }); | |
87 |
|
112 | |||
88 | Pylons = super.Pylons.override (attrs: { |
|
113 | Pylons = super.Pylons.override (attrs: { | |
@@ -101,6 +126,15 b' self: super: {' | |||||
101 | # confuses pserve. |
|
126 | # confuses pserve. | |
102 | ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped |
|
127 | ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped | |
103 | ''; |
|
128 | ''; | |
|
129 | meta = { | |||
|
130 | license = localLicenses.repoze; | |||
|
131 | }; | |||
|
132 | }); | |||
|
133 | ||||
|
134 | pyramid-debugtoolbar = super.pyramid-debugtoolbar.override (attrs: { | |||
|
135 | meta = { | |||
|
136 | license = [ pkgs.lib.licenses.bsdOriginal localLicenses.repoze ]; | |||
|
137 | }; | |||
104 | }); |
|
138 | }); | |
105 |
|
139 | |||
106 | Pyro4 = super.Pyro4.override (attrs: { |
|
140 | Pyro4 = super.Pyro4.override (attrs: { | |
@@ -117,6 +151,9 b' self: super: {' | |||||
117 | propagatedBuildInputs = [ |
|
151 | propagatedBuildInputs = [ | |
118 | pkgs.sqlite |
|
152 | pkgs.sqlite | |
119 | ]; |
|
153 | ]; | |
|
154 | meta = { | |||
|
155 | license = [ pkgs.lib.licenses.zlib pkgs.lib.licenses.libpng ]; | |||
|
156 | }; | |||
120 | }); |
|
157 | }); | |
121 |
|
158 | |||
122 | pytest-runner = super.pytest-runner.override (attrs: { |
|
159 | pytest-runner = super.pytest-runner.override (attrs: { | |
@@ -158,6 +195,77 b' self: super: {' | |||||
158 | ]; |
|
195 | ]; | |
159 | }); |
|
196 | }); | |
160 |
|
197 | |||
|
198 | URLObject = super.URLObject.override (attrs: { | |||
|
199 | meta = { | |||
|
200 | license = { | |||
|
201 | spdxId = "Unlicense"; | |||
|
202 | fullName = "The Unlicense"; | |||
|
203 | url = http://unlicense.org/; | |||
|
204 | }; | |||
|
205 | }; | |||
|
206 | }); | |||
|
207 | ||||
|
208 | amqplib = super.amqplib.override (attrs: { | |||
|
209 | meta = { | |||
|
210 | license = pkgs.lib.licenses.lgpl3; | |||
|
211 | }; | |||
|
212 | }); | |||
|
213 | ||||
|
214 | docutils = super.docutils.override (attrs: { | |||
|
215 | meta = { | |||
|
216 | license = pkgs.lib.licenses.bsd2; | |||
|
217 | }; | |||
|
218 | }); | |||
|
219 | ||||
|
220 | colander = super.colander.override (attrs: { | |||
|
221 | meta = { | |||
|
222 | license = localLicenses.repoze; | |||
|
223 | }; | |||
|
224 | }); | |||
|
225 | ||||
|
226 | pyramid-beaker = super.pyramid-beaker.override (attrs: { | |||
|
227 | meta = { | |||
|
228 | license = localLicenses.repoze; | |||
|
229 | }; | |||
|
230 | }); | |||
|
231 | ||||
|
232 | pyramid-mako = super.pyramid-mako.override (attrs: { | |||
|
233 | meta = { | |||
|
234 | license = localLicenses.repoze; | |||
|
235 | }; | |||
|
236 | }); | |||
|
237 | ||||
|
238 | repoze.lru = super.repoze.lru.override (attrs: { | |||
|
239 | meta = { | |||
|
240 | license = localLicenses.repoze; | |||
|
241 | }; | |||
|
242 | }); | |||
|
243 | ||||
|
244 | recaptcha-client = super.recaptcha-client.override (attrs: { | |||
|
245 | meta = { | |||
|
246 | # TODO: It is MIT/X11 | |||
|
247 | license = pkgs.lib.licenses.mit; | |||
|
248 | }; | |||
|
249 | }); | |||
|
250 | ||||
|
251 | python-editor = super.python-editor.override (attrs: { | |||
|
252 | meta = { | |||
|
253 | license = pkgs.lib.licenses.asl20; | |||
|
254 | }; | |||
|
255 | }); | |||
|
256 | ||||
|
257 | translationstring = super.translationstring.override (attrs: { | |||
|
258 | meta = { | |||
|
259 | license = localLicenses.repoze; | |||
|
260 | }; | |||
|
261 | }); | |||
|
262 | ||||
|
263 | venusian = super.venusian.override (attrs: { | |||
|
264 | meta = { | |||
|
265 | license = localLicenses.repoze; | |||
|
266 | }; | |||
|
267 | }); | |||
|
268 | ||||
161 | # Avoid that setuptools is replaced, this leads to trouble |
|
269 | # Avoid that setuptools is replaced, this leads to trouble | |
162 | # with buildPythonPackage. |
|
270 | # with buildPythonPackage. | |
163 | setuptools = basePythonPackages.setuptools; |
|
271 | setuptools = basePythonPackages.setuptools; |
@@ -8,6 +8,9 b'' | |||||
8 | url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz"; |
|
8 | url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz"; | |
9 | md5 = "5264ceb02717843cbc9ffce8e6e06bdb"; |
|
9 | md5 = "5264ceb02717843cbc9ffce8e6e06bdb"; | |
10 | }; |
|
10 | }; | |
|
11 | meta = { | |||
|
12 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
13 | }; | |||
11 | }; |
|
14 | }; | |
12 | Beaker = super.buildPythonPackage { |
|
15 | Beaker = super.buildPythonPackage { | |
13 | name = "Beaker-1.7.0"; |
|
16 | name = "Beaker-1.7.0"; | |
@@ -18,6 +21,9 b'' | |||||
18 | url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz"; |
|
21 | url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz"; | |
19 | md5 = "386be3f7fe427358881eee4622b428b3"; |
|
22 | md5 = "386be3f7fe427358881eee4622b428b3"; | |
20 | }; |
|
23 | }; | |
|
24 | meta = { | |||
|
25 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
26 | }; | |||
21 | }; |
|
27 | }; | |
22 | CProfileV = super.buildPythonPackage { |
|
28 | CProfileV = super.buildPythonPackage { | |
23 | name = "CProfileV-1.0.6"; |
|
29 | name = "CProfileV-1.0.6"; | |
@@ -28,6 +34,9 b'' | |||||
28 | url = "https://pypi.python.org/packages/eb/df/983a0b6cfd3ac94abf023f5011cb04f33613ace196e33f53c86cf91850d5/CProfileV-1.0.6.tar.gz"; |
|
34 | url = "https://pypi.python.org/packages/eb/df/983a0b6cfd3ac94abf023f5011cb04f33613ace196e33f53c86cf91850d5/CProfileV-1.0.6.tar.gz"; | |
29 | md5 = "08c7c242b6e64237bc53c5d13537e03d"; |
|
35 | md5 = "08c7c242b6e64237bc53c5d13537e03d"; | |
30 | }; |
|
36 | }; | |
|
37 | meta = { | |||
|
38 | license = [ pkgs.lib.licenses.mit ]; | |||
|
39 | }; | |||
31 | }; |
|
40 | }; | |
32 | Fabric = super.buildPythonPackage { |
|
41 | Fabric = super.buildPythonPackage { | |
33 | name = "Fabric-1.10.0"; |
|
42 | name = "Fabric-1.10.0"; | |
@@ -38,6 +47,9 b'' | |||||
38 | url = "https://pypi.python.org/packages/e3/5f/b6ebdb5241d5ec9eab582a5c8a01255c1107da396f849e538801d2fe64a5/Fabric-1.10.0.tar.gz"; |
|
47 | url = "https://pypi.python.org/packages/e3/5f/b6ebdb5241d5ec9eab582a5c8a01255c1107da396f849e538801d2fe64a5/Fabric-1.10.0.tar.gz"; | |
39 | md5 = "2cb96473387f0e7aa035210892352f4a"; |
|
48 | md5 = "2cb96473387f0e7aa035210892352f4a"; | |
40 | }; |
|
49 | }; | |
|
50 | meta = { | |||
|
51 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
52 | }; | |||
41 | }; |
|
53 | }; | |
42 | FormEncode = super.buildPythonPackage { |
|
54 | FormEncode = super.buildPythonPackage { | |
43 | name = "FormEncode-1.2.4"; |
|
55 | name = "FormEncode-1.2.4"; | |
@@ -48,6 +60,9 b'' | |||||
48 | url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz"; |
|
60 | url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz"; | |
49 | md5 = "6bc17fb9aed8aea198975e888e2077f4"; |
|
61 | md5 = "6bc17fb9aed8aea198975e888e2077f4"; | |
50 | }; |
|
62 | }; | |
|
63 | meta = { | |||
|
64 | license = [ pkgs.lib.licenses.psfl ]; | |||
|
65 | }; | |||
51 | }; |
|
66 | }; | |
52 | Jinja2 = super.buildPythonPackage { |
|
67 | Jinja2 = super.buildPythonPackage { | |
53 | name = "Jinja2-2.7.3"; |
|
68 | name = "Jinja2-2.7.3"; | |
@@ -58,6 +73,9 b'' | |||||
58 | url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz"; |
|
73 | url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz"; | |
59 | md5 = "b9dffd2f3b43d673802fe857c8445b1a"; |
|
74 | md5 = "b9dffd2f3b43d673802fe857c8445b1a"; | |
60 | }; |
|
75 | }; | |
|
76 | meta = { | |||
|
77 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
78 | }; | |||
61 | }; |
|
79 | }; | |
62 | Mako = super.buildPythonPackage { |
|
80 | Mako = super.buildPythonPackage { | |
63 | name = "Mako-1.0.1"; |
|
81 | name = "Mako-1.0.1"; | |
@@ -68,6 +86,9 b'' | |||||
68 | url = "https://pypi.python.org/packages/8e/a4/aa56533ecaa5f22ca92428f74e074d0c9337282933c722391902c8f9e0f8/Mako-1.0.1.tar.gz"; |
|
86 | url = "https://pypi.python.org/packages/8e/a4/aa56533ecaa5f22ca92428f74e074d0c9337282933c722391902c8f9e0f8/Mako-1.0.1.tar.gz"; | |
69 | md5 = "9f0aafd177b039ef67b90ea350497a54"; |
|
87 | md5 = "9f0aafd177b039ef67b90ea350497a54"; | |
70 | }; |
|
88 | }; | |
|
89 | meta = { | |||
|
90 | license = [ pkgs.lib.licenses.mit ]; | |||
|
91 | }; | |||
71 | }; |
|
92 | }; | |
72 | Markdown = super.buildPythonPackage { |
|
93 | Markdown = super.buildPythonPackage { | |
73 | name = "Markdown-2.6.2"; |
|
94 | name = "Markdown-2.6.2"; | |
@@ -78,6 +99,9 b'' | |||||
78 | url = "https://pypi.python.org/packages/62/8b/83658b5f6c220d5fcde9f9852d46ea54765d734cfbc5a9f4c05bfc36db4d/Markdown-2.6.2.tar.gz"; |
|
99 | url = "https://pypi.python.org/packages/62/8b/83658b5f6c220d5fcde9f9852d46ea54765d734cfbc5a9f4c05bfc36db4d/Markdown-2.6.2.tar.gz"; | |
79 | md5 = "256d19afcc564dc4ce4c229bb762f7ae"; |
|
100 | md5 = "256d19afcc564dc4ce4c229bb762f7ae"; | |
80 | }; |
|
101 | }; | |
|
102 | meta = { | |||
|
103 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
104 | }; | |||
81 | }; |
|
105 | }; | |
82 | MarkupSafe = super.buildPythonPackage { |
|
106 | MarkupSafe = super.buildPythonPackage { | |
83 | name = "MarkupSafe-0.23"; |
|
107 | name = "MarkupSafe-0.23"; | |
@@ -88,6 +112,9 b'' | |||||
88 | url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz"; |
|
112 | url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz"; | |
89 | md5 = "f5ab3deee4c37cd6a922fb81e730da6e"; |
|
113 | md5 = "f5ab3deee4c37cd6a922fb81e730da6e"; | |
90 | }; |
|
114 | }; | |
|
115 | meta = { | |||
|
116 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
117 | }; | |||
91 | }; |
|
118 | }; | |
92 | MySQL-python = super.buildPythonPackage { |
|
119 | MySQL-python = super.buildPythonPackage { | |
93 | name = "MySQL-python-1.2.5"; |
|
120 | name = "MySQL-python-1.2.5"; | |
@@ -98,6 +125,9 b'' | |||||
98 | url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip"; |
|
125 | url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip"; | |
99 | md5 = "654f75b302db6ed8dc5a898c625e030c"; |
|
126 | md5 = "654f75b302db6ed8dc5a898c625e030c"; | |
100 | }; |
|
127 | }; | |
|
128 | meta = { | |||
|
129 | license = [ pkgs.lib.licenses.gpl1 ]; | |||
|
130 | }; | |||
101 | }; |
|
131 | }; | |
102 | Paste = super.buildPythonPackage { |
|
132 | Paste = super.buildPythonPackage { | |
103 | name = "Paste-2.0.2"; |
|
133 | name = "Paste-2.0.2"; | |
@@ -108,6 +138,9 b'' | |||||
108 | url = "https://pypi.python.org/packages/d5/8d/0f8ac40687b97ff3e07ebd1369be20bdb3f93864d2dc3c2ff542edb4ce50/Paste-2.0.2.tar.gz"; |
|
138 | url = "https://pypi.python.org/packages/d5/8d/0f8ac40687b97ff3e07ebd1369be20bdb3f93864d2dc3c2ff542edb4ce50/Paste-2.0.2.tar.gz"; | |
109 | md5 = "4bfc8a7eaf858f6309d2ac0f40fc951c"; |
|
139 | md5 = "4bfc8a7eaf858f6309d2ac0f40fc951c"; | |
110 | }; |
|
140 | }; | |
|
141 | meta = { | |||
|
142 | license = [ pkgs.lib.licenses.mit ]; | |||
|
143 | }; | |||
111 | }; |
|
144 | }; | |
112 | PasteDeploy = super.buildPythonPackage { |
|
145 | PasteDeploy = super.buildPythonPackage { | |
113 | name = "PasteDeploy-1.5.2"; |
|
146 | name = "PasteDeploy-1.5.2"; | |
@@ -118,6 +151,9 b'' | |||||
118 | url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz"; |
|
151 | url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz"; | |
119 | md5 = "352b7205c78c8de4987578d19431af3b"; |
|
152 | md5 = "352b7205c78c8de4987578d19431af3b"; | |
120 | }; |
|
153 | }; | |
|
154 | meta = { | |||
|
155 | license = [ pkgs.lib.licenses.mit ]; | |||
|
156 | }; | |||
121 | }; |
|
157 | }; | |
122 | PasteScript = super.buildPythonPackage { |
|
158 | PasteScript = super.buildPythonPackage { | |
123 | name = "PasteScript-1.7.5"; |
|
159 | name = "PasteScript-1.7.5"; | |
@@ -128,6 +164,9 b'' | |||||
128 | url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz"; |
|
164 | url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz"; | |
129 | md5 = "4c72d78dcb6bb993f30536842c16af4d"; |
|
165 | md5 = "4c72d78dcb6bb993f30536842c16af4d"; | |
130 | }; |
|
166 | }; | |
|
167 | meta = { | |||
|
168 | license = [ pkgs.lib.licenses.mit ]; | |||
|
169 | }; | |||
131 | }; |
|
170 | }; | |
132 | Pygments = super.buildPythonPackage { |
|
171 | Pygments = super.buildPythonPackage { | |
133 | name = "Pygments-2.0.2"; |
|
172 | name = "Pygments-2.0.2"; | |
@@ -138,6 +177,9 b'' | |||||
138 | url = "https://pypi.python.org/packages/f4/c6/bdbc5a8a112256b2b6136af304dbae93d8b1ef8738ff2d12a51018800e46/Pygments-2.0.2.tar.gz"; |
|
177 | url = "https://pypi.python.org/packages/f4/c6/bdbc5a8a112256b2b6136af304dbae93d8b1ef8738ff2d12a51018800e46/Pygments-2.0.2.tar.gz"; | |
139 | md5 = "238587a1370d62405edabd0794b3ec4a"; |
|
178 | md5 = "238587a1370d62405edabd0794b3ec4a"; | |
140 | }; |
|
179 | }; | |
|
180 | meta = { | |||
|
181 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
182 | }; | |||
141 | }; |
|
183 | }; | |
142 | Pylons = super.buildPythonPackage { |
|
184 | Pylons = super.buildPythonPackage { | |
143 | name = "Pylons-1.0.1"; |
|
185 | name = "Pylons-1.0.1"; | |
@@ -148,6 +190,9 b'' | |||||
148 | url = "https://pypi.python.org/packages/a2/69/b835a6bad00acbfeed3f33c6e44fa3f936efc998c795bfb15c61a79ecf62/Pylons-1.0.1.tar.gz"; |
|
190 | url = "https://pypi.python.org/packages/a2/69/b835a6bad00acbfeed3f33c6e44fa3f936efc998c795bfb15c61a79ecf62/Pylons-1.0.1.tar.gz"; | |
149 | md5 = "6cb880d75fa81213192142b07a6e4915"; |
|
191 | md5 = "6cb880d75fa81213192142b07a6e4915"; | |
150 | }; |
|
192 | }; | |
|
193 | meta = { | |||
|
194 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
195 | }; | |||
151 | }; |
|
196 | }; | |
152 | Pyro4 = super.buildPythonPackage { |
|
197 | Pyro4 = super.buildPythonPackage { | |
153 | name = "Pyro4-4.41"; |
|
198 | name = "Pyro4-4.41"; | |
@@ -158,6 +203,9 b'' | |||||
158 | url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz"; |
|
203 | url = "https://pypi.python.org/packages/56/2b/89b566b4bf3e7f8ba790db2d1223852f8cb454c52cab7693dd41f608ca2a/Pyro4-4.41.tar.gz"; | |
159 | md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c"; |
|
204 | md5 = "ed69e9bfafa9c06c049a87cb0c4c2b6c"; | |
160 | }; |
|
205 | }; | |
|
206 | meta = { | |||
|
207 | license = [ pkgs.lib.licenses.mit ]; | |||
|
208 | }; | |||
161 | }; |
|
209 | }; | |
162 | Routes = super.buildPythonPackage { |
|
210 | Routes = super.buildPythonPackage { | |
163 | name = "Routes-1.13"; |
|
211 | name = "Routes-1.13"; | |
@@ -168,6 +216,9 b'' | |||||
168 | url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz"; |
|
216 | url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz"; | |
169 | md5 = "d527b0ab7dd9172b1275a41f97448783"; |
|
217 | md5 = "d527b0ab7dd9172b1275a41f97448783"; | |
170 | }; |
|
218 | }; | |
|
219 | meta = { | |||
|
220 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
221 | }; | |||
171 | }; |
|
222 | }; | |
172 | SQLAlchemy = super.buildPythonPackage { |
|
223 | SQLAlchemy = super.buildPythonPackage { | |
173 | name = "SQLAlchemy-0.9.9"; |
|
224 | name = "SQLAlchemy-0.9.9"; | |
@@ -178,6 +229,9 b'' | |||||
178 | url = "https://pypi.python.org/packages/28/f7/1bbfd0d8597e8c358d5e15a166a486ad82fc5579b4e67b6ef7c05b1d182b/SQLAlchemy-0.9.9.tar.gz"; |
|
229 | url = "https://pypi.python.org/packages/28/f7/1bbfd0d8597e8c358d5e15a166a486ad82fc5579b4e67b6ef7c05b1d182b/SQLAlchemy-0.9.9.tar.gz"; | |
179 | md5 = "8a10a9bd13ed3336ef7333ac2cc679ff"; |
|
230 | md5 = "8a10a9bd13ed3336ef7333ac2cc679ff"; | |
180 | }; |
|
231 | }; | |
|
232 | meta = { | |||
|
233 | license = [ pkgs.lib.licenses.mit ]; | |||
|
234 | }; | |||
181 | }; |
|
235 | }; | |
182 | Sphinx = super.buildPythonPackage { |
|
236 | Sphinx = super.buildPythonPackage { | |
183 | name = "Sphinx-1.2.2"; |
|
237 | name = "Sphinx-1.2.2"; | |
@@ -188,6 +242,9 b'' | |||||
188 | url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz"; |
|
242 | url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz"; | |
189 | md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4"; |
|
243 | md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4"; | |
190 | }; |
|
244 | }; | |
|
245 | meta = { | |||
|
246 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
247 | }; | |||
191 | }; |
|
248 | }; | |
192 | Tempita = super.buildPythonPackage { |
|
249 | Tempita = super.buildPythonPackage { | |
193 | name = "Tempita-0.5.2"; |
|
250 | name = "Tempita-0.5.2"; | |
@@ -198,6 +255,9 b'' | |||||
198 | url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz"; |
|
255 | url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz"; | |
199 | md5 = "4c2f17bb9d481821c41b6fbee904cea1"; |
|
256 | md5 = "4c2f17bb9d481821c41b6fbee904cea1"; | |
200 | }; |
|
257 | }; | |
|
258 | meta = { | |||
|
259 | license = [ pkgs.lib.licenses.mit ]; | |||
|
260 | }; | |||
201 | }; |
|
261 | }; | |
202 | URLObject = super.buildPythonPackage { |
|
262 | URLObject = super.buildPythonPackage { | |
203 | name = "URLObject-2.4.0"; |
|
263 | name = "URLObject-2.4.0"; | |
@@ -208,6 +268,9 b'' | |||||
208 | url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz"; |
|
268 | url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz"; | |
209 | md5 = "2ed819738a9f0a3051f31dc9924e3065"; |
|
269 | md5 = "2ed819738a9f0a3051f31dc9924e3065"; | |
210 | }; |
|
270 | }; | |
|
271 | meta = { | |||
|
272 | license = [ ]; | |||
|
273 | }; | |||
211 | }; |
|
274 | }; | |
212 | WebError = super.buildPythonPackage { |
|
275 | WebError = super.buildPythonPackage { | |
213 | name = "WebError-0.10.3"; |
|
276 | name = "WebError-0.10.3"; | |
@@ -218,6 +281,9 b'' | |||||
218 | url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz"; |
|
281 | url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz"; | |
219 | md5 = "84b9990b0baae6fd440b1e60cdd06f9a"; |
|
282 | md5 = "84b9990b0baae6fd440b1e60cdd06f9a"; | |
220 | }; |
|
283 | }; | |
|
284 | meta = { | |||
|
285 | license = [ pkgs.lib.licenses.mit ]; | |||
|
286 | }; | |||
221 | }; |
|
287 | }; | |
222 | WebHelpers = super.buildPythonPackage { |
|
288 | WebHelpers = super.buildPythonPackage { | |
223 | name = "WebHelpers-1.3"; |
|
289 | name = "WebHelpers-1.3"; | |
@@ -228,6 +294,9 b'' | |||||
228 | url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz"; |
|
294 | url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz"; | |
229 | md5 = "32749ffadfc40fea51075a7def32588b"; |
|
295 | md5 = "32749ffadfc40fea51075a7def32588b"; | |
230 | }; |
|
296 | }; | |
|
297 | meta = { | |||
|
298 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
299 | }; | |||
231 | }; |
|
300 | }; | |
232 | WebHelpers2 = super.buildPythonPackage { |
|
301 | WebHelpers2 = super.buildPythonPackage { | |
233 | name = "WebHelpers2-2.0"; |
|
302 | name = "WebHelpers2-2.0"; | |
@@ -238,6 +307,9 b'' | |||||
238 | url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz"; |
|
307 | url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz"; | |
239 | md5 = "0f6b68d70c12ee0aed48c00b24da13d3"; |
|
308 | md5 = "0f6b68d70c12ee0aed48c00b24da13d3"; | |
240 | }; |
|
309 | }; | |
|
310 | meta = { | |||
|
311 | license = [ pkgs.lib.licenses.mit ]; | |||
|
312 | }; | |||
241 | }; |
|
313 | }; | |
242 | WebOb = super.buildPythonPackage { |
|
314 | WebOb = super.buildPythonPackage { | |
243 | name = "WebOb-1.3.1"; |
|
315 | name = "WebOb-1.3.1"; | |
@@ -248,6 +320,9 b'' | |||||
248 | url = "https://pypi.python.org/packages/16/78/adfc0380b8a0d75b2d543fa7085ba98a573b1ae486d9def88d172b81b9fa/WebOb-1.3.1.tar.gz"; |
|
320 | url = "https://pypi.python.org/packages/16/78/adfc0380b8a0d75b2d543fa7085ba98a573b1ae486d9def88d172b81b9fa/WebOb-1.3.1.tar.gz"; | |
249 | md5 = "20918251c5726956ba8fef22d1556177"; |
|
321 | md5 = "20918251c5726956ba8fef22d1556177"; | |
250 | }; |
|
322 | }; | |
|
323 | meta = { | |||
|
324 | license = [ pkgs.lib.licenses.mit ]; | |||
|
325 | }; | |||
251 | }; |
|
326 | }; | |
252 | WebTest = super.buildPythonPackage { |
|
327 | WebTest = super.buildPythonPackage { | |
253 | name = "WebTest-1.4.3"; |
|
328 | name = "WebTest-1.4.3"; | |
@@ -258,6 +333,9 b'' | |||||
258 | url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip"; |
|
333 | url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip"; | |
259 | md5 = "631ce728bed92c681a4020a36adbc353"; |
|
334 | md5 = "631ce728bed92c681a4020a36adbc353"; | |
260 | }; |
|
335 | }; | |
|
336 | meta = { | |||
|
337 | license = [ pkgs.lib.licenses.mit ]; | |||
|
338 | }; | |||
261 | }; |
|
339 | }; | |
262 | Whoosh = super.buildPythonPackage { |
|
340 | Whoosh = super.buildPythonPackage { | |
263 | name = "Whoosh-2.7.0"; |
|
341 | name = "Whoosh-2.7.0"; | |
@@ -268,6 +346,9 b'' | |||||
268 | url = "https://pypi.python.org/packages/1c/dc/2f0231ff3875ded36df8c1ab851451e51a237dc0e5a86d3d96036158da94/Whoosh-2.7.0.zip"; |
|
346 | url = "https://pypi.python.org/packages/1c/dc/2f0231ff3875ded36df8c1ab851451e51a237dc0e5a86d3d96036158da94/Whoosh-2.7.0.zip"; | |
269 | md5 = "7abfd970f16fadc7311960f3fa0bc7a9"; |
|
347 | md5 = "7abfd970f16fadc7311960f3fa0bc7a9"; | |
270 | }; |
|
348 | }; | |
|
349 | meta = { | |||
|
350 | license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ]; | |||
|
351 | }; | |||
271 | }; |
|
352 | }; | |
272 | alembic = super.buildPythonPackage { |
|
353 | alembic = super.buildPythonPackage { | |
273 | name = "alembic-0.8.4"; |
|
354 | name = "alembic-0.8.4"; | |
@@ -278,6 +359,9 b'' | |||||
278 | url = "https://pypi.python.org/packages/ca/7e/299b4499b5c75e5a38c5845145ad24755bebfb8eec07a2e1c366b7181eeb/alembic-0.8.4.tar.gz"; |
|
359 | url = "https://pypi.python.org/packages/ca/7e/299b4499b5c75e5a38c5845145ad24755bebfb8eec07a2e1c366b7181eeb/alembic-0.8.4.tar.gz"; | |
279 | md5 = "5f95d8ee62b443f9b37eb5bee76c582d"; |
|
360 | md5 = "5f95d8ee62b443f9b37eb5bee76c582d"; | |
280 | }; |
|
361 | }; | |
|
362 | meta = { | |||
|
363 | license = [ pkgs.lib.licenses.mit ]; | |||
|
364 | }; | |||
281 | }; |
|
365 | }; | |
282 | amqplib = super.buildPythonPackage { |
|
366 | amqplib = super.buildPythonPackage { | |
283 | name = "amqplib-1.0.2"; |
|
367 | name = "amqplib-1.0.2"; | |
@@ -288,6 +372,9 b'' | |||||
288 | url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz"; |
|
372 | url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz"; | |
289 | md5 = "5c92f17fbedd99b2b4a836d4352d1e2f"; |
|
373 | md5 = "5c92f17fbedd99b2b4a836d4352d1e2f"; | |
290 | }; |
|
374 | }; | |
|
375 | meta = { | |||
|
376 | license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; | |||
|
377 | }; | |||
291 | }; |
|
378 | }; | |
292 | anyjson = super.buildPythonPackage { |
|
379 | anyjson = super.buildPythonPackage { | |
293 | name = "anyjson-0.3.3"; |
|
380 | name = "anyjson-0.3.3"; | |
@@ -298,6 +385,9 b'' | |||||
298 | url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz"; |
|
385 | url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz"; | |
299 | md5 = "2ea28d6ec311aeeebaf993cb3008b27c"; |
|
386 | md5 = "2ea28d6ec311aeeebaf993cb3008b27c"; | |
300 | }; |
|
387 | }; | |
|
388 | meta = { | |||
|
389 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
390 | }; | |||
301 | }; |
|
391 | }; | |
302 | appenlight-client = super.buildPythonPackage { |
|
392 | appenlight-client = super.buildPythonPackage { | |
303 | name = "appenlight-client-0.6.14"; |
|
393 | name = "appenlight-client-0.6.14"; | |
@@ -308,6 +398,9 b'' | |||||
308 | url = "https://pypi.python.org/packages/4d/e0/23fee3ebada8143f707e65c06bcb82992040ee64ea8355e044ed55ebf0c1/appenlight_client-0.6.14.tar.gz"; |
|
398 | url = "https://pypi.python.org/packages/4d/e0/23fee3ebada8143f707e65c06bcb82992040ee64ea8355e044ed55ebf0c1/appenlight_client-0.6.14.tar.gz"; | |
309 | md5 = "578c69b09f4356d898fff1199b98a95c"; |
|
399 | md5 = "578c69b09f4356d898fff1199b98a95c"; | |
310 | }; |
|
400 | }; | |
|
401 | meta = { | |||
|
402 | license = [ pkgs.lib.licenses.bsdOriginal { fullName = "DFSG approved"; } ]; | |||
|
403 | }; | |||
311 | }; |
|
404 | }; | |
312 | authomatic = super.buildPythonPackage { |
|
405 | authomatic = super.buildPythonPackage { | |
313 | name = "authomatic-0.1.0.post1"; |
|
406 | name = "authomatic-0.1.0.post1"; | |
@@ -318,6 +411,9 b'' | |||||
318 | url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz"; |
|
411 | url = "https://pypi.python.org/packages/08/1a/8a930461e604c2d5a7a871e1ac59fa82ccf994c32e807230c8d2fb07815a/Authomatic-0.1.0.post1.tar.gz"; | |
319 | md5 = "be3f3ce08747d776aae6d6cc8dcb49a9"; |
|
412 | md5 = "be3f3ce08747d776aae6d6cc8dcb49a9"; | |
320 | }; |
|
413 | }; | |
|
414 | meta = { | |||
|
415 | license = [ pkgs.lib.licenses.mit ]; | |||
|
416 | }; | |||
321 | }; |
|
417 | }; | |
322 | backport-ipaddress = super.buildPythonPackage { |
|
418 | backport-ipaddress = super.buildPythonPackage { | |
323 | name = "backport-ipaddress-0.1"; |
|
419 | name = "backport-ipaddress-0.1"; | |
@@ -328,6 +424,9 b'' | |||||
328 | url = "https://pypi.python.org/packages/d3/30/54c6dab05a4dec44db25ff309f1fbb6b7a8bde3f2bade38bb9da67bbab8f/backport_ipaddress-0.1.tar.gz"; |
|
424 | url = "https://pypi.python.org/packages/d3/30/54c6dab05a4dec44db25ff309f1fbb6b7a8bde3f2bade38bb9da67bbab8f/backport_ipaddress-0.1.tar.gz"; | |
329 | md5 = "9c1f45f4361f71b124d7293a60006c05"; |
|
425 | md5 = "9c1f45f4361f71b124d7293a60006c05"; | |
330 | }; |
|
426 | }; | |
|
427 | meta = { | |||
|
428 | license = [ pkgs.lib.licenses.psfl ]; | |||
|
429 | }; | |||
331 | }; |
|
430 | }; | |
332 | bottle = super.buildPythonPackage { |
|
431 | bottle = super.buildPythonPackage { | |
333 | name = "bottle-0.12.8"; |
|
432 | name = "bottle-0.12.8"; | |
@@ -338,6 +437,9 b'' | |||||
338 | url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz"; |
|
437 | url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz"; | |
339 | md5 = "13132c0a8f607bf860810a6ee9064c5b"; |
|
438 | md5 = "13132c0a8f607bf860810a6ee9064c5b"; | |
340 | }; |
|
439 | }; | |
|
440 | meta = { | |||
|
441 | license = [ pkgs.lib.licenses.mit ]; | |||
|
442 | }; | |||
341 | }; |
|
443 | }; | |
342 | bumpversion = super.buildPythonPackage { |
|
444 | bumpversion = super.buildPythonPackage { | |
343 | name = "bumpversion-0.5.3"; |
|
445 | name = "bumpversion-0.5.3"; | |
@@ -348,6 +450,9 b'' | |||||
348 | url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz"; |
|
450 | url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz"; | |
349 | md5 = "c66a3492eafcf5ad4b024be9fca29820"; |
|
451 | md5 = "c66a3492eafcf5ad4b024be9fca29820"; | |
350 | }; |
|
452 | }; | |
|
453 | meta = { | |||
|
454 | license = [ pkgs.lib.licenses.mit ]; | |||
|
455 | }; | |||
351 | }; |
|
456 | }; | |
352 | celery = super.buildPythonPackage { |
|
457 | celery = super.buildPythonPackage { | |
353 | name = "celery-2.2.10"; |
|
458 | name = "celery-2.2.10"; | |
@@ -358,6 +463,9 b'' | |||||
358 | url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz"; |
|
463 | url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz"; | |
359 | md5 = "898bc87e54f278055b561316ba73e222"; |
|
464 | md5 = "898bc87e54f278055b561316ba73e222"; | |
360 | }; |
|
465 | }; | |
|
466 | meta = { | |||
|
467 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
468 | }; | |||
361 | }; |
|
469 | }; | |
362 | click = super.buildPythonPackage { |
|
470 | click = super.buildPythonPackage { | |
363 | name = "click-5.1"; |
|
471 | name = "click-5.1"; | |
@@ -368,6 +476,9 b'' | |||||
368 | url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz"; |
|
476 | url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz"; | |
369 | md5 = "9c5323008cccfe232a8b161fc8196d41"; |
|
477 | md5 = "9c5323008cccfe232a8b161fc8196d41"; | |
370 | }; |
|
478 | }; | |
|
479 | meta = { | |||
|
480 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
481 | }; | |||
371 | }; |
|
482 | }; | |
372 | colander = super.buildPythonPackage { |
|
483 | colander = super.buildPythonPackage { | |
373 | name = "colander-1.2"; |
|
484 | name = "colander-1.2"; | |
@@ -378,6 +489,9 b'' | |||||
378 | url = "https://pypi.python.org/packages/14/23/c9ceba07a6a1dc0eefbb215fc0dc64aabc2b22ee756bc0f0c13278fa0887/colander-1.2.tar.gz"; |
|
489 | url = "https://pypi.python.org/packages/14/23/c9ceba07a6a1dc0eefbb215fc0dc64aabc2b22ee756bc0f0c13278fa0887/colander-1.2.tar.gz"; | |
379 | md5 = "83db21b07936a0726e588dae1914b9ed"; |
|
490 | md5 = "83db21b07936a0726e588dae1914b9ed"; | |
380 | }; |
|
491 | }; | |
|
492 | meta = { | |||
|
493 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
494 | }; | |||
381 | }; |
|
495 | }; | |
382 | configobj = super.buildPythonPackage { |
|
496 | configobj = super.buildPythonPackage { | |
383 | name = "configobj-5.0.6"; |
|
497 | name = "configobj-5.0.6"; | |
@@ -388,6 +502,9 b'' | |||||
388 | url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz"; |
|
502 | url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz"; | |
389 | md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6"; |
|
503 | md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6"; | |
390 | }; |
|
504 | }; | |
|
505 | meta = { | |||
|
506 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
507 | }; | |||
391 | }; |
|
508 | }; | |
392 | cov-core = super.buildPythonPackage { |
|
509 | cov-core = super.buildPythonPackage { | |
393 | name = "cov-core-1.15.0"; |
|
510 | name = "cov-core-1.15.0"; | |
@@ -398,6 +515,9 b'' | |||||
398 | url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz"; |
|
515 | url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz"; | |
399 | md5 = "f519d4cb4c4e52856afb14af52919fe6"; |
|
516 | md5 = "f519d4cb4c4e52856afb14af52919fe6"; | |
400 | }; |
|
517 | }; | |
|
518 | meta = { | |||
|
519 | license = [ pkgs.lib.licenses.mit ]; | |||
|
520 | }; | |||
401 | }; |
|
521 | }; | |
402 | coverage = super.buildPythonPackage { |
|
522 | coverage = super.buildPythonPackage { | |
403 | name = "coverage-3.7.1"; |
|
523 | name = "coverage-3.7.1"; | |
@@ -408,6 +528,9 b'' | |||||
408 | url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz"; |
|
528 | url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz"; | |
409 | md5 = "c47b36ceb17eaff3ecfab3bcd347d0df"; |
|
529 | md5 = "c47b36ceb17eaff3ecfab3bcd347d0df"; | |
410 | }; |
|
530 | }; | |
|
531 | meta = { | |||
|
532 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
533 | }; | |||
411 | }; |
|
534 | }; | |
412 | cssselect = super.buildPythonPackage { |
|
535 | cssselect = super.buildPythonPackage { | |
413 | name = "cssselect-0.9.1"; |
|
536 | name = "cssselect-0.9.1"; | |
@@ -418,6 +541,9 b'' | |||||
418 | url = "https://pypi.python.org/packages/aa/e5/9ee1460d485b94a6d55732eb7ad5b6c084caf73dd6f9cb0bb7d2a78fafe8/cssselect-0.9.1.tar.gz"; |
|
541 | url = "https://pypi.python.org/packages/aa/e5/9ee1460d485b94a6d55732eb7ad5b6c084caf73dd6f9cb0bb7d2a78fafe8/cssselect-0.9.1.tar.gz"; | |
419 | md5 = "c74f45966277dc7a0f768b9b0f3522ac"; |
|
542 | md5 = "c74f45966277dc7a0f768b9b0f3522ac"; | |
420 | }; |
|
543 | }; | |
|
544 | meta = { | |||
|
545 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
546 | }; | |||
421 | }; |
|
547 | }; | |
422 | decorator = super.buildPythonPackage { |
|
548 | decorator = super.buildPythonPackage { | |
423 | name = "decorator-3.4.2"; |
|
549 | name = "decorator-3.4.2"; | |
@@ -428,6 +554,9 b'' | |||||
428 | url = "https://pypi.python.org/packages/35/3a/42566eb7a2cbac774399871af04e11d7ae3fc2579e7dae85213b8d1d1c57/decorator-3.4.2.tar.gz"; |
|
554 | url = "https://pypi.python.org/packages/35/3a/42566eb7a2cbac774399871af04e11d7ae3fc2579e7dae85213b8d1d1c57/decorator-3.4.2.tar.gz"; | |
429 | md5 = "9e0536870d2b83ae27d58dbf22582f4d"; |
|
555 | md5 = "9e0536870d2b83ae27d58dbf22582f4d"; | |
430 | }; |
|
556 | }; | |
|
557 | meta = { | |||
|
558 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
559 | }; | |||
431 | }; |
|
560 | }; | |
432 | docutils = super.buildPythonPackage { |
|
561 | docutils = super.buildPythonPackage { | |
433 | name = "docutils-0.12"; |
|
562 | name = "docutils-0.12"; | |
@@ -438,6 +567,9 b'' | |||||
438 | url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz"; |
|
567 | url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz"; | |
439 | md5 = "4622263b62c5c771c03502afa3157768"; |
|
568 | md5 = "4622263b62c5c771c03502afa3157768"; | |
440 | }; |
|
569 | }; | |
|
570 | meta = { | |||
|
571 | license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.publicDomain pkgs.lib.licenses.gpl1 { fullName = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; } pkgs.lib.licenses.psfl ]; | |||
|
572 | }; | |||
441 | }; |
|
573 | }; | |
442 | dogpile.cache = super.buildPythonPackage { |
|
574 | dogpile.cache = super.buildPythonPackage { | |
443 | name = "dogpile.cache-0.5.7"; |
|
575 | name = "dogpile.cache-0.5.7"; | |
@@ -448,6 +580,9 b'' | |||||
448 | url = "https://pypi.python.org/packages/07/74/2a83bedf758156d9c95d112691bbad870d3b77ccbcfb781b4ef836ea7d96/dogpile.cache-0.5.7.tar.gz"; |
|
580 | url = "https://pypi.python.org/packages/07/74/2a83bedf758156d9c95d112691bbad870d3b77ccbcfb781b4ef836ea7d96/dogpile.cache-0.5.7.tar.gz"; | |
449 | md5 = "3e58ce41af574aab41d78e9c4190f194"; |
|
581 | md5 = "3e58ce41af574aab41d78e9c4190f194"; | |
450 | }; |
|
582 | }; | |
|
583 | meta = { | |||
|
584 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
585 | }; | |||
451 | }; |
|
586 | }; | |
452 | dogpile.core = super.buildPythonPackage { |
|
587 | dogpile.core = super.buildPythonPackage { | |
453 | name = "dogpile.core-0.4.1"; |
|
588 | name = "dogpile.core-0.4.1"; | |
@@ -458,6 +593,9 b'' | |||||
458 | url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz"; |
|
593 | url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz"; | |
459 | md5 = "01cb19f52bba3e95c9b560f39341f045"; |
|
594 | md5 = "01cb19f52bba3e95c9b560f39341f045"; | |
460 | }; |
|
595 | }; | |
|
596 | meta = { | |||
|
597 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
598 | }; | |||
461 | }; |
|
599 | }; | |
462 | dulwich = super.buildPythonPackage { |
|
600 | dulwich = super.buildPythonPackage { | |
463 | name = "dulwich-0.12.0"; |
|
601 | name = "dulwich-0.12.0"; | |
@@ -468,6 +606,9 b'' | |||||
468 | url = "https://pypi.python.org/packages/6f/04/fbe561b6d45c0ec758330d5b7f5ba4b6cb4f1ca1ab49859d2fc16320da75/dulwich-0.12.0.tar.gz"; |
|
606 | url = "https://pypi.python.org/packages/6f/04/fbe561b6d45c0ec758330d5b7f5ba4b6cb4f1ca1ab49859d2fc16320da75/dulwich-0.12.0.tar.gz"; | |
469 | md5 = "f3a8a12bd9f9dd8c233e18f3d49436fa"; |
|
607 | md5 = "f3a8a12bd9f9dd8c233e18f3d49436fa"; | |
470 | }; |
|
608 | }; | |
|
609 | meta = { | |||
|
610 | license = [ pkgs.lib.licenses.gpl2Plus ]; | |||
|
611 | }; | |||
471 | }; |
|
612 | }; | |
472 | ecdsa = super.buildPythonPackage { |
|
613 | ecdsa = super.buildPythonPackage { | |
473 | name = "ecdsa-0.11"; |
|
614 | name = "ecdsa-0.11"; | |
@@ -478,6 +619,9 b'' | |||||
478 | url = "https://pypi.python.org/packages/6c/3f/92fe5dcdcaa7bd117be21e5520c9a54375112b66ec000d209e9e9519fad1/ecdsa-0.11.tar.gz"; |
|
619 | url = "https://pypi.python.org/packages/6c/3f/92fe5dcdcaa7bd117be21e5520c9a54375112b66ec000d209e9e9519fad1/ecdsa-0.11.tar.gz"; | |
479 | md5 = "8ef586fe4dbb156697d756900cb41d7c"; |
|
620 | md5 = "8ef586fe4dbb156697d756900cb41d7c"; | |
480 | }; |
|
621 | }; | |
|
622 | meta = { | |||
|
623 | license = [ pkgs.lib.licenses.mit ]; | |||
|
624 | }; | |||
481 | }; |
|
625 | }; | |
482 | elasticsearch = super.buildPythonPackage { |
|
626 | elasticsearch = super.buildPythonPackage { | |
483 | name = "elasticsearch-2.3.0"; |
|
627 | name = "elasticsearch-2.3.0"; | |
@@ -488,6 +632,9 b'' | |||||
488 | url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz"; |
|
632 | url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz"; | |
489 | md5 = "2550f3b51629cf1ef9636608af92c340"; |
|
633 | md5 = "2550f3b51629cf1ef9636608af92c340"; | |
490 | }; |
|
634 | }; | |
|
635 | meta = { | |||
|
636 | license = [ pkgs.lib.licenses.asl20 ]; | |||
|
637 | }; | |||
491 | }; |
|
638 | }; | |
492 | elasticsearch-dsl = super.buildPythonPackage { |
|
639 | elasticsearch-dsl = super.buildPythonPackage { | |
493 | name = "elasticsearch-dsl-2.0.0"; |
|
640 | name = "elasticsearch-dsl-2.0.0"; | |
@@ -498,6 +645,9 b'' | |||||
498 | url = "https://pypi.python.org/packages/4e/5d/e788ae8dbe2ff4d13426db0a027533386a5c276c77a2654dc0e2007ce04a/elasticsearch-dsl-2.0.0.tar.gz"; |
|
645 | url = "https://pypi.python.org/packages/4e/5d/e788ae8dbe2ff4d13426db0a027533386a5c276c77a2654dc0e2007ce04a/elasticsearch-dsl-2.0.0.tar.gz"; | |
499 | md5 = "4cdfec81bb35383dd3b7d02d7dc5ee68"; |
|
646 | md5 = "4cdfec81bb35383dd3b7d02d7dc5ee68"; | |
500 | }; |
|
647 | }; | |
|
648 | meta = { | |||
|
649 | license = [ pkgs.lib.licenses.asl20 ]; | |||
|
650 | }; | |||
501 | }; |
|
651 | }; | |
502 | flake8 = super.buildPythonPackage { |
|
652 | flake8 = super.buildPythonPackage { | |
503 | name = "flake8-2.4.1"; |
|
653 | name = "flake8-2.4.1"; | |
@@ -508,6 +658,9 b'' | |||||
508 | url = "https://pypi.python.org/packages/8f/b5/9a73c66c7dba273bac8758398f060c008a25f3e84531063b42503b5d0a95/flake8-2.4.1.tar.gz"; |
|
658 | url = "https://pypi.python.org/packages/8f/b5/9a73c66c7dba273bac8758398f060c008a25f3e84531063b42503b5d0a95/flake8-2.4.1.tar.gz"; | |
509 | md5 = "ed45d3db81a3b7c88bd63c6e37ca1d65"; |
|
659 | md5 = "ed45d3db81a3b7c88bd63c6e37ca1d65"; | |
510 | }; |
|
660 | }; | |
|
661 | meta = { | |||
|
662 | license = [ pkgs.lib.licenses.mit ]; | |||
|
663 | }; | |||
511 | }; |
|
664 | }; | |
512 | future = super.buildPythonPackage { |
|
665 | future = super.buildPythonPackage { | |
513 | name = "future-0.14.3"; |
|
666 | name = "future-0.14.3"; | |
@@ -518,6 +671,9 b'' | |||||
518 | url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz"; |
|
671 | url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz"; | |
519 | md5 = "e94079b0bd1fc054929e8769fc0f6083"; |
|
672 | md5 = "e94079b0bd1fc054929e8769fc0f6083"; | |
520 | }; |
|
673 | }; | |
|
674 | meta = { | |||
|
675 | license = [ { fullName = "OSI Approved"; } pkgs.lib.licenses.mit ]; | |||
|
676 | }; | |||
521 | }; |
|
677 | }; | |
522 | futures = super.buildPythonPackage { |
|
678 | futures = super.buildPythonPackage { | |
523 | name = "futures-3.0.2"; |
|
679 | name = "futures-3.0.2"; | |
@@ -528,6 +684,9 b'' | |||||
528 | url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz"; |
|
684 | url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz"; | |
529 | md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a"; |
|
685 | md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a"; | |
530 | }; |
|
686 | }; | |
|
687 | meta = { | |||
|
688 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
689 | }; | |||
531 | }; |
|
690 | }; | |
532 | gnureadline = super.buildPythonPackage { |
|
691 | gnureadline = super.buildPythonPackage { | |
533 | name = "gnureadline-6.3.3"; |
|
692 | name = "gnureadline-6.3.3"; | |
@@ -538,9 +697,12 b'' | |||||
538 | url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz"; |
|
697 | url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz"; | |
539 | md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c"; |
|
698 | md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c"; | |
540 | }; |
|
699 | }; | |
|
700 | meta = { | |||
|
701 | license = [ pkgs.lib.licenses.gpl1 ]; | |||
|
702 | }; | |||
541 | }; |
|
703 | }; | |
542 | gprof2dot = super.buildPythonPackage { |
|
704 | gprof2dot = super.buildPythonPackage { | |
543 |
name = "gprof2dot-2015.12. |
|
705 | name = "gprof2dot-2015.12.1"; | |
544 | buildInputs = with self; []; |
|
706 | buildInputs = with self; []; | |
545 | doCheck = false; |
|
707 | doCheck = false; | |
546 | propagatedBuildInputs = with self; []; |
|
708 | propagatedBuildInputs = with self; []; | |
@@ -548,6 +710,9 b'' | |||||
548 | url = "https://pypi.python.org/packages/b9/34/7bf93c1952d40fa5c95ad963f4d8344b61ef58558632402eca18e6c14127/gprof2dot-2015.12.1.tar.gz"; |
|
710 | url = "https://pypi.python.org/packages/b9/34/7bf93c1952d40fa5c95ad963f4d8344b61ef58558632402eca18e6c14127/gprof2dot-2015.12.1.tar.gz"; | |
549 | md5 = "e23bf4e2f94db032750c193384b4165b"; |
|
711 | md5 = "e23bf4e2f94db032750c193384b4165b"; | |
550 | }; |
|
712 | }; | |
|
713 | meta = { | |||
|
714 | license = [ { fullName = "LGPL"; } ]; | |||
|
715 | }; | |||
551 | }; |
|
716 | }; | |
552 | greenlet = super.buildPythonPackage { |
|
717 | greenlet = super.buildPythonPackage { | |
553 | name = "greenlet-0.4.9"; |
|
718 | name = "greenlet-0.4.9"; | |
@@ -558,6 +723,9 b'' | |||||
558 | url = "https://pypi.python.org/packages/4e/3d/9d421539b74e33608b245092870156b2e171fb49f2b51390aa4641eecb4a/greenlet-0.4.9.zip"; |
|
723 | url = "https://pypi.python.org/packages/4e/3d/9d421539b74e33608b245092870156b2e171fb49f2b51390aa4641eecb4a/greenlet-0.4.9.zip"; | |
559 | md5 = "c6659cdb2a5e591723e629d2eef22e82"; |
|
724 | md5 = "c6659cdb2a5e591723e629d2eef22e82"; | |
560 | }; |
|
725 | }; | |
|
726 | meta = { | |||
|
727 | license = [ pkgs.lib.licenses.mit ]; | |||
|
728 | }; | |||
561 | }; |
|
729 | }; | |
562 | gunicorn = super.buildPythonPackage { |
|
730 | gunicorn = super.buildPythonPackage { | |
563 | name = "gunicorn-19.6.0"; |
|
731 | name = "gunicorn-19.6.0"; | |
@@ -568,6 +736,9 b'' | |||||
568 | url = "https://pypi.python.org/packages/84/ce/7ea5396efad1cef682bbc4068e72a0276341d9d9d0f501da609fab9fcb80/gunicorn-19.6.0.tar.gz"; |
|
736 | url = "https://pypi.python.org/packages/84/ce/7ea5396efad1cef682bbc4068e72a0276341d9d9d0f501da609fab9fcb80/gunicorn-19.6.0.tar.gz"; | |
569 | md5 = "338e5e8a83ea0f0625f768dba4597530"; |
|
737 | md5 = "338e5e8a83ea0f0625f768dba4597530"; | |
570 | }; |
|
738 | }; | |
|
739 | meta = { | |||
|
740 | license = [ pkgs.lib.licenses.mit ]; | |||
|
741 | }; | |||
571 | }; |
|
742 | }; | |
572 | infrae.cache = super.buildPythonPackage { |
|
743 | infrae.cache = super.buildPythonPackage { | |
573 | name = "infrae.cache-1.0.1"; |
|
744 | name = "infrae.cache-1.0.1"; | |
@@ -578,15 +749,21 b'' | |||||
578 | url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz"; |
|
749 | url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz"; | |
579 | md5 = "b09076a766747e6ed2a755cc62088e32"; |
|
750 | md5 = "b09076a766747e6ed2a755cc62088e32"; | |
580 | }; |
|
751 | }; | |
|
752 | meta = { | |||
|
753 | license = [ pkgs.lib.licenses.zpt21 ]; | |||
|
754 | }; | |||
581 | }; |
|
755 | }; | |
582 | invoke = super.buildPythonPackage { |
|
756 | invoke = super.buildPythonPackage { | |
583 |
name = "invoke-0.1 |
|
757 | name = "invoke-0.13.0"; | |
584 | buildInputs = with self; []; |
|
758 | buildInputs = with self; []; | |
585 | doCheck = false; |
|
759 | doCheck = false; | |
586 | propagatedBuildInputs = with self; []; |
|
760 | propagatedBuildInputs = with self; []; | |
587 | src = fetchurl { |
|
761 | src = fetchurl { | |
588 | url = "https://pypi.python.org/packages/d3/bb/36a5558ea19882073def7b0edeef4a0e6282056fed96506dd10b1d532bd4/invoke-0.11.1.tar.gz"; |
|
762 | url = "https://pypi.python.org/packages/47/bf/d07ef52fa1ac645468858bbac7cb95b246a972a045e821493d17d89c81be/invoke-0.13.0.tar.gz"; | |
589 | md5 = "3d4ecbe26779ceef1046ecf702c9c4a8"; |
|
763 | md5 = "c0d1ed4bfb34eaab551662d8cfee6540"; | |
|
764 | }; | |||
|
765 | meta = { | |||
|
766 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
590 | }; |
|
767 | }; | |
591 | }; |
|
768 | }; | |
592 | ipdb = super.buildPythonPackage { |
|
769 | ipdb = super.buildPythonPackage { | |
@@ -598,6 +775,9 b'' | |||||
598 | url = "https://pypi.python.org/packages/f0/25/d7dd430ced6cd8dc242a933c8682b5dbf32eb4011d82f87e34209e5ec845/ipdb-0.8.zip"; |
|
775 | url = "https://pypi.python.org/packages/f0/25/d7dd430ced6cd8dc242a933c8682b5dbf32eb4011d82f87e34209e5ec845/ipdb-0.8.zip"; | |
599 | md5 = "96dca0712efa01aa5eaf6b22071dd3ed"; |
|
776 | md5 = "96dca0712efa01aa5eaf6b22071dd3ed"; | |
600 | }; |
|
777 | }; | |
|
778 | meta = { | |||
|
779 | license = [ pkgs.lib.licenses.gpl1 ]; | |||
|
780 | }; | |||
601 | }; |
|
781 | }; | |
602 | ipython = super.buildPythonPackage { |
|
782 | ipython = super.buildPythonPackage { | |
603 | name = "ipython-3.1.0"; |
|
783 | name = "ipython-3.1.0"; | |
@@ -608,6 +788,9 b'' | |||||
608 | url = "https://pypi.python.org/packages/06/91/120c0835254c120af89f066afaabf81289bc2726c1fc3ca0555df6882f58/ipython-3.1.0.tar.gz"; |
|
788 | url = "https://pypi.python.org/packages/06/91/120c0835254c120af89f066afaabf81289bc2726c1fc3ca0555df6882f58/ipython-3.1.0.tar.gz"; | |
609 | md5 = "a749d90c16068687b0ec45a27e72ef8f"; |
|
789 | md5 = "a749d90c16068687b0ec45a27e72ef8f"; | |
610 | }; |
|
790 | }; | |
|
791 | meta = { | |||
|
792 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
793 | }; | |||
611 | }; |
|
794 | }; | |
612 | iso8601 = super.buildPythonPackage { |
|
795 | iso8601 = super.buildPythonPackage { | |
613 | name = "iso8601-0.1.11"; |
|
796 | name = "iso8601-0.1.11"; | |
@@ -618,6 +801,9 b'' | |||||
618 | url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz"; |
|
801 | url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz"; | |
619 | md5 = "b06d11cd14a64096f907086044f0fe38"; |
|
802 | md5 = "b06d11cd14a64096f907086044f0fe38"; | |
620 | }; |
|
803 | }; | |
|
804 | meta = { | |||
|
805 | license = [ pkgs.lib.licenses.mit ]; | |||
|
806 | }; | |||
621 | }; |
|
807 | }; | |
622 | itsdangerous = super.buildPythonPackage { |
|
808 | itsdangerous = super.buildPythonPackage { | |
623 | name = "itsdangerous-0.24"; |
|
809 | name = "itsdangerous-0.24"; | |
@@ -628,6 +814,9 b'' | |||||
628 | url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz"; |
|
814 | url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz"; | |
629 | md5 = "a3d55aa79369aef5345c036a8a26307f"; |
|
815 | md5 = "a3d55aa79369aef5345c036a8a26307f"; | |
630 | }; |
|
816 | }; | |
|
817 | meta = { | |||
|
818 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
819 | }; | |||
631 | }; |
|
820 | }; | |
632 | kombu = super.buildPythonPackage { |
|
821 | kombu = super.buildPythonPackage { | |
633 | name = "kombu-1.5.1"; |
|
822 | name = "kombu-1.5.1"; | |
@@ -638,6 +827,9 b'' | |||||
638 | url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz"; |
|
827 | url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz"; | |
639 | md5 = "50662f3c7e9395b3d0721fb75d100b63"; |
|
828 | md5 = "50662f3c7e9395b3d0721fb75d100b63"; | |
640 | }; |
|
829 | }; | |
|
830 | meta = { | |||
|
831 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
832 | }; | |||
641 | }; |
|
833 | }; | |
642 | lxml = super.buildPythonPackage { |
|
834 | lxml = super.buildPythonPackage { | |
643 | name = "lxml-3.4.4"; |
|
835 | name = "lxml-3.4.4"; | |
@@ -648,6 +840,9 b'' | |||||
648 | url = "https://pypi.python.org/packages/63/c7/4f2a2a4ad6c6fa99b14be6b3c1cece9142e2d915aa7c43c908677afc8fa4/lxml-3.4.4.tar.gz"; |
|
840 | url = "https://pypi.python.org/packages/63/c7/4f2a2a4ad6c6fa99b14be6b3c1cece9142e2d915aa7c43c908677afc8fa4/lxml-3.4.4.tar.gz"; | |
649 | md5 = "a9a65972afc173ec7a39c585f4eea69c"; |
|
841 | md5 = "a9a65972afc173ec7a39c585f4eea69c"; | |
650 | }; |
|
842 | }; | |
|
843 | meta = { | |||
|
844 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
845 | }; | |||
651 | }; |
|
846 | }; | |
652 | mccabe = super.buildPythonPackage { |
|
847 | mccabe = super.buildPythonPackage { | |
653 | name = "mccabe-0.3"; |
|
848 | name = "mccabe-0.3"; | |
@@ -658,6 +853,9 b'' | |||||
658 | url = "https://pypi.python.org/packages/c9/2e/75231479e11a906b64ac43bad9d0bb534d00080b18bdca8db9da46e1faf7/mccabe-0.3.tar.gz"; |
|
853 | url = "https://pypi.python.org/packages/c9/2e/75231479e11a906b64ac43bad9d0bb534d00080b18bdca8db9da46e1faf7/mccabe-0.3.tar.gz"; | |
659 | md5 = "81640948ff226f8c12b3277059489157"; |
|
854 | md5 = "81640948ff226f8c12b3277059489157"; | |
660 | }; |
|
855 | }; | |
|
856 | meta = { | |||
|
857 | license = [ { fullName = "Expat license"; } pkgs.lib.licenses.mit ]; | |||
|
858 | }; | |||
661 | }; |
|
859 | }; | |
662 | meld3 = super.buildPythonPackage { |
|
860 | meld3 = super.buildPythonPackage { | |
663 | name = "meld3-1.0.2"; |
|
861 | name = "meld3-1.0.2"; | |
@@ -668,6 +866,9 b'' | |||||
668 | url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz"; |
|
866 | url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz"; | |
669 | md5 = "3ccc78cd79cffd63a751ad7684c02c91"; |
|
867 | md5 = "3ccc78cd79cffd63a751ad7684c02c91"; | |
670 | }; |
|
868 | }; | |
|
869 | meta = { | |||
|
870 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
871 | }; | |||
671 | }; |
|
872 | }; | |
672 | mock = super.buildPythonPackage { |
|
873 | mock = super.buildPythonPackage { | |
673 | name = "mock-1.0.1"; |
|
874 | name = "mock-1.0.1"; | |
@@ -678,6 +879,9 b'' | |||||
678 | url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip"; |
|
879 | url = "https://pypi.python.org/packages/15/45/30273ee91feb60dabb8fbb2da7868520525f02cf910279b3047182feed80/mock-1.0.1.zip"; | |
679 | md5 = "869f08d003c289a97c1a6610faf5e913"; |
|
880 | md5 = "869f08d003c289a97c1a6610faf5e913"; | |
680 | }; |
|
881 | }; | |
|
882 | meta = { | |||
|
883 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
884 | }; | |||
681 | }; |
|
885 | }; | |
682 | msgpack-python = super.buildPythonPackage { |
|
886 | msgpack-python = super.buildPythonPackage { | |
683 | name = "msgpack-python-0.4.6"; |
|
887 | name = "msgpack-python-0.4.6"; | |
@@ -688,6 +892,9 b'' | |||||
688 | url = "https://pypi.python.org/packages/15/ce/ff2840885789ef8035f66cd506ea05bdb228340307d5e71a7b1e3f82224c/msgpack-python-0.4.6.tar.gz"; |
|
892 | url = "https://pypi.python.org/packages/15/ce/ff2840885789ef8035f66cd506ea05bdb228340307d5e71a7b1e3f82224c/msgpack-python-0.4.6.tar.gz"; | |
689 | md5 = "8b317669314cf1bc881716cccdaccb30"; |
|
893 | md5 = "8b317669314cf1bc881716cccdaccb30"; | |
690 | }; |
|
894 | }; | |
|
895 | meta = { | |||
|
896 | license = [ pkgs.lib.licenses.asl20 ]; | |||
|
897 | }; | |||
691 | }; |
|
898 | }; | |
692 | nose = super.buildPythonPackage { |
|
899 | nose = super.buildPythonPackage { | |
693 | name = "nose-1.3.6"; |
|
900 | name = "nose-1.3.6"; | |
@@ -698,6 +905,9 b'' | |||||
698 | url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz"; |
|
905 | url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz"; | |
699 | md5 = "0ca546d81ca8309080fc80cb389e7a16"; |
|
906 | md5 = "0ca546d81ca8309080fc80cb389e7a16"; | |
700 | }; |
|
907 | }; | |
|
908 | meta = { | |||
|
909 | license = [ { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "GNU LGPL"; } ]; | |||
|
910 | }; | |||
701 | }; |
|
911 | }; | |
702 | objgraph = super.buildPythonPackage { |
|
912 | objgraph = super.buildPythonPackage { | |
703 | name = "objgraph-2.0.0"; |
|
913 | name = "objgraph-2.0.0"; | |
@@ -708,6 +918,9 b'' | |||||
708 | url = "https://pypi.python.org/packages/d7/33/ace750b59247496ed769b170586c5def7202683f3d98e737b75b767ff29e/objgraph-2.0.0.tar.gz"; |
|
918 | url = "https://pypi.python.org/packages/d7/33/ace750b59247496ed769b170586c5def7202683f3d98e737b75b767ff29e/objgraph-2.0.0.tar.gz"; | |
709 | md5 = "25b0d5e5adc74aa63ead15699614159c"; |
|
919 | md5 = "25b0d5e5adc74aa63ead15699614159c"; | |
710 | }; |
|
920 | }; | |
|
921 | meta = { | |||
|
922 | license = [ pkgs.lib.licenses.mit ]; | |||
|
923 | }; | |||
711 | }; |
|
924 | }; | |
712 | packaging = super.buildPythonPackage { |
|
925 | packaging = super.buildPythonPackage { | |
713 | name = "packaging-15.2"; |
|
926 | name = "packaging-15.2"; | |
@@ -718,6 +931,9 b'' | |||||
718 | url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz"; |
|
931 | url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz"; | |
719 | md5 = "c16093476f6ced42128bf610e5db3784"; |
|
932 | md5 = "c16093476f6ced42128bf610e5db3784"; | |
720 | }; |
|
933 | }; | |
|
934 | meta = { | |||
|
935 | license = [ pkgs.lib.licenses.asl20 ]; | |||
|
936 | }; | |||
721 | }; |
|
937 | }; | |
722 | paramiko = super.buildPythonPackage { |
|
938 | paramiko = super.buildPythonPackage { | |
723 | name = "paramiko-1.15.1"; |
|
939 | name = "paramiko-1.15.1"; | |
@@ -728,6 +944,9 b'' | |||||
728 | url = "https://pypi.python.org/packages/04/2b/a22d2a560c1951abbbf95a0628e245945565f70dc082d9e784666887222c/paramiko-1.15.1.tar.gz"; |
|
944 | url = "https://pypi.python.org/packages/04/2b/a22d2a560c1951abbbf95a0628e245945565f70dc082d9e784666887222c/paramiko-1.15.1.tar.gz"; | |
729 | md5 = "48c274c3f9b1282932567b21f6acf3b5"; |
|
945 | md5 = "48c274c3f9b1282932567b21f6acf3b5"; | |
730 | }; |
|
946 | }; | |
|
947 | meta = { | |||
|
948 | license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; | |||
|
949 | }; | |||
731 | }; |
|
950 | }; | |
732 | pep8 = super.buildPythonPackage { |
|
951 | pep8 = super.buildPythonPackage { | |
733 | name = "pep8-1.5.7"; |
|
952 | name = "pep8-1.5.7"; | |
@@ -738,6 +957,9 b'' | |||||
738 | url = "https://pypi.python.org/packages/8b/de/259f5e735897ada1683489dd514b2a1c91aaa74e5e6b68f80acf128a6368/pep8-1.5.7.tar.gz"; |
|
957 | url = "https://pypi.python.org/packages/8b/de/259f5e735897ada1683489dd514b2a1c91aaa74e5e6b68f80acf128a6368/pep8-1.5.7.tar.gz"; | |
739 | md5 = "f6adbdd69365ecca20513c709f9b7c93"; |
|
958 | md5 = "f6adbdd69365ecca20513c709f9b7c93"; | |
740 | }; |
|
959 | }; | |
|
960 | meta = { | |||
|
961 | license = [ { fullName = "Expat license"; } pkgs.lib.licenses.mit ]; | |||
|
962 | }; | |||
741 | }; |
|
963 | }; | |
742 | psutil = super.buildPythonPackage { |
|
964 | psutil = super.buildPythonPackage { | |
743 | name = "psutil-2.2.1"; |
|
965 | name = "psutil-2.2.1"; | |
@@ -748,6 +970,9 b'' | |||||
748 | url = "https://pypi.python.org/packages/df/47/ee54ef14dd40f8ce831a7581001a5096494dc99fe71586260ca6b531fe86/psutil-2.2.1.tar.gz"; |
|
970 | url = "https://pypi.python.org/packages/df/47/ee54ef14dd40f8ce831a7581001a5096494dc99fe71586260ca6b531fe86/psutil-2.2.1.tar.gz"; | |
749 | md5 = "1a2b58cd9e3a53528bb6148f0c4d5244"; |
|
971 | md5 = "1a2b58cd9e3a53528bb6148f0c4d5244"; | |
750 | }; |
|
972 | }; | |
|
973 | meta = { | |||
|
974 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
975 | }; | |||
751 | }; |
|
976 | }; | |
752 | psycopg2 = super.buildPythonPackage { |
|
977 | psycopg2 = super.buildPythonPackage { | |
753 | name = "psycopg2-2.6"; |
|
978 | name = "psycopg2-2.6"; | |
@@ -758,6 +983,9 b'' | |||||
758 | url = "https://pypi.python.org/packages/dd/c7/9016ff8ff69da269b1848276eebfb264af5badf6b38caad805426771f04d/psycopg2-2.6.tar.gz"; |
|
983 | url = "https://pypi.python.org/packages/dd/c7/9016ff8ff69da269b1848276eebfb264af5badf6b38caad805426771f04d/psycopg2-2.6.tar.gz"; | |
759 | md5 = "fbbb039a8765d561a1c04969bbae7c74"; |
|
984 | md5 = "fbbb039a8765d561a1c04969bbae7c74"; | |
760 | }; |
|
985 | }; | |
|
986 | meta = { | |||
|
987 | license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ]; | |||
|
988 | }; | |||
761 | }; |
|
989 | }; | |
762 | py = super.buildPythonPackage { |
|
990 | py = super.buildPythonPackage { | |
763 | name = "py-1.4.29"; |
|
991 | name = "py-1.4.29"; | |
@@ -768,6 +996,9 b'' | |||||
768 | url = "https://pypi.python.org/packages/2a/bc/a1a4a332ac10069b8e5e25136a35e08a03f01fd6ab03d819889d79a1fd65/py-1.4.29.tar.gz"; |
|
996 | url = "https://pypi.python.org/packages/2a/bc/a1a4a332ac10069b8e5e25136a35e08a03f01fd6ab03d819889d79a1fd65/py-1.4.29.tar.gz"; | |
769 | md5 = "c28e0accba523a29b35a48bb703fb96c"; |
|
997 | md5 = "c28e0accba523a29b35a48bb703fb96c"; | |
770 | }; |
|
998 | }; | |
|
999 | meta = { | |||
|
1000 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1001 | }; | |||
771 | }; |
|
1002 | }; | |
772 | py-bcrypt = super.buildPythonPackage { |
|
1003 | py-bcrypt = super.buildPythonPackage { | |
773 | name = "py-bcrypt-0.4"; |
|
1004 | name = "py-bcrypt-0.4"; | |
@@ -778,6 +1009,9 b'' | |||||
778 | url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz"; |
|
1009 | url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz"; | |
779 | md5 = "dd8b367d6b716a2ea2e72392525f4e36"; |
|
1010 | md5 = "dd8b367d6b716a2ea2e72392525f4e36"; | |
780 | }; |
|
1011 | }; | |
|
1012 | meta = { | |||
|
1013 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
1014 | }; | |||
781 | }; |
|
1015 | }; | |
782 | pycrypto = super.buildPythonPackage { |
|
1016 | pycrypto = super.buildPythonPackage { | |
783 | name = "pycrypto-2.6.1"; |
|
1017 | name = "pycrypto-2.6.1"; | |
@@ -788,6 +1022,9 b'' | |||||
788 | url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz"; |
|
1022 | url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz"; | |
789 | md5 = "55a61a054aa66812daf5161a0d5d7eda"; |
|
1023 | md5 = "55a61a054aa66812daf5161a0d5d7eda"; | |
790 | }; |
|
1024 | }; | |
|
1025 | meta = { | |||
|
1026 | license = [ pkgs.lib.licenses.publicDomain ]; | |||
|
1027 | }; | |||
791 | }; |
|
1028 | }; | |
792 | pycurl = super.buildPythonPackage { |
|
1029 | pycurl = super.buildPythonPackage { | |
793 | name = "pycurl-7.19.5"; |
|
1030 | name = "pycurl-7.19.5"; | |
@@ -798,6 +1035,9 b'' | |||||
798 | url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz"; |
|
1035 | url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz"; | |
799 | md5 = "47b4eac84118e2606658122104e62072"; |
|
1036 | md5 = "47b4eac84118e2606658122104e62072"; | |
800 | }; |
|
1037 | }; | |
|
1038 | meta = { | |||
|
1039 | license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; | |||
|
1040 | }; | |||
801 | }; |
|
1041 | }; | |
802 | pyflakes = super.buildPythonPackage { |
|
1042 | pyflakes = super.buildPythonPackage { | |
803 | name = "pyflakes-0.8.1"; |
|
1043 | name = "pyflakes-0.8.1"; | |
@@ -808,6 +1048,9 b'' | |||||
808 | url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz"; |
|
1048 | url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz"; | |
809 | md5 = "905fe91ad14b912807e8fdc2ac2e2c23"; |
|
1049 | md5 = "905fe91ad14b912807e8fdc2ac2e2c23"; | |
810 | }; |
|
1050 | }; | |
|
1051 | meta = { | |||
|
1052 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1053 | }; | |||
811 | }; |
|
1054 | }; | |
812 | pyparsing = super.buildPythonPackage { |
|
1055 | pyparsing = super.buildPythonPackage { | |
813 | name = "pyparsing-1.5.7"; |
|
1056 | name = "pyparsing-1.5.7"; | |
@@ -818,6 +1061,9 b'' | |||||
818 | url = "https://pypi.python.org/packages/2e/26/e8fb5b4256a5f5036be7ce115ef8db8d06bc537becfbdc46c6af008314ee/pyparsing-1.5.7.zip"; |
|
1061 | url = "https://pypi.python.org/packages/2e/26/e8fb5b4256a5f5036be7ce115ef8db8d06bc537becfbdc46c6af008314ee/pyparsing-1.5.7.zip"; | |
819 | md5 = "b86854857a368d6ccb4d5b6e76d0637f"; |
|
1062 | md5 = "b86854857a368d6ccb4d5b6e76d0637f"; | |
820 | }; |
|
1063 | }; | |
|
1064 | meta = { | |||
|
1065 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1066 | }; | |||
821 | }; |
|
1067 | }; | |
822 | pyramid = super.buildPythonPackage { |
|
1068 | pyramid = super.buildPythonPackage { | |
823 | name = "pyramid-1.6.1"; |
|
1069 | name = "pyramid-1.6.1"; | |
@@ -828,6 +1074,9 b'' | |||||
828 | url = "https://pypi.python.org/packages/30/b3/fcc4a2a4800cbf21989e00454b5828cf1f7fe35c63e0810b350e56d4c475/pyramid-1.6.1.tar.gz"; |
|
1074 | url = "https://pypi.python.org/packages/30/b3/fcc4a2a4800cbf21989e00454b5828cf1f7fe35c63e0810b350e56d4c475/pyramid-1.6.1.tar.gz"; | |
829 | md5 = "b18688ff3cc33efdbb098a35b45dd122"; |
|
1075 | md5 = "b18688ff3cc33efdbb098a35b45dd122"; | |
830 | }; |
|
1076 | }; | |
|
1077 | meta = { | |||
|
1078 | license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
1079 | }; | |||
831 | }; |
|
1080 | }; | |
832 | pyramid-beaker = super.buildPythonPackage { |
|
1081 | pyramid-beaker = super.buildPythonPackage { | |
833 | name = "pyramid-beaker-0.8"; |
|
1082 | name = "pyramid-beaker-0.8"; | |
@@ -838,6 +1087,9 b'' | |||||
838 | url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz"; |
|
1087 | url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz"; | |
839 | md5 = "22f14be31b06549f80890e2c63a93834"; |
|
1088 | md5 = "22f14be31b06549f80890e2c63a93834"; | |
840 | }; |
|
1089 | }; | |
|
1090 | meta = { | |||
|
1091 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
1092 | }; | |||
841 | }; |
|
1093 | }; | |
842 | pyramid-debugtoolbar = super.buildPythonPackage { |
|
1094 | pyramid-debugtoolbar = super.buildPythonPackage { | |
843 | name = "pyramid-debugtoolbar-2.4.2"; |
|
1095 | name = "pyramid-debugtoolbar-2.4.2"; | |
@@ -848,6 +1100,9 b'' | |||||
848 | url = "https://pypi.python.org/packages/89/00/ed5426ee41ed747ba3ffd30e8230841a6878286ea67d480b1444d24f06a2/pyramid_debugtoolbar-2.4.2.tar.gz"; |
|
1100 | url = "https://pypi.python.org/packages/89/00/ed5426ee41ed747ba3ffd30e8230841a6878286ea67d480b1444d24f06a2/pyramid_debugtoolbar-2.4.2.tar.gz"; | |
849 | md5 = "073ea67086cc4bd5decc3a000853642d"; |
|
1101 | md5 = "073ea67086cc4bd5decc3a000853642d"; | |
850 | }; |
|
1102 | }; | |
|
1103 | meta = { | |||
|
1104 | license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ]; | |||
|
1105 | }; | |||
851 | }; |
|
1106 | }; | |
852 | pyramid-jinja2 = super.buildPythonPackage { |
|
1107 | pyramid-jinja2 = super.buildPythonPackage { | |
853 | name = "pyramid-jinja2-2.5"; |
|
1108 | name = "pyramid-jinja2-2.5"; | |
@@ -858,6 +1113,9 b'' | |||||
858 | url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz"; |
|
1113 | url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz"; | |
859 | md5 = "07cb6547204ac5e6f0b22a954ccee928"; |
|
1114 | md5 = "07cb6547204ac5e6f0b22a954ccee928"; | |
860 | }; |
|
1115 | }; | |
|
1116 | meta = { | |||
|
1117 | license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
1118 | }; | |||
861 | }; |
|
1119 | }; | |
862 | pyramid-mako = super.buildPythonPackage { |
|
1120 | pyramid-mako = super.buildPythonPackage { | |
863 | name = "pyramid-mako-1.0.2"; |
|
1121 | name = "pyramid-mako-1.0.2"; | |
@@ -868,6 +1126,9 b'' | |||||
868 | url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz"; |
|
1126 | url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz"; | |
869 | md5 = "ee25343a97eb76bd90abdc2a774eb48a"; |
|
1127 | md5 = "ee25343a97eb76bd90abdc2a774eb48a"; | |
870 | }; |
|
1128 | }; | |
|
1129 | meta = { | |||
|
1130 | license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
1131 | }; | |||
871 | }; |
|
1132 | }; | |
872 | pysqlite = super.buildPythonPackage { |
|
1133 | pysqlite = super.buildPythonPackage { | |
873 | name = "pysqlite-2.6.3"; |
|
1134 | name = "pysqlite-2.6.3"; | |
@@ -878,6 +1139,9 b'' | |||||
878 | url = "https://pypi.python.org/packages/5c/a6/1c429cd4c8069cf4bfbd0eb4d592b3f4042155a8202df83d7e9b93aa3dc2/pysqlite-2.6.3.tar.gz"; |
|
1139 | url = "https://pypi.python.org/packages/5c/a6/1c429cd4c8069cf4bfbd0eb4d592b3f4042155a8202df83d7e9b93aa3dc2/pysqlite-2.6.3.tar.gz"; | |
879 | md5 = "7ff1cedee74646b50117acff87aa1cfa"; |
|
1140 | md5 = "7ff1cedee74646b50117acff87aa1cfa"; | |
880 | }; |
|
1141 | }; | |
|
1142 | meta = { | |||
|
1143 | license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ]; | |||
|
1144 | }; | |||
881 | }; |
|
1145 | }; | |
882 | pytest = super.buildPythonPackage { |
|
1146 | pytest = super.buildPythonPackage { | |
883 | name = "pytest-2.8.5"; |
|
1147 | name = "pytest-2.8.5"; | |
@@ -888,6 +1152,9 b'' | |||||
888 | url = "https://pypi.python.org/packages/b1/3d/d7ea9b0c51e0cacded856e49859f0a13452747491e842c236bbab3714afe/pytest-2.8.5.zip"; |
|
1152 | url = "https://pypi.python.org/packages/b1/3d/d7ea9b0c51e0cacded856e49859f0a13452747491e842c236bbab3714afe/pytest-2.8.5.zip"; | |
889 | md5 = "8493b06f700862f1294298d6c1b715a9"; |
|
1153 | md5 = "8493b06f700862f1294298d6c1b715a9"; | |
890 | }; |
|
1154 | }; | |
|
1155 | meta = { | |||
|
1156 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1157 | }; | |||
891 | }; |
|
1158 | }; | |
892 | pytest-catchlog = super.buildPythonPackage { |
|
1159 | pytest-catchlog = super.buildPythonPackage { | |
893 | name = "pytest-catchlog-1.2.2"; |
|
1160 | name = "pytest-catchlog-1.2.2"; | |
@@ -898,6 +1165,9 b'' | |||||
898 | url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip"; |
|
1165 | url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip"; | |
899 | md5 = "09d890c54c7456c818102b7ff8c182c8"; |
|
1166 | md5 = "09d890c54c7456c818102b7ff8c182c8"; | |
900 | }; |
|
1167 | }; | |
|
1168 | meta = { | |||
|
1169 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1170 | }; | |||
901 | }; |
|
1171 | }; | |
902 | pytest-cov = super.buildPythonPackage { |
|
1172 | pytest-cov = super.buildPythonPackage { | |
903 | name = "pytest-cov-1.8.1"; |
|
1173 | name = "pytest-cov-1.8.1"; | |
@@ -908,6 +1178,9 b'' | |||||
908 | url = "https://pypi.python.org/packages/11/4b/b04646e97f1721878eb21e9f779102d84dd044d324382263b1770a3e4838/pytest-cov-1.8.1.tar.gz"; |
|
1178 | url = "https://pypi.python.org/packages/11/4b/b04646e97f1721878eb21e9f779102d84dd044d324382263b1770a3e4838/pytest-cov-1.8.1.tar.gz"; | |
909 | md5 = "76c778afa2494088270348be42d759fc"; |
|
1179 | md5 = "76c778afa2494088270348be42d759fc"; | |
910 | }; |
|
1180 | }; | |
|
1181 | meta = { | |||
|
1182 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1183 | }; | |||
911 | }; |
|
1184 | }; | |
912 | pytest-profiling = super.buildPythonPackage { |
|
1185 | pytest-profiling = super.buildPythonPackage { | |
913 | name = "pytest-profiling-1.0.1"; |
|
1186 | name = "pytest-profiling-1.0.1"; | |
@@ -918,6 +1191,9 b'' | |||||
918 | url = "https://pypi.python.org/packages/d8/67/8ffab73406e22870e07fa4dc8dce1d7689b26dba8efd00161c9b6fc01ec0/pytest-profiling-1.0.1.tar.gz"; |
|
1191 | url = "https://pypi.python.org/packages/d8/67/8ffab73406e22870e07fa4dc8dce1d7689b26dba8efd00161c9b6fc01ec0/pytest-profiling-1.0.1.tar.gz"; | |
919 | md5 = "354404eb5b3fd4dc5eb7fffbb3d9b68b"; |
|
1192 | md5 = "354404eb5b3fd4dc5eb7fffbb3d9b68b"; | |
920 | }; |
|
1193 | }; | |
|
1194 | meta = { | |||
|
1195 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1196 | }; | |||
921 | }; |
|
1197 | }; | |
922 | pytest-runner = super.buildPythonPackage { |
|
1198 | pytest-runner = super.buildPythonPackage { | |
923 | name = "pytest-runner-2.7.1"; |
|
1199 | name = "pytest-runner-2.7.1"; | |
@@ -928,6 +1204,9 b'' | |||||
928 | url = "https://pypi.python.org/packages/99/6b/c4ff4418d3424d4475b7af60724fd4a5cdd91ed8e489dc9443281f0052bc/pytest-runner-2.7.1.tar.gz"; |
|
1204 | url = "https://pypi.python.org/packages/99/6b/c4ff4418d3424d4475b7af60724fd4a5cdd91ed8e489dc9443281f0052bc/pytest-runner-2.7.1.tar.gz"; | |
929 | md5 = "e56f0bc8d79a6bd91772b44ef4215c7e"; |
|
1205 | md5 = "e56f0bc8d79a6bd91772b44ef4215c7e"; | |
930 | }; |
|
1206 | }; | |
|
1207 | meta = { | |||
|
1208 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1209 | }; | |||
931 | }; |
|
1210 | }; | |
932 | pytest-timeout = super.buildPythonPackage { |
|
1211 | pytest-timeout = super.buildPythonPackage { | |
933 | name = "pytest-timeout-0.4"; |
|
1212 | name = "pytest-timeout-0.4"; | |
@@ -938,6 +1217,9 b'' | |||||
938 | url = "https://pypi.python.org/packages/24/48/5f6bd4b8026a26e1dd427243d560a29a0f1b24a5c7cffca4bf049a7bb65b/pytest-timeout-0.4.tar.gz"; |
|
1217 | url = "https://pypi.python.org/packages/24/48/5f6bd4b8026a26e1dd427243d560a29a0f1b24a5c7cffca4bf049a7bb65b/pytest-timeout-0.4.tar.gz"; | |
939 | md5 = "03b28aff69cbbfb959ed35ade5fde262"; |
|
1218 | md5 = "03b28aff69cbbfb959ed35ade5fde262"; | |
940 | }; |
|
1219 | }; | |
|
1220 | meta = { | |||
|
1221 | license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ]; | |||
|
1222 | }; | |||
941 | }; |
|
1223 | }; | |
942 | python-dateutil = super.buildPythonPackage { |
|
1224 | python-dateutil = super.buildPythonPackage { | |
943 | name = "python-dateutil-1.5"; |
|
1225 | name = "python-dateutil-1.5"; | |
@@ -948,6 +1230,9 b'' | |||||
948 | url = "https://pypi.python.org/packages/b4/7c/df59c89a753eb33c7c44e1dd42de0e9bc2ccdd5a4d576e0bfad97cc280cb/python-dateutil-1.5.tar.gz"; |
|
1230 | url = "https://pypi.python.org/packages/b4/7c/df59c89a753eb33c7c44e1dd42de0e9bc2ccdd5a4d576e0bfad97cc280cb/python-dateutil-1.5.tar.gz"; | |
949 | md5 = "0dcb1de5e5cad69490a3b6ab63f0cfa5"; |
|
1231 | md5 = "0dcb1de5e5cad69490a3b6ab63f0cfa5"; | |
950 | }; |
|
1232 | }; | |
|
1233 | meta = { | |||
|
1234 | license = [ pkgs.lib.licenses.psfl ]; | |||
|
1235 | }; | |||
951 | }; |
|
1236 | }; | |
952 | python-editor = super.buildPythonPackage { |
|
1237 | python-editor = super.buildPythonPackage { | |
953 | name = "python-editor-1.0.1"; |
|
1238 | name = "python-editor-1.0.1"; | |
@@ -958,6 +1243,9 b'' | |||||
958 | url = "https://pypi.python.org/packages/2b/c0/df7b87d5cf016f82eab3b05cd35f53287c1178ad8c42bfb6fa61b89b22f6/python-editor-1.0.1.tar.gz"; |
|
1243 | url = "https://pypi.python.org/packages/2b/c0/df7b87d5cf016f82eab3b05cd35f53287c1178ad8c42bfb6fa61b89b22f6/python-editor-1.0.1.tar.gz"; | |
959 | md5 = "e1fa63535b40e022fa4fd646fd8b511a"; |
|
1244 | md5 = "e1fa63535b40e022fa4fd646fd8b511a"; | |
960 | }; |
|
1245 | }; | |
|
1246 | meta = { | |||
|
1247 | license = [ pkgs.lib.licenses.asl20 ]; | |||
|
1248 | }; | |||
961 | }; |
|
1249 | }; | |
962 | python-ldap = super.buildPythonPackage { |
|
1250 | python-ldap = super.buildPythonPackage { | |
963 | name = "python-ldap-2.4.19"; |
|
1251 | name = "python-ldap-2.4.19"; | |
@@ -968,6 +1256,9 b'' | |||||
968 | url = "https://pypi.python.org/packages/42/81/1b64838c82e64f14d4e246ff00b52e650a35c012551b891ada2b85d40737/python-ldap-2.4.19.tar.gz"; |
|
1256 | url = "https://pypi.python.org/packages/42/81/1b64838c82e64f14d4e246ff00b52e650a35c012551b891ada2b85d40737/python-ldap-2.4.19.tar.gz"; | |
969 | md5 = "b941bf31d09739492aa19ef679e94ae3"; |
|
1257 | md5 = "b941bf31d09739492aa19ef679e94ae3"; | |
970 | }; |
|
1258 | }; | |
|
1259 | meta = { | |||
|
1260 | license = [ pkgs.lib.licenses.psfl ]; | |||
|
1261 | }; | |||
971 | }; |
|
1262 | }; | |
972 | python-memcached = super.buildPythonPackage { |
|
1263 | python-memcached = super.buildPythonPackage { | |
973 | name = "python-memcached-1.57"; |
|
1264 | name = "python-memcached-1.57"; | |
@@ -978,6 +1269,9 b'' | |||||
978 | url = "https://pypi.python.org/packages/52/9d/eebc0dcbc5c7c66840ad207dfc1baa376dadb74912484bff73819cce01e6/python-memcached-1.57.tar.gz"; |
|
1269 | url = "https://pypi.python.org/packages/52/9d/eebc0dcbc5c7c66840ad207dfc1baa376dadb74912484bff73819cce01e6/python-memcached-1.57.tar.gz"; | |
979 | md5 = "de21f64b42b2d961f3d4ad7beb5468a1"; |
|
1270 | md5 = "de21f64b42b2d961f3d4ad7beb5468a1"; | |
980 | }; |
|
1271 | }; | |
|
1272 | meta = { | |||
|
1273 | license = [ pkgs.lib.licenses.psfl ]; | |||
|
1274 | }; | |||
981 | }; |
|
1275 | }; | |
982 | python-pam = super.buildPythonPackage { |
|
1276 | python-pam = super.buildPythonPackage { | |
983 | name = "python-pam-1.8.2"; |
|
1277 | name = "python-pam-1.8.2"; | |
@@ -988,6 +1282,9 b'' | |||||
988 | url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz"; |
|
1282 | url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz"; | |
989 | md5 = "db71b6b999246fb05d78ecfbe166629d"; |
|
1283 | md5 = "db71b6b999246fb05d78ecfbe166629d"; | |
990 | }; |
|
1284 | }; | |
|
1285 | meta = { | |||
|
1286 | license = [ { fullName = "License :: OSI Approved :: MIT License"; } pkgs.lib.licenses.mit ]; | |||
|
1287 | }; | |||
991 | }; |
|
1288 | }; | |
992 | pytz = super.buildPythonPackage { |
|
1289 | pytz = super.buildPythonPackage { | |
993 | name = "pytz-2015.4"; |
|
1290 | name = "pytz-2015.4"; | |
@@ -998,6 +1295,9 b'' | |||||
998 | url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip"; |
|
1295 | url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip"; | |
999 | md5 = "233f2a2b370d03f9b5911700cc9ebf3c"; |
|
1296 | md5 = "233f2a2b370d03f9b5911700cc9ebf3c"; | |
1000 | }; |
|
1297 | }; | |
|
1298 | meta = { | |||
|
1299 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1300 | }; | |||
1001 | }; |
|
1301 | }; | |
1002 | pyzmq = super.buildPythonPackage { |
|
1302 | pyzmq = super.buildPythonPackage { | |
1003 | name = "pyzmq-14.6.0"; |
|
1303 | name = "pyzmq-14.6.0"; | |
@@ -1008,6 +1308,9 b'' | |||||
1008 | url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz"; |
|
1308 | url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz"; | |
1009 | md5 = "395b5de95a931afa5b14c9349a5b8024"; |
|
1309 | md5 = "395b5de95a931afa5b14c9349a5b8024"; | |
1010 | }; |
|
1310 | }; | |
|
1311 | meta = { | |||
|
1312 | license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; | |||
|
1313 | }; | |||
1011 | }; |
|
1314 | }; | |
1012 | recaptcha-client = super.buildPythonPackage { |
|
1315 | recaptcha-client = super.buildPythonPackage { | |
1013 | name = "recaptcha-client-1.0.6"; |
|
1316 | name = "recaptcha-client-1.0.6"; | |
@@ -1018,6 +1321,9 b'' | |||||
1018 | url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz"; |
|
1321 | url = "https://pypi.python.org/packages/0a/ea/5f2fbbfd894bdac1c68ef8d92019066cfcf9fbff5fe3d728d2b5c25c8db4/recaptcha-client-1.0.6.tar.gz"; | |
1019 | md5 = "74228180f7e1fb76c4d7089160b0d919"; |
|
1322 | md5 = "74228180f7e1fb76c4d7089160b0d919"; | |
1020 | }; |
|
1323 | }; | |
|
1324 | meta = { | |||
|
1325 | license = [ { fullName = "MIT/X11"; } ]; | |||
|
1326 | }; | |||
1021 | }; |
|
1327 | }; | |
1022 | repoze.lru = super.buildPythonPackage { |
|
1328 | repoze.lru = super.buildPythonPackage { | |
1023 | name = "repoze.lru-0.6"; |
|
1329 | name = "repoze.lru-0.6"; | |
@@ -1028,6 +1334,9 b'' | |||||
1028 | url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz"; |
|
1334 | url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz"; | |
1029 | md5 = "2c3b64b17a8e18b405f55d46173e14dd"; |
|
1335 | md5 = "2c3b64b17a8e18b405f55d46173e14dd"; | |
1030 | }; |
|
1336 | }; | |
|
1337 | meta = { | |||
|
1338 | license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
1339 | }; | |||
1031 | }; |
|
1340 | }; | |
1032 | requests = super.buildPythonPackage { |
|
1341 | requests = super.buildPythonPackage { | |
1033 | name = "requests-2.9.1"; |
|
1342 | name = "requests-2.9.1"; | |
@@ -1038,13 +1347,19 b'' | |||||
1038 | url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz"; |
|
1347 | url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz"; | |
1039 | md5 = "0b7f480d19012ec52bab78292efd976d"; |
|
1348 | md5 = "0b7f480d19012ec52bab78292efd976d"; | |
1040 | }; |
|
1349 | }; | |
|
1350 | meta = { | |||
|
1351 | license = [ pkgs.lib.licenses.asl20 ]; | |||
|
1352 | }; | |||
1041 | }; |
|
1353 | }; | |
1042 | rhodecode-enterprise-ce = super.buildPythonPackage { |
|
1354 | rhodecode-enterprise-ce = super.buildPythonPackage { | |
1043 |
name = "rhodecode-enterprise-ce-4. |
|
1355 | name = "rhodecode-enterprise-ce-4.2.0"; | |
1044 | buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner]; |
|
1356 | buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner]; | |
1045 | doCheck = true; |
|
1357 | doCheck = true; | |
1046 | propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors psutil py-bcrypt]; |
|
1358 | propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors psutil py-bcrypt]; | |
1047 | src = ./.; |
|
1359 | src = ./.; | |
|
1360 | meta = { | |||
|
1361 | license = [ { fullName = "AGPLv3, and Commercial License"; } ]; | |||
|
1362 | }; | |||
1048 | }; |
|
1363 | }; | |
1049 | rhodecode-tools = super.buildPythonPackage { |
|
1364 | rhodecode-tools = super.buildPythonPackage { | |
1050 | name = "rhodecode-tools-0.8.3"; |
|
1365 | name = "rhodecode-tools-0.8.3"; | |
@@ -1055,6 +1370,9 b'' | |||||
1055 | url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.8.3.zip"; |
|
1370 | url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.8.3.zip"; | |
1056 | md5 = "9acdfd71b8ddf4056057065f37ab9ccb"; |
|
1371 | md5 = "9acdfd71b8ddf4056057065f37ab9ccb"; | |
1057 | }; |
|
1372 | }; | |
|
1373 | meta = { | |||
|
1374 | license = [ { fullName = "AGPLv3 and Proprietary"; } ]; | |||
|
1375 | }; | |||
1058 | }; |
|
1376 | }; | |
1059 | serpent = super.buildPythonPackage { |
|
1377 | serpent = super.buildPythonPackage { | |
1060 | name = "serpent-1.12"; |
|
1378 | name = "serpent-1.12"; | |
@@ -1065,6 +1383,9 b'' | |||||
1065 | url = "https://pypi.python.org/packages/3b/19/1e0e83b47c09edaef8398655088036e7e67386b5c48770218ebb339fbbd5/serpent-1.12.tar.gz"; |
|
1383 | url = "https://pypi.python.org/packages/3b/19/1e0e83b47c09edaef8398655088036e7e67386b5c48770218ebb339fbbd5/serpent-1.12.tar.gz"; | |
1066 | md5 = "05869ac7b062828b34f8f927f0457b65"; |
|
1384 | md5 = "05869ac7b062828b34f8f927f0457b65"; | |
1067 | }; |
|
1385 | }; | |
|
1386 | meta = { | |||
|
1387 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1388 | }; | |||
1068 | }; |
|
1389 | }; | |
1069 | setproctitle = super.buildPythonPackage { |
|
1390 | setproctitle = super.buildPythonPackage { | |
1070 | name = "setproctitle-1.1.8"; |
|
1391 | name = "setproctitle-1.1.8"; | |
@@ -1075,6 +1396,9 b'' | |||||
1075 | url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz"; |
|
1396 | url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz"; | |
1076 | md5 = "728f4c8c6031bbe56083a48594027edd"; |
|
1397 | md5 = "728f4c8c6031bbe56083a48594027edd"; | |
1077 | }; |
|
1398 | }; | |
|
1399 | meta = { | |||
|
1400 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
1401 | }; | |||
1078 | }; |
|
1402 | }; | |
1079 | setuptools = super.buildPythonPackage { |
|
1403 | setuptools = super.buildPythonPackage { | |
1080 | name = "setuptools-20.8.1"; |
|
1404 | name = "setuptools-20.8.1"; | |
@@ -1085,6 +1409,9 b'' | |||||
1085 | url = "https://pypi.python.org/packages/c4/19/c1bdc88b53da654df43770f941079dbab4e4788c2dcb5658fb86259894c7/setuptools-20.8.1.zip"; |
|
1409 | url = "https://pypi.python.org/packages/c4/19/c1bdc88b53da654df43770f941079dbab4e4788c2dcb5658fb86259894c7/setuptools-20.8.1.zip"; | |
1086 | md5 = "fe58a5cac0df20bb83942b252a4b0543"; |
|
1410 | md5 = "fe58a5cac0df20bb83942b252a4b0543"; | |
1087 | }; |
|
1411 | }; | |
|
1412 | meta = { | |||
|
1413 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1414 | }; | |||
1088 | }; |
|
1415 | }; | |
1089 | setuptools-scm = super.buildPythonPackage { |
|
1416 | setuptools-scm = super.buildPythonPackage { | |
1090 | name = "setuptools-scm-1.11.0"; |
|
1417 | name = "setuptools-scm-1.11.0"; | |
@@ -1095,6 +1422,9 b'' | |||||
1095 | url = "https://pypi.python.org/packages/cd/5f/e3a038292358058d83d764a47d09114aa5a8003ed4529518f9e580f1a94f/setuptools_scm-1.11.0.tar.gz"; |
|
1422 | url = "https://pypi.python.org/packages/cd/5f/e3a038292358058d83d764a47d09114aa5a8003ed4529518f9e580f1a94f/setuptools_scm-1.11.0.tar.gz"; | |
1096 | md5 = "4c5c896ba52e134bbc3507bac6400087"; |
|
1423 | md5 = "4c5c896ba52e134bbc3507bac6400087"; | |
1097 | }; |
|
1424 | }; | |
|
1425 | meta = { | |||
|
1426 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1427 | }; | |||
1098 | }; |
|
1428 | }; | |
1099 | simplejson = super.buildPythonPackage { |
|
1429 | simplejson = super.buildPythonPackage { | |
1100 | name = "simplejson-3.7.2"; |
|
1430 | name = "simplejson-3.7.2"; | |
@@ -1105,6 +1435,9 b'' | |||||
1105 | url = "https://pypi.python.org/packages/6d/89/7f13f099344eea9d6722779a1f165087cb559598107844b1ac5dbd831fb1/simplejson-3.7.2.tar.gz"; |
|
1435 | url = "https://pypi.python.org/packages/6d/89/7f13f099344eea9d6722779a1f165087cb559598107844b1ac5dbd831fb1/simplejson-3.7.2.tar.gz"; | |
1106 | md5 = "a5fc7d05d4cb38492285553def5d4b46"; |
|
1436 | md5 = "a5fc7d05d4cb38492285553def5d4b46"; | |
1107 | }; |
|
1437 | }; | |
|
1438 | meta = { | |||
|
1439 | license = [ pkgs.lib.licenses.mit pkgs.lib.licenses.afl21 ]; | |||
|
1440 | }; | |||
1108 | }; |
|
1441 | }; | |
1109 | six = super.buildPythonPackage { |
|
1442 | six = super.buildPythonPackage { | |
1110 | name = "six-1.9.0"; |
|
1443 | name = "six-1.9.0"; | |
@@ -1115,6 +1448,9 b'' | |||||
1115 | url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz"; |
|
1448 | url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz"; | |
1116 | md5 = "476881ef4012262dfc8adc645ee786c4"; |
|
1449 | md5 = "476881ef4012262dfc8adc645ee786c4"; | |
1117 | }; |
|
1450 | }; | |
|
1451 | meta = { | |||
|
1452 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1453 | }; | |||
1118 | }; |
|
1454 | }; | |
1119 | subprocess32 = super.buildPythonPackage { |
|
1455 | subprocess32 = super.buildPythonPackage { | |
1120 | name = "subprocess32-3.2.6"; |
|
1456 | name = "subprocess32-3.2.6"; | |
@@ -1125,6 +1461,9 b'' | |||||
1125 | url = "https://pypi.python.org/packages/28/8d/33ccbff51053f59ae6c357310cac0e79246bbed1d345ecc6188b176d72c3/subprocess32-3.2.6.tar.gz"; |
|
1461 | url = "https://pypi.python.org/packages/28/8d/33ccbff51053f59ae6c357310cac0e79246bbed1d345ecc6188b176d72c3/subprocess32-3.2.6.tar.gz"; | |
1126 | md5 = "754c5ab9f533e764f931136974b618f1"; |
|
1462 | md5 = "754c5ab9f533e764f931136974b618f1"; | |
1127 | }; |
|
1463 | }; | |
|
1464 | meta = { | |||
|
1465 | license = [ pkgs.lib.licenses.psfl ]; | |||
|
1466 | }; | |||
1128 | }; |
|
1467 | }; | |
1129 | supervisor = super.buildPythonPackage { |
|
1468 | supervisor = super.buildPythonPackage { | |
1130 | name = "supervisor-3.1.3"; |
|
1469 | name = "supervisor-3.1.3"; | |
@@ -1135,6 +1474,9 b'' | |||||
1135 | url = "https://pypi.python.org/packages/a6/41/65ad5bd66230b173eb4d0b8810230f3a9c59ef52ae066e540b6b99895db7/supervisor-3.1.3.tar.gz"; |
|
1474 | url = "https://pypi.python.org/packages/a6/41/65ad5bd66230b173eb4d0b8810230f3a9c59ef52ae066e540b6b99895db7/supervisor-3.1.3.tar.gz"; | |
1136 | md5 = "aad263c4fbc070de63dd354864d5e552"; |
|
1475 | md5 = "aad263c4fbc070de63dd354864d5e552"; | |
1137 | }; |
|
1476 | }; | |
|
1477 | meta = { | |||
|
1478 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
1479 | }; | |||
1138 | }; |
|
1480 | }; | |
1139 | transifex-client = super.buildPythonPackage { |
|
1481 | transifex-client = super.buildPythonPackage { | |
1140 | name = "transifex-client-0.10"; |
|
1482 | name = "transifex-client-0.10"; | |
@@ -1145,6 +1487,9 b'' | |||||
1145 | url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz"; |
|
1487 | url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz"; | |
1146 | md5 = "5549538d84b8eede6b254cd81ae024fa"; |
|
1488 | md5 = "5549538d84b8eede6b254cd81ae024fa"; | |
1147 | }; |
|
1489 | }; | |
|
1490 | meta = { | |||
|
1491 | license = [ pkgs.lib.licenses.gpl2 ]; | |||
|
1492 | }; | |||
1148 | }; |
|
1493 | }; | |
1149 | translationstring = super.buildPythonPackage { |
|
1494 | translationstring = super.buildPythonPackage { | |
1150 | name = "translationstring-1.3"; |
|
1495 | name = "translationstring-1.3"; | |
@@ -1155,6 +1500,9 b'' | |||||
1155 | url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz"; |
|
1500 | url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz"; | |
1156 | md5 = "a4b62e0f3c189c783a1685b3027f7c90"; |
|
1501 | md5 = "a4b62e0f3c189c783a1685b3027f7c90"; | |
1157 | }; |
|
1502 | }; | |
|
1503 | meta = { | |||
|
1504 | license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ]; | |||
|
1505 | }; | |||
1158 | }; |
|
1506 | }; | |
1159 | trollius = super.buildPythonPackage { |
|
1507 | trollius = super.buildPythonPackage { | |
1160 | name = "trollius-1.0.4"; |
|
1508 | name = "trollius-1.0.4"; | |
@@ -1165,6 +1513,9 b'' | |||||
1165 | url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz"; |
|
1513 | url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz"; | |
1166 | md5 = "3631a464d49d0cbfd30ab2918ef2b783"; |
|
1514 | md5 = "3631a464d49d0cbfd30ab2918ef2b783"; | |
1167 | }; |
|
1515 | }; | |
|
1516 | meta = { | |||
|
1517 | license = [ pkgs.lib.licenses.asl20 ]; | |||
|
1518 | }; | |||
1168 | }; |
|
1519 | }; | |
1169 | uWSGI = super.buildPythonPackage { |
|
1520 | uWSGI = super.buildPythonPackage { | |
1170 | name = "uWSGI-2.0.11.2"; |
|
1521 | name = "uWSGI-2.0.11.2"; | |
@@ -1175,6 +1526,9 b'' | |||||
1175 | url = "https://pypi.python.org/packages/9b/78/918db0cfab0546afa580c1e565209c49aaf1476bbfe491314eadbe47c556/uwsgi-2.0.11.2.tar.gz"; |
|
1526 | url = "https://pypi.python.org/packages/9b/78/918db0cfab0546afa580c1e565209c49aaf1476bbfe491314eadbe47c556/uwsgi-2.0.11.2.tar.gz"; | |
1176 | md5 = "1f02dcbee7f6f61de4b1fd68350cf16f"; |
|
1527 | md5 = "1f02dcbee7f6f61de4b1fd68350cf16f"; | |
1177 | }; |
|
1528 | }; | |
|
1529 | meta = { | |||
|
1530 | license = [ pkgs.lib.licenses.gpl2 ]; | |||
|
1531 | }; | |||
1178 | }; |
|
1532 | }; | |
1179 | urllib3 = super.buildPythonPackage { |
|
1533 | urllib3 = super.buildPythonPackage { | |
1180 | name = "urllib3-1.16"; |
|
1534 | name = "urllib3-1.16"; | |
@@ -1185,6 +1539,9 b'' | |||||
1185 | url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz"; |
|
1539 | url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz"; | |
1186 | md5 = "fcaab1c5385c57deeb7053d3d7d81d59"; |
|
1540 | md5 = "fcaab1c5385c57deeb7053d3d7d81d59"; | |
1187 | }; |
|
1541 | }; | |
|
1542 | meta = { | |||
|
1543 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1544 | }; | |||
1188 | }; |
|
1545 | }; | |
1189 | venusian = super.buildPythonPackage { |
|
1546 | venusian = super.buildPythonPackage { | |
1190 | name = "venusian-1.0"; |
|
1547 | name = "venusian-1.0"; | |
@@ -1195,6 +1552,9 b'' | |||||
1195 | url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz"; |
|
1552 | url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz"; | |
1196 | md5 = "dccf2eafb7113759d60c86faf5538756"; |
|
1553 | md5 = "dccf2eafb7113759d60c86faf5538756"; | |
1197 | }; |
|
1554 | }; | |
|
1555 | meta = { | |||
|
1556 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
1557 | }; | |||
1198 | }; |
|
1558 | }; | |
1199 | waitress = super.buildPythonPackage { |
|
1559 | waitress = super.buildPythonPackage { | |
1200 | name = "waitress-0.8.9"; |
|
1560 | name = "waitress-0.8.9"; | |
@@ -1205,6 +1565,9 b'' | |||||
1205 | url = "https://pypi.python.org/packages/ee/65/fc9dee74a909a1187ca51e4f15ad9c4d35476e4ab5813f73421505c48053/waitress-0.8.9.tar.gz"; |
|
1565 | url = "https://pypi.python.org/packages/ee/65/fc9dee74a909a1187ca51e4f15ad9c4d35476e4ab5813f73421505c48053/waitress-0.8.9.tar.gz"; | |
1206 | md5 = "da3f2e62b3676be5dd630703a68e2a04"; |
|
1566 | md5 = "da3f2e62b3676be5dd630703a68e2a04"; | |
1207 | }; |
|
1567 | }; | |
|
1568 | meta = { | |||
|
1569 | license = [ pkgs.lib.licenses.zpt21 ]; | |||
|
1570 | }; | |||
1208 | }; |
|
1571 | }; | |
1209 | wsgiref = super.buildPythonPackage { |
|
1572 | wsgiref = super.buildPythonPackage { | |
1210 | name = "wsgiref-0.1.2"; |
|
1573 | name = "wsgiref-0.1.2"; | |
@@ -1215,6 +1578,9 b'' | |||||
1215 | url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip"; |
|
1578 | url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip"; | |
1216 | md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb"; |
|
1579 | md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb"; | |
1217 | }; |
|
1580 | }; | |
|
1581 | meta = { | |||
|
1582 | license = [ { fullName = "PSF or ZPL"; } ]; | |||
|
1583 | }; | |||
1218 | }; |
|
1584 | }; | |
1219 | zope.cachedescriptors = super.buildPythonPackage { |
|
1585 | zope.cachedescriptors = super.buildPythonPackage { | |
1220 | name = "zope.cachedescriptors-4.0.0"; |
|
1586 | name = "zope.cachedescriptors-4.0.0"; | |
@@ -1225,6 +1591,9 b'' | |||||
1225 | url = "https://pypi.python.org/packages/40/33/694b6644c37f28553f4b9f20b3c3a20fb709a22574dff20b5bdffb09ecd5/zope.cachedescriptors-4.0.0.tar.gz"; |
|
1591 | url = "https://pypi.python.org/packages/40/33/694b6644c37f28553f4b9f20b3c3a20fb709a22574dff20b5bdffb09ecd5/zope.cachedescriptors-4.0.0.tar.gz"; | |
1226 | md5 = "8d308de8c936792c8e758058fcb7d0f0"; |
|
1592 | md5 = "8d308de8c936792c8e758058fcb7d0f0"; | |
1227 | }; |
|
1593 | }; | |
|
1594 | meta = { | |||
|
1595 | license = [ pkgs.lib.licenses.zpt21 ]; | |||
|
1596 | }; | |||
1228 | }; |
|
1597 | }; | |
1229 | zope.deprecation = super.buildPythonPackage { |
|
1598 | zope.deprecation = super.buildPythonPackage { | |
1230 | name = "zope.deprecation-4.1.2"; |
|
1599 | name = "zope.deprecation-4.1.2"; | |
@@ -1235,6 +1604,9 b'' | |||||
1235 | url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz"; |
|
1604 | url = "https://pypi.python.org/packages/c1/d3/3919492d5e57d8dd01b36f30b34fc8404a30577392b1eb817c303499ad20/zope.deprecation-4.1.2.tar.gz"; | |
1236 | md5 = "e9a663ded58f4f9f7881beb56cae2782"; |
|
1605 | md5 = "e9a663ded58f4f9f7881beb56cae2782"; | |
1237 | }; |
|
1606 | }; | |
|
1607 | meta = { | |||
|
1608 | license = [ pkgs.lib.licenses.zpt21 ]; | |||
|
1609 | }; | |||
1238 | }; |
|
1610 | }; | |
1239 | zope.event = super.buildPythonPackage { |
|
1611 | zope.event = super.buildPythonPackage { | |
1240 | name = "zope.event-4.0.3"; |
|
1612 | name = "zope.event-4.0.3"; | |
@@ -1245,6 +1617,9 b'' | |||||
1245 | url = "https://pypi.python.org/packages/c1/29/91ba884d7d6d96691df592e9e9c2bfa57a47040ec1ff47eff18c85137152/zope.event-4.0.3.tar.gz"; |
|
1617 | url = "https://pypi.python.org/packages/c1/29/91ba884d7d6d96691df592e9e9c2bfa57a47040ec1ff47eff18c85137152/zope.event-4.0.3.tar.gz"; | |
1246 | md5 = "9a3780916332b18b8b85f522bcc3e249"; |
|
1618 | md5 = "9a3780916332b18b8b85f522bcc3e249"; | |
1247 | }; |
|
1619 | }; | |
|
1620 | meta = { | |||
|
1621 | license = [ pkgs.lib.licenses.zpt21 ]; | |||
|
1622 | }; | |||
1248 | }; |
|
1623 | }; | |
1249 | zope.interface = super.buildPythonPackage { |
|
1624 | zope.interface = super.buildPythonPackage { | |
1250 | name = "zope.interface-4.1.3"; |
|
1625 | name = "zope.interface-4.1.3"; | |
@@ -1255,6 +1630,9 b'' | |||||
1255 | url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz"; |
|
1630 | url = "https://pypi.python.org/packages/9d/81/2509ca3c6f59080123c1a8a97125eb48414022618cec0e64eb1313727bfe/zope.interface-4.1.3.tar.gz"; | |
1256 | md5 = "9ae3d24c0c7415deb249dd1a132f0f79"; |
|
1631 | md5 = "9ae3d24c0c7415deb249dd1a132f0f79"; | |
1257 | }; |
|
1632 | }; | |
|
1633 | meta = { | |||
|
1634 | license = [ pkgs.lib.licenses.zpt21 ]; | |||
|
1635 | }; | |||
1258 | }; |
|
1636 | }; | |
1259 |
|
1637 | |||
1260 | ### Test requirements |
|
1638 | ### Test requirements |
@@ -25,6 +25,7 b'' | |||||
25 | # vcsserver resides. |
|
25 | # vcsserver resides. | |
26 |
|
26 | |||
27 | { pkgs ? import <nixpkgs> {} |
|
27 | { pkgs ? import <nixpkgs> {} | |
|
28 | , doCheck ? true | |||
28 | }: |
|
29 | }: | |
29 |
|
30 | |||
30 | let |
|
31 | let |
@@ -69,7 +69,6 b' flake8==2.4.1' | |||||
69 | future==0.14.3 |
|
69 | future==0.14.3 | |
70 | futures==3.0.2 |
|
70 | futures==3.0.2 | |
71 | gprof2dot==2015.12.1 |
|
71 | gprof2dot==2015.12.1 | |
72 | greenlet==0.4.9 |
|
|||
73 | gunicorn==19.6.0 |
|
72 | gunicorn==19.6.0 | |
74 |
|
73 | |||
75 | # TODO: Needs subvertpy and blows up without Subversion headers, |
|
74 | # TODO: Needs subvertpy and blows up without Subversion headers, | |
@@ -78,7 +77,7 b' gunicorn==19.6.0' | |||||
78 |
|
77 | |||
79 | gnureadline==6.3.3 |
|
78 | gnureadline==6.3.3 | |
80 | infrae.cache==1.0.1 |
|
79 | infrae.cache==1.0.1 | |
81 |
invoke==0.1 |
|
80 | invoke==0.13.0 | |
82 | ipdb==0.8 |
|
81 | ipdb==0.8 | |
83 | ipython==3.1.0 |
|
82 | ipython==3.1.0 | |
84 | iso8601==0.1.11 |
|
83 | iso8601==0.1.11 |
@@ -22,6 +22,7 b'' | |||||
22 | Authentication modules |
|
22 | Authentication modules | |
23 | """ |
|
23 | """ | |
24 |
|
24 | |||
|
25 | import colander | |||
25 | import logging |
|
26 | import logging | |
26 | import time |
|
27 | import time | |
27 | import traceback |
|
28 | import traceback | |
@@ -97,16 +98,18 b' class RhodeCodeAuthPluginBase(object):' | |||||
97 | # Mapping of python to DB settings model types. Plugins may override or |
|
98 | # Mapping of python to DB settings model types. Plugins may override or | |
98 | # extend this mapping. |
|
99 | # extend this mapping. | |
99 | _settings_type_map = { |
|
100 | _settings_type_map = { | |
100 | str: 'str', |
|
101 | colander.String: 'unicode', | |
101 |
|
|
102 | colander.Integer: 'int', | |
102 |
|
|
103 | colander.Boolean: 'bool', | |
103 |
|
|
104 | colander.List: 'list', | |
104 | list: 'list', |
|
|||
105 | } |
|
105 | } | |
106 |
|
106 | |||
107 | def __init__(self, plugin_id): |
|
107 | def __init__(self, plugin_id): | |
108 | self._plugin_id = plugin_id |
|
108 | self._plugin_id = plugin_id | |
109 |
|
109 | |||
|
110 | def __str__(self): | |||
|
111 | return self.get_id() | |||
|
112 | ||||
110 | def _get_setting_full_name(self, name): |
|
113 | def _get_setting_full_name(self, name): | |
111 | """ |
|
114 | """ | |
112 | Return the full setting name used for storing values in the database. |
|
115 | Return the full setting name used for storing values in the database. | |
@@ -116,16 +119,19 b' class RhodeCodeAuthPluginBase(object):' | |||||
116 | # PluginSetting or to use the plugin id here. |
|
119 | # PluginSetting or to use the plugin id here. | |
117 | return 'auth_{}_{}'.format(self.name, name) |
|
120 | return 'auth_{}_{}'.format(self.name, name) | |
118 |
|
121 | |||
119 |
def _get_setting_type(self, name |
|
122 | def _get_setting_type(self, name): | |
|
123 | """ | |||
|
124 | Return the type of a setting. This type is defined by the SettingsModel | |||
|
125 | and determines how the setting is stored in DB. Optionally the suffix | |||
|
126 | `.encrypted` is appended to instruct SettingsModel to store it | |||
|
127 | encrypted. | |||
120 |
|
|
128 | """ | |
121 | Get the type as used by the SettingsModel accordingly to type of passed |
|
129 | schema_node = self.get_settings_schema().get(name) | |
122 | value. Optionally the suffix `.encrypted` is appended to instruct |
|
130 | db_type = self._settings_type_map.get( | |
123 | SettingsModel to store it encrypted. |
|
131 | type(schema_node.typ), 'unicode') | |
124 | """ |
|
|||
125 | type_ = self._settings_type_map.get(type(value), 'unicode') |
|
|||
126 | if name in self._settings_encrypted: |
|
132 | if name in self._settings_encrypted: | |
127 |
type |
|
133 | db_type = '{}.encrypted'.format(db_type) | |
128 |
return type |
|
134 | return db_type | |
129 |
|
135 | |||
130 | def is_enabled(self): |
|
136 | def is_enabled(self): | |
131 | """ |
|
137 | """ | |
@@ -161,20 +167,20 b' class RhodeCodeAuthPluginBase(object):' | |||||
161 | """ |
|
167 | """ | |
162 | return AuthnPluginSettingsSchemaBase() |
|
168 | return AuthnPluginSettingsSchemaBase() | |
163 |
|
169 | |||
164 | def get_setting_by_name(self, name): |
|
170 | def get_setting_by_name(self, name, default=None): | |
165 | """ |
|
171 | """ | |
166 | Returns a plugin setting by name. |
|
172 | Returns a plugin setting by name. | |
167 | """ |
|
173 | """ | |
168 | full_name = self._get_setting_full_name(name) |
|
174 | full_name = self._get_setting_full_name(name) | |
169 | db_setting = SettingsModel().get_setting_by_name(full_name) |
|
175 | db_setting = SettingsModel().get_setting_by_name(full_name) | |
170 |
return db_setting.app_settings_value if db_setting else |
|
176 | return db_setting.app_settings_value if db_setting else default | |
171 |
|
177 | |||
172 | def create_or_update_setting(self, name, value): |
|
178 | def create_or_update_setting(self, name, value): | |
173 | """ |
|
179 | """ | |
174 | Create or update a setting for this plugin in the persistent storage. |
|
180 | Create or update a setting for this plugin in the persistent storage. | |
175 | """ |
|
181 | """ | |
176 | full_name = self._get_setting_full_name(name) |
|
182 | full_name = self._get_setting_full_name(name) | |
177 |
type_ = self._get_setting_type(name |
|
183 | type_ = self._get_setting_type(name) | |
178 | db_setting = SettingsModel().create_or_update_setting( |
|
184 | db_setting = SettingsModel().create_or_update_setting( | |
179 | full_name, value, type_) |
|
185 | full_name, value, type_) | |
180 | return db_setting.app_settings_value |
|
186 | return db_setting.app_settings_value |
@@ -56,10 +56,12 b' class AuthnPluginViewBase(object):' | |||||
56 | errors = errors or {} |
|
56 | errors = errors or {} | |
57 | schema = self.plugin.get_settings_schema() |
|
57 | schema = self.plugin.get_settings_schema() | |
58 |
|
58 | |||
59 |
# |
|
59 | # Compute default values for the form. Priority is: | |
|
60 | # 1. Passed to this method 2. DB value 3. Schema default | |||
60 | for node in schema: |
|
61 | for node in schema: | |
61 | db_value = self.plugin.get_setting_by_name(node.name) |
|
62 | if node.name not in defaults: | |
62 | defaults.setdefault(node.name, db_value) |
|
63 | defaults[node.name] = self.plugin.get_setting_by_name( | |
|
64 | node.name, node.default) | |||
63 |
|
65 | |||
64 | template_context = { |
|
66 | template_context = { | |
65 | 'defaults': defaults, |
|
67 | 'defaults': defaults, | |
@@ -78,15 +80,17 b' class AuthnPluginViewBase(object):' | |||||
78 | View that validates and stores the plugin settings. |
|
80 | View that validates and stores the plugin settings. | |
79 | """ |
|
81 | """ | |
80 | schema = self.plugin.get_settings_schema() |
|
82 | schema = self.plugin.get_settings_schema() | |
|
83 | data = self.request.params | |||
|
84 | ||||
81 | try: |
|
85 | try: | |
82 |
valid_data = schema.deserialize( |
|
86 | valid_data = schema.deserialize(data) | |
83 | except colander.Invalid, e: |
|
87 | except colander.Invalid, e: | |
84 | # Display error message and display form again. |
|
88 | # Display error message and display form again. | |
85 | self.request.session.flash( |
|
89 | self.request.session.flash( | |
86 | _('Errors exist when saving plugin settings. ' |
|
90 | _('Errors exist when saving plugin settings. ' | |
87 | 'Please check the form inputs.'), |
|
91 | 'Please check the form inputs.'), | |
88 | queue='error') |
|
92 | queue='error') | |
89 | defaults = schema.flatten(self.request.params) |
|
93 | defaults = {key: data[key] for key in data if key in schema} | |
90 | return self.settings_get(errors=e.asdict(), defaults=defaults) |
|
94 | return self.settings_get(errors=e.asdict(), defaults=defaults) | |
91 |
|
95 | |||
92 | # Store validated data. |
|
96 | # Store validated data. |
@@ -82,7 +82,7 b' def load_environment(global_conf, app_co' | |||||
82 |
|
82 | |||
83 | config['routes.map'] = make_map(config) |
|
83 | config['routes.map'] = make_map(config) | |
84 |
|
84 | |||
85 | if asbool(config['debug']): |
|
85 | if asbool(config.get('generate_js_files', 'false')): | |
86 | jsroutes = config['routes.map'].jsroutes() |
|
86 | jsroutes = config['routes.map'].jsroutes() | |
87 | jsroutes_file_content = generate_jsroutes_content(jsroutes) |
|
87 | jsroutes_file_content = generate_jsroutes_content(jsroutes) | |
88 | jsroutes_file_path = os.path.join( |
|
88 | jsroutes_file_path = os.path.join( |
@@ -29,7 +29,8 b' def generate_jsroutes_content(jsroutes):' | |||||
29 | * DO NOT CHANGE THIS FILE MANUALLY * |
|
29 | * DO NOT CHANGE THIS FILE MANUALLY * | |
30 | * * |
|
30 | * * | |
31 | * * |
|
31 | * * | |
32 |
* This file is automatically generated when the app starts up |
|
32 | * This file is automatically generated when the app starts up with * | |
|
33 | * generate_js_files = true * | |||
33 | * * |
|
34 | * * | |
34 | * To add a route here pass jsroute=True to the route definition in the app * |
|
35 | * To add a route here pass jsroute=True to the route definition in the app * | |
35 | * * |
|
36 | * * |
@@ -1,217 +1,256 b'' | |||||
1 | { |
|
1 | { | |
2 | "cyrus-sasl-2.1.26": { |
|
2 | "nodejs-4.3.1": { | |
3 | "cyrus": "http://cyrusimap.web.cmu.edu/mediawiki/index.php/Downloads#Licensing" |
|
3 | "MIT License": "http://spdx.org/licenses/MIT" | |
4 | }, |
|
4 | }, | |
5 |
" |
|
5 | "postgresql-9.5.1": { | |
6 |
" |
|
6 | "PostgreSQL License": "http://spdx.org/licenses/PostgreSQL" | |
7 | }, |
|
7 | }, | |
8 |
" |
|
8 | "python-2.7.11": { | |
9 | "OpenSSL": "http://spdx.org/licenses/OpenSSL" |
|
9 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
10 | }, |
|
|||
11 | "python-2.7.10": { |
|
|||
12 | "Python-2.0": "http://spdx.org/licenses/Python-2.0" |
|
|||
13 | }, |
|
10 | }, | |
14 | "python2.7-Babel-1.3": { |
|
11 | "python2.7-Babel-1.3": { | |
15 |
"BSD |
|
12 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
16 | }, |
|
13 | }, | |
17 | "python2.7-Beaker-1.7.0": { |
|
14 | "python2.7-Beaker-1.7.0": { | |
18 |
"BSD |
|
15 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
19 | }, |
|
16 | }, | |
20 | "python2.7-FormEncode-1.2.4": { |
|
17 | "python2.7-FormEncode-1.2.4": { | |
21 |
"Python |
|
18 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
22 | }, |
|
19 | }, | |
23 | "python2.7-Mako-1.0.1": { |
|
20 | "python2.7-Mako-1.0.1": { | |
24 | "MIT": "http://spdx.org/licenses/MIT" |
|
21 | "MIT License": "http://spdx.org/licenses/MIT" | |
25 | }, |
|
22 | }, | |
26 | "python2.7-Markdown-2.6.2": { |
|
23 | "python2.7-Markdown-2.6.2": { | |
27 |
"BSD |
|
24 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
28 | }, |
|
25 | }, | |
29 | "python2.7-MarkupSafe-0.23": { |
|
26 | "python2.7-MarkupSafe-0.23": { | |
30 |
"BSD |
|
27 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
31 | }, |
|
28 | }, | |
32 | "python2.7-Paste-2.0.2": { |
|
29 | "python2.7-Paste-2.0.2": { | |
33 | "MIT": "http://spdx.org/licenses/MIT" |
|
30 | "MIT License": "http://spdx.org/licenses/MIT" | |
34 | }, |
|
31 | }, | |
35 | "python2.7-PasteDeploy-1.5.2": { |
|
32 | "python2.7-PasteDeploy-1.5.2": { | |
36 | "MIT": "http://spdx.org/licenses/MIT" |
|
33 | "MIT License": "http://spdx.org/licenses/MIT" | |
37 | }, |
|
34 | }, | |
38 | "python2.7-PasteScript-1.7.5": { |
|
35 | "python2.7-PasteScript-1.7.5": { | |
39 | "MIT": "http://spdx.org/licenses/MIT" |
|
36 | "MIT License": "http://spdx.org/licenses/MIT" | |
40 | }, |
|
37 | }, | |
41 | "python2.7-Pygments-2.0.2": { |
|
38 | "python2.7-Pygments-2.0.2": { | |
42 |
"BSD |
|
39 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
43 | }, |
|
40 | }, | |
44 |
"python2.7-Pylons-1.0. |
|
41 | "python2.7-Pylons-1.0.1-patch1": { | |
45 |
"BSD |
|
42 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
46 | }, |
|
43 | }, | |
47 | "python2.7-Pyro4-4.35": { |
|
44 | "python2.7-Pyro4-4.35": { | |
48 | "MIT": "http://spdx.org/licenses/MIT" |
|
45 | "MIT License": "http://spdx.org/licenses/MIT" | |
49 | }, |
|
46 | }, | |
50 | "python2.7-Routes-1.13": { |
|
47 | "python2.7-Routes-1.13": { | |
51 | "MIT": "http://spdx.org/licenses/MIT" |
|
48 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
52 | }, |
|
49 | }, | |
53 | "python2.7-SQLAlchemy-0.9.9": { |
|
50 | "python2.7-SQLAlchemy-0.9.9": { | |
54 | "MIT": "http://spdx.org/licenses/MIT" |
|
51 | "MIT License": "http://spdx.org/licenses/MIT" | |
55 | }, |
|
52 | }, | |
56 | "python2.7-Tempita-0.5.2": { |
|
53 | "python2.7-Tempita-0.5.2": { | |
57 | "MIT": "http://spdx.org/licenses/MIT" |
|
54 | "MIT License": "http://spdx.org/licenses/MIT" | |
58 | }, |
|
55 | }, | |
59 | "python2.7-URLObject-2.4.0": { |
|
56 | "python2.7-URLObject-2.4.0": { | |
60 |
"Unlicense": "http:// |
|
57 | "The Unlicense": "http://unlicense.org/" | |
61 | }, |
|
58 | }, | |
62 | "python2.7-WebError-0.10.3": { |
|
59 | "python2.7-WebError-0.10.3": { | |
63 | "MIT": "http://spdx.org/licenses/MIT" |
|
60 | "MIT License": "http://spdx.org/licenses/MIT" | |
64 | }, |
|
61 | }, | |
65 |
"python2.7-WebHelpers-1.3 |
|
62 | "python2.7-WebHelpers-1.3": { | |
66 |
"BSD |
|
63 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
67 | }, |
|
64 | }, | |
68 | "python2.7-WebHelpers2-2.0": { |
|
65 | "python2.7-WebHelpers2-2.0": { | |
69 |
" |
|
66 | "MIT License": "http://spdx.org/licenses/MIT" | |
70 | }, |
|
67 | }, | |
71 | "python2.7-WebOb-1.3.1": { |
|
68 | "python2.7-WebOb-1.3.1": { | |
72 | "MIT": "http://spdx.org/licenses/MIT" |
|
69 | "MIT License": "http://spdx.org/licenses/MIT" | |
73 | }, |
|
70 | }, | |
74 |
"python2.7-Whoosh-2.7.0 |
|
71 | "python2.7-Whoosh-2.7.0": { | |
75 |
"BSD |
|
72 | "BSD 2-clause \"Simplified\" License": "http://spdx.org/licenses/BSD-2-Clause", | |
|
73 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |||
76 | }, |
|
74 | }, | |
77 | "python2.7-alembic-0.8.4": { |
|
75 | "python2.7-alembic-0.8.4": { | |
78 | "MIT": "http://spdx.org/licenses/MIT" |
|
76 | "MIT License": "http://spdx.org/licenses/MIT" | |
79 | }, |
|
77 | }, | |
80 | "python2.7-amqplib-1.0.2": { |
|
78 | "python2.7-amqplib-1.0.2": { | |
81 |
" |
|
79 | "GNU Lesser General Public License v3.0 only": "http://spdx.org/licenses/LGPL-3.0" | |
82 | }, |
|
80 | }, | |
83 | "python2.7-anyjson-0.3.3": { |
|
81 | "python2.7-anyjson-0.3.3": { | |
84 |
"BSD |
|
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 | "python2.7-authomatic-0.1.0.post1": { | |
87 |
" |
|
88 | "MIT License": "http://spdx.org/licenses/MIT" | |
88 | }, |
|
89 | }, | |
89 |
"python2.7-backport |
|
90 | "python2.7-backport-ipaddress-0.1": { | |
90 |
"Python |
|
91 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
91 | }, |
|
92 | }, | |
92 | "python2.7-celery-2.2.10": { |
|
93 | "python2.7-celery-2.2.10": { | |
93 |
"BSD |
|
94 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
94 | }, |
|
95 | }, | |
95 |
"python2.7-click- |
|
96 | "python2.7-click-5.1": { | |
96 |
"BSD |
|
97 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
|
98 | }, | |||
|
99 | "python2.7-colander-1.2": { | |||
|
100 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |||
97 | }, |
|
101 | }, | |
98 | "python2.7-configobj-5.0.6": { |
|
102 | "python2.7-configobj-5.0.6": { | |
99 |
"BSD |
|
103 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
100 | }, |
|
104 | }, | |
101 | "python2.7-cssselect-0.9.1": { |
|
105 | "python2.7-cssselect-0.9.1": { | |
102 |
"BSD |
|
106 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
103 | }, |
|
107 | }, | |
104 | "python2.7-decorator-3.4.2": { |
|
108 | "python2.7-decorator-3.4.2": { | |
105 |
"BSD |
|
109 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
106 | }, |
|
110 | }, | |
107 | "python2.7-docutils-0.12": { |
|
111 | "python2.7-docutils-0.12": { | |
108 |
"BSD |
|
112 | "BSD 2-clause \"Simplified\" License": "http://spdx.org/licenses/BSD-2-Clause" | |
|
113 | }, | |||
|
114 | "python2.7-elasticsearch-2.3.0": { | |||
|
115 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |||
|
116 | }, | |||
|
117 | "python2.7-elasticsearch-dsl-2.0.0": { | |||
|
118 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |||
109 | }, |
|
119 | }, | |
110 | "python2.7-future-0.14.3": { |
|
120 | "python2.7-future-0.14.3": { | |
111 | "MIT": "http://spdx.org/licenses/MIT" |
|
121 | "MIT License": "http://spdx.org/licenses/MIT" | |
112 | }, |
|
122 | }, | |
113 | "python2.7-futures-3.0.2": { |
|
123 | "python2.7-futures-3.0.2": { | |
114 |
"BSD |
|
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 |
|
129 | "python2.7-gunicorn-19.6.0": { | |
117 | "MIT": "http://spdx.org/licenses/MIT" |
|
130 | "MIT License": "http://spdx.org/licenses/MIT" | |
118 | }, |
|
131 | }, | |
119 |
"python2.7- |
|
132 | "python2.7-infrae.cache-1.0.1": { | |
120 |
" |
|
133 | "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1" | |
121 | }, |
|
134 | }, | |
122 | "python2.7-ipython-3.1.0": { |
|
135 | "python2.7-ipython-3.1.0": { | |
123 |
"BSD |
|
136 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
124 | }, |
|
|||
125 | "python2.7-kombu-1.5.1-patch1": { |
|
|||
126 | "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause" |
|
|||
127 | }, |
|
137 | }, | |
128 |
"python2.7- |
|
138 | "python2.7-iso8601-0.1.11": { | |
129 | "expat": "http://directory.fsf.org/wiki/License:Expat" |
|
139 | "MIT License": "http://spdx.org/licenses/MIT" | |
130 | }, |
|
140 | }, | |
131 |
"python2.7- |
|
141 | "python2.7-kombu-1.5.1": { | |
132 | "repoze": "http://repoze.org/license.html" |
|
142 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
133 | }, |
|
143 | }, | |
134 | "python2.7-msgpack-python-0.4.6": { |
|
144 | "python2.7-msgpack-python-0.4.6": { | |
135 |
"Apache |
|
145 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |
136 | }, |
|
|||
137 | "python2.7-objgraph-2.0.0": { |
|
|||
138 | "MIT": "http://spdx.org/licenses/MIT" |
|
|||
139 | }, |
|
146 | }, | |
140 | "python2.7-packaging-15.2": { |
|
147 | "python2.7-packaging-15.2": { | |
141 |
"Apache |
|
148 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |
142 | }, |
|
149 | }, | |
143 | "python2.7-psutil-2.2.1": { |
|
150 | "python2.7-psutil-2.2.1": { | |
144 |
"BSD |
|
151 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
145 | }, |
|
152 | }, | |
146 | "python2.7-psycopg2-2.6": { |
|
153 | "python2.7-psycopg2-2.6": { | |
147 |
" |
|
154 | "GNU Lesser General Public License v3.0 or later": "http://spdx.org/licenses/LGPL-3.0+" | |
148 | }, |
|
155 | }, | |
149 | "python2.7-py-1.4.29": { |
|
156 | "python2.7-py-1.4.29": { | |
150 | "MIT": "http://spdx.org/licenses/MIT" |
|
157 | "MIT License": "http://spdx.org/licenses/MIT" | |
151 | }, |
|
158 | }, | |
152 | "python2.7-py-bcrypt-0.4": { |
|
159 | "python2.7-py-bcrypt-0.4": { | |
153 |
"BSD |
|
160 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" | |
154 | }, |
|
161 | }, | |
155 | "python2.7-pycrypto-2.6.1": { |
|
162 | "python2.7-pycrypto-2.6.1": { | |
156 |
" |
|
163 | "Public Domain": null | |
|
164 | }, | |||
|
165 | "python2.7-pycurl-7.19.5": { | |||
|
166 | "MIT License": "http://spdx.org/licenses/MIT" | |||
157 | }, |
|
167 | }, | |
158 | "python2.7-pyparsing-1.5.7": { |
|
168 | "python2.7-pyparsing-1.5.7": { | |
159 | "MIT": "http://spdx.org/licenses/MIT" |
|
169 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
170 | }, | |||
|
171 | "python2.7-pyramid-1.6.1": { | |||
|
172 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |||
|
173 | }, | |||
|
174 | "python2.7-pyramid-beaker-0.8": { | |||
|
175 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |||
|
176 | }, | |||
|
177 | "python2.7-pyramid-debugtoolbar-2.4.2": { | |||
|
178 | "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause", | |||
|
179 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |||
|
180 | }, | |||
|
181 | "python2.7-pyramid-mako-1.0.2": { | |||
|
182 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |||
160 | }, |
|
183 | }, | |
161 | "python2.7-pysqlite-2.6.3": { |
|
184 | "python2.7-pysqlite-2.6.3": { | |
162 |
" |
|
185 | "libpng License": "http://spdx.org/licenses/Libpng", | |
163 |
" |
|
186 | "zlib License": "http://spdx.org/licenses/Zlib" | |
164 | }, |
|
187 | }, | |
165 | "python2.7-pytest-2.8.5": { |
|
188 | "python2.7-pytest-2.8.5": { | |
166 | "MIT": "http://spdx.org/licenses/MIT" |
|
189 | "MIT License": "http://spdx.org/licenses/MIT" | |
|
190 | }, | |||
|
191 | "python2.7-pytest-runner-2.7.1": { | |||
|
192 | "MIT License": "http://spdx.org/licenses/MIT" | |||
167 | }, |
|
193 | }, | |
168 | "python2.7-python-dateutil-1.5": { |
|
194 | "python2.7-python-dateutil-1.5": { | |
169 | "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" |
|
195 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
|
196 | }, | |||
|
197 | "python2.7-python-editor-1.0.1": { | |||
|
198 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |||
170 | }, |
|
199 | }, | |
171 | "python2.7-python-ldap-2.4.19": { |
|
200 | "python2.7-python-ldap-2.4.19": { | |
172 |
"Python |
|
201 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |
|
202 | }, | |||
|
203 | "python2.7-python-memcached-1.57": { | |||
|
204 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0" | |||
173 | }, |
|
205 | }, | |
174 | "python2.7-pytz-2015.4": { |
|
206 | "python2.7-pytz-2015.4": { | |
175 | "MIT": "http://spdx.org/licenses/MIT" |
|
207 | "MIT License": "http://spdx.org/licenses/MIT" | |
176 | }, |
|
208 | }, | |
177 | "python2.7-recaptcha-client-1.0.6": { |
|
209 | "python2.7-recaptcha-client-1.0.6": { | |
178 | "MIT": "http://spdx.org/licenses/MIT" |
|
210 | "MIT License": "http://spdx.org/licenses/MIT" | |
179 | }, |
|
211 | }, | |
180 | "python2.7-repoze.lru-0.6": { |
|
212 | "python2.7-repoze.lru-0.6": { | |
181 |
" |
|
213 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |
182 | }, |
|
214 | }, | |
183 |
"python2.7-requests-2. |
|
215 | "python2.7-requests-2.9.1": { | |
184 |
"A |
|
216 | "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0" | |
185 | }, |
|
217 | }, | |
186 |
"python2.7-serpent-1.1 |
|
218 | "python2.7-serpent-1.12": { | |
187 | "MIT": "http://spdx.org/licenses/MIT" |
|
219 | "MIT License": "http://spdx.org/licenses/MIT" | |
188 | }, |
|
220 | }, | |
189 |
"python2.7-set |
|
221 | "python2.7-setuptools-19.4": { | |
190 | "BSD-2-Clause": "http://spdx.org/licenses/BSD-2-Clause" |
|
222 | "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0", | |
|
223 | "Zope Public License 2.0": "http://spdx.org/licenses/ZPL-2.0" | |||
191 | }, |
|
224 | }, | |
192 |
"python2.7-setuptools- |
|
225 | "python2.7-setuptools-scm-1.11.0": { | |
193 | "PSF": null, |
|
226 | "MIT License": "http://spdx.org/licenses/MIT" | |
194 | "ZPL": null |
|
|||
195 | }, |
|
227 | }, | |
196 | "python2.7-simplejson-3.7.2": { |
|
228 | "python2.7-simplejson-3.7.2": { | |
197 |
" |
|
229 | "Academic Free License": "http://spdx.org/licenses/AFL-2.1", | |
|
230 | "MIT License": "http://spdx.org/licenses/MIT" | |||
198 | }, |
|
231 | }, | |
199 | "python2.7-six-1.9.0": { |
|
232 | "python2.7-six-1.9.0": { | |
200 | "MIT": "http://spdx.org/licenses/MIT" |
|
233 | "MIT License": "http://spdx.org/licenses/MIT" | |
201 | }, |
|
234 | }, | |
202 | "python2.7-subprocess32-3.2.6": { |
|
235 | "python2.7-translationstring-1.3": { | |
203 | "Python-2.0": "http://spdx.org/licenses/Python-2.0" |
|
236 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |
204 | }, |
|
237 | }, | |
205 |
"python2.7- |
|
238 | "python2.7-urllib3-1.16": { | |
206 |
" |
|
239 | "MIT License": "http://spdx.org/licenses/MIT" | |
207 | }, |
|
240 | }, | |
208 |
"python2.7- |
|
241 | "python2.7-venusian-1.0": { | |
209 | "APSL-2.0": "http://spdx.org/licenses/APSL-2.0" |
|
242 | "Repoze License": "http://www.repoze.org/LICENSE.txt" | |
210 | }, |
|
243 | }, | |
211 | "python2.7-waitress-0.8.9": { |
|
244 | "python2.7-waitress-0.8.9": { | |
212 |
"Z |
|
245 | "Zope Public License 2.1": "http://spdx.org/licenses/ZPL-2.1" | |
213 | }, |
|
246 | }, | |
214 | "python2.7-zope.cachedescriptors-4.0.0": { |
|
247 | "python2.7-zope.cachedescriptors-4.0.0": { | |
215 |
"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 | from paste.registry import RegistryManager |
|
26 | from paste.registry import RegistryManager | |
27 | from paste.gzipper import make_gzip_middleware |
|
27 | from paste.gzipper import make_gzip_middleware | |
28 | from pylons.middleware import ErrorHandler, StatusCodeRedirect |
|
|||
29 | from pylons.wsgiapp import PylonsApp |
|
28 | from pylons.wsgiapp import PylonsApp | |
30 | from pyramid.authorization import ACLAuthorizationPolicy |
|
29 | from pyramid.authorization import ACLAuthorizationPolicy | |
31 | from pyramid.config import Configurator |
|
30 | from pyramid.config import Configurator | |
32 | from pyramid.static import static_view |
|
31 | from pyramid.static import static_view | |
33 | from pyramid.settings import asbool, aslist |
|
32 | from pyramid.settings import asbool, aslist | |
34 | from pyramid.wsgi import wsgiapp |
|
33 | from pyramid.wsgi import wsgiapp | |
|
34 | from pyramid.httpexceptions import HTTPError, HTTPInternalServerError | |||
|
35 | import pyramid.httpexceptions as httpexceptions | |||
|
36 | from pyramid.renderers import render_to_response, render | |||
35 | from routes.middleware import RoutesMiddleware |
|
37 | from routes.middleware import RoutesMiddleware | |
36 | import routes.util |
|
38 | import routes.util | |
37 |
|
39 | |||
@@ -87,38 +89,15 b' def make_app(global_conf, full_stack=Tru' | |||||
87 | app = csrf.OriginChecker(app, expected_origin, |
|
89 | app = csrf.OriginChecker(app, expected_origin, | |
88 | skip_urls=[routes.util.url_for('api')]) |
|
90 | skip_urls=[routes.util.url_for('api')]) | |
89 |
|
91 | |||
90 | # Add RoutesMiddleware. Currently we have two instances in the stack. This |
|
|||
91 | # is the lower one to make the StatusCodeRedirect middleware happy. |
|
|||
92 | # TODO: johbo: This is not optimal, search for a better solution. |
|
|||
93 | app = RoutesMiddleware(app, config['routes.map']) |
|
|||
94 |
|
||||
95 | # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares) |
|
|||
96 | if asbool(config['pdebug']): |
|
|||
97 | from rhodecode.lib.profiler import ProfilingMiddleware |
|
|||
98 | app = ProfilingMiddleware(app) |
|
|||
99 |
|
||||
100 | # Protect from VCS Server error related pages when server is not available |
|
|||
101 | vcs_server_enabled = asbool(config.get('vcs.server.enable', 'true')) |
|
|||
102 | if not vcs_server_enabled: |
|
|||
103 | app = DisableVCSPagesWrapper(app) |
|
|||
104 |
|
92 | |||
105 | if asbool(full_stack): |
|
93 | if asbool(full_stack): | |
106 |
|
94 | |||
107 | # Appenlight monitoring and error handler |
|
95 | # Appenlight monitoring and error handler | |
108 | app, appenlight_client = wrap_in_appenlight_if_enabled(app, config) |
|
96 | app, appenlight_client = wrap_in_appenlight_if_enabled(app, config) | |
109 |
|
97 | |||
110 | # Handle Python exceptions |
|
|||
111 | app = ErrorHandler(app, global_conf, **config['pylons.errorware']) |
|
|||
112 |
|
||||
113 | # we want our low level middleware to get to the request ASAP. We don't |
|
98 | # we want our low level middleware to get to the request ASAP. We don't | |
114 | # need any pylons stack middleware in them |
|
99 | # need any pylons stack middleware in them | |
115 | app = VCSMiddleware(app, config, appenlight_client) |
|
100 | app = VCSMiddleware(app, config, appenlight_client) | |
116 | # Display error documents for 401, 403, 404 status codes (and |
|
|||
117 | # 500 when debug is disabled) |
|
|||
118 | if asbool(config['debug']): |
|
|||
119 | app = StatusCodeRedirect(app) |
|
|||
120 | else: |
|
|||
121 | app = StatusCodeRedirect(app, [400, 401, 403, 404, 500]) |
|
|||
122 |
|
101 | |||
123 | # Establish the Registry for this application |
|
102 | # Establish the Registry for this application | |
124 | app = RegistryManager(app) |
|
103 | app = RegistryManager(app) | |
@@ -176,16 +155,69 b' def add_pylons_compat_data(registry, glo' | |||||
176 | registry._pylons_compat_settings = settings |
|
155 | registry._pylons_compat_settings = settings | |
177 |
|
156 | |||
178 |
|
157 | |||
|
158 | def webob_to_pyramid_http_response(webob_response): | |||
|
159 | ResponseClass = httpexceptions.status_map[webob_response.status_int] | |||
|
160 | pyramid_response = ResponseClass(webob_response.status) | |||
|
161 | pyramid_response.status = webob_response.status | |||
|
162 | pyramid_response.headers.update(webob_response.headers) | |||
|
163 | if pyramid_response.headers['content-type'] == 'text/html': | |||
|
164 | pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8' | |||
|
165 | return pyramid_response | |||
|
166 | ||||
|
167 | ||||
|
168 | def error_handler(exception, request): | |||
|
169 | # TODO: dan: replace the old pylons error controller with this | |||
|
170 | from rhodecode.model.settings import SettingsModel | |||
|
171 | from rhodecode.lib.utils2 import AttributeDict | |||
|
172 | ||||
|
173 | try: | |||
|
174 | rc_config = SettingsModel().get_all_settings() | |||
|
175 | except Exception: | |||
|
176 | log.exception('failed to fetch settings') | |||
|
177 | rc_config = {} | |||
|
178 | ||||
|
179 | base_response = HTTPInternalServerError() | |||
|
180 | # prefer original exception for the response since it may have headers set | |||
|
181 | if isinstance(exception, HTTPError): | |||
|
182 | base_response = exception | |||
|
183 | ||||
|
184 | c = AttributeDict() | |||
|
185 | c.error_message = base_response.status | |||
|
186 | c.error_explanation = base_response.explanation or str(base_response) | |||
|
187 | c.visual = AttributeDict() | |||
|
188 | ||||
|
189 | c.visual.rhodecode_support_url = ( | |||
|
190 | request.registry.settings.get('rhodecode_support_url') or | |||
|
191 | request.route_url('rhodecode_support') | |||
|
192 | ) | |||
|
193 | c.redirect_time = 0 | |||
|
194 | c.rhodecode_name = rc_config.get('rhodecode_title', '') | |||
|
195 | if not c.rhodecode_name: | |||
|
196 | c.rhodecode_name = 'Rhodecode' | |||
|
197 | ||||
|
198 | response = render_to_response( | |||
|
199 | '/errors/error_document.html', {'c': c}, request=request, | |||
|
200 | response=base_response) | |||
|
201 | ||||
|
202 | return response | |||
|
203 | ||||
|
204 | ||||
179 | def includeme(config): |
|
205 | def includeme(config): | |
180 | settings = config.registry.settings |
|
206 | settings = config.registry.settings | |
181 |
|
207 | |||
|
208 | if asbool(settings.get('appenlight', 'false')): | |||
|
209 | config.include('appenlight_client.ext.pyramid_tween') | |||
|
210 | ||||
182 | # Includes which are required. The application would fail without them. |
|
211 | # Includes which are required. The application would fail without them. | |
183 | config.include('pyramid_mako') |
|
212 | config.include('pyramid_mako') | |
184 | config.include('pyramid_beaker') |
|
213 | config.include('pyramid_beaker') | |
|
214 | config.include('rhodecode.admin') | |||
185 | config.include('rhodecode.authentication') |
|
215 | config.include('rhodecode.authentication') | |
186 | config.include('rhodecode.login') |
|
216 | config.include('rhodecode.login') | |
187 | config.include('rhodecode.tweens') |
|
217 | config.include('rhodecode.tweens') | |
188 | config.include('rhodecode.api') |
|
218 | config.include('rhodecode.api') | |
|
219 | config.add_route( | |||
|
220 | 'rhodecode_support', 'https://rhodecode.com/help/', static=True) | |||
189 |
|
221 | |||
190 | # Set the authorization policy. |
|
222 | # Set the authorization policy. | |
191 | authz_policy = ACLAuthorizationPolicy() |
|
223 | authz_policy = ACLAuthorizationPolicy() | |
@@ -204,16 +236,52 b' def includeme(config):' | |||||
204 | for inc in includes: |
|
236 | for inc in includes: | |
205 | config.include(inc) |
|
237 | config.include(inc) | |
206 |
|
238 | |||
|
239 | pylons_app = make_app( | |||
|
240 | config.registry._pylons_compat_global_config, | |||
|
241 | **config.registry._pylons_compat_settings) | |||
|
242 | config.registry._pylons_compat_config = pylons_app.config | |||
|
243 | ||||
|
244 | pylons_app_as_view = wsgiapp(pylons_app) | |||
|
245 | ||||
|
246 | # Protect from VCS Server error related pages when server is not available | |||
|
247 | vcs_server_enabled = asbool(settings.get('vcs.server.enable', 'true')) | |||
|
248 | if not vcs_server_enabled: | |||
|
249 | pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view) | |||
|
250 | ||||
|
251 | ||||
|
252 | def pylons_app_with_error_handler(context, request): | |||
|
253 | """ | |||
|
254 | Handle exceptions from rc pylons app: | |||
|
255 | ||||
|
256 | - old webob type exceptions get converted to pyramid exceptions | |||
|
257 | - pyramid exceptions are passed to the error handler view | |||
|
258 | """ | |||
|
259 | try: | |||
|
260 | response = pylons_app_as_view(context, request) | |||
|
261 | if 400 <= response.status_int <= 599: # webob type error responses | |||
|
262 | return error_handler( | |||
|
263 | webob_to_pyramid_http_response(response), request) | |||
|
264 | except HTTPError as e: # pyramid type exceptions | |||
|
265 | return error_handler(e, request) | |||
|
266 | except Exception: | |||
|
267 | if settings.get('debugtoolbar.enabled', False): | |||
|
268 | raise | |||
|
269 | return error_handler(HTTPInternalServerError(), request) | |||
|
270 | return response | |||
|
271 | ||||
207 | # This is the glue which allows us to migrate in chunks. By registering the |
|
272 | # This is the glue which allows us to migrate in chunks. By registering the | |
208 | # pylons based application as the "Not Found" view in Pyramid, we will |
|
273 | # pylons based application as the "Not Found" view in Pyramid, we will | |
209 | # fallback to the old application each time the new one does not yet know |
|
274 | # fallback to the old application each time the new one does not yet know | |
210 | # how to handle a request. |
|
275 | # how to handle a request. | |
211 | pylons_app = make_app( |
|
276 | config.add_notfound_view(pylons_app_with_error_handler) | |
212 | config.registry._pylons_compat_global_config, |
|
277 | ||
213 | **config.registry._pylons_compat_settings) |
|
278 | if settings.get('debugtoolbar.enabled', False): | |
214 | config.registry._pylons_compat_config = pylons_app.config |
|
279 | # if toolbar, then only http type exceptions get caught and rendered | |
215 | pylons_app_as_view = wsgiapp(pylons_app) |
|
280 | ExcClass = HTTPError | |
216 | config.add_notfound_view(pylons_app_as_view) |
|
281 | else: | |
|
282 | # if no toolbar, then any exception gets caught and rendered | |||
|
283 | ExcClass = Exception | |||
|
284 | config.add_view(error_handler, context=ExcClass) | |||
217 |
|
285 | |||
218 |
|
286 | |||
219 | def includeme_last(config): |
|
287 | def includeme_last(config): | |
@@ -253,13 +321,16 b' def wrap_app_in_wsgi_middlewares(pyramid' | |||||
253 | # enable https redirects based on HTTP_X_URL_SCHEME set by proxy |
|
321 | # enable https redirects based on HTTP_X_URL_SCHEME set by proxy | |
254 | pyramid_app = HttpsFixup(pyramid_app, settings) |
|
322 | pyramid_app = HttpsFixup(pyramid_app, settings) | |
255 |
|
323 | |||
256 | # Add RoutesMiddleware. Currently we have two instances in the stack. This |
|
324 | # Add RoutesMiddleware to support the pylons compatibility tween during | |
257 | # is the upper one to support the pylons compatibility tween during |
|
|||
258 |
|
325 | |||
259 | # migration to pyramid. |
|
326 | # migration to pyramid. | |
260 | pyramid_app = RoutesMiddleware( |
|
327 | pyramid_app = RoutesMiddleware( | |
261 | pyramid_app, config.registry._pylons_compat_config['routes.map']) |
|
328 | pyramid_app, config.registry._pylons_compat_config['routes.map']) | |
262 |
|
329 | |||
|
330 | if asbool(settings.get('appenlight', 'false')): | |||
|
331 | pyramid_app, _ = wrap_in_appenlight_if_enabled( | |||
|
332 | pyramid_app, config.registry._pylons_compat_config) | |||
|
333 | ||||
263 | # TODO: johbo: Don't really see why we enable the gzip middleware when |
|
334 | # TODO: johbo: Don't really see why we enable the gzip middleware when | |
264 | # serving static files, might be something that should have its own setting |
|
335 | # serving static files, might be something that should have its own setting | |
265 | # as well? |
|
336 | # as well? |
@@ -166,10 +166,6 b' def make_map(config):' | |||||
166 | def check_int(environ, match_dict): |
|
166 | def check_int(environ, match_dict): | |
167 | return match_dict.get('id').isdigit() |
|
167 | return match_dict.get('id').isdigit() | |
168 |
|
168 | |||
169 | # The ErrorController route (handles 404/500 error pages); it should |
|
|||
170 | # likely stay at the top, ensuring it can always be resolved |
|
|||
171 | rmap.connect('/error/{action}', controller='error') |
|
|||
172 | rmap.connect('/error/{action}/{id}', controller='error') |
|
|||
173 |
|
169 | |||
174 | #========================================================================== |
|
170 | #========================================================================== | |
175 | # CUSTOM ROUTES HERE |
|
171 | # CUSTOM ROUTES HERE | |
@@ -509,10 +505,6 b' def make_map(config):' | |||||
509 | m.connect('admin_settings_labs', '/settings/labs', |
|
505 | m.connect('admin_settings_labs', '/settings/labs', | |
510 | action='settings_labs', conditions={'method': ['GET']}) |
|
506 | action='settings_labs', conditions={'method': ['GET']}) | |
511 |
|
507 | |||
512 | m.connect('admin_settings_open_source', '/settings/open_source', |
|
|||
513 | action='settings_open_source', |
|
|||
514 | conditions={'method': ['GET']}) |
|
|||
515 |
|
||||
516 | # ADMIN MY ACCOUNT |
|
508 | # ADMIN MY ACCOUNT | |
517 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
509 | with rmap.submapper(path_prefix=ADMIN_PREFIX, | |
518 | controller='admin/my_account') as m: |
|
510 | controller='admin/my_account') as m: |
@@ -68,21 +68,25 b' def configure_vcs(config):' | |||||
68 |
|
68 | |||
69 |
|
69 | |||
70 | def initialize_database(config): |
|
70 | def initialize_database(config): | |
71 | from rhodecode.lib.utils2 import engine_from_config |
|
71 | from rhodecode.lib.utils2 import engine_from_config, get_encryption_key | |
72 | engine = engine_from_config(config, 'sqlalchemy.db1.') |
|
72 | engine = engine_from_config(config, 'sqlalchemy.db1.') | |
73 |
init_model(engine, encryption_key=config |
|
73 | init_model(engine, encryption_key=get_encryption_key(config)) | |
74 |
|
74 | |||
75 |
|
75 | |||
76 | def initialize_test_environment(settings, test_env=None): |
|
76 | def initialize_test_environment(settings, test_env=None): | |
77 | if test_env is None: |
|
77 | if test_env is None: | |
78 | test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0)) |
|
78 | test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0)) | |
79 |
|
79 | |||
80 |
from rhodecode.lib.utils import |
|
80 | from rhodecode.lib.utils import ( | |
|
81 | create_test_directory, create_test_database, create_test_repositories, | |||
|
82 | create_test_index) | |||
81 | from rhodecode.tests import TESTS_TMP_PATH |
|
83 | from rhodecode.tests import TESTS_TMP_PATH | |
82 | # test repos |
|
84 | # test repos | |
83 | if test_env: |
|
85 | if test_env: | |
84 |
create_test_ |
|
86 | create_test_directory(TESTS_TMP_PATH) | |
85 |
create_test_ |
|
87 | create_test_database(TESTS_TMP_PATH, settings) | |
|
88 | create_test_repositories(TESTS_TMP_PATH, settings) | |||
|
89 | create_test_index(TESTS_TMP_PATH, settings) | |||
86 |
|
90 | |||
87 |
|
91 | |||
88 | def get_vcs_server_protocol(config): |
|
92 | def get_vcs_server_protocol(config): |
@@ -99,7 +99,7 b' class RepoGroupsController(BaseControlle' | |||||
99 | if repo_group.user: |
|
99 | if repo_group.user: | |
100 | data.update({'user': repo_group.user.username}) |
|
100 | data.update({'user': repo_group.user.username}) | |
101 | else: |
|
101 | else: | |
102 | replacement_user = User.get_first_admin().username |
|
102 | replacement_user = User.get_first_super_admin().username | |
103 | data.update({'user': replacement_user}) |
|
103 | data.update({'user': replacement_user}) | |
104 |
|
104 | |||
105 | # fill repository group users |
|
105 | # fill repository group users | |
@@ -246,11 +246,10 b' class RepoGroupsController(BaseControlle' | |||||
246 | repo_group=c.repo_group) |
|
246 | repo_group=c.repo_group) | |
247 |
|
247 | |||
248 | repo_group_form = RepoGroupForm( |
|
248 | repo_group_form = RepoGroupForm( | |
249 | edit=True, |
|
249 | edit=True, old_data=c.repo_group.get_dict(), | |
250 | old_data=c.repo_group.get_dict(), |
|
|||
251 | available_groups=c.repo_groups_choices, |
|
250 | available_groups=c.repo_groups_choices, | |
252 | can_create_in_root=can_create_in_root, |
|
251 | can_create_in_root=can_create_in_root, allow_disabled=True)() | |
253 | )() |
|
252 | ||
254 | try: |
|
253 | try: | |
255 | form_result = repo_group_form.to_python(dict(request.POST)) |
|
254 | form_result = repo_group_form.to_python(dict(request.POST)) | |
256 | gr_name = form_result['group_name'] |
|
255 | gr_name = form_result['group_name'] |
@@ -248,9 +248,9 b' class ReposController(BaseRepoController' | |||||
248 | task_id = request.GET.get('task_id') |
|
248 | task_id = request.GET.get('task_id') | |
249 |
|
249 | |||
250 | if task_id and task_id not in ['None']: |
|
250 | if task_id and task_id not in ['None']: | |
251 |
|
|
251 | import rhodecode | |
252 | from celery.result import AsyncResult |
|
252 | from celery.result import AsyncResult | |
253 | if CELERY_ENABLED: |
|
253 | if rhodecode.CELERY_ENABLED: | |
254 | task = AsyncResult(task_id) |
|
254 | task = AsyncResult(task_id) | |
255 | if task.failed(): |
|
255 | if task.failed(): | |
256 | msg = self._log_creation_exception(task.result, c.repo) |
|
256 | msg = self._log_creation_exception(task.result, c.repo) | |
@@ -307,9 +307,9 b' class ReposController(BaseRepoController' | |||||
307 | 'repo_group': repo.group.get_dict() if repo.group else {}, |
|
307 | 'repo_group': repo.group.get_dict() if repo.group else {}, | |
308 | 'repo_type': repo.repo_type, |
|
308 | 'repo_type': repo.repo_type, | |
309 | } |
|
309 | } | |
310 |
_form = RepoForm( |
|
310 | _form = RepoForm( | |
311 |
|
|
311 | edit=True, old_data=old_data, repo_groups=c.repo_groups_choices, | |
312 |
|
|
312 | landing_revs=c.landing_revs_choices, allow_disabled=True)() | |
313 |
|
313 | |||
314 | try: |
|
314 | try: | |
315 | form_result = _form.to_python(dict(request.POST)) |
|
315 | form_result = _form.to_python(dict(request.POST)) |
@@ -37,6 +37,7 b' from pylons.i18n.translation import _, l' | |||||
37 | from webob.exc import HTTPBadRequest |
|
37 | from webob.exc import HTTPBadRequest | |
38 |
|
38 | |||
39 | import rhodecode |
|
39 | import rhodecode | |
|
40 | from rhodecode.admin.navigation import navigation_list | |||
40 | from rhodecode.lib import auth |
|
41 | from rhodecode.lib import auth | |
41 | from rhodecode.lib import helpers as h |
|
42 | from rhodecode.lib import helpers as h | |
42 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
43 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |
@@ -47,7 +48,7 b' from rhodecode.lib.utils2 import (' | |||||
47 | str2bool, safe_unicode, AttributeDict, safe_int) |
|
48 | str2bool, safe_unicode, AttributeDict, safe_int) | |
48 | from rhodecode.lib.compat import OrderedDict |
|
49 | from rhodecode.lib.compat import OrderedDict | |
49 | from rhodecode.lib.ext_json import json |
|
50 | from rhodecode.lib.ext_json import json | |
50 |
from rhodecode.lib.utils import jsonify |
|
51 | from rhodecode.lib.utils import jsonify | |
51 |
|
52 | |||
52 | from rhodecode.model.db import RhodeCodeUi, Repository |
|
53 | from rhodecode.model.db import RhodeCodeUi, Repository | |
53 | from rhodecode.model.forms import ApplicationSettingsForm, \ |
|
54 | from rhodecode.model.forms import ApplicationSettingsForm, \ | |
@@ -60,8 +61,9 b' from rhodecode.model.meta import Session' | |||||
60 | from rhodecode.model.settings import ( |
|
61 | from rhodecode.model.settings import ( | |
61 | IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound, |
|
62 | IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound, | |
62 | SettingsModel) |
|
63 | SettingsModel) | |
|
64 | ||||
63 | from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER |
|
65 | from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER | |
64 | from rhodecode.model.user import UserModel |
|
66 | ||
65 |
|
67 | |||
66 | log = logging.getLogger(__name__) |
|
68 | log = logging.getLogger(__name__) | |
67 |
|
69 | |||
@@ -78,7 +80,7 b' class SettingsController(BaseController)' | |||||
78 | super(SettingsController, self).__before__() |
|
80 | super(SettingsController, self).__before__() | |
79 | c.labs_active = str2bool( |
|
81 | c.labs_active = str2bool( | |
80 | rhodecode.CONFIG.get('labs_settings_active', 'false')) |
|
82 | rhodecode.CONFIG.get('labs_settings_active', 'false')) | |
81 |
c.navlist = navigation |
|
83 | c.navlist = navigation_list(request) | |
82 |
|
84 | |||
83 | def _get_hg_ui_settings(self): |
|
85 | def _get_hg_ui_settings(self): | |
84 | ret = RhodeCodeUi.query().all() |
|
86 | ret = RhodeCodeUi.query().all() | |
@@ -257,8 +259,8 b' class SettingsController(BaseController)' | |||||
257 | Session().add(sett) |
|
259 | Session().add(sett) | |
258 |
|
260 | |||
259 | Session().commit() |
|
261 | Session().commit() | |
|
262 | SettingsModel().invalidate_settings_cache() | |||
260 | h.flash(_('Updated application settings'), category='success') |
|
263 | h.flash(_('Updated application settings'), category='success') | |
261 |
|
||||
262 | except Exception: |
|
264 | except Exception: | |
263 | log.exception("Exception while updating application settings") |
|
265 | log.exception("Exception while updating application settings") | |
264 | h.flash( |
|
266 | h.flash( | |
@@ -321,7 +323,7 b' class SettingsController(BaseController)' | |||||
321 | Session().add(sett) |
|
323 | Session().add(sett) | |
322 |
|
324 | |||
323 | Session().commit() |
|
325 | Session().commit() | |
324 |
|
326 | SettingsModel().invalidate_settings_cache() | ||
325 | h.flash(_('Updated visualisation settings'), category='success') |
|
327 | h.flash(_('Updated visualisation settings'), category='success') | |
326 | except Exception: |
|
328 | except Exception: | |
327 | log.exception("Exception updating visualization settings") |
|
329 | log.exception("Exception updating visualization settings") | |
@@ -403,6 +405,7 b' class SettingsController(BaseController)' | |||||
403 |
|
405 | |||
404 | Session().commit() |
|
406 | Session().commit() | |
405 |
|
407 | |||
|
408 | SettingsModel().invalidate_settings_cache() | |||
406 | h.flash(_('Updated issue tracker entries'), category='success') |
|
409 | h.flash(_('Updated issue tracker entries'), category='success') | |
407 | return redirect(url('admin_settings_issuetracker')) |
|
410 | return redirect(url('admin_settings_issuetracker')) | |
408 |
|
411 | |||
@@ -523,6 +526,7 b' class SettingsController(BaseController)' | |||||
523 | def settings_system(self): |
|
526 | def settings_system(self): | |
524 | """GET /admin/settings/system: All items in the collection""" |
|
527 | """GET /admin/settings/system: All items in the collection""" | |
525 | # url('admin_settings_system') |
|
528 | # url('admin_settings_system') | |
|
529 | snapshot = str2bool(request.GET.get('snapshot')) | |||
526 | c.active = 'system' |
|
530 | c.active = 'system' | |
527 |
|
531 | |||
528 | defaults = self._form_defaults() |
|
532 | defaults = self._form_defaults() | |
@@ -557,6 +561,35 b' class SettingsController(BaseController)' | |||||
557 | except TypeError: |
|
561 | except TypeError: | |
558 | c.system_memory = 'NOT AVAILABLE' |
|
562 | c.system_memory = 'NOT AVAILABLE' | |
559 |
|
563 | |||
|
564 | rhodecode_ini_safe = rhodecode.CONFIG.copy() | |||
|
565 | blacklist = [ | |||
|
566 | 'rhodecode_license_key', | |||
|
567 | 'routes.map', | |||
|
568 | 'pylons.h', | |||
|
569 | 'pylons.app_globals', | |||
|
570 | 'pylons.environ_config', | |||
|
571 | 'sqlalchemy.db1.url', | |||
|
572 | ('app_conf', 'sqlalchemy.db1.url') | |||
|
573 | ] | |||
|
574 | for k in blacklist: | |||
|
575 | if isinstance(k, tuple): | |||
|
576 | section, key = k | |||
|
577 | if section in rhodecode_ini_safe: | |||
|
578 | rhodecode_ini_safe[section].pop(key, None) | |||
|
579 | else: | |||
|
580 | rhodecode_ini_safe.pop(k, None) | |||
|
581 | ||||
|
582 | c.rhodecode_ini_safe = rhodecode_ini_safe | |||
|
583 | ||||
|
584 | # TODO: marcink, figure out how to allow only selected users to do this | |||
|
585 | c.allowed_to_snapshot = False | |||
|
586 | ||||
|
587 | if snapshot: | |||
|
588 | if c.allowed_to_snapshot: | |||
|
589 | return render('admin/settings/settings_system_snapshot.html') | |||
|
590 | else: | |||
|
591 | h.flash('You are not allowed to do this', category='warning') | |||
|
592 | ||||
560 | return htmlfill.render( |
|
593 | return htmlfill.render( | |
561 | render('admin/settings/settings.html'), |
|
594 | render('admin/settings/settings.html'), | |
562 | defaults=defaults, |
|
595 | defaults=defaults, | |
@@ -708,6 +741,7 b' class SettingsController(BaseController)' | |||||
708 | category='error') |
|
741 | category='error') | |
709 | else: |
|
742 | else: | |
710 | Session().commit() |
|
743 | Session().commit() | |
|
744 | SettingsModel().invalidate_settings_cache() | |||
711 | h.flash(_('Updated Labs settings'), category='success') |
|
745 | h.flash(_('Updated Labs settings'), category='success') | |
712 | return redirect(url('admin_settings_labs')) |
|
746 | return redirect(url('admin_settings_labs')) | |
713 |
|
747 | |||
@@ -733,20 +767,6 b' class SettingsController(BaseController)' | |||||
733 | encoding='UTF-8', |
|
767 | encoding='UTF-8', | |
734 | force_defaults=False) |
|
768 | force_defaults=False) | |
735 |
|
769 | |||
736 | @HasPermissionAllDecorator('hg.admin') |
|
|||
737 | def settings_open_source(self): |
|
|||
738 | # url('admin_settings_open_source') |
|
|||
739 |
|
||||
740 | c.active = 'open_source' |
|
|||
741 | c.opensource_licenses = collections.OrderedDict( |
|
|||
742 | sorted(read_opensource_licenses().items(), key=lambda t: t[0])) |
|
|||
743 |
|
||||
744 | return htmlfill.render( |
|
|||
745 | render('admin/settings/settings.html'), |
|
|||
746 | defaults=self._form_defaults(), |
|
|||
747 | encoding='UTF-8', |
|
|||
748 | force_defaults=False) |
|
|||
749 |
|
||||
750 | def _form_defaults(self): |
|
770 | def _form_defaults(self): | |
751 | defaults = SettingsModel().get_all_settings() |
|
771 | defaults = SettingsModel().get_all_settings() | |
752 | defaults.update(self._get_hg_ui_settings()) |
|
772 | defaults.update(self._get_hg_ui_settings()) | |
@@ -791,76 +811,3 b' LabSetting = collections.namedtuple(' | |||||
791 | help=lazy_ugettext('e.g. http://localhost:8080/') |
|
811 | help=lazy_ugettext('e.g. http://localhost:8080/') | |
792 | ), |
|
812 | ), | |
793 | ] |
|
813 | ] | |
794 |
|
||||
795 |
|
||||
796 | NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url']) |
|
|||
797 |
|
||||
798 |
|
||||
799 | class NavEntry(object): |
|
|||
800 |
|
||||
801 | def __init__(self, key, name, view_name, pyramid=False): |
|
|||
802 | self.key = key |
|
|||
803 | self.name = name |
|
|||
804 | self.view_name = view_name |
|
|||
805 | self.pyramid = pyramid |
|
|||
806 |
|
||||
807 | def generate_url(self, request): |
|
|||
808 | if self.pyramid: |
|
|||
809 | if hasattr(request, 'route_path'): |
|
|||
810 | return request.route_path(self.view_name) |
|
|||
811 | else: |
|
|||
812 | # TODO: johbo: Remove this after migrating to pyramid. |
|
|||
813 | # We need the pyramid request here to generate URLs to pyramid |
|
|||
814 | # views from within pylons views. |
|
|||
815 | from pyramid.threadlocal import get_current_request |
|
|||
816 | pyramid_request = get_current_request() |
|
|||
817 | return pyramid_request.route_path(self.view_name) |
|
|||
818 | else: |
|
|||
819 | return url(self.view_name) |
|
|||
820 |
|
||||
821 |
|
||||
822 | class NavigationRegistry(object): |
|
|||
823 |
|
||||
824 | _base_entries = [ |
|
|||
825 | NavEntry('global', lazy_ugettext('Global'), 'admin_settings_global'), |
|
|||
826 | NavEntry('vcs', lazy_ugettext('VCS'), 'admin_settings_vcs'), |
|
|||
827 | NavEntry('visual', lazy_ugettext('Visual'), 'admin_settings_visual'), |
|
|||
828 | NavEntry('mapping', lazy_ugettext('Remap and Rescan'), |
|
|||
829 | 'admin_settings_mapping'), |
|
|||
830 | NavEntry('issuetracker', lazy_ugettext('Issue Tracker'), |
|
|||
831 | 'admin_settings_issuetracker'), |
|
|||
832 | NavEntry('email', lazy_ugettext('Email'), 'admin_settings_email'), |
|
|||
833 | NavEntry('hooks', lazy_ugettext('Hooks'), 'admin_settings_hooks'), |
|
|||
834 | NavEntry('search', lazy_ugettext('Full Text Search'), |
|
|||
835 | 'admin_settings_search'), |
|
|||
836 | NavEntry('system', lazy_ugettext('System Info'), |
|
|||
837 | 'admin_settings_system'), |
|
|||
838 | NavEntry('open_source', lazy_ugettext('Open Source Licenses'), |
|
|||
839 | 'admin_settings_open_source'), |
|
|||
840 | # TODO: marcink: we disable supervisor now until the supervisor stats |
|
|||
841 | # page is fixed in the nix configuration |
|
|||
842 | # NavEntry('supervisor', lazy_ugettext('Supervisor'), |
|
|||
843 | # 'admin_settings_supervisor'), |
|
|||
844 | ] |
|
|||
845 |
|
||||
846 | def __init__(self): |
|
|||
847 | self._registered_entries = collections.OrderedDict([ |
|
|||
848 | (item.key, item) for item in self.__class__._base_entries |
|
|||
849 | ]) |
|
|||
850 |
|
||||
851 | # Add the labs entry when it's activated. |
|
|||
852 | labs_active = str2bool( |
|
|||
853 | rhodecode.CONFIG.get('labs_settings_active', 'false')) |
|
|||
854 | if labs_active: |
|
|||
855 | self.add_entry( |
|
|||
856 | NavEntry('labs', lazy_ugettext('Labs'), 'admin_settings_labs')) |
|
|||
857 |
|
||||
858 | def add_entry(self, entry): |
|
|||
859 | self._registered_entries[entry.key] = entry |
|
|||
860 |
|
||||
861 | def get_navlist(self, request): |
|
|||
862 | navlist = [NavListEntry(i.key, i.name, i.generate_url(request)) |
|
|||
863 | for i in self._registered_entries.values()] |
|
|||
864 | return navlist |
|
|||
865 |
|
||||
866 | navigation = NavigationRegistry() |
|
@@ -88,7 +88,7 b' class UserGroupsController(BaseControlle' | |||||
88 | if user_group.user: |
|
88 | if user_group.user: | |
89 | data.update({'user': user_group.user.username}) |
|
89 | data.update({'user': user_group.user.username}) | |
90 | else: |
|
90 | else: | |
91 | replacement_user = User.get_first_admin().username |
|
91 | replacement_user = User.get_first_super_admin().username | |
92 | data.update({'user': replacement_user}) |
|
92 | data.update({'user': replacement_user}) | |
93 | return data |
|
93 | return data | |
94 |
|
94 | |||
@@ -209,9 +209,9 b' class UserGroupsController(BaseControlle' | |||||
209 |
|
209 | |||
210 | available_members = [safe_unicode(x[0]) for x in c.available_members] |
|
210 | available_members = [safe_unicode(x[0]) for x in c.available_members] | |
211 |
|
211 | |||
212 |
users_group_form = UserGroupForm( |
|
212 | users_group_form = UserGroupForm( | |
213 |
|
|
213 | edit=True, old_data=c.user_group.get_dict(), | |
214 |
|
|
214 | available_members=available_members, allow_disabled=True)() | |
215 |
|
215 | |||
216 | try: |
|
216 | try: | |
217 | form_result = users_group_form.to_python(request.POST) |
|
217 | form_result = users_group_form.to_python(request.POST) |
@@ -216,6 +216,8 b' class UsersController(BaseController):' | |||||
216 | prefix_error=False, |
|
216 | prefix_error=False, | |
217 | encoding="UTF-8", |
|
217 | encoding="UTF-8", | |
218 | force_defaults=False) |
|
218 | force_defaults=False) | |
|
219 | except UserCreationError as e: | |||
|
220 | h.flash(e, 'error') | |||
219 | except Exception: |
|
221 | except Exception: | |
220 | log.exception("Exception updating user") |
|
222 | log.exception("Exception updating user") | |
221 | h.flash(_('Error occurred during update of user %s') |
|
223 | h.flash(_('Error occurred during update of user %s') | |
@@ -401,7 +403,7 b' class UsersController(BaseController):' | |||||
401 | c.active = 'advanced' |
|
403 | c.active = 'advanced' | |
402 | c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) |
|
404 | c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) | |
403 | c.personal_repo_group = RepoGroup.get_by_group_name(user.username) |
|
405 | c.personal_repo_group = RepoGroup.get_by_group_name(user.username) | |
404 | c.first_admin = User.get_first_admin() |
|
406 | c.first_admin = User.get_first_super_admin() | |
405 | defaults = user.get_dict() |
|
407 | defaults = user.get_dict() | |
406 |
|
408 | |||
407 | # Interim workaround if the user participated on any pull requests as a |
|
409 | # Interim workaround if the user participated on any pull requests as a |
@@ -37,7 +37,7 b' from rhodecode.lib.base import BaseContr' | |||||
37 | from rhodecode.lib.index import searcher_from_config |
|
37 | from rhodecode.lib.index import searcher_from_config | |
38 | from rhodecode.lib.ext_json import json |
|
38 | from rhodecode.lib.ext_json import json | |
39 | from rhodecode.lib.utils import jsonify |
|
39 | from rhodecode.lib.utils import jsonify | |
40 | from rhodecode.lib.utils2 import safe_unicode |
|
40 | from rhodecode.lib.utils2 import safe_unicode, str2bool | |
41 | from rhodecode.model.db import Repository, RepoGroup |
|
41 | from rhodecode.model.db import Repository, RepoGroup | |
42 | from rhodecode.model.repo import RepoModel |
|
42 | from rhodecode.model.repo import RepoModel | |
43 | from rhodecode.model.repo_group import RepoGroupModel |
|
43 | from rhodecode.model.repo_group import RepoGroupModel | |
@@ -259,13 +259,16 b' class HomeController(BaseController):' | |||||
259 | @jsonify |
|
259 | @jsonify | |
260 | def user_autocomplete_data(self): |
|
260 | def user_autocomplete_data(self): | |
261 | query = request.GET.get('query') |
|
261 | query = request.GET.get('query') | |
|
262 | active = str2bool(request.GET.get('active') or True) | |||
262 |
|
263 | |||
263 | repo_model = RepoModel() |
|
264 | repo_model = RepoModel() | |
264 |
_users = repo_model.get_users( |
|
265 | _users = repo_model.get_users( | |
|
266 | name_contains=query, only_active=active) | |||
265 |
|
267 | |||
266 | if request.GET.get('user_groups'): |
|
268 | if request.GET.get('user_groups'): | |
267 | # extend with user groups |
|
269 | # extend with user groups | |
268 |
_user_groups = repo_model.get_user_groups( |
|
270 | _user_groups = repo_model.get_user_groups( | |
|
271 | name_contains=query, only_active=active) | |||
269 | _users = _users + _user_groups |
|
272 | _users = _users + _user_groups | |
270 |
|
273 | |||
271 | return {'suggestions': _users} |
|
274 | return {'suggestions': _users} | |
@@ -274,4 +277,13 b' class HomeController(BaseController):' | |||||
274 | @XHRRequired() |
|
277 | @XHRRequired() | |
275 | @jsonify |
|
278 | @jsonify | |
276 | def user_group_autocomplete_data(self): |
|
279 | def user_group_autocomplete_data(self): | |
277 | return {'suggestions': []} |
|
280 | query = request.GET.get('query') | |
|
281 | active = str2bool(request.GET.get('active') or True) | |||
|
282 | ||||
|
283 | repo_model = RepoModel() | |||
|
284 | _user_groups = repo_model.get_user_groups( | |||
|
285 | name_contains=query, only_active=active) | |||
|
286 | _user_groups = _user_groups | |||
|
287 | ||||
|
288 | return {'suggestions': _user_groups} | |||
|
289 |
@@ -17,7 +17,8 b'' | |||||
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
18 |
|
18 | |||
19 | from zope.interface import implementer |
|
19 | from zope.interface import implementer | |
20 |
from rhodecode.interfaces import |
|
20 | from rhodecode.interfaces import ( | |
|
21 | IUserRegistered, IUserPreCreate, IUserPreUpdate) | |||
21 |
|
22 | |||
22 |
|
23 | |||
23 | @implementer(IUserRegistered) |
|
24 | @implementer(IUserRegistered) | |
@@ -29,3 +30,24 b' class UserRegistered(object):' | |||||
29 | def __init__(self, user, session): |
|
30 | def __init__(self, user, session): | |
30 | self.user = user |
|
31 | self.user = user | |
31 | self.session = session |
|
32 | self.session = session | |
|
33 | ||||
|
34 | ||||
|
35 | @implementer(IUserPreCreate) | |||
|
36 | class UserPreCreate(object): | |||
|
37 | """ | |||
|
38 | An instance of this class is emitted as an :term:`event` before a new user | |||
|
39 | object is created. | |||
|
40 | """ | |||
|
41 | def __init__(self, user_data): | |||
|
42 | self.user_data = user_data | |||
|
43 | ||||
|
44 | ||||
|
45 | @implementer(IUserPreUpdate) | |||
|
46 | class UserPreUpdate(object): | |||
|
47 | """ | |||
|
48 | An instance of this class is emitted as an :term:`event` before a user | |||
|
49 | object is updated. | |||
|
50 | """ | |||
|
51 | def __init__(self, user, user_data): | |||
|
52 | self.user = user | |||
|
53 | self.user_data = user_data |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
@@ -26,3 +26,18 b' class IUserRegistered(Interface):' | |||||
26 | """ |
|
26 | """ | |
27 | user = Attribute('The user object.') |
|
27 | user = Attribute('The user object.') | |
28 | session = Attribute('The session while processing the register form post.') |
|
28 | session = Attribute('The session while processing the register form post.') | |
|
29 | ||||
|
30 | ||||
|
31 | class IUserPreCreate(Interface): | |||
|
32 | """ | |||
|
33 | An event type that is emitted before a new user object is created. | |||
|
34 | """ | |||
|
35 | user_data = Attribute('Data used to create the new user') | |||
|
36 | ||||
|
37 | ||||
|
38 | class IUserPreUpdate(Interface): | |||
|
39 | """ | |||
|
40 | An event type that is emitted before a user object is updated. | |||
|
41 | """ | |||
|
42 | user = Attribute('The not yet updated user object') | |||
|
43 | user_data = Attribute('Data used to update the user') |
@@ -255,7 +255,7 b' class BasicAuth(AuthBasicAuthenticator):' | |||||
255 |
|
255 | |||
256 |
|
256 | |||
257 | def attach_context_attributes(context): |
|
257 | def attach_context_attributes(context): | |
258 | rc_config = SettingsModel().get_all_settings() |
|
258 | rc_config = SettingsModel().get_all_settings(cache=True) | |
259 |
|
259 | |||
260 | context.rhodecode_version = rhodecode.__version__ |
|
260 | context.rhodecode_version = rhodecode.__version__ | |
261 | context.rhodecode_edition = config.get('rhodecode.edition') |
|
261 | context.rhodecode_edition = config.get('rhodecode.edition') | |
@@ -425,7 +425,7 b' class BaseController(WSGIController):' | |||||
425 | _route_name = '.'.join([environ['pylons.routes_dict']['controller'], |
|
425 | _route_name = '.'.join([environ['pylons.routes_dict']['controller'], | |
426 | environ['pylons.routes_dict']['action']]) |
|
426 | environ['pylons.routes_dict']['action']]) | |
427 |
|
427 | |||
428 | self.rc_config = SettingsModel().get_all_settings() |
|
428 | self.rc_config = SettingsModel().get_all_settings(cache=True) | |
429 | self.ip_addr = get_ip_addr(environ) |
|
429 | self.ip_addr = get_ip_addr(environ) | |
430 |
|
430 | |||
431 | # The rhodecode auth user is looked up and passed through the |
|
431 | # The rhodecode auth user is looked up and passed through the |
@@ -87,6 +87,12 b' def get_cache_manager(region_name, cache' | |||||
87 |
|
87 | |||
88 |
|
88 | |||
89 | def clear_cache_manager(cache_manager): |
|
89 | def clear_cache_manager(cache_manager): | |
|
90 | """ | |||
|
91 | namespace = 'foobar' | |||
|
92 | cache_manager = get_cache_manager('repo_cache_long', namespace) | |||
|
93 | clear_cache_manager(cache_manager) | |||
|
94 | """ | |||
|
95 | ||||
90 | log.debug('Clearing all values for cache manager %s', cache_manager) |
|
96 | log.debug('Clearing all values for cache manager %s', cache_manager) | |
91 | cache_manager.clear() |
|
97 | cache_manager.clear() | |
92 |
|
98 | |||
@@ -161,7 +167,7 b' class FreshRegionCache(ActiveRegionCache' | |||||
161 | class InvalidationContext(object): |
|
167 | class InvalidationContext(object): | |
162 | def __repr__(self): |
|
168 | def __repr__(self): | |
163 | return '<InvalidationContext:{}[{}]>'.format( |
|
169 | return '<InvalidationContext:{}[{}]>'.format( | |
164 | self.repo_name, self.cache_type) |
|
170 | safe_str(self.repo_name), safe_str(self.cache_type)) | |
165 |
|
171 | |||
166 | def __init__(self, compute_func, repo_name, cache_type, |
|
172 | def __init__(self, compute_func, repo_name, cache_type, | |
167 | raise_exception=False): |
|
173 | raise_exception=False): |
@@ -34,7 +34,6 b' from decorator import decorator' | |||||
34 |
|
34 | |||
35 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
35 | from zope.cachedescriptors.property import Lazy as LazyProperty | |
36 |
|
36 | |||
37 | from rhodecode import CELERY_ENABLED, CELERY_EAGER |
|
|||
38 | from rhodecode.config import utils |
|
37 | from rhodecode.config import utils | |
39 | from rhodecode.lib.utils2 import safe_str, md5_safe, aslist |
|
38 | from rhodecode.lib.utils2 import safe_str, md5_safe, aslist | |
40 | from rhodecode.lib.pidlock import DaemonLock, LockHeld |
|
39 | from rhodecode.lib.pidlock import DaemonLock, LockHeld | |
@@ -54,8 +53,7 b' class ResultWrapper(object):' | |||||
54 |
|
53 | |||
55 |
|
54 | |||
56 | def run_task(task, *args, **kwargs): |
|
55 | def run_task(task, *args, **kwargs): | |
57 |
|
|
56 | if rhodecode.CELERY_ENABLED: | |
58 | if CELERY_ENABLED: |
|
|||
59 | try: |
|
57 | try: | |
60 | t = task.apply_async(args=args, kwargs=kwargs) |
|
58 | t = task.apply_async(args=args, kwargs=kwargs) | |
61 | log.info('running task %s:%s', t.task_id, task) |
|
59 | log.info('running task %s:%s', t.task_id, task) | |
@@ -63,18 +61,18 b' def run_task(task, *args, **kwargs):' | |||||
63 |
|
61 | |||
64 | except socket.error as e: |
|
62 | except socket.error as e: | |
65 | if isinstance(e, IOError) and e.errno == 111: |
|
63 | if isinstance(e, IOError) and e.errno == 111: | |
66 |
log. |
|
64 | log.error('Unable to connect to celeryd. Sync execution') | |
67 | CELERY_ENABLED = False |
|
65 | rhodecode.CELERY_ENABLED = False | |
68 | else: |
|
66 | else: | |
69 | log.exception("Exception while connecting to celeryd.") |
|
67 | log.exception("Exception while connecting to celeryd.") | |
70 | except KeyError as e: |
|
68 | except KeyError as e: | |
71 |
|
|
69 | log.error('Unable to connect to celeryd. Sync execution') | |
72 | except Exception as e: |
|
70 | except Exception as e: | |
73 | log.exception( |
|
71 | log.exception( | |
74 | "Exception while trying to run task asynchronous. " |
|
72 | "Exception while trying to run task asynchronous. " | |
75 | "Fallback to sync execution.") |
|
73 | "Fallback to sync execution.") | |
76 |
|
74 | else: | ||
77 | log.debug('executing task %s in sync mode', task) |
|
75 | log.debug('executing task %s in sync mode', task) | |
78 | return ResultWrapper(task(*args, **kwargs)) |
|
76 | return ResultWrapper(task(*args, **kwargs)) | |
79 |
|
77 | |||
80 |
|
78 | |||
@@ -106,7 +104,7 b' def locked_task(func):' | |||||
106 |
|
104 | |||
107 |
|
105 | |||
108 | def get_session(): |
|
106 | def get_session(): | |
109 | if CELERY_ENABLED: |
|
107 | if rhodecode.CELERY_ENABLED: | |
110 | utils.initialize_database(config) |
|
108 | utils.initialize_database(config) | |
111 | sa = meta.Session() |
|
109 | sa = meta.Session() | |
112 | return sa |
|
110 | return sa | |
@@ -118,7 +116,7 b' def dbsession(func):' | |||||
118 | ret = func(*fargs, **fkwargs) |
|
116 | ret = func(*fargs, **fkwargs) | |
119 | return ret |
|
117 | return ret | |
120 | finally: |
|
118 | finally: | |
121 | if CELERY_ENABLED and not CELERY_EAGER: |
|
119 | if rhodecode.CELERY_ENABLED and not rhodecode.CELERY_EAGER: | |
122 | meta.Session.remove() |
|
120 | meta.Session.remove() | |
123 |
|
121 | |||
124 | return decorator(__wrapper, func) |
|
122 | return decorator(__wrapper, func) | |
@@ -126,7 +124,7 b' def dbsession(func):' | |||||
126 |
|
124 | |||
127 | def vcsconnection(func): |
|
125 | def vcsconnection(func): | |
128 | def __wrapper(func, *fargs, **fkwargs): |
|
126 | def __wrapper(func, *fargs, **fkwargs): | |
129 | if CELERY_ENABLED and not CELERY_EAGER: |
|
127 | if rhodecode.CELERY_ENABLED and not rhodecode.CELERY_EAGER: | |
130 | backends = config['vcs.backends'] = aslist( |
|
128 | backends = config['vcs.backends'] = aslist( | |
131 | config.get('vcs.backends', 'hg,git'), sep=',') |
|
129 | config.get('vcs.backends', 'hg,git'), sep=',') | |
132 | for alias in rhodecode.BACKENDS.keys(): |
|
130 | for alias in rhodecode.BACKENDS.keys(): |
@@ -30,7 +30,7 b' import logging' | |||||
30 | from celery.task import task |
|
30 | from celery.task import task | |
31 | from pylons import config |
|
31 | from pylons import config | |
32 |
|
32 | |||
33 | from rhodecode import CELERY_ENABLED |
|
33 | import rhodecode | |
34 | from rhodecode.lib.celerylib import ( |
|
34 | from rhodecode.lib.celerylib import ( | |
35 | run_task, dbsession, __get_lockkey, LockHeld, DaemonLock, |
|
35 | run_task, dbsession, __get_lockkey, LockHeld, DaemonLock, | |
36 | get_session, vcsconnection) |
|
36 | get_session, vcsconnection) | |
@@ -45,7 +45,7 b' add_cache(config) # pragma: no cover' | |||||
45 |
|
45 | |||
46 |
|
46 | |||
47 | def get_logger(cls): |
|
47 | def get_logger(cls): | |
48 | if CELERY_ENABLED: |
|
48 | if rhodecode.CELERY_ENABLED: | |
49 | try: |
|
49 | try: | |
50 | log = cls.get_logger() |
|
50 | log = cls.get_logger() | |
51 | except Exception: |
|
51 | except Exception: |
@@ -478,9 +478,9 b' class DbManage(object):' | |||||
478 | elif not os.access(path, os.W_OK) and path_ok: |
|
478 | elif not os.access(path, os.W_OK) and path_ok: | |
479 | log.warning('No write permission to given path %s' % (path,)) |
|
479 | log.warning('No write permission to given path %s' % (path,)) | |
480 |
|
480 | |||
481 | q = ('Given path %s is not writeable, do you want to ' |
|
481 | q = ('Given path %s is not writeable, do you want to ' | |
482 | 'continue with read only mode ? [y/n]' % (path,)) |
|
482 | 'continue with read only mode ? [y/n]' % (path,)) | |
483 | if not self.ask_ok(q): |
|
483 | if not self.ask_ok(q): | |
484 | log.error('Canceled by user') |
|
484 | log.error('Canceled by user') | |
485 | sys.exit(-1) |
|
485 | sys.exit(-1) | |
486 |
|
486 |
@@ -23,31 +23,84 b'' | |||||
23 | Generic encryption library for RhodeCode |
|
23 | Generic encryption library for RhodeCode | |
24 | """ |
|
24 | """ | |
25 |
|
25 | |||
26 | import hashlib |
|
|||
27 | import base64 |
|
26 | import base64 | |
28 |
|
27 | |||
29 | from Crypto.Cipher import AES |
|
28 | from Crypto.Cipher import AES | |
30 | from Crypto import Random |
|
29 | from Crypto import Random | |
|
30 | from Crypto.Hash import HMAC, SHA256 | |||
31 |
|
31 | |||
32 | from rhodecode.lib.utils2 import safe_str |
|
32 | from rhodecode.lib.utils2 import safe_str | |
33 |
|
33 | |||
34 |
|
34 | |||
|
35 | class SignatureVerificationError(Exception): | |||
|
36 | pass | |||
|
37 | ||||
|
38 | ||||
|
39 | class InvalidDecryptedValue(str): | |||
|
40 | ||||
|
41 | def __new__(cls, content): | |||
|
42 | """ | |||
|
43 | This will generate something like this:: | |||
|
44 | <InvalidDecryptedValue(QkWusFgLJXR6m42v...)> | |||
|
45 | And represent a safe indicator that encryption key is broken | |||
|
46 | """ | |||
|
47 | content = '<{}({}...)>'.format(cls.__name__, content[:16]) | |||
|
48 | return str.__new__(cls, content) | |||
|
49 | ||||
|
50 | ||||
35 | class AESCipher(object): |
|
51 | class AESCipher(object): | |
36 | def __init__(self, key): |
|
52 | def __init__(self, key, hmac=False, strict_verification=True): | |
37 | # create padding, trim to long enc key |
|
|||
38 | if not key: |
|
53 | if not key: | |
39 | raise ValueError('passed key variable is empty') |
|
54 | raise ValueError('passed key variable is empty') | |
|
55 | self.strict_verification = strict_verification | |||
40 | self.block_size = 32 |
|
56 | self.block_size = 32 | |
41 | self.key = hashlib.sha256(safe_str(key)).digest() |
|
57 | self.hmac_size = 32 | |
|
58 | self.hmac = hmac | |||
|
59 | ||||
|
60 | self.key = SHA256.new(safe_str(key)).digest() | |||
|
61 | self.hmac_key = SHA256.new(self.key).digest() | |||
|
62 | ||||
|
63 | def verify_hmac_signature(self, raw_data): | |||
|
64 | org_hmac_signature = raw_data[-self.hmac_size:] | |||
|
65 | data_without_sig = raw_data[:-self.hmac_size] | |||
|
66 | recomputed_hmac = HMAC.new( | |||
|
67 | self.hmac_key, data_without_sig, digestmod=SHA256).digest() | |||
|
68 | return org_hmac_signature == recomputed_hmac | |||
42 |
|
69 | |||
43 | def encrypt(self, raw): |
|
70 | def encrypt(self, raw): | |
44 | raw = self._pad(raw) |
|
71 | raw = self._pad(raw) | |
45 | iv = Random.new().read(AES.block_size) |
|
72 | iv = Random.new().read(AES.block_size) | |
46 | cipher = AES.new(self.key, AES.MODE_CBC, iv) |
|
73 | cipher = AES.new(self.key, AES.MODE_CBC, iv) | |
47 |
|
|
74 | enc_value = cipher.encrypt(raw) | |
|
75 | ||||
|
76 | hmac_signature = '' | |||
|
77 | if self.hmac: | |||
|
78 | # compute hmac+sha256 on iv + enc text, we use | |||
|
79 | # encrypt then mac method to create the signature | |||
|
80 | hmac_signature = HMAC.new( | |||
|
81 | self.hmac_key, iv + enc_value, digestmod=SHA256).digest() | |||
|
82 | ||||
|
83 | return base64.b64encode(iv + enc_value + hmac_signature) | |||
48 |
|
84 | |||
49 | def decrypt(self, enc): |
|
85 | def decrypt(self, enc): | |
|
86 | enc_org = enc | |||
50 | enc = base64.b64decode(enc) |
|
87 | enc = base64.b64decode(enc) | |
|
88 | ||||
|
89 | if self.hmac and len(enc) > self.hmac_size: | |||
|
90 | if self.verify_hmac_signature(enc): | |||
|
91 | # cut off the HMAC verification digest | |||
|
92 | enc = enc[:-self.hmac_size] | |||
|
93 | else: | |||
|
94 | if self.strict_verification: | |||
|
95 | raise SignatureVerificationError( | |||
|
96 | "Encryption signature verification failed. " | |||
|
97 | "Please check your secret key, and/or encrypted value. " | |||
|
98 | "Secret key is stored as " | |||
|
99 | "`rhodecode.encrypted_values.secret` or " | |||
|
100 | "`beaker.session.secret` inside .ini file") | |||
|
101 | ||||
|
102 | return InvalidDecryptedValue(enc_org) | |||
|
103 | ||||
51 | iv = enc[:AES.block_size] |
|
104 | iv = enc[:AES.block_size] | |
52 | cipher = AES.new(self.key, AES.MODE_CBC, iv) |
|
105 | cipher = AES.new(self.key, AES.MODE_CBC, iv) | |
53 | return self._unpad(cipher.decrypt(enc[AES.block_size:])) |
|
106 | return self._unpad(cipher.decrypt(enc[AES.block_size:])) |
@@ -438,15 +438,17 b' def get_matching_line_offsets(lines, ter' | |||||
438 | :param max_lines: cut off for lines of interest |
|
438 | :param max_lines: cut off for lines of interest | |
439 | eg. |
|
439 | eg. | |
440 |
|
440 | |||
441 | >>> get_matching_line_offsets(''' |
|
441 | text = ''' | |
442 | words words words |
|
442 | words words words | |
443 | words words words |
|
443 | words words words | |
444 | some text some |
|
444 | some text some | |
445 | words words words |
|
445 | words words words | |
446 | words words words |
|
446 | words words words | |
447 | text here what |
|
447 | text here what | |
448 | ''', 'text', context=1) |
|
448 | ''' | |
|
449 | get_matching_line_offsets(text, 'text', context=1) | |||
449 | {3: [(5, 9)], 6: [(0, 4)]] |
|
450 | {3: [(5, 9)], 6: [(0, 4)]] | |
|
451 | ||||
450 | """ |
|
452 | """ | |
451 | matching_lines = {} |
|
453 | matching_lines = {} | |
452 | phrases = [normalize_text_for_matching(phrase) |
|
454 | phrases = [normalize_text_for_matching(phrase) | |
@@ -460,6 +462,7 b' text here what' | |||||
460 |
|
462 | |||
461 | return matching_lines |
|
463 | return matching_lines | |
462 |
|
464 | |||
|
465 | ||||
463 | def get_lexer_safe(mimetype=None, filepath=None): |
|
466 | def get_lexer_safe(mimetype=None, filepath=None): | |
464 | """ |
|
467 | """ | |
465 | Tries to return a relevant pygments lexer using mimetype/filepath name, |
|
468 | Tries to return a relevant pygments lexer using mimetype/filepath name, | |
@@ -470,7 +473,7 b' def get_lexer_safe(mimetype=None, filepa' | |||||
470 | if mimetype: |
|
473 | if mimetype: | |
471 | lexer = get_lexer_for_mimetype(mimetype) |
|
474 | lexer = get_lexer_for_mimetype(mimetype) | |
472 | if not lexer: |
|
475 | if not lexer: | |
473 | lexer = get_lexer_for_filename(path) |
|
476 | lexer = get_lexer_for_filename(filepath) | |
474 | except pygments.util.ClassNotFound: |
|
477 | except pygments.util.ClassNotFound: | |
475 | pass |
|
478 | pass | |
476 |
|
479 | |||
@@ -675,11 +678,6 b' def _shorten_commit_id(commit_id):' | |||||
675 | return commit_id[:def_len] |
|
678 | return commit_id[:def_len] | |
676 |
|
679 | |||
677 |
|
680 | |||
678 | def get_repo_id_from_name(repo_name): |
|
|||
679 | repo = get_by_repo_name(repo_name) |
|
|||
680 | return repo.repo_id |
|
|||
681 |
|
||||
682 |
|
||||
683 | def show_id(commit): |
|
681 | def show_id(commit): | |
684 | """ |
|
682 | """ | |
685 | Configurable function that shows ID |
|
683 | Configurable function that shows ID | |
@@ -744,6 +742,32 b' def is_svn_without_proxy(repository):' | |||||
744 | return False |
|
742 | return False | |
745 |
|
743 | |||
746 |
|
744 | |||
|
745 | def discover_user(author): | |||
|
746 | """ | |||
|
747 | Tries to discover RhodeCode User based on the autho string. Author string | |||
|
748 | is typically `FirstName LastName <email@address.com>` | |||
|
749 | """ | |||
|
750 | ||||
|
751 | # if author is already an instance use it for extraction | |||
|
752 | if isinstance(author, User): | |||
|
753 | return author | |||
|
754 | ||||
|
755 | # Valid email in the attribute passed, see if they're in the system | |||
|
756 | _email = author_email(author) | |||
|
757 | if _email != '': | |||
|
758 | user = User.get_by_email(_email, case_insensitive=True, cache=True) | |||
|
759 | if user is not None: | |||
|
760 | return user | |||
|
761 | ||||
|
762 | # Maybe it's a username, we try to extract it and fetch by username ? | |||
|
763 | _author = author_name(author) | |||
|
764 | user = User.get_by_username(_author, case_insensitive=True, cache=True) | |||
|
765 | if user is not None: | |||
|
766 | return user | |||
|
767 | ||||
|
768 | return None | |||
|
769 | ||||
|
770 | ||||
747 | def email_or_none(author): |
|
771 | def email_or_none(author): | |
748 | # extract email from the commit string |
|
772 | # extract email from the commit string | |
749 | _email = author_email(author) |
|
773 | _email = author_email(author) | |
@@ -765,30 +789,13 b' def email_or_none(author):' | |||||
765 | return None |
|
789 | return None | |
766 |
|
790 | |||
767 |
|
791 | |||
768 | def discover_user(author): |
|
|||
769 | # if author is already an instance use it for extraction |
|
|||
770 | if isinstance(author, User): |
|
|||
771 | return author |
|
|||
772 |
|
||||
773 | # Valid email in the attribute passed, see if they're in the system |
|
|||
774 | _email = email(author) |
|
|||
775 | if _email != '': |
|
|||
776 | user = User.get_by_email(_email, case_insensitive=True, cache=True) |
|
|||
777 | if user is not None: |
|
|||
778 | return user |
|
|||
779 |
|
||||
780 | # Maybe it's a username? |
|
|||
781 | _author = author_name(author) |
|
|||
782 | user = User.get_by_username(_author, case_insensitive=True, |
|
|||
783 | cache=True) |
|
|||
784 | if user is not None: |
|
|||
785 | return user |
|
|||
786 |
|
||||
787 | return None |
|
|||
788 |
|
||||
789 |
|
||||
790 | def link_to_user(author, length=0, **kwargs): |
|
792 | def link_to_user(author, length=0, **kwargs): | |
791 | user = discover_user(author) |
|
793 | user = discover_user(author) | |
|
794 | # user can be None, but if we have it already it means we can re-use it | |||
|
795 | # in the person() function, so we save 1 intensive-query | |||
|
796 | if user: | |||
|
797 | author = user | |||
|
798 | ||||
792 | display_person = person(author, 'username_or_name_or_email') |
|
799 | display_person = person(author, 'username_or_name_or_email') | |
793 | if length: |
|
800 | if length: | |
794 | display_person = shorter(display_person, length) |
|
801 | display_person = shorter(display_person, length) | |
@@ -803,11 +810,9 b' def link_to_user(author, length=0, **kwa' | |||||
803 |
|
810 | |||
804 |
|
811 | |||
805 | def person(author, show_attr="username_and_name"): |
|
812 | def person(author, show_attr="username_and_name"): | |
806 | # attr to return from fetched user |
|
|||
807 | person_getter = lambda usr: getattr(usr, show_attr) |
|
|||
808 | user = discover_user(author) |
|
813 | user = discover_user(author) | |
809 | if user: |
|
814 | if user: | |
810 |
return |
|
815 | return getattr(user, show_attr) | |
811 | else: |
|
816 | else: | |
812 | _author = author_name(author) |
|
817 | _author = author_name(author) | |
813 | _email = email(author) |
|
818 | _email = email(author) | |
@@ -827,10 +832,10 b' def person_by_id(id_, show_attr="usernam' | |||||
827 | return id_ |
|
832 | return id_ | |
828 |
|
833 | |||
829 |
|
834 | |||
830 | def gravatar_with_user(author): |
|
835 | def gravatar_with_user(author, show_disabled=False): | |
831 | from rhodecode.lib.utils import PartialRenderer |
|
836 | from rhodecode.lib.utils import PartialRenderer | |
832 | _render = PartialRenderer('base/base.html') |
|
837 | _render = PartialRenderer('base/base.html') | |
833 | return _render('gravatar_with_user', author) |
|
838 | return _render('gravatar_with_user', author, show_disabled=show_disabled) | |
834 |
|
839 | |||
835 |
|
840 | |||
836 | def desc_stylize(value): |
|
841 | def desc_stylize(value): | |
@@ -851,7 +856,7 b' def desc_stylize(value):' | |||||
851 | value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', |
|
856 | value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', | |
852 | '<div class="metatag" tag="lang">\\2</div>', value) |
|
857 | '<div class="metatag" tag="lang">\\2</div>', value) | |
853 | value = re.sub(r'\[([a-z]+)\]', |
|
858 | value = re.sub(r'\[([a-z]+)\]', | |
854 | '<div class="metatag" tag="\\1">\\1</div>', value) |
|
859 | '<div class="metatag" tag="\\1">\\1</div>', value) | |
855 |
|
860 | |||
856 | return value |
|
861 | return value | |
857 |
|
862 | |||
@@ -876,7 +881,7 b' def escaped_stylize(value):' | |||||
876 | value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', |
|
881 | value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', | |
877 | '<div class="metatag" tag="lang">\\2</div>', value) |
|
882 | '<div class="metatag" tag="lang">\\2</div>', value) | |
878 | value = re.sub(r'\[([a-z]+)\]', |
|
883 | value = re.sub(r'\[([a-z]+)\]', | |
879 | '<div class="metatag" tag="\\1">\\1</div>', value) |
|
884 | '<div class="metatag" tag="\\1">\\1</div>', value) | |
880 |
|
885 | |||
881 | return value |
|
886 | return value | |
882 |
|
887 | |||
@@ -1647,10 +1652,10 b' def process_patterns(text_string, repo_n' | |||||
1647 | if repo_name: |
|
1652 | if repo_name: | |
1648 | # Retrieving repo_name to avoid invalid repo_name to explode on |
|
1653 | # Retrieving repo_name to avoid invalid repo_name to explode on | |
1649 | # IssueTrackerSettingsModel but still passing invalid name further down |
|
1654 | # IssueTrackerSettingsModel but still passing invalid name further down | |
1650 | repo = Repository.get_by_repo_name(repo_name) |
|
1655 | repo = Repository.get_by_repo_name(repo_name, cache=True) | |
1651 |
|
1656 | |||
1652 | settings_model = IssueTrackerSettingsModel(repo=repo) |
|
1657 | settings_model = IssueTrackerSettingsModel(repo=repo) | |
1653 | active_entries = settings_model.get_settings() |
|
1658 | active_entries = settings_model.get_settings(cache=True) | |
1654 |
|
1659 | |||
1655 | newtext = text_string |
|
1660 | newtext = text_string | |
1656 | for uid, entry in active_entries.items(): |
|
1661 | for uid, entry in active_entries.items(): |
@@ -24,15 +24,21 b' Disable VCS pages when VCS Server is not' | |||||
24 |
|
24 | |||
25 | import logging |
|
25 | import logging | |
26 | import re |
|
26 | import re | |
27 |
|
27 | from pyramid.httpexceptions import HTTPBadGateway | ||
28 |
|
28 | |||
29 | log = logging.getLogger(__name__) |
|
29 | log = logging.getLogger(__name__) | |
30 |
|
30 | |||
31 |
|
31 | |||
|
32 | class VCSServerUnavailable(HTTPBadGateway): | |||
|
33 | """ HTTP Exception class for when VCS Server is unavailable """ | |||
|
34 | code = 502 | |||
|
35 | title = 'VCS Server Required' | |||
|
36 | explanation = 'A VCS Server is required for this action. There is currently no VCS Server configured.' | |||
|
37 | ||||
32 | class DisableVCSPagesWrapper(object): |
|
38 | class DisableVCSPagesWrapper(object): | |
33 | """ |
|
39 | """ | |
34 |
|
|
40 | Pyramid view wrapper to disable all pages that require VCS Server to be | |
35 | avoiding that errors explode to the user. |
|
41 | running, avoiding that errors explode to the user. | |
36 |
|
42 | |||
37 | This Wrapper should be enabled only in case VCS Server is not available |
|
43 | This Wrapper should be enabled only in case VCS Server is not available | |
38 | for the instance. |
|
44 | for the instance. | |
@@ -60,11 +66,11 b' class DisableVCSPagesWrapper(object):' | |||||
60 | log.debug('accessing: `%s` with VCS Server disabled', path_info) |
|
66 | log.debug('accessing: `%s` with VCS Server disabled', path_info) | |
61 | return False |
|
67 | return False | |
62 |
|
68 | |||
63 |
def __init__(self, |
|
69 | def __init__(self, handler): | |
64 |
self. |
|
70 | self.handler = handler | |
65 |
|
71 | |||
66 |
def __call__(self, |
|
72 | def __call__(self, context, request): | |
67 |
if not self._check_vcs_requirement( |
|
73 | if not self._check_vcs_requirement(request.path): | |
68 | environ['PATH_INFO'] = '/error/vcs_unavailable' |
|
74 | raise VCSServerUnavailable('VCS Server is not available') | |
69 |
|
75 | |||
70 |
return self. |
|
76 | return self.handler(context, request) |
@@ -33,14 +33,14 b' import tempfile' | |||||
33 | import traceback |
|
33 | import traceback | |
34 | import tarfile |
|
34 | import tarfile | |
35 | import warnings |
|
35 | import warnings | |
36 |
from os.path import |
|
36 | from os.path import join as jn | |
37 | from os.path import dirname as dn, join as jn |
|
|||
38 |
|
37 | |||
39 | import paste |
|
38 | import paste | |
40 | import pkg_resources |
|
39 | import pkg_resources | |
41 | from paste.script.command import Command, BadCommand |
|
40 | from paste.script.command import Command, BadCommand | |
42 | from webhelpers.text import collapse, remove_formatting, strip_tags |
|
41 | from webhelpers.text import collapse, remove_formatting, strip_tags | |
43 | from mako import exceptions |
|
42 | from mako import exceptions | |
|
43 | from pyramid.threadlocal import get_current_registry | |||
44 |
|
44 | |||
45 | from rhodecode.lib.fakemod import create_module |
|
45 | from rhodecode.lib.fakemod import create_module | |
46 | from rhodecode.lib.vcs.backends.base import Config |
|
46 | from rhodecode.lib.vcs.backends.base import Config | |
@@ -52,8 +52,7 b' from rhodecode.model import meta' | |||||
52 | from rhodecode.model.db import ( |
|
52 | from rhodecode.model.db import ( | |
53 | Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup) |
|
53 | Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup) | |
54 | from rhodecode.model.meta import Session |
|
54 | from rhodecode.model.meta import Session | |
55 | from rhodecode.model.repo_group import RepoGroupModel |
|
55 | ||
56 | from rhodecode.model.settings import VcsSettingsModel, SettingsModel |
|
|||
57 |
|
56 | |||
58 | log = logging.getLogger(__name__) |
|
57 | log = logging.getLogger(__name__) | |
59 |
|
58 | |||
@@ -384,6 +383,8 b' def config_data_from_db(clear_session=Tr' | |||||
384 | Read the configuration data from the database and return configuration |
|
383 | Read the configuration data from the database and return configuration | |
385 | tuples. |
|
384 | tuples. | |
386 | """ |
|
385 | """ | |
|
386 | from rhodecode.model.settings import VcsSettingsModel | |||
|
387 | ||||
387 | config = [] |
|
388 | config = [] | |
388 |
|
389 | |||
389 | sa = meta.Session() |
|
390 | sa = meta.Session() | |
@@ -467,6 +468,7 b' def set_rhodecode_config(config):' | |||||
467 |
|
468 | |||
468 | :param config: |
|
469 | :param config: | |
469 | """ |
|
470 | """ | |
|
471 | from rhodecode.model.settings import SettingsModel | |||
470 | app_settings = SettingsModel().get_all_settings() |
|
472 | app_settings = SettingsModel().get_all_settings() | |
471 |
|
473 | |||
472 | for k, v in app_settings.items(): |
|
474 | for k, v in app_settings.items(): | |
@@ -481,6 +483,7 b' def map_groups(path):' | |||||
481 |
|
483 | |||
482 | :param paths: full path to repository |
|
484 | :param paths: full path to repository | |
483 | """ |
|
485 | """ | |
|
486 | from rhodecode.model.repo_group import RepoGroupModel | |||
484 | sa = meta.Session() |
|
487 | sa = meta.Session() | |
485 | groups = path.split(Repository.NAME_SEP) |
|
488 | groups = path.split(Repository.NAME_SEP) | |
486 | parent = None |
|
489 | parent = None | |
@@ -489,7 +492,7 b' def map_groups(path):' | |||||
489 | # last element is repo in nested groups structure |
|
492 | # last element is repo in nested groups structure | |
490 | groups = groups[:-1] |
|
493 | groups = groups[:-1] | |
491 | rgm = RepoGroupModel(sa) |
|
494 | rgm = RepoGroupModel(sa) | |
492 | owner = User.get_first_admin() |
|
495 | owner = User.get_first_super_admin() | |
493 | for lvl, group_name in enumerate(groups): |
|
496 | for lvl, group_name in enumerate(groups): | |
494 | group_name = '/'.join(groups[:lvl] + [group_name]) |
|
497 | group_name = '/'.join(groups[:lvl] + [group_name]) | |
495 | group = RepoGroup.get_by_group_name(group_name) |
|
498 | group = RepoGroup.get_by_group_name(group_name) | |
@@ -525,9 +528,12 b' def repo2db_mapper(initial_repo_list, re' | |||||
525 | """ |
|
528 | """ | |
526 | from rhodecode.model.repo import RepoModel |
|
529 | from rhodecode.model.repo import RepoModel | |
527 | from rhodecode.model.scm import ScmModel |
|
530 | from rhodecode.model.scm import ScmModel | |
|
531 | from rhodecode.model.repo_group import RepoGroupModel | |||
|
532 | from rhodecode.model.settings import SettingsModel | |||
|
533 | ||||
528 | sa = meta.Session() |
|
534 | sa = meta.Session() | |
529 | repo_model = RepoModel() |
|
535 | repo_model = RepoModel() | |
530 | user = User.get_first_admin() |
|
536 | user = User.get_first_super_admin() | |
531 | added = [] |
|
537 | added = [] | |
532 |
|
538 | |||
533 | # creation defaults |
|
539 | # creation defaults | |
@@ -701,58 +707,56 b' def get_custom_lexer(extension):' | |||||
701 | #============================================================================== |
|
707 | #============================================================================== | |
702 | # TEST FUNCTIONS AND CREATORS |
|
708 | # TEST FUNCTIONS AND CREATORS | |
703 | #============================================================================== |
|
709 | #============================================================================== | |
704 |
def create_test_index(repo_location, config |
|
710 | def create_test_index(repo_location, config): | |
705 | """ |
|
711 | """ | |
706 | Makes default test index |
|
712 | Makes default test index. | |
707 |
|
713 | """ | ||
708 | :param config: test config |
|
714 | import rc_testdata | |
709 | :param full_index: |
|
|||
710 | # start test server: |
|
|||
711 | rcserver --with-vcsserver test.ini |
|
|||
712 |
|
715 | |||
713 | # build index and store it in /tmp/rc/index: |
|
716 | rc_testdata.extract_search_index( | |
714 | rhodecode-index --force --api-host=http://vps1.dev:5000 --api-key=xxx --engine-location=/tmp/rc/index |
|
717 | 'vcs_search_index', os.path.dirname(config['search.location'])) | |
715 |
|
||||
716 | # package and move new packages |
|
|||
717 | tar -zcvf vcs_search_index.tar.gz -C /tmp/rc index |
|
|||
718 | mv vcs_search_index.tar.gz rhodecode/tests/fixtures/ |
|
|||
719 |
|
||||
720 | """ |
|
|||
721 | cur_dir = dn(dn(abspath(__file__))) |
|
|||
722 | with tarfile.open(jn(cur_dir, 'tests', 'fixtures', |
|
|||
723 | 'vcs_search_index.tar.gz')) as tar: |
|
|||
724 | tar.extractall(os.path.dirname(config['search.location'])) |
|
|||
725 |
|
718 | |||
726 |
|
719 | |||
727 |
def create_test_ |
|
720 | def create_test_directory(test_path): | |
|
721 | """ | |||
|
722 | Create test directory if it doesn't exist. | |||
728 |
|
|
723 | """ | |
729 | Makes a fresh database and |
|
724 | if not os.path.isdir(test_path): | |
730 | installs test repository into tmp dir |
|
725 | log.debug('Creating testdir %s', test_path) | |
|
726 | os.makedirs(test_path) | |||
|
727 | ||||
|
728 | ||||
|
729 | def create_test_database(test_path, config): | |||
|
730 | """ | |||
|
731 | Makes a fresh database. | |||
731 | """ |
|
732 | """ | |
732 | from rhodecode.lib.db_manage import DbManage |
|
733 | from rhodecode.lib.db_manage import DbManage | |
733 | from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO, TESTS_TMP_PATH |
|
|||
734 |
|
734 | |||
735 | # PART ONE create db |
|
735 | # PART ONE create db | |
736 | dbconf = config['sqlalchemy.db1.url'] |
|
736 | dbconf = config['sqlalchemy.db1.url'] | |
737 | log.debug('making test db %s', dbconf) |
|
737 | log.debug('making test db %s', dbconf) | |
738 |
|
738 | |||
739 | # create test dir if it doesn't exist |
|
|||
740 | if not os.path.isdir(repos_test_path): |
|
|||
741 | log.debug('Creating testdir %s', repos_test_path) |
|
|||
742 | os.makedirs(repos_test_path) |
|
|||
743 |
|
||||
744 | dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'], |
|
739 | dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'], | |
745 | tests=True, cli_args={'force_ask': True}) |
|
740 | tests=True, cli_args={'force_ask': True}) | |
746 | dbmanage.create_tables(override=True) |
|
741 | dbmanage.create_tables(override=True) | |
747 | dbmanage.set_db_version() |
|
742 | dbmanage.set_db_version() | |
748 | # for tests dynamically set new root paths based on generated content |
|
743 | # for tests dynamically set new root paths based on generated content | |
749 |
dbmanage.create_settings(dbmanage.config_prompt( |
|
744 | dbmanage.create_settings(dbmanage.config_prompt(test_path)) | |
750 | dbmanage.create_default_user() |
|
745 | dbmanage.create_default_user() | |
751 | dbmanage.create_test_admin_and_users() |
|
746 | dbmanage.create_test_admin_and_users() | |
752 | dbmanage.create_permissions() |
|
747 | dbmanage.create_permissions() | |
753 | dbmanage.populate_default_permissions() |
|
748 | dbmanage.populate_default_permissions() | |
754 | Session().commit() |
|
749 | Session().commit() | |
755 | # PART TWO make test repo |
|
750 | ||
|
751 | ||||
|
752 | def create_test_repositories(test_path, config): | |||
|
753 | """ | |||
|
754 | Creates test repositories in the temporary directory. Repositories are | |||
|
755 | extracted from archives within the rc_testdata package. | |||
|
756 | """ | |||
|
757 | import rc_testdata | |||
|
758 | from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO | |||
|
759 | ||||
756 | log.debug('making test vcs repositories') |
|
760 | log.debug('making test vcs repositories') | |
757 |
|
761 | |||
758 | idx_path = config['search.location'] |
|
762 | idx_path = config['search.location'] | |
@@ -767,24 +771,15 b' def create_test_env(repos_test_path, con' | |||||
767 | log.debug('remove %s', data_path) |
|
771 | log.debug('remove %s', data_path) | |
768 | shutil.rmtree(data_path) |
|
772 | shutil.rmtree(data_path) | |
769 |
|
773 | |||
770 | # CREATE DEFAULT TEST REPOS |
|
774 | rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO)) | |
771 | cur_dir = dn(dn(abspath(__file__))) |
|
775 | rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO)) | |
772 | with tarfile.open(jn(cur_dir, 'tests', 'fixtures', |
|
|||
773 | 'vcs_test_hg.tar.gz')) as tar: |
|
|||
774 | tar.extractall(jn(TESTS_TMP_PATH, HG_REPO)) |
|
|||
775 |
|
||||
776 | cur_dir = dn(dn(abspath(__file__))) |
|
|||
777 | with tarfile.open(jn(cur_dir, 'tests', 'fixtures', |
|
|||
778 | 'vcs_test_git.tar.gz')) as tar: |
|
|||
779 | tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO)) |
|
|||
780 |
|
776 | |||
781 | # Note: Subversion is in the process of being integrated with the system, |
|
777 | # Note: Subversion is in the process of being integrated with the system, | |
782 | # until we have a properly packed version of the test svn repository, this |
|
778 | # until we have a properly packed version of the test svn repository, this | |
783 | # tries to copy over the repo from a package "rc_testdata" |
|
779 | # tries to copy over the repo from a package "rc_testdata" | |
784 | import rc_testdata |
|
|||
785 | svn_repo_path = rc_testdata.get_svn_repo_archive() |
|
780 | svn_repo_path = rc_testdata.get_svn_repo_archive() | |
786 | with tarfile.open(svn_repo_path) as tar: |
|
781 | with tarfile.open(svn_repo_path) as tar: | |
787 |
tar.extractall(jn( |
|
782 | tar.extractall(jn(test_path, SVN_REPO)) | |
788 |
|
783 | |||
789 |
|
784 | |||
790 | #============================================================================== |
|
785 | #============================================================================== | |
@@ -976,7 +971,20 b' def read_opensource_licenses():' | |||||
976 |
|
971 | |||
977 | if not _license_cache: |
|
972 | if not _license_cache: | |
978 | licenses = pkg_resources.resource_string( |
|
973 | licenses = pkg_resources.resource_string( | |
979 |
'rhodecode |
|
974 | 'rhodecode', 'config/licenses.json') | |
980 | _license_cache = json.loads(licenses) |
|
975 | _license_cache = json.loads(licenses) | |
981 |
|
976 | |||
982 | return _license_cache |
|
977 | return _license_cache | |
|
978 | ||||
|
979 | ||||
|
980 | def get_registry(request): | |||
|
981 | """ | |||
|
982 | Utility to get the pyramid registry from a request. During migration to | |||
|
983 | pyramid we sometimes want to use the pyramid registry from pylons context. | |||
|
984 | Therefore this utility returns `request.registry` for pyramid requests and | |||
|
985 | uses `get_current_registry()` for pylons requests. | |||
|
986 | """ | |||
|
987 | try: | |||
|
988 | return request.registry | |||
|
989 | except AttributeError: | |||
|
990 | return get_current_registry() |
@@ -321,7 +321,8 b' def engine_from_config(configuration, pr' | |||||
321 | setattr(conn, 'query_start_time', time.time()) |
|
321 | setattr(conn, 'query_start_time', time.time()) | |
322 | log.info(color_sql(">>>>> STARTING QUERY >>>>>")) |
|
322 | log.info(color_sql(">>>>> STARTING QUERY >>>>>")) | |
323 | calling_context = find_calling_context(ignore_modules=[ |
|
323 | calling_context = find_calling_context(ignore_modules=[ | |
324 | 'rhodecode.lib.caching_query' |
|
324 | 'rhodecode.lib.caching_query', | |
|
325 | 'rhodecode.model.settings', | |||
325 | ]) |
|
326 | ]) | |
326 | if calling_context: |
|
327 | if calling_context: | |
327 | log.info(color_sql('call context %s:%s' % ( |
|
328 | log.info(color_sql('call context %s:%s' % ( | |
@@ -341,6 +342,12 b' def engine_from_config(configuration, pr' | |||||
341 | return engine |
|
342 | return engine | |
342 |
|
343 | |||
343 |
|
344 | |||
|
345 | def get_encryption_key(config): | |||
|
346 | secret = config.get('rhodecode.encrypted_values.secret') | |||
|
347 | default = config['beaker.session.secret'] | |||
|
348 | return secret or default | |||
|
349 | ||||
|
350 | ||||
344 | def age(prevdate, now=None, show_short_version=False, show_suffix=True, |
|
351 | def age(prevdate, now=None, show_short_version=False, show_suffix=True, | |
345 | short_format=False): |
|
352 | short_format=False): | |
346 | """ |
|
353 | """ |
@@ -93,11 +93,14 b' def connect_http(server_and_port):' | |||||
93 | from rhodecode.lib.vcs import connection, client_http |
|
93 | from rhodecode.lib.vcs import connection, client_http | |
94 | from rhodecode.lib.middleware.utils import scm_app |
|
94 | from rhodecode.lib.middleware.utils import scm_app | |
95 |
|
95 | |||
96 |
session = |
|
96 | session_factory = client_http.ThreadlocalSessionFactory() | |
97 |
|
97 | |||
98 |
connection.Git = client_http.RepoMaker( |
|
98 | connection.Git = client_http.RepoMaker( | |
99 |
|
|
99 | server_and_port, '/git', session_factory) | |
100 |
connection. |
|
100 | connection.Hg = client_http.RepoMaker( | |
|
101 | server_and_port, '/hg', session_factory) | |||
|
102 | connection.Svn = client_http.RepoMaker( | |||
|
103 | server_and_port, '/svn', session_factory) | |||
101 |
|
104 | |||
102 | scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy( |
|
105 | scm_app.HG_REMOTE_WSGI = client_http.VcsHttpProxy( | |
103 | server_and_port, '/proxy/hg') |
|
106 | server_and_port, '/proxy/hg') |
@@ -31,6 +31,7 b' implementation.' | |||||
31 |
|
31 | |||
32 | import copy |
|
32 | import copy | |
33 | import logging |
|
33 | import logging | |
|
34 | import threading | |||
34 | import urllib2 |
|
35 | import urllib2 | |
35 | import urlparse |
|
36 | import urlparse | |
36 | import uuid |
|
37 | import uuid | |
@@ -38,7 +39,7 b' import uuid' | |||||
38 | import msgpack |
|
39 | import msgpack | |
39 | import requests |
|
40 | import requests | |
40 |
|
41 | |||
41 | from . import exceptions |
|
42 | from . import exceptions, CurlSession | |
42 |
|
43 | |||
43 |
|
44 | |||
44 | log = logging.getLogger(__name__) |
|
45 | log = logging.getLogger(__name__) | |
@@ -54,15 +55,16 b' EXCEPTIONS_MAP = {' | |||||
54 |
|
55 | |||
55 | class RepoMaker(object): |
|
56 | class RepoMaker(object): | |
56 |
|
57 | |||
57 | def __init__(self, server_and_port, backend_endpoint, session): |
|
58 | def __init__(self, server_and_port, backend_endpoint, session_factory): | |
58 | self.url = urlparse.urljoin( |
|
59 | self.url = urlparse.urljoin( | |
59 | 'http://%s' % server_and_port, backend_endpoint) |
|
60 | 'http://%s' % server_and_port, backend_endpoint) | |
60 | self._session = session |
|
61 | self._session_factory = session_factory | |
61 |
|
62 | |||
62 | def __call__(self, path, config, with_wire=None): |
|
63 | def __call__(self, path, config, with_wire=None): | |
63 | log.debug('RepoMaker call on %s', path) |
|
64 | log.debug('RepoMaker call on %s', path) | |
64 | return RemoteRepo( |
|
65 | return RemoteRepo( | |
65 |
path, config, self.url, self._session, |
|
66 | path, config, self.url, self._session_factory(), | |
|
67 | with_wire=with_wire) | |||
66 |
|
68 | |||
67 | def __getattr__(self, name): |
|
69 | def __getattr__(self, name): | |
68 | def f(*args, **kwargs): |
|
70 | def f(*args, **kwargs): | |
@@ -76,7 +78,8 b' class RepoMaker(object):' | |||||
76 | 'method': name, |
|
78 | 'method': name, | |
77 | 'params': {'args': args, 'kwargs': kwargs} |
|
79 | 'params': {'args': args, 'kwargs': kwargs} | |
78 | } |
|
80 | } | |
79 | return _remote_call(self.url, payload, EXCEPTIONS_MAP, self._session) |
|
81 | return _remote_call( | |
|
82 | self.url, payload, EXCEPTIONS_MAP, self._session_factory()) | |||
80 |
|
83 | |||
81 |
|
84 | |||
82 | class RemoteRepo(object): |
|
85 | class RemoteRepo(object): | |
@@ -216,3 +219,17 b' class VcsHttpProxy(object):' | |||||
216 | headers = iterator.next() |
|
219 | headers = iterator.next() | |
217 |
|
220 | |||
218 | return iterator, status, headers |
|
221 | return iterator, status, headers | |
|
222 | ||||
|
223 | ||||
|
224 | class ThreadlocalSessionFactory(object): | |||
|
225 | """ | |||
|
226 | Creates one CurlSession per thread on demand. | |||
|
227 | """ | |||
|
228 | ||||
|
229 | def __init__(self): | |||
|
230 | self._thread_local = threading.local() | |||
|
231 | ||||
|
232 | def __call__(self): | |||
|
233 | if not hasattr(self._thread_local, 'curl_session'): | |||
|
234 | self._thread_local.curl_session = CurlSession() | |||
|
235 | return self._thread_local.curl_session |
@@ -43,9 +43,10 b" The application's model objects" | |||||
43 | import logging |
|
43 | import logging | |
44 |
|
44 | |||
45 | from pylons import config |
|
45 | from pylons import config | |
|
46 | from pyramid.threadlocal import get_current_registry | |||
46 |
|
47 | |||
47 | from rhodecode.model import meta, db |
|
48 | from rhodecode.model import meta, db | |
48 | from rhodecode.lib.utils2 import obfuscate_url_pw |
|
49 | from rhodecode.lib.utils2 import obfuscate_url_pw, get_encryption_key | |
49 |
|
50 | |||
50 | log = logging.getLogger(__name__) |
|
51 | log = logging.getLogger(__name__) | |
51 |
|
52 | |||
@@ -65,8 +66,8 b' def init_model(engine, encryption_key=No' | |||||
65 |
|
66 | |||
66 |
|
67 | |||
67 | def init_model_encryption(migration_models): |
|
68 | def init_model_encryption(migration_models): | |
68 |
migration_models.ENCRYPTION_KEY = config |
|
69 | migration_models.ENCRYPTION_KEY = get_encryption_key(config) | |
69 | db.ENCRYPTION_KEY = config['beaker.session.secret'] |
|
70 | db.ENCRYPTION_KEY = get_encryption_key(config) | |
70 |
|
71 | |||
71 |
|
72 | |||
72 | class BaseModel(object): |
|
73 | class BaseModel(object): | |
@@ -144,6 +145,17 b' class BaseModel(object):' | |||||
144 | return self._get_instance( |
|
145 | return self._get_instance( | |
145 | db.Permission, permission, callback=db.Permission.get_by_key) |
|
146 | db.Permission, permission, callback=db.Permission.get_by_key) | |
146 |
|
147 | |||
|
148 | def send_event(self, event): | |||
|
149 | """ | |||
|
150 | Helper method to send an event. This wraps the pyramid logic to send an | |||
|
151 | event. | |||
|
152 | """ | |||
|
153 | # For the first step we are using pyramids thread locals here. If the | |||
|
154 | # event mechanism works out as a good solution we should think about | |||
|
155 | # passing the registry into the constructor to get rid of it. | |||
|
156 | registry = get_current_registry() | |||
|
157 | registry.notify(event) | |||
|
158 | ||||
147 | @classmethod |
|
159 | @classmethod | |
148 | def get_all(cls): |
|
160 | def get_all(cls): | |
149 | """ |
|
161 | """ |
@@ -70,7 +70,8 b' log = logging.getLogger(__name__)' | |||||
70 | # BASE CLASSES |
|
70 | # BASE CLASSES | |
71 | # ============================================================================= |
|
71 | # ============================================================================= | |
72 |
|
72 | |||
73 |
# this is propagated from .ini file |
|
73 | # this is propagated from .ini file rhodecode.encrypted_values.secret or | |
|
74 | # beaker.session.secret if first is not set. | |||
74 | # and initialized at environment.py |
|
75 | # and initialized at environment.py | |
75 | ENCRYPTION_KEY = None |
|
76 | ENCRYPTION_KEY = None | |
76 |
|
77 | |||
@@ -115,14 +116,17 b' class EncryptedTextValue(TypeDecorator):' | |||||
115 | def process_bind_param(self, value, dialect): |
|
116 | def process_bind_param(self, value, dialect): | |
116 | if not value: |
|
117 | if not value: | |
117 | return value |
|
118 | return value | |
118 | if value.startswith('enc$aes$'): |
|
119 | if value.startswith('enc$aes$') or value.startswith('enc$aes_hmac$'): | |
119 | # protect against double encrypting if someone manually starts |
|
120 | # protect against double encrypting if someone manually starts | |
120 | # doing |
|
121 | # doing | |
121 | raise ValueError('value needs to be in unencrypted format, ie. ' |
|
122 | raise ValueError('value needs to be in unencrypted format, ie. ' | |
122 |
'not starting with enc$aes |
|
123 | 'not starting with enc$aes') | |
123 |
return 'enc$aes$%s' % AESCipher( |
|
124 | return 'enc$aes_hmac$%s' % AESCipher( | |
|
125 | ENCRYPTION_KEY, hmac=True).encrypt(value) | |||
124 |
|
126 | |||
125 | def process_result_value(self, value, dialect): |
|
127 | def process_result_value(self, value, dialect): | |
|
128 | import rhodecode | |||
|
129 | ||||
126 | if not value: |
|
130 | if not value: | |
127 | return value |
|
131 | return value | |
128 |
|
132 | |||
@@ -134,9 +138,19 b' class EncryptedTextValue(TypeDecorator):' | |||||
134 | if parts[0] != 'enc': |
|
138 | if parts[0] != 'enc': | |
135 | # parts ok but without our header ? |
|
139 | # parts ok but without our header ? | |
136 | return value |
|
140 | return value | |
137 |
|
141 | enc_strict_mode = str2bool(rhodecode.CONFIG.get( | ||
|
142 | 'rhodecode.encrypted_values.strict') or True) | |||
138 | # at that stage we know it's our encryption |
|
143 | # at that stage we know it's our encryption | |
139 | decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) |
|
144 | if parts[1] == 'aes': | |
|
145 | decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2]) | |||
|
146 | elif parts[1] == 'aes_hmac': | |||
|
147 | decrypted_data = AESCipher( | |||
|
148 | ENCRYPTION_KEY, hmac=True, | |||
|
149 | strict_verification=enc_strict_mode).decrypt(parts[2]) | |||
|
150 | else: | |||
|
151 | raise ValueError( | |||
|
152 | 'Encryption type part is wrong, must be `aes` ' | |||
|
153 | 'or `aes_hmac`, got `%s` instead' % (parts[1])) | |||
140 | return decrypted_data |
|
154 | return decrypted_data | |
141 |
|
155 | |||
142 |
|
156 | |||
@@ -220,6 +234,20 b' class BaseModel(object):' | |||||
220 | obj = cls.query().get(id_) |
|
234 | obj = cls.query().get(id_) | |
221 | Session().delete(obj) |
|
235 | Session().delete(obj) | |
222 |
|
236 | |||
|
237 | @classmethod | |||
|
238 | def identity_cache(cls, session, attr_name, value): | |||
|
239 | exist_in_session = [] | |||
|
240 | for (item_cls, pkey), instance in session.identity_map.items(): | |||
|
241 | if cls == item_cls and getattr(instance, attr_name) == value: | |||
|
242 | exist_in_session.append(instance) | |||
|
243 | if exist_in_session: | |||
|
244 | if len(exist_in_session) == 1: | |||
|
245 | return exist_in_session[0] | |||
|
246 | log.exception( | |||
|
247 | 'multiple objects with attr %s and ' | |||
|
248 | 'value %s found with same name: %r', | |||
|
249 | attr_name, value, exist_in_session) | |||
|
250 | ||||
223 | def __repr__(self): |
|
251 | def __repr__(self): | |
224 | if hasattr(self, '__unicode__'): |
|
252 | if hasattr(self, '__unicode__'): | |
225 | # python repr needs to return str |
|
253 | # python repr needs to return str | |
@@ -639,16 +667,26 b' class User(Base, BaseModel):' | |||||
639 | log.error(traceback.format_exc()) |
|
667 | log.error(traceback.format_exc()) | |
640 |
|
668 | |||
641 | @classmethod |
|
669 | @classmethod | |
642 |
def get_by_username(cls, username, case_insensitive=False, |
|
670 | def get_by_username(cls, username, case_insensitive=False, | |
|
671 | cache=False, identity_cache=False): | |||
|
672 | session = Session() | |||
|
673 | ||||
643 | if case_insensitive: |
|
674 | if case_insensitive: | |
644 | q = cls.query().filter(func.lower(cls.username) == func.lower(username)) |
|
675 | q = cls.query().filter( | |
|
676 | func.lower(cls.username) == func.lower(username)) | |||
645 | else: |
|
677 | else: | |
646 | q = cls.query().filter(cls.username == username) |
|
678 | q = cls.query().filter(cls.username == username) | |
647 |
|
679 | |||
648 | if cache: |
|
680 | if cache: | |
649 | q = q.options(FromCache( |
|
681 | if identity_cache: | |
650 | "sql_cache_short", |
|
682 | val = cls.identity_cache(session, 'username', username) | |
651 | "get_user_%s" % _hash_key(username))) |
|
683 | if val: | |
|
684 | return val | |||
|
685 | else: | |||
|
686 | q = q.options( | |||
|
687 | FromCache("sql_cache_short", | |||
|
688 | "get_user_by_name_%s" % _hash_key(username))) | |||
|
689 | ||||
652 | return q.scalar() |
|
690 | return q.scalar() | |
653 |
|
691 | |||
654 | @classmethod |
|
692 | @classmethod | |
@@ -752,10 +790,10 b' class User(Base, BaseModel):' | |||||
752 | Session().add(self) |
|
790 | Session().add(self) | |
753 |
|
791 | |||
754 | @classmethod |
|
792 | @classmethod | |
755 | def get_first_admin(cls): |
|
793 | def get_first_super_admin(cls): | |
756 |
user = User.query().filter(User.admin == |
|
794 | user = User.query().filter(User.admin == true()).first() | |
757 | if user is None: |
|
795 | if user is None: | |
758 | raise Exception('Missing administrative account!') |
|
796 | raise Exception('FATAL: Missing administrative account!') | |
759 | return user |
|
797 | return user | |
760 |
|
798 | |||
761 | @classmethod |
|
799 | @classmethod | |
@@ -770,7 +808,7 b' class User(Base, BaseModel):' | |||||
770 | def get_default_user(cls, cache=False): |
|
808 | def get_default_user(cls, cache=False): | |
771 | user = User.get_by_username(User.DEFAULT_USER, cache=cache) |
|
809 | user = User.get_by_username(User.DEFAULT_USER, cache=cache) | |
772 | if user is None: |
|
810 | if user is None: | |
773 | raise Exception('Missing default account!') |
|
811 | raise Exception('FATAL: Missing default account!') | |
774 | return user |
|
812 | return user | |
775 |
|
813 | |||
776 | def _get_default_perms(self, user, suffix=''): |
|
814 | def _get_default_perms(self, user, suffix=''): | |
@@ -1264,9 +1302,9 b' class Repository(Base, BaseModel):' | |||||
1264 | "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, |
|
1302 | "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, | |
1265 | unique=False, default=None) |
|
1303 | unique=False, default=None) | |
1266 |
|
1304 | |||
1267 | user = relationship('User') |
|
1305 | user = relationship('User', lazy='joined') | |
1268 | fork = relationship('Repository', remote_side=repo_id) |
|
1306 | fork = relationship('Repository', remote_side=repo_id, lazy='joined') | |
1269 | group = relationship('RepoGroup') |
|
1307 | group = relationship('RepoGroup', lazy='joined') | |
1270 | repo_to_perm = relationship( |
|
1308 | repo_to_perm = relationship( | |
1271 | 'UserRepoToPerm', cascade='all', |
|
1309 | 'UserRepoToPerm', cascade='all', | |
1272 | order_by='UserRepoToPerm.repo_to_perm_id') |
|
1310 | order_by='UserRepoToPerm.repo_to_perm_id') | |
@@ -1364,7 +1402,7 b' class Repository(Base, BaseModel):' | |||||
1364 | def normalize_repo_name(cls, repo_name): |
|
1402 | def normalize_repo_name(cls, repo_name): | |
1365 | """ |
|
1403 | """ | |
1366 | Normalizes os specific repo_name to the format internally stored inside |
|
1404 | Normalizes os specific repo_name to the format internally stored inside | |
1367 |
da |
|
1405 | database using URL_SEP | |
1368 |
|
1406 | |||
1369 | :param cls: |
|
1407 | :param cls: | |
1370 | :param repo_name: |
|
1408 | :param repo_name: | |
@@ -1372,11 +1410,20 b' class Repository(Base, BaseModel):' | |||||
1372 | return cls.NAME_SEP.join(repo_name.split(os.sep)) |
|
1410 | return cls.NAME_SEP.join(repo_name.split(os.sep)) | |
1373 |
|
1411 | |||
1374 | @classmethod |
|
1412 | @classmethod | |
1375 | def get_by_repo_name(cls, repo_name): |
|
1413 | def get_by_repo_name(cls, repo_name, cache=False, identity_cache=False): | |
1376 | q = Session().query(cls).filter(cls.repo_name == repo_name) |
|
1414 | session = Session() | |
1377 | q = q.options(joinedload(Repository.fork))\ |
|
1415 | q = session.query(cls).filter(cls.repo_name == repo_name) | |
1378 | .options(joinedload(Repository.user))\ |
|
1416 | ||
1379 | .options(joinedload(Repository.group)) |
|
1417 | if cache: | |
|
1418 | if identity_cache: | |||
|
1419 | val = cls.identity_cache(session, 'repo_name', repo_name) | |||
|
1420 | if val: | |||
|
1421 | return val | |||
|
1422 | else: | |||
|
1423 | q = q.options( | |||
|
1424 | FromCache("sql_cache_short", | |||
|
1425 | "get_repo_by_name_%s" % _hash_key(repo_name))) | |||
|
1426 | ||||
1380 | return q.scalar() |
|
1427 | return q.scalar() | |
1381 |
|
1428 | |||
1382 | @classmethod |
|
1429 | @classmethod | |
@@ -1721,7 +1768,7 b' class Repository(Base, BaseModel):' | |||||
1721 | clone_uri = self.clone_uri |
|
1768 | clone_uri = self.clone_uri | |
1722 | if clone_uri: |
|
1769 | if clone_uri: | |
1723 | import urlobject |
|
1770 | import urlobject | |
1724 |
url_obj = urlobject.URLObject( |
|
1771 | url_obj = urlobject.URLObject(clone_uri) | |
1725 | if url_obj.password: |
|
1772 | if url_obj.password: | |
1726 | clone_uri = url_obj.with_password('*****') |
|
1773 | clone_uri = url_obj.with_password('*****') | |
1727 | return clone_uri |
|
1774 | return clone_uri |
@@ -138,7 +138,11 b' def UserForm(edit=False, available_langu' | |||||
138 | return _UserForm |
|
138 | return _UserForm | |
139 |
|
139 | |||
140 |
|
140 | |||
141 |
def UserGroupForm(edit=False, old_data= |
|
141 | def UserGroupForm(edit=False, old_data=None, available_members=None, | |
|
142 | allow_disabled=False): | |||
|
143 | old_data = old_data or {} | |||
|
144 | available_members = available_members or [] | |||
|
145 | ||||
142 | class _UserGroupForm(formencode.Schema): |
|
146 | class _UserGroupForm(formencode.Schema): | |
143 | allow_extra_fields = True |
|
147 | allow_extra_fields = True | |
144 | filter_extra_fields = True |
|
148 | filter_extra_fields = True | |
@@ -157,14 +161,18 b' def UserGroupForm(edit=False, old_data={' | |||||
157 | available_members, hideList=False, testValueList=True, |
|
161 | available_members, hideList=False, testValueList=True, | |
158 | if_missing=None, not_empty=False |
|
162 | if_missing=None, not_empty=False | |
159 | ) |
|
163 | ) | |
160 | #this is user group owner |
|
164 | # this is user group owner | |
161 | user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) |
|
165 | user = All( | |
162 |
|
166 | v.UnicodeString(not_empty=True), | ||
|
167 | v.ValidRepoUser(allow_disabled)) | |||
163 | return _UserGroupForm |
|
168 | return _UserGroupForm | |
164 |
|
169 | |||
165 |
|
170 | |||
166 |
def RepoGroupForm(edit=False, old_data= |
|
171 | def RepoGroupForm(edit=False, old_data=None, available_groups=None, | |
167 | can_create_in_root=False): |
|
172 | can_create_in_root=False, allow_disabled=False): | |
|
173 | old_data = old_data or {} | |||
|
174 | available_groups = available_groups or [] | |||
|
175 | ||||
168 | class _RepoGroupForm(formencode.Schema): |
|
176 | class _RepoGroupForm(formencode.Schema): | |
169 | allow_extra_fields = True |
|
177 | allow_extra_fields = True | |
170 | filter_extra_fields = False |
|
178 | filter_extra_fields = False | |
@@ -178,11 +186,14 b' def RepoGroupForm(edit=False, old_data={' | |||||
178 | group_parent_id = v.OneOf(available_groups, hideList=False, |
|
186 | group_parent_id = v.OneOf(available_groups, hideList=False, | |
179 | testValueList=True, not_empty=True) |
|
187 | testValueList=True, not_empty=True) | |
180 | enable_locking = v.StringBoolean(if_missing=False) |
|
188 | enable_locking = v.StringBoolean(if_missing=False) | |
181 | chained_validators = [v.ValidRepoGroup(edit, old_data, can_create_in_root)] |
|
189 | chained_validators = [ | |
|
190 | v.ValidRepoGroup(edit, old_data, can_create_in_root)] | |||
182 |
|
191 | |||
183 | if edit: |
|
192 | if edit: | |
184 | #this is repo group owner |
|
193 | # this is repo group owner | |
185 | user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) |
|
194 | user = All( | |
|
195 | v.UnicodeString(not_empty=True), | |||
|
196 | v.ValidRepoUser(allow_disabled)) | |||
186 |
|
197 | |||
187 | return _RepoGroupForm |
|
198 | return _RepoGroupForm | |
188 |
|
199 | |||
@@ -221,7 +232,8 b' def PasswordResetForm():' | |||||
221 | return _PasswordResetForm |
|
232 | return _PasswordResetForm | |
222 |
|
233 | |||
223 |
|
234 | |||
224 |
def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None |
|
235 | def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None, | |
|
236 | allow_disabled=False): | |||
225 | old_data = old_data or {} |
|
237 | old_data = old_data or {} | |
226 | repo_groups = repo_groups or [] |
|
238 | repo_groups = repo_groups or [] | |
227 | landing_revs = landing_revs or [] |
|
239 | landing_revs = landing_revs or [] | |
@@ -248,7 +260,9 b' def RepoForm(edit=False, old_data=None, ' | |||||
248 |
|
260 | |||
249 | if edit: |
|
261 | if edit: | |
250 | # this is repo owner |
|
262 | # this is repo owner | |
251 | user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) |
|
263 | user = All( | |
|
264 | v.UnicodeString(not_empty=True), | |||
|
265 | v.ValidRepoUser(allow_disabled)) | |||
252 | clone_uri_change = v.UnicodeString( |
|
266 | clone_uri_change = v.UnicodeString( | |
253 | not_empty=False, if_missing=v.Missing) |
|
267 | not_empty=False, if_missing=v.Missing) | |
254 |
|
268 |
@@ -140,10 +140,12 b' class RepoModel(BaseModel):' | |||||
140 |
|
140 | |||
141 | return None |
|
141 | return None | |
142 |
|
142 | |||
143 | def get_users(self, name_contains=None, limit=20): |
|
143 | def get_users(self, name_contains=None, limit=20, only_active=True): | |
144 | # TODO: mikhail: move this method to the UserModel. |
|
144 | # TODO: mikhail: move this method to the UserModel. | |
145 | query = self.sa.query(User) |
|
145 | query = self.sa.query(User) | |
146 | query = query.filter(User.active == true()) |
|
146 | if only_active: | |
|
147 | query = query.filter(User.active == true()) | |||
|
148 | ||||
147 | if name_contains: |
|
149 | if name_contains: | |
148 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) |
|
150 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) | |
149 | query = query.filter( |
|
151 | query = query.filter( | |
@@ -165,16 +167,19 b' class RepoModel(BaseModel):' | |||||
165 | 'icon_link': h.gravatar_url(user.email, 14), |
|
167 | 'icon_link': h.gravatar_url(user.email, 14), | |
166 | 'value_display': h.person(user.email), |
|
168 | 'value_display': h.person(user.email), | |
167 | 'value': user.username, |
|
169 | 'value': user.username, | |
168 | 'value_type': 'user' |
|
170 | 'value_type': 'user', | |
|
171 | 'active': user.active, | |||
169 | } |
|
172 | } | |
170 | for user in users |
|
173 | for user in users | |
171 | ] |
|
174 | ] | |
172 | return _users |
|
175 | return _users | |
173 |
|
176 | |||
174 | def get_user_groups(self, name_contains=None, limit=20): |
|
177 | def get_user_groups(self, name_contains=None, limit=20, only_active=True): | |
175 | # TODO: mikhail: move this method to the UserGroupModel. |
|
178 | # TODO: mikhail: move this method to the UserGroupModel. | |
176 | query = self.sa.query(UserGroup) |
|
179 | query = self.sa.query(UserGroup) | |
177 | query = query.filter(UserGroup.users_group_active == true()) |
|
180 | if only_active: | |
|
181 | query = query.filter(UserGroup.users_group_active == true()) | |||
|
182 | ||||
178 | if name_contains: |
|
183 | if name_contains: | |
179 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) |
|
184 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) | |
180 | query = query.filter( |
|
185 | query = query.filter( | |
@@ -196,7 +201,8 b' class RepoModel(BaseModel):' | |||||
196 | 'value_display': 'Group: %s (%d members)' % ( |
|
201 | 'value_display': 'Group: %s (%d members)' % ( | |
197 | group.users_group_name, len(group.members),), |
|
202 | group.users_group_name, len(group.members),), | |
198 | 'value': group.users_group_name, |
|
203 | 'value': group.users_group_name, | |
199 | 'value_type': 'user_group' |
|
204 | 'value_type': 'user_group', | |
|
205 | 'active': group.users_group_active, | |||
200 | } |
|
206 | } | |
201 | for group in user_groups |
|
207 | for group in user_groups | |
202 | ] |
|
208 | ] | |
@@ -333,7 +339,7 b' class RepoModel(BaseModel):' | |||||
333 | if repo_info.user: |
|
339 | if repo_info.user: | |
334 | defaults.update({'user': repo_info.user.username}) |
|
340 | defaults.update({'user': repo_info.user.username}) | |
335 | else: |
|
341 | else: | |
336 | replacement_user = User.get_first_admin().username |
|
342 | replacement_user = User.get_first_super_admin().username | |
337 | defaults.update({'user': replacement_user}) |
|
343 | defaults.update({'user': replacement_user}) | |
338 |
|
344 | |||
339 | # fill repository users |
|
345 | # fill repository users |
@@ -23,6 +23,7 b' import logging' | |||||
23 | from collections import namedtuple |
|
23 | from collections import namedtuple | |
24 | from functools import wraps |
|
24 | from functools import wraps | |
25 |
|
25 | |||
|
26 | from rhodecode.lib import caches | |||
26 | from rhodecode.lib.caching_query import FromCache |
|
27 | from rhodecode.lib.caching_query import FromCache | |
27 | from rhodecode.lib.utils2 import ( |
|
28 | from rhodecode.lib.utils2 import ( | |
28 | Optional, AttributeDict, safe_str, remove_prefix, str2bool) |
|
29 | Optional, AttributeDict, safe_str, remove_prefix, str2bool) | |
@@ -200,23 +201,37 b' class SettingsModel(BaseModel):' | |||||
200 | Session.add(res) |
|
201 | Session.add(res) | |
201 | return res |
|
202 | return res | |
202 |
|
203 | |||
|
204 | def invalidate_settings_cache(self): | |||
|
205 | namespace = 'rhodecode_settings' | |||
|
206 | cache_manager = caches.get_cache_manager('sql_cache_short', namespace) | |||
|
207 | caches.clear_cache_manager(cache_manager) | |||
|
208 | ||||
203 | def get_all_settings(self, cache=False): |
|
209 | def get_all_settings(self, cache=False): | |
204 | q = self._get_settings_query() |
|
210 | def _compute(): | |
205 | if cache: |
|
211 | q = self._get_settings_query() | |
206 | repo = self._get_repo(self.repo) if self.repo else None |
|
212 | if not q: | |
207 | cache_key = ( |
|
213 | raise Exception('Could not get application settings !') | |
208 | "get_repo_{}_settings".format(repo.repo_id) |
|
|||
209 | if repo else "get_hg_settings") |
|
|||
210 | q = q.options(FromCache("sql_cache_short", cache_key)) |
|
|||
211 |
|
214 | |||
212 | if not q: |
|
215 | settings = { | |
213 | raise Exception('Could not get application settings !') |
|
216 | 'rhodecode_' + result.app_settings_name: result.app_settings_value | |
|
217 | for result in q | |||
|
218 | } | |||
|
219 | return settings | |||
214 |
|
220 | |||
215 | settings = { |
|
221 | if cache: | |
216 | 'rhodecode_' + result.app_settings_name: result.app_settings_value |
|
222 | log.debug('Fetching app settings using cache') | |
217 | for result in q |
|
223 | repo = self._get_repo(self.repo) if self.repo else None | |
218 | } |
|
224 | namespace = 'rhodecode_settings' | |
219 | return settings |
|
225 | cache_manager = caches.get_cache_manager( | |
|
226 | 'sql_cache_short', namespace) | |||
|
227 | _cache_key = ( | |||
|
228 | "get_repo_{}_settings".format(repo.repo_id) | |||
|
229 | if repo else "get_app_settings") | |||
|
230 | ||||
|
231 | return cache_manager.get(_cache_key, createfunc=_compute) | |||
|
232 | ||||
|
233 | else: | |||
|
234 | return _compute() | |||
220 |
|
235 | |||
221 | def get_auth_settings(self): |
|
236 | def get_auth_settings(self): | |
222 | q = self._get_settings_query() |
|
237 | q = self._get_settings_query() |
@@ -26,13 +26,13 b' import logging' | |||||
26 | import traceback |
|
26 | import traceback | |
27 |
|
27 | |||
28 | import datetime |
|
28 | import datetime | |
29 | from pylons import url |
|
|||
30 | from pylons.i18n.translation import _ |
|
29 | from pylons.i18n.translation import _ | |
31 |
|
30 | |||
32 | import ipaddress |
|
31 | import ipaddress | |
33 | from sqlalchemy.exc import DatabaseError |
|
32 | from sqlalchemy.exc import DatabaseError | |
34 | from sqlalchemy.sql.expression import true, false |
|
33 | from sqlalchemy.sql.expression import true, false | |
35 |
|
34 | |||
|
35 | from rhodecode.events import UserPreCreate, UserPreUpdate | |||
36 | from rhodecode.lib.utils2 import ( |
|
36 | from rhodecode.lib.utils2 import ( | |
37 | safe_unicode, get_current_rhodecode_user, action_logger_generic, |
|
37 | safe_unicode, get_current_rhodecode_user, action_logger_generic, | |
38 | AttributeDict) |
|
38 | AttributeDict) | |
@@ -270,10 +270,12 b' class UserModel(BaseModel):' | |||||
270 | # raises UserCreationError if it's not allowed for any reason to |
|
270 | # raises UserCreationError if it's not allowed for any reason to | |
271 | # create new active user, this also executes pre-create hooks |
|
271 | # create new active user, this also executes pre-create hooks | |
272 | check_allowed_create_user(user_data, cur_user, strict_check=True) |
|
272 | check_allowed_create_user(user_data, cur_user, strict_check=True) | |
|
273 | self.send_event(UserPreCreate(user_data)) | |||
273 | new_user = User() |
|
274 | new_user = User() | |
274 | edit = False |
|
275 | edit = False | |
275 | else: |
|
276 | else: | |
276 | log.debug('updating user %s', username) |
|
277 | log.debug('updating user %s', username) | |
|
278 | self.send_event(UserPreUpdate(user, user_data)) | |||
277 | new_user = user |
|
279 | new_user = user | |
278 | edit = True |
|
280 | edit = True | |
279 |
|
281 | |||
@@ -375,7 +377,7 b' class UserModel(BaseModel):' | |||||
375 | raise |
|
377 | raise | |
376 |
|
378 | |||
377 | def _handle_user_repos(self, username, repositories, handle_mode=None): |
|
379 | def _handle_user_repos(self, username, repositories, handle_mode=None): | |
378 | _superadmin = self.cls.get_first_admin() |
|
380 | _superadmin = self.cls.get_first_super_admin() | |
379 | left_overs = True |
|
381 | left_overs = True | |
380 |
|
382 | |||
381 | from rhodecode.model.repo import RepoModel |
|
383 | from rhodecode.model.repo import RepoModel | |
@@ -398,7 +400,7 b' class UserModel(BaseModel):' | |||||
398 |
|
400 | |||
399 | def _handle_user_repo_groups(self, username, repository_groups, |
|
401 | def _handle_user_repo_groups(self, username, repository_groups, | |
400 | handle_mode=None): |
|
402 | handle_mode=None): | |
401 | _superadmin = self.cls.get_first_admin() |
|
403 | _superadmin = self.cls.get_first_super_admin() | |
402 | left_overs = True |
|
404 | left_overs = True | |
403 |
|
405 | |||
404 | from rhodecode.model.repo_group import RepoGroupModel |
|
406 | from rhodecode.model.repo_group import RepoGroupModel | |
@@ -420,7 +422,7 b' class UserModel(BaseModel):' | |||||
420 | return left_overs |
|
422 | return left_overs | |
421 |
|
423 | |||
422 | def _handle_user_user_groups(self, username, user_groups, handle_mode=None): |
|
424 | def _handle_user_user_groups(self, username, user_groups, handle_mode=None): | |
423 | _superadmin = self.cls.get_first_admin() |
|
425 | _superadmin = self.cls.get_first_super_admin() | |
424 | left_overs = True |
|
426 | left_overs = True | |
425 |
|
427 | |||
426 | from rhodecode.model.user_group import UserGroupModel |
|
428 | from rhodecode.model.user_group import UserGroupModel |
@@ -498,7 +498,7 b' class UserGroupModel(BaseModel):' | |||||
498 | self.remove_user_from_group(gr, user) |
|
498 | self.remove_user_from_group(gr, user) | |
499 |
|
499 | |||
500 | # now we calculate in which groups user should be == groups params |
|
500 | # now we calculate in which groups user should be == groups params | |
501 | owner = User.get_first_admin().username |
|
501 | owner = User.get_first_super_admin().username | |
502 | for gr in set(groups): |
|
502 | for gr in set(groups): | |
503 | existing_group = UserGroup.get_by_group_name(gr) |
|
503 | existing_group = UserGroup.get_by_group_name(gr) | |
504 | if not existing_group: |
|
504 | if not existing_group: |
@@ -193,21 +193,26 b' def ValidRegex(msg=None):' | |||||
193 | return _validator |
|
193 | return _validator | |
194 |
|
194 | |||
195 |
|
195 | |||
196 | def ValidRepoUser(): |
|
196 | def ValidRepoUser(allow_disabled=False): | |
197 | class _validator(formencode.validators.FancyValidator): |
|
197 | class _validator(formencode.validators.FancyValidator): | |
198 | messages = { |
|
198 | messages = { | |
199 | 'invalid_username': _(u'Username %(username)s is not valid') |
|
199 | 'invalid_username': _(u'Username %(username)s is not valid'), | |
|
200 | 'disabled_username': _(u'Username %(username)s is disabled') | |||
200 | } |
|
201 | } | |
201 |
|
202 | |||
202 | def validate_python(self, value, state): |
|
203 | def validate_python(self, value, state): | |
203 | try: |
|
204 | try: | |
204 |
User.query().filter(User. |
|
205 | user = User.query().filter(User.username == value).one() | |
205 | .filter(User.username == value).one() |
|
|||
206 | except Exception: |
|
206 | except Exception: | |
207 | msg = M(self, 'invalid_username', state, username=value) |
|
207 | msg = M(self, 'invalid_username', state, username=value) | |
208 | raise formencode.Invalid( |
|
208 | raise formencode.Invalid( | |
209 | msg, value, state, error_dict={'username': msg} |
|
209 | msg, value, state, error_dict={'username': msg} | |
210 | ) |
|
210 | ) | |
|
211 | if user and (not allow_disabled and not user.active): | |||
|
212 | msg = M(self, 'disabled_username', state, username=value) | |||
|
213 | raise formencode.Invalid( | |||
|
214 | msg, value, state, error_dict={'username': msg} | |||
|
215 | ) | |||
211 |
|
216 | |||
212 | return _validator |
|
217 | return _validator | |
213 |
|
218 |
@@ -269,6 +269,33 b' form.rcform {' | |||||
269 |
|
269 | |||
270 | } |
|
270 | } | |
271 |
|
271 | |||
|
272 | .badged-field { | |||
|
273 | .user-badge { | |||
|
274 | line-height: 25px; | |||
|
275 | padding: 10px 5px; | |||
|
276 | border-radius: @border-radius; | |||
|
277 | border-top: 1px solid @rclightblue; | |||
|
278 | border-left: 1px solid @rclightblue; | |||
|
279 | border-bottom: 1px solid @rclightblue; | |||
|
280 | font-size: 14px; | |||
|
281 | font-style: normal; | |||
|
282 | color: @text-light; | |||
|
283 | display: inline-block; | |||
|
284 | vertical-align: top; | |||
|
285 | cursor: default; | |||
|
286 | margin-right: -2px; | |||
|
287 | } | |||
|
288 | .badge-input-container { | |||
|
289 | display: flex; | |||
|
290 | position: relative; | |||
|
291 | } | |||
|
292 | .user-disabled { | |||
|
293 | text-decoration: line-through; | |||
|
294 | } | |||
|
295 | .badge-input-wrap { | |||
|
296 | display: inline-block; | |||
|
297 | } | |||
|
298 | } | |||
272 |
|
299 | |||
273 | // for situations where we wish to display the form value but not the form input |
|
300 | // for situations where we wish to display the form value but not the form input | |
274 | input.input-valuedisplay { |
|
301 | input.input-valuedisplay { |
@@ -296,30 +296,30 b' ul.auth_plugins {' | |||||
296 | } |
|
296 | } | |
297 | } |
|
297 | } | |
298 |
|
298 | |||
299 | // Pull Requests |
|
299 | ||
|
300 | // My Account PR list | |||
|
301 | ||||
|
302 | #show_closed { | |||
|
303 | margin: 0 1em 0 0; | |||
|
304 | } | |||
300 |
|
305 | |||
301 | .pullrequestlist { |
|
306 | .pullrequestlist { | |
302 | max-width: @pullrequest-width; |
|
307 | .closed { | |
303 | margin-bottom: @space; |
|
308 | background-color: @grey6; | |
304 |
|
309 | } | ||
305 | // Tweaks for "My Account" / "Pull requests" |
|
310 | .td-status { | |
306 | .prwrapper { |
|
311 | padding-left: .5em; | |
307 | clear: left; |
|
312 | } | |
|
313 | .truncate { | |||
|
314 | height: 2.75em; | |||
|
315 | white-space: pre-line; | |||
|
316 | } | |||
|
317 | table.rctable .user { | |||
|
318 | padding-left: 0; | |||
|
319 | } | |||
|
320 | } | |||
308 |
|
321 | |||
309 | .pr { |
|
322 | // Pull Requests | |
310 | margin: 0; |
|
|||
311 | padding: 0; |
|
|||
312 | border-bottom: none; |
|
|||
313 | } |
|
|||
314 |
|
||||
315 | // TODO: johbo: Replace with something that makes up an inline form or |
|
|||
316 | // similar. |
|
|||
317 | .repolist_actions { |
|
|||
318 | display: inline-block; |
|
|||
319 | } |
|
|||
320 | } |
|
|||
321 |
|
||||
322 | } |
|
|||
323 |
|
323 | |||
324 | .pullrequests_section_head { |
|
324 | .pullrequests_section_head { | |
325 | display: block; |
|
325 | display: block; | |
@@ -1086,6 +1086,7 b' table.issuetracker {' | |||||
1086 | } |
|
1086 | } | |
1087 | } |
|
1087 | } | |
1088 |
|
1088 | |||
|
1089 | ||||
1089 | //Permissions Settings |
|
1090 | //Permissions Settings | |
1090 | #add_perm { |
|
1091 | #add_perm { | |
1091 | margin: 0 0 @padding; |
|
1092 | margin: 0 0 @padding; |
@@ -28,7 +28,7 b'' | |||||
28 | margin: 0 7px 0 .7em; |
|
28 | margin: 0 7px 0 .7em; | |
29 | font-size: @basefontsize; |
|
29 | font-size: @basefontsize; | |
30 | color: white; |
|
30 | color: white; | |
31 |
|
31 | |||
32 | &.empty { |
|
32 | &.empty { | |
33 | background-color: @grey4; |
|
33 | background-color: @grey4; | |
34 | } |
|
34 | } | |
@@ -94,7 +94,7 b'' | |||||
94 | &:focus { |
|
94 | &:focus { | |
95 | outline: none; |
|
95 | outline: none; | |
96 | } |
|
96 | } | |
97 |
|
97 | |||
98 | ul li { |
|
98 | ul li { | |
99 | display: block; |
|
99 | display: block; | |
100 |
|
100 | |||
@@ -145,7 +145,7 b'' | |||||
145 | &:hover, |
|
145 | &:hover, | |
146 | &.open, |
|
146 | &.open, | |
147 | &.active { |
|
147 | &.active { | |
148 |
a { |
|
148 | a { | |
149 | color: @grey1; |
|
149 | color: @grey1; | |
150 | } |
|
150 | } | |
151 | } |
|
151 | } | |
@@ -288,6 +288,11 b'' | |||||
288 | } |
|
288 | } | |
289 | } |
|
289 | } | |
290 |
|
290 | |||
|
291 | .navigation li:last-child .submenu { | |||
|
292 | right: -20px; | |||
|
293 | left: auto; | |||
|
294 | } | |||
|
295 | ||||
291 | .submenu { |
|
296 | .submenu { | |
292 | position: absolute; |
|
297 | position: absolute; | |
293 | top: 100%; |
|
298 | top: 100%; | |
@@ -333,7 +338,7 b'' | |||||
333 | -moz-transition: background .3s; |
|
338 | -moz-transition: background .3s; | |
334 | -o-transition: background .3s; |
|
339 | -o-transition: background .3s; | |
335 | transition: background .3s; |
|
340 | transition: background .3s; | |
336 |
|
341 | |||
337 | ul { |
|
342 | ul { | |
338 | display: block; |
|
343 | display: block; | |
339 | } |
|
344 | } | |
@@ -480,7 +485,7 b'' | |||||
480 | &.select2-result-unselectable > .select2-result-label { |
|
485 | &.select2-result-unselectable > .select2-result-label { | |
481 | margin: 0 8px; |
|
486 | margin: 0 8px; | |
482 | } |
|
487 | } | |
483 |
|
488 | |||
484 | } |
|
489 | } | |
485 | } |
|
490 | } | |
486 |
|
491 | |||
@@ -594,7 +599,7 b' ul#context-pages {' | |||||
594 | padding: 0; |
|
599 | padding: 0; | |
595 | border: none; |
|
600 | border: none; | |
596 | } |
|
601 | } | |
597 |
|
602 | |||
598 | .nav-pills { |
|
603 | .nav-pills { | |
599 | margin: 0; |
|
604 | margin: 0; | |
600 | } |
|
605 | } |
@@ -6,7 +6,6 b'' | |||||
6 |
|
6 | |||
7 | width: 100%; |
|
7 | width: 100%; | |
8 | margin: 0 0 25px 0; |
|
8 | margin: 0 0 25px 0; | |
9 | border-color: @grey5; |
|
|||
10 | .border-radius(@border-radius); |
|
9 | .border-radius(@border-radius); | |
11 | .box-shadow(none); |
|
10 | .box-shadow(none); | |
12 |
|
11 | |||
@@ -23,7 +22,6 b'' | |||||
23 | position: relative; |
|
22 | position: relative; | |
24 | min-height: 1em; |
|
23 | min-height: 1em; | |
25 | padding: @padding @panel-padding; |
|
24 | padding: @padding @panel-padding; | |
26 | background-color: @grey6; |
|
|||
27 | border-bottom: none; |
|
25 | border-bottom: none; | |
28 |
|
26 | |||
29 | .panel-title, |
|
27 | .panel-title, |
@@ -19,19 +19,25 b'' | |||||
19 | /** |
|
19 | /** | |
20 | * autocomplete formatter that uses gravatar |
|
20 | * autocomplete formatter that uses gravatar | |
21 | * */ |
|
21 | * */ | |
22 | var autocompleteFormatResult = function(data, value, org_formatter) { |
|
22 | var autocompleteFormatResult = function (data, value, org_formatter) { | |
23 | var value_display = data.value_display; |
|
23 | var activeUser = data.active || true; | |
|
24 | var valueDisplay = data.value_display; | |||
|
25 | ||||
|
26 | if (!activeUser) { | |||
|
27 | valueDisplay = '<strong>(disabled)</strong> ' + valueDisplay; | |||
|
28 | } | |||
|
29 | ||||
24 | var escapeRegExChars = function (value) { |
|
30 | var escapeRegExChars = function (value) { | |
25 | return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); |
|
31 | return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | |
26 | }; |
|
32 | }; | |
27 | var pattern = '(' + escapeRegExChars(value) + ')'; |
|
33 | var pattern = '(' + escapeRegExChars(value) + ')'; | |
28 |
value |
|
34 | valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); | |
29 | var tmpl = '<div class="ac-container-wrap"><img class="gravatar" src="{0}"/>{1}</div>'; |
|
35 | var tmpl = '<div class="ac-container-wrap"><img class="gravatar" src="{0}"/>{1}</div>'; | |
30 | if (data.icon_link === "") { |
|
36 | if (data.icon_link === "") { | |
31 | tmpl = '<div class="ac-container-wrap">{0}</div>'; |
|
37 | tmpl = '<div class="ac-container-wrap">{0}</div>'; | |
32 |
return tmpl.format(value |
|
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,13 +1,12 b'' | |||||
|
1 | <%namespace name="base" file="/base/base.html"/> | |||
1 |
|
2 | |||
2 | <div class="panel panel-default"> |
|
3 | <div class="panel panel-default"> | |
3 | <div class="panel-body"> |
|
4 | <div class="panel-body"> | |
4 | <div class="field"> |
|
|||
5 | %if c.show_closed: |
|
5 | %if c.show_closed: | |
6 | ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))} |
|
6 | ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))} | |
7 | %else: |
|
7 | %else: | |
8 | ${h.checkbox('show_closed',label=_('Show Closed Pull Requests'))} |
|
8 | ${h.checkbox('show_closed',label=_('Show Closed Pull Requests'))} | |
9 | %endif |
|
9 | %endif | |
10 | </div> |
|
|||
11 | </div> |
|
10 | </div> | |
12 | </div> |
|
11 | </div> | |
13 |
|
12 | |||
@@ -15,29 +14,57 b'' | |||||
15 | <div class="panel-heading"> |
|
14 | <div class="panel-heading"> | |
16 | <h3 class="panel-title">${_('Pull Requests You Opened')}</h3> |
|
15 | <h3 class="panel-title">${_('Pull Requests You Opened')}</h3> | |
17 | </div> |
|
16 | </div> | |
18 |
|
||||
19 | <div class="panel-body"> |
|
17 | <div class="panel-body"> | |
20 | <div class="pullrequestlist"> |
|
18 | <div class="pullrequestlist"> | |
21 | %if c.my_pull_requests: |
|
19 | %if c.my_pull_requests: | |
|
20 | <table class="rctable"> | |||
|
21 | <thead> | |||
|
22 | <th class="td-status"></th> | |||
|
23 | <th>${_('Target Repo')}</th> | |||
|
24 | <th>${_('Author')}</th> | |||
|
25 | <th></th> | |||
|
26 | <th>${_('Title')}</th> | |||
|
27 | <th class="td-time">${_('Opened On')}</th> | |||
|
28 | <th></th> | |||
|
29 | </thead> | |||
22 | %for pull_request in c.my_pull_requests: |
|
30 | %for pull_request in c.my_pull_requests: | |
23 |
< |
|
31 | <tr class="${'closed' if pull_request.is_closed() else ''} prwrapper"> | |
24 |
<d |
|
32 | <td class="td-status"> | |
25 | <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div> |
|
33 | <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div> | |
26 | <a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}"> |
|
34 | </td> | |
27 | ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.format_date(pull_request.created_on))} |
|
35 | <td class="td-componentname"> | |
28 | %if pull_request.is_closed(): |
|
36 | ${h.link_to(pull_request.target_repo.repo_name,h.url('summary_home',repo_name=pull_request.target_repo.repo_name))} | |
29 | (${_('Closed')}) |
|
37 | </td> | |
30 | %endif |
|
38 | <td class="user"> | |
31 | </a> |
|
39 | ${base.gravatar_with_user(pull_request.author.email, 16)} | |
32 | <div class="repolist_actions"> |
|
40 | </td> | |
33 | ${h.secure_form(url('pullrequest_delete', repo_name=pull_request.target_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')} |
|
41 | <td class="td-message expand_commit" data-pr-id="m${pull_request.pull_request_id}" title="${_('Expand commit message')}"> | |
34 | ${h.submit('remove_%s' % pull_request.pull_request_id, _('Delete'), |
|
42 | <div class="show_more_col"> | |
35 | class_="btn btn-link btn-danger",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")} |
|
43 | <i class="show_more"></i> | |
36 | ${h.end_form()} |
|
|||
37 | </div> |
|
44 | </div> | |
38 |
</d |
|
45 | </td> | |
39 | </div> |
|
46 | <td class="mid td-description"> | |
|
47 | <div class="log-container truncate-wrap"> | |||
|
48 | <div class="message truncate" id="c-m${pull_request.pull_request_id}"><a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">#${pull_request.pull_request_id}: ${pull_request.title}</a>\ | |||
|
49 | %if pull_request.is_closed(): | |||
|
50 | (${_('Closed')})\ | |||
|
51 | %endif | |||
|
52 | <br/>${pull_request.description}</div> | |||
|
53 | </div> | |||
|
54 | </td> | |||
|
55 | ||||
|
56 | <td class="td-time"> | |||
|
57 | ${h.age_component(pull_request.created_on)} | |||
|
58 | </td> | |||
|
59 | <td class="td-action repolist_actions"> | |||
|
60 | ${h.secure_form(url('pullrequest_delete', repo_name=pull_request.target_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')} | |||
|
61 | ${h.submit('remove_%s' % pull_request.pull_request_id, _('Delete'), | |||
|
62 | class_="btn btn-link btn-danger",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")} | |||
|
63 | ${h.end_form()} | |||
|
64 | </td> | |||
|
65 | </tr> | |||
40 | %endfor |
|
66 | %endfor | |
|
67 | </table> | |||
41 | %else: |
|
68 | %else: | |
42 | <h2><span class="empty_data">${_('You currently have no open pull requests.')}</span></h2> |
|
69 | <h2><span class="empty_data">${_('You currently have no open pull requests.')}</span></h2> | |
43 | %endif |
|
70 | %endif | |
@@ -53,21 +80,49 b'' | |||||
53 | <div class="panel-body"> |
|
80 | <div class="panel-body"> | |
54 | <div class="pullrequestlist"> |
|
81 | <div class="pullrequestlist"> | |
55 | %if c.participate_in_pull_requests: |
|
82 | %if c.participate_in_pull_requests: | |
|
83 | <table class="rctable"> | |||
|
84 | <thead> | |||
|
85 | <th class="td-status"></th> | |||
|
86 | <th>${_('Target Repo')}</th> | |||
|
87 | <th>${_('Author')}</th> | |||
|
88 | <th></th> | |||
|
89 | <th>${_('Title')}</th> | |||
|
90 | <th class="td-time">${_('Opened On')}</th> | |||
|
91 | </thead> | |||
56 | %for pull_request in c.participate_in_pull_requests: |
|
92 | %for pull_request in c.participate_in_pull_requests: | |
57 |
< |
|
93 | <tr class="${'closed' if pull_request.is_closed() else ''} prwrapper"> | |
58 |
<d |
|
94 | <td class="td-status"> | |
59 | <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div> |
|
95 | <div class="${'flag_status %s' % pull_request.calculated_review_status()} pull-left"></div> | |
60 | <a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}"> |
|
96 | </td> | |
61 | ${_('Pull request #%s opened by %s on %s') % (pull_request.pull_request_id, pull_request.author.full_name, h.format_date(pull_request.created_on))} |
|
97 | <td class="td-componentname"> | |
62 | </a> |
|
98 | ${h.link_to(pull_request.target_repo.repo_name,h.url('summary_home',repo_name=pull_request.target_repo.repo_name))} | |
63 | %if pull_request.is_closed(): |
|
99 | </td> | |
64 | (${_('Closed')}) |
|
100 | <td class="user"> | |
65 | %endif |
|
101 | ${base.gravatar_with_user(pull_request.author.email, 16)} | |
66 |
</d |
|
102 | </td> | |
67 | </div> |
|
103 | <td class="td-message expand_commit" data-pr-id="p${pull_request.pull_request_id}" title="${_('Expand commit message')}"> | |
|
104 | <div class="show_more_col"> | |||
|
105 | <i class="show_more"></i> | |||
|
106 | </div> | |||
|
107 | </td> | |||
|
108 | <td class="mid td-description"> | |||
|
109 | <div class="log-container truncate-wrap"> | |||
|
110 | <div class="message truncate" id="c-p${pull_request.pull_request_id}"><a href="${h.url('pullrequest_show',repo_name=pull_request.target_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">#${pull_request.pull_request_id}: ${pull_request.title}</a>\ | |||
|
111 | %if pull_request.is_closed(): | |||
|
112 | (${_('Closed')})\ | |||
|
113 | %endif | |||
|
114 | <br/>${pull_request.description}</div> | |||
|
115 | </div> | |||
|
116 | </td> | |||
|
117 | ||||
|
118 | <td class="td-time"> | |||
|
119 | ${h.age_component(pull_request.created_on)} | |||
|
120 | </td> | |||
|
121 | </tr> | |||
68 | %endfor |
|
122 | %endfor | |
|
123 | </table> | |||
69 | %else: |
|
124 | %else: | |
70 |
< |
|
125 | <h2 class="empty_data">${_('There are currently no open pull requests requiring your participation.')}</h2> | |
71 | %endif |
|
126 | %endif | |
72 | </div> |
|
127 | </div> | |
73 | </div> |
|
128 | </div> | |
@@ -81,5 +136,18 b'' | |||||
81 | else{ |
|
136 | else{ | |
82 | window.location = "${h.url('my_account_pullrequests')}"; |
|
137 | window.location = "${h.url('my_account_pullrequests')}"; | |
83 | } |
|
138 | } | |
84 | }) |
|
139 | }); | |
|
140 | $('.expand_commit').on('click',function(e){ | |||
|
141 | var target_expand = $(this); | |||
|
142 | var cid = target_expand.data('prId'); | |||
|
143 | ||||
|
144 | if (target_expand.hasClass('open')){ | |||
|
145 | $('#c-'+cid).css({'height': '2.75em', 'text-overflow': 'ellipsis', 'overflow':'hidden'}); | |||
|
146 | target_expand.removeClass('open'); | |||
|
147 | } | |||
|
148 | else { | |||
|
149 | $('#c-'+cid).css({'height': 'auto', 'text-overflow': 'initial', 'overflow':'visible'}); | |||
|
150 | target_expand.addClass('open'); | |||
|
151 | } | |||
|
152 | }); | |||
85 | </script> |
|
153 | </script> |
@@ -1,4 +1,6 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
|
2 | <%namespace name="base" file="/base/base.html"/> | |||
|
3 | ||||
2 | <div class="panel panel-default"> |
|
4 | <div class="panel panel-default"> | |
3 | <div class="panel-heading"> |
|
5 | <div class="panel-heading"> | |
4 | <h3 class="panel-title">${_('Settings for Repository Group: %s') % c.repo_group.name}</h3> |
|
6 | <h3 class="panel-title">${_('Settings for Repository Group: %s') % c.repo_group.name}</h3> | |
@@ -16,15 +18,25 b'' | |||||
16 | ${h.text('group_name',class_='medium')} |
|
18 | ${h.text('group_name',class_='medium')} | |
17 | </div> |
|
19 | </div> | |
18 | </div> |
|
20 | </div> | |
19 | <div class="field"> |
|
21 | ||
|
22 | <div class="field badged-field"> | |||
20 | <div class="label"> |
|
23 | <div class="label"> | |
21 | <label for="user">${_('Owner')}:</label> |
|
24 | <label for="user">${_('Owner')}:</label> | |
22 | </div> |
|
25 | </div> | |
23 | <div class="input"> |
|
26 | <div class="input"> | |
24 | ${h.text('user', class_="medium", autocomplete="off")} |
|
27 | <div class="badge-input-container"> | |
25 | <span class="help-block">${_('Change Repository Group Owner.')}</span> |
|
28 | <div class="user-badge"> | |
|
29 | ${base.gravatar_with_user(c.repo_group.user.email, show_disabled=not c.repo_group.user.active)} | |||
|
30 | </div> | |||
|
31 | <div class="badge-input-wrap"> | |||
|
32 | ${h.text('user', class_="medium", autocomplete="off")} | |||
|
33 | </div> | |||
|
34 | </div> | |||
|
35 | <form:error name="user"/> | |||
|
36 | <p class="help-block">${_('Change owner of this repository group.')}</p> | |||
26 | </div> |
|
37 | </div> | |
27 | </div> |
|
38 | </div> | |
|
39 | ||||
28 | <div class="field"> |
|
40 | <div class="field"> | |
29 | <div class="label label-textarea"> |
|
41 | <div class="label label-textarea"> | |
30 | <label for="group_description">${_('Description')}:</label> |
|
42 | <label for="group_description">${_('Description')}:</label> |
@@ -1,3 +1,6 b'' | |||||
|
1 | ## -*- coding: utf-8 -*- | |||
|
2 | <%namespace name="base" file="/base/base.html"/> | |||
|
3 | ||||
1 | <div class="panel panel-default"> |
|
4 | <div class="panel panel-default"> | |
2 | <div class="panel-heading"> |
|
5 | <div class="panel-heading"> | |
3 | <h3 class="panel-title">${_('Settings for Repository: %s') % c.repo_info.repo_name}</h3> |
|
6 | <h3 class="panel-title">${_('Settings for Repository: %s') % c.repo_info.repo_name}</h3> | |
@@ -69,15 +72,25 b'' | |||||
69 | <p class="help-block">${_('Default commit for files page, downloads, whoosh and readme')}</p> |
|
72 | <p class="help-block">${_('Default commit for files page, downloads, whoosh and readme')}</p> | |
70 | </div> |
|
73 | </div> | |
71 | </div> |
|
74 | </div> | |
72 | <div class="field"> |
|
75 | ||
|
76 | <div class="field badged-field"> | |||
73 | <div class="label"> |
|
77 | <div class="label"> | |
74 | <label for="user">${_('Owner')}:</label> |
|
78 | <label for="user">${_('Owner')}:</label> | |
75 | </div> |
|
79 | </div> | |
76 | <div class="input"> |
|
80 | <div class="input"> | |
77 | ${h.text('user', class_="medium", autocomplete="off")} |
|
81 | <div class="badge-input-container"> | |
78 | <p class="help-block">${_('Change owner of this repository.')}</p> |
|
82 | <div class="user-badge"> | |
|
83 | ${base.gravatar_with_user(c.repo_info.user.email, show_disabled=not c.repo_info.user.active)} | |||
|
84 | </div> | |||
|
85 | <div class="badge-input-wrap"> | |||
|
86 | ${h.text('user', class_="medium", autocomplete="off")} | |||
|
87 | </div> | |||
|
88 | </div> | |||
|
89 | <form:error name="user"/> | |||
|
90 | <p class="help-block">${_('Change owner of this repository.')}</p> | |||
79 | </div> |
|
91 | </div> | |
80 |
|
|
92 | </div> | |
|
93 | ||||
81 | <div class="field"> |
|
94 | <div class="field"> | |
82 | <div class="label label-textarea"> |
|
95 | <div class="label label-textarea"> | |
83 | <label for="repo_description">${_('Description')}:</label> |
|
96 | <label for="repo_description">${_('Description')}:</label> |
@@ -20,6 +20,7 b'' | |||||
20 | <td> |
|
20 | <td> | |
21 | ${h.literal(', '.join([ |
|
21 | ${h.literal(', '.join([ | |
22 | '<a href="%(link)s" title="%(name)s">%(name)s</a>' % {'link':link, 'name':name} |
|
22 | '<a href="%(link)s" title="%(name)s">%(name)s</a>' % {'link':link, 'name':name} | |
|
23 | if link else name | |||
23 | for name,link in licenses.items()]))} |
|
24 | for name,link in licenses.items()]))} | |
24 | </td> |
|
25 | </td> | |
25 | </tr> |
|
26 | </tr> |
@@ -45,12 +45,15 b'' | |||||
45 | <div class="panel panel-default"> |
|
45 | <div class="panel panel-default"> | |
46 | <div class="panel-heading"> |
|
46 | <div class="panel-heading"> | |
47 | <h3 class="panel-title">${_('System Info')}</h3> |
|
47 | <h3 class="panel-title">${_('System Info')}</h3> | |
|
48 | % if c.allowed_to_snapshot: | |||
|
49 | <a href="${url('admin_settings_system', snapshot=1)}" class="panel-edit">${_('create snapshot')}</a> | |||
|
50 | % endif | |||
48 | </div> |
|
51 | </div> | |
49 | <div class="panel-body"> |
|
52 | <div class="panel-body"> | |
50 | <dl class="dl-horizontal settings"> |
|
53 | <dl class="dl-horizontal settings"> | |
51 | %for dt, dd, tt in elems: |
|
54 | %for dt, dd, tt in elems: | |
52 |
<dt |
|
55 | <dt>${dt}:</dt> | |
53 |
<dd |
|
56 | <dd title="${tt}">${dd}</dd> | |
54 | %endfor |
|
57 | %endfor | |
55 | </dl> |
|
58 | </dl> | |
56 | </div> |
|
59 | </div> | |
@@ -69,7 +72,7 b'' | |||||
69 | <tbody> |
|
72 | <tbody> | |
70 | %for key, value in c.py_modules: |
|
73 | %for key, value in c.py_modules: | |
71 | <tr> |
|
74 | <tr> | |
72 |
<td |
|
75 | <td>${key}</td> | |
73 | <td>${value}</td> |
|
76 | <td>${value}</td> | |
74 | </tr> |
|
77 | </tr> | |
75 | %endfor |
|
78 | %endfor |
@@ -1,3 +1,6 b'' | |||||
|
1 | ## -*- coding: utf-8 -*- | |||
|
2 | <%namespace name="base" file="/base/base.html"/> | |||
|
3 | ||||
1 | <div class="panel panel-default"> |
|
4 | <div class="panel panel-default"> | |
2 | <div class="panel-heading"> |
|
5 | <div class="panel-heading"> | |
3 | <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3> |
|
6 | <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3> | |
@@ -15,15 +18,25 b'' | |||||
15 | ${h.text('users_group_name',class_='medium')} |
|
18 | ${h.text('users_group_name',class_='medium')} | |
16 | </div> |
|
19 | </div> | |
17 | </div> |
|
20 | </div> | |
18 | <div class="field"> |
|
21 | ||
|
22 | <div class="field badged-field"> | |||
19 | <div class="label"> |
|
23 | <div class="label"> | |
20 | <label for="user">${_('Owner')}:</label> |
|
24 | <label for="user">${_('Owner')}:</label> | |
21 | </div> |
|
25 | </div> | |
22 | <div class="input"> |
|
26 | <div class="input"> | |
23 | ${h.text('user', class_="medium", autocomplete="off")} |
|
27 | <div class="badge-input-container"> | |
24 | <span class="help-block">${_('Change owner of this user group.')}</span> |
|
28 | <div class="user-badge"> | |
|
29 | ${base.gravatar_with_user(c.user_group.user.email, show_disabled=not c.user_group.user.active)} | |||
|
30 | </div> | |||
|
31 | <div class="badge-input-wrap"> | |||
|
32 | ${h.text('user', class_="medium", autocomplete="off")} | |||
|
33 | </div> | |||
|
34 | </div> | |||
|
35 | <form:error name="user"/> | |||
|
36 | <p class="help-block">${_('Change owner of this user group.')}</p> | |||
25 | </div> |
|
37 | </div> | |
26 |
|
|
38 | </div> | |
|
39 | ||||
27 | <div class="field"> |
|
40 | <div class="field"> | |
28 | <div class="label label-textarea"> |
|
41 | <div class="label label-textarea"> | |
29 | <label for="user_group_description">${_('Description')}:</label> |
|
42 | <label for="user_group_description">${_('Description')}:</label> |
@@ -128,7 +128,6 b'' | |||||
128 | </div> |
|
128 | </div> | |
129 | ${h.end_form()} |
|
129 | ${h.end_form()} | |
130 | </div> |
|
130 | </div> | |
131 | </%def> |
|
|||
132 | <script> |
|
131 | <script> | |
133 | $(document).ready(function(){ |
|
132 | $(document).ready(function(){ | |
134 | $('#username').focus(); |
|
133 | $('#username').focus(); | |
@@ -142,3 +141,4 b'' | |||||
142 | }) |
|
141 | }) | |
143 | }) |
|
142 | }) | |
144 | </script> |
|
143 | </script> | |
|
144 | </%def> |
@@ -134,10 +134,10 b'' | |||||
134 | </%def> |
|
134 | </%def> | |
135 |
|
135 | |||
136 |
|
136 | |||
137 | <%def name="gravatar_with_user(contact, size=16)"> |
|
137 | <%def name="gravatar_with_user(contact, size=16, show_disabled=False)"> | |
138 | <div class="rc-user tooltip" title="${contact}"> |
|
138 | <div class="rc-user tooltip" title="${contact}"> | |
139 | ${self.gravatar(h.email_or_none(contact), size)} |
|
139 | ${self.gravatar(h.email_or_none(contact), size)} | |
140 | <span class="user"> ${h.link_to_user(contact)}</span> |
|
140 | <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span> | |
141 | </div> |
|
141 | </div> | |
142 | </%def> |
|
142 | </%def> | |
143 |
|
143 | |||
@@ -195,7 +195,7 b'' | |||||
195 | %if repo_instance.clone_uri: |
|
195 | %if repo_instance.clone_uri: | |
196 | <p> |
|
196 | <p> | |
197 | <i class="icon-code-fork"></i> ${_('Clone from')} |
|
197 | <i class="icon-code-fork"></i> ${_('Clone from')} | |
198 | <a href="${h.url(str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a> |
|
198 | <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a> | |
199 | </p> |
|
199 | </p> | |
200 | %endif |
|
200 | %endif | |
201 |
|
201 |
@@ -13,9 +13,10 b' A new user `${user.username}` has regist' | |||||
13 | - Username: ${user.username} |
|
13 | - Username: ${user.username} | |
14 | - Full Name: ${user.firstname} ${user.lastname} |
|
14 | - Full Name: ${user.firstname} ${user.lastname} | |
15 | - Email: ${user.email} |
|
15 | - Email: ${user.email} | |
|
16 | - Profile link: ${h.url('user_profile', username=user.username, qualified=True)} | |||
16 | </%def> |
|
17 | </%def> | |
17 |
|
18 | |||
18 | ## BODY GOES BELOW |
|
19 | ## BODY GOES BELOW | |
19 | <div style="white-space: pre-wrap"> |
|
20 | <div style="white-space: pre-wrap"> | |
20 | ${body_plaintext()} |
|
21 | ${body_plaintext()} | |
21 | </div> No newline at end of file |
|
22 | </div> |
@@ -27,7 +27,7 b'' | |||||
27 | <div class="left-column"> |
|
27 | <div class="left-column"> | |
28 | <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/> |
|
28 | <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/> | |
29 | </div> |
|
29 | </div> | |
30 |
|
30 | <%block name="above_login_button" /> | ||
31 | <div id="login" class="right-column"> |
|
31 | <div id="login" class="right-column"> | |
32 | <%include file="/base/flash_msg.html"/> |
|
32 | <%include file="/base/flash_msg.html"/> | |
33 | <!-- login --> |
|
33 | <!-- login --> |
@@ -47,9 +47,9 b'' | |||||
47 | <ul class="nav nav-pills nav-stacked"> |
|
47 | <ul class="nav nav-pills nav-stacked"> | |
48 | <li class="${'active' if c.active=='open' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0)}">${_('Opened')}</a></li> |
|
48 | <li class="${'active' if c.active=='open' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0)}">${_('Opened')}</a></li> | |
49 | <li class="${'active' if c.active=='my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,my=1)}">${_('Opened by me')}</a></li> |
|
49 | <li class="${'active' if c.active=='my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,my=1)}">${_('Opened by me')}</a></li> | |
|
50 | <li class="${'active' if c.active=='awaiting' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_review=1)}">${_('Awaiting review')}</a></li> | |||
50 | <li class="${'active' if c.active=='awaiting_my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_my_review=1)}">${_('Awaiting my review')}</a></li> |
|
51 | <li class="${'active' if c.active=='awaiting_my' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_my_review=1)}">${_('Awaiting my review')}</a></li> | |
51 | <li class="${'active' if c.active=='closed' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,closed=1)}">${_('Closed')}</a></li> |
|
52 | <li class="${'active' if c.active=='closed' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,closed=1)}">${_('Closed')}</a></li> | |
52 | <li class="${'active' if c.active=='awaiting' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=0,awaiting_review=1)}">${_('Awaiting review')}</a></li> |
|
|||
53 | <li class="${'active' if c.active=='source' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=1)}">${_('From this repo')}</a></li> |
|
53 | <li class="${'active' if c.active=='source' else ''}"><a href="${h.url('pullrequest_show_all',repo_name=c.repo_name,source=1)}">${_('From this repo')}</a></li> | |
54 | </ul> |
|
54 | </ul> | |
55 | </div> |
|
55 | </div> |
@@ -27,7 +27,7 b'' | |||||
27 | <div class="left-column"> |
|
27 | <div class="left-column"> | |
28 | <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/> |
|
28 | <img class="sign-in-image" src="${h.url('/images/sign-in.png')}" alt="RhodeCode"/> | |
29 | </div> |
|
29 | </div> | |
30 |
|
30 | <%block name="above_register_button" /> | ||
31 | <div id="register" class="right-column"> |
|
31 | <div id="register" class="right-column"> | |
32 | <%include file="/base/flash_msg.html"/> |
|
32 | <%include file="/base/flash_msg.html"/> | |
33 | <!-- login --> |
|
33 | <!-- login --> |
@@ -85,9 +85,12 b' class TestMyAccountController(TestContro' | |||||
85 | response = self.app.get(url('my_account_pullrequests')) |
|
85 | response = self.app.get(url('my_account_pullrequests')) | |
86 | response.mustcontain('You currently have no open pull requests.') |
|
86 | response.mustcontain('You currently have no open pull requests.') | |
87 |
|
87 | |||
88 | pr = pr_util.create_pull_request() |
|
88 | pr = pr_util.create_pull_request(title='TestMyAccountPR') | |
89 | response = self.app.get(url('my_account_pullrequests')) |
|
89 | response = self.app.get(url('my_account_pullrequests')) | |
90 | response.mustcontain('Pull request #%d opened' % pr.pull_request_id) |
|
90 | response.mustcontain('There are currently no open pull requests ' | |
|
91 | 'requiring your participation') | |||
|
92 | ||||
|
93 | response.mustcontain('#%s: TestMyAccountPR' % pr.pull_request_id) | |||
91 |
|
94 | |||
92 | def test_my_account_my_emails(self): |
|
95 | def test_my_account_my_emails(self): | |
93 | self.log_user() |
|
96 | self.log_user() |
@@ -460,6 +460,10 b' class TestLabsSettings(object):' | |||||
460 |
|
460 | |||
461 | @pytest.mark.usefixtures('app') |
|
461 | @pytest.mark.usefixtures('app') | |
462 | class TestOpenSourceLicenses(object): |
|
462 | class TestOpenSourceLicenses(object): | |
|
463 | ||||
|
464 | def _get_url(self): | |||
|
465 | return ADMIN_PREFIX + '/settings/open_source' | |||
|
466 | ||||
463 | def test_records_are_displayed(self, autologin_user): |
|
467 | def test_records_are_displayed(self, autologin_user): | |
464 | sample_licenses = { |
|
468 | sample_licenses = { | |
465 | "python2.7-pytest-2.7.1": { |
|
469 | "python2.7-pytest-2.7.1": { | |
@@ -470,11 +474,10 b' class TestOpenSourceLicenses(object):' | |||||
470 | } |
|
474 | } | |
471 | } |
|
475 | } | |
472 | read_licenses_patch = mock.patch( |
|
476 | read_licenses_patch = mock.patch( | |
473 |
'rhodecode. |
|
477 | 'rhodecode.admin.views.read_opensource_licenses', | |
474 | return_value=sample_licenses) |
|
478 | return_value=sample_licenses) | |
475 | with read_licenses_patch: |
|
479 | with read_licenses_patch: | |
476 | response = self.app.get( |
|
480 | response = self.app.get(self._get_url(), status=200) | |
477 | url('admin_settings_open_source'), status=200) |
|
|||
478 |
|
481 | |||
479 | assert_response = AssertResponse(response) |
|
482 | assert_response = AssertResponse(response) | |
480 | assert_response.element_contains( |
|
483 | assert_response.element_contains( | |
@@ -485,14 +488,13 b' class TestOpenSourceLicenses(object):' | |||||
485 | assert_response.element_contains('.panel-body', license) |
|
488 | assert_response.element_contains('.panel-body', license) | |
486 |
|
489 | |||
487 | def test_records_can_be_read(self, autologin_user): |
|
490 | def test_records_can_be_read(self, autologin_user): | |
488 |
response = self.app.get(url( |
|
491 | response = self.app.get(self._get_url(), status=200) | |
489 | assert_response = AssertResponse(response) |
|
492 | assert_response = AssertResponse(response) | |
490 | assert_response.element_contains( |
|
493 | assert_response.element_contains( | |
491 | '.panel-heading', 'Licenses of Third Party Packages') |
|
494 | '.panel-heading', 'Licenses of Third Party Packages') | |
492 |
|
495 | |||
493 | def test_forbidden_when_normal_user(self, autologin_regular_user): |
|
496 | def test_forbidden_when_normal_user(self, autologin_regular_user): | |
494 | self.app.get( |
|
497 | self.app.get(self._get_url(), status=403) | |
495 | url('admin_settings_open_source'), status=403) |
|
|||
496 |
|
498 | |||
497 |
|
499 | |||
498 | @pytest.mark.usefixtures("app") |
|
500 | @pytest.mark.usefixtures("app") |
@@ -33,7 +33,7 b' class TestFeedController(TestController)' | |||||
33 | assert """<rss version="2.0">""" in response |
|
33 | assert """<rss version="2.0">""" in response | |
34 |
|
34 | |||
35 | def test_rss_with_auth_token(self, backend): |
|
35 | def test_rss_with_auth_token(self, backend): | |
36 | auth_token = User.get_first_admin().feed_token |
|
36 | auth_token = User.get_first_super_admin().feed_token | |
37 | assert auth_token != '' |
|
37 | assert auth_token != '' | |
38 | response = self.app.get(url(controller='feed', action='rss', |
|
38 | response = self.app.get(url(controller='feed', action='rss', | |
39 | repo_name=backend.repo_name, auth_token=auth_token)) |
|
39 | repo_name=backend.repo_name, auth_token=auth_token)) |
@@ -110,10 +110,12 b' class TestHomeController(TestController)' | |||||
110 | def test_index_show_version(self, autologin_user, name, state): |
|
110 | def test_index_show_version(self, autologin_user, name, state): | |
111 | version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__ |
|
111 | version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__ | |
112 |
|
112 | |||
113 |
s |
|
113 | sett = SettingsModel().create_or_update_setting( | |
114 | show.app_settings_value = state |
|
114 | 'show_version', state, 'bool') | |
115 |
Session().add(s |
|
115 | Session().add(sett) | |
116 | Session().commit() |
|
116 | Session().commit() | |
|
117 | SettingsModel().invalidate_settings_cache() | |||
|
118 | ||||
117 | response = self.app.get(url(controller='home', action='index')) |
|
119 | response = self.app.get(url(controller='home', action='index')) | |
118 | if state is True: |
|
120 | if state is True: | |
119 | response.mustcontain(version_string) |
|
121 | response.mustcontain(version_string) | |
@@ -133,6 +135,18 b' class TestUserAutocompleteData(TestContr' | |||||
133 | values = [suggestion['value'] for suggestion in result['suggestions']] |
|
135 | values = [suggestion['value'] for suggestion in result['suggestions']] | |
134 | assert user_name in values |
|
136 | assert user_name in values | |
135 |
|
137 | |||
|
138 | def test_returns_inactive_users_when_active_flag_sent(self, user_util): | |||
|
139 | self.log_user() | |||
|
140 | user = user_util.create_user(is_active=False) | |||
|
141 | user_name = user.username | |||
|
142 | response = self.app.get( | |||
|
143 | url(controller='home', action='user_autocomplete_data', | |||
|
144 | user_groups='true', active='0'), | |||
|
145 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) | |||
|
146 | result = json.loads(response.body) | |||
|
147 | values = [suggestion['value'] for suggestion in result['suggestions']] | |||
|
148 | assert user_name in values | |||
|
149 | ||||
136 | def test_returns_groups_when_user_groups_sent(self, user_util): |
|
150 | def test_returns_groups_when_user_groups_sent(self, user_util): | |
137 | self.log_user() |
|
151 | self.log_user() | |
138 | group = user_util.create_user_group(user_groups_active=True) |
|
152 | group = user_util.create_user_group(user_groups_active=True) | |
@@ -173,8 +187,10 b' class TestUserAutocompleteData(TestContr' | |||||
173 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) |
|
187 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) | |
174 |
|
188 | |||
175 | result = json.loads(response.body) |
|
189 | result = json.loads(response.body) | |
176 |
users_mock.assert_called_once_with( |
|
190 | users_mock.assert_called_once_with( | |
177 | groups_mock.assert_called_once_with(name_contains=query) |
|
191 | name_contains=query, only_active=True) | |
|
192 | groups_mock.assert_called_once_with( | |||
|
193 | name_contains=query, only_active=True) | |||
178 | assert len(result['suggestions']) == 20 |
|
194 | assert len(result['suggestions']) == 20 | |
179 |
|
195 | |||
180 |
|
196 |
@@ -448,7 +448,7 b' class TestLoginController:' | |||||
448 | assert [] == whitelist['api_access_controllers_whitelist'] |
|
448 | assert [] == whitelist['api_access_controllers_whitelist'] | |
449 | if test_name == 'proper_auth_token': |
|
449 | if test_name == 'proper_auth_token': | |
450 | # use builtin if api_key is None |
|
450 | # use builtin if api_key is None | |
451 | auth_token = User.get_first_admin().api_key |
|
451 | auth_token = User.get_first_super_admin().api_key | |
452 |
|
452 | |||
453 | with fixture.anon_access(False): |
|
453 | with fixture.anon_access(False): | |
454 | self.app.get(url(controller='changeset', |
|
454 | self.app.get(url(controller='changeset', | |
@@ -471,7 +471,7 b' class TestLoginController:' | |||||
471 | assert ['ChangesetController:changeset_raw'] == \ |
|
471 | assert ['ChangesetController:changeset_raw'] == \ | |
472 | whitelist['api_access_controllers_whitelist'] |
|
472 | whitelist['api_access_controllers_whitelist'] | |
473 | if test_name == 'proper_auth_token': |
|
473 | if test_name == 'proper_auth_token': | |
474 | auth_token = User.get_first_admin().api_key |
|
474 | auth_token = User.get_first_super_admin().api_key | |
475 |
|
475 | |||
476 | with fixture.anon_access(False): |
|
476 | with fixture.anon_access(False): | |
477 | self.app.get(url(controller='changeset', |
|
477 | self.app.get(url(controller='changeset', |
@@ -19,36 +19,35 b'' | |||||
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | import pytest |
|
21 | import pytest | |
22 | from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper |
|
22 | from pyramid.response import Response | |
|
23 | from pyramid.testing import DummyRequest | |||
|
24 | from rhodecode.lib.middleware.disable_vcs import ( | |||
|
25 | DisableVCSPagesWrapper, VCSServerUnavailable) | |||
23 |
|
26 | |||
24 |
|
27 | |||
25 |
@pytest.mark.parametrize('url, |
|
28 | @pytest.mark.parametrize('url, should_raise', [ | |
26 |
('/', |
|
29 | ('/', False), | |
27 |
('/_admin/settings', |
|
30 | ('/_admin/settings', False), | |
28 |
('/_admin/i_am_fine', |
|
31 | ('/_admin/i_am_fine', False), | |
29 |
('/_admin/settings/mappings', |
|
32 | ('/_admin/settings/mappings', True), | |
30 |
('/_admin/my_account/repos', |
|
33 | ('/_admin/my_account/repos', True), | |
31 |
('/_admin/create_repository', |
|
34 | ('/_admin/create_repository', True), | |
32 |
('/_admin/gists/1', |
|
35 | ('/_admin/gists/1', True), | |
33 |
('/_admin/notifications/1', |
|
36 | ('/_admin/notifications/1', True), | |
34 | ]) |
|
37 | ]) | |
35 |
def test_vcs_disabled(url, |
|
38 | def test_vcs_disabled(url, should_raise): | |
36 |
app = DisableVCSPagesWrapper( |
|
39 | wrapped_view = DisableVCSPagesWrapper(pyramid_view) | |
37 | assert expected_url == app(get_environ(url), None) |
|
40 | request = DummyRequest(path=url) | |
38 |
|
||||
39 |
|
41 | |||
40 | def get_environ(url): |
|
42 | if should_raise: | |
41 | """Construct a minimum WSGI environ based on the URL.""" |
|
43 | with pytest.raises(VCSServerUnavailable): | |
42 | environ = { |
|
44 | response = wrapped_view(None, request) | |
43 | 'PATH_INFO': url, |
|
45 | else: | |
44 | } |
|
46 | response = wrapped_view(None, request) | |
45 | return environ |
|
47 | assert response.status_int == 200 | |
46 |
|
||||
47 |
|
48 | |||
48 | class SimpleApp(object): |
|
49 | def pyramid_view(context, request): | |
49 | """ |
|
50 | """ | |
50 |
A mock |
|
51 | A mock pyramid view to be used in the wrapper | |
51 | from the middleware |
|
|||
52 | """ |
|
52 | """ | |
53 | def __call__(self, environ, start_response): |
|
53 | return Response('success') | |
54 | return environ['PATH_INFO'] |
|
@@ -20,7 +20,8 b'' | |||||
20 |
|
20 | |||
21 | import pytest |
|
21 | import pytest | |
22 |
|
22 | |||
23 |
from rhodecode.lib.encrypt import |
|
23 | from rhodecode.lib.encrypt import ( | |
|
24 | AESCipher, SignatureVerificationError, InvalidDecryptedValue) | |||
24 |
|
25 | |||
25 |
|
26 | |||
26 | class TestEncryptModule(object): |
|
27 | class TestEncryptModule(object): | |
@@ -38,3 +39,38 b' class TestEncryptModule(object):' | |||||
38 | def test_encryption(self, key, text): |
|
39 | def test_encryption(self, key, text): | |
39 | enc = AESCipher(key).encrypt(text) |
|
40 | enc = AESCipher(key).encrypt(text) | |
40 | assert AESCipher(key).decrypt(enc) == text |
|
41 | assert AESCipher(key).decrypt(enc) == text | |
|
42 | ||||
|
43 | def test_encryption_with_hmac(self): | |||
|
44 | key = 'secret' | |||
|
45 | text = 'ihatemysql' | |||
|
46 | enc = AESCipher(key, hmac=True).encrypt(text) | |||
|
47 | assert AESCipher(key, hmac=True).decrypt(enc) == text | |||
|
48 | ||||
|
49 | def test_encryption_with_hmac_with_bad_key(self): | |||
|
50 | key = 'secretstring' | |||
|
51 | text = 'ihatemysql' | |||
|
52 | enc = AESCipher(key, hmac=True).encrypt(text) | |||
|
53 | ||||
|
54 | with pytest.raises(SignatureVerificationError) as e: | |||
|
55 | assert AESCipher('differentsecret', hmac=True).decrypt(enc) == '' | |||
|
56 | ||||
|
57 | assert 'Encryption signature verification failed' in str(e) | |||
|
58 | ||||
|
59 | def test_encryption_with_hmac_with_bad_data(self): | |||
|
60 | key = 'secret' | |||
|
61 | text = 'ihatemysql' | |||
|
62 | enc = AESCipher(key, hmac=True).encrypt(text) | |||
|
63 | enc = 'xyz' + enc[3:] | |||
|
64 | with pytest.raises(SignatureVerificationError) as e: | |||
|
65 | assert AESCipher(key, hmac=True).decrypt(enc) == text | |||
|
66 | ||||
|
67 | assert 'Encryption signature verification failed' in str(e) | |||
|
68 | ||||
|
69 | def test_encryption_with_hmac_with_bad_key_not_strict(self): | |||
|
70 | key = 'secretstring' | |||
|
71 | text = 'ihatemysql' | |||
|
72 | enc = AESCipher(key, hmac=True).encrypt(text) | |||
|
73 | ||||
|
74 | assert isinstance(AESCipher( | |||
|
75 | 'differentsecret', hmac=True, strict_verification=False | |||
|
76 | ).decrypt(enc), InvalidDecryptedValue) |
@@ -84,8 +84,12 b' def test_process_patterns_repo(backend, ' | |||||
84 | 'pref': '#', |
|
84 | 'pref': '#', | |
85 | } |
|
85 | } | |
86 | } |
|
86 | } | |
|
87 | ||||
|
88 | def get_settings_mock(self, cache=True): | |||
|
89 | return config | |||
|
90 | ||||
87 | with mock.patch.object(IssueTrackerSettingsModel, |
|
91 | with mock.patch.object(IssueTrackerSettingsModel, | |
88 |
'get_settings', |
|
92 | 'get_settings', get_settings_mock): | |
89 | processed_text = helpers.process_patterns( |
|
93 | processed_text = helpers.process_patterns( | |
90 | text_string, repo.repo_name, config) |
|
94 | text_string, repo.repo_name, config) | |
91 |
|
95 | |||
@@ -106,8 +110,12 b' def test_process_patterns_no_repo(text_s' | |||||
106 | 'pref': '#', |
|
110 | 'pref': '#', | |
107 | } |
|
111 | } | |
108 | } |
|
112 | } | |
|
113 | ||||
|
114 | def get_settings_mock(self, cache=True): | |||
|
115 | return config | |||
|
116 | ||||
109 | with mock.patch.object(IssueTrackerSettingsModel, |
|
117 | with mock.patch.object(IssueTrackerSettingsModel, | |
110 |
'get_global_settings', |
|
118 | 'get_global_settings', get_settings_mock): | |
111 | processed_text = helpers.process_patterns( |
|
119 | processed_text = helpers.process_patterns( | |
112 | text_string, '', config) |
|
120 | text_string, '', config) | |
113 |
|
121 | |||
@@ -126,8 +134,12 b' def test_process_patterns_non_existent_r' | |||||
126 | 'pref': '#', |
|
134 | 'pref': '#', | |
127 | } |
|
135 | } | |
128 | } |
|
136 | } | |
|
137 | ||||
|
138 | def get_settings_mock(self, cache=True): | |||
|
139 | return config | |||
|
140 | ||||
129 | with mock.patch.object(IssueTrackerSettingsModel, |
|
141 | with mock.patch.object(IssueTrackerSettingsModel, | |
130 |
'get_global_settings', |
|
142 | 'get_global_settings', get_settings_mock): | |
131 | processed_text = helpers.process_patterns( |
|
143 | processed_text = helpers.process_patterns( | |
132 | text_string, 'do-not-exist', config) |
|
144 | text_string, 'do-not-exist', config) | |
133 |
|
145 | |||
@@ -182,10 +194,12 b' def test_get_matching_offsets(test_text,' | |||||
182 | assert helpers.get_matching_offsets( |
|
194 | assert helpers.get_matching_offsets( | |
183 | test_text, text_phrases) == expected_output |
|
195 | test_text, text_phrases) == expected_output | |
184 |
|
196 | |||
|
197 | ||||
185 | def test_normalize_text_for_matching(): |
|
198 | def test_normalize_text_for_matching(): | |
186 | assert helpers.normalize_text_for_matching( |
|
199 | assert helpers.normalize_text_for_matching( | |
187 | 'OJjfe)*#$*@)$JF*)3r2f80h') == 'ojjfe jf 3r2f80h' |
|
200 | 'OJjfe)*#$*@)$JF*)3r2f80h') == 'ojjfe jf 3r2f80h' | |
188 |
|
201 | |||
|
202 | ||||
189 | def test_get_matching_line_offsets(): |
|
203 | def test_get_matching_line_offsets(): | |
190 | assert helpers.get_matching_line_offsets([ |
|
204 | assert helpers.get_matching_line_offsets([ | |
191 | 'words words words', |
|
205 | 'words words words', | |
@@ -193,4 +207,4 b' def test_get_matching_line_offsets():' | |||||
193 | 'some text some', |
|
207 | 'some text some', | |
194 | 'words words words', |
|
208 | 'words words words', | |
195 | 'words words words', |
|
209 | 'words words words', | |
196 | 'text here what'], 'text') == {3: [(5, 9)], 6: [(0, 4)]} No newline at end of file |
|
210 | 'text here what'], 'text') == {3: [(5, 9)], 6: [(0, 4)]} |
@@ -29,6 +29,7 b' import pytest' | |||||
29 | from rhodecode.lib import caching_query |
|
29 | from rhodecode.lib import caching_query | |
30 | from rhodecode.lib import utils |
|
30 | from rhodecode.lib import utils | |
31 | from rhodecode.lib.utils2 import md5 |
|
31 | from rhodecode.lib.utils2 import md5 | |
|
32 | from rhodecode.model import settings | |||
32 | from rhodecode.model import db |
|
33 | from rhodecode.model import db | |
33 | from rhodecode.model import meta |
|
34 | from rhodecode.model import meta | |
34 | from rhodecode.model.repo import RepoModel |
|
35 | from rhodecode.model.repo import RepoModel | |
@@ -402,7 +403,7 b' class TestConfigDataFromDb(object):' | |||||
402 | ] |
|
403 | ] | |
403 | repo_name = 'test_repo' |
|
404 | repo_name = 'test_repo' | |
404 |
|
405 | |||
405 |
model_patch = mock.patch.object( |
|
406 | model_patch = mock.patch.object(settings, 'VcsSettingsModel') | |
406 | hooks_patch = mock.patch.object( |
|
407 | hooks_patch = mock.patch.object( | |
407 | utils, 'get_enabled_hook_classes', |
|
408 | utils, 'get_enabled_hook_classes', | |
408 | return_value=['pull', 'push', 'repo_size']) |
|
409 | return_value=['pull', 'push', 'repo_size']) |
@@ -432,7 +432,13 b' def test_get_repo_by_id(test, expected):' | |||||
432 | assert _test == expected |
|
432 | assert _test == expected | |
433 |
|
433 | |||
434 |
|
434 | |||
435 | def test_invalidation_context(pylonsapp): |
|
435 | @pytest.mark.parametrize("test_repo_name, repo_type", [ | |
|
436 | ("test_repo_1", None), | |||
|
437 | ("repo_group/foobar", None), | |||
|
438 | ("test_non_asci_ąćę", None), | |||
|
439 | (u"test_non_asci_unicode_ąćę", None), | |||
|
440 | ]) | |||
|
441 | def test_invalidation_context(pylonsapp, test_repo_name, repo_type): | |||
436 | from beaker.cache import cache_region |
|
442 | from beaker.cache import cache_region | |
437 | from rhodecode.lib import caches |
|
443 | from rhodecode.lib import caches | |
438 | from rhodecode.model.db import CacheKey |
|
444 | from rhodecode.model.db import CacheKey | |
@@ -442,7 +448,7 b' def test_invalidation_context(pylonsapp)' | |||||
442 | return 'result' |
|
448 | return 'result' | |
443 |
|
449 | |||
444 | invalidator_context = CacheKey.repo_context_cache( |
|
450 | invalidator_context = CacheKey.repo_context_cache( | |
445 |
_dummy_func, |
|
451 | _dummy_func, test_repo_name, 'repo') | |
446 |
|
452 | |||
447 | with invalidator_context as context: |
|
453 | with invalidator_context as context: | |
448 | invalidated = context.invalidate() |
|
454 | invalidated = context.invalidate() | |
@@ -452,6 +458,8 b' def test_invalidation_context(pylonsapp)' | |||||
452 | assert 'result' == result |
|
458 | assert 'result' == result | |
453 | assert isinstance(context, caches.FreshRegionCache) |
|
459 | assert isinstance(context, caches.FreshRegionCache) | |
454 |
|
460 | |||
|
461 | assert 'InvalidationContext' in repr(invalidator_context) | |||
|
462 | ||||
455 | with invalidator_context as context: |
|
463 | with invalidator_context as context: | |
456 | context.invalidate() |
|
464 | context.invalidate() | |
457 | result = context.compute() |
|
465 | result = context.compute() |
@@ -58,30 +58,43 b' def stub_session():' | |||||
58 | return session |
|
58 | return session | |
59 |
|
59 | |||
60 |
|
60 | |||
61 | def test_repo_maker_uses_session_for_classmethods(stub_session): |
|
61 | @pytest.fixture | |
|
62 | def stub_session_factory(stub_session): | |||
|
63 | """ | |||
|
64 | Stub of `rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory`. | |||
|
65 | """ | |||
|
66 | session_factory = mock.Mock() | |||
|
67 | session_factory.return_value = stub_session | |||
|
68 | return session_factory | |||
|
69 | ||||
|
70 | ||||
|
71 | def test_repo_maker_uses_session_for_classmethods(stub_session_factory): | |||
62 | repo_maker = client_http.RepoMaker( |
|
72 | repo_maker = client_http.RepoMaker( | |
63 | 'server_and_port', 'endpoint', stub_session) |
|
73 | 'server_and_port', 'endpoint', stub_session_factory) | |
64 | repo_maker.example_call() |
|
74 | repo_maker.example_call() | |
65 | stub_session.post.assert_called_with( |
|
75 | stub_session_factory().post.assert_called_with( | |
66 | 'http://server_and_port/endpoint', data=mock.ANY) |
|
76 | 'http://server_and_port/endpoint', data=mock.ANY) | |
67 |
|
77 | |||
68 |
|
78 | |||
69 | def test_repo_maker_uses_session_for_instance_methods( |
|
79 | def test_repo_maker_uses_session_for_instance_methods( | |
70 | stub_session, config): |
|
80 | stub_session_factory, config): | |
71 | repo_maker = client_http.RepoMaker( |
|
81 | repo_maker = client_http.RepoMaker( | |
72 | 'server_and_port', 'endpoint', stub_session) |
|
82 | 'server_and_port', 'endpoint', stub_session_factory) | |
73 | repo = repo_maker('stub_path', config) |
|
83 | repo = repo_maker('stub_path', config) | |
74 | repo.example_call() |
|
84 | repo.example_call() | |
75 | stub_session.post.assert_called_with( |
|
85 | stub_session_factory().post.assert_called_with( | |
76 | 'http://server_and_port/endpoint', data=mock.ANY) |
|
86 | 'http://server_and_port/endpoint', data=mock.ANY) | |
77 |
|
87 | |||
78 |
|
88 | |||
|
89 | @mock.patch('rhodecode.lib.vcs.client_http.ThreadlocalSessionFactory') | |||
79 | @mock.patch('rhodecode.lib.vcs.connection') |
|
90 | @mock.patch('rhodecode.lib.vcs.connection') | |
80 |
def test_connect_passes_in_the_same_session( |
|
91 | def test_connect_passes_in_the_same_session( | |
81 | session_factory_patcher = mock.patch.object( |
|
92 | connection, session_factory_class, stub_session): | |
82 | vcs, '_create_http_rpc_session', return_value=stub_session) |
|
93 | session_factory = session_factory_class.return_value | |
83 | with session_factory_patcher: |
|
94 | session_factory.return_value = stub_session | |
84 | vcs.connect_http('server_and_port') |
|
95 | ||
85 | assert connection.Hg._session == stub_session |
|
96 | vcs.connect_http('server_and_port') | |
86 | assert connection.Svn._session == stub_session |
|
97 | ||
87 |
assert connection. |
|
98 | assert connection.Hg._session_factory() == stub_session | |
|
99 | assert connection.Svn._session_factory() == stub_session | |||
|
100 | assert connection.Git._session_factory() == stub_session |
@@ -69,7 +69,6 b' def pylons_compatibility_tween_factory(h' | |||||
69 | context.rhodecode_user = auth_user |
|
69 | context.rhodecode_user = auth_user | |
70 | attach_context_attributes(context) |
|
70 | attach_context_attributes(context) | |
71 | pylons.tmpl_context._push_object(context) |
|
71 | pylons.tmpl_context._push_object(context) | |
72 |
|
||||
73 | return handler(request) |
|
72 | return handler(request) | |
74 | finally: |
|
73 | finally: | |
75 | # Dispose current database session and rollback uncommitted |
|
74 | # Dispose current database session and rollback uncommitted |
@@ -518,7 +518,7 b' vcs.connection_timeout = 3600' | |||||
518 | ### LOGGING CONFIGURATION #### |
|
518 | ### LOGGING CONFIGURATION #### | |
519 | ################################ |
|
519 | ################################ | |
520 | [loggers] |
|
520 | [loggers] | |
521 |
keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates |
|
521 | keys = root, routes, rhodecode, sqlalchemy, beaker, pyro4, templates | |
522 |
|
522 | |||
523 | [handlers] |
|
523 | [handlers] | |
524 | keys = console, console_sql |
|
524 | keys = console, console_sql | |
@@ -570,12 +570,6 b' handlers = console_sql' | |||||
570 | qualname = sqlalchemy.engine |
|
570 | qualname = sqlalchemy.engine | |
571 | propagate = 0 |
|
571 | propagate = 0 | |
572 |
|
572 | |||
573 | [logger_whoosh_indexer] |
|
|||
574 | level = DEBUG |
|
|||
575 | handlers = |
|
|||
576 | qualname = whoosh_indexer |
|
|||
577 | propagate = 1 |
|
|||
578 |
|
||||
579 | ############## |
|
573 | ############## | |
580 | ## HANDLERS ## |
|
574 | ## HANDLERS ## | |
581 | ############## |
|
575 | ############## |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
1 | NO CONTENT: file was removed, binary diff hidden |
|
NO CONTENT: file was removed, binary diff hidden |
General Comments 0
You need to be logged in to leave comments.
Login now