##// END OF EJS Templates
release: Merge default into stable for release preparation
marcink -
r3002:f5da0c46 merge stable
parent child Browse files
Show More
@@ -0,0 +1,3 b''
1 [pip2nix]
2 requirements = -r ./requirements_docs.txt
3 output = ./python-packages-generated.nix
@@ -0,0 +1,221 b''
1 # Generated by pip2nix 0.8.0.dev1
2 # See https://github.com/johbo/pip2nix
3
4 { pkgs, fetchurl, fetchgit, fetchhg }:
5
6 self: super: {
7 "alabaster" = super.buildPythonPackage {
8 name = "alabaster-0.7.11";
9 doCheck = false;
10 src = fetchurl {
11 url = "https://files.pythonhosted.org/packages/3f/46/9346ea429931d80244ab7f11c4fce83671df0b7ae5a60247a2b588592c46/alabaster-0.7.11.tar.gz";
12 sha256 = "1mvm69xsn5xf1jc45kdq1mn0yq0pfn54mv2jcww4s1vwqx6iyfxn";
13 };
14 };
15 "babel" = super.buildPythonPackage {
16 name = "babel-2.6.0";
17 doCheck = false;
18 propagatedBuildInputs = [
19 self."pytz"
20 ];
21 src = fetchurl {
22 url = "https://files.pythonhosted.org/packages/be/cc/9c981b249a455fa0c76338966325fc70b7265521bad641bf2932f77712f4/Babel-2.6.0.tar.gz";
23 sha256 = "08rxmbx2s4irp0w0gmn498vns5xy0fagm0fg33xa772jiks51flc";
24 };
25 };
26 "certifi" = super.buildPythonPackage {
27 name = "certifi-2018.8.24";
28 doCheck = false;
29 src = fetchurl {
30 url = "https://files.pythonhosted.org/packages/e1/0f/f8d5e939184547b3bdc6128551b831a62832713aa98c2ccdf8c47ecc7f17/certifi-2018.8.24.tar.gz";
31 sha256 = "0f0nhrj9mlrf79iway4578wrsgmjh0fmacl9zv8zjckdy7b90rip";
32 };
33 };
34 "chardet" = super.buildPythonPackage {
35 name = "chardet-3.0.4";
36 doCheck = false;
37 src = fetchurl {
38 url = "https://files.pythonhosted.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz";
39 sha256 = "1bpalpia6r5x1kknbk11p1fzph56fmmnp405ds8icksd3knr5aw4";
40 };
41 };
42 "docutils" = super.buildPythonPackage {
43 name = "docutils-0.14";
44 doCheck = false;
45 src = fetchurl {
46 url = "https://files.pythonhosted.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
47 sha256 = "0x22fs3pdmr42kvz6c654756wja305qv6cx1zbhwlagvxgr4xrji";
48 };
49 };
50 "idna" = super.buildPythonPackage {
51 name = "idna-2.7";
52 doCheck = false;
53 src = fetchurl {
54 url = "https://files.pythonhosted.org/packages/65/c4/80f97e9c9628f3cac9b98bfca0402ede54e0563b56482e3e6e45c43c4935/idna-2.7.tar.gz";
55 sha256 = "05jam7d31767dr12x0rbvvs8lxnpb1mhdb2zdlfxgh83z6k3hjk8";
56 };
57 };
58 "imagesize" = super.buildPythonPackage {
59 name = "imagesize-1.1.0";
60 doCheck = false;
61 src = fetchurl {
62 url = "https://files.pythonhosted.org/packages/41/f5/3cf63735d54aa9974e544aa25858d8f9670ac5b4da51020bbfc6aaade741/imagesize-1.1.0.tar.gz";
63 sha256 = "1dg3wn7qpwmhgqc0r9na2ding1wif9q5spz3j9zn2riwphc2k0zk";
64 };
65 };
66 "jinja2" = super.buildPythonPackage {
67 name = "jinja2-2.9.6";
68 doCheck = false;
69 propagatedBuildInputs = [
70 self."markupsafe"
71 ];
72 src = fetchurl {
73 url = "https://files.pythonhosted.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
74 sha256 = "1zzrkywhziqffrzks14kzixz7nd4yh2vc0fb04a68vfd2ai03anx";
75 };
76 };
77 "markupsafe" = super.buildPythonPackage {
78 name = "markupsafe-1.0";
79 doCheck = false;
80 src = fetchurl {
81 url = "https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
82 sha256 = "0rdn1s8x9ni7ss8rfiacj7x1085lx8mh2zdwqslnw8xc3l4nkgm6";
83 };
84 };
85 "packaging" = super.buildPythonPackage {
86 name = "packaging-17.1";
87 doCheck = false;
88 propagatedBuildInputs = [
89 self."pyparsing"
90 self."six"
91 ];
92 src = fetchurl {
93 url = "https://files.pythonhosted.org/packages/77/32/439f47be99809c12ef2da8b60a2c47987786d2c6c9205549dd6ef95df8bd/packaging-17.1.tar.gz";
94 sha256 = "0nrpayk8kij1zm9sjnk38ldz3a6705ggvw8ljylqbrb4vmqbf6gh";
95 };
96 };
97 "pygments" = super.buildPythonPackage {
98 name = "pygments-2.2.0";
99 doCheck = false;
100 src = fetchurl {
101 url = "https://files.pythonhosted.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
102 sha256 = "1k78qdvir1yb1c634nkv6rbga8wv4289xarghmsbbvzhvr311bnv";
103 };
104 };
105 "pyparsing" = super.buildPythonPackage {
106 name = "pyparsing-2.2.0";
107 doCheck = false;
108 src = fetchurl {
109 url = "https://files.pythonhosted.org/packages/3c/ec/a94f8cf7274ea60b5413df054f82a8980523efd712ec55a59e7c3357cf7c/pyparsing-2.2.0.tar.gz";
110 sha256 = "016b9gh606aa44sq92jslm89bg874ia0yyiyb643fa6dgbsbqch8";
111 };
112 };
113 "pytz" = super.buildPythonPackage {
114 name = "pytz-2018.4";
115 doCheck = false;
116 src = fetchurl {
117 url = "https://files.pythonhosted.org/packages/10/76/52efda4ef98e7544321fd8d5d512e11739c1df18b0649551aeccfb1c8376/pytz-2018.4.tar.gz";
118 sha256 = "0jgpqx3kk2rhv81j1izjxvmx8d0x7hzs1857pgqnixic5wq2ar60";
119 };
120 };
121 "requests" = super.buildPythonPackage {
122 name = "requests-2.19.1";
123 doCheck = false;
124 propagatedBuildInputs = [
125 self."chardet"
126 self."idna"
127 self."urllib3"
128 self."certifi"
129 ];
130 src = fetchurl {
131 url = "https://files.pythonhosted.org/packages/54/1f/782a5734931ddf2e1494e4cd615a51ff98e1879cbe9eecbdfeaf09aa75e9/requests-2.19.1.tar.gz";
132 sha256 = "0snf8xxdzsgh1x2zv3vilvbrv9jbpmnfagzzb1rjmmvflckdh8pc";
133 };
134 };
135 "setuptools" = super.buildPythonPackage {
136 name = "setuptools-40.2.0";
137 doCheck = false;
138 src = fetchurl {
139 url = "https://files.pythonhosted.org/packages/ef/1d/201c13e353956a1c840f5d0fbf0461bd45bbd678ea4843ebf25924e8984c/setuptools-40.2.0.zip";
140 sha256 = "19ng5m7kigllg3x96c91y3a2k28g6kwnbb1v4warrnp4xma1v227";
141 };
142 };
143 "six" = super.buildPythonPackage {
144 name = "six-1.11.0";
145 doCheck = false;
146 src = fetchurl {
147 url = "https://files.pythonhosted.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
148 sha256 = "1scqzwc51c875z23phj48gircqjgnn3af8zy2izjwmnlxrxsgs3h";
149 };
150 };
151 "snowballstemmer" = super.buildPythonPackage {
152 name = "snowballstemmer-1.2.1";
153 doCheck = false;
154 src = fetchurl {
155 url = "https://files.pythonhosted.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz";
156 sha256 = "0a0idq4y5frv7qsg2x62jd7rd272749xk4x99misf5rcifk2d7wi";
157 };
158 };
159 "sphinx" = super.buildPythonPackage {
160 name = "sphinx-1.7.8";
161 doCheck = false;
162 propagatedBuildInputs = [
163 self."six"
164 self."jinja2"
165 self."pygments"
166 self."docutils"
167 self."snowballstemmer"
168 self."babel"
169 self."alabaster"
170 self."imagesize"
171 self."requests"
172 self."setuptools"
173 self."packaging"
174 self."sphinxcontrib-websupport"
175 self."typing"
176 ];
177 src = fetchurl {
178 url = "https://files.pythonhosted.org/packages/ac/54/4ef326d0c654da1ed91341a7a1f43efc18a8c770ddd2b8e45df97cb79d82/Sphinx-1.7.8.tar.gz";
179 sha256 = "1ryz0w4c31930f1br2sjwrxwx9cmsy7cqdb0d81g98n9bj250w50";
180 };
181 };
182 "sphinx-rtd-theme" = super.buildPythonPackage {
183 name = "sphinx-rtd-theme-0.4.1";
184 doCheck = false;
185 propagatedBuildInputs = [
186 self."sphinx"
187 ];
188 src = fetchurl {
189 url = "https://files.pythonhosted.org/packages/f2/b0/a1933d792b806118ddbca6699f2e2c844d9b1b16e84a89d7effd5cd2a800/sphinx_rtd_theme-0.4.1.tar.gz";
190 sha256 = "1xkyqam8dzbjaymdyvkiif85m4y3jf8crdiwlgcfp8gqcj57aj9v";
191 };
192 };
193 "sphinxcontrib-websupport" = super.buildPythonPackage {
194 name = "sphinxcontrib-websupport-1.1.0";
195 doCheck = false;
196 src = fetchurl {
197 url = "https://files.pythonhosted.org/packages/07/7a/e74b06dce85555ffee33e1d6b7381314169ebf7e31b62c18fcb2815626b7/sphinxcontrib-websupport-1.1.0.tar.gz";
198 sha256 = "1ff3ix76xi1y6m99qxhaq5161ix9swwzydilvdya07mgbcvpzr4x";
199 };
200 };
201 "typing" = super.buildPythonPackage {
202 name = "typing-3.6.6";
203 doCheck = false;
204 src = fetchurl {
205 url = "https://files.pythonhosted.org/packages/bf/9b/2bf84e841575b633d8d91ad923e198a415e3901f228715524689495b4317/typing-3.6.6.tar.gz";
206 sha256 = "0ba9acs4awx15bf9v3nrs781msbd2nx826906nj6fqks2bvca9s0";
207 };
208 };
209 "urllib3" = super.buildPythonPackage {
210 name = "urllib3-1.23";
211 doCheck = false;
212 src = fetchurl {
213 url = "https://files.pythonhosted.org/packages/3c/d2/dc5471622bd200db1cd9319e02e71bc655e9ea27b8e0ce65fc69de0dac15/urllib3-1.23.tar.gz";
214 sha256 = "1bvbd35q3zdcd7gsv38fwpizy7p06dr0154g5gfybrvnbvhwb2m6";
215 };
216 };
217
218 ### Test requirements
219
220
221 }
@@ -0,0 +1,133 b''
1 |RCE| 4.13.0 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2018-09-05
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13 - Branch permissions: new set of permissions were added to control branch modification.
14 There are 4 basic permissions that can be set for branch names/branch patterns:
15 * no-access (any modification for given branch is forbidden)
16 * web-merge (modify branch by web based PR merge)
17 * push (only non-forced modification on branch are allowed)
18 * forced push (all modification to branch are allowed)
19 Available in EE edition only.
20 - Unified search and repo-switcher: a new persistent search box is now present allowing
21 to search for repositories, repository groups, commits (using full text search),
22 users, user-groups. Replaces redundant quick-filters/repo switcher.
23 - Default Reviewers: added possibility to match against regex based pattern as
24 alternative syntax to glob which didn't handle all the cases.
25 - Built-in Error tracker: added new exception tracking capability. All errors are now
26 tracked and stored. This allows instance admins to see potential problems without
27 access to the machine and logs.
28 - User Groups: each user group which users have access to expose public profile link.
29 It's possible to view the members of a group before attaching it to any resource.
30 - New caching framework: existing Beaker cache was completely replaced by dogpile.cache
31 library. This new cache framework in addition to solving multiple
32 performance/reliability problems of Beaker is used to cache permissions tree.
33 This gives huge performance boosts for very large and complex permission trees.
34 - Pull Requests: description field is now allowed to use a RST/Markdown syntax.
35 - SVN: added support for SVN 1.10 release line.
36
37
38 General
39 ^^^^^^^
40
41 - Google: updated google auth plugin with latest API changes.
42 - Frontend: Switched to Polymer 2.0.
43 - Events: added a default timeout for operation calling the endpoint url, so
44 they won't block forever.
45 - SQLAlchemy: allow DB connection ping/refresh using dedicated flag from .ini file.
46 `sqlalchemy.db1.ping_connection = true`
47 - Pull Requests: added option to force-refresh merge workspace in case of problems.
48 Adding GET param `?force_refresh=1` into PR page triggers the refresh.
49 - Pull Requests: show more info about version of comment vs latest version.
50 - Diffs: skip line numbers during copy from a diff view.
51 - License: use simple cache to read license info.
52 Due to the complex and expensive encryption, this reduces requests time by ~10ms.
53 - Debug: add new custom logging to track unique requests across systems.
54 Allows tracking single requests in very busy system by unique ID added into logging system.
55 - Configuration: .ini files now can replace a special placeholders e.g "{ENV_NAME}"
56 into a value from the ENVIRONMENT. Allows easier setup in Docker and similar.
57 - Backend: don't support vcsserver.scm_app anymore, now it uses http even if scm_app
58 is specified.
59 - Repositories: re-order creation/fork forms for better UX and consistency.
60 - UI: Add the number of inactive users in _admin/users and _admin/user_groups
61 - UX: updated registration form to better indicate what is the process of binding a
62 RhodeCode account with external one like Google.
63 - API: pull-requests allow automatic title generation via API
64 - VCSServer: errors: use a better interface to track exceptions and tracebacks.
65 - VCSServer: caches: replaced beaker with dogpile cache.
66 - GIT: use GIT_DISCOVERY_ACROSS_FILESYSTEM for better compatibility on NFS servers.
67 - Dependencies: bumped mercurial to 4.6.2
68 - Dependencies: bumped evolve to 8.0.1
69 - Dependencies: bumped hgsubversion to 1.9.2
70 - Dependencies: bumped git version to 2.16.4
71 - Dependencies: bumped SVN to 1.10.2
72 - Dependencies: added alternative pymysql drivers for mysql
73 - NIX: updated to 18.03 nix packages, now shipped with python 2.7.15
74 release and multiple other new libraries.
75
76
77 Security
78 ^^^^^^^^
79
80 - Mercurial: general protocol security updates.
81 * Fixes Mercurial's CVE for lack of permissions checking on mercurial batch commands.
82 * Introduced more strict checks for permissions, now they default to push instead of pull.
83 * Decypher batch commands and pick top-most permission to be required.
84 * This follows changes in Mercurial CORE after 4.6.1 release.
85 - Fixed bug in bleach sanitizer allowing certain custom payload to bypass it. Now
86 we always fails if sanitizing fails. This could lead to stored XSS
87 - Fixed stored XSS in binary file rendering.
88 - Fixed stored XSS in repo forks datagrid.
89
90
91 Performance
92 ^^^^^^^^^^^
93
94 - Permissions: Permission trees for users and now cached, after calculation.
95 This reduces response time for some pages dramatically.
96 In case of any permission changes caches are invalidated.
97 - Core: new dogpile.cache based cache framework was introduced, which is faster than
98 previously used Beaker.
99
100
101 Fixes
102 ^^^^^
103
104 - Audit Logs: store properly IP for certain events.
105 - External Auth: pass along came_from into the url so we get properly
106 redirected back after logging using external auth provider.
107 - Pull Requests: lock submit on pull request to prevent double submission on a fast click.
108 - Pull Requests: fixed a case of unresolved comments attached to removed file in pull request.
109 That prevented from closing it.
110 - Pull Requests: use numeric repo id for creation of shadow repos. Fixes a problem
111 when repository is renamed during PR lifetime.
112 - API: fixed creation of a pull request with default reviewer rules.
113 - Default Reviewers: fixed voting rule calculation on user group.
114 - Pull Requests: in GIT use force fetch and update for target ref.
115 This solves a case when in PR a target repository is force updated (by push force)
116 and is out of sync.
117 - VCSServer: detect early potential locale problem, and fallback to LC_ALL=C,
118 instead of crashing vcsserver.
119 - Pull Requests: use a safer way of destroying shadow repositories.
120 Fixes some problems in NFS storage and big repositories
121
122
123 Upgrade notes
124 ^^^^^^^^^^^^^
125
126 - The direct backend `vcsserver.scm_app` is not supported anymore. This backed was
127 already deprecated some time ago. Now it will use `http` mode even if scm_app is
128 specified. Please contact us in case you still use it, and not sure how to upgrade.
129 - New dogpile cache settings are not ported to converted .ini. If users want to do
130 adjustments please copy the settings over dogpile cache section from a newly
131 generated rhodecode.template.ini file. This file is stored next to rhodecode.ini
132 - SVN 1.10.2 was introduced in this release. Please make sure to update your
133 mod_dav to the same version for best compatibility.
@@ -0,0 +1,52 b''
1
2 ==============================
3 Generate the Nix expressions
4 ==============================
5
6 Details can be found in the repository of `RhodeCode Enterprise CE`_ inside of
7 the file `docs/contributing/dependencies.rst`.
8
9 Start the environment as follows:
10
11 .. code:: shell
12
13 nix-shell pkgs/shell-generate.nix
14
15
16
17 Python dependencies
18 ===================
19
20 .. code:: shell
21
22 pip2nix generate --licenses
23 # or
24 nix-shell pkgs/shell-generate.nix --command "pip2nix generate --licenses"
25
26
27 NodeJS dependencies
28 ===================
29
30 .. code:: shell
31
32 rm -rf node_modules
33 nix-shell pkgs/shell-generate.nix --command "
34 node2nix --input package.json \
35 -o pkgs/node-packages.nix \
36 -e pkgs/node-env.nix \
37 -c pkgs/node-default.nix \
38 -d --flatten --nodejs-6 "
39
40
41
42 Bower dependencies
43 ==================
44
45 .. code:: shell
46
47 nix-shell pkgs/shell-generate.nix --command "bower2nix bower.json pkgs/bower-packages.nix"
48
49
50 .. Links
51
52 .. _RhodeCode Enterprise CE: https://code.rhodecode.com/rhodecode-enterprise-ce
@@ -0,0 +1,17 b''
1 { pkgs
2 , pythonPackages
3 }:
4
5 rec {
6 pip2nix-src = pkgs.fetchzip {
7 url = https://github.com/johbo/pip2nix/archive/51e6fdae34d0e8ded9efeef7a8601730249687a6.tar.gz;
8 sha256 = "02a4jjgi7lsvf8mhrxsd56s9a3yg20081rl9bgc2m84w60v2gbz2";
9 };
10
11 pip2nix = import pip2nix-src {
12 inherit
13 pkgs
14 pythonPackages;
15 };
16
17 }
@@ -0,0 +1,13 b''
1 diff -rup Beaker-1.9.1-orig/beaker/ext/database.py Beaker-1.9.1/beaker/ext/database.py
2 --- Beaker-1.9.1-orig/beaker/ext/database.py 2018-05-22 18:22:34.802619619 +0200
3 +++ Beaker-1.9.1/beaker/ext/database.py 2018-05-22 17:07:14.048335196 +0200
4 @@ -91,7 +91,8 @@ class DatabaseNamespaceManager(OpenResou
5 sa.Column('created', types.DateTime, nullable=False),
6 sa.Column('data', types.PickleType, nullable=False),
7 sa.UniqueConstraint('namespace'),
8 - schema=schema_name if schema_name else meta.schema
9 + schema=schema_name if schema_name else meta.schema,
10 + extend_existing=True
11 )
12 cache.create(checkfirst=True)
13 return cache
@@ -0,0 +1,53 b''
1 { pkgs ? (import <nixpkgs> {})
2 , pythonPackages ? "python27Packages"
3 }:
4
5 with pkgs.lib;
6
7 let _pythonPackages = pythonPackages; in
8 let
9 pythonPackages = getAttr _pythonPackages pkgs;
10
11 pip2nix = import ./nix-common/pip2nix.nix {
12 inherit
13 pkgs
14 pythonPackages;
15 };
16
17 in
18
19 pkgs.stdenv.mkDerivation {
20 name = "pip2nix-generated";
21 buildInputs = [
22 # Allows to generate python packages
23 pip2nix.pip2nix
24 pythonPackages.pip-tools
25
26 # Allows to generate bower dependencies
27 pkgs.nodePackages.bower2nix
28
29 # Allows to generate node dependencies
30 pkgs.nodePackages.node2nix
31
32 # We need mysql_config to be around
33 pkgs.mysql
34
35 # We need postgresql to be around
36 pkgs.postgresql
37
38 # Curl is needed for pycurl
39 pkgs.curl
40 ];
41
42 shellHook = ''
43 runHook preShellHook
44 runHook postShellHook
45 '';
46
47 preShellHook = ''
48 echo "Starting Generate Shell"
49 # Custom prompt to distinguish from other dev envs.
50 export PS1="\n\[\033[1;32m\][Generate-shell:\w]$\[\033[0m\] "
51 export PYCURL_SSL_LIBRARY=openssl
52 '';
53 }
@@ -0,0 +1,44 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2018 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 logging
22
23 from rhodecode import events
24 from rhodecode.lib import rc_cache
25
26 log = logging.getLogger(__name__)
27
28
29 def trigger_user_permission_flush(event):
30 """
31 Subscriber to the `UserPermissionsChange`. This triggers the
32 automatic flush of permission caches, so the users affected receive new permissions
33 Right Away
34 """
35
36 affected_user_ids = set(event.user_ids)
37 for user_id in affected_user_ids:
38 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
39 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
40 log.debug('Deleted %s cache keys for user_id: %s', del_keys, user_id)
41
42
43 def includeme(config):
44 config.add_subscriber(trigger_user_permission_flush, events.UserPermissionsChange)
@@ -0,0 +1,154 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2018-2018 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 import os
21 import logging
22
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
25
26 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps.admin.navigation import navigation_list
28 from rhodecode.lib import helpers as h
29 from rhodecode.lib.auth import (
30 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
31 from rhodecode.lib.utils2 import time_to_utcdatetime, safe_int
32 from rhodecode.lib import exc_tracking
33
34 log = logging.getLogger(__name__)
35
36
37 class ExceptionsTrackerView(BaseAppView):
38 def load_default_context(self):
39 c = self._get_local_tmpl_context()
40 c.navlist = navigation_list(self.request)
41 return c
42
43 def count_all_exceptions(self):
44 exc_store_path = exc_tracking.get_exc_store()
45 count = 0
46 for fname in os.listdir(exc_store_path):
47 parts = fname.split('_', 2)
48 if not len(parts) == 3:
49 continue
50 count +=1
51 return count
52
53 def get_all_exceptions(self, read_metadata=False, limit=None):
54 exc_store_path = exc_tracking.get_exc_store()
55 exception_list = []
56
57 def key_sorter(val):
58 try:
59 return val.split('_')[-1]
60 except Exception:
61 return 0
62 count = 0
63 for fname in reversed(sorted(os.listdir(exc_store_path), key=key_sorter)):
64
65 parts = fname.split('_', 2)
66 if not len(parts) == 3:
67 continue
68
69 exc_id, app_type, exc_timestamp = parts
70
71 exc = {'exc_id': exc_id, 'app_type': app_type, 'exc_type': 'unknown',
72 'exc_utc_date': '', 'exc_timestamp': exc_timestamp}
73
74 if read_metadata:
75 full_path = os.path.join(exc_store_path, fname)
76 # we can read our metadata
77 with open(full_path, 'rb') as f:
78 exc_metadata = exc_tracking.exc_unserialize(f.read())
79 exc.update(exc_metadata)
80
81 # convert our timestamp to a date obj, for nicer representation
82 exc['exc_utc_date'] = time_to_utcdatetime(exc['exc_timestamp'])
83 exception_list.append(exc)
84
85 count += 1
86 if limit and count >= limit:
87 break
88 return exception_list
89
90 @LoginRequired()
91 @HasPermissionAllDecorator('hg.admin')
92 @view_config(
93 route_name='admin_settings_exception_tracker', request_method='GET',
94 renderer='rhodecode:templates/admin/settings/settings.mako')
95 def browse_exceptions(self):
96 _ = self.request.translate
97 c = self.load_default_context()
98 c.active = 'exceptions_browse'
99 c.limit = safe_int(self.request.GET.get('limit')) or 50
100 c.next_limit = c.limit + 50
101 c.exception_list = self.get_all_exceptions(read_metadata=True, limit=c.limit)
102 c.exception_list_count = self.count_all_exceptions()
103 c.exception_store_dir = exc_tracking.get_exc_store()
104 return self._get_template_context(c)
105
106 @LoginRequired()
107 @HasPermissionAllDecorator('hg.admin')
108 @view_config(
109 route_name='admin_settings_exception_tracker_show', request_method='GET',
110 renderer='rhodecode:templates/admin/settings/settings.mako')
111 def exception_show(self):
112 _ = self.request.translate
113 c = self.load_default_context()
114
115 c.active = 'exceptions'
116 c.exception_id = self.request.matchdict['exception_id']
117 c.traceback = exc_tracking.read_exception(c.exception_id, prefix=None)
118 return self._get_template_context(c)
119
120 @LoginRequired()
121 @HasPermissionAllDecorator('hg.admin')
122 @CSRFRequired()
123 @view_config(
124 route_name='admin_settings_exception_tracker_delete_all', request_method='POST',
125 renderer='rhodecode:templates/admin/settings/settings.mako')
126 def exception_delete_all(self):
127 _ = self.request.translate
128 c = self.load_default_context()
129
130 c.active = 'exceptions'
131 all_exc = self.get_all_exceptions()
132 exc_count = len(all_exc)
133 for exc in all_exc:
134 exc_tracking.delete_exception(exc['exc_id'], prefix=None)
135
136 h.flash(_('Removed {} Exceptions').format(exc_count), category='success')
137 raise HTTPFound(h.route_path('admin_settings_exception_tracker'))
138
139 @LoginRequired()
140 @HasPermissionAllDecorator('hg.admin')
141 @CSRFRequired()
142 @view_config(
143 route_name='admin_settings_exception_tracker_delete', request_method='POST',
144 renderer='rhodecode:templates/admin/settings/settings.mako')
145 def exception_delete(self):
146 _ = self.request.translate
147 c = self.load_default_context()
148
149 c.active = 'exceptions'
150 c.exception_id = self.request.matchdict['exception_id']
151 exc_tracking.delete_exception(c.exception_id, prefix=None)
152
153 h.flash(_('Removed Exception {}').format(c.exception_id), category='success')
154 raise HTTPFound(h.route_path('admin_settings_exception_tracker'))
@@ -0,0 +1,77 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 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 pytest
22
23 from rhodecode.tests.utils import permission_update_data_generator
24
25
26 def route_path(name, params=None, **kwargs):
27 import urllib
28
29 base_url = {
30 'edit_repo_perms': '/{repo_name}/settings/permissions'
31 # update is the same url
32 }[name].format(**kwargs)
33
34 if params:
35 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
36 return base_url
37
38
39 @pytest.mark.usefixtures("app")
40 class TestRepoPermissionsView(object):
41
42 def test_edit_perms_view(self, user_util, autologin_user):
43 repo = user_util.create_repo()
44 self.app.get(
45 route_path('edit_repo_perms',
46 repo_name=repo.repo_name), status=200)
47
48 def test_update_permissions(self, csrf_token, user_util):
49 repo = user_util.create_repo()
50 repo_name = repo.repo_name
51 user = user_util.create_user()
52 user_id = user.user_id
53 username = user.username
54
55 # grant new
56 form_data = permission_update_data_generator(
57 csrf_token,
58 default='repository.write',
59 grant=[(user_id, 'repository.write', username, 'user')])
60
61 response = self.app.post(
62 route_path('edit_repo_perms',
63 repo_name=repo_name), form_data).follow()
64
65 assert 'Repository permissions updated' in response
66
67 # revoke given
68 form_data = permission_update_data_generator(
69 csrf_token,
70 default='repository.read',
71 revoke=[(user_id, 'user')])
72
73 response = self.app.post(
74 route_path('edit_repo_perms',
75 repo_name=repo_name), form_data).follow()
76
77 assert 'Repository permissions updated' in response
@@ -0,0 +1,45 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2011-2018 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 logging
22
23 from pyramid.view import view_config
24
25 from rhodecode.apps._base import RepoAppView
26 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27
28 log = logging.getLogger(__name__)
29
30
31 class RepoSettingsBranchPermissionsView(RepoAppView):
32
33 def load_default_context(self):
34 c = self._get_local_tmpl_context()
35 return c
36
37 @LoginRequired()
38 @HasRepoPermissionAnyDecorator('repository.admin')
39 @view_config(
40 route_name='edit_repo_perms_branch', request_method='GET',
41 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
42 def branch_permissions(self):
43 c = self.load_default_context()
44 c.active = 'permissions_branch'
45 return self._get_template_context(c)
@@ -0,0 +1,80 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 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 pytest
22
23 from rhodecode.tests.utils import permission_update_data_generator
24
25
26 def route_path(name, params=None, **kwargs):
27 import urllib
28 from rhodecode.apps._base import ADMIN_PREFIX
29
30 base_url = {
31 'edit_user_group_perms':
32 ADMIN_PREFIX + '/user_groups/{user_group_id}/edit/permissions',
33 'edit_user_group_perms_update':
34 ADMIN_PREFIX + '/user_groups/{user_group_id}/edit/permissions/update',
35 }[name].format(**kwargs)
36
37 if params:
38 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
39 return base_url
40
41
42 @pytest.mark.usefixtures("app")
43 class TestUserGroupPermissionsView(object):
44
45 def test_edit_perms_view(self, user_util, autologin_user):
46 user_group = user_util.create_user_group()
47 self.app.get(
48 route_path('edit_user_group_perms',
49 user_group_id=user_group.users_group_id), status=200)
50
51 def test_update_permissions(self, csrf_token, user_util):
52 user_group = user_util.create_user_group()
53 user_group_id = user_group.users_group_id
54 user = user_util.create_user()
55 user_id = user.user_id
56 username = user.username
57
58 # grant new
59 form_data = permission_update_data_generator(
60 csrf_token,
61 default='usergroup.write',
62 grant=[(user_id, 'usergroup.write', username, 'user')])
63
64 response = self.app.post(
65 route_path('edit_user_group_perms_update',
66 user_group_id=user_group_id), form_data).follow()
67
68 assert 'User Group permissions updated' in response
69
70 # revoke given
71 form_data = permission_update_data_generator(
72 csrf_token,
73 default='usergroup.read',
74 revoke=[(user_id, 'user')])
75
76 response = self.app.post(
77 route_path('edit_user_group_perms_update',
78 user_group_id=user_group_id), form_data).follow()
79
80 assert 'User Group permissions updated' in response
This diff has been collapsed as it changes many lines, (4587 lines changed) Show them Hide them
@@ -0,0 +1,4587 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 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 Database Models for RhodeCode Enterprise
23 """
24
25 import re
26 import os
27 import time
28 import hashlib
29 import logging
30 import datetime
31 import warnings
32 import ipaddress
33 import functools
34 import traceback
35 import collections
36
37 from sqlalchemy import (
38 or_, and_, not_, func, TypeDecorator, event,
39 Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
40 Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
41 Text, Float, PickleType)
42 from sqlalchemy.sql.expression import true, false
43 from sqlalchemy.sql.functions import coalesce, count # noqa
44 from sqlalchemy.orm import (
45 relationship, joinedload, class_mapper, validates, aliased)
46 from sqlalchemy.ext.declarative import declared_attr
47 from sqlalchemy.ext.hybrid import hybrid_property
48 from sqlalchemy.exc import IntegrityError # noqa
49 from sqlalchemy.dialects.mysql import LONGTEXT
50 from beaker.cache import cache_region
51 from zope.cachedescriptors.property import Lazy as LazyProperty
52
53 from pyramid.threadlocal import get_current_request
54
55 from rhodecode.translation import _
56 from rhodecode.lib.vcs import get_vcs_instance
57 from rhodecode.lib.vcs.backends.base import EmptyCommit, Reference
58 from rhodecode.lib.utils2 import (
59 str2bool, safe_str, get_commit_safe, safe_unicode, md5_safe,
60 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict,
61 glob2re, StrictAttributeDict, cleaned_uri)
62 from rhodecode.lib.jsonalchemy import MutationObj, MutationList, JsonType, \
63 JsonRaw
64 from rhodecode.lib.ext_json import json
65 from rhodecode.lib.caching_query import FromCache
66 from rhodecode.lib.encrypt import AESCipher
67
68 from rhodecode.model.meta import Base, Session
69
70 URL_SEP = '/'
71 log = logging.getLogger(__name__)
72
73 # =============================================================================
74 # BASE CLASSES
75 # =============================================================================
76
77 # this is propagated from .ini file rhodecode.encrypted_values.secret or
78 # beaker.session.secret if first is not set.
79 # and initialized at environment.py
80 ENCRYPTION_KEY = None
81
82 # used to sort permissions by types, '#' used here is not allowed to be in
83 # usernames, and it's very early in sorted string.printable table.
84 PERMISSION_TYPE_SORT = {
85 'admin': '####',
86 'write': '###',
87 'read': '##',
88 'none': '#',
89 }
90
91
92 def display_user_sort(obj):
93 """
94 Sort function used to sort permissions in .permissions() function of
95 Repository, RepoGroup, UserGroup. Also it put the default user in front
96 of all other resources
97 """
98
99 if obj.username == User.DEFAULT_USER:
100 return '#####'
101 prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '')
102 return prefix + obj.username
103
104
105 def display_user_group_sort(obj):
106 """
107 Sort function used to sort permissions in .permissions() function of
108 Repository, RepoGroup, UserGroup. Also it put the default user in front
109 of all other resources
110 """
111
112 prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '')
113 return prefix + obj.users_group_name
114
115
116 def _hash_key(k):
117 return md5_safe(k)
118
119
120 def in_filter_generator(qry, items, limit=500):
121 """
122 Splits IN() into multiple with OR
123 e.g.::
124 cnt = Repository.query().filter(
125 or_(
126 *in_filter_generator(Repository.repo_id, range(100000))
127 )).count()
128 """
129 if not items:
130 # empty list will cause empty query which might cause security issues
131 # this can lead to hidden unpleasant results
132 items = [-1]
133
134 parts = []
135 for chunk in xrange(0, len(items), limit):
136 parts.append(
137 qry.in_(items[chunk: chunk + limit])
138 )
139
140 return parts
141
142
143 class EncryptedTextValue(TypeDecorator):
144 """
145 Special column for encrypted long text data, use like::
146
147 value = Column("encrypted_value", EncryptedValue(), nullable=False)
148
149 This column is intelligent so if value is in unencrypted form it return
150 unencrypted form, but on save it always encrypts
151 """
152 impl = Text
153
154 def process_bind_param(self, value, dialect):
155 if not value:
156 return value
157 if value.startswith('enc$aes$') or value.startswith('enc$aes_hmac$'):
158 # protect against double encrypting if someone manually starts
159 # doing
160 raise ValueError('value needs to be in unencrypted format, ie. '
161 'not starting with enc$aes')
162 return 'enc$aes_hmac$%s' % AESCipher(
163 ENCRYPTION_KEY, hmac=True).encrypt(value)
164
165 def process_result_value(self, value, dialect):
166 import rhodecode
167
168 if not value:
169 return value
170
171 parts = value.split('$', 3)
172 if not len(parts) == 3:
173 # probably not encrypted values
174 return value
175 else:
176 if parts[0] != 'enc':
177 # parts ok but without our header ?
178 return value
179 enc_strict_mode = str2bool(rhodecode.CONFIG.get(
180 'rhodecode.encrypted_values.strict') or True)
181 # at that stage we know it's our encryption
182 if parts[1] == 'aes':
183 decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2])
184 elif parts[1] == 'aes_hmac':
185 decrypted_data = AESCipher(
186 ENCRYPTION_KEY, hmac=True,
187 strict_verification=enc_strict_mode).decrypt(parts[2])
188 else:
189 raise ValueError(
190 'Encryption type part is wrong, must be `aes` '
191 'or `aes_hmac`, got `%s` instead' % (parts[1]))
192 return decrypted_data
193
194
195 class BaseModel(object):
196 """
197 Base Model for all classes
198 """
199
200 @classmethod
201 def _get_keys(cls):
202 """return column names for this model """
203 return class_mapper(cls).c.keys()
204
205 def get_dict(self):
206 """
207 return dict with keys and values corresponding
208 to this model data """
209
210 d = {}
211 for k in self._get_keys():
212 d[k] = getattr(self, k)
213
214 # also use __json__() if present to get additional fields
215 _json_attr = getattr(self, '__json__', None)
216 if _json_attr:
217 # update with attributes from __json__
218 if callable(_json_attr):
219 _json_attr = _json_attr()
220 for k, val in _json_attr.iteritems():
221 d[k] = val
222 return d
223
224 def get_appstruct(self):
225 """return list with keys and values tuples corresponding
226 to this model data """
227
228 lst = []
229 for k in self._get_keys():
230 lst.append((k, getattr(self, k),))
231 return lst
232
233 def populate_obj(self, populate_dict):
234 """populate model with data from given populate_dict"""
235
236 for k in self._get_keys():
237 if k in populate_dict:
238 setattr(self, k, populate_dict[k])
239
240 @classmethod
241 def query(cls):
242 return Session().query(cls)
243
244 @classmethod
245 def get(cls, id_):
246 if id_:
247 return cls.query().get(id_)
248
249 @classmethod
250 def get_or_404(cls, id_):
251 from pyramid.httpexceptions import HTTPNotFound
252
253 try:
254 id_ = int(id_)
255 except (TypeError, ValueError):
256 raise HTTPNotFound()
257
258 res = cls.query().get(id_)
259 if not res:
260 raise HTTPNotFound()
261 return res
262
263 @classmethod
264 def getAll(cls):
265 # deprecated and left for backward compatibility
266 return cls.get_all()
267
268 @classmethod
269 def get_all(cls):
270 return cls.query().all()
271
272 @classmethod
273 def delete(cls, id_):
274 obj = cls.query().get(id_)
275 Session().delete(obj)
276
277 @classmethod
278 def identity_cache(cls, session, attr_name, value):
279 exist_in_session = []
280 for (item_cls, pkey), instance in session.identity_map.items():
281 if cls == item_cls and getattr(instance, attr_name) == value:
282 exist_in_session.append(instance)
283 if exist_in_session:
284 if len(exist_in_session) == 1:
285 return exist_in_session[0]
286 log.exception(
287 'multiple objects with attr %s and '
288 'value %s found with same name: %r',
289 attr_name, value, exist_in_session)
290
291 def __repr__(self):
292 if hasattr(self, '__unicode__'):
293 # python repr needs to return str
294 try:
295 return safe_str(self.__unicode__())
296 except UnicodeDecodeError:
297 pass
298 return '<DB:%s>' % (self.__class__.__name__)
299
300
301 class RhodeCodeSetting(Base, BaseModel):
302 __tablename__ = 'rhodecode_settings'
303 __table_args__ = (
304 UniqueConstraint('app_settings_name'),
305 {'extend_existing': True, 'mysql_engine': 'InnoDB',
306 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
307 )
308
309 SETTINGS_TYPES = {
310 'str': safe_str,
311 'int': safe_int,
312 'unicode': safe_unicode,
313 'bool': str2bool,
314 'list': functools.partial(aslist, sep=',')
315 }
316 DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions'
317 GLOBAL_CONF_KEY = 'app_settings'
318
319 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
320 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
321 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
322 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
323
324 def __init__(self, key='', val='', type='unicode'):
325 self.app_settings_name = key
326 self.app_settings_type = type
327 self.app_settings_value = val
328
329 @validates('_app_settings_value')
330 def validate_settings_value(self, key, val):
331 assert type(val) == unicode
332 return val
333
334 @hybrid_property
335 def app_settings_value(self):
336 v = self._app_settings_value
337 _type = self.app_settings_type
338 if _type:
339 _type = self.app_settings_type.split('.')[0]
340 # decode the encrypted value
341 if 'encrypted' in self.app_settings_type:
342 cipher = EncryptedTextValue()
343 v = safe_unicode(cipher.process_result_value(v, None))
344
345 converter = self.SETTINGS_TYPES.get(_type) or \
346 self.SETTINGS_TYPES['unicode']
347 return converter(v)
348
349 @app_settings_value.setter
350 def app_settings_value(self, val):
351 """
352 Setter that will always make sure we use unicode in app_settings_value
353
354 :param val:
355 """
356 val = safe_unicode(val)
357 # encode the encrypted value
358 if 'encrypted' in self.app_settings_type:
359 cipher = EncryptedTextValue()
360 val = safe_unicode(cipher.process_bind_param(val, None))
361 self._app_settings_value = val
362
363 @hybrid_property
364 def app_settings_type(self):
365 return self._app_settings_type
366
367 @app_settings_type.setter
368 def app_settings_type(self, val):
369 if val.split('.')[0] not in self.SETTINGS_TYPES:
370 raise Exception('type must be one of %s got %s'
371 % (self.SETTINGS_TYPES.keys(), val))
372 self._app_settings_type = val
373
374 def __unicode__(self):
375 return u"<%s('%s:%s[%s]')>" % (
376 self.__class__.__name__,
377 self.app_settings_name, self.app_settings_value,
378 self.app_settings_type
379 )
380
381
382 class RhodeCodeUi(Base, BaseModel):
383 __tablename__ = 'rhodecode_ui'
384 __table_args__ = (
385 UniqueConstraint('ui_key'),
386 {'extend_existing': True, 'mysql_engine': 'InnoDB',
387 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
388 )
389
390 HOOK_REPO_SIZE = 'changegroup.repo_size'
391 # HG
392 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
393 HOOK_PULL = 'outgoing.pull_logger'
394 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
395 HOOK_PRETX_PUSH = 'pretxnchangegroup.pre_push'
396 HOOK_PUSH = 'changegroup.push_logger'
397 HOOK_PUSH_KEY = 'pushkey.key_push'
398
399 # TODO: johbo: Unify way how hooks are configured for git and hg,
400 # git part is currently hardcoded.
401
402 # SVN PATTERNS
403 SVN_BRANCH_ID = 'vcs_svn_branch'
404 SVN_TAG_ID = 'vcs_svn_tag'
405
406 ui_id = Column(
407 "ui_id", Integer(), nullable=False, unique=True, default=None,
408 primary_key=True)
409 ui_section = Column(
410 "ui_section", String(255), nullable=True, unique=None, default=None)
411 ui_key = Column(
412 "ui_key", String(255), nullable=True, unique=None, default=None)
413 ui_value = Column(
414 "ui_value", String(255), nullable=True, unique=None, default=None)
415 ui_active = Column(
416 "ui_active", Boolean(), nullable=True, unique=None, default=True)
417
418 def __repr__(self):
419 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section,
420 self.ui_key, self.ui_value)
421
422
423 class RepoRhodeCodeSetting(Base, BaseModel):
424 __tablename__ = 'repo_rhodecode_settings'
425 __table_args__ = (
426 UniqueConstraint(
427 'app_settings_name', 'repository_id',
428 name='uq_repo_rhodecode_setting_name_repo_id'),
429 {'extend_existing': True, 'mysql_engine': 'InnoDB',
430 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
431 )
432
433 repository_id = Column(
434 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
435 nullable=False)
436 app_settings_id = Column(
437 "app_settings_id", Integer(), nullable=False, unique=True,
438 default=None, primary_key=True)
439 app_settings_name = Column(
440 "app_settings_name", String(255), nullable=True, unique=None,
441 default=None)
442 _app_settings_value = Column(
443 "app_settings_value", String(4096), nullable=True, unique=None,
444 default=None)
445 _app_settings_type = Column(
446 "app_settings_type", String(255), nullable=True, unique=None,
447 default=None)
448
449 repository = relationship('Repository')
450
451 def __init__(self, repository_id, key='', val='', type='unicode'):
452 self.repository_id = repository_id
453 self.app_settings_name = key
454 self.app_settings_type = type
455 self.app_settings_value = val
456
457 @validates('_app_settings_value')
458 def validate_settings_value(self, key, val):
459 assert type(val) == unicode
460 return val
461
462 @hybrid_property
463 def app_settings_value(self):
464 v = self._app_settings_value
465 type_ = self.app_settings_type
466 SETTINGS_TYPES = RhodeCodeSetting.SETTINGS_TYPES
467 converter = SETTINGS_TYPES.get(type_) or SETTINGS_TYPES['unicode']
468 return converter(v)
469
470 @app_settings_value.setter
471 def app_settings_value(self, val):
472 """
473 Setter that will always make sure we use unicode in app_settings_value
474
475 :param val:
476 """
477 self._app_settings_value = safe_unicode(val)
478
479 @hybrid_property
480 def app_settings_type(self):
481 return self._app_settings_type
482
483 @app_settings_type.setter
484 def app_settings_type(self, val):
485 SETTINGS_TYPES = RhodeCodeSetting.SETTINGS_TYPES
486 if val not in SETTINGS_TYPES:
487 raise Exception('type must be one of %s got %s'
488 % (SETTINGS_TYPES.keys(), val))
489 self._app_settings_type = val
490
491 def __unicode__(self):
492 return u"<%s('%s:%s:%s[%s]')>" % (
493 self.__class__.__name__, self.repository.repo_name,
494 self.app_settings_name, self.app_settings_value,
495 self.app_settings_type
496 )
497
498
499 class RepoRhodeCodeUi(Base, BaseModel):
500 __tablename__ = 'repo_rhodecode_ui'
501 __table_args__ = (
502 UniqueConstraint(
503 'repository_id', 'ui_section', 'ui_key',
504 name='uq_repo_rhodecode_ui_repository_id_section_key'),
505 {'extend_existing': True, 'mysql_engine': 'InnoDB',
506 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
507 )
508
509 repository_id = Column(
510 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
511 nullable=False)
512 ui_id = Column(
513 "ui_id", Integer(), nullable=False, unique=True, default=None,
514 primary_key=True)
515 ui_section = Column(
516 "ui_section", String(255), nullable=True, unique=None, default=None)
517 ui_key = Column(
518 "ui_key", String(255), nullable=True, unique=None, default=None)
519 ui_value = Column(
520 "ui_value", String(255), nullable=True, unique=None, default=None)
521 ui_active = Column(
522 "ui_active", Boolean(), nullable=True, unique=None, default=True)
523
524 repository = relationship('Repository')
525
526 def __repr__(self):
527 return '<%s[%s:%s]%s=>%s]>' % (
528 self.__class__.__name__, self.repository.repo_name,
529 self.ui_section, self.ui_key, self.ui_value)
530
531
532 class User(Base, BaseModel):
533 __tablename__ = 'users'
534 __table_args__ = (
535 UniqueConstraint('username'), UniqueConstraint('email'),
536 Index('u_username_idx', 'username'),
537 Index('u_email_idx', 'email'),
538 {'extend_existing': True, 'mysql_engine': 'InnoDB',
539 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
540 )
541 DEFAULT_USER = 'default'
542 DEFAULT_USER_EMAIL = 'anonymous@rhodecode.org'
543 DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
544
545 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
546 username = Column("username", String(255), nullable=True, unique=None, default=None)
547 password = Column("password", String(255), nullable=True, unique=None, default=None)
548 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
549 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
550 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
551 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
552 _email = Column("email", String(255), nullable=True, unique=None, default=None)
553 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
554 last_activity = Column('last_activity', DateTime(timezone=False), nullable=True, unique=None, default=None)
555
556 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
557 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
558 _api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
559 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
560 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
561 _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data
562
563 user_log = relationship('UserLog')
564 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
565
566 repositories = relationship('Repository')
567 repository_groups = relationship('RepoGroup')
568 user_groups = relationship('UserGroup')
569
570 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
571 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
572
573 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
574 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
575 user_group_to_perm = relationship('UserUserGroupToPerm', primaryjoin='UserUserGroupToPerm.user_id==User.user_id', cascade='all')
576
577 group_member = relationship('UserGroupMember', cascade='all')
578
579 notifications = relationship('UserNotification', cascade='all')
580 # notifications assigned to this user
581 user_created_notifications = relationship('Notification', cascade='all')
582 # comments created by this user
583 user_comments = relationship('ChangesetComment', cascade='all')
584 # user profile extra info
585 user_emails = relationship('UserEmailMap', cascade='all')
586 user_ip_map = relationship('UserIpMap', cascade='all')
587 user_auth_tokens = relationship('UserApiKeys', cascade='all')
588 user_ssh_keys = relationship('UserSshKeys', cascade='all')
589
590 # gists
591 user_gists = relationship('Gist', cascade='all')
592 # user pull requests
593 user_pull_requests = relationship('PullRequest', cascade='all')
594 # external identities
595 extenal_identities = relationship(
596 'ExternalIdentity',
597 primaryjoin="User.user_id==ExternalIdentity.local_user_id",
598 cascade='all')
599 # review rules
600 user_review_rules = relationship('RepoReviewRuleUser', cascade='all')
601
602 def __unicode__(self):
603 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
604 self.user_id, self.username)
605
606 @hybrid_property
607 def email(self):
608 return self._email
609
610 @email.setter
611 def email(self, val):
612 self._email = val.lower() if val else None
613
614 @hybrid_property
615 def first_name(self):
616 from rhodecode.lib import helpers as h
617 if self.name:
618 return h.escape(self.name)
619 return self.name
620
621 @hybrid_property
622 def last_name(self):
623 from rhodecode.lib import helpers as h
624 if self.lastname:
625 return h.escape(self.lastname)
626 return self.lastname
627
628 @hybrid_property
629 def api_key(self):
630 """
631 Fetch if exist an auth-token with role ALL connected to this user
632 """
633 user_auth_token = UserApiKeys.query()\
634 .filter(UserApiKeys.user_id == self.user_id)\
635 .filter(or_(UserApiKeys.expires == -1,
636 UserApiKeys.expires >= time.time()))\
637 .filter(UserApiKeys.role == UserApiKeys.ROLE_ALL).first()
638 if user_auth_token:
639 user_auth_token = user_auth_token.api_key
640
641 return user_auth_token
642
643 @api_key.setter
644 def api_key(self, val):
645 # don't allow to set API key this is deprecated for now
646 self._api_key = None
647
648 @property
649 def reviewer_pull_requests(self):
650 return PullRequestReviewers.query() \
651 .options(joinedload(PullRequestReviewers.pull_request)) \
652 .filter(PullRequestReviewers.user_id == self.user_id) \
653 .all()
654
655 @property
656 def firstname(self):
657 # alias for future
658 return self.name
659
660 @property
661 def emails(self):
662 other = UserEmailMap.query()\
663 .filter(UserEmailMap.user == self) \
664 .order_by(UserEmailMap.email_id.asc()) \
665 .all()
666 return [self.email] + [x.email for x in other]
667
668 @property
669 def auth_tokens(self):
670 auth_tokens = self.get_auth_tokens()
671 return [x.api_key for x in auth_tokens]
672
673 def get_auth_tokens(self):
674 return UserApiKeys.query()\
675 .filter(UserApiKeys.user == self)\
676 .order_by(UserApiKeys.user_api_key_id.asc())\
677 .all()
678
679 @LazyProperty
680 def feed_token(self):
681 return self.get_feed_token()
682
683 def get_feed_token(self, cache=True):
684 feed_tokens = UserApiKeys.query()\
685 .filter(UserApiKeys.user == self)\
686 .filter(UserApiKeys.role == UserApiKeys.ROLE_FEED)
687 if cache:
688 feed_tokens = feed_tokens.options(
689 FromCache("long_term", "get_user_feed_token_%s" % self.user_id))
690
691 feed_tokens = feed_tokens.all()
692 if feed_tokens:
693 return feed_tokens[0].api_key
694 return 'NO_FEED_TOKEN_AVAILABLE'
695
696 @classmethod
697 def get(cls, user_id, cache=False):
698 if not user_id:
699 return
700
701 user = cls.query()
702 if cache:
703 user = user.options(
704 FromCache("sql_cache_short", "get_users_%s" % user_id))
705 return user.get(user_id)
706
707 @classmethod
708 def extra_valid_auth_tokens(cls, user, role=None):
709 tokens = UserApiKeys.query().filter(UserApiKeys.user == user)\
710 .filter(or_(UserApiKeys.expires == -1,
711 UserApiKeys.expires >= time.time()))
712 if role:
713 tokens = tokens.filter(or_(UserApiKeys.role == role,
714 UserApiKeys.role == UserApiKeys.ROLE_ALL))
715 return tokens.all()
716
717 def authenticate_by_token(self, auth_token, roles=None, scope_repo_id=None):
718 from rhodecode.lib import auth
719
720 log.debug('Trying to authenticate user: %s via auth-token, '
721 'and roles: %s', self, roles)
722
723 if not auth_token:
724 return False
725
726 crypto_backend = auth.crypto_backend()
727
728 roles = (roles or []) + [UserApiKeys.ROLE_ALL]
729 tokens_q = UserApiKeys.query()\
730 .filter(UserApiKeys.user_id == self.user_id)\
731 .filter(or_(UserApiKeys.expires == -1,
732 UserApiKeys.expires >= time.time()))
733
734 tokens_q = tokens_q.filter(UserApiKeys.role.in_(roles))
735
736 plain_tokens = []
737 hash_tokens = []
738
739 for token in tokens_q.all():
740 # verify scope first
741 if token.repo_id:
742 # token has a scope, we need to verify it
743 if scope_repo_id != token.repo_id:
744 log.debug(
745 'Scope mismatch: token has a set repo scope: %s, '
746 'and calling scope is:%s, skipping further checks',
747 token.repo, scope_repo_id)
748 # token has a scope, and it doesn't match, skip token
749 continue
750
751 if token.api_key.startswith(crypto_backend.ENC_PREF):
752 hash_tokens.append(token.api_key)
753 else:
754 plain_tokens.append(token.api_key)
755
756 is_plain_match = auth_token in plain_tokens
757 if is_plain_match:
758 return True
759
760 for hashed in hash_tokens:
761 # TODO(marcink): this is expensive to calculate, but most secure
762 match = crypto_backend.hash_check(auth_token, hashed)
763 if match:
764 return True
765
766 return False
767
768 @property
769 def ip_addresses(self):
770 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
771 return [x.ip_addr for x in ret]
772
773 @property
774 def username_and_name(self):
775 return '%s (%s %s)' % (self.username, self.first_name, self.last_name)
776
777 @property
778 def username_or_name_or_email(self):
779 full_name = self.full_name if self.full_name is not ' ' else None
780 return self.username or full_name or self.email
781
782 @property
783 def full_name(self):
784 return '%s %s' % (self.first_name, self.last_name)
785
786 @property
787 def full_name_or_username(self):
788 return ('%s %s' % (self.first_name, self.last_name)
789 if (self.first_name and self.last_name) else self.username)
790
791 @property
792 def full_contact(self):
793 return '%s %s <%s>' % (self.first_name, self.last_name, self.email)
794
795 @property
796 def short_contact(self):
797 return '%s %s' % (self.first_name, self.last_name)
798
799 @property
800 def is_admin(self):
801 return self.admin
802
803 def AuthUser(self, **kwargs):
804 """
805 Returns instance of AuthUser for this user
806 """
807 from rhodecode.lib.auth import AuthUser
808 return AuthUser(user_id=self.user_id, username=self.username, **kwargs)
809
810 @hybrid_property
811 def user_data(self):
812 if not self._user_data:
813 return {}
814
815 try:
816 return json.loads(self._user_data)
817 except TypeError:
818 return {}
819
820 @user_data.setter
821 def user_data(self, val):
822 if not isinstance(val, dict):
823 raise Exception('user_data must be dict, got %s' % type(val))
824 try:
825 self._user_data = json.dumps(val)
826 except Exception:
827 log.error(traceback.format_exc())
828
829 @classmethod
830 def get_by_username(cls, username, case_insensitive=False,
831 cache=False, identity_cache=False):
832 session = Session()
833
834 if case_insensitive:
835 q = cls.query().filter(
836 func.lower(cls.username) == func.lower(username))
837 else:
838 q = cls.query().filter(cls.username == username)
839
840 if cache:
841 if identity_cache:
842 val = cls.identity_cache(session, 'username', username)
843 if val:
844 return val
845 else:
846 cache_key = "get_user_by_name_%s" % _hash_key(username)
847 q = q.options(
848 FromCache("sql_cache_short", cache_key))
849
850 return q.scalar()
851
852 @classmethod
853 def get_by_auth_token(cls, auth_token, cache=False):
854 q = UserApiKeys.query()\
855 .filter(UserApiKeys.api_key == auth_token)\
856 .filter(or_(UserApiKeys.expires == -1,
857 UserApiKeys.expires >= time.time()))
858 if cache:
859 q = q.options(
860 FromCache("sql_cache_short", "get_auth_token_%s" % auth_token))
861
862 match = q.first()
863 if match:
864 return match.user
865
866 @classmethod
867 def get_by_email(cls, email, case_insensitive=False, cache=False):
868
869 if case_insensitive:
870 q = cls.query().filter(func.lower(cls.email) == func.lower(email))
871
872 else:
873 q = cls.query().filter(cls.email == email)
874
875 email_key = _hash_key(email)
876 if cache:
877 q = q.options(
878 FromCache("sql_cache_short", "get_email_key_%s" % email_key))
879
880 ret = q.scalar()
881 if ret is None:
882 q = UserEmailMap.query()
883 # try fetching in alternate email map
884 if case_insensitive:
885 q = q.filter(func.lower(UserEmailMap.email) == func.lower(email))
886 else:
887 q = q.filter(UserEmailMap.email == email)
888 q = q.options(joinedload(UserEmailMap.user))
889 if cache:
890 q = q.options(
891 FromCache("sql_cache_short", "get_email_map_key_%s" % email_key))
892 ret = getattr(q.scalar(), 'user', None)
893
894 return ret
895
896 @classmethod
897 def get_from_cs_author(cls, author):
898 """
899 Tries to get User objects out of commit author string
900
901 :param author:
902 """
903 from rhodecode.lib.helpers import email, author_name
904 # Valid email in the attribute passed, see if they're in the system
905 _email = email(author)
906 if _email:
907 user = cls.get_by_email(_email, case_insensitive=True)
908 if user:
909 return user
910 # Maybe we can match by username?
911 _author = author_name(author)
912 user = cls.get_by_username(_author, case_insensitive=True)
913 if user:
914 return user
915
916 def update_userdata(self, **kwargs):
917 usr = self
918 old = usr.user_data
919 old.update(**kwargs)
920 usr.user_data = old
921 Session().add(usr)
922 log.debug('updated userdata with ', kwargs)
923
924 def update_lastlogin(self):
925 """Update user lastlogin"""
926 self.last_login = datetime.datetime.now()
927 Session().add(self)
928 log.debug('updated user %s lastlogin', self.username)
929
930 def update_lastactivity(self):
931 """Update user lastactivity"""
932 self.last_activity = datetime.datetime.now()
933 Session().add(self)
934 log.debug('updated user `%s` last activity', self.username)
935
936 def update_password(self, new_password):
937 from rhodecode.lib.auth import get_crypt_password
938
939 self.password = get_crypt_password(new_password)
940 Session().add(self)
941
942 @classmethod
943 def get_first_super_admin(cls):
944 user = User.query().filter(User.admin == true()).first()
945 if user is None:
946 raise Exception('FATAL: Missing administrative account!')
947 return user
948
949 @classmethod
950 def get_all_super_admins(cls):
951 """
952 Returns all admin accounts sorted by username
953 """
954 return User.query().filter(User.admin == true())\
955 .order_by(User.username.asc()).all()
956
957 @classmethod
958 def get_default_user(cls, cache=False, refresh=False):
959 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
960 if user is None:
961 raise Exception('FATAL: Missing default account!')
962 if refresh:
963 # The default user might be based on outdated state which
964 # has been loaded from the cache.
965 # A call to refresh() ensures that the
966 # latest state from the database is used.
967 Session().refresh(user)
968 return user
969
970 def _get_default_perms(self, user, suffix=''):
971 from rhodecode.model.permission import PermissionModel
972 return PermissionModel().get_default_perms(user.user_perms, suffix)
973
974 def get_default_perms(self, suffix=''):
975 return self._get_default_perms(self, suffix)
976
977 def get_api_data(self, include_secrets=False, details='full'):
978 """
979 Common function for generating user related data for API
980
981 :param include_secrets: By default secrets in the API data will be replaced
982 by a placeholder value to prevent exposing this data by accident. In case
983 this data shall be exposed, set this flag to ``True``.
984
985 :param details: details can be 'basic|full' basic gives only a subset of
986 the available user information that includes user_id, name and emails.
987 """
988 user = self
989 user_data = self.user_data
990 data = {
991 'user_id': user.user_id,
992 'username': user.username,
993 'firstname': user.name,
994 'lastname': user.lastname,
995 'email': user.email,
996 'emails': user.emails,
997 }
998 if details == 'basic':
999 return data
1000
1001 auth_token_length = 40
1002 auth_token_replacement = '*' * auth_token_length
1003
1004 extras = {
1005 'auth_tokens': [auth_token_replacement],
1006 'active': user.active,
1007 'admin': user.admin,
1008 'extern_type': user.extern_type,
1009 'extern_name': user.extern_name,
1010 'last_login': user.last_login,
1011 'last_activity': user.last_activity,
1012 'ip_addresses': user.ip_addresses,
1013 'language': user_data.get('language')
1014 }
1015 data.update(extras)
1016
1017 if include_secrets:
1018 data['auth_tokens'] = user.auth_tokens
1019 return data
1020
1021 def __json__(self):
1022 data = {
1023 'full_name': self.full_name,
1024 'full_name_or_username': self.full_name_or_username,
1025 'short_contact': self.short_contact,
1026 'full_contact': self.full_contact,
1027 }
1028 data.update(self.get_api_data())
1029 return data
1030
1031
1032 class UserApiKeys(Base, BaseModel):
1033 __tablename__ = 'user_api_keys'
1034 __table_args__ = (
1035 Index('uak_api_key_idx', 'api_key', unique=True),
1036 Index('uak_api_key_expires_idx', 'api_key', 'expires'),
1037 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1038 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1039 )
1040 __mapper_args__ = {}
1041
1042 # ApiKey role
1043 ROLE_ALL = 'token_role_all'
1044 ROLE_HTTP = 'token_role_http'
1045 ROLE_VCS = 'token_role_vcs'
1046 ROLE_API = 'token_role_api'
1047 ROLE_FEED = 'token_role_feed'
1048 ROLE_PASSWORD_RESET = 'token_password_reset'
1049
1050 ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED]
1051
1052 user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1053 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1054 api_key = Column("api_key", String(255), nullable=False, unique=True)
1055 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1056 expires = Column('expires', Float(53), nullable=False)
1057 role = Column('role', String(255), nullable=True)
1058 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1059
1060 # scope columns
1061 repo_id = Column(
1062 'repo_id', Integer(), ForeignKey('repositories.repo_id'),
1063 nullable=True, unique=None, default=None)
1064 repo = relationship('Repository', lazy='joined')
1065
1066 repo_group_id = Column(
1067 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
1068 nullable=True, unique=None, default=None)
1069 repo_group = relationship('RepoGroup', lazy='joined')
1070
1071 user = relationship('User', lazy='joined')
1072
1073 def __unicode__(self):
1074 return u"<%s('%s')>" % (self.__class__.__name__, self.role)
1075
1076 def __json__(self):
1077 data = {
1078 'auth_token': self.api_key,
1079 'role': self.role,
1080 'scope': self.scope_humanized,
1081 'expired': self.expired
1082 }
1083 return data
1084
1085 def get_api_data(self, include_secrets=False):
1086 data = self.__json__()
1087 if include_secrets:
1088 return data
1089 else:
1090 data['auth_token'] = self.token_obfuscated
1091 return data
1092
1093 @hybrid_property
1094 def description_safe(self):
1095 from rhodecode.lib import helpers as h
1096 return h.escape(self.description)
1097
1098 @property
1099 def expired(self):
1100 if self.expires == -1:
1101 return False
1102 return time.time() > self.expires
1103
1104 @classmethod
1105 def _get_role_name(cls, role):
1106 return {
1107 cls.ROLE_ALL: _('all'),
1108 cls.ROLE_HTTP: _('http/web interface'),
1109 cls.ROLE_VCS: _('vcs (git/hg/svn protocol)'),
1110 cls.ROLE_API: _('api calls'),
1111 cls.ROLE_FEED: _('feed access'),
1112 }.get(role, role)
1113
1114 @property
1115 def role_humanized(self):
1116 return self._get_role_name(self.role)
1117
1118 def _get_scope(self):
1119 if self.repo:
1120 return repr(self.repo)
1121 if self.repo_group:
1122 return repr(self.repo_group) + ' (recursive)'
1123 return 'global'
1124
1125 @property
1126 def scope_humanized(self):
1127 return self._get_scope()
1128
1129 @property
1130 def token_obfuscated(self):
1131 if self.api_key:
1132 return self.api_key[:4] + "****"
1133
1134
1135 class UserEmailMap(Base, BaseModel):
1136 __tablename__ = 'user_email_map'
1137 __table_args__ = (
1138 Index('uem_email_idx', 'email'),
1139 UniqueConstraint('email'),
1140 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1141 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1142 )
1143 __mapper_args__ = {}
1144
1145 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1146 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1147 _email = Column("email", String(255), nullable=True, unique=False, default=None)
1148 user = relationship('User', lazy='joined')
1149
1150 @validates('_email')
1151 def validate_email(self, key, email):
1152 # check if this email is not main one
1153 main_email = Session().query(User).filter(User.email == email).scalar()
1154 if main_email is not None:
1155 raise AttributeError('email %s is present is user table' % email)
1156 return email
1157
1158 @hybrid_property
1159 def email(self):
1160 return self._email
1161
1162 @email.setter
1163 def email(self, val):
1164 self._email = val.lower() if val else None
1165
1166
1167 class UserIpMap(Base, BaseModel):
1168 __tablename__ = 'user_ip_map'
1169 __table_args__ = (
1170 UniqueConstraint('user_id', 'ip_addr'),
1171 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1172 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1173 )
1174 __mapper_args__ = {}
1175
1176 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1177 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1178 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
1179 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
1180 description = Column("description", String(10000), nullable=True, unique=None, default=None)
1181 user = relationship('User', lazy='joined')
1182
1183 @hybrid_property
1184 def description_safe(self):
1185 from rhodecode.lib import helpers as h
1186 return h.escape(self.description)
1187
1188 @classmethod
1189 def _get_ip_range(cls, ip_addr):
1190 net = ipaddress.ip_network(safe_unicode(ip_addr), strict=False)
1191 return [str(net.network_address), str(net.broadcast_address)]
1192
1193 def __json__(self):
1194 return {
1195 'ip_addr': self.ip_addr,
1196 'ip_range': self._get_ip_range(self.ip_addr),
1197 }
1198
1199 def __unicode__(self):
1200 return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__,
1201 self.user_id, self.ip_addr)
1202
1203
1204 class UserSshKeys(Base, BaseModel):
1205 __tablename__ = 'user_ssh_keys'
1206 __table_args__ = (
1207 Index('usk_ssh_key_fingerprint_idx', 'ssh_key_fingerprint'),
1208
1209 UniqueConstraint('ssh_key_fingerprint'),
1210
1211 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1212 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1213 )
1214 __mapper_args__ = {}
1215
1216 ssh_key_id = Column('ssh_key_id', Integer(), nullable=False, unique=True, default=None, primary_key=True)
1217 ssh_key_data = Column('ssh_key_data', String(10240), nullable=False, unique=None, default=None)
1218 ssh_key_fingerprint = Column('ssh_key_fingerprint', String(255), nullable=False, unique=None, default=None)
1219
1220 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1221
1222 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1223 accessed_on = Column('accessed_on', DateTime(timezone=False), nullable=True, default=None)
1224 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1225
1226 user = relationship('User', lazy='joined')
1227
1228 def __json__(self):
1229 data = {
1230 'ssh_fingerprint': self.ssh_key_fingerprint,
1231 'description': self.description,
1232 'created_on': self.created_on
1233 }
1234 return data
1235
1236 def get_api_data(self):
1237 data = self.__json__()
1238 return data
1239
1240
1241 class UserLog(Base, BaseModel):
1242 __tablename__ = 'user_logs'
1243 __table_args__ = (
1244 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1245 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1246 )
1247 VERSION_1 = 'v1'
1248 VERSION_2 = 'v2'
1249 VERSIONS = [VERSION_1, VERSION_2]
1250
1251 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1252 user_id = Column("user_id", Integer(), ForeignKey('users.user_id',ondelete='SET NULL'), nullable=True, unique=None, default=None)
1253 username = Column("username", String(255), nullable=True, unique=None, default=None)
1254 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id', ondelete='SET NULL'), nullable=True, unique=None, default=None)
1255 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
1256 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
1257 action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None)
1258 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
1259
1260 version = Column("version", String(255), nullable=True, default=VERSION_1)
1261 user_data = Column('user_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1262 action_data = Column('action_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1263
1264 def __unicode__(self):
1265 return u"<%s('id:%s:%s')>" % (
1266 self.__class__.__name__, self.repository_name, self.action)
1267
1268 def __json__(self):
1269 return {
1270 'user_id': self.user_id,
1271 'username': self.username,
1272 'repository_id': self.repository_id,
1273 'repository_name': self.repository_name,
1274 'user_ip': self.user_ip,
1275 'action_date': self.action_date,
1276 'action': self.action,
1277 }
1278
1279 @hybrid_property
1280 def entry_id(self):
1281 return self.user_log_id
1282
1283 @property
1284 def action_as_day(self):
1285 return datetime.date(*self.action_date.timetuple()[:3])
1286
1287 user = relationship('User')
1288 repository = relationship('Repository', cascade='')
1289
1290
1291 class UserGroup(Base, BaseModel):
1292 __tablename__ = 'users_groups'
1293 __table_args__ = (
1294 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1295 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1296 )
1297
1298 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1299 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
1300 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
1301 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
1302 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
1303 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
1304 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1305 _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data
1306
1307 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
1308 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
1309 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
1310 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
1311 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
1312 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
1313
1314 user_group_review_rules = relationship('RepoReviewRuleUserGroup', cascade='all')
1315 user = relationship('User', primaryjoin="User.user_id==UserGroup.user_id")
1316
1317 @classmethod
1318 def _load_group_data(cls, column):
1319 if not column:
1320 return {}
1321
1322 try:
1323 return json.loads(column) or {}
1324 except TypeError:
1325 return {}
1326
1327 @hybrid_property
1328 def description_safe(self):
1329 from rhodecode.lib import helpers as h
1330 return h.escape(self.user_group_description)
1331
1332 @hybrid_property
1333 def group_data(self):
1334 return self._load_group_data(self._group_data)
1335
1336 @group_data.expression
1337 def group_data(self, **kwargs):
1338 return self._group_data
1339
1340 @group_data.setter
1341 def group_data(self, val):
1342 try:
1343 self._group_data = json.dumps(val)
1344 except Exception:
1345 log.error(traceback.format_exc())
1346
1347 @classmethod
1348 def _load_sync(cls, group_data):
1349 if group_data:
1350 return group_data.get('extern_type')
1351
1352 @property
1353 def sync(self):
1354 return self._load_sync(self.group_data)
1355
1356 def __unicode__(self):
1357 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
1358 self.users_group_id,
1359 self.users_group_name)
1360
1361 @classmethod
1362 def get_by_group_name(cls, group_name, cache=False,
1363 case_insensitive=False):
1364 if case_insensitive:
1365 q = cls.query().filter(func.lower(cls.users_group_name) ==
1366 func.lower(group_name))
1367
1368 else:
1369 q = cls.query().filter(cls.users_group_name == group_name)
1370 if cache:
1371 q = q.options(
1372 FromCache("sql_cache_short", "get_group_%s" % _hash_key(group_name)))
1373 return q.scalar()
1374
1375 @classmethod
1376 def get(cls, user_group_id, cache=False):
1377 if not user_group_id:
1378 return
1379
1380 user_group = cls.query()
1381 if cache:
1382 user_group = user_group.options(
1383 FromCache("sql_cache_short", "get_users_group_%s" % user_group_id))
1384 return user_group.get(user_group_id)
1385
1386 def permissions(self, with_admins=True, with_owner=True):
1387 q = UserUserGroupToPerm.query().filter(UserUserGroupToPerm.user_group == self)
1388 q = q.options(joinedload(UserUserGroupToPerm.user_group),
1389 joinedload(UserUserGroupToPerm.user),
1390 joinedload(UserUserGroupToPerm.permission),)
1391
1392 # get owners and admins and permissions. We do a trick of re-writing
1393 # objects from sqlalchemy to named-tuples due to sqlalchemy session
1394 # has a global reference and changing one object propagates to all
1395 # others. This means if admin is also an owner admin_row that change
1396 # would propagate to both objects
1397 perm_rows = []
1398 for _usr in q.all():
1399 usr = AttributeDict(_usr.user.get_dict())
1400 usr.permission = _usr.permission.permission_name
1401 perm_rows.append(usr)
1402
1403 # filter the perm rows by 'default' first and then sort them by
1404 # admin,write,read,none permissions sorted again alphabetically in
1405 # each group
1406 perm_rows = sorted(perm_rows, key=display_user_sort)
1407
1408 _admin_perm = 'usergroup.admin'
1409 owner_row = []
1410 if with_owner:
1411 usr = AttributeDict(self.user.get_dict())
1412 usr.owner_row = True
1413 usr.permission = _admin_perm
1414 owner_row.append(usr)
1415
1416 super_admin_rows = []
1417 if with_admins:
1418 for usr in User.get_all_super_admins():
1419 # if this admin is also owner, don't double the record
1420 if usr.user_id == owner_row[0].user_id:
1421 owner_row[0].admin_row = True
1422 else:
1423 usr = AttributeDict(usr.get_dict())
1424 usr.admin_row = True
1425 usr.permission = _admin_perm
1426 super_admin_rows.append(usr)
1427
1428 return super_admin_rows + owner_row + perm_rows
1429
1430 def permission_user_groups(self):
1431 q = UserGroupUserGroupToPerm.query().filter(UserGroupUserGroupToPerm.target_user_group == self)
1432 q = q.options(joinedload(UserGroupUserGroupToPerm.user_group),
1433 joinedload(UserGroupUserGroupToPerm.target_user_group),
1434 joinedload(UserGroupUserGroupToPerm.permission),)
1435
1436 perm_rows = []
1437 for _user_group in q.all():
1438 usr = AttributeDict(_user_group.user_group.get_dict())
1439 usr.permission = _user_group.permission.permission_name
1440 perm_rows.append(usr)
1441
1442 perm_rows = sorted(perm_rows, key=display_user_group_sort)
1443 return perm_rows
1444
1445 def _get_default_perms(self, user_group, suffix=''):
1446 from rhodecode.model.permission import PermissionModel
1447 return PermissionModel().get_default_perms(user_group.users_group_to_perm, suffix)
1448
1449 def get_default_perms(self, suffix=''):
1450 return self._get_default_perms(self, suffix)
1451
1452 def get_api_data(self, with_group_members=True, include_secrets=False):
1453 """
1454 :param include_secrets: See :meth:`User.get_api_data`, this parameter is
1455 basically forwarded.
1456
1457 """
1458 user_group = self
1459 data = {
1460 'users_group_id': user_group.users_group_id,
1461 'group_name': user_group.users_group_name,
1462 'group_description': user_group.user_group_description,
1463 'active': user_group.users_group_active,
1464 'owner': user_group.user.username,
1465 'sync': user_group.sync,
1466 'owner_email': user_group.user.email,
1467 }
1468
1469 if with_group_members:
1470 users = []
1471 for user in user_group.members:
1472 user = user.user
1473 users.append(user.get_api_data(include_secrets=include_secrets))
1474 data['users'] = users
1475
1476 return data
1477
1478
1479 class UserGroupMember(Base, BaseModel):
1480 __tablename__ = 'users_groups_members'
1481 __table_args__ = (
1482 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1483 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1484 )
1485
1486 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1487 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1488 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1489
1490 user = relationship('User', lazy='joined')
1491 users_group = relationship('UserGroup')
1492
1493 def __init__(self, gr_id='', u_id=''):
1494 self.users_group_id = gr_id
1495 self.user_id = u_id
1496
1497
1498 class RepositoryField(Base, BaseModel):
1499 __tablename__ = 'repositories_fields'
1500 __table_args__ = (
1501 UniqueConstraint('repository_id', 'field_key'), # no-multi field
1502 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1503 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1504 )
1505 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
1506
1507 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1508 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1509 field_key = Column("field_key", String(250))
1510 field_label = Column("field_label", String(1024), nullable=False)
1511 field_value = Column("field_value", String(10000), nullable=False)
1512 field_desc = Column("field_desc", String(1024), nullable=False)
1513 field_type = Column("field_type", String(255), nullable=False, unique=None)
1514 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1515
1516 repository = relationship('Repository')
1517
1518 @property
1519 def field_key_prefixed(self):
1520 return 'ex_%s' % self.field_key
1521
1522 @classmethod
1523 def un_prefix_key(cls, key):
1524 if key.startswith(cls.PREFIX):
1525 return key[len(cls.PREFIX):]
1526 return key
1527
1528 @classmethod
1529 def get_by_key_name(cls, key, repo):
1530 row = cls.query()\
1531 .filter(cls.repository == repo)\
1532 .filter(cls.field_key == key).scalar()
1533 return row
1534
1535
1536 class Repository(Base, BaseModel):
1537 __tablename__ = 'repositories'
1538 __table_args__ = (
1539 Index('r_repo_name_idx', 'repo_name', mysql_length=255),
1540 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1541 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1542 )
1543 DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
1544 DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}'
1545 DEFAULT_CLONE_URI_SSH = 'ssh://{sys_user}@{hostname}/{repo}'
1546
1547 STATE_CREATED = 'repo_state_created'
1548 STATE_PENDING = 'repo_state_pending'
1549 STATE_ERROR = 'repo_state_error'
1550
1551 LOCK_AUTOMATIC = 'lock_auto'
1552 LOCK_API = 'lock_api'
1553 LOCK_WEB = 'lock_web'
1554 LOCK_PULL = 'lock_pull'
1555
1556 NAME_SEP = URL_SEP
1557
1558 repo_id = Column(
1559 "repo_id", Integer(), nullable=False, unique=True, default=None,
1560 primary_key=True)
1561 _repo_name = Column(
1562 "repo_name", Text(), nullable=False, default=None)
1563 _repo_name_hash = Column(
1564 "repo_name_hash", String(255), nullable=False, unique=True)
1565 repo_state = Column("repo_state", String(255), nullable=True)
1566
1567 clone_uri = Column(
1568 "clone_uri", EncryptedTextValue(), nullable=True, unique=False,
1569 default=None)
1570 push_uri = Column(
1571 "push_uri", EncryptedTextValue(), nullable=True, unique=False,
1572 default=None)
1573 repo_type = Column(
1574 "repo_type", String(255), nullable=False, unique=False, default=None)
1575 user_id = Column(
1576 "user_id", Integer(), ForeignKey('users.user_id'), nullable=False,
1577 unique=False, default=None)
1578 private = Column(
1579 "private", Boolean(), nullable=True, unique=None, default=None)
1580 enable_statistics = Column(
1581 "statistics", Boolean(), nullable=True, unique=None, default=True)
1582 enable_downloads = Column(
1583 "downloads", Boolean(), nullable=True, unique=None, default=True)
1584 description = Column(
1585 "description", String(10000), nullable=True, unique=None, default=None)
1586 created_on = Column(
1587 'created_on', DateTime(timezone=False), nullable=True, unique=None,
1588 default=datetime.datetime.now)
1589 updated_on = Column(
1590 'updated_on', DateTime(timezone=False), nullable=True, unique=None,
1591 default=datetime.datetime.now)
1592 _landing_revision = Column(
1593 "landing_revision", String(255), nullable=False, unique=False,
1594 default=None)
1595 enable_locking = Column(
1596 "enable_locking", Boolean(), nullable=False, unique=None,
1597 default=False)
1598 _locked = Column(
1599 "locked", String(255), nullable=True, unique=False, default=None)
1600 _changeset_cache = Column(
1601 "changeset_cache", LargeBinary(), nullable=True) # JSON data
1602
1603 fork_id = Column(
1604 "fork_id", Integer(), ForeignKey('repositories.repo_id'),
1605 nullable=True, unique=False, default=None)
1606 group_id = Column(
1607 "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True,
1608 unique=False, default=None)
1609
1610 user = relationship('User', lazy='joined')
1611 fork = relationship('Repository', remote_side=repo_id, lazy='joined')
1612 group = relationship('RepoGroup', lazy='joined')
1613 repo_to_perm = relationship(
1614 'UserRepoToPerm', cascade='all',
1615 order_by='UserRepoToPerm.repo_to_perm_id')
1616 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
1617 stats = relationship('Statistics', cascade='all', uselist=False)
1618
1619 followers = relationship(
1620 'UserFollowing',
1621 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
1622 cascade='all')
1623 extra_fields = relationship(
1624 'RepositoryField', cascade="all, delete, delete-orphan")
1625 logs = relationship('UserLog')
1626 comments = relationship(
1627 'ChangesetComment', cascade="all, delete, delete-orphan")
1628 pull_requests_source = relationship(
1629 'PullRequest',
1630 primaryjoin='PullRequest.source_repo_id==Repository.repo_id',
1631 cascade="all, delete, delete-orphan")
1632 pull_requests_target = relationship(
1633 'PullRequest',
1634 primaryjoin='PullRequest.target_repo_id==Repository.repo_id',
1635 cascade="all, delete, delete-orphan")
1636 ui = relationship('RepoRhodeCodeUi', cascade="all")
1637 settings = relationship('RepoRhodeCodeSetting', cascade="all")
1638 integrations = relationship('Integration',
1639 cascade="all, delete, delete-orphan")
1640
1641 scoped_tokens = relationship('UserApiKeys', cascade="all")
1642
1643 def __unicode__(self):
1644 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
1645 safe_unicode(self.repo_name))
1646
1647 @hybrid_property
1648 def description_safe(self):
1649 from rhodecode.lib import helpers as h
1650 return h.escape(self.description)
1651
1652 @hybrid_property
1653 def landing_rev(self):
1654 # always should return [rev_type, rev]
1655 if self._landing_revision:
1656 _rev_info = self._landing_revision.split(':')
1657 if len(_rev_info) < 2:
1658 _rev_info.insert(0, 'rev')
1659 return [_rev_info[0], _rev_info[1]]
1660 return [None, None]
1661
1662 @landing_rev.setter
1663 def landing_rev(self, val):
1664 if ':' not in val:
1665 raise ValueError('value must be delimited with `:` and consist '
1666 'of <rev_type>:<rev>, got %s instead' % val)
1667 self._landing_revision = val
1668
1669 @hybrid_property
1670 def locked(self):
1671 if self._locked:
1672 user_id, timelocked, reason = self._locked.split(':')
1673 lock_values = int(user_id), timelocked, reason
1674 else:
1675 lock_values = [None, None, None]
1676 return lock_values
1677
1678 @locked.setter
1679 def locked(self, val):
1680 if val and isinstance(val, (list, tuple)):
1681 self._locked = ':'.join(map(str, val))
1682 else:
1683 self._locked = None
1684
1685 @hybrid_property
1686 def changeset_cache(self):
1687 from rhodecode.lib.vcs.backends.base import EmptyCommit
1688 dummy = EmptyCommit().__json__()
1689 if not self._changeset_cache:
1690 return dummy
1691 try:
1692 return json.loads(self._changeset_cache)
1693 except TypeError:
1694 return dummy
1695 except Exception:
1696 log.error(traceback.format_exc())
1697 return dummy
1698
1699 @changeset_cache.setter
1700 def changeset_cache(self, val):
1701 try:
1702 self._changeset_cache = json.dumps(val)
1703 except Exception:
1704 log.error(traceback.format_exc())
1705
1706 @hybrid_property
1707 def repo_name(self):
1708 return self._repo_name
1709
1710 @repo_name.setter
1711 def repo_name(self, value):
1712 self._repo_name = value
1713 self._repo_name_hash = hashlib.sha1(safe_str(value)).hexdigest()
1714
1715 @classmethod
1716 def normalize_repo_name(cls, repo_name):
1717 """
1718 Normalizes os specific repo_name to the format internally stored inside
1719 database using URL_SEP
1720
1721 :param cls:
1722 :param repo_name:
1723 """
1724 return cls.NAME_SEP.join(repo_name.split(os.sep))
1725
1726 @classmethod
1727 def get_by_repo_name(cls, repo_name, cache=False, identity_cache=False):
1728 session = Session()
1729 q = session.query(cls).filter(cls.repo_name == repo_name)
1730
1731 if cache:
1732 if identity_cache:
1733 val = cls.identity_cache(session, 'repo_name', repo_name)
1734 if val:
1735 return val
1736 else:
1737 cache_key = "get_repo_by_name_%s" % _hash_key(repo_name)
1738 q = q.options(
1739 FromCache("sql_cache_short", cache_key))
1740
1741 return q.scalar()
1742
1743 @classmethod
1744 def get_by_id_or_repo_name(cls, repoid):
1745 if isinstance(repoid, (int, long)):
1746 try:
1747 repo = cls.get(repoid)
1748 except ValueError:
1749 repo = None
1750 else:
1751 repo = cls.get_by_repo_name(repoid)
1752 return repo
1753
1754 @classmethod
1755 def get_by_full_path(cls, repo_full_path):
1756 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
1757 repo_name = cls.normalize_repo_name(repo_name)
1758 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
1759
1760 @classmethod
1761 def get_repo_forks(cls, repo_id):
1762 return cls.query().filter(Repository.fork_id == repo_id)
1763
1764 @classmethod
1765 def base_path(cls):
1766 """
1767 Returns base path when all repos are stored
1768
1769 :param cls:
1770 """
1771 q = Session().query(RhodeCodeUi)\
1772 .filter(RhodeCodeUi.ui_key == cls.NAME_SEP)
1773 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
1774 return q.one().ui_value
1775
1776 @classmethod
1777 def get_all_repos(cls, user_id=Optional(None), group_id=Optional(None),
1778 case_insensitive=True):
1779 q = Repository.query()
1780
1781 if not isinstance(user_id, Optional):
1782 q = q.filter(Repository.user_id == user_id)
1783
1784 if not isinstance(group_id, Optional):
1785 q = q.filter(Repository.group_id == group_id)
1786
1787 if case_insensitive:
1788 q = q.order_by(func.lower(Repository.repo_name))
1789 else:
1790 q = q.order_by(Repository.repo_name)
1791 return q.all()
1792
1793 @property
1794 def forks(self):
1795 """
1796 Return forks of this repo
1797 """
1798 return Repository.get_repo_forks(self.repo_id)
1799
1800 @property
1801 def parent(self):
1802 """
1803 Returns fork parent
1804 """
1805 return self.fork
1806
1807 @property
1808 def just_name(self):
1809 return self.repo_name.split(self.NAME_SEP)[-1]
1810
1811 @property
1812 def groups_with_parents(self):
1813 groups = []
1814 if self.group is None:
1815 return groups
1816
1817 cur_gr = self.group
1818 groups.insert(0, cur_gr)
1819 while 1:
1820 gr = getattr(cur_gr, 'parent_group', None)
1821 cur_gr = cur_gr.parent_group
1822 if gr is None:
1823 break
1824 groups.insert(0, gr)
1825
1826 return groups
1827
1828 @property
1829 def groups_and_repo(self):
1830 return self.groups_with_parents, self
1831
1832 @LazyProperty
1833 def repo_path(self):
1834 """
1835 Returns base full path for that repository means where it actually
1836 exists on a filesystem
1837 """
1838 q = Session().query(RhodeCodeUi).filter(
1839 RhodeCodeUi.ui_key == self.NAME_SEP)
1840 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
1841 return q.one().ui_value
1842
1843 @property
1844 def repo_full_path(self):
1845 p = [self.repo_path]
1846 # we need to split the name by / since this is how we store the
1847 # names in the database, but that eventually needs to be converted
1848 # into a valid system path
1849 p += self.repo_name.split(self.NAME_SEP)
1850 return os.path.join(*map(safe_unicode, p))
1851
1852 @property
1853 def cache_keys(self):
1854 """
1855 Returns associated cache keys for that repo
1856 """
1857 return CacheKey.query()\
1858 .filter(CacheKey.cache_args == self.repo_name)\
1859 .order_by(CacheKey.cache_key)\
1860 .all()
1861
1862 @property
1863 def cached_diffs_relative_dir(self):
1864 """
1865 Return a relative to the repository store path of cached diffs
1866 used for safe display for users, who shouldn't know the absolute store
1867 path
1868 """
1869 return os.path.join(
1870 os.path.dirname(self.repo_name),
1871 self.cached_diffs_dir.split(os.path.sep)[-1])
1872
1873 @property
1874 def cached_diffs_dir(self):
1875 path = self.repo_full_path
1876 return os.path.join(
1877 os.path.dirname(path),
1878 '.__shadow_diff_cache_repo_{}'.format(self.repo_id))
1879
1880 def cached_diffs(self):
1881 diff_cache_dir = self.cached_diffs_dir
1882 if os.path.isdir(diff_cache_dir):
1883 return os.listdir(diff_cache_dir)
1884 return []
1885
1886 def get_new_name(self, repo_name):
1887 """
1888 returns new full repository name based on assigned group and new new
1889
1890 :param group_name:
1891 """
1892 path_prefix = self.group.full_path_splitted if self.group else []
1893 return self.NAME_SEP.join(path_prefix + [repo_name])
1894
1895 @property
1896 def _config(self):
1897 """
1898 Returns db based config object.
1899 """
1900 from rhodecode.lib.utils import make_db_config
1901 return make_db_config(clear_session=False, repo=self)
1902
1903 def permissions(self, with_admins=True, with_owner=True):
1904 q = UserRepoToPerm.query().filter(UserRepoToPerm.repository == self)
1905 q = q.options(joinedload(UserRepoToPerm.repository),
1906 joinedload(UserRepoToPerm.user),
1907 joinedload(UserRepoToPerm.permission),)
1908
1909 # get owners and admins and permissions. We do a trick of re-writing
1910 # objects from sqlalchemy to named-tuples due to sqlalchemy session
1911 # has a global reference and changing one object propagates to all
1912 # others. This means if admin is also an owner admin_row that change
1913 # would propagate to both objects
1914 perm_rows = []
1915 for _usr in q.all():
1916 usr = AttributeDict(_usr.user.get_dict())
1917 usr.permission = _usr.permission.permission_name
1918 usr.permission_id = _usr.repo_to_perm_id
1919 perm_rows.append(usr)
1920
1921 # filter the perm rows by 'default' first and then sort them by
1922 # admin,write,read,none permissions sorted again alphabetically in
1923 # each group
1924 perm_rows = sorted(perm_rows, key=display_user_sort)
1925
1926 _admin_perm = 'repository.admin'
1927 owner_row = []
1928 if with_owner:
1929 usr = AttributeDict(self.user.get_dict())
1930 usr.owner_row = True
1931 usr.permission = _admin_perm
1932 usr.permission_id = None
1933 owner_row.append(usr)
1934
1935 super_admin_rows = []
1936 if with_admins:
1937 for usr in User.get_all_super_admins():
1938 # if this admin is also owner, don't double the record
1939 if usr.user_id == owner_row[0].user_id:
1940 owner_row[0].admin_row = True
1941 else:
1942 usr = AttributeDict(usr.get_dict())
1943 usr.admin_row = True
1944 usr.permission = _admin_perm
1945 usr.permission_id = None
1946 super_admin_rows.append(usr)
1947
1948 return super_admin_rows + owner_row + perm_rows
1949
1950 def permission_user_groups(self):
1951 q = UserGroupRepoToPerm.query().filter(
1952 UserGroupRepoToPerm.repository == self)
1953 q = q.options(joinedload(UserGroupRepoToPerm.repository),
1954 joinedload(UserGroupRepoToPerm.users_group),
1955 joinedload(UserGroupRepoToPerm.permission),)
1956
1957 perm_rows = []
1958 for _user_group in q.all():
1959 usr = AttributeDict(_user_group.users_group.get_dict())
1960 usr.permission = _user_group.permission.permission_name
1961 perm_rows.append(usr)
1962
1963 perm_rows = sorted(perm_rows, key=display_user_group_sort)
1964 return perm_rows
1965
1966 def get_api_data(self, include_secrets=False):
1967 """
1968 Common function for generating repo api data
1969
1970 :param include_secrets: See :meth:`User.get_api_data`.
1971
1972 """
1973 # TODO: mikhail: Here there is an anti-pattern, we probably need to
1974 # move this methods on models level.
1975 from rhodecode.model.settings import SettingsModel
1976 from rhodecode.model.repo import RepoModel
1977
1978 repo = self
1979 _user_id, _time, _reason = self.locked
1980
1981 data = {
1982 'repo_id': repo.repo_id,
1983 'repo_name': repo.repo_name,
1984 'repo_type': repo.repo_type,
1985 'clone_uri': repo.clone_uri or '',
1986 'push_uri': repo.push_uri or '',
1987 'url': RepoModel().get_url(self),
1988 'private': repo.private,
1989 'created_on': repo.created_on,
1990 'description': repo.description_safe,
1991 'landing_rev': repo.landing_rev,
1992 'owner': repo.user.username,
1993 'fork_of': repo.fork.repo_name if repo.fork else None,
1994 'fork_of_id': repo.fork.repo_id if repo.fork else None,
1995 'enable_statistics': repo.enable_statistics,
1996 'enable_locking': repo.enable_locking,
1997 'enable_downloads': repo.enable_downloads,
1998 'last_changeset': repo.changeset_cache,
1999 'locked_by': User.get(_user_id).get_api_data(
2000 include_secrets=include_secrets) if _user_id else None,
2001 'locked_date': time_to_datetime(_time) if _time else None,
2002 'lock_reason': _reason if _reason else None,
2003 }
2004
2005 # TODO: mikhail: should be per-repo settings here
2006 rc_config = SettingsModel().get_all_settings()
2007 repository_fields = str2bool(
2008 rc_config.get('rhodecode_repository_fields'))
2009 if repository_fields:
2010 for f in self.extra_fields:
2011 data[f.field_key_prefixed] = f.field_value
2012
2013 return data
2014
2015 @classmethod
2016 def lock(cls, repo, user_id, lock_time=None, lock_reason=None):
2017 if not lock_time:
2018 lock_time = time.time()
2019 if not lock_reason:
2020 lock_reason = cls.LOCK_AUTOMATIC
2021 repo.locked = [user_id, lock_time, lock_reason]
2022 Session().add(repo)
2023 Session().commit()
2024
2025 @classmethod
2026 def unlock(cls, repo):
2027 repo.locked = None
2028 Session().add(repo)
2029 Session().commit()
2030
2031 @classmethod
2032 def getlock(cls, repo):
2033 return repo.locked
2034
2035 def is_user_lock(self, user_id):
2036 if self.lock[0]:
2037 lock_user_id = safe_int(self.lock[0])
2038 user_id = safe_int(user_id)
2039 # both are ints, and they are equal
2040 return all([lock_user_id, user_id]) and lock_user_id == user_id
2041
2042 return False
2043
2044 def get_locking_state(self, action, user_id, only_when_enabled=True):
2045 """
2046 Checks locking on this repository, if locking is enabled and lock is
2047 present returns a tuple of make_lock, locked, locked_by.
2048 make_lock can have 3 states None (do nothing) True, make lock
2049 False release lock, This value is later propagated to hooks, which
2050 do the locking. Think about this as signals passed to hooks what to do.
2051
2052 """
2053 # TODO: johbo: This is part of the business logic and should be moved
2054 # into the RepositoryModel.
2055
2056 if action not in ('push', 'pull'):
2057 raise ValueError("Invalid action value: %s" % repr(action))
2058
2059 # defines if locked error should be thrown to user
2060 currently_locked = False
2061 # defines if new lock should be made, tri-state
2062 make_lock = None
2063 repo = self
2064 user = User.get(user_id)
2065
2066 lock_info = repo.locked
2067
2068 if repo and (repo.enable_locking or not only_when_enabled):
2069 if action == 'push':
2070 # check if it's already locked !, if it is compare users
2071 locked_by_user_id = lock_info[0]
2072 if user.user_id == locked_by_user_id:
2073 log.debug(
2074 'Got `push` action from user %s, now unlocking', user)
2075 # unlock if we have push from user who locked
2076 make_lock = False
2077 else:
2078 # we're not the same user who locked, ban with
2079 # code defined in settings (default is 423 HTTP Locked) !
2080 log.debug('Repo %s is currently locked by %s', repo, user)
2081 currently_locked = True
2082 elif action == 'pull':
2083 # [0] user [1] date
2084 if lock_info[0] and lock_info[1]:
2085 log.debug('Repo %s is currently locked by %s', repo, user)
2086 currently_locked = True
2087 else:
2088 log.debug('Setting lock on repo %s by %s', repo, user)
2089 make_lock = True
2090
2091 else:
2092 log.debug('Repository %s do not have locking enabled', repo)
2093
2094 log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s',
2095 make_lock, currently_locked, lock_info)
2096
2097 from rhodecode.lib.auth import HasRepoPermissionAny
2098 perm_check = HasRepoPermissionAny('repository.write', 'repository.admin')
2099 if make_lock and not perm_check(repo_name=repo.repo_name, user=user):
2100 # if we don't have at least write permission we cannot make a lock
2101 log.debug('lock state reset back to FALSE due to lack '
2102 'of at least read permission')
2103 make_lock = False
2104
2105 return make_lock, currently_locked, lock_info
2106
2107 @property
2108 def last_db_change(self):
2109 return self.updated_on
2110
2111 @property
2112 def clone_uri_hidden(self):
2113 clone_uri = self.clone_uri
2114 if clone_uri:
2115 import urlobject
2116 url_obj = urlobject.URLObject(cleaned_uri(clone_uri))
2117 if url_obj.password:
2118 clone_uri = url_obj.with_password('*****')
2119 return clone_uri
2120
2121 @property
2122 def push_uri_hidden(self):
2123 push_uri = self.push_uri
2124 if push_uri:
2125 import urlobject
2126 url_obj = urlobject.URLObject(cleaned_uri(push_uri))
2127 if url_obj.password:
2128 push_uri = url_obj.with_password('*****')
2129 return push_uri
2130
2131 def clone_url(self, **override):
2132 from rhodecode.model.settings import SettingsModel
2133
2134 uri_tmpl = None
2135 if 'with_id' in override:
2136 uri_tmpl = self.DEFAULT_CLONE_URI_ID
2137 del override['with_id']
2138
2139 if 'uri_tmpl' in override:
2140 uri_tmpl = override['uri_tmpl']
2141 del override['uri_tmpl']
2142
2143 ssh = False
2144 if 'ssh' in override:
2145 ssh = True
2146 del override['ssh']
2147
2148 # we didn't override our tmpl from **overrides
2149 if not uri_tmpl:
2150 rc_config = SettingsModel().get_all_settings(cache=True)
2151 if ssh:
2152 uri_tmpl = rc_config.get(
2153 'rhodecode_clone_uri_ssh_tmpl') or self.DEFAULT_CLONE_URI_SSH
2154 else:
2155 uri_tmpl = rc_config.get(
2156 'rhodecode_clone_uri_tmpl') or self.DEFAULT_CLONE_URI
2157
2158 request = get_current_request()
2159 return get_clone_url(request=request,
2160 uri_tmpl=uri_tmpl,
2161 repo_name=self.repo_name,
2162 repo_id=self.repo_id, **override)
2163
2164 def set_state(self, state):
2165 self.repo_state = state
2166 Session().add(self)
2167 #==========================================================================
2168 # SCM PROPERTIES
2169 #==========================================================================
2170
2171 def get_commit(self, commit_id=None, commit_idx=None, pre_load=None):
2172 return get_commit_safe(
2173 self.scm_instance(), commit_id, commit_idx, pre_load=pre_load)
2174
2175 def get_changeset(self, rev=None, pre_load=None):
2176 warnings.warn("Use get_commit", DeprecationWarning)
2177 commit_id = None
2178 commit_idx = None
2179 if isinstance(rev, basestring):
2180 commit_id = rev
2181 else:
2182 commit_idx = rev
2183 return self.get_commit(commit_id=commit_id, commit_idx=commit_idx,
2184 pre_load=pre_load)
2185
2186 def get_landing_commit(self):
2187 """
2188 Returns landing commit, or if that doesn't exist returns the tip
2189 """
2190 _rev_type, _rev = self.landing_rev
2191 commit = self.get_commit(_rev)
2192 if isinstance(commit, EmptyCommit):
2193 return self.get_commit()
2194 return commit
2195
2196 def update_commit_cache(self, cs_cache=None, config=None):
2197 """
2198 Update cache of last changeset for repository, keys should be::
2199
2200 short_id
2201 raw_id
2202 revision
2203 parents
2204 message
2205 date
2206 author
2207
2208 :param cs_cache:
2209 """
2210 from rhodecode.lib.vcs.backends.base import BaseChangeset
2211 if cs_cache is None:
2212 # use no-cache version here
2213 scm_repo = self.scm_instance(cache=False, config=config)
2214 if scm_repo:
2215 cs_cache = scm_repo.get_commit(
2216 pre_load=["author", "date", "message", "parents"])
2217 else:
2218 cs_cache = EmptyCommit()
2219
2220 if isinstance(cs_cache, BaseChangeset):
2221 cs_cache = cs_cache.__json__()
2222
2223 def is_outdated(new_cs_cache):
2224 if (new_cs_cache['raw_id'] != self.changeset_cache['raw_id'] or
2225 new_cs_cache['revision'] != self.changeset_cache['revision']):
2226 return True
2227 return False
2228
2229 # check if we have maybe already latest cached revision
2230 if is_outdated(cs_cache) or not self.changeset_cache:
2231 _default = datetime.datetime.fromtimestamp(0)
2232 last_change = cs_cache.get('date') or _default
2233 log.debug('updated repo %s with new cs cache %s',
2234 self.repo_name, cs_cache)
2235 self.updated_on = last_change
2236 self.changeset_cache = cs_cache
2237 Session().add(self)
2238 Session().commit()
2239 else:
2240 log.debug('Skipping update_commit_cache for repo:`%s` '
2241 'commit already with latest changes', self.repo_name)
2242
2243 @property
2244 def tip(self):
2245 return self.get_commit('tip')
2246
2247 @property
2248 def author(self):
2249 return self.tip.author
2250
2251 @property
2252 def last_change(self):
2253 return self.scm_instance().last_change
2254
2255 def get_comments(self, revisions=None):
2256 """
2257 Returns comments for this repository grouped by revisions
2258
2259 :param revisions: filter query by revisions only
2260 """
2261 cmts = ChangesetComment.query()\
2262 .filter(ChangesetComment.repo == self)
2263 if revisions:
2264 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
2265 grouped = collections.defaultdict(list)
2266 for cmt in cmts.all():
2267 grouped[cmt.revision].append(cmt)
2268 return grouped
2269
2270 def statuses(self, revisions=None):
2271 """
2272 Returns statuses for this repository
2273
2274 :param revisions: list of revisions to get statuses for
2275 """
2276 statuses = ChangesetStatus.query()\
2277 .filter(ChangesetStatus.repo == self)\
2278 .filter(ChangesetStatus.version == 0)
2279
2280 if revisions:
2281 # Try doing the filtering in chunks to avoid hitting limits
2282 size = 500
2283 status_results = []
2284 for chunk in xrange(0, len(revisions), size):
2285 status_results += statuses.filter(
2286 ChangesetStatus.revision.in_(
2287 revisions[chunk: chunk+size])
2288 ).all()
2289 else:
2290 status_results = statuses.all()
2291
2292 grouped = {}
2293
2294 # maybe we have open new pullrequest without a status?
2295 stat = ChangesetStatus.STATUS_UNDER_REVIEW
2296 status_lbl = ChangesetStatus.get_status_lbl(stat)
2297 for pr in PullRequest.query().filter(PullRequest.source_repo == self).all():
2298 for rev in pr.revisions:
2299 pr_id = pr.pull_request_id
2300 pr_repo = pr.target_repo.repo_name
2301 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
2302
2303 for stat in status_results:
2304 pr_id = pr_repo = None
2305 if stat.pull_request:
2306 pr_id = stat.pull_request.pull_request_id
2307 pr_repo = stat.pull_request.target_repo.repo_name
2308 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
2309 pr_id, pr_repo]
2310 return grouped
2311
2312 # ==========================================================================
2313 # SCM CACHE INSTANCE
2314 # ==========================================================================
2315
2316 def scm_instance(self, **kwargs):
2317 import rhodecode
2318
2319 # Passing a config will not hit the cache currently only used
2320 # for repo2dbmapper
2321 config = kwargs.pop('config', None)
2322 cache = kwargs.pop('cache', None)
2323 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
2324 # if cache is NOT defined use default global, else we have a full
2325 # control over cache behaviour
2326 if cache is None and full_cache and not config:
2327 return self._get_instance_cached()
2328 return self._get_instance(cache=bool(cache), config=config)
2329
2330 def _get_instance_cached(self):
2331 return self._get_instance()
2332
2333 def _get_instance(self, cache=True, config=None):
2334 config = config or self._config
2335 custom_wire = {
2336 'cache': cache # controls the vcs.remote cache
2337 }
2338 repo = get_vcs_instance(
2339 repo_path=safe_str(self.repo_full_path),
2340 config=config,
2341 with_wire=custom_wire,
2342 create=False,
2343 _vcs_alias=self.repo_type)
2344
2345 return repo
2346
2347 def __json__(self):
2348 return {'landing_rev': self.landing_rev}
2349
2350 def get_dict(self):
2351
2352 # Since we transformed `repo_name` to a hybrid property, we need to
2353 # keep compatibility with the code which uses `repo_name` field.
2354
2355 result = super(Repository, self).get_dict()
2356 result['repo_name'] = result.pop('_repo_name', None)
2357 return result
2358
2359
2360 class RepoGroup(Base, BaseModel):
2361 __tablename__ = 'groups'
2362 __table_args__ = (
2363 UniqueConstraint('group_name', 'group_parent_id'),
2364 CheckConstraint('group_id != group_parent_id'),
2365 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2366 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
2367 )
2368 __mapper_args__ = {'order_by': 'group_name'}
2369
2370 CHOICES_SEPARATOR = '/' # used to generate select2 choices for nested groups
2371
2372 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2373 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
2374 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
2375 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
2376 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
2377 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
2378 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2379 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
2380 personal = Column('personal', Boolean(), nullable=True, unique=None, default=None)
2381
2382 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
2383 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
2384 parent_group = relationship('RepoGroup', remote_side=group_id)
2385 user = relationship('User')
2386 integrations = relationship('Integration',
2387 cascade="all, delete, delete-orphan")
2388
2389 def __init__(self, group_name='', parent_group=None):
2390 self.group_name = group_name
2391 self.parent_group = parent_group
2392
2393 def __unicode__(self):
2394 return u"<%s('id:%s:%s')>" % (
2395 self.__class__.__name__, self.group_id, self.group_name)
2396
2397 @hybrid_property
2398 def description_safe(self):
2399 from rhodecode.lib import helpers as h
2400 return h.escape(self.group_description)
2401
2402 @classmethod
2403 def _generate_choice(cls, repo_group):
2404 from webhelpers.html import literal as _literal
2405 _name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
2406 return repo_group.group_id, _name(repo_group.full_path_splitted)
2407
2408 @classmethod
2409 def groups_choices(cls, groups=None, show_empty_group=True):
2410 if not groups:
2411 groups = cls.query().all()
2412
2413 repo_groups = []
2414 if show_empty_group:
2415 repo_groups = [(-1, u'-- %s --' % _('No parent'))]
2416
2417 repo_groups.extend([cls._generate_choice(x) for x in groups])
2418
2419 repo_groups = sorted(
2420 repo_groups, key=lambda t: t[1].split(cls.CHOICES_SEPARATOR)[0])
2421 return repo_groups
2422
2423 @classmethod
2424 def url_sep(cls):
2425 return URL_SEP
2426
2427 @classmethod
2428 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
2429 if case_insensitive:
2430 gr = cls.query().filter(func.lower(cls.group_name)
2431 == func.lower(group_name))
2432 else:
2433 gr = cls.query().filter(cls.group_name == group_name)
2434 if cache:
2435 name_key = _hash_key(group_name)
2436 gr = gr.options(
2437 FromCache("sql_cache_short", "get_group_%s" % name_key))
2438 return gr.scalar()
2439
2440 @classmethod
2441 def get_user_personal_repo_group(cls, user_id):
2442 user = User.get(user_id)
2443 if user.username == User.DEFAULT_USER:
2444 return None
2445
2446 return cls.query()\
2447 .filter(cls.personal == true()) \
2448 .filter(cls.user == user).scalar()
2449
2450 @classmethod
2451 def get_all_repo_groups(cls, user_id=Optional(None), group_id=Optional(None),
2452 case_insensitive=True):
2453 q = RepoGroup.query()
2454
2455 if not isinstance(user_id, Optional):
2456 q = q.filter(RepoGroup.user_id == user_id)
2457
2458 if not isinstance(group_id, Optional):
2459 q = q.filter(RepoGroup.group_parent_id == group_id)
2460
2461 if case_insensitive:
2462 q = q.order_by(func.lower(RepoGroup.group_name))
2463 else:
2464 q = q.order_by(RepoGroup.group_name)
2465 return q.all()
2466
2467 @property
2468 def parents(self):
2469 parents_recursion_limit = 10
2470 groups = []
2471 if self.parent_group is None:
2472 return groups
2473 cur_gr = self.parent_group
2474 groups.insert(0, cur_gr)
2475 cnt = 0
2476 while 1:
2477 cnt += 1
2478 gr = getattr(cur_gr, 'parent_group', None)
2479 cur_gr = cur_gr.parent_group
2480 if gr is None:
2481 break
2482 if cnt == parents_recursion_limit:
2483 # this will prevent accidental infinit loops
2484 log.error(('more than %s parents found for group %s, stopping '
2485 'recursive parent fetching' % (parents_recursion_limit, self)))
2486 break
2487
2488 groups.insert(0, gr)
2489 return groups
2490
2491 @property
2492 def last_db_change(self):
2493 return self.updated_on
2494
2495 @property
2496 def children(self):
2497 return RepoGroup.query().filter(RepoGroup.parent_group == self)
2498
2499 @property
2500 def name(self):
2501 return self.group_name.split(RepoGroup.url_sep())[-1]
2502
2503 @property
2504 def full_path(self):
2505 return self.group_name
2506
2507 @property
2508 def full_path_splitted(self):
2509 return self.group_name.split(RepoGroup.url_sep())
2510
2511 @property
2512 def repositories(self):
2513 return Repository.query()\
2514 .filter(Repository.group == self)\
2515 .order_by(Repository.repo_name)
2516
2517 @property
2518 def repositories_recursive_count(self):
2519 cnt = self.repositories.count()
2520
2521 def children_count(group):
2522 cnt = 0
2523 for child in group.children:
2524 cnt += child.repositories.count()
2525 cnt += children_count(child)
2526 return cnt
2527
2528 return cnt + children_count(self)
2529
2530 def _recursive_objects(self, include_repos=True):
2531 all_ = []
2532
2533 def _get_members(root_gr):
2534 if include_repos:
2535 for r in root_gr.repositories:
2536 all_.append(r)
2537 childs = root_gr.children.all()
2538 if childs:
2539 for gr in childs:
2540 all_.append(gr)
2541 _get_members(gr)
2542
2543 _get_members(self)
2544 return [self] + all_
2545
2546 def recursive_groups_and_repos(self):
2547 """
2548 Recursive return all groups, with repositories in those groups
2549 """
2550 return self._recursive_objects()
2551
2552 def recursive_groups(self):
2553 """
2554 Returns all children groups for this group including children of children
2555 """
2556 return self._recursive_objects(include_repos=False)
2557
2558 def get_new_name(self, group_name):
2559 """
2560 returns new full group name based on parent and new name
2561
2562 :param group_name:
2563 """
2564 path_prefix = (self.parent_group.full_path_splitted if
2565 self.parent_group else [])
2566 return RepoGroup.url_sep().join(path_prefix + [group_name])
2567
2568 def permissions(self, with_admins=True, with_owner=True):
2569 q = UserRepoGroupToPerm.query().filter(UserRepoGroupToPerm.group == self)
2570 q = q.options(joinedload(UserRepoGroupToPerm.group),
2571 joinedload(UserRepoGroupToPerm.user),
2572 joinedload(UserRepoGroupToPerm.permission),)
2573
2574 # get owners and admins and permissions. We do a trick of re-writing
2575 # objects from sqlalchemy to named-tuples due to sqlalchemy session
2576 # has a global reference and changing one object propagates to all
2577 # others. This means if admin is also an owner admin_row that change
2578 # would propagate to both objects
2579 perm_rows = []
2580 for _usr in q.all():
2581 usr = AttributeDict(_usr.user.get_dict())
2582 usr.permission = _usr.permission.permission_name
2583 perm_rows.append(usr)
2584
2585 # filter the perm rows by 'default' first and then sort them by
2586 # admin,write,read,none permissions sorted again alphabetically in
2587 # each group
2588 perm_rows = sorted(perm_rows, key=display_user_sort)
2589
2590 _admin_perm = 'group.admin'
2591 owner_row = []
2592 if with_owner:
2593 usr = AttributeDict(self.user.get_dict())
2594 usr.owner_row = True
2595 usr.permission = _admin_perm
2596 owner_row.append(usr)
2597
2598 super_admin_rows = []
2599 if with_admins:
2600 for usr in User.get_all_super_admins():
2601 # if this admin is also owner, don't double the record
2602 if usr.user_id == owner_row[0].user_id:
2603 owner_row[0].admin_row = True
2604 else:
2605 usr = AttributeDict(usr.get_dict())
2606 usr.admin_row = True
2607 usr.permission = _admin_perm
2608 super_admin_rows.append(usr)
2609
2610 return super_admin_rows + owner_row + perm_rows
2611
2612 def permission_user_groups(self):
2613 q = UserGroupRepoGroupToPerm.query().filter(UserGroupRepoGroupToPerm.group == self)
2614 q = q.options(joinedload(UserGroupRepoGroupToPerm.group),
2615 joinedload(UserGroupRepoGroupToPerm.users_group),
2616 joinedload(UserGroupRepoGroupToPerm.permission),)
2617
2618 perm_rows = []
2619 for _user_group in q.all():
2620 usr = AttributeDict(_user_group.users_group.get_dict())
2621 usr.permission = _user_group.permission.permission_name
2622 perm_rows.append(usr)
2623
2624 perm_rows = sorted(perm_rows, key=display_user_group_sort)
2625 return perm_rows
2626
2627 def get_api_data(self):
2628 """
2629 Common function for generating api data
2630
2631 """
2632 group = self
2633 data = {
2634 'group_id': group.group_id,
2635 'group_name': group.group_name,
2636 'group_description': group.description_safe,
2637 'parent_group': group.parent_group.group_name if group.parent_group else None,
2638 'repositories': [x.repo_name for x in group.repositories],
2639 'owner': group.user.username,
2640 }
2641 return data
2642
2643
2644 class Permission(Base, BaseModel):
2645 __tablename__ = 'permissions'
2646 __table_args__ = (
2647 Index('p_perm_name_idx', 'permission_name'),
2648 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2649 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
2650 )
2651 PERMS = [
2652 ('hg.admin', _('RhodeCode Super Administrator')),
2653
2654 ('repository.none', _('Repository no access')),
2655 ('repository.read', _('Repository read access')),
2656 ('repository.write', _('Repository write access')),
2657 ('repository.admin', _('Repository admin access')),
2658
2659 ('group.none', _('Repository group no access')),
2660 ('group.read', _('Repository group read access')),
2661 ('group.write', _('Repository group write access')),
2662 ('group.admin', _('Repository group admin access')),
2663
2664 ('usergroup.none', _('User group no access')),
2665 ('usergroup.read', _('User group read access')),
2666 ('usergroup.write', _('User group write access')),
2667 ('usergroup.admin', _('User group admin access')),
2668
2669 ('branch.none', _('Branch no permissions')),
2670 ('branch.merge', _('Branch access by web merge')),
2671 ('branch.push', _('Branch access by push')),
2672 ('branch.push_force', _('Branch access by push with force')),
2673
2674 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
2675 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
2676
2677 ('hg.usergroup.create.false', _('User Group creation disabled')),
2678 ('hg.usergroup.create.true', _('User Group creation enabled')),
2679
2680 ('hg.create.none', _('Repository creation disabled')),
2681 ('hg.create.repository', _('Repository creation enabled')),
2682 ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')),
2683 ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')),
2684
2685 ('hg.fork.none', _('Repository forking disabled')),
2686 ('hg.fork.repository', _('Repository forking enabled')),
2687
2688 ('hg.register.none', _('Registration disabled')),
2689 ('hg.register.manual_activate', _('User Registration with manual account activation')),
2690 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
2691
2692 ('hg.password_reset.enabled', _('Password reset enabled')),
2693 ('hg.password_reset.hidden', _('Password reset hidden')),
2694 ('hg.password_reset.disabled', _('Password reset disabled')),
2695
2696 ('hg.extern_activate.manual', _('Manual activation of external account')),
2697 ('hg.extern_activate.auto', _('Automatic activation of external account')),
2698
2699 ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')),
2700 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
2701 ]
2702
2703 # definition of system default permissions for DEFAULT user, created on
2704 # system setup
2705 DEFAULT_USER_PERMISSIONS = [
2706 # object perms
2707 'repository.read',
2708 'group.read',
2709 'usergroup.read',
2710 # branch
2711 'branch.push',
2712 # global
2713 'hg.create.repository',
2714 'hg.repogroup.create.false',
2715 'hg.usergroup.create.false',
2716 'hg.create.write_on_repogroup.true',
2717 'hg.fork.repository',
2718 'hg.register.manual_activate',
2719 'hg.password_reset.enabled',
2720 'hg.extern_activate.auto',
2721 'hg.inherit_default_perms.true',
2722 ]
2723
2724 # defines which permissions are more important higher the more important
2725 # Weight defines which permissions are more important.
2726 # The higher number the more important.
2727 PERM_WEIGHTS = {
2728 'repository.none': 0,
2729 'repository.read': 1,
2730 'repository.write': 3,
2731 'repository.admin': 4,
2732
2733 'group.none': 0,
2734 'group.read': 1,
2735 'group.write': 3,
2736 'group.admin': 4,
2737
2738 'usergroup.none': 0,
2739 'usergroup.read': 1,
2740 'usergroup.write': 3,
2741 'usergroup.admin': 4,
2742
2743 'branch.none': 0,
2744 'branch.merge': 1,
2745 'branch.push': 3,
2746 'branch.push_force': 4,
2747
2748 'hg.repogroup.create.false': 0,
2749 'hg.repogroup.create.true': 1,
2750
2751 'hg.usergroup.create.false': 0,
2752 'hg.usergroup.create.true': 1,
2753
2754 'hg.fork.none': 0,
2755 'hg.fork.repository': 1,
2756 'hg.create.none': 0,
2757 'hg.create.repository': 1
2758 }
2759
2760 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2761 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
2762 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
2763
2764 def __unicode__(self):
2765 return u"<%s('%s:%s')>" % (
2766 self.__class__.__name__, self.permission_id, self.permission_name
2767 )
2768
2769 @classmethod
2770 def get_by_key(cls, key):
2771 return cls.query().filter(cls.permission_name == key).scalar()
2772
2773 @classmethod
2774 def get_default_repo_perms(cls, user_id, repo_id=None):
2775 q = Session().query(UserRepoToPerm, Repository, Permission)\
2776 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
2777 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
2778 .filter(UserRepoToPerm.user_id == user_id)
2779 if repo_id:
2780 q = q.filter(UserRepoToPerm.repository_id == repo_id)
2781 return q.all()
2782
2783 @classmethod
2784 def get_default_repo_perms_from_user_group(cls, user_id, repo_id=None):
2785 q = Session().query(UserGroupRepoToPerm, Repository, Permission)\
2786 .join(
2787 Permission,
2788 UserGroupRepoToPerm.permission_id == Permission.permission_id)\
2789 .join(
2790 Repository,
2791 UserGroupRepoToPerm.repository_id == Repository.repo_id)\
2792 .join(
2793 UserGroup,
2794 UserGroupRepoToPerm.users_group_id ==
2795 UserGroup.users_group_id)\
2796 .join(
2797 UserGroupMember,
2798 UserGroupRepoToPerm.users_group_id ==
2799 UserGroupMember.users_group_id)\
2800 .filter(
2801 UserGroupMember.user_id == user_id,
2802 UserGroup.users_group_active == true())
2803 if repo_id:
2804 q = q.filter(UserGroupRepoToPerm.repository_id == repo_id)
2805 return q.all()
2806
2807 @classmethod
2808 def get_default_group_perms(cls, user_id, repo_group_id=None):
2809 q = Session().query(UserRepoGroupToPerm, RepoGroup, Permission)\
2810 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
2811 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
2812 .filter(UserRepoGroupToPerm.user_id == user_id)
2813 if repo_group_id:
2814 q = q.filter(UserRepoGroupToPerm.group_id == repo_group_id)
2815 return q.all()
2816
2817 @classmethod
2818 def get_default_group_perms_from_user_group(
2819 cls, user_id, repo_group_id=None):
2820 q = Session().query(UserGroupRepoGroupToPerm, RepoGroup, Permission)\
2821 .join(
2822 Permission,
2823 UserGroupRepoGroupToPerm.permission_id ==
2824 Permission.permission_id)\
2825 .join(
2826 RepoGroup,
2827 UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id)\
2828 .join(
2829 UserGroup,
2830 UserGroupRepoGroupToPerm.users_group_id ==
2831 UserGroup.users_group_id)\
2832 .join(
2833 UserGroupMember,
2834 UserGroupRepoGroupToPerm.users_group_id ==
2835 UserGroupMember.users_group_id)\
2836 .filter(
2837 UserGroupMember.user_id == user_id,
2838 UserGroup.users_group_active == true())
2839 if repo_group_id:
2840 q = q.filter(UserGroupRepoGroupToPerm.group_id == repo_group_id)
2841 return q.all()
2842
2843 @classmethod
2844 def get_default_user_group_perms(cls, user_id, user_group_id=None):
2845 q = Session().query(UserUserGroupToPerm, UserGroup, Permission)\
2846 .join((Permission, UserUserGroupToPerm.permission_id == Permission.permission_id))\
2847 .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
2848 .filter(UserUserGroupToPerm.user_id == user_id)
2849 if user_group_id:
2850 q = q.filter(UserUserGroupToPerm.user_group_id == user_group_id)
2851 return q.all()
2852
2853 @classmethod
2854 def get_default_user_group_perms_from_user_group(
2855 cls, user_id, user_group_id=None):
2856 TargetUserGroup = aliased(UserGroup, name='target_user_group')
2857 q = Session().query(UserGroupUserGroupToPerm, UserGroup, Permission)\
2858 .join(
2859 Permission,
2860 UserGroupUserGroupToPerm.permission_id ==
2861 Permission.permission_id)\
2862 .join(
2863 TargetUserGroup,
2864 UserGroupUserGroupToPerm.target_user_group_id ==
2865 TargetUserGroup.users_group_id)\
2866 .join(
2867 UserGroup,
2868 UserGroupUserGroupToPerm.user_group_id ==
2869 UserGroup.users_group_id)\
2870 .join(
2871 UserGroupMember,
2872 UserGroupUserGroupToPerm.user_group_id ==
2873 UserGroupMember.users_group_id)\
2874 .filter(
2875 UserGroupMember.user_id == user_id,
2876 UserGroup.users_group_active == true())
2877 if user_group_id:
2878 q = q.filter(
2879 UserGroupUserGroupToPerm.user_group_id == user_group_id)
2880
2881 return q.all()
2882
2883
2884 class UserRepoToPerm(Base, BaseModel):
2885 __tablename__ = 'repo_to_perm'
2886 __table_args__ = (
2887 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
2888 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2889 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
2890 )
2891 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2892 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
2893 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
2894 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
2895
2896 user = relationship('User')
2897 repository = relationship('Repository')
2898 permission = relationship('Permission')
2899
2900 branch_perm_entry = relationship('UserToRepoBranchPermission', cascade="all, delete, delete-orphan", lazy='joined')
2901
2902 @classmethod
2903 def create(cls, user, repository, permission):
2904 n = cls()
2905 n.user = user
2906 n.repository = repository
2907 n.permission = permission
2908 Session().add(n)
2909 return n
2910
2911 def __unicode__(self):
2912 return u'<%s => %s >' % (self.user, self.repository)
2913
2914
2915 class UserUserGroupToPerm(Base, BaseModel):
2916 __tablename__ = 'user_user_group_to_perm'
2917 __table_args__ = (
2918 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
2919 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2920 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
2921 )
2922 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2923 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
2924 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
2925 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
2926
2927 user = relationship('User')
2928 user_group = relationship('UserGroup')
2929 permission = relationship('Permission')
2930
2931 @classmethod
2932 def create(cls, user, user_group, permission):
2933 n = cls()
2934 n.user = user
2935 n.user_group = user_group
2936 n.permission = permission
2937 Session().add(n)
2938 return n
2939
2940 def __unicode__(self):
2941 return u'<%s => %s >' % (self.user, self.user_group)
2942
2943
2944 class UserToPerm(Base, BaseModel):
2945 __tablename__ = 'user_to_perm'
2946 __table_args__ = (
2947 UniqueConstraint('user_id', 'permission_id'),
2948 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2949 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
2950 )
2951 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2952 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
2953 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
2954
2955 user = relationship('User')
2956 permission = relationship('Permission', lazy='joined')
2957
2958 def __unicode__(self):
2959 return u'<%s => %s >' % (self.user, self.permission)
2960
2961
2962 class UserGroupRepoToPerm(Base, BaseModel):
2963 __tablename__ = 'users_group_repo_to_perm'
2964 __table_args__ = (
2965 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
2966 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2967 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
2968 )
2969 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2970 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
2971 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
2972 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
2973
2974 users_group = relationship('UserGroup')
2975 permission = relationship('Permission')
2976 repository = relationship('Repository')
2977
2978 @classmethod
2979 def create(cls, users_group, repository, permission):
2980 n = cls()
2981 n.users_group = users_group
2982 n.repository = repository
2983 n.permission = permission
2984 Session().add(n)
2985 return n
2986
2987 def __unicode__(self):
2988 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
2989
2990
2991 class UserGroupUserGroupToPerm(Base, BaseModel):
2992 __tablename__ = 'user_group_user_group_to_perm'
2993 __table_args__ = (
2994 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
2995 CheckConstraint('target_user_group_id != user_group_id'),
2996 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2997 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
2998 )
2999 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3000 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3001 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3002 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3003
3004 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
3005 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
3006 permission = relationship('Permission')
3007
3008 @classmethod
3009 def create(cls, target_user_group, user_group, permission):
3010 n = cls()
3011 n.target_user_group = target_user_group
3012 n.user_group = user_group
3013 n.permission = permission
3014 Session().add(n)
3015 return n
3016
3017 def __unicode__(self):
3018 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
3019
3020
3021 class UserGroupToPerm(Base, BaseModel):
3022 __tablename__ = 'users_group_to_perm'
3023 __table_args__ = (
3024 UniqueConstraint('users_group_id', 'permission_id',),
3025 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3026 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3027 )
3028 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3029 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3030 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3031
3032 users_group = relationship('UserGroup')
3033 permission = relationship('Permission')
3034
3035
3036 class UserRepoGroupToPerm(Base, BaseModel):
3037 __tablename__ = 'user_repo_group_to_perm'
3038 __table_args__ = (
3039 UniqueConstraint('user_id', 'group_id', 'permission_id'),
3040 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3041 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3042 )
3043
3044 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3045 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3046 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3047 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3048
3049 user = relationship('User')
3050 group = relationship('RepoGroup')
3051 permission = relationship('Permission')
3052
3053 @classmethod
3054 def create(cls, user, repository_group, permission):
3055 n = cls()
3056 n.user = user
3057 n.group = repository_group
3058 n.permission = permission
3059 Session().add(n)
3060 return n
3061
3062
3063 class UserGroupRepoGroupToPerm(Base, BaseModel):
3064 __tablename__ = 'users_group_repo_group_to_perm'
3065 __table_args__ = (
3066 UniqueConstraint('users_group_id', 'group_id'),
3067 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3068 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3069 )
3070
3071 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3072 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3073 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3074 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3075
3076 users_group = relationship('UserGroup')
3077 permission = relationship('Permission')
3078 group = relationship('RepoGroup')
3079
3080 @classmethod
3081 def create(cls, user_group, repository_group, permission):
3082 n = cls()
3083 n.users_group = user_group
3084 n.group = repository_group
3085 n.permission = permission
3086 Session().add(n)
3087 return n
3088
3089 def __unicode__(self):
3090 return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group)
3091
3092
3093 class Statistics(Base, BaseModel):
3094 __tablename__ = 'statistics'
3095 __table_args__ = (
3096 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3097 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3098 )
3099 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3100 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
3101 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
3102 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
3103 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
3104 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
3105
3106 repository = relationship('Repository', single_parent=True)
3107
3108
3109 class UserFollowing(Base, BaseModel):
3110 __tablename__ = 'user_followings'
3111 __table_args__ = (
3112 UniqueConstraint('user_id', 'follows_repository_id'),
3113 UniqueConstraint('user_id', 'follows_user_id'),
3114 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3115 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3116 )
3117
3118 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3119 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3120 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
3121 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
3122 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
3123
3124 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
3125
3126 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
3127 follows_repository = relationship('Repository', order_by='Repository.repo_name')
3128
3129 @classmethod
3130 def get_repo_followers(cls, repo_id):
3131 return cls.query().filter(cls.follows_repo_id == repo_id)
3132
3133
3134 class CacheKey(Base, BaseModel):
3135 __tablename__ = 'cache_invalidation'
3136 __table_args__ = (
3137 UniqueConstraint('cache_key'),
3138 Index('key_idx', 'cache_key'),
3139 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3140 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3141 )
3142 CACHE_TYPE_ATOM = 'ATOM'
3143 CACHE_TYPE_RSS = 'RSS'
3144 CACHE_TYPE_README = 'README'
3145
3146 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3147 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
3148 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
3149 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
3150
3151 def __init__(self, cache_key, cache_args=''):
3152 self.cache_key = cache_key
3153 self.cache_args = cache_args
3154 self.cache_active = False
3155
3156 def __unicode__(self):
3157 return u"<%s('%s:%s[%s]')>" % (
3158 self.__class__.__name__,
3159 self.cache_id, self.cache_key, self.cache_active)
3160
3161 def _cache_key_partition(self):
3162 prefix, repo_name, suffix = self.cache_key.partition(self.cache_args)
3163 return prefix, repo_name, suffix
3164
3165 def get_prefix(self):
3166 """
3167 Try to extract prefix from existing cache key. The key could consist
3168 of prefix, repo_name, suffix
3169 """
3170 # this returns prefix, repo_name, suffix
3171 return self._cache_key_partition()[0]
3172
3173 def get_suffix(self):
3174 """
3175 get suffix that might have been used in _get_cache_key to
3176 generate self.cache_key. Only used for informational purposes
3177 in repo_edit.mako.
3178 """
3179 # prefix, repo_name, suffix
3180 return self._cache_key_partition()[2]
3181
3182 @classmethod
3183 def delete_all_cache(cls):
3184 """
3185 Delete all cache keys from database.
3186 Should only be run when all instances are down and all entries
3187 thus stale.
3188 """
3189 cls.query().delete()
3190 Session().commit()
3191
3192 @classmethod
3193 def get_cache_key(cls, repo_name, cache_type):
3194 """
3195
3196 Generate a cache key for this process of RhodeCode instance.
3197 Prefix most likely will be process id or maybe explicitly set
3198 instance_id from .ini file.
3199 """
3200 import rhodecode
3201 prefix = safe_unicode(rhodecode.CONFIG.get('instance_id') or '')
3202
3203 repo_as_unicode = safe_unicode(repo_name)
3204 key = u'{}_{}'.format(repo_as_unicode, cache_type) \
3205 if cache_type else repo_as_unicode
3206
3207 return u'{}{}'.format(prefix, key)
3208
3209 @classmethod
3210 def set_invalidate(cls, repo_name, delete=False):
3211 """
3212 Mark all caches of a repo as invalid in the database.
3213 """
3214
3215 try:
3216 qry = Session().query(cls).filter(cls.cache_args == repo_name)
3217 if delete:
3218 log.debug('cache objects deleted for repo %s',
3219 safe_str(repo_name))
3220 qry.delete()
3221 else:
3222 log.debug('cache objects marked as invalid for repo %s',
3223 safe_str(repo_name))
3224 qry.update({"cache_active": False})
3225
3226 Session().commit()
3227 except Exception:
3228 log.exception(
3229 'Cache key invalidation failed for repository %s',
3230 safe_str(repo_name))
3231 Session().rollback()
3232
3233 @classmethod
3234 def get_active_cache(cls, cache_key):
3235 inv_obj = cls.query().filter(cls.cache_key == cache_key).scalar()
3236 if inv_obj:
3237 return inv_obj
3238 return None
3239
3240
3241 class ChangesetComment(Base, BaseModel):
3242 __tablename__ = 'changeset_comments'
3243 __table_args__ = (
3244 Index('cc_revision_idx', 'revision'),
3245 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3246 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3247 )
3248
3249 COMMENT_OUTDATED = u'comment_outdated'
3250 COMMENT_TYPE_NOTE = u'note'
3251 COMMENT_TYPE_TODO = u'todo'
3252 COMMENT_TYPES = [COMMENT_TYPE_NOTE, COMMENT_TYPE_TODO]
3253
3254 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
3255 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
3256 revision = Column('revision', String(40), nullable=True)
3257 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
3258 pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True)
3259 line_no = Column('line_no', Unicode(10), nullable=True)
3260 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
3261 f_path = Column('f_path', Unicode(1000), nullable=True)
3262 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
3263 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
3264 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
3265 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
3266 renderer = Column('renderer', Unicode(64), nullable=True)
3267 display_state = Column('display_state', Unicode(128), nullable=True)
3268
3269 comment_type = Column('comment_type', Unicode(128), nullable=True, default=COMMENT_TYPE_NOTE)
3270 resolved_comment_id = Column('resolved_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'), nullable=True)
3271 resolved_comment = relationship('ChangesetComment', remote_side=comment_id, backref='resolved_by')
3272 author = relationship('User', lazy='joined')
3273 repo = relationship('Repository')
3274 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan", lazy='joined')
3275 pull_request = relationship('PullRequest', lazy='joined')
3276 pull_request_version = relationship('PullRequestVersion')
3277
3278 @classmethod
3279 def get_users(cls, revision=None, pull_request_id=None):
3280 """
3281 Returns user associated with this ChangesetComment. ie those
3282 who actually commented
3283
3284 :param cls:
3285 :param revision:
3286 """
3287 q = Session().query(User)\
3288 .join(ChangesetComment.author)
3289 if revision:
3290 q = q.filter(cls.revision == revision)
3291 elif pull_request_id:
3292 q = q.filter(cls.pull_request_id == pull_request_id)
3293 return q.all()
3294
3295 @classmethod
3296 def get_index_from_version(cls, pr_version, versions):
3297 num_versions = [x.pull_request_version_id for x in versions]
3298 try:
3299 return num_versions.index(pr_version) +1
3300 except (IndexError, ValueError):
3301 return
3302
3303 @property
3304 def outdated(self):
3305 return self.display_state == self.COMMENT_OUTDATED
3306
3307 def outdated_at_version(self, version):
3308 """
3309 Checks if comment is outdated for given pull request version
3310 """
3311 return self.outdated and self.pull_request_version_id != version
3312
3313 def older_than_version(self, version):
3314 """
3315 Checks if comment is made from previous version than given
3316 """
3317 if version is None:
3318 return self.pull_request_version_id is not None
3319
3320 return self.pull_request_version_id < version
3321
3322 @property
3323 def resolved(self):
3324 return self.resolved_by[0] if self.resolved_by else None
3325
3326 @property
3327 def is_todo(self):
3328 return self.comment_type == self.COMMENT_TYPE_TODO
3329
3330 @property
3331 def is_inline(self):
3332 return self.line_no and self.f_path
3333
3334 def get_index_version(self, versions):
3335 return self.get_index_from_version(
3336 self.pull_request_version_id, versions)
3337
3338 def __repr__(self):
3339 if self.comment_id:
3340 return '<DB:Comment #%s>' % self.comment_id
3341 else:
3342 return '<DB:Comment at %#x>' % id(self)
3343
3344 def get_api_data(self):
3345 comment = self
3346 data = {
3347 'comment_id': comment.comment_id,
3348 'comment_type': comment.comment_type,
3349 'comment_text': comment.text,
3350 'comment_status': comment.status_change,
3351 'comment_f_path': comment.f_path,
3352 'comment_lineno': comment.line_no,
3353 'comment_author': comment.author,
3354 'comment_created_on': comment.created_on
3355 }
3356 return data
3357
3358 def __json__(self):
3359 data = dict()
3360 data.update(self.get_api_data())
3361 return data
3362
3363
3364 class ChangesetStatus(Base, BaseModel):
3365 __tablename__ = 'changeset_statuses'
3366 __table_args__ = (
3367 Index('cs_revision_idx', 'revision'),
3368 Index('cs_version_idx', 'version'),
3369 UniqueConstraint('repo_id', 'revision', 'version'),
3370 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3371 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3372 )
3373 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
3374 STATUS_APPROVED = 'approved'
3375 STATUS_REJECTED = 'rejected'
3376 STATUS_UNDER_REVIEW = 'under_review'
3377
3378 STATUSES = [
3379 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
3380 (STATUS_APPROVED, _("Approved")),
3381 (STATUS_REJECTED, _("Rejected")),
3382 (STATUS_UNDER_REVIEW, _("Under Review")),
3383 ]
3384
3385 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
3386 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
3387 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
3388 revision = Column('revision', String(40), nullable=False)
3389 status = Column('status', String(128), nullable=False, default=DEFAULT)
3390 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
3391 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
3392 version = Column('version', Integer(), nullable=False, default=0)
3393 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
3394
3395 author = relationship('User', lazy='joined')
3396 repo = relationship('Repository')
3397 comment = relationship('ChangesetComment', lazy='joined')
3398 pull_request = relationship('PullRequest', lazy='joined')
3399
3400 def __unicode__(self):
3401 return u"<%s('%s[v%s]:%s')>" % (
3402 self.__class__.__name__,
3403 self.status, self.version, self.author
3404 )
3405
3406 @classmethod
3407 def get_status_lbl(cls, value):
3408 return dict(cls.STATUSES).get(value)
3409
3410 @property
3411 def status_lbl(self):
3412 return ChangesetStatus.get_status_lbl(self.status)
3413
3414 def get_api_data(self):
3415 status = self
3416 data = {
3417 'status_id': status.changeset_status_id,
3418 'status': status.status,
3419 }
3420 return data
3421
3422 def __json__(self):
3423 data = dict()
3424 data.update(self.get_api_data())
3425 return data
3426
3427
3428 class _PullRequestBase(BaseModel):
3429 """
3430 Common attributes of pull request and version entries.
3431 """
3432
3433 # .status values
3434 STATUS_NEW = u'new'
3435 STATUS_OPEN = u'open'
3436 STATUS_CLOSED = u'closed'
3437
3438 title = Column('title', Unicode(255), nullable=True)
3439 description = Column(
3440 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'),
3441 nullable=True)
3442 # new/open/closed status of pull request (not approve/reject/etc)
3443 status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW)
3444 created_on = Column(
3445 'created_on', DateTime(timezone=False), nullable=False,
3446 default=datetime.datetime.now)
3447 updated_on = Column(
3448 'updated_on', DateTime(timezone=False), nullable=False,
3449 default=datetime.datetime.now)
3450
3451 @declared_attr
3452 def user_id(cls):
3453 return Column(
3454 "user_id", Integer(), ForeignKey('users.user_id'), nullable=False,
3455 unique=None)
3456
3457 # 500 revisions max
3458 _revisions = Column(
3459 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
3460
3461 @declared_attr
3462 def source_repo_id(cls):
3463 # TODO: dan: rename column to source_repo_id
3464 return Column(
3465 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'),
3466 nullable=False)
3467
3468 source_ref = Column('org_ref', Unicode(255), nullable=False)
3469
3470 @declared_attr
3471 def target_repo_id(cls):
3472 # TODO: dan: rename column to target_repo_id
3473 return Column(
3474 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'),
3475 nullable=False)
3476
3477 target_ref = Column('other_ref', Unicode(255), nullable=False)
3478 _shadow_merge_ref = Column('shadow_merge_ref', Unicode(255), nullable=True)
3479
3480 # TODO: dan: rename column to last_merge_source_rev
3481 _last_merge_source_rev = Column(
3482 'last_merge_org_rev', String(40), nullable=True)
3483 # TODO: dan: rename column to last_merge_target_rev
3484 _last_merge_target_rev = Column(
3485 'last_merge_other_rev', String(40), nullable=True)
3486 _last_merge_status = Column('merge_status', Integer(), nullable=True)
3487 merge_rev = Column('merge_rev', String(40), nullable=True)
3488
3489 reviewer_data = Column(
3490 'reviewer_data_json', MutationObj.as_mutable(
3491 JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
3492
3493 @property
3494 def reviewer_data_json(self):
3495 return json.dumps(self.reviewer_data)
3496
3497 @hybrid_property
3498 def description_safe(self):
3499 from rhodecode.lib import helpers as h
3500 return h.escape(self.description)
3501
3502 @hybrid_property
3503 def revisions(self):
3504 return self._revisions.split(':') if self._revisions else []
3505
3506 @revisions.setter
3507 def revisions(self, val):
3508 self._revisions = ':'.join(val)
3509
3510 @hybrid_property
3511 def last_merge_status(self):
3512 return safe_int(self._last_merge_status)
3513
3514 @last_merge_status.setter
3515 def last_merge_status(self, val):
3516 self._last_merge_status = val
3517
3518 @declared_attr
3519 def author(cls):
3520 return relationship('User', lazy='joined')
3521
3522 @declared_attr
3523 def source_repo(cls):
3524 return relationship(
3525 'Repository',
3526 primaryjoin='%s.source_repo_id==Repository.repo_id' % cls.__name__)
3527
3528 @property
3529 def source_ref_parts(self):
3530 return self.unicode_to_reference(self.source_ref)
3531
3532 @declared_attr
3533 def target_repo(cls):
3534 return relationship(
3535 'Repository',
3536 primaryjoin='%s.target_repo_id==Repository.repo_id' % cls.__name__)
3537
3538 @property
3539 def target_ref_parts(self):
3540 return self.unicode_to_reference(self.target_ref)
3541
3542 @property
3543 def shadow_merge_ref(self):
3544 return self.unicode_to_reference(self._shadow_merge_ref)
3545
3546 @shadow_merge_ref.setter
3547 def shadow_merge_ref(self, ref):
3548 self._shadow_merge_ref = self.reference_to_unicode(ref)
3549
3550 def unicode_to_reference(self, raw):
3551 """
3552 Convert a unicode (or string) to a reference object.
3553 If unicode evaluates to False it returns None.
3554 """
3555 if raw:
3556 refs = raw.split(':')
3557 return Reference(*refs)
3558 else:
3559 return None
3560
3561 def reference_to_unicode(self, ref):
3562 """
3563 Convert a reference object to unicode.
3564 If reference is None it returns None.
3565 """
3566 if ref:
3567 return u':'.join(ref)
3568 else:
3569 return None
3570
3571 def get_api_data(self, with_merge_state=True):
3572 from rhodecode.model.pull_request import PullRequestModel
3573
3574 pull_request = self
3575 if with_merge_state:
3576 merge_status = PullRequestModel().merge_status(pull_request)
3577 merge_state = {
3578 'status': merge_status[0],
3579 'message': safe_unicode(merge_status[1]),
3580 }
3581 else:
3582 merge_state = {'status': 'not_available',
3583 'message': 'not_available'}
3584
3585 merge_data = {
3586 'clone_url': PullRequestModel().get_shadow_clone_url(pull_request),
3587 'reference': (
3588 pull_request.shadow_merge_ref._asdict()
3589 if pull_request.shadow_merge_ref else None),
3590 }
3591
3592 data = {
3593 'pull_request_id': pull_request.pull_request_id,
3594 'url': PullRequestModel().get_url(pull_request),
3595 'title': pull_request.title,
3596 'description': pull_request.description,
3597 'status': pull_request.status,
3598 'created_on': pull_request.created_on,
3599 'updated_on': pull_request.updated_on,
3600 'commit_ids': pull_request.revisions,
3601 'review_status': pull_request.calculated_review_status(),
3602 'mergeable': merge_state,
3603 'source': {
3604 'clone_url': pull_request.source_repo.clone_url(),
3605 'repository': pull_request.source_repo.repo_name,
3606 'reference': {
3607 'name': pull_request.source_ref_parts.name,
3608 'type': pull_request.source_ref_parts.type,
3609 'commit_id': pull_request.source_ref_parts.commit_id,
3610 },
3611 },
3612 'target': {
3613 'clone_url': pull_request.target_repo.clone_url(),
3614 'repository': pull_request.target_repo.repo_name,
3615 'reference': {
3616 'name': pull_request.target_ref_parts.name,
3617 'type': pull_request.target_ref_parts.type,
3618 'commit_id': pull_request.target_ref_parts.commit_id,
3619 },
3620 },
3621 'merge': merge_data,
3622 'author': pull_request.author.get_api_data(include_secrets=False,
3623 details='basic'),
3624 'reviewers': [
3625 {
3626 'user': reviewer.get_api_data(include_secrets=False,
3627 details='basic'),
3628 'reasons': reasons,
3629 'review_status': st[0][1].status if st else 'not_reviewed',
3630 }
3631 for obj, reviewer, reasons, mandatory, st in
3632 pull_request.reviewers_statuses()
3633 ]
3634 }
3635
3636 return data
3637
3638
3639 class PullRequest(Base, _PullRequestBase):
3640 __tablename__ = 'pull_requests'
3641 __table_args__ = (
3642 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3643 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3644 )
3645
3646 pull_request_id = Column(
3647 'pull_request_id', Integer(), nullable=False, primary_key=True)
3648
3649 def __repr__(self):
3650 if self.pull_request_id:
3651 return '<DB:PullRequest #%s>' % self.pull_request_id
3652 else:
3653 return '<DB:PullRequest at %#x>' % id(self)
3654
3655 reviewers = relationship('PullRequestReviewers',
3656 cascade="all, delete, delete-orphan")
3657 statuses = relationship('ChangesetStatus',
3658 cascade="all, delete, delete-orphan")
3659 comments = relationship('ChangesetComment',
3660 cascade="all, delete, delete-orphan")
3661 versions = relationship('PullRequestVersion',
3662 cascade="all, delete, delete-orphan",
3663 lazy='dynamic')
3664
3665 @classmethod
3666 def get_pr_display_object(cls, pull_request_obj, org_pull_request_obj,
3667 internal_methods=None):
3668
3669 class PullRequestDisplay(object):
3670 """
3671 Special object wrapper for showing PullRequest data via Versions
3672 It mimics PR object as close as possible. This is read only object
3673 just for display
3674 """
3675
3676 def __init__(self, attrs, internal=None):
3677 self.attrs = attrs
3678 # internal have priority over the given ones via attrs
3679 self.internal = internal or ['versions']
3680
3681 def __getattr__(self, item):
3682 if item in self.internal:
3683 return getattr(self, item)
3684 try:
3685 return self.attrs[item]
3686 except KeyError:
3687 raise AttributeError(
3688 '%s object has no attribute %s' % (self, item))
3689
3690 def __repr__(self):
3691 return '<DB:PullRequestDisplay #%s>' % self.attrs.get('pull_request_id')
3692
3693 def versions(self):
3694 return pull_request_obj.versions.order_by(
3695 PullRequestVersion.pull_request_version_id).all()
3696
3697 def is_closed(self):
3698 return pull_request_obj.is_closed()
3699
3700 @property
3701 def pull_request_version_id(self):
3702 return getattr(pull_request_obj, 'pull_request_version_id', None)
3703
3704 attrs = StrictAttributeDict(pull_request_obj.get_api_data())
3705
3706 attrs.author = StrictAttributeDict(
3707 pull_request_obj.author.get_api_data())
3708 if pull_request_obj.target_repo:
3709 attrs.target_repo = StrictAttributeDict(
3710 pull_request_obj.target_repo.get_api_data())
3711 attrs.target_repo.clone_url = pull_request_obj.target_repo.clone_url
3712
3713 if pull_request_obj.source_repo:
3714 attrs.source_repo = StrictAttributeDict(
3715 pull_request_obj.source_repo.get_api_data())
3716 attrs.source_repo.clone_url = pull_request_obj.source_repo.clone_url
3717
3718 attrs.source_ref_parts = pull_request_obj.source_ref_parts
3719 attrs.target_ref_parts = pull_request_obj.target_ref_parts
3720 attrs.revisions = pull_request_obj.revisions
3721
3722 attrs.shadow_merge_ref = org_pull_request_obj.shadow_merge_ref
3723 attrs.reviewer_data = org_pull_request_obj.reviewer_data
3724 attrs.reviewer_data_json = org_pull_request_obj.reviewer_data_json
3725
3726 return PullRequestDisplay(attrs, internal=internal_methods)
3727
3728 def is_closed(self):
3729 return self.status == self.STATUS_CLOSED
3730
3731 def __json__(self):
3732 return {
3733 'revisions': self.revisions,
3734 }
3735
3736 def calculated_review_status(self):
3737 from rhodecode.model.changeset_status import ChangesetStatusModel
3738 return ChangesetStatusModel().calculated_review_status(self)
3739
3740 def reviewers_statuses(self):
3741 from rhodecode.model.changeset_status import ChangesetStatusModel
3742 return ChangesetStatusModel().reviewers_statuses(self)
3743
3744 @property
3745 def workspace_id(self):
3746 from rhodecode.model.pull_request import PullRequestModel
3747 return PullRequestModel()._workspace_id(self)
3748
3749 def get_shadow_repo(self):
3750 workspace_id = self.workspace_id
3751 vcs_obj = self.target_repo.scm_instance()
3752 shadow_repository_path = vcs_obj._get_shadow_repository_path(
3753 workspace_id)
3754 return vcs_obj._get_shadow_instance(shadow_repository_path)
3755
3756
3757 class PullRequestVersion(Base, _PullRequestBase):
3758 __tablename__ = 'pull_request_versions'
3759 __table_args__ = (
3760 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3761 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3762 )
3763
3764 pull_request_version_id = Column(
3765 'pull_request_version_id', Integer(), nullable=False, primary_key=True)
3766 pull_request_id = Column(
3767 'pull_request_id', Integer(),
3768 ForeignKey('pull_requests.pull_request_id'), nullable=False)
3769 pull_request = relationship('PullRequest')
3770
3771 def __repr__(self):
3772 if self.pull_request_version_id:
3773 return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id
3774 else:
3775 return '<DB:PullRequestVersion at %#x>' % id(self)
3776
3777 @property
3778 def reviewers(self):
3779 return self.pull_request.reviewers
3780
3781 @property
3782 def versions(self):
3783 return self.pull_request.versions
3784
3785 def is_closed(self):
3786 # calculate from original
3787 return self.pull_request.status == self.STATUS_CLOSED
3788
3789 def calculated_review_status(self):
3790 return self.pull_request.calculated_review_status()
3791
3792 def reviewers_statuses(self):
3793 return self.pull_request.reviewers_statuses()
3794
3795
3796 class PullRequestReviewers(Base, BaseModel):
3797 __tablename__ = 'pull_request_reviewers'
3798 __table_args__ = (
3799 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3800 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3801 )
3802
3803 @hybrid_property
3804 def reasons(self):
3805 if not self._reasons:
3806 return []
3807 return self._reasons
3808
3809 @reasons.setter
3810 def reasons(self, val):
3811 val = val or []
3812 if any(not isinstance(x, basestring) for x in val):
3813 raise Exception('invalid reasons type, must be list of strings')
3814 self._reasons = val
3815
3816 pull_requests_reviewers_id = Column(
3817 'pull_requests_reviewers_id', Integer(), nullable=False,
3818 primary_key=True)
3819 pull_request_id = Column(
3820 "pull_request_id", Integer(),
3821 ForeignKey('pull_requests.pull_request_id'), nullable=False)
3822 user_id = Column(
3823 "user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
3824 _reasons = Column(
3825 'reason', MutationList.as_mutable(
3826 JsonType('list', dialect_map=dict(mysql=UnicodeText(16384)))))
3827
3828 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
3829 user = relationship('User')
3830 pull_request = relationship('PullRequest')
3831
3832 rule_data = Column(
3833 'rule_data_json',
3834 JsonType(dialect_map=dict(mysql=UnicodeText(16384))))
3835
3836 def rule_user_group_data(self):
3837 """
3838 Returns the voting user group rule data for this reviewer
3839 """
3840
3841 if self.rule_data and 'vote_rule' in self.rule_data:
3842 user_group_data = {}
3843 if 'rule_user_group_entry_id' in self.rule_data:
3844 # means a group with voting rules !
3845 user_group_data['id'] = self.rule_data['rule_user_group_entry_id']
3846 user_group_data['name'] = self.rule_data['rule_name']
3847 user_group_data['vote_rule'] = self.rule_data['vote_rule']
3848
3849 return user_group_data
3850
3851 def __unicode__(self):
3852 return u"<%s('id:%s')>" % (self.__class__.__name__,
3853 self.pull_requests_reviewers_id)
3854
3855
3856 class Notification(Base, BaseModel):
3857 __tablename__ = 'notifications'
3858 __table_args__ = (
3859 Index('notification_type_idx', 'type'),
3860 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3861 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3862 )
3863
3864 TYPE_CHANGESET_COMMENT = u'cs_comment'
3865 TYPE_MESSAGE = u'message'
3866 TYPE_MENTION = u'mention'
3867 TYPE_REGISTRATION = u'registration'
3868 TYPE_PULL_REQUEST = u'pull_request'
3869 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
3870
3871 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
3872 subject = Column('subject', Unicode(512), nullable=True)
3873 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
3874 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
3875 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
3876 type_ = Column('type', Unicode(255))
3877
3878 created_by_user = relationship('User')
3879 notifications_to_users = relationship('UserNotification', lazy='joined',
3880 cascade="all, delete, delete-orphan")
3881
3882 @property
3883 def recipients(self):
3884 return [x.user for x in UserNotification.query()\
3885 .filter(UserNotification.notification == self)\
3886 .order_by(UserNotification.user_id.asc()).all()]
3887
3888 @classmethod
3889 def create(cls, created_by, subject, body, recipients, type_=None):
3890 if type_ is None:
3891 type_ = Notification.TYPE_MESSAGE
3892
3893 notification = cls()
3894 notification.created_by_user = created_by
3895 notification.subject = subject
3896 notification.body = body
3897 notification.type_ = type_
3898 notification.created_on = datetime.datetime.now()
3899
3900 for u in recipients:
3901 assoc = UserNotification()
3902 assoc.notification = notification
3903
3904 # if created_by is inside recipients mark his notification
3905 # as read
3906 if u.user_id == created_by.user_id:
3907 assoc.read = True
3908
3909 u.notifications.append(assoc)
3910 Session().add(notification)
3911
3912 return notification
3913
3914
3915 class UserNotification(Base, BaseModel):
3916 __tablename__ = 'user_to_notification'
3917 __table_args__ = (
3918 UniqueConstraint('user_id', 'notification_id'),
3919 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3920 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3921 )
3922 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
3923 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
3924 read = Column('read', Boolean, default=False)
3925 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
3926
3927 user = relationship('User', lazy="joined")
3928 notification = relationship('Notification', lazy="joined",
3929 order_by=lambda: Notification.created_on.desc(),)
3930
3931 def mark_as_read(self):
3932 self.read = True
3933 Session().add(self)
3934
3935
3936 class Gist(Base, BaseModel):
3937 __tablename__ = 'gists'
3938 __table_args__ = (
3939 Index('g_gist_access_id_idx', 'gist_access_id'),
3940 Index('g_created_on_idx', 'created_on'),
3941 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3942 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3943 )
3944 GIST_PUBLIC = u'public'
3945 GIST_PRIVATE = u'private'
3946 DEFAULT_FILENAME = u'gistfile1.txt'
3947
3948 ACL_LEVEL_PUBLIC = u'acl_public'
3949 ACL_LEVEL_PRIVATE = u'acl_private'
3950
3951 gist_id = Column('gist_id', Integer(), primary_key=True)
3952 gist_access_id = Column('gist_access_id', Unicode(250))
3953 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
3954 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
3955 gist_expires = Column('gist_expires', Float(53), nullable=False)
3956 gist_type = Column('gist_type', Unicode(128), nullable=False)
3957 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
3958 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
3959 acl_level = Column('acl_level', Unicode(128), nullable=True)
3960
3961 owner = relationship('User')
3962
3963 def __repr__(self):
3964 return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id)
3965
3966 @hybrid_property
3967 def description_safe(self):
3968 from rhodecode.lib import helpers as h
3969 return h.escape(self.gist_description)
3970
3971 @classmethod
3972 def get_or_404(cls, id_):
3973 from pyramid.httpexceptions import HTTPNotFound
3974
3975 res = cls.query().filter(cls.gist_access_id == id_).scalar()
3976 if not res:
3977 raise HTTPNotFound()
3978 return res
3979
3980 @classmethod
3981 def get_by_access_id(cls, gist_access_id):
3982 return cls.query().filter(cls.gist_access_id == gist_access_id).scalar()
3983
3984 def gist_url(self):
3985 from rhodecode.model.gist import GistModel
3986 return GistModel().get_url(self)
3987
3988 @classmethod
3989 def base_path(cls):
3990 """
3991 Returns base path when all gists are stored
3992
3993 :param cls:
3994 """
3995 from rhodecode.model.gist import GIST_STORE_LOC
3996 q = Session().query(RhodeCodeUi)\
3997 .filter(RhodeCodeUi.ui_key == URL_SEP)
3998 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
3999 return os.path.join(q.one().ui_value, GIST_STORE_LOC)
4000
4001 def get_api_data(self):
4002 """
4003 Common function for generating gist related data for API
4004 """
4005 gist = self
4006 data = {
4007 'gist_id': gist.gist_id,
4008 'type': gist.gist_type,
4009 'access_id': gist.gist_access_id,
4010 'description': gist.gist_description,
4011 'url': gist.gist_url(),
4012 'expires': gist.gist_expires,
4013 'created_on': gist.created_on,
4014 'modified_at': gist.modified_at,
4015 'content': None,
4016 'acl_level': gist.acl_level,
4017 }
4018 return data
4019
4020 def __json__(self):
4021 data = dict(
4022 )
4023 data.update(self.get_api_data())
4024 return data
4025 # SCM functions
4026
4027 def scm_instance(self, **kwargs):
4028 full_repo_path = os.path.join(self.base_path(), self.gist_access_id)
4029 return get_vcs_instance(
4030 repo_path=safe_str(full_repo_path), create=False)
4031
4032
4033 class ExternalIdentity(Base, BaseModel):
4034 __tablename__ = 'external_identities'
4035 __table_args__ = (
4036 Index('local_user_id_idx', 'local_user_id'),
4037 Index('external_id_idx', 'external_id'),
4038 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4039 'mysql_charset': 'utf8'})
4040
4041 external_id = Column('external_id', Unicode(255), default=u'',
4042 primary_key=True)
4043 external_username = Column('external_username', Unicode(1024), default=u'')
4044 local_user_id = Column('local_user_id', Integer(),
4045 ForeignKey('users.user_id'), primary_key=True)
4046 provider_name = Column('provider_name', Unicode(255), default=u'',
4047 primary_key=True)
4048 access_token = Column('access_token', String(1024), default=u'')
4049 alt_token = Column('alt_token', String(1024), default=u'')
4050 token_secret = Column('token_secret', String(1024), default=u'')
4051
4052 @classmethod
4053 def by_external_id_and_provider(cls, external_id, provider_name,
4054 local_user_id=None):
4055 """
4056 Returns ExternalIdentity instance based on search params
4057
4058 :param external_id:
4059 :param provider_name:
4060 :return: ExternalIdentity
4061 """
4062 query = cls.query()
4063 query = query.filter(cls.external_id == external_id)
4064 query = query.filter(cls.provider_name == provider_name)
4065 if local_user_id:
4066 query = query.filter(cls.local_user_id == local_user_id)
4067 return query.first()
4068
4069 @classmethod
4070 def user_by_external_id_and_provider(cls, external_id, provider_name):
4071 """
4072 Returns User instance based on search params
4073
4074 :param external_id:
4075 :param provider_name:
4076 :return: User
4077 """
4078 query = User.query()
4079 query = query.filter(cls.external_id == external_id)
4080 query = query.filter(cls.provider_name == provider_name)
4081 query = query.filter(User.user_id == cls.local_user_id)
4082 return query.first()
4083
4084 @classmethod
4085 def by_local_user_id(cls, local_user_id):
4086 """
4087 Returns all tokens for user
4088
4089 :param local_user_id:
4090 :return: ExternalIdentity
4091 """
4092 query = cls.query()
4093 query = query.filter(cls.local_user_id == local_user_id)
4094 return query
4095
4096
4097 class Integration(Base, BaseModel):
4098 __tablename__ = 'integrations'
4099 __table_args__ = (
4100 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4101 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
4102 )
4103
4104 integration_id = Column('integration_id', Integer(), primary_key=True)
4105 integration_type = Column('integration_type', String(255))
4106 enabled = Column('enabled', Boolean(), nullable=False)
4107 name = Column('name', String(255), nullable=False)
4108 child_repos_only = Column('child_repos_only', Boolean(), nullable=False,
4109 default=False)
4110
4111 settings = Column(
4112 'settings_json', MutationObj.as_mutable(
4113 JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
4114 repo_id = Column(
4115 'repo_id', Integer(), ForeignKey('repositories.repo_id'),
4116 nullable=True, unique=None, default=None)
4117 repo = relationship('Repository', lazy='joined')
4118
4119 repo_group_id = Column(
4120 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
4121 nullable=True, unique=None, default=None)
4122 repo_group = relationship('RepoGroup', lazy='joined')
4123
4124 @property
4125 def scope(self):
4126 if self.repo:
4127 return repr(self.repo)
4128 if self.repo_group:
4129 if self.child_repos_only:
4130 return repr(self.repo_group) + ' (child repos only)'
4131 else:
4132 return repr(self.repo_group) + ' (recursive)'
4133 if self.child_repos_only:
4134 return 'root_repos'
4135 return 'global'
4136
4137 def __repr__(self):
4138 return '<Integration(%r, %r)>' % (self.integration_type, self.scope)
4139
4140
4141 class RepoReviewRuleUser(Base, BaseModel):
4142 __tablename__ = 'repo_review_rules_users'
4143 __table_args__ = (
4144 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4145 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4146 )
4147
4148 repo_review_rule_user_id = Column('repo_review_rule_user_id', Integer(), primary_key=True)
4149 repo_review_rule_id = Column("repo_review_rule_id", Integer(), ForeignKey('repo_review_rules.repo_review_rule_id'))
4150 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False)
4151 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
4152 user = relationship('User')
4153
4154 def rule_data(self):
4155 return {
4156 'mandatory': self.mandatory
4157 }
4158
4159
4160 class RepoReviewRuleUserGroup(Base, BaseModel):
4161 __tablename__ = 'repo_review_rules_users_groups'
4162 __table_args__ = (
4163 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4164 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4165 )
4166 VOTE_RULE_ALL = -1
4167
4168 repo_review_rule_users_group_id = Column('repo_review_rule_users_group_id', Integer(), primary_key=True)
4169 repo_review_rule_id = Column("repo_review_rule_id", Integer(), ForeignKey('repo_review_rules.repo_review_rule_id'))
4170 users_group_id = Column("users_group_id", Integer(),ForeignKey('users_groups.users_group_id'), nullable=False)
4171 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
4172 vote_rule = Column("vote_rule", Integer(), nullable=True, default=VOTE_RULE_ALL)
4173 users_group = relationship('UserGroup')
4174
4175 def rule_data(self):
4176 return {
4177 'mandatory': self.mandatory,
4178 'vote_rule': self.vote_rule
4179 }
4180
4181 @property
4182 def vote_rule_label(self):
4183 if not self.vote_rule or self.vote_rule == self.VOTE_RULE_ALL:
4184 return 'all must vote'
4185 else:
4186 return 'min. vote {}'.format(self.vote_rule)
4187
4188
4189 class RepoReviewRule(Base, BaseModel):
4190 __tablename__ = 'repo_review_rules'
4191 __table_args__ = (
4192 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4193 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4194 )
4195
4196 repo_review_rule_id = Column(
4197 'repo_review_rule_id', Integer(), primary_key=True)
4198 repo_id = Column(
4199 "repo_id", Integer(), ForeignKey('repositories.repo_id'))
4200 repo = relationship('Repository', backref='review_rules')
4201
4202 review_rule_name = Column('review_rule_name', String(255))
4203 _branch_pattern = Column("branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
4204 _target_branch_pattern = Column("target_branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
4205 _file_pattern = Column("file_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
4206
4207 use_authors_for_review = Column("use_authors_for_review", Boolean(), nullable=False, default=False)
4208 forbid_author_to_review = Column("forbid_author_to_review", Boolean(), nullable=False, default=False)
4209 forbid_commit_author_to_review = Column("forbid_commit_author_to_review", Boolean(), nullable=False, default=False)
4210 forbid_adding_reviewers = Column("forbid_adding_reviewers", Boolean(), nullable=False, default=False)
4211
4212 rule_users = relationship('RepoReviewRuleUser')
4213 rule_user_groups = relationship('RepoReviewRuleUserGroup')
4214
4215 def _validate_glob(self, value):
4216 re.compile('^' + glob2re(value) + '$')
4217
4218 @hybrid_property
4219 def source_branch_pattern(self):
4220 return self._branch_pattern or '*'
4221
4222 @source_branch_pattern.setter
4223 def source_branch_pattern(self, value):
4224 self._validate_glob(value)
4225 self._branch_pattern = value or '*'
4226
4227 @hybrid_property
4228 def target_branch_pattern(self):
4229 return self._target_branch_pattern or '*'
4230
4231 @target_branch_pattern.setter
4232 def target_branch_pattern(self, value):
4233 self._validate_glob(value)
4234 self._target_branch_pattern = value or '*'
4235
4236 @hybrid_property
4237 def file_pattern(self):
4238 return self._file_pattern or '*'
4239
4240 @file_pattern.setter
4241 def file_pattern(self, value):
4242 self._validate_glob(value)
4243 self._file_pattern = value or '*'
4244
4245 def matches(self, source_branch, target_branch, files_changed):
4246 """
4247 Check if this review rule matches a branch/files in a pull request
4248
4249 :param source_branch: source branch name for the commit
4250 :param target_branch: target branch name for the commit
4251 :param files_changed: list of file paths changed in the pull request
4252 """
4253
4254 source_branch = source_branch or ''
4255 target_branch = target_branch or ''
4256 files_changed = files_changed or []
4257
4258 branch_matches = True
4259 if source_branch or target_branch:
4260 if self.source_branch_pattern == '*':
4261 source_branch_match = True
4262 else:
4263 source_branch_regex = re.compile(
4264 '^' + glob2re(self.source_branch_pattern) + '$')
4265 source_branch_match = bool(source_branch_regex.search(source_branch))
4266 if self.target_branch_pattern == '*':
4267 target_branch_match = True
4268 else:
4269 target_branch_regex = re.compile(
4270 '^' + glob2re(self.target_branch_pattern) + '$')
4271 target_branch_match = bool(target_branch_regex.search(target_branch))
4272
4273 branch_matches = source_branch_match and target_branch_match
4274
4275 files_matches = True
4276 if self.file_pattern != '*':
4277 files_matches = False
4278 file_regex = re.compile(glob2re(self.file_pattern))
4279 for filename in files_changed:
4280 if file_regex.search(filename):
4281 files_matches = True
4282 break
4283
4284 return branch_matches and files_matches
4285
4286 @property
4287 def review_users(self):
4288 """ Returns the users which this rule applies to """
4289
4290 users = collections.OrderedDict()
4291
4292 for rule_user in self.rule_users:
4293 if rule_user.user.active:
4294 if rule_user.user not in users:
4295 users[rule_user.user.username] = {
4296 'user': rule_user.user,
4297 'source': 'user',
4298 'source_data': {},
4299 'data': rule_user.rule_data()
4300 }
4301
4302 for rule_user_group in self.rule_user_groups:
4303 source_data = {
4304 'user_group_id': rule_user_group.users_group.users_group_id,
4305 'name': rule_user_group.users_group.users_group_name,
4306 'members': len(rule_user_group.users_group.members)
4307 }
4308 for member in rule_user_group.users_group.members:
4309 if member.user.active:
4310 key = member.user.username
4311 if key in users:
4312 # skip this member as we have him already
4313 # this prevents from override the "first" matched
4314 # users with duplicates in multiple groups
4315 continue
4316
4317 users[key] = {
4318 'user': member.user,
4319 'source': 'user_group',
4320 'source_data': source_data,
4321 'data': rule_user_group.rule_data()
4322 }
4323
4324 return users
4325
4326 def user_group_vote_rule(self):
4327 rules = []
4328 if self.rule_user_groups:
4329 for user_group in self.rule_user_groups:
4330 rules.append(user_group)
4331 return rules
4332
4333 def __repr__(self):
4334 return '<RepoReviewerRule(id=%r, repo=%r)>' % (
4335 self.repo_review_rule_id, self.repo)
4336
4337
4338 class ScheduleEntry(Base, BaseModel):
4339 __tablename__ = 'schedule_entries'
4340 __table_args__ = (
4341 UniqueConstraint('schedule_name', name='s_schedule_name_idx'),
4342 UniqueConstraint('task_uid', name='s_task_uid_idx'),
4343 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4344 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
4345 )
4346 schedule_types = ['crontab', 'timedelta', 'integer']
4347 schedule_entry_id = Column('schedule_entry_id', Integer(), primary_key=True)
4348
4349 schedule_name = Column("schedule_name", String(255), nullable=False, unique=None, default=None)
4350 schedule_description = Column("schedule_description", String(10000), nullable=True, unique=None, default=None)
4351 schedule_enabled = Column("schedule_enabled", Boolean(), nullable=False, unique=None, default=True)
4352
4353 _schedule_type = Column("schedule_type", String(255), nullable=False, unique=None, default=None)
4354 schedule_definition = Column('schedule_definition_json', MutationObj.as_mutable(JsonType(default=lambda: "", dialect_map=dict(mysql=LONGTEXT()))))
4355
4356 schedule_last_run = Column('schedule_last_run', DateTime(timezone=False), nullable=True, unique=None, default=None)
4357 schedule_total_run_count = Column('schedule_total_run_count', Integer(), nullable=True, unique=None, default=0)
4358
4359 # task
4360 task_uid = Column("task_uid", String(255), nullable=False, unique=None, default=None)
4361 task_dot_notation = Column("task_dot_notation", String(4096), nullable=False, unique=None, default=None)
4362 task_args = Column('task_args_json', MutationObj.as_mutable(JsonType(default=list, dialect_map=dict(mysql=LONGTEXT()))))
4363 task_kwargs = Column('task_kwargs_json', MutationObj.as_mutable(JsonType(default=dict, dialect_map=dict(mysql=LONGTEXT()))))
4364
4365 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4366 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=None)
4367
4368 @hybrid_property
4369 def schedule_type(self):
4370 return self._schedule_type
4371
4372 @schedule_type.setter
4373 def schedule_type(self, val):
4374 if val not in self.schedule_types:
4375 raise ValueError('Value must be on of `{}` and got `{}`'.format(
4376 val, self.schedule_type))
4377
4378 self._schedule_type = val
4379
4380 @classmethod
4381 def get_uid(cls, obj):
4382 args = obj.task_args
4383 kwargs = obj.task_kwargs
4384 if isinstance(args, JsonRaw):
4385 try:
4386 args = json.loads(args)
4387 except ValueError:
4388 args = tuple()
4389
4390 if isinstance(kwargs, JsonRaw):
4391 try:
4392 kwargs = json.loads(kwargs)
4393 except ValueError:
4394 kwargs = dict()
4395
4396 dot_notation = obj.task_dot_notation
4397 val = '.'.join(map(safe_str, [
4398 sorted(dot_notation), args, sorted(kwargs.items())]))
4399 return hashlib.sha1(val).hexdigest()
4400
4401 @classmethod
4402 def get_by_schedule_name(cls, schedule_name):
4403 return cls.query().filter(cls.schedule_name == schedule_name).scalar()
4404
4405 @classmethod
4406 def get_by_schedule_id(cls, schedule_id):
4407 return cls.query().filter(cls.schedule_entry_id == schedule_id).scalar()
4408
4409 @property
4410 def task(self):
4411 return self.task_dot_notation
4412
4413 @property
4414 def schedule(self):
4415 from rhodecode.lib.celerylib.utils import raw_2_schedule
4416 schedule = raw_2_schedule(self.schedule_definition, self.schedule_type)
4417 return schedule
4418
4419 @property
4420 def args(self):
4421 try:
4422 return list(self.task_args or [])
4423 except ValueError:
4424 return list()
4425
4426 @property
4427 def kwargs(self):
4428 try:
4429 return dict(self.task_kwargs or {})
4430 except ValueError:
4431 return dict()
4432
4433 def _as_raw(self, val):
4434 if hasattr(val, 'de_coerce'):
4435 val = val.de_coerce()
4436 if val:
4437 val = json.dumps(val)
4438
4439 return val
4440
4441 @property
4442 def schedule_definition_raw(self):
4443 return self._as_raw(self.schedule_definition)
4444
4445 @property
4446 def args_raw(self):
4447 return self._as_raw(self.task_args)
4448
4449 @property
4450 def kwargs_raw(self):
4451 return self._as_raw(self.task_kwargs)
4452
4453 def __repr__(self):
4454 return '<DB:ScheduleEntry({}:{})>'.format(
4455 self.schedule_entry_id, self.schedule_name)
4456
4457
4458 @event.listens_for(ScheduleEntry, 'before_update')
4459 def update_task_uid(mapper, connection, target):
4460 target.task_uid = ScheduleEntry.get_uid(target)
4461
4462
4463 @event.listens_for(ScheduleEntry, 'before_insert')
4464 def set_task_uid(mapper, connection, target):
4465 target.task_uid = ScheduleEntry.get_uid(target)
4466
4467
4468 class _BaseBranchPerms(BaseModel):
4469 @classmethod
4470 def compute_hash(cls, value):
4471 return md5_safe(value)
4472
4473 @hybrid_property
4474 def branch_pattern(self):
4475 return self._branch_pattern or '*'
4476
4477 @hybrid_property
4478 def branch_hash(self):
4479 return self._branch_hash
4480
4481 def _validate_glob(self, value):
4482 re.compile('^' + glob2re(value) + '$')
4483
4484 @branch_pattern.setter
4485 def branch_pattern(self, value):
4486 self._validate_glob(value)
4487 self._branch_pattern = value or '*'
4488 # set the Hash when setting the branch pattern
4489 self._branch_hash = self.compute_hash(self._branch_pattern)
4490
4491 def matches(self, branch):
4492 """
4493 Check if this the branch matches entry
4494
4495 :param branch: branch name for the commit
4496 """
4497
4498 branch = branch or ''
4499
4500 branch_matches = True
4501 if branch:
4502 branch_regex = re.compile('^' + glob2re(self.branch_pattern) + '$')
4503 branch_matches = bool(branch_regex.search(branch))
4504
4505 return branch_matches
4506
4507
4508 class UserToRepoBranchPermission(Base, _BaseBranchPerms):
4509 __tablename__ = 'user_to_repo_branch_permissions'
4510 __table_args__ = (
4511 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4512 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4513 )
4514
4515 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
4516
4517 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
4518 repo = relationship('Repository', backref='user_branch_perms')
4519
4520 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
4521 permission = relationship('Permission')
4522
4523 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('repo_to_perm.repo_to_perm_id'), nullable=False, unique=None, default=None)
4524 user_repo_to_perm = relationship('UserRepoToPerm')
4525
4526 rule_order = Column('rule_order', Integer(), nullable=False)
4527 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
4528 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
4529
4530 def __unicode__(self):
4531 return u'<UserBranchPermission(%s => %r)>' % (
4532 self.user_repo_to_perm, self.branch_pattern)
4533
4534
4535 class UserGroupToRepoBranchPermission(Base, _BaseBranchPerms):
4536 __tablename__ = 'user_group_to_repo_branch_permissions'
4537 __table_args__ = (
4538 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4539 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4540 )
4541
4542 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
4543
4544 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
4545 repo = relationship('Repository', backref='user_group_branch_perms')
4546
4547 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
4548 permission = relationship('Permission')
4549
4550 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('users_group_repo_to_perm.users_group_to_perm_id'), nullable=False, unique=None, default=None)
4551 user_group_repo_to_perm = relationship('UserGroupRepoToPerm')
4552
4553 rule_order = Column('rule_order', Integer(), nullable=False)
4554 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
4555 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
4556
4557 def __unicode__(self):
4558 return u'<UserBranchPermission(%s => %r)>' % (
4559 self.user_group_repo_to_perm, self.branch_pattern)
4560
4561
4562 class DbMigrateVersion(Base, BaseModel):
4563 __tablename__ = 'db_migrate_version'
4564 __table_args__ = (
4565 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4566 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
4567 )
4568 repository_id = Column('repository_id', String(250), primary_key=True)
4569 repository_path = Column('repository_path', Text)
4570 version = Column('version', Integer)
4571
4572
4573 class DbSession(Base, BaseModel):
4574 __tablename__ = 'db_session'
4575 __table_args__ = (
4576 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4577 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
4578 )
4579
4580 def __repr__(self):
4581 return '<DB:DbSession({})>'.format(self.id)
4582
4583 id = Column('id', Integer())
4584 namespace = Column('namespace', String(255), primary_key=True)
4585 accessed = Column('accessed', DateTime, nullable=False)
4586 created = Column('created', DateTime, nullable=False)
4587 data = Column('data', PickleType, nullable=False)
@@ -0,0 +1,40 b''
1 import logging
2
3 from sqlalchemy import *
4
5 from rhodecode.model import meta
6 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
7
8 log = logging.getLogger(__name__)
9
10
11 def upgrade(migrate_engine):
12 """
13 Upgrade operations go here.
14 Don't create your own engine; bind migrate_engine to your metadata
15 """
16 _reset_base(migrate_engine)
17 from rhodecode.lib.dbmigrate.schema import db_4_11_0_0 as db
18
19 pull_request_table = db.PullRequest.__table__
20 pull_request_version_table = db.PullRequestVersion.__table__
21
22 renderer = Column('description_renderer', Unicode(64), nullable=True)
23 renderer.create(table=pull_request_table)
24
25 renderer_ver = Column('description_renderer', Unicode(64), nullable=True)
26 renderer_ver.create(table=pull_request_version_table)
27
28 # issue fixups
29 fixups(db, meta.Session)
30
31
32 def downgrade(migrate_engine):
33 meta = MetaData()
34 meta.bind = migrate_engine
35
36
37 def fixups(models, _SESSION):
38 pass
39
40
@@ -0,0 +1,46 b''
1 import logging
2
3 from sqlalchemy import *
4 from sqlalchemy.engine import reflection
5 from sqlalchemy.dialects.mysql import LONGTEXT
6
7 from alembic.migration import MigrationContext
8 from alembic.operations import Operations
9
10 from rhodecode.lib.dbmigrate.utils import create_default_permissions, \
11 create_default_object_permission
12 from rhodecode.model import meta
13 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
14
15 log = logging.getLogger(__name__)
16
17
18 def upgrade(migrate_engine):
19 """
20 Upgrade operations go here.
21 Don't create your own engine; bind migrate_engine to your metadata
22 """
23 _reset_base(migrate_engine)
24 from rhodecode.lib.dbmigrate.schema import db_4_13_0_0 as db
25
26 # issue fixups
27 fixups(db, meta.Session)
28
29
30 def downgrade(migrate_engine):
31 meta = MetaData()
32 meta.bind = migrate_engine
33
34
35 def fixups(models, _SESSION):
36 # create default permissions
37 create_default_permissions(_SESSION, models)
38 log.info('created default global permissions definitions')
39 _SESSION().commit()
40
41 # # fix default object permissions
42 # create_default_object_permission(_SESSION, models)
43
44 log.info('created default permission')
45 _SESSION().commit()
46
@@ -0,0 +1,39 b''
1 import logging
2
3 from sqlalchemy import *
4 from sqlalchemy.engine import reflection
5 from sqlalchemy.dialects.mysql import LONGTEXT
6
7 from alembic.migration import MigrationContext
8 from alembic.operations import Operations
9
10 from rhodecode.model import meta
11 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
12
13 log = logging.getLogger(__name__)
14
15
16 def upgrade(migrate_engine):
17 """
18 Upgrade operations go here.
19 Don't create your own engine; bind migrate_engine to your metadata
20 """
21 _reset_base(migrate_engine)
22 from rhodecode.lib.dbmigrate.schema import db_4_13_0_0 as db
23
24 db.UserToRepoBranchPermission.__table__.create()
25 db.UserGroupToRepoBranchPermission.__table__.create()
26
27 # issue fixups
28 fixups(db, meta.Session)
29
30
31 def downgrade(migrate_engine):
32 meta = MetaData()
33 meta.bind = migrate_engine
34
35
36 def fixups(models, _SESSION):
37 pass
38
39
@@ -0,0 +1,43 b''
1 import logging
2
3 from sqlalchemy import *
4
5 from rhodecode.lib.dbmigrate.utils import (
6 create_default_object_permission, create_default_permissions)
7
8 from rhodecode.model import meta
9 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
10
11 log = logging.getLogger(__name__)
12
13
14 def upgrade(migrate_engine):
15 """
16 Upgrade operations go here.
17 Don't create your own engine; bind migrate_engine to your metadata
18 """
19 _reset_base(migrate_engine)
20 from rhodecode.lib.dbmigrate.schema import db_4_13_0_0 as db
21
22 # issue fixups
23 fixups(db, meta.Session)
24
25
26 def downgrade(migrate_engine):
27 meta = MetaData()
28 meta.bind = migrate_engine
29
30
31 def fixups(models, _SESSION):
32 # create default permissions
33 create_default_permissions(_SESSION, models)
34 log.info('created default global permissions definitions')
35 _SESSION().commit()
36
37 # fix default object permissions
38 create_default_object_permission(_SESSION, models)
39
40 log.info('created default permission')
41 _SESSION().commit()
42
43
@@ -0,0 +1,146 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 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 os
22 import time
23 import datetime
24 import msgpack
25 import logging
26 import traceback
27 import tempfile
28
29
30 log = logging.getLogger(__name__)
31
32 # NOTE: Any changes should be synced with exc_tracking at vcsserver.lib.exc_tracking
33 global_prefix = 'rhodecode'
34
35
36 def exc_serialize(exc_id, tb, exc_type):
37
38 data = {
39 'version': 'v1',
40 'exc_id': exc_id,
41 'exc_utc_date': datetime.datetime.utcnow().isoformat(),
42 'exc_timestamp': repr(time.time()),
43 'exc_message': tb,
44 'exc_type': exc_type,
45 }
46 return msgpack.packb(data), data
47
48
49 def exc_unserialize(tb):
50 return msgpack.unpackb(tb)
51
52
53 def get_exc_store():
54 """
55 Get and create exception store if it's not existing
56 """
57 exc_store_dir = 'rc_exception_store_v1'
58 # fallback
59 _exc_store_path = os.path.join(tempfile.gettempdir(), exc_store_dir)
60
61 exc_store_dir = '' # TODO: need a persistent cross instance store here
62 if exc_store_dir:
63 _exc_store_path = os.path.join(exc_store_dir, exc_store_dir)
64
65 _exc_store_path = os.path.abspath(_exc_store_path)
66 if not os.path.isdir(_exc_store_path):
67 os.makedirs(_exc_store_path)
68 log.debug('Initializing exceptions store at %s', _exc_store_path)
69 return _exc_store_path
70
71
72 def _store_exception(exc_id, exc_info, prefix):
73 exc_type, exc_value, exc_traceback = exc_info
74 tb = ''.join(traceback.format_exception(
75 exc_type, exc_value, exc_traceback, None))
76
77 exc_type_name = exc_type.__name__
78 exc_store_path = get_exc_store()
79 exc_data, org_data = exc_serialize(exc_id, tb, exc_type_name)
80 exc_pref_id = '{}_{}_{}'.format(exc_id, prefix, org_data['exc_timestamp'])
81 if not os.path.isdir(exc_store_path):
82 os.makedirs(exc_store_path)
83 stored_exc_path = os.path.join(exc_store_path, exc_pref_id)
84 with open(stored_exc_path, 'wb') as f:
85 f.write(exc_data)
86 log.debug('Stored generated exception %s as: %s', exc_id, stored_exc_path)
87
88
89 def store_exception(exc_id, exc_info, prefix=global_prefix):
90 try:
91 _store_exception(exc_id=exc_id, exc_info=exc_info, prefix=prefix)
92 except Exception:
93 log.exception('Failed to store exception `%s` information', exc_id)
94 # there's no way this can fail, it will crash server badly if it does.
95 pass
96
97
98 def _find_exc_file(exc_id, prefix=global_prefix):
99 exc_store_path = get_exc_store()
100 if prefix:
101 exc_id = '{}_{}'.format(exc_id, prefix)
102 else:
103 # search without a prefix
104 exc_id = '{}'.format(exc_id)
105
106 # we need to search the store for such start pattern as above
107 for fname in os.listdir(exc_store_path):
108 if fname.startswith(exc_id):
109 exc_id = os.path.join(exc_store_path, fname)
110 break
111 continue
112 else:
113 exc_id = None
114
115 return exc_id
116
117
118 def _read_exception(exc_id, prefix):
119 exc_id_file_path = _find_exc_file(exc_id=exc_id, prefix=prefix)
120 if exc_id_file_path:
121 with open(exc_id_file_path, 'rb') as f:
122 return exc_unserialize(f.read())
123 else:
124 log.debug('Exception File `%s` not found', exc_id_file_path)
125 return None
126
127
128 def read_exception(exc_id, prefix=global_prefix):
129 try:
130 return _read_exception(exc_id=exc_id, prefix=prefix)
131 except Exception:
132 log.exception('Failed to read exception `%s` information', exc_id)
133 # there's no way this can fail, it will crash server badly if it does.
134 return None
135
136
137 def delete_exception(exc_id, prefix=global_prefix):
138 try:
139 exc_id_file_path = _find_exc_file(exc_id, prefix=prefix)
140 if exc_id_file_path:
141 os.remove(exc_id_file_path)
142
143 except Exception:
144 log.exception('Failed to remove exception `%s` information', exc_id)
145 # there's no way this can fail, it will crash server badly if it does.
146 pass
@@ -0,0 +1,75 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2015-2018 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 logging
22 from dogpile.cache import register_backend
23
24 register_backend(
25 "dogpile.cache.rc.memory_lru", "rhodecode.lib.rc_cache.backends",
26 "LRUMemoryBackend")
27
28 register_backend(
29 "dogpile.cache.rc.file_namespace", "rhodecode.lib.rc_cache.backends",
30 "FileNamespaceBackend")
31
32 register_backend(
33 "dogpile.cache.rc.redis", "rhodecode.lib.rc_cache.backends",
34 "RedisPickleBackend")
35
36
37 log = logging.getLogger(__name__)
38
39 from . import region_meta
40 from .utils import (
41 get_default_cache_settings, key_generator, get_or_create_region,
42 clear_cache_namespace, make_region, InvalidationContext,
43 FreshRegionCache, ActiveRegionCache)
44
45
46 def configure_dogpile_cache(settings):
47 cache_dir = settings.get('cache_dir')
48 if cache_dir:
49 region_meta.dogpile_config_defaults['cache_dir'] = cache_dir
50
51 rc_cache_data = get_default_cache_settings(settings, prefixes=['rc_cache.'])
52
53 # inspect available namespaces
54 avail_regions = set()
55 for key in rc_cache_data.keys():
56 namespace_name = key.split('.', 1)[0]
57 avail_regions.add(namespace_name)
58 log.debug('dogpile: found following cache regions: %s', avail_regions)
59
60 # register them into namespace
61 for region_name in avail_regions:
62 new_region = make_region(
63 name=region_name,
64 function_key_generator=key_generator
65 )
66
67 new_region.configure_from_config(settings, 'rc_cache.{}.'.format(region_name))
68
69 log.debug('dogpile: registering a new region %s[%s]',
70 region_name, new_region.__dict__)
71 region_meta.dogpile_cache_regions[region_name] = new_region
72
73
74 def includeme(config):
75 configure_dogpile_cache(config.registry.settings)
@@ -0,0 +1,203 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2015-2018 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 import time
21 import errno
22 import logging
23
24 import gevent
25
26 from dogpile.cache.backends import memory as memory_backend
27 from dogpile.cache.backends import file as file_backend
28 from dogpile.cache.backends import redis as redis_backend
29 from dogpile.cache.backends.file import NO_VALUE, compat, FileLock
30 from dogpile.cache.util import memoized_property
31
32 from rhodecode.lib.memory_lru_dict import LRUDict, LRUDictDebug
33
34
35 _default_max_size = 1024
36
37 log = logging.getLogger(__name__)
38
39
40 class LRUMemoryBackend(memory_backend.MemoryBackend):
41 pickle_values = False
42
43 def __init__(self, arguments):
44 max_size = arguments.pop('max_size', _default_max_size)
45
46 LRUDictClass = LRUDict
47 if arguments.pop('log_key_count', None):
48 LRUDictClass = LRUDictDebug
49
50 arguments['cache_dict'] = LRUDictClass(max_size)
51 super(LRUMemoryBackend, self).__init__(arguments)
52
53 def delete(self, key):
54 try:
55 del self._cache[key]
56 except KeyError:
57 # we don't care if key isn't there at deletion
58 pass
59
60 def delete_multi(self, keys):
61 for key in keys:
62 self.delete(key)
63
64
65 class Serializer(object):
66 def _dumps(self, value, safe=False):
67 try:
68 return compat.pickle.dumps(value)
69 except Exception:
70 if safe:
71 return NO_VALUE
72 else:
73 raise
74
75 def _loads(self, value, safe=True):
76 try:
77 return compat.pickle.loads(value)
78 except Exception:
79 if safe:
80 return NO_VALUE
81 else:
82 raise
83
84
85 class CustomLockFactory(FileLock):
86
87 @memoized_property
88 def _module(self):
89 import fcntl
90 flock_org = fcntl.flock
91
92 def gevent_flock(fd, operation):
93 """
94 Gevent compatible flock
95 """
96 # set non-blocking, this will cause an exception if we cannot acquire a lock
97 operation |= fcntl.LOCK_NB
98 start_lock_time = time.time()
99 timeout = 60 * 5 # 5min
100 while True:
101 try:
102 flock_org(fd, operation)
103 # lock has been acquired
104 break
105 except (OSError, IOError) as e:
106 # raise on other errors than Resource temporarily unavailable
107 if e.errno != errno.EAGAIN:
108 raise
109 elif (time.time() - start_lock_time) > timeout:
110 # waited to much time on a lock, better fail than loop for ever
111 log.error('Failed to acquire lock on `%s` after waiting %ss',
112 self.filename, timeout)
113 raise
114 wait_timeout = 0.03
115 log.debug('Failed to acquire lock on `%s`, retry in %ss',
116 self.filename, wait_timeout)
117 gevent.sleep(wait_timeout)
118
119 fcntl.flock = gevent_flock
120 return fcntl
121
122
123 class FileNamespaceBackend(Serializer, file_backend.DBMBackend):
124
125 def __init__(self, arguments):
126 arguments['lock_factory'] = CustomLockFactory
127 super(FileNamespaceBackend, self).__init__(arguments)
128
129 def list_keys(self, prefix=''):
130 def cond(v):
131 if not prefix:
132 return True
133
134 if v.startswith(prefix):
135 return True
136 return False
137
138 with self._dbm_file(True) as dbm:
139
140 return filter(cond, dbm.keys())
141
142 def get_store(self):
143 return self.filename
144
145 def get(self, key):
146 with self._dbm_file(False) as dbm:
147 if hasattr(dbm, 'get'):
148 value = dbm.get(key, NO_VALUE)
149 else:
150 # gdbm objects lack a .get method
151 try:
152 value = dbm[key]
153 except KeyError:
154 value = NO_VALUE
155 if value is not NO_VALUE:
156 value = self._loads(value)
157 return value
158
159 def set(self, key, value):
160 with self._dbm_file(True) as dbm:
161 dbm[key] = self._dumps(value)
162
163 def set_multi(self, mapping):
164 with self._dbm_file(True) as dbm:
165 for key, value in mapping.items():
166 dbm[key] = self._dumps(value)
167
168
169 class RedisPickleBackend(Serializer, redis_backend.RedisBackend):
170 def list_keys(self, prefix=''):
171 if prefix:
172 prefix = prefix + '*'
173 return self.client.keys(prefix)
174
175 def get_store(self):
176 return self.client.connection_pool
177
178 def get(self, key):
179 value = self.client.get(key)
180 if value is None:
181 return NO_VALUE
182 return self._loads(value)
183
184 def set(self, key, value):
185 if self.redis_expiration_time:
186 self.client.setex(key, self.redis_expiration_time,
187 self._dumps(value))
188 else:
189 self.client.set(key, self._dumps(value))
190
191 def set_multi(self, mapping):
192 mapping = dict(
193 (k, self._dumps(v))
194 for k, v in mapping.items()
195 )
196
197 if not self.redis_expiration_time:
198 self.client.mset(mapping)
199 else:
200 pipe = self.client.pipeline()
201 for key, value in mapping.items():
202 pipe.setex(key, self.redis_expiration_time, value)
203 pipe.execute()
@@ -0,0 +1,28 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2015-2018 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 import os
21 import tempfile
22
23 dogpile_config_defaults = {
24 'cache_dir': os.path.join(tempfile.gettempdir(), 'rc_cache')
25 }
26
27 # GLOBAL TO STORE ALL REGISTERED REGIONS
28 dogpile_cache_regions = {}
@@ -0,0 +1,322 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2015-2018 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 import os
21 import time
22 import logging
23 import functools
24 import threading
25
26 from dogpile.cache import CacheRegion
27 from dogpile.cache.util import compat
28
29 import rhodecode
30 from rhodecode.lib.utils import safe_str, sha1
31 from rhodecode.lib.utils2 import safe_unicode, str2bool
32 from rhodecode.model.db import Session, CacheKey, IntegrityError
33
34 from . import region_meta
35
36 log = logging.getLogger(__name__)
37
38
39 class RhodeCodeCacheRegion(CacheRegion):
40
41 def conditional_cache_on_arguments(
42 self, namespace=None,
43 expiration_time=None,
44 should_cache_fn=None,
45 to_str=compat.string_type,
46 function_key_generator=None,
47 condition=True):
48 """
49 Custom conditional decorator, that will not touch any dogpile internals if
50 condition isn't meet. This works a bit different than should_cache_fn
51 And it's faster in cases we don't ever want to compute cached values
52 """
53 expiration_time_is_callable = compat.callable(expiration_time)
54
55 if function_key_generator is None:
56 function_key_generator = self.function_key_generator
57
58 def decorator(fn):
59 if to_str is compat.string_type:
60 # backwards compatible
61 key_generator = function_key_generator(namespace, fn)
62 else:
63 key_generator = function_key_generator(namespace, fn, to_str=to_str)
64
65 @functools.wraps(fn)
66 def decorate(*arg, **kw):
67 key = key_generator(*arg, **kw)
68
69 @functools.wraps(fn)
70 def creator():
71 return fn(*arg, **kw)
72
73 if not condition:
74 return creator()
75
76 timeout = expiration_time() if expiration_time_is_callable \
77 else expiration_time
78
79 return self.get_or_create(key, creator, timeout, should_cache_fn)
80
81 def invalidate(*arg, **kw):
82 key = key_generator(*arg, **kw)
83 self.delete(key)
84
85 def set_(value, *arg, **kw):
86 key = key_generator(*arg, **kw)
87 self.set(key, value)
88
89 def get(*arg, **kw):
90 key = key_generator(*arg, **kw)
91 return self.get(key)
92
93 def refresh(*arg, **kw):
94 key = key_generator(*arg, **kw)
95 value = fn(*arg, **kw)
96 self.set(key, value)
97 return value
98
99 decorate.set = set_
100 decorate.invalidate = invalidate
101 decorate.refresh = refresh
102 decorate.get = get
103 decorate.original = fn
104 decorate.key_generator = key_generator
105
106 return decorate
107
108 return decorator
109
110
111 def make_region(*arg, **kw):
112 return RhodeCodeCacheRegion(*arg, **kw)
113
114
115 def get_default_cache_settings(settings, prefixes=None):
116 prefixes = prefixes or []
117 cache_settings = {}
118 for key in settings.keys():
119 for prefix in prefixes:
120 if key.startswith(prefix):
121 name = key.split(prefix)[1].strip()
122 val = settings[key]
123 if isinstance(val, basestring):
124 val = val.strip()
125 cache_settings[name] = val
126 return cache_settings
127
128
129 def compute_key_from_params(*args):
130 """
131 Helper to compute key from given params to be used in cache manager
132 """
133 return sha1("_".join(map(safe_str, args)))
134
135
136 def key_generator(namespace, fn):
137 fname = fn.__name__
138
139 def generate_key(*args):
140 namespace_pref = namespace or 'default'
141 arg_key = compute_key_from_params(*args)
142 final_key = "{}:{}_{}".format(namespace_pref, fname, arg_key)
143
144 return final_key
145
146 return generate_key
147
148
149 def get_or_create_region(region_name, region_namespace=None):
150 from rhodecode.lib.rc_cache.backends import FileNamespaceBackend
151 region_obj = region_meta.dogpile_cache_regions.get(region_name)
152 if not region_obj:
153 raise EnvironmentError(
154 'Region `{}` not in configured: {}.'.format(
155 region_name, region_meta.dogpile_cache_regions.keys()))
156
157 region_uid_name = '{}:{}'.format(region_name, region_namespace)
158 if isinstance(region_obj.actual_backend, FileNamespaceBackend):
159 region_exist = region_meta.dogpile_cache_regions.get(region_namespace)
160 if region_exist:
161 log.debug('Using already configured region: %s', region_namespace)
162 return region_exist
163 cache_dir = region_meta.dogpile_config_defaults['cache_dir']
164 expiration_time = region_obj.expiration_time
165
166 if not os.path.isdir(cache_dir):
167 os.makedirs(cache_dir)
168 new_region = make_region(
169 name=region_uid_name, function_key_generator=key_generator
170 )
171 namespace_filename = os.path.join(
172 cache_dir, "{}.cache.dbm".format(region_namespace))
173 # special type that allows 1db per namespace
174 new_region.configure(
175 backend='dogpile.cache.rc.file_namespace',
176 expiration_time=expiration_time,
177 arguments={"filename": namespace_filename}
178 )
179
180 # create and save in region caches
181 log.debug('configuring new region: %s',region_uid_name)
182 region_obj = region_meta.dogpile_cache_regions[region_namespace] = new_region
183
184 return region_obj
185
186
187 def clear_cache_namespace(cache_region, cache_namespace_uid):
188 region = get_or_create_region(cache_region, cache_namespace_uid)
189 cache_keys = region.backend.list_keys(prefix=cache_namespace_uid)
190 num_delete_keys = len(cache_keys)
191 if num_delete_keys:
192 region.delete_multi(cache_keys)
193 return num_delete_keys
194
195
196 class ActiveRegionCache(object):
197 def __init__(self, context):
198 self.context = context
199
200 def should_invalidate(self):
201 return False
202
203
204 class FreshRegionCache(object):
205 def __init__(self, context):
206 self.context = context
207
208 def should_invalidate(self):
209 return True
210
211
212 class InvalidationContext(object):
213 """
214 usage::
215
216 from rhodecode.lib import rc_cache
217
218 cache_namespace_uid = CacheKey.SOME_NAMESPACE.format(1)
219 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
220
221 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid, condition=True)
222 def heavy_compute(cache_name, param1, param2):
223 print('COMPUTE {}, {}, {}'.format(cache_name, param1, param2))
224
225 # invalidation namespace is shared namespace key for all process caches
226 # we use it to send a global signal
227 invalidation_namespace = 'repo_cache:1'
228
229 inv_context_manager = rc_cache.InvalidationContext(
230 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
231 with inv_context_manager as invalidation_context:
232 args = ('one', 'two')
233 # re-compute and store cache if we get invalidate signal
234 if invalidation_context.should_invalidate():
235 result = heavy_compute.refresh(*args)
236 else:
237 result = heavy_compute(*args)
238
239 compute_time = inv_context_manager.compute_time
240 log.debug('result computed in %.3fs' ,compute_time)
241
242 # To send global invalidation signal, simply run
243 CacheKey.set_invalidate(invalidation_namespace)
244
245 """
246
247 def __repr__(self):
248 return '<InvalidationContext:{}[{}]>'.format(
249 safe_str(self.cache_key), safe_str(self.uid))
250
251 def __init__(self, uid, invalidation_namespace='',
252 raise_exception=False, thread_scoped=None):
253 self.uid = uid
254 self.invalidation_namespace = invalidation_namespace
255 self.raise_exception = raise_exception
256 self.proc_id = safe_unicode(rhodecode.CONFIG.get('instance_id') or 'DEFAULT')
257 self.thread_id = 'global'
258
259 if thread_scoped is None:
260 # if we set "default" we can override this via .ini settings
261 thread_scoped = str2bool(rhodecode.CONFIG.get('cache_thread_scoped'))
262
263 # Append the thread id to the cache key if this invalidation context
264 # should be scoped to the current thread.
265 if thread_scoped is True:
266 self.thread_id = threading.current_thread().ident
267
268 self.cache_key = compute_key_from_params(uid)
269 self.cache_key = 'proc:{}_thread:{}_{}'.format(
270 self.proc_id, self.thread_id, self.cache_key)
271 self.compute_time = 0
272
273 def get_or_create_cache_obj(self, uid, invalidation_namespace=''):
274 cache_obj = CacheKey.get_active_cache(self.cache_key)
275 log.debug('Fetched cache obj %s using %s cache key.', cache_obj, self.cache_key)
276 invalidation_namespace = invalidation_namespace or self.invalidation_namespace
277 if not cache_obj:
278 cache_obj = CacheKey(self.cache_key, cache_args=invalidation_namespace)
279 return cache_obj
280
281 def __enter__(self):
282 """
283 Test if current object is valid, and return CacheRegion function
284 that does invalidation and calculation
285 """
286 # register or get a new key based on uid
287 self.cache_obj = self.get_or_create_cache_obj(uid=self.uid)
288 self._start_time = time.time()
289 if self.cache_obj.cache_active:
290 # means our cache obj is existing and marked as it's
291 # cache is not outdated, we return ActiveRegionCache
292 self.skip_cache_active_change = True
293
294 return ActiveRegionCache(context=self)
295
296 # the key is either not existing or set to False, we return
297 # the real invalidator which re-computes value. We additionally set
298 # the flag to actually update the Database objects
299 self.skip_cache_active_change = False
300 return FreshRegionCache(context=self)
301
302 def __exit__(self, exc_type, exc_val, exc_tb):
303 # save compute time
304 self.compute_time = time.time() - self._start_time
305
306 if self.skip_cache_active_change:
307 return
308
309 try:
310 self.cache_obj.cache_active = True
311 Session().add(self.cache_obj)
312 Session().commit()
313 except IntegrityError:
314 # if we catch integrity error, it means we inserted this object
315 # assumption is that's really an edge race-condition case and
316 # it's safe is to skip it
317 Session().rollback()
318 except Exception:
319 log.exception('Failed to commit on cache key update')
320 Session().rollback()
321 if self.raise_exception:
322 raise
@@ -0,0 +1,29 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2017-2018 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 uuid import uuid4
22 from pyramid.decorator import reify
23 from pyramid.request import Request as _Request
24
25
26 class Request(_Request):
27 @reify
28 def req_id(self):
29 return str(uuid4())
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,9 b''
1 <div class="panel panel-default">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Default Permissions for Branches.')}</h3>
4 </div>
5 <div class="panel-body">
6 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
7 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_branch_permissions.png')}"/>
8 </div>
9 </div>
@@ -0,0 +1,9 b''
1 <div class="panel panel-default">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Repository Branch Permissions.')}</h3>
4 </div>
5 <div class="panel-body">
6 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
7 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/repo_branch_permissions.png')}"/>
8 </div>
9 </div>
@@ -0,0 +1,38 b''
1 <div class="panel panel-default">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Exceptions Tracker - Exception ID')}: ${c.exception_id}</h3>
4 </div>
5 <div class="panel-body">
6 % if c.traceback:
7
8 <h4>${_('Exception `{}` generated on UTC date: {}').format(c.traceback.get('exc_type', 'NO_TYPE'), c.traceback.get('exc_utc_date', 'NO_DATE'))}</h4>
9 <pre>${c.traceback.get('exc_message', 'NO_MESSAGE')}</pre>
10
11 % else:
12 ${_('Unable to Read Exception. It might be removed or non-existing.')}
13 % endif
14 </div>
15 </div>
16
17
18 % if c.traceback:
19 <div class="panel panel-danger">
20 <div class="panel-heading" id="advanced-delete">
21 <h3 class="panel-title">${_('Delete this Exception')}</h3>
22 </div>
23 <div class="panel-body">
24 ${h.secure_form(h.route_path('admin_settings_exception_tracker_delete', exception_id=c.exception_id), request=request)}
25 <div style="margin: 0 0 20px 0" class="fake-space"></div>
26
27 <div class="field">
28 <button class="btn btn-small btn-danger" type="submit"
29 onclick="return confirm('${_('Confirm to delete this exception')}');">
30 <i class="icon-remove-sign"></i>
31 ${_('Delete This Exception')}
32 </button>
33 </div>
34
35 ${h.end_form()}
36 </div>
37 </div>
38 % endif
@@ -0,0 +1,57 b''
1 <div class="panel panel-default">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Exceptions Tracker ')}</h3>
4 </div>
5 <div class="panel-body">
6 % if c.exception_list_count == 1:
7 ${_('There is {} stored exception.').format(c.exception_list_count)}
8 % else:
9 ${_('There are {} stored exceptions.').format(c.exception_list_count)}
10 % endif
11 ${_('Store directory')}: ${c.exception_store_dir}
12
13 ${h.secure_form(h.route_path('admin_settings_exception_tracker_delete_all'), request=request)}
14 <div style="margin: 0 0 20px 0" class="fake-space"></div>
15
16 <div class="field">
17 <button class="btn btn-small btn-danger" type="submit"
18 onclick="return confirm('${_('Confirm to delete all exceptions')}');">
19 <i class="icon-remove-sign"></i>
20 ${_('Delete All')}
21 </button>
22 </div>
23
24 ${h.end_form()}
25
26 </div>
27 </div>
28
29
30 <div class="panel panel-default">
31 <div class="panel-heading">
32 <h3 class="panel-title">${_('Exceptions Tracker - Showing the last {} Exceptions').format(c.limit)}.</h3>
33 <a class="panel-edit" href="${h.current_route_path(request, limit=c.next_limit)}">${_('Show more')}</a>
34 </div>
35 <div class="panel-body">
36 <table class="rctable">
37 <tr>
38 <th>#</th>
39 <th>Exception ID</th>
40 <th>Date</th>
41 <th>App Type</th>
42 <th>Exc Type</th>
43 </tr>
44 <% cnt = len(c.exception_list)%>
45 % for tb in c.exception_list:
46 <tr>
47 <td>${cnt}</td>
48 <td><a href="${h.route_path('admin_settings_exception_tracker_show', exception_id=tb['exc_id'])}"><code>${tb['exc_id']}</code></a></td>
49 <td>${h.format_date(tb['exc_utc_date'])}</td>
50 <td>${tb['app_type']}</td>
51 <td>${tb['exc_type']}</td>
52 </tr>
53 <% cnt -=1 %>
54 % endfor
55 </table>
56 </div>
57 </div>
@@ -0,0 +1,41 b''
1 <%namespace name="base" file="/base/base.mako"/>
2
3 <div class="panel panel-default">
4 <div class="panel-heading">
5 <h3 class="panel-title">${_('Caches')}</h3>
6 </div>
7 <div class="panel-body">
8 <p>
9 Cache keys used for storing cached values of user permissions and authentication plugin cache.
10 Invalidating the cache will remove those entries.
11 </p>
12
13 <pre>
14 region: ${c.region.name}
15 backend: ${c.region.actual_backend.__class__}
16 store: ${c.region.actual_backend.get_store()}
17
18 % if c.user_keys:
19 ${len(c.user_keys)} <a href="#showKeys" onclick="$('#show-keys').toggle()">${_('Show all')}</a>
20 <span id="show-keys" style="display: none">
21 % for k in c.user_keys:
22 - ${k}
23 % endfor
24 </span>
25 % else:
26 NO KEYS FOUND
27 % endif
28 </pre>
29 <p></p>
30 ${h.secure_form(h.route_path('edit_user_caches_update', user_id=c.user.user_id), request=request)}
31 <div class="form">
32 <div class="fields">
33 ${h.submit('reset_cache_%s' % c.user.user_id, _('Invalidate user cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate user cache')+"');")}
34 </div>
35 </div>
36 ${h.end_form()}
37
38 </div>
39 </div>
40
41
@@ -0,0 +1,94 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 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 os
22 import pytest
23
24 from rhodecode.tests import (
25 TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
26 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
27 from rhodecode.tests.vcs_operations import (
28 Command, _check_proper_hg_push, _check_proper_git_push, _add_files_and_push)
29
30
31 @pytest.mark.usefixtures("disable_anonymous_user")
32 class TestVCSOperations(object):
33
34 @pytest.mark.parametrize('username, password', [
35 (TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS),
36 (TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS),
37 ])
38 @pytest.mark.parametrize('branch_perm', [
39 'branch.none',
40 'branch.merge',
41 'branch.push',
42 'branch.push_force',
43 ])
44 def test_push_to_protected_branch_fails_with_message_hg(
45 self, rc_web_server, tmpdir, branch_perm, user_util,
46 branch_permission_setter, username, password):
47 repo = user_util.create_repo(repo_type='hg')
48 repo_name = repo.repo_name
49 branch_permission_setter(repo_name, username, permission=branch_perm)
50
51 clone_url = rc_web_server.repo_clone_url(
52 repo.repo_name, user=username, passwd=password)
53 Command(os.path.dirname(tmpdir.strpath)).execute(
54 'hg clone', clone_url, tmpdir.strpath)
55
56 stdout, stderr = _add_files_and_push(
57 'hg', tmpdir.strpath, clone_url=clone_url)
58 if branch_perm in ['branch.push', 'branch.push_force']:
59 _check_proper_hg_push(stdout, stderr)
60 else:
61 msg = "Branch `default` changes rejected by rule `*`=>{}".format(branch_perm)
62 assert msg in stdout
63 assert "transaction abort" in stdout
64
65 @pytest.mark.parametrize('username, password', [
66 (TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS),
67 (TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS),
68 ])
69 @pytest.mark.parametrize('branch_perm', [
70 'branch.none',
71 'branch.merge',
72 'branch.push',
73 'branch.push_force',
74 ])
75 def test_push_to_protected_branch_fails_with_message_git(
76 self, rc_web_server, tmpdir, branch_perm, user_util,
77 branch_permission_setter, username, password):
78 repo = user_util.create_repo(repo_type='git')
79 repo_name = repo.repo_name
80 branch_permission_setter(repo_name, username, permission=branch_perm)
81
82 clone_url = rc_web_server.repo_clone_url(
83 repo.repo_name, user=username, passwd=password)
84 Command(os.path.dirname(tmpdir.strpath)).execute(
85 'git clone', clone_url, tmpdir.strpath)
86
87 stdout, stderr = _add_files_and_push(
88 'git', tmpdir.strpath, clone_url=clone_url)
89 if branch_perm in ['branch.push', 'branch.push_force']:
90 _check_proper_git_push(stdout, stderr)
91 else:
92 msg = "Branch `master` changes rejected by rule `*`=>{}".format(branch_perm)
93 assert msg in stderr
94 assert "(pre-receive hook declined)" in stderr
@@ -0,0 +1,122 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 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 os
23 import pytest
24
25 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
26 from rhodecode.tests.vcs_operations import (
27 Command, _check_proper_hg_push, _check_proper_git_push,
28 _add_files, _add_files_and_push)
29
30
31 @pytest.mark.usefixtures("disable_anonymous_user")
32 class TestVCSOperations(object):
33
34 def test_push_force_hg(self, rc_web_server, tmpdir, user_util):
35 repo = user_util.create_repo(repo_type='hg')
36 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
37 Command(os.path.dirname(tmpdir.strpath)).execute(
38 'hg clone', clone_url, tmpdir.strpath)
39
40 stdout, stderr = _add_files_and_push(
41 'hg', tmpdir.strpath, clone_url=clone_url)
42 _check_proper_hg_push(stdout, stderr)
43
44 # rewrite history, and push with force
45 Command(tmpdir.strpath).execute(
46 'hg checkout -r 1 && hg commit -m "starting new head"')
47 _add_files('hg', tmpdir.strpath, clone_url=clone_url)
48
49 stdout, stderr = Command(tmpdir.strpath).execute(
50 'hg push --verbose -f {}'.format(clone_url))
51
52 _check_proper_hg_push(stdout, stderr)
53
54 def test_push_force_git(self, rc_web_server, tmpdir, user_util):
55 repo = user_util.create_repo(repo_type='git')
56 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
57 Command(os.path.dirname(tmpdir.strpath)).execute(
58 'git clone', clone_url, tmpdir.strpath)
59
60 stdout, stderr = _add_files_and_push(
61 'git', tmpdir.strpath, clone_url=clone_url)
62 _check_proper_git_push(stdout, stderr)
63
64 # rewrite history, and push with force
65 Command(tmpdir.strpath).execute(
66 'git reset --hard HEAD~2')
67 stdout, stderr = Command(tmpdir.strpath).execute(
68 'git push -f {} master'.format(clone_url))
69
70 assert '(forced update)' in stderr
71
72 def test_push_force_hg_blocked_by_branch_permissions(
73 self, rc_web_server, tmpdir, user_util, branch_permission_setter):
74 repo = user_util.create_repo(repo_type='hg')
75 repo_name = repo.repo_name
76 username = TEST_USER_ADMIN_LOGIN
77 branch_permission_setter(repo_name, username, permission='branch.push')
78
79 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
80 Command(os.path.dirname(tmpdir.strpath)).execute(
81 'hg clone', clone_url, tmpdir.strpath)
82
83 stdout, stderr = _add_files_and_push(
84 'hg', tmpdir.strpath, clone_url=clone_url)
85 _check_proper_hg_push(stdout, stderr)
86
87 # rewrite history, and push with force
88 Command(tmpdir.strpath).execute(
89 'hg checkout -r 1 && hg commit -m "starting new head"')
90 _add_files('hg', tmpdir.strpath, clone_url=clone_url)
91
92 stdout, stderr = Command(tmpdir.strpath).execute(
93 'hg push --verbose -f {}'.format(clone_url))
94
95 assert "Branch `default` changes rejected by rule `*`=>branch.push" in stdout
96 assert "FORCE PUSH FORBIDDEN" in stdout
97 assert "transaction abort" in stdout
98
99 def test_push_force_git_blocked_by_branch_permissions(
100 self, rc_web_server, tmpdir, user_util, branch_permission_setter):
101 repo = user_util.create_repo(repo_type='git')
102 repo_name = repo.repo_name
103 username = TEST_USER_ADMIN_LOGIN
104 branch_permission_setter(repo_name, username, permission='branch.push')
105
106 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
107 Command(os.path.dirname(tmpdir.strpath)).execute(
108 'git clone', clone_url, tmpdir.strpath)
109
110 stdout, stderr = _add_files_and_push(
111 'git', tmpdir.strpath, clone_url=clone_url)
112 _check_proper_git_push(stdout, stderr)
113
114 # rewrite history, and push with force
115 Command(tmpdir.strpath).execute(
116 'git reset --hard HEAD~2')
117 stdout, stderr = Command(tmpdir.strpath).execute(
118 'git push -f {} master'.format(clone_url))
119
120 assert "Branch `master` changes rejected by rule `*`=>branch.push" in stderr
121 assert "FORCE PUSH FORBIDDEN" in stderr
122 assert "(pre-receive hook declined)" in stderr
@@ -0,0 +1,115 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2018 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 os
23 import pytest
24
25 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
26 from rhodecode.tests.vcs_operations import (
27 Command, _check_proper_hg_push, _check_proper_git_push, _add_files_and_push)
28
29
30 @pytest.mark.usefixtures("disable_anonymous_user")
31 class TestVCSOperations(object):
32
33 def test_push_new_branch_hg(self, rc_web_server, tmpdir, user_util):
34 repo = user_util.create_repo(repo_type='hg')
35 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
36 Command(os.path.dirname(tmpdir.strpath)).execute(
37 'hg clone', clone_url, tmpdir.strpath)
38
39 stdout, stderr = _add_files_and_push(
40 'hg', tmpdir.strpath, clone_url=clone_url)
41 _check_proper_hg_push(stdout, stderr)
42
43 # start new branch, and push file into it
44 Command(tmpdir.strpath).execute(
45 'hg branch dev && hg commit -m "starting dev branch"')
46 stdout, stderr = _add_files_and_push(
47 'hg', tmpdir.strpath, clone_url=clone_url, target_branch='dev',
48 new_branch=True)
49
50 _check_proper_hg_push(stdout, stderr)
51
52 def test_push_new_branch_git(self, rc_web_server, tmpdir, user_util):
53 repo = user_util.create_repo(repo_type='git')
54 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
55 Command(os.path.dirname(tmpdir.strpath)).execute(
56 'git clone', clone_url, tmpdir.strpath)
57
58 stdout, stderr = _add_files_and_push(
59 'git', tmpdir.strpath, clone_url=clone_url)
60 _check_proper_git_push(stdout, stderr)
61
62 # start new branch, and push file into it
63 Command(tmpdir.strpath).execute('git checkout -b dev')
64 stdout, stderr = _add_files_and_push(
65 'git', tmpdir.strpath, clone_url=clone_url, target_branch='dev',
66 new_branch=True)
67
68 _check_proper_git_push(stdout, stderr, branch='dev')
69
70 def test_push_new_branch_hg_with_branch_permissions_no_force_push(
71 self, rc_web_server, tmpdir, user_util, branch_permission_setter):
72 repo = user_util.create_repo(repo_type='hg')
73 repo_name = repo.repo_name
74 username = TEST_USER_ADMIN_LOGIN
75 branch_permission_setter(repo_name, username, permission='branch.push')
76
77 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
78 Command(os.path.dirname(tmpdir.strpath)).execute(
79 'hg clone', clone_url, tmpdir.strpath)
80
81 stdout, stderr = _add_files_and_push(
82 'hg', tmpdir.strpath, clone_url=clone_url)
83 _check_proper_hg_push(stdout, stderr)
84
85 # start new branch, and push file into it
86 Command(tmpdir.strpath).execute(
87 'hg branch dev && hg commit -m "starting dev branch"')
88 stdout, stderr = _add_files_and_push(
89 'hg', tmpdir.strpath, clone_url=clone_url, target_branch='dev',
90 new_branch=True)
91
92 _check_proper_hg_push(stdout, stderr)
93
94 def test_push_new_branch_git_with_branch_permissions_no_force_push(
95 self, rc_web_server, tmpdir, user_util, branch_permission_setter):
96 repo = user_util.create_repo(repo_type='git')
97 repo_name = repo.repo_name
98 username = TEST_USER_ADMIN_LOGIN
99 branch_permission_setter(repo_name, username, permission='branch.push')
100
101 clone_url = rc_web_server.repo_clone_url(repo.repo_name)
102 Command(os.path.dirname(tmpdir.strpath)).execute(
103 'git clone', clone_url, tmpdir.strpath)
104
105 stdout, stderr = _add_files_and_push(
106 'git', tmpdir.strpath, clone_url=clone_url)
107 _check_proper_git_push(stdout, stderr)
108
109 # start new branch, and push file into it
110 Command(tmpdir.strpath).execute('git checkout -b dev')
111 stdout, stderr = _add_files_and_push(
112 'git', tmpdir.strpath, clone_url=clone_url, target_branch='dev',
113 new_branch=True)
114
115 _check_proper_git_push(stdout, stderr, branch='dev')
@@ -1,5 +1,5 b''
1 1 [bumpversion]
2 current_version = 4.12.4
2 current_version = 4.13.0
3 3 message = release: Bump version {current_version} to {new_version}
4 4
5 5 [bumpversion:file:rhodecode/VERSION]
@@ -5,25 +5,20 b' done = false'
5 5 done = true
6 6
7 7 [task:rc_tools_pinned]
8 done = true
9 8
10 9 [task:fixes_on_stable]
11 done = true
12 10
13 11 [task:pip2nix_generated]
14 done = true
15 12
16 13 [task:changelog_updated]
17 done = true
18 14
19 15 [task:generate_api_docs]
20 done = true
16
17 [task:updated_translation]
21 18
22 19 [release]
23 state = prepared
24 version = 4.12.4
25
26 [task:updated_translation]
20 state = in_progress
21 version = 4.13.0
27 22
28 23 [task:generate_js_routes]
29 24
@@ -26,6 +26,8 b' recursive-include rhodecode *.mako'
26 26 # 502 page
27 27 include rhodecode/public/502.html
28 28
29 # robots
30 include rhodecode/public/robots.txt
29 31
30 32 # images, css
31 33 include rhodecode/public/css/*.css
@@ -7,8 +7,9 b' About'
7 7
8 8 ``RhodeCode`` is a fast and powerful management tool for Mercurial_ and GIT_
9 9 and Subversion_ with a built in push/pull server, full text search,
10 pull requests and powerfull code-review system. It works on http/https and
10 pull requests and powerful code-review system. It works on http/https and
11 11 has a few unique features like:
12
12 13 - plugable architecture
13 14 - advanced permission system with IP restrictions
14 15 - rich set of authentication plugins including LDAP,
@@ -78,10 +79,9 b' Listed bellow are various support resour'
78 79
79 80 - Official issue tracker `RhodeCode Issue tracker <https://issues.rhodecode.com>`_
80 81
81 - Search our community portal `Community portal <https://community.rhodecode.com>`_
82 - Official Slack Community Channel `RhodeCode Slack <https://rhodecode.com/join>`_
82 83
83 - Join #rhodecode on FreeNode (irc.freenode.net)
84 or use http://webchat.freenode.net/?channels=rhodecode for web access to irc.
84 - Search our community portal `Community portal <https://community.rhodecode.com>`_
85 85
86 86 - You can also follow RhodeCode on twitter **@RhodeCode** where we often post
87 87 news and other interesting stuff about RhodeCode.
@@ -3,15 +3,15 b''
3 3 "description": "User interface for elements for rhodecode",
4 4 "main": "index.html",
5 5 "dependencies": {
6 "webcomponentsjs": "^0.7.22",
7 "polymer": "Polymer/polymer#^1.6.1",
8 "paper-button": "PolymerElements/paper-button#^1.0.13",
9 "paper-spinner": "PolymerElements/paper-spinner#^1.2.0",
10 "paper-tooltip": "PolymerElements/paper-tooltip#^1.1.2",
11 "paper-toast": "PolymerElements/paper-toast#^1.3.0",
12 "paper-toggle-button": "PolymerElements/paper-toggle-button#^1.2.0",
13 "iron-ajax": "PolymerElements/iron-ajax#^1.4.3",
14 "iron-autogrow-textarea": "PolymerElements/iron-autogrow-textarea#^1.0.13",
15 "iron-a11y-keys": "PolymerElements/iron-a11y-keys#^1.0.6"
6 "webcomponentsjs": "^1.2.3",
7 "polymer": "Polymer/polymer#^2.6.0",
8 "paper-button": "PolymerElements/paper-button#^2.1.2",
9 "paper-spinner": "PolymerElements/paper-spinner#^2.1.0",
10 "paper-tooltip": "PolymerElements/paper-tooltip#^2.1.1",
11 "paper-toast": "PolymerElements/paper-toast#^2.1.2",
12 "paper-toggle-button": "PolymerElements/paper-toggle-button#^2.1.1",
13 "iron-ajax": "PolymerElements/iron-ajax#^2.1.3",
14 "iron-autogrow-textarea": "PolymerElements/iron-autogrow-textarea#^2.2.0",
15 "iron-a11y-keys": "PolymerElements/iron-a11y-keys#^2.1.2"
16 16 }
17 17 }
@@ -2,7 +2,6 b''
2 2
3 3 ################################################################################
4 4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 5 ################################################################################
7 6
8 7 [DEFAULT]
@@ -46,10 +45,9 b' debug = true'
46 45 host = 127.0.0.1
47 46 port = 5000
48 47
49 ##################################
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
52 ##################################
48 ###########################################################
49 ## WAITRESS WSGI SERVER - Recommended for Development ####
50 ###########################################################
53 51
54 52 use = egg:waitress#main
55 53 ## number of worker threads
@@ -67,15 +65,15 b' asyncore_use_poll = true'
67 65 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68 66
69 67 #use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
68 ## Sets the number of process workers. More workers means more concurent connections
69 ## RhodeCode can handle at the same time. Each additional worker also it increases
70 ## memory usage as each has it's own set of caches.
71 ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
72 ## than 8-10 unless for really big deployments .e.g 700-1000 users.
73 ## `instance_id = *` must be set in the [app:main] section below (which is the default)
74 ## when using more than 1 worker.
74 75 #workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
77 #threads = 1
78 ## process name
76 ## process name visible in process list
79 77 #proc_name = rhodecode
80 78 ## type of worker class, one of sync, gevent
81 79 ## recommended for bigger setup is using of of other than sync one
@@ -103,6 +101,11 b' use = egg:PasteDeploy#prefix'
103 101 prefix = /
104 102
105 103 [app:main]
104 ## The %(here)s variable will be replaced with the absolute path of parent directory
105 ## of this file
106 ## In addition ENVIRONMENT variables usage is possible, e.g
107 ## sqlalchemy.db1.url = {ENV_RC_DB_URL}
108
106 109 use = egg:rhodecode-enterprise-ce
107 110
108 111 ## enable proxy prefix middleware, defined above
@@ -148,12 +151,12 b' gzip_responses = false'
148 151 ## autogenerate javascript routes file on startup
149 152 generate_js_files = false
150 153
151 ## Optional Languages
152 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
154 ## System global default language.
155 ## All available languages: en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
153 156 lang = en
154 157
155 ## perform a full repository scan on each server start, this should be
156 ## set to false after first startup, to allow faster server restarts.
158 ## Perform a full repository scan and import on each server start.
159 ## Settings this to true could lead to very long startup time.
157 160 startup.import_repos = false
158 161
159 162 ## Uncomment and set this path to use archive download cache.
@@ -167,23 +170,23 b' startup.import_repos = false'
167 170 ## SSH calls. Set this for events to receive proper url for SSH calls.
168 171 app.base_url = http://rhodecode.local
169 172
170 ## change this to unique ID for security
173 ## Unique application ID. Should be a random unique string for security.
171 174 app_instance_uuid = rc-production
172 175
173 ## cut off limit for large diffs (size in bytes). If overall diff size on
176 ## Cut off limit for large diffs (size in bytes). If overall diff size on
174 177 ## commit, or pull request exceeds this limit this diff will be displayed
175 178 ## partially. E.g 512000 == 512Kb
176 179 cut_off_limit_diff = 512000
177 180
178 ## cut off limit for large files inside diffs (size in bytes). Each individual
181 ## Cut off limit for large files inside diffs (size in bytes). Each individual
179 182 ## file inside diff which exceeds this limit will be displayed partially.
180 183 ## E.g 128000 == 128Kb
181 184 cut_off_limit_file = 128000
182 185
183 ## use cache version of scm repo everywhere
186 ## use cached version of vcs repositories everywhere. Recommended to be `true`
184 187 vcs_full_cache = true
185 188
186 ## force https in RhodeCode, fixes https redirects, assumes it's always https
189 ## Force https in RhodeCode, fixes https redirects, assumes it's always https.
187 190 ## Normally this is controlled by proper http flags sent from http server
188 191 force_https = false
189 192
@@ -230,7 +233,7 b' gist_alias_url ='
230 233 # GistView:*
231 234 api_access_controllers_whitelist =
232 235
233 ## default encoding used to convert from and to unicode
236 ## Default encoding used to convert from and to unicode
234 237 ## can be also a comma separated list of encoding in case of mixed encodings
235 238 default_encoding = UTF-8
236 239
@@ -277,8 +280,8 b' allow_repo_location_change = true'
277 280 ## allows to setup custom hooks in settings page
278 281 allow_custom_hooks_settings = true
279 282
280 ## generated license token, goto license page in RhodeCode settings to obtain
281 ## new token
283 ## Generated license token required for EE edition license.
284 ## New generated token value can be found in Admin > settings > license page.
282 285 license_token =
283 286
284 287 ## supervisor connection uri, for managing supervisor and logs.
@@ -308,65 +311,66 b' celery.max_tasks_per_child = 100'
308 311 ## tasks will never be sent to the queue, but executed locally instead.
309 312 celery.task_always_eager = false
310 313
311 ####################################
312 ### BEAKER CACHE ####
313 ####################################
314 # default cache dir for templates. Putting this into a ramdisk
315 ## can boost performance, eg. %(here)s/data_ramdisk
314 #####################################
315 ### DOGPILE CACHE ####
316 #####################################
317 ## Default cache dir for caches. Putting this into a ramdisk
318 ## can boost performance, eg. /tmpfs/data_ramdisk, however this directory might require
319 ## large amount of space
316 320 cache_dir = %(here)s/data
317 321
318 ## locking and default file storage for Beaker. Putting this into a ramdisk
319 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
320 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
321 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
322
323 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
322 ## `cache_perms` cache settings for permission tree, auth TTL.
323 rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
324 rc_cache.cache_perms.expiration_time = 300
324 325
325 beaker.cache.super_short_term.type = memory
326 beaker.cache.super_short_term.expire = 10
327 beaker.cache.super_short_term.key_length = 256
326 ## alternative `cache_perms` redis backend with distributed lock
327 #rc_cache.cache_perms.backend = dogpile.cache.rc.redis
328 #rc_cache.cache_perms.expiration_time = 300
329 ## redis_expiration_time needs to be greater then expiration_time
330 #rc_cache.cache_perms.arguments.redis_expiration_time = 7200
331 #rc_cache.cache_perms.arguments.socket_timeout = 30
332 #rc_cache.cache_perms.arguments.host = localhost
333 #rc_cache.cache_perms.arguments.port = 6379
334 #rc_cache.cache_perms.arguments.db = 0
335 #rc_cache.cache_perms.arguments.distributed_lock = true
328 336
329 beaker.cache.short_term.type = memory
330 beaker.cache.short_term.expire = 60
331 beaker.cache.short_term.key_length = 256
332
333 beaker.cache.long_term.type = memory
334 beaker.cache.long_term.expire = 36000
335 beaker.cache.long_term.key_length = 256
337 ## `cache_repo` cache settings for FileTree, Readme, RSS FEEDS
338 rc_cache.cache_repo.backend = dogpile.cache.rc.file_namespace
339 rc_cache.cache_repo.expiration_time = 2592000
336 340
337 beaker.cache.sql_cache_short.type = memory
338 beaker.cache.sql_cache_short.expire = 10
339 beaker.cache.sql_cache_short.key_length = 256
341 ## alternative `cache_repo` redis backend with distributed lock
342 #rc_cache.cache_repo.backend = dogpile.cache.rc.redis
343 #rc_cache.cache_repo.expiration_time = 2592000
344 ## redis_expiration_time needs to be greater then expiration_time
345 #rc_cache.cache_repo.arguments.redis_expiration_time = 2678400
346 #rc_cache.cache_repo.arguments.socket_timeout = 30
347 #rc_cache.cache_repo.arguments.host = localhost
348 #rc_cache.cache_repo.arguments.port = 6379
349 #rc_cache.cache_repo.arguments.db = 1
350 #rc_cache.cache_repo.arguments.distributed_lock = true
340 351
341 ## default is memory cache, configure only if required
342 ## using multi-node or multi-worker setup
343 #beaker.cache.auth_plugins.type = ext:database
344 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
345 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
346 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
347 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
348 #beaker.cache.auth_plugins.sa.pool_size = 10
349 #beaker.cache.auth_plugins.sa.max_overflow = 0
352 ## cache settings for SQL queries, this needs to use memory type backend
353 rc_cache.sql_cache_short.backend = dogpile.cache.rc.memory_lru
354 rc_cache.sql_cache_short.expiration_time = 30
350 355
351 beaker.cache.repo_cache_long.type = memorylru_base
352 beaker.cache.repo_cache_long.max_items = 4096
353 beaker.cache.repo_cache_long.expire = 2592000
356 ## `cache_repo_longterm` cache for repo object instances, this needs to use memory
357 ## type backend as the objects kept are not pickle serializable
358 rc_cache.cache_repo_longterm.backend = dogpile.cache.rc.memory_lru
359 ## by default we use 96H, this is using invalidation on push anyway
360 rc_cache.cache_repo_longterm.expiration_time = 345600
361 ## max items in LRU cache, reduce this number to save memory, and expire last used
362 ## cached objects
363 rc_cache.cache_repo_longterm.max_size = 10000
354 364
355 ## default is memorylru_base cache, configure only if required
356 ## using multi-node or multi-worker setup
357 #beaker.cache.repo_cache_long.type = ext:memcached
358 #beaker.cache.repo_cache_long.url = localhost:11211
359 #beaker.cache.repo_cache_long.expire = 1209600
360 #beaker.cache.repo_cache_long.key_length = 256
361 365
362 366 ####################################
363 367 ### BEAKER SESSION ####
364 368 ####################################
365 369
366 370 ## .session.type is type of storage options for the session, current allowed
367 ## types are file, ext:memcached, ext:database, and memory (default).
371 ## types are file, ext:memcached, ext:redis, ext:database, and memory (default).
368 372 beaker.session.type = file
369 beaker.session.data_dir = %(here)s/data/sessions/data
373 beaker.session.data_dir = %(here)s/data/sessions
370 374
371 375 ## db based session, fast, and allows easy management over logged in users
372 376 #beaker.session.type = ext:database
@@ -502,10 +506,7 b' appenlight.log_namespace_blacklist ='
502 506 ################################################################################
503 507 #set debug = false
504 508
505
506 ##############
507 ## STYLING ##
508 ##############
509 # enable debug style page
509 510 debug_style = true
510 511
511 512 ###########################################
@@ -514,6 +515,9 b' debug_style = true'
514 515 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
515 516 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
516 517 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
518 # pymysql is an alternative driver for MySQL, use in case of problems with default one
519 #sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
520
517 521 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
518 522
519 523 # see sqlalchemy docs for other advanced settings
@@ -533,6 +537,9 b' sqlalchemy.db1.convert_unicode = true'
533 537 ## which defaults to five.
534 538 #sqlalchemy.db1.max_overflow = 10
535 539
540 ## Connection check ping, used to detect broken database connections
541 ## could be enabled to better handle cases if MySQL has gone away errors
542 #sqlalchemy.db1.ping_connection = true
536 543
537 544 ##################
538 545 ### VCS CONFIG ###
@@ -547,15 +554,18 b' vcs.server.protocol = http'
547 554
548 555 ## Push/Pull operations protocol, available options are:
549 556 ## `http` - use http-rpc backend (default)
550 ##
551 557 vcs.scm_app_implementation = http
552 558
553 559 ## Push/Pull operations hooks protocol, available options are:
554 560 ## `http` - use http-rpc backend (default)
555 561 vcs.hooks.protocol = http
556 562
563 ## Host on which this instance is listening for hooks. If vcsserver is in other location
564 ## this should be adjusted.
565 vcs.hooks.host = 127.0.0.1
566
557 567 vcs.server.log_level = debug
558 ## Start VCSServer with this instance as a subprocess, usefull for development
568 ## Start VCSServer with this instance as a subprocess, useful for development
559 569 vcs.start_server = false
560 570
561 571 ## List of enabled VCS backends, available options are:
@@ -638,7 +648,7 b' custom.conf = 1'
638 648 ### LOGGING CONFIGURATION ####
639 649 ################################
640 650 [loggers]
641 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
651 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
642 652
643 653 [handlers]
644 654 keys = console, console_sql
@@ -694,9 +704,12 b' level = DEBUG'
694 704 formatter = color_formatter
695 705
696 706 [handler_console_sql]
707 # "level = DEBUG" logs SQL queries and results.
708 # "level = INFO" logs SQL queries.
709 # "level = WARN" logs neither. (Recommended for production systems.)
697 710 class = StreamHandler
698 711 args = (sys.stderr, )
699 level = DEBUG
712 level = WARN
700 713 formatter = color_formatter_sql
701 714
702 715 ################
@@ -715,5 +728,5 b' datefmt = %Y-%m-%d %H:%M:%S'
715 728
716 729 [formatter_color_formatter_sql]
717 730 class = rhodecode.lib.logging_formatter.ColorFormatterSql
718 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
731 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
719 732 datefmt = %Y-%m-%d %H:%M:%S
@@ -2,7 +2,6 b''
2 2
3 3 ################################################################################
4 4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 5 ################################################################################
7 6
8 7 [DEFAULT]
@@ -46,10 +45,9 b' debug = true'
46 45 host = 127.0.0.1
47 46 port = 5000
48 47
49 ##################################
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
52 ##################################
48 ###########################################################
49 ## WAITRESS WSGI SERVER - Recommended for Development ####
50 ###########################################################
53 51
54 52 #use = egg:waitress#main
55 53 ## number of worker threads
@@ -67,21 +65,21 b' port = 5000'
67 65 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68 66
69 67 use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
68 ## Sets the number of process workers. More workers means more concurent connections
69 ## RhodeCode can handle at the same time. Each additional worker also it increases
70 ## memory usage as each has it's own set of caches.
71 ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
72 ## than 8-10 unless for really big deployments .e.g 700-1000 users.
73 ## `instance_id = *` must be set in the [app:main] section below (which is the default)
74 ## when using more than 1 worker.
74 75 workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
77 #threads = 1
78 ## process name
76 ## process name visible in process list
79 77 proc_name = rhodecode
80 78 ## type of worker class, one of sync, gevent
81 79 ## recommended for bigger setup is using of of other than sync one
82 80 worker_class = gevent
83 81 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
82 worker_connections = 10
85 83 ## max number of requests that worker will handle before being gracefully
86 84 ## restarted, could prevent memory leaks
87 85 max_requests = 1000
@@ -103,6 +101,11 b' use = egg:PasteDeploy#prefix'
103 101 prefix = /
104 102
105 103 [app:main]
104 ## The %(here)s variable will be replaced with the absolute path of parent directory
105 ## of this file
106 ## In addition ENVIRONMENT variables usage is possible, e.g
107 ## sqlalchemy.db1.url = {ENV_RC_DB_URL}
108
106 109 use = egg:rhodecode-enterprise-ce
107 110
108 111 ## enable proxy prefix middleware, defined above
@@ -123,12 +126,12 b' gzip_responses = false'
123 126 ## autogenerate javascript routes file on startup
124 127 generate_js_files = false
125 128
126 ## Optional Languages
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
129 ## System global default language.
130 ## All available languages: en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
128 131 lang = en
129 132
130 ## perform a full repository scan on each server start, this should be
131 ## set to false after first startup, to allow faster server restarts.
133 ## Perform a full repository scan and import on each server start.
134 ## Settings this to true could lead to very long startup time.
132 135 startup.import_repos = false
133 136
134 137 ## Uncomment and set this path to use archive download cache.
@@ -142,23 +145,23 b' startup.import_repos = false'
142 145 ## SSH calls. Set this for events to receive proper url for SSH calls.
143 146 app.base_url = http://rhodecode.local
144 147
145 ## change this to unique ID for security
148 ## Unique application ID. Should be a random unique string for security.
146 149 app_instance_uuid = rc-production
147 150
148 ## cut off limit for large diffs (size in bytes). If overall diff size on
151 ## Cut off limit for large diffs (size in bytes). If overall diff size on
149 152 ## commit, or pull request exceeds this limit this diff will be displayed
150 153 ## partially. E.g 512000 == 512Kb
151 154 cut_off_limit_diff = 512000
152 155
153 ## cut off limit for large files inside diffs (size in bytes). Each individual
156 ## Cut off limit for large files inside diffs (size in bytes). Each individual
154 157 ## file inside diff which exceeds this limit will be displayed partially.
155 158 ## E.g 128000 == 128Kb
156 159 cut_off_limit_file = 128000
157 160
158 ## use cache version of scm repo everywhere
161 ## use cached version of vcs repositories everywhere. Recommended to be `true`
159 162 vcs_full_cache = true
160 163
161 ## force https in RhodeCode, fixes https redirects, assumes it's always https
164 ## Force https in RhodeCode, fixes https redirects, assumes it's always https.
162 165 ## Normally this is controlled by proper http flags sent from http server
163 166 force_https = false
164 167
@@ -205,7 +208,7 b' gist_alias_url ='
205 208 # GistView:*
206 209 api_access_controllers_whitelist =
207 210
208 ## default encoding used to convert from and to unicode
211 ## Default encoding used to convert from and to unicode
209 212 ## can be also a comma separated list of encoding in case of mixed encodings
210 213 default_encoding = UTF-8
211 214
@@ -252,8 +255,8 b' allow_repo_location_change = true'
252 255 ## allows to setup custom hooks in settings page
253 256 allow_custom_hooks_settings = true
254 257
255 ## generated license token, goto license page in RhodeCode settings to obtain
256 ## new token
258 ## Generated license token required for EE edition license.
259 ## New generated token value can be found in Admin > settings > license page.
257 260 license_token =
258 261
259 262 ## supervisor connection uri, for managing supervisor and logs.
@@ -283,65 +286,66 b' celery.max_tasks_per_child = 100'
283 286 ## tasks will never be sent to the queue, but executed locally instead.
284 287 celery.task_always_eager = false
285 288
286 ####################################
287 ### BEAKER CACHE ####
288 ####################################
289 # default cache dir for templates. Putting this into a ramdisk
290 ## can boost performance, eg. %(here)s/data_ramdisk
289 #####################################
290 ### DOGPILE CACHE ####
291 #####################################
292 ## Default cache dir for caches. Putting this into a ramdisk
293 ## can boost performance, eg. /tmpfs/data_ramdisk, however this directory might require
294 ## large amount of space
291 295 cache_dir = %(here)s/data
292 296
293 ## locking and default file storage for Beaker. Putting this into a ramdisk
294 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
295 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
296 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
297
298 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
297 ## `cache_perms` cache settings for permission tree, auth TTL.
298 rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
299 rc_cache.cache_perms.expiration_time = 300
299 300
300 beaker.cache.super_short_term.type = memory
301 beaker.cache.super_short_term.expire = 10
302 beaker.cache.super_short_term.key_length = 256
301 ## alternative `cache_perms` redis backend with distributed lock
302 #rc_cache.cache_perms.backend = dogpile.cache.rc.redis
303 #rc_cache.cache_perms.expiration_time = 300
304 ## redis_expiration_time needs to be greater then expiration_time
305 #rc_cache.cache_perms.arguments.redis_expiration_time = 7200
306 #rc_cache.cache_perms.arguments.socket_timeout = 30
307 #rc_cache.cache_perms.arguments.host = localhost
308 #rc_cache.cache_perms.arguments.port = 6379
309 #rc_cache.cache_perms.arguments.db = 0
310 #rc_cache.cache_perms.arguments.distributed_lock = true
303 311
304 beaker.cache.short_term.type = memory
305 beaker.cache.short_term.expire = 60
306 beaker.cache.short_term.key_length = 256
307
308 beaker.cache.long_term.type = memory
309 beaker.cache.long_term.expire = 36000
310 beaker.cache.long_term.key_length = 256
312 ## `cache_repo` cache settings for FileTree, Readme, RSS FEEDS
313 rc_cache.cache_repo.backend = dogpile.cache.rc.file_namespace
314 rc_cache.cache_repo.expiration_time = 2592000
311 315
312 beaker.cache.sql_cache_short.type = memory
313 beaker.cache.sql_cache_short.expire = 10
314 beaker.cache.sql_cache_short.key_length = 256
316 ## alternative `cache_repo` redis backend with distributed lock
317 #rc_cache.cache_repo.backend = dogpile.cache.rc.redis
318 #rc_cache.cache_repo.expiration_time = 2592000
319 ## redis_expiration_time needs to be greater then expiration_time
320 #rc_cache.cache_repo.arguments.redis_expiration_time = 2678400
321 #rc_cache.cache_repo.arguments.socket_timeout = 30
322 #rc_cache.cache_repo.arguments.host = localhost
323 #rc_cache.cache_repo.arguments.port = 6379
324 #rc_cache.cache_repo.arguments.db = 1
325 #rc_cache.cache_repo.arguments.distributed_lock = true
315 326
316 ## default is memory cache, configure only if required
317 ## using multi-node or multi-worker setup
318 #beaker.cache.auth_plugins.type = ext:database
319 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
320 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
321 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
322 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
323 #beaker.cache.auth_plugins.sa.pool_size = 10
324 #beaker.cache.auth_plugins.sa.max_overflow = 0
327 ## cache settings for SQL queries, this needs to use memory type backend
328 rc_cache.sql_cache_short.backend = dogpile.cache.rc.memory_lru
329 rc_cache.sql_cache_short.expiration_time = 30
325 330
326 beaker.cache.repo_cache_long.type = memorylru_base
327 beaker.cache.repo_cache_long.max_items = 4096
328 beaker.cache.repo_cache_long.expire = 2592000
331 ## `cache_repo_longterm` cache for repo object instances, this needs to use memory
332 ## type backend as the objects kept are not pickle serializable
333 rc_cache.cache_repo_longterm.backend = dogpile.cache.rc.memory_lru
334 ## by default we use 96H, this is using invalidation on push anyway
335 rc_cache.cache_repo_longterm.expiration_time = 345600
336 ## max items in LRU cache, reduce this number to save memory, and expire last used
337 ## cached objects
338 rc_cache.cache_repo_longterm.max_size = 10000
329 339
330 ## default is memorylru_base cache, configure only if required
331 ## using multi-node or multi-worker setup
332 #beaker.cache.repo_cache_long.type = ext:memcached
333 #beaker.cache.repo_cache_long.url = localhost:11211
334 #beaker.cache.repo_cache_long.expire = 1209600
335 #beaker.cache.repo_cache_long.key_length = 256
336 340
337 341 ####################################
338 342 ### BEAKER SESSION ####
339 343 ####################################
340 344
341 345 ## .session.type is type of storage options for the session, current allowed
342 ## types are file, ext:memcached, ext:database, and memory (default).
346 ## types are file, ext:memcached, ext:redis, ext:database, and memory (default).
343 347 beaker.session.type = file
344 beaker.session.data_dir = %(here)s/data/sessions/data
348 beaker.session.data_dir = %(here)s/data/sessions
345 349
346 350 ## db based session, fast, and allows easy management over logged in users
347 351 #beaker.session.type = ext:database
@@ -484,6 +488,9 b' set debug = false'
484 488 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
485 489 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
486 490 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
491 # pymysql is an alternative driver for MySQL, use in case of problems with default one
492 #sqlalchemy.db1.url = mysql+pymysql://root:qweqwe@localhost/rhodecode
493
487 494 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
488 495
489 496 # see sqlalchemy docs for other advanced settings
@@ -503,6 +510,9 b' sqlalchemy.db1.convert_unicode = true'
503 510 ## which defaults to five.
504 511 #sqlalchemy.db1.max_overflow = 10
505 512
513 ## Connection check ping, used to detect broken database connections
514 ## could be enabled to better handle cases if MySQL has gone away errors
515 #sqlalchemy.db1.ping_connection = true
506 516
507 517 ##################
508 518 ### VCS CONFIG ###
@@ -517,15 +527,17 b' vcs.server.protocol = http'
517 527
518 528 ## Push/Pull operations protocol, available options are:
519 529 ## `http` - use http-rpc backend (default)
520 ##
521 530 vcs.scm_app_implementation = http
522 531
523 532 ## Push/Pull operations hooks protocol, available options are:
524 533 ## `http` - use http-rpc backend (default)
525 534 vcs.hooks.protocol = http
535 ## Host on which this instance is listening for hooks. If vcsserver is in other location
536 ## this should be adjusted.
537 vcs.hooks.host = 127.0.0.1
526 538
527 539 vcs.server.log_level = info
528 ## Start VCSServer with this instance as a subprocess, usefull for development
540 ## Start VCSServer with this instance as a subprocess, useful for development
529 541 vcs.start_server = false
530 542
531 543 ## List of enabled VCS backends, available options are:
@@ -608,7 +620,7 b' custom.conf = 1'
608 620 ### LOGGING CONFIGURATION ####
609 621 ################################
610 622 [loggers]
611 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery
623 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
612 624
613 625 [handlers]
614 626 keys = console, console_sql
@@ -664,6 +676,9 b' level = INFO'
664 676 formatter = generic
665 677
666 678 [handler_console_sql]
679 # "level = DEBUG" logs SQL queries and results.
680 # "level = INFO" logs SQL queries.
681 # "level = WARN" logs neither. (Recommended for production systems.)
667 682 class = StreamHandler
668 683 args = (sys.stderr, )
669 684 level = WARN
@@ -685,5 +700,5 b' datefmt = %Y-%m-%d %H:%M:%S'
685 700
686 701 [formatter_color_formatter_sql]
687 702 class = rhodecode.lib.logging_formatter.ColorFormatterSql
688 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
703 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
689 704 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,41 +1,40 b''
1 1 # Nix environment for the community edition
2 2 #
3 # This shall be as lean as possible, just producing the Enterprise
3 # This shall be as lean as possible, just producing the enterprise-ce
4 4 # derivation. For advanced tweaks to pimp up the development environment we use
5 5 # "shell.nix" so that it does not have to clutter this file.
6 #
7 # Configuration, set values in "~/.nixpkgs/config.nix".
8 # example
9 # {
10 # # Thoughts on how to configure the dev environment
11 # rc = {
12 # codeInternalUrl = "https://usr:token@internal-code.rhodecode.com";
13 # sources = {
14 # rhodecode-vcsserver = "/home/user/work/rhodecode-vcsserver";
15 # rhodecode-enterprise-ce = "/home/user/work/rhodecode-enterprise-ce";
16 # rhodecode-enterprise-ee = "/home/user/work/rhodecode-enterprise-ee";
17 # };
18 # };
19 # }
6 20
7 21 args@
8 22 { pythonPackages ? "python27Packages"
9 23 , pythonExternalOverrides ? self: super: {}
10 , doCheck ? true
24 , doCheck ? false
11 25 , ...
12 26 }:
13 27
14 28 let
15
16 29 # Use nixpkgs from args or import them. We use this indirect approach
17 30 # through args to be able to use the name `pkgs` for our customized packages.
18 31 # Otherwise we will end up with an infinite recursion.
19 nixpkgs = args.pkgs or (import <nixpkgs> { });
32 pkgs = args.pkgs or (import <nixpkgs> { });
20 33
21 # johbo: Interim bridge which allows us to build with the upcoming
22 # nixos.16.09 branch (unstable at the moment of writing this note) and the
23 # current stable nixos-16.03.
24 backwardsCompatibleFetchgit = { ... }@args:
25 let
26 origSources = nixpkgs.fetchgit args;
27 in
28 nixpkgs.lib.overrideDerivation origSources (oldAttrs: {
29 NIX_PREFETCH_GIT_CHECKOUT_HOOK = ''
30 find $out -name '.git*' -print0 | xargs -0 rm -rf
31 '';
32 });
33
34 # Create a customized version of nixpkgs which should be used throughout the
35 # rest of this file.
36 pkgs = nixpkgs.overridePackages (self: super: {
37 fetchgit = backwardsCompatibleFetchgit;
38 });
34 # Works with the new python-packages, still can fallback to the old
35 # variant.
36 basePythonPackagesUnfix = basePythonPackages.__unfix__ or (
37 self: basePythonPackages.override (a: { inherit self; }));
39 38
40 39 # Evaluates to the last segment of a file system path.
41 40 basename = path: with pkgs.lib; last (splitString "/" path);
@@ -46,7 +45,7 b' let'
46 45 ext = last (splitString "." path);
47 46 in
48 47 !builtins.elem (basename path) [
49 ".git" ".hg" "__pycache__" ".eggs"
48 ".git" ".hg" "__pycache__" ".eggs" ".idea" ".dev"
50 49 "bower_components" "node_modules"
51 50 "build" "data" "result" "tmp"] &&
52 51 !builtins.elem ext ["egg-info" "pyc"] &&
@@ -54,18 +53,20 b' let'
54 53 # it would still be good to restore it since we want to ignore "result-*".
55 54 !hasPrefix "result" path;
56 55
57 basePythonPackages = with builtins; if isAttrs pythonPackages
58 then pythonPackages
59 else getAttr pythonPackages pkgs;
56 sources =
57 let
58 inherit (pkgs.lib) all isString attrValues;
59 sourcesConfig = pkgs.config.rc.sources or {};
60 in
61 # Ensure that sources are configured as strings. Using a path
62 # would result in a copy into the nix store.
63 assert all isString (attrValues sourcesConfig);
64 sourcesConfig;
60 65
61 buildBowerComponents =
62 pkgs.buildBowerComponents or
63 (import ./pkgs/backport-16.03-build-bower-components.nix { inherit pkgs; });
64
65 sources = pkgs.config.rc.sources or {};
66 version = builtins.readFile ./rhodecode/VERSION;
66 version = builtins.readFile "${rhodecode-enterprise-ce-src}/rhodecode/VERSION";
67 67 rhodecode-enterprise-ce-src = builtins.filterSource src-filter ./.;
68 68
69 buildBowerComponents = pkgs.buildBowerComponents;
69 70 nodeEnv = import ./pkgs/node-default.nix {
70 71 inherit pkgs;
71 72 };
@@ -77,133 +78,145 b' let'
77 78 src = rhodecode-enterprise-ce-src;
78 79 };
79 80
80 pythonGeneratedPackages = self: basePythonPackages.override (a: {
81 inherit self;
82 })
83 // (scopedImport {
84 self = self;
85 super = basePythonPackages;
86 inherit pkgs;
87 inherit (pkgs) fetchurl fetchgit;
88 } ./pkgs/python-packages.nix);
81 rhodecode-testdata-src = sources.rhodecode-testdata or (
82 pkgs.fetchhg {
83 url = "https://code.rhodecode.com/upstream/rc_testdata";
84 rev = "v0.10.0";
85 sha256 = "0zn9swwvx4vgw4qn8q3ri26vvzgrxn15x6xnjrysi1bwmz01qjl0";
86 });
89 87
90 pythonOverrides = import ./pkgs/python-packages-overrides.nix {
91 inherit
92 basePythonPackages
93 pkgs;
88 rhodecode-testdata = import "${rhodecode-testdata-src}/default.nix" {
89 inherit
90 doCheck
91 pkgs
92 pythonPackages;
94 93 };
95 94
96 95 pythonLocalOverrides = self: super: {
97 96 rhodecode-enterprise-ce =
98 97 let
99 98 linkNodeAndBowerPackages = ''
100 echo "Export RhodeCode CE path"
101 99 export RHODECODE_CE_PATH=${rhodecode-enterprise-ce-src}
102 echo "Link node packages"
100
101 echo "[BEGIN]: Link node packages"
103 102 rm -fr node_modules
104 103 mkdir node_modules
105 104 # johbo: Linking individual packages allows us to run "npm install"
106 105 # inside of a shell to try things out. Re-entering the shell will
107 106 # restore a clean environment.
108 107 ln -s ${nodeDependencies}/lib/node_modules/* node_modules/
108 echo "[DONE]: Link node packages"
109 109
110 echo "DONE: Link node packages"
111
112 echo "Link bower packages"
110 echo "[BEGIN]: Link bower packages"
113 111 rm -fr bower_components
114 112 mkdir bower_components
113 ln -s ${bowerComponents}/bower_components/* bower_components/
114 echo "[DONE]: Link bower packages"
115 '';
115 116
116 ln -s ${bowerComponents}/bower_components/* bower_components/
117 echo "DONE: Link bower packages"
118 '';
117 releaseName = "RhodeCodeEnterpriseCE-${version}";
119 118 in super.rhodecode-enterprise-ce.override (attrs: {
120
121 119 inherit
122 120 doCheck
123 121 version;
122
124 123 name = "rhodecode-enterprise-ce-${version}";
125 releaseName = "RhodeCodeEnterpriseCE-${version}";
124 releaseName = releaseName;
126 125 src = rhodecode-enterprise-ce-src;
127 126 dontStrip = true; # prevent strip, we don't need it.
128 127
129 buildInputs =
130 attrs.buildInputs ++
131 (with self; [
132 pkgs.nodePackages.bower
133 pkgs.nodePackages.grunt-cli
134 pkgs.subversion
135 pytest-catchlog
136 rhodecode-testdata
137 ]);
138
139 #TODO: either move this into overrides, OR use the new machanics from
140 # pip2nix and requiremtn.txt file
141 propagatedBuildInputs = attrs.propagatedBuildInputs ++ (with self; [
142 rhodecode-tools
143 ]);
144
145 # TODO: johbo: Make a nicer way to expose the parts. Maybe
146 # pkgs/default.nix?
128 # expose following attributed outside
147 129 passthru = {
148 130 inherit
131 rhodecode-testdata
149 132 bowerComponents
150 133 linkNodeAndBowerPackages
151 134 myPythonPackagesUnfix
152 pythonLocalOverrides;
135 pythonLocalOverrides
136 pythonCommunityOverrides;
137
153 138 pythonPackages = self;
154 139 };
155 140
141 buildInputs =
142 attrs.buildInputs or [] ++ [
143 rhodecode-testdata
144 pkgs.nodePackages.bower
145 pkgs.nodePackages.grunt-cli
146 ];
147
148 #NOTE: option to inject additional propagatedBuildInputs
149 propagatedBuildInputs =
150 attrs.propagatedBuildInputs or [] ++ [
151
152 ];
153
156 154 LC_ALL = "en_US.UTF-8";
157 155 LOCALE_ARCHIVE =
158 if pkgs.stdenv ? glibc
156 if pkgs.stdenv.isLinux
159 157 then "${pkgs.glibcLocales}/lib/locale/locale-archive"
160 158 else "";
161 159
160 # Add bin directory to path so that tests can find 'rhodecode'.
162 161 preCheck = ''
163 162 export PATH="$out/bin:$PATH"
164 163 '';
165 164
165 # custom check phase for testing
166 checkPhase = ''
167 runHook preCheck
168 PYTHONHASHSEED=random py.test -vv -p no:sugar -r xw --cov-config=.coveragerc --cov=rhodecode --cov-report=term-missing rhodecode
169 runHook postCheck
170 '';
171
166 172 postCheck = ''
167 rm -rf $out/lib/${self.python.libPrefix}/site-packages/pytest_pylons
173 echo "Cleanup of rhodecode/tests"
168 174 rm -rf $out/lib/${self.python.libPrefix}/site-packages/rhodecode/tests
169 175 '';
170 176
171 preBuild = linkNodeAndBowerPackages + ''
177 preBuild = ''
178
179 echo "Building frontend assets"
180 ${linkNodeAndBowerPackages}
172 181 grunt
173 182 rm -fr node_modules
174 183 '';
175 184
176 185 postInstall = ''
177 echo "Writing meta information for rccontrol to nix-support/rccontrol"
186 echo "Writing enterprise-ce meta information for rccontrol to nix-support/rccontrol"
178 187 mkdir -p $out/nix-support/rccontrol
179 188 cp -v rhodecode/VERSION $out/nix-support/rccontrol/version
180 echo "DONE: Meta information for rccontrol written"
189 echo "[DONE]: enterprise-ce meta information for rccontrol written"
190
191 mkdir -p $out/etc
192 cp configs/production.ini $out/etc
193 echo "[DONE]: saved enterprise-ce production.ini into $out/etc"
181 194
182 195 # python based programs need to be wrapped
196 mkdir -p $out/bin
197 # rhodecode-tools
198 ln -s ${self.rhodecode-tools}/bin/rhodecode-* $out/bin/
199
200 # required binaries from dependencies
201 #ln -s ${self.python}/bin/python $out/bin
183 202 ln -s ${self.pyramid}/bin/* $out/bin/
184 203 ln -s ${self.gunicorn}/bin/gunicorn $out/bin/
185 204 ln -s ${self.supervisor}/bin/supervisor* $out/bin/
186 ln -s ${self.PasteScript}/bin/paster $out/bin/
205 ln -s ${self.pastescript}/bin/paster $out/bin/
187 206 ln -s ${self.channelstream}/bin/channelstream $out/bin/
188 207 ln -s ${self.celery}/bin/celery $out/bin/
208 echo "[DONE]: created symlinks into $out/bin"
189 209
190 # rhodecode-tools
191 ln -s ${self.rhodecode-tools}/bin/rhodecode-* $out/bin/
192
193 # note that condition should be restricted when adding further tools
194 210 for file in $out/bin/*;
195 211 do
196 212 wrapProgram $file \
197 --prefix PATH : $PATH \
198 --prefix PYTHONPATH : $PYTHONPATH \
199 --set PYTHONHASHSEED random
213 --prefix PATH : $PATH \
214 --prefix PYTHONPATH : $PYTHONPATH \
215 --set PYTHONHASHSEED random
200 216 done
201 217
202 mkdir $out/etc
203 cp configs/production.ini $out/etc
218 echo "[DONE]: enterprise-ce binary wrapping"
204 219
205
206 # TODO: johbo: Make part of ac-tests
207 220 if [ ! -f rhodecode/public/js/scripts.js ]; then
208 221 echo "Missing scripts.js"
209 222 exit 1
@@ -213,31 +226,33 b' let'
213 226 exit 1
214 227 fi
215 228 '';
216
217 229 });
218 230
219 rhodecode-testdata = import "${rhodecode-testdata-src}/default.nix" {
220 inherit
221 doCheck
222 pkgs
223 pythonPackages;
224 };
225
226 231 };
227 232
228 rhodecode-testdata-src = sources.rhodecode-testdata or (
229 pkgs.fetchhg {
230 url = "https://code.rhodecode.com/upstream/rc_testdata";
231 rev = "v0.10.0";
232 sha256 = "0zn9swwvx4vgw4qn8q3ri26vvzgrxn15x6xnjrysi1bwmz01qjl0";
233 });
233 basePythonPackages = with builtins;
234 if isAttrs pythonPackages then
235 pythonPackages
236 else
237 getAttr pythonPackages pkgs;
238
239 pythonGeneratedPackages = import ./pkgs/python-packages.nix {
240 inherit pkgs;
241 inherit (pkgs) fetchurl fetchgit fetchhg;
242 };
243
244 pythonCommunityOverrides = import ./pkgs/python-packages-overrides.nix {
245 inherit pkgs basePythonPackages;
246 };
234 247
235 248 # Apply all overrides and fix the final package set
236 249 myPythonPackagesUnfix = with pkgs.lib;
237 250 (extends pythonExternalOverrides
238 251 (extends pythonLocalOverrides
239 (extends pythonOverrides
240 pythonGeneratedPackages)));
252 (extends pythonCommunityOverrides
253 (extends pythonGeneratedPackages
254 basePythonPackagesUnfix))));
255
241 256 myPythonPackages = (pkgs.lib.fix myPythonPackagesUnfix);
242 257
243 258 in myPythonPackages.rhodecode-enterprise-ce
@@ -1,4 +1,9 b''
1 # generating packages
2 nix-shell pkgs/shell-generate.nix
3 cd docs
4 pip2nix generate
5
1 6 # building the docs
2 7 cd docs
3 8 nix-build default.nix -o result
4 make clean html No newline at end of file
9 make clean html
@@ -88,17 +88,21 b' want to index:'
88 88 (venv)$ rhodecode-index --instance-name=enterprise-1
89 89
90 90 # Using default installation
91 $ /home/user/.rccontrol/enterprise-4/profile/bin/rhodecode-index \
92 --instance-name=enterprise-4
91 $ /home/user/.rccontrol/enterprise-1/profile/bin/rhodecode-index \
92 --instance-name=enterprise-1
93 93
94 94 # Using a custom mapping file
95 $ /home/user/.rccontrol/enterprise-4/profile/bin/rhodecode-index \
96 --instance-name=enterprise-4 \
97 --mapping=/home/user/.rccontrol/enterprise-4/mapping.ini
95 $ /home/user/.rccontrol/enterprise-1/profile/bin/rhodecode-index \
96 --instance-name=enterprise-1 \
97 --mapping=/home/user/.rccontrol/enterprise-1/mapping.ini
98 98
99 99 .. note::
100 100
101 |RCT| require |PY| 2.7 to run.
101 In case of often indexing the index may become fragmented. Most often a result of that
102 is error about `too many open files`. To fix this indexer needs to be executed with
103 --optimize flag. E.g `rhodecode-index --instance-name=enterprise-1 --optimize`
104 This should be executed regularly, once a week is recommended.
105
102 106
103 107 .. _set-index:
104 108
@@ -12,7 +12,7 b' if there are lots of session files.'
12 12
13 13 Therefore, in a large scale deployment, to give better performance,
14 14 scalability, and maintainability we recommend switching from file-based
15 sessions to database-based user sessions or memcached sessions.
15 sessions to database-based user sessions or Redis based sessions.
16 16
17 17 To switch to database-based user sessions uncomment the following section in
18 18 your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
@@ -41,14 +41,20 b' and make sure you comment out the file b'
41 41 #beaker.session.data_dir = %(here)s/data/sessions/data
42 42
43 43
44 To switch to memcached-based user sessions uncomment the following section in
44 The `table_name` will be automatically created on specified database if it isn't yet existing.
45 Database specified in the `beaker.session.sa.url` can be the same that RhodeCode
46 uses, or if required it can be a different one. We recommend to use the same database.
47
48
49
50 To switch to reds-based user sessions uncomment the following section in
45 51 your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
46 52
47 53 .. code-block:: ini
48 54
49 ## memcached sessions
50 beaker.session.type = ext:memcached
51 beaker.session.url = localhost:11211
55 ## redis sessions
56 beaker.session.type = ext:redis
57 beaker.session.url = localhost:6379
52 58
53 59
54 60 and make sure you comment out the file based sessions.
@@ -83,7 +83,7 b' comment_pull_request'
83 83 create_pull_request
84 84 -------------------
85 85
86 .. py:function:: create_pull_request(apiuser, source_repo, target_repo, source_ref, target_ref, title, description=<Optional:''>, reviewers=<Optional:None>)
86 .. py:function:: create_pull_request(apiuser, source_repo, target_repo, source_ref, target_ref, title=<Optional:''>, description=<Optional:''>, description_renderer=<Optional:''>, reviewers=<Optional:None>)
87 87
88 88 Creates a new pull request.
89 89
@@ -104,10 +104,14 b' create_pull_request'
104 104 :type source_ref: str
105 105 :param target_ref: Set the target ref name.
106 106 :type target_ref: str
107 :param title: Set the pull request title.
107 :param title: Optionally Set the pull request title, it's generated otherwise
108 108 :type title: str
109 109 :param description: Set the pull request description.
110 110 :type description: Optional(str)
111 :type description_renderer: Optional(str)
112 :param description_renderer: Set pull request renderer for the description.
113 It should be 'rst', 'markdown' or 'plain'. If not give default
114 system renderer will be used
111 115 :param reviewers: Set the new pull request reviewers list.
112 116 Reviewer defined by review rules will be added automatically to the
113 117 defined list.
@@ -368,7 +372,7 b' merge_pull_request'
368 372 update_pull_request
369 373 -------------------
370 374
371 .. py:function:: update_pull_request(apiuser, pullrequestid, repoid=<Optional:None>, title=<Optional:''>, description=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>)
375 .. py:function:: update_pull_request(apiuser, pullrequestid, repoid=<Optional:None>, title=<Optional:''>, description=<Optional:''>, description_renderer=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>)
372 376
373 377 Updates a pull request.
374 378
@@ -382,6 +386,9 b' update_pull_request'
382 386 :type title: str
383 387 :param description: Update pull request description.
384 388 :type description: Optional(str)
389 :type description_renderer: Optional(str)
390 :param description_renderer: Update pull request renderer for the description.
391 It should be 'rst', 'markdown' or 'plain'
385 392 :param reviewers: Update pull request reviewers list with new value.
386 393 :type reviewers: Optional(list)
387 394 Accepts username strings or objects of the format:
@@ -32,6 +32,7 b' import common'
32 32 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33 33 # ones.
34 34 extensions = [
35 'sphinx.ext.autodoc',
35 36 'sphinx.ext.intersphinx',
36 37 'sphinx.ext.todo',
37 38 'sphinx.ext.imgmath'
@@ -42,13 +43,6 b' intersphinx_mapping = {'
42 43 'control': ('https://docs.rhodecode.com/RhodeCode-Control/', None),
43 44 }
44 45
45 if tags.has('dev'):
46 intersphinx_mapping.update({
47 'enterprise': ('https://ci.rhodecode.com/documentation/Momentum/', None),
48 'control': ('https://ci.rhodecode.com/documentation/Control/', None),
49 })
50
51
52 46 # Add any paths that contain templates here, relative to this directory.
53 47 templates_path = ['_templates']
54 48
@@ -65,11 +59,12 b" master_doc = 'index'"
65 59 # |version| and |release|, also used in various other places throughout the
66 60 # built documents.
67 61
68 # TODO: johbo: Move into common package for documentation utilities
62
69 63 def _get_version():
70 64 with open('../rhodecode/VERSION') as f:
71 65 return f.read().strip()
72 66
67
73 68 # The full version, including alpha/beta/rc tags.
74 69 release = _get_version()
75 70 # The short X.Y version.
@@ -47,7 +47,7 b' Switch nix to the latest STABLE channel'
47 47
48 48 run::
49 49
50 nix-channel --add https://nixos.org/channels/nixos-16.03 nixpkgs
50 nix-channel --add https://nixos.org/channels/nixos-18.03 nixpkgs
51 51
52 52 Followed by::
53 53
@@ -5,249 +5,215 b' let'
5 5
6 6 pkgs = import <nixpkgs> { inherit system; };
7 7
8 inherit (pkgs) fetchurl fetchgit;
8 inherit (pkgs) fetchurl;
9 9
10 10 buildPythonPackage = pkgs.python27Packages.buildPythonPackage;
11 11 python = pkgs.python27Packages.python;
12 12
13 Jinja2 = buildPythonPackage rec {
14 name = "Jinja2-2.9.6";
15 buildInputs = [];
13
14 alabaster = buildPythonPackage {
15 name = "alabaster-0.7.11";
16 doCheck = false;
17 src = fetchurl {
18 url = "https://files.pythonhosted.org/packages/3f/46/9346ea429931d80244ab7f11c4fce83671df0b7ae5a60247a2b588592c46/alabaster-0.7.11.tar.gz";
19 sha256 = "1mvm69xsn5xf1jc45kdq1mn0yq0pfn54mv2jcww4s1vwqx6iyfxn";
20 };
21 };
22 babel = buildPythonPackage {
23 name = "babel-2.6.0";
16 24 doCheck = false;
17 propagatedBuildInputs = [MarkupSafe];
25 propagatedBuildInputs = [
26 pytz
27 ];
28 src = fetchurl {
29 url = "https://files.pythonhosted.org/packages/be/cc/9c981b249a455fa0c76338966325fc70b7265521bad641bf2932f77712f4/Babel-2.6.0.tar.gz";
30 sha256 = "08rxmbx2s4irp0w0gmn498vns5xy0fagm0fg33xa772jiks51flc";
31 };
32 };
33 certifi = buildPythonPackage {
34 name = "certifi-2018.8.24";
35 doCheck = false;
18 36 src = fetchurl {
19 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
20 md5 = "6411537324b4dba0956aaa8109f3c77b";
37 url = "https://files.pythonhosted.org/packages/e1/0f/f8d5e939184547b3bdc6128551b831a62832713aa98c2ccdf8c47ecc7f17/certifi-2018.8.24.tar.gz";
38 sha256 = "0f0nhrj9mlrf79iway4578wrsgmjh0fmacl9zv8zjckdy7b90rip";
39 };
40 };
41 chardet = buildPythonPackage {
42 name = "chardet-3.0.4";
43 doCheck = false;
44 src = fetchurl {
45 url = "https://files.pythonhosted.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz";
46 sha256 = "1bpalpia6r5x1kknbk11p1fzph56fmmnp405ds8icksd3knr5aw4";
47 };
48 };
49 docutils = buildPythonPackage {
50 name = "docutils-0.14";
51 doCheck = false;
52 src = fetchurl {
53 url = "https://files.pythonhosted.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
54 sha256 = "0x22fs3pdmr42kvz6c654756wja305qv6cx1zbhwlagvxgr4xrji";
21 55 };
22 56 };
23
24 MarkupSafe = buildPythonPackage rec {
25 name = "MarkupSafe-1.0";
26 buildInputs = [];
57 idna = buildPythonPackage {
58 name = "idna-2.7";
59 doCheck = false;
60 src = fetchurl {
61 url = "https://files.pythonhosted.org/packages/65/c4/80f97e9c9628f3cac9b98bfca0402ede54e0563b56482e3e6e45c43c4935/idna-2.7.tar.gz";
62 sha256 = "05jam7d31767dr12x0rbvvs8lxnpb1mhdb2zdlfxgh83z6k3hjk8";
63 };
64 };
65 imagesize = buildPythonPackage {
66 name = "imagesize-1.1.0";
27 67 doCheck = false;
28 propagatedBuildInputs = [];
29 68 src = fetchurl {
30 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
31 md5 = "2fcedc9284d50e577b5192e8e3578355";
69 url = "https://files.pythonhosted.org/packages/41/f5/3cf63735d54aa9974e544aa25858d8f9670ac5b4da51020bbfc6aaade741/imagesize-1.1.0.tar.gz";
70 sha256 = "1dg3wn7qpwmhgqc0r9na2ding1wif9q5spz3j9zn2riwphc2k0zk";
71 };
72 };
73 jinja2 = buildPythonPackage {
74 name = "jinja2-2.9.6";
75 doCheck = false;
76 propagatedBuildInputs = [
77 markupsafe
78 ];
79 src = fetchurl {
80 url = "https://files.pythonhosted.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
81 sha256 = "1zzrkywhziqffrzks14kzixz7nd4yh2vc0fb04a68vfd2ai03anx";
32 82 };
33 83 };
34
35 Pygments = buildPythonPackage {
36 name = "Pygments-2.2.0";
37 buildInputs = [];
84 markupsafe = buildPythonPackage {
85 name = "markupsafe-1.0";
86 doCheck = false;
87 src = fetchurl {
88 url = "https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
89 sha256 = "0rdn1s8x9ni7ss8rfiacj7x1085lx8mh2zdwqslnw8xc3l4nkgm6";
90 };
91 };
92 packaging = buildPythonPackage {
93 name = "packaging-17.1";
38 94 doCheck = false;
39 propagatedBuildInputs = [];
95 propagatedBuildInputs = [
96 pyparsing
97 six
98 ];
40 99 src = fetchurl {
41 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
42 md5 = "13037baca42f16917cbd5ad2fab50844";
100 url = "https://files.pythonhosted.org/packages/77/32/439f47be99809c12ef2da8b60a2c47987786d2c6c9205549dd6ef95df8bd/packaging-17.1.tar.gz";
101 sha256 = "0nrpayk8kij1zm9sjnk38ldz3a6705ggvw8ljylqbrb4vmqbf6gh";
102 };
103 };
104 pygments = buildPythonPackage {
105 name = "pygments-2.2.0";
106 doCheck = false;
107 src = fetchurl {
108 url = "https://files.pythonhosted.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
109 sha256 = "1k78qdvir1yb1c634nkv6rbga8wv4289xarghmsbbvzhvr311bnv";
43 110 };
44 111 };
45
46 Sphinx = buildPythonPackage (rec {
47 name = "Sphinx-1.6.5";
112 pyparsing = buildPythonPackage {
113 name = "pyparsing-2.2.0";
114 doCheck = false;
48 115 src = fetchurl {
49 url = "https://pypi.python.org/packages/8b/7e/b188d9a3b9c938e736e02a74c1363c2888e095d770df2c72b4c312f9fdcb/Sphinx-1.6.5.tar.gz";
50 md5 = "cd73118c21ec610432e63e6421ec54f1";
116 url = "https://files.pythonhosted.org/packages/3c/ec/a94f8cf7274ea60b5413df054f82a8980523efd712ec55a59e7c3357cf7c/pyparsing-2.2.0.tar.gz";
117 sha256 = "016b9gh606aa44sq92jslm89bg874ia0yyiyb643fa6dgbsbqch8";
51 118 };
119 };
120 pytz = buildPythonPackage {
121 name = "pytz-2018.4";
122 doCheck = false;
123 src = fetchurl {
124 url = "https://files.pythonhosted.org/packages/10/76/52efda4ef98e7544321fd8d5d512e11739c1df18b0649551aeccfb1c8376/pytz-2018.4.tar.gz";
125 sha256 = "0jgpqx3kk2rhv81j1izjxvmx8d0x7hzs1857pgqnixic5wq2ar60";
126 };
127 };
128 requests = buildPythonPackage {
129 name = "requests-2.19.1";
130 doCheck = false;
52 131 propagatedBuildInputs = [
53 six
54 Jinja2
55 Pygments
56 docutils
57 snowballstemmer
58 babel
59 alabaster
60 imagesize
61 requests
62 setuptools
63 sphinxcontrib-websupport
64 typing
65
66 # special cases
67 pytz
68 sphinx_rtd_theme
69
132 chardet
133 idna
134 urllib3
135 certifi
70 136 ];
71 });
72
73 alabaster = buildPythonPackage rec {
74 name = "alabaster-0.7.10";
75 buildInputs = [];
137 src = fetchurl {
138 url = "https://files.pythonhosted.org/packages/54/1f/782a5734931ddf2e1494e4cd615a51ff98e1879cbe9eecbdfeaf09aa75e9/requests-2.19.1.tar.gz";
139 sha256 = "0snf8xxdzsgh1x2zv3vilvbrv9jbpmnfagzzb1rjmmvflckdh8pc";
140 };
141 };
142 six = buildPythonPackage {
143 name = "six-1.11.0";
76 144 doCheck = false;
77 propagatedBuildInputs = [];
78 145 src = fetchurl {
79 url = "https://pypi.python.org/packages/d0/a5/e3a9ad3ee86aceeff71908ae562580643b955ea1b1d4f08ed6f7e8396bd7/alabaster-0.7.10.tar.gz";
80 md5 = "7934dccf38801faa105f6e7b4784f493";
146 url = "https://files.pythonhosted.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
147 sha256 = "1scqzwc51c875z23phj48gircqjgnn3af8zy2izjwmnlxrxsgs3h";
148 };
149 };
150 snowballstemmer = buildPythonPackage {
151 name = "snowballstemmer-1.2.1";
152 doCheck = false;
153 src = fetchurl {
154 url = "https://files.pythonhosted.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz";
155 sha256 = "0a0idq4y5frv7qsg2x62jd7rd272749xk4x99misf5rcifk2d7wi";
81 156 };
82 157 };
83
84 babel = buildPythonPackage {
85 name = "babel-2.5.1";
86 buildInputs = [];
158 sphinx = buildPythonPackage {
159 name = "sphinx-1.7.8";
87 160 doCheck = false;
88 propagatedBuildInputs = [pytz];
161 propagatedBuildInputs = [
162 six
163 jinja2
164 pygments
165 docutils
166 snowballstemmer
167 babel
168 alabaster
169 imagesize
170 requests
171 setuptools
172 packaging
173 sphinxcontrib-websupport
174 typing
175 ];
89 176 src = fetchurl {
90 url = "https://pypi.python.org/packages/5a/22/63f1dbb8514bb7e0d0c8a85cc9b14506599a075e231985f98afd70430e1f/Babel-2.5.1.tar.gz";
91 md5 = "60228b3ce93a203357158b909afe8ae1";
177 url = "https://files.pythonhosted.org/packages/ac/54/4ef326d0c654da1ed91341a7a1f43efc18a8c770ddd2b8e45df97cb79d82/Sphinx-1.7.8.tar.gz";
178 sha256 = "1ryz0w4c31930f1br2sjwrxwx9cmsy7cqdb0d81g98n9bj250w50";
92 179 };
93 180 };
94
95 certifi = buildPythonPackage {
96 name = "certifi-2017.11.5";
97 buildInputs = [];
181 sphinx-rtd-theme = buildPythonPackage {
182 name = "sphinx-rtd-theme-0.4.1";
98 183 doCheck = false;
99 propagatedBuildInputs = [];
184 propagatedBuildInputs = [
185 sphinx
186 ];
100 187 src = fetchurl {
101 url = "https://pypi.python.org/packages/23/3f/8be01c50ed24a4bd6b8da799839066ce0288f66f5e11f0367323467f0cbc/certifi-2017.11.5.tar.gz";
102 md5 = "c15ac46ed1fe4b607ff3405928f9a992";
188 url = "https://files.pythonhosted.org/packages/f2/b0/a1933d792b806118ddbca6699f2e2c844d9b1b16e84a89d7effd5cd2a800/sphinx_rtd_theme-0.4.1.tar.gz";
189 sha256 = "1xkyqam8dzbjaymdyvkiif85m4y3jf8crdiwlgcfp8gqcj57aj9v";
103 190 };
104 191 };
105
106 chardet = buildPythonPackage {
107 name = "chardet-3.0.4";
108 buildInputs = [];
192 sphinxcontrib-websupport = buildPythonPackage {
193 name = "sphinxcontrib-websupport-1.1.0";
109 194 doCheck = false;
110 propagatedBuildInputs = [];
111 195 src = fetchurl {
112 url = "https://pypi.python.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz";
113 md5 = "7dd1ba7f9c77e32351b0a0cfacf4055c";
196 url = "https://files.pythonhosted.org/packages/07/7a/e74b06dce85555ffee33e1d6b7381314169ebf7e31b62c18fcb2815626b7/sphinxcontrib-websupport-1.1.0.tar.gz";
197 sha256 = "1ff3ix76xi1y6m99qxhaq5161ix9swwzydilvdya07mgbcvpzr4x";
114 198 };
115 199 };
116
117 docutils = buildPythonPackage {
118 name = "docutils-0.14";
119 buildInputs = [];
200 typing = buildPythonPackage {
201 name = "typing-3.6.6";
120 202 doCheck = false;
121 propagatedBuildInputs = [];
122 203 src = fetchurl {
123 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
124 md5 = "c53768d63db3873b7d452833553469de";
204 url = "https://files.pythonhosted.org/packages/bf/9b/2bf84e841575b633d8d91ad923e198a415e3901f228715524689495b4317/typing-3.6.6.tar.gz";
205 sha256 = "0ba9acs4awx15bf9v3nrs781msbd2nx826906nj6fqks2bvca9s0";
206 };
207 };
208 urllib3 = buildPythonPackage {
209 name = "urllib3-1.23";
210 doCheck = false;
211 src = fetchurl {
212 url = "https://files.pythonhosted.org/packages/3c/d2/dc5471622bd200db1cd9319e02e71bc655e9ea27b8e0ce65fc69de0dac15/urllib3-1.23.tar.gz";
213 sha256 = "1bvbd35q3zdcd7gsv38fwpizy7p06dr0154g5gfybrvnbvhwb2m6";
125 214 };
126 215 };
127 216
128 idna = buildPythonPackage {
129 name = "idna-2.6";
130 buildInputs = [];
131 doCheck = false;
132 propagatedBuildInputs = [];
133 src = fetchurl {
134 url = "https://pypi.python.org/packages/f4/bd/0467d62790828c23c47fc1dfa1b1f052b24efdf5290f071c7a91d0d82fd3/idna-2.6.tar.gz";
135 md5 = "c706e2790b016bd0ed4edd2d4ba4d147";
136 };
137 };
138
139 imagesize = buildPythonPackage {
140 name = "imagesize-0.7.1";
141 buildInputs = [];
142 doCheck = false;
143 propagatedBuildInputs = [];
144 src = fetchurl {
145 url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/imagesize-0.7.1.tar.gz";
146 md5 = "976148283286a6ba5f69b0f81aef8052";
147 };
148 };
149
150 pytz = buildPythonPackage {
151 name = "pytz-2017.3";
152 buildInputs = [];
153 doCheck = false;
154 propagatedBuildInputs = [];
155 src = fetchurl {
156 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
157 md5 = "7006b56c0d68a162d9fe57d4249c3171";
158 };
159 };
160
161 requests = buildPythonPackage {
162 name = "requests-2.18.4";
163 buildInputs = [];
164 doCheck = false;
165 propagatedBuildInputs = [chardet idna urllib3 certifi];
166 src = fetchurl {
167 url = "https://pypi.python.org/packages/b0/e1/eab4fc3752e3d240468a8c0b284607899d2fbfb236a56b7377a329aa8d09/requests-2.18.4.tar.gz";
168 md5 = "081412b2ef79bdc48229891af13f4d82";
169 };
170 };
171
172 six = buildPythonPackage {
173 name = "six-1.11.0";
174 buildInputs = [];
175 doCheck = false;
176 propagatedBuildInputs = [];
177 src = fetchurl {
178 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
179 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
180 };
181 };
182
183 snowballstemmer = buildPythonPackage {
184 name = "snowballstemmer-1.2.1";
185 buildInputs = [];
186 doCheck = false;
187 propagatedBuildInputs = [];
188 src = fetchurl {
189 url = "https://pypi.python.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz";
190 md5 = "643b019667a708a922172e33a99bf2fa";
191 };
192 };
193
194 sphinx-rtd-theme = buildPythonPackage {
195 name = "sphinx-rtd-theme-0.2.5b1";
196 buildInputs = [];
197 doCheck = false;
198 propagatedBuildInputs = [];
199 src = fetchurl {
200 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
201 md5 = "0923473a43bd2527f32151f195f2a521";
202 };
203 };
204
205 sphinxcontrib-websupport = buildPythonPackage {
206 name = "sphinxcontrib-websupport-1.0.1";
207 buildInputs = [];
208 doCheck = false;
209 propagatedBuildInputs = [];
210 src = fetchurl {
211 url = "https://pypi.python.org/packages/c5/6b/f0630436b931ad4f8331a9399ca18a7d447f0fcc0c7178fb56b1aee68d01/sphinxcontrib-websupport-1.0.1.tar.gz";
212 md5 = "84df26463b1ba65b07f926dbe2055665";
213 };
214 };
215
216 typing = buildPythonPackage {
217 name = "typing-3.6.2";
218 buildInputs = [];
219 doCheck = false;
220 propagatedBuildInputs = [];
221 src = fetchurl {
222 url = "https://pypi.python.org/packages/ca/38/16ba8d542e609997fdcd0214628421c971f8c395084085354b11ff4ac9c3/typing-3.6.2.tar.gz";
223 md5 = "143af0bf3afd1887622771f2f1ffe8e1";
224 };
225 };
226
227 urllib3 = buildPythonPackage {
228 name = "urllib3-1.22";
229 buildInputs = [];
230 doCheck = false;
231 propagatedBuildInputs = [];
232 src = fetchurl {
233 url = "https://pypi.python.org/packages/ee/11/7c59620aceedcc1ef65e156cc5ce5a24ef87be4107c2b74458464e437a5d/urllib3-1.22.tar.gz";
234 md5 = "0da7bed3fe94bf7dc59ae37885cc72f7";
235 };
236 };
237
238
239 sphinx_rtd_theme = buildPythonPackage rec {
240 name = "sphinx-rtd-theme-0.2.5b1";
241 buildInputs = [];
242 doCheck = false;
243 propagatedBuildInputs = [];
244 src = fetchurl {
245 url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz";
246 md5 = "0923473a43bd2527f32151f195f2a521";
247 };
248
249
250 };
251 217 # Avoid that setuptools is replaced, this leads to trouble
252 218 # with buildPythonPackage.
253 219 setuptools = pkgs.python27Packages.setuptools;
@@ -255,7 +221,7 b' let'
255 221 in python.buildEnv.override {
256 222 inherit python;
257 223 extraLibs = [
258 Sphinx
259 sphinx_rtd_theme
224 sphinx
225 sphinx-rtd-theme
260 226 ];
261 }
227 } No newline at end of file
@@ -37,6 +37,7 b' To convert the old version into a curren'
37 37 |repo| into a local machine using a recent |git| client, then push it to a new
38 38 |repo| inside |RCE|.
39 39
40
40 41 VCS Server Memory Consumption
41 42 -----------------------------
42 43
@@ -48,24 +49,34 b' shipped with the optimal configuration a'
48 49 To fix this issue, upgrade to |RCE| 3.3.2 or greater, and if you discover
49 50 memory consumption issues check the VCS Server settings.
50 51
51 Fedora 23
52 ---------
52 Fedora 23 / Ubuntu 18.04
53 ------------------------
54
55 |RCC| has a know problem with locales, due to changes in glibc 2.27+ which affects
56 the local-archive format, which is now incompatible with our used glibc 2.26.
57
53 58
54 |RCC| does not run perfectly on Fedora 23 due to a locale issue. This is a
55 known issue under investigation due to the Nix packaging of the product, see the
56 `Github issue here`_. |RCC| runs fine on Fedora 21.
59 To work around this problem, you need set path to ``$LOCAL_ARCHIVE`` to the
60 locale package in older pre glibc 2.27 format, or set `LC_ALL=C` in your enviroment.
61
62 To use the pre 2.27 locale-archive fix follow these steps:
57 63
58 To work around this problem, you need to point ``$LOCAL_ARCHIVE`` to the
59 workaround locale package.
64 1. Download the pre 2.27 locale-archive package
60 65
61 1. Download this package:
62 http://lipa.ms.mff.cuni.cz/~cunav5am/nix/locale-archive
66 .. code-block:: bash
67
68 wget https://dls.rhodecode.com/assets/locale-archive
69
63 70
64 71 2. Point ``$LOCAL_ARCHIVE`` to the locale package.
65 72
66 73 .. code-block:: bash
67 74
68 $ export LOCALE_ARCHIVE=/home/VERSION/locale-archive # change to your path
75 $ export LOCALE_ARCHIVE=/home/USER/locale-archive # change to your path
76
77 This can either added in `~/.rccontrol/supervisor/supervisord.ini`
78 or in user .bashrc/.zshrc etc, or via a startup script that
79 runs `rccontrol self-init`
69 80
70 81 If you happen to be running |RCC| from systemd, use the following
71 82 example to pass the correct locale information on boot.
@@ -85,4 +96,3 b' example to pass the correct locale infor'
85 96 [Install]
86 97 WantedBy=multi-user.target
87 98
88 .. _Github issue here: https://github.com/NixOS/nix/issues/599
@@ -9,6 +9,7 b' Release Notes'
9 9 .. toctree::
10 10 :maxdepth: 1
11 11
12 release-notes-4.13.0.rst
12 13 release-notes-4.12.4.rst
13 14 release-notes-4.12.3.rst
14 15 release-notes-4.12.2.rst
@@ -1,8 +1,8 b''
1 Sphinx==1.6.5
1 sphinx==1.7.8
2 2 six==1.11.0
3 sphinx_rtd_theme==0.2.5b1
3 sphinx_rtd_theme==0.4.1
4 4 docutils==0.14.0
5 Pygments==2.2.0
6 MarkupSafe==1.0.0
7 Jinja2==2.9.6
8 pytz No newline at end of file
5 pygments==2.2.0
6 markupsafe==1.0.0
7 jinja2==2.9.6
8 pytz==2018.4
@@ -1,6 +1,13 b''
1 1 {
2 2 "name": "rhodecode-enterprise",
3 "version": "0.0.1",
3 "version": "1.0.0",
4 "private": true,
5 "description" : "RhodeCode JS packaged",
6 "license": "SEE LICENSE IN LICENSE.txt",
7 "repository" : {
8 "type" : "hg",
9 "url" : "https://code.rhodecode.com/rhodecode-enterprise-ce"
10 },
4 11 "devDependencies": {
5 12 "grunt": "^0.4.5",
6 13 "grunt-contrib-copy": "^1.0.0",
@@ -8,16 +15,17 b''
8 15 "grunt-contrib-jshint": "^0.12.0",
9 16 "grunt-contrib-less": "^1.1.0",
10 17 "grunt-contrib-watch": "^0.6.1",
11 "crisper": "^2.0.2",
12 "vulcanize": "^1.14.8",
18 "crisper": "^2.1.1",
19 "vulcanize": "^1.16.0",
13 20 "grunt-crisper": "^1.0.1",
14 21 "grunt-vulcanize": "^1.0.0",
15 22 "node2nix": "^1.0.0",
16 23 "jshint": "^2.9.1-rc3",
17 "bower": "^1.7.9",
24 "bower": "^1.8.4",
18 25 "jquery": "1.11.3",
19 26 "favico.js": "^0.3.10",
20 "clipboard": "^1.7.1",
27 "clipboard": "^2.0.1",
28 "qrious": "^4.0.2",
21 29 "moment": "^2.18.1",
22 30 "mousetrap": "^1.6.1",
23 31 "appenlight-client": "git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1"
@@ -1,33 +1,30 b''
1 # Generated by bower2nix v3.2.0 (https://github.com/rvl/bower2nix)
1 2 { fetchbower, buildEnv }:
2 3 buildEnv { name = "bower-env"; ignoreCollisions = true; paths = [
3 (fetchbower "webcomponentsjs" "0.7.22" "^0.7.22" "178h9j8jq9wi5845f5pxhhhqw6x022nzmpzm4di8fgsdl1f6nr5d")
4 (fetchbower "polymer" "Polymer/polymer#1.6.1" "Polymer/polymer#^1.6.1" "09mm0jgk457gvwqlc155swch7gjr6fs3g7spnvhi6vh5b6518540")
5 (fetchbower "paper-button" "PolymerElements/paper-button#1.0.13" "PolymerElements/paper-button#^1.0.13" "0i3y153nqk06pn0gk282vyybnl3g1w3w41d5i9z659cgn27g3fvm")
6 (fetchbower "paper-spinner" "PolymerElements/paper-spinner#1.2.0" "PolymerElements/paper-spinner#^1.2.0" "1av1m6y81jw3hjhz1yqy3rwcgxarjzl58ldfn4q6sn51pgzngfqb")
7 (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.3" "PolymerElements/paper-tooltip#^1.1.2" "0vmrm1n8k9sk9nvqy03q177axy22pia6i3j1gxbk72j3pqiqvg6k")
8 (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m")
9 (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#1.2.0" "PolymerElements/paper-toggle-button#^1.2.0" "0mphcng3ngspbpg4jjn0mb91nvr4xc1phq3qswib15h6sfww1b2w")
10 (fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.4" "PolymerElements/iron-ajax#^1.4.4" "0jpi7ik3zljw8yh2ccc85r26lcpzmkc2nl1kn6fqdx57zkzk9v5b")
11 (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#1.0.13" "PolymerElements/iron-autogrow-textarea#^1.0.13" "0zwhpl97vii1s8k0lgain8i9dnw29b0mxc5ixdscx9las13n2lqq")
12 (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#1.0.6" "PolymerElements/iron-a11y-keys#^1.0.6" "1xz3mgghfcxixq28sdb654iaxj4nyi1bzcwf77ydkms6fviqs9mv")
13 (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#1.3.1" "PolymerElements/iron-flex-layout#^1.0.0" "0nswv3ih3bhflgcd2wjfmddqswzgqxb2xbq65jk9w3rkj26hplbl")
14 (fetchbower "paper-behaviors" "PolymerElements/paper-behaviors#1.0.12" "PolymerElements/paper-behaviors#^1.0.0" "012bqk97awgz55cn7rm9g7cckrdhkqhls3zvp8l6nd4rdwcrdzq8")
15 (fetchbower "paper-material" "PolymerElements/paper-material#1.0.6" "PolymerElements/paper-material#^1.0.0" "0rljmknfdbm5aabvx9pk77754zckj3l127c3mvnmwkpkkr353xnh")
16 (fetchbower "paper-styles" "PolymerElements/paper-styles#1.1.4" "PolymerElements/paper-styles#^1.0.0" "0j8vg74xrcxlni8i93dsab3y80f34kk30lv4yblqpkp9c3nrilf7")
17 (fetchbower "neon-animation" "PolymerElements/neon-animation#1.2.4" "PolymerElements/neon-animation#^1.0.0" "16mz9i2n5w0k5j8d6gha23cnbdgm5syz3fawyh89gdbq97bi2q5j")
18 (fetchbower "iron-a11y-announcer" "PolymerElements/iron-a11y-announcer#1.0.5" "PolymerElements/iron-a11y-announcer#^1.0.0" "0n7c7j1pwk3835s7s2jd9125wdcsqf216yi5gj07wn5s8h8p7m9d")
19 (fetchbower "iron-overlay-behavior" "PolymerElements/iron-overlay-behavior#1.8.6" "PolymerElements/iron-overlay-behavior#^1.0.9" "14brn9gz6qqskarg3fxk91xs7vg02vgcsz9a9743kidxr0l0413m")
20 (fetchbower "iron-fit-behavior" "PolymerElements/iron-fit-behavior#1.2.5" "PolymerElements/iron-fit-behavior#^1.1.0" "1msnlh8lp1xg6v4h6dkjwj9kzac5q5q208ayla3x9hi483ki6rlf")
21 (fetchbower "iron-checked-element-behavior" "PolymerElements/iron-checked-element-behavior#1.0.5" "PolymerElements/iron-checked-element-behavior#^1.0.0" "0l0yy4ah454s8bzfv076s8by7h67zy9ni6xb932qwyhx8br6c1m7")
22 (fetchbower "promise-polyfill" "polymerlabs/promise-polyfill#1.0.1" "polymerlabs/promise-polyfill#^1.0.0" "045bj2caav3famr5hhxgs1dx7n08r4s46mlzwb313vdy17is38xb")
23 (fetchbower "iron-behaviors" "PolymerElements/iron-behaviors#1.0.17" "PolymerElements/iron-behaviors#^1.0.0" "021qvkmbk32jrrmmphpmwgby4bzi5jyf47rh1bxmq2ip07ly4bpr")
24 (fetchbower "iron-validatable-behavior" "PolymerElements/iron-validatable-behavior#1.1.1" "PolymerElements/iron-validatable-behavior#^1.0.0" "1yhxlvywhw2klbbgm3f3cmanxfxggagph4ii635zv0c13707wslv")
25 (fetchbower "iron-form-element-behavior" "PolymerElements/iron-form-element-behavior#1.0.6" "PolymerElements/iron-form-element-behavior#^1.0.0" "0rdhxivgkdhhz2yadgdbjfc70l555p3y83vjh8rfj5hr0asyn6q1")
26 (fetchbower "iron-a11y-keys-behavior" "polymerelements/iron-a11y-keys-behavior#1.1.9" "polymerelements/iron-a11y-keys-behavior#^1.0.0" "1imm4gc84qizihhbyhfa8lwjh3myhj837f79i5m04xjgwrjmkaf6")
27 (fetchbower "paper-ripple" "PolymerElements/paper-ripple#1.0.8" "PolymerElements/paper-ripple#^1.0.0" "0r9sq8ik7wwrw0qb82c3rw0c030ljwd3s466c9y4qbcrsbvfjnns")
28 (fetchbower "font-roboto" "PolymerElements/font-roboto#1.0.1" "PolymerElements/font-roboto#^1.0.1" "02jz43r0wkyr3yp7rq2rc08l5cwnsgca9fr54sr4rhsnl7cjpxrj")
29 (fetchbower "iron-meta" "PolymerElements/iron-meta#1.1.2" "PolymerElements/iron-meta#^1.0.0" "1wl4dx8fnsknw9z9xi8bpc4cy9x70c11x4zxwxnj73hf3smifppl")
30 (fetchbower "iron-resizable-behavior" "PolymerElements/iron-resizable-behavior#1.0.5" "PolymerElements/iron-resizable-behavior#^1.0.0" "1fd5zmbr2hax42vmcasncvk7lzi38fmb1kyii26nn8pnnjak7zkn")
31 (fetchbower "iron-selector" "PolymerElements/iron-selector#1.5.2" "PolymerElements/iron-selector#^1.0.0" "1ajv46llqzvahm5g6g75w7nfyjcslp53ji0wm96l2k94j87spv3r")
32 (fetchbower "web-animations-js" "web-animations/web-animations-js#2.2.2" "web-animations/web-animations-js#^2.2.0" "1izfvm3l67vwys0bqbhidi9rqziw2f8wv289386sc6jsxzgkzhga")
4 (fetchbower "webcomponentsjs" "1.2.3" "^1.2.3" "0db2fjk779rhl9d4ifpk1j9a83vngx6j3hk7si1752dqxj857267")
5 (fetchbower "polymer" "Polymer/polymer#2.6.0" "Polymer/polymer#^2.6.0" "1jw5syjn0naa7dlxzxvsgwb20zbkbpx0pcg0wzjq4wr49c20nw0k")
6 (fetchbower "paper-button" "PolymerElements/paper-button#2.1.2" "PolymerElements/paper-button#^2.1.2" "1lwmjwhvimh02gss39yjp5h7yg9mxl1ig59yrk085v86y5f5ilz1")
7 (fetchbower "paper-spinner" "PolymerElements/paper-spinner#2.1.0" "PolymerElements/paper-spinner#^2.1.0" "07jamgxzvy4r9pgf5ikj1fm8nkrw6sywgcxvmm7ax58hjvmd4i45")
8 (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#2.1.1" "PolymerElements/paper-tooltip#^2.1.1" "0ja9vz4xps7dxfx6kmrwq0gifbjsyc3pk9l3hd5233ss72ghlvgb")
9 (fetchbower "paper-toast" "PolymerElements/paper-toast#2.1.2" "PolymerElements/paper-toast#^2.1.2" "0mkj9ayjx2l9hvrz4kw3yjbgrs9w873k05ywv94nh92mzpjkxn04")
10 (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#2.1.1" "PolymerElements/paper-toggle-button#^2.1.1" "1rl5ar3ny6r3v9hr8s68v8b3zh5yl52pikhi4b9iv9grv29g5999")
11 (fetchbower "iron-ajax" "PolymerElements/iron-ajax#2.1.3" "PolymerElements/iron-ajax#^2.1.3" "187zb6lkv18yapl292qhn611mbl4i2bqs2dimlwmdjaln285nc1l")
12 (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#2.2.0" "PolymerElements/iron-autogrow-textarea#^2.2.0" "1cx7g49m20z08x25z24g2pvv6m6dwfbkga3nsw0rpi3jk7xhznqw")
13 (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#2.1.2" "PolymerElements/iron-a11y-keys#^2.1.2" "0zdn3bzfrk88iwahmmzvcjn3m90zga1l8dx42b365n8if0n0zapj")
14 (fetchbower "shadycss" "webcomponents/shadycss#1.3.5" "webcomponents/shadycss#^v1.1.0" "1xp07d6jlmc3ywg4cdp2nijwi0vrbzw468242xz0s6zx5z2n2wzf")
15 (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#2.0.3" "PolymerElements/iron-flex-layout#1 - 2" "1ir9ili3rkcgbfj6is5s70vyb7m6avz0av0lpjjlhhsplrrl90bk")
16 (fetchbower "paper-behaviors" "PolymerElements/paper-behaviors#2.1.1" "PolymerElements/paper-behaviors#1 - 2" "0wzyznmy1q64jsm6lck0xma92lg2hz9h9m05r68iy20iyrvbjld7")
17 (fetchbower "paper-styles" "PolymerElements/paper-styles#2.1.0" "PolymerElements/paper-styles#1 - 2" "0xzsd7pvjsk7lgcmvx4q0dvps40q3mymkx26zgs8ns91s1ssfqbx")
18 (fetchbower "iron-a11y-announcer" "PolymerElements/iron-a11y-announcer#2.1.0" "PolymerElements/iron-a11y-announcer#1 - 2" "1hvmw76im8y3pxmg1yfnlkzap429q9i4v1z42y7m8lz0996jmxrz")
19 (fetchbower "iron-overlay-behavior" "PolymerElements/iron-overlay-behavior#2.3.4" "PolymerElements/iron-overlay-behavior#1 - 2" "0hk2fxhfz7kg27349qz1c87vq6nfdcnjr9az3q95ak3rigsb71wg")
20 (fetchbower "iron-fit-behavior" "PolymerElements/iron-fit-behavior#2.2.1" "PolymerElements/iron-fit-behavior#1 - 2" "0v89am4r2fncr7m9k0f2xqh5bvgn2dqjjc7p515ix4grk89whbs3")
21 (fetchbower "iron-checked-element-behavior" "PolymerElements/iron-checked-element-behavior#2.1.1" "PolymerElements/iron-checked-element-behavior#1 - 2" "00gpvnb7anspadw59av7lca6p03qlx59dgnhw3lqf5v223dsh0l3")
22 (fetchbower "iron-behaviors" "PolymerElements/iron-behaviors#2.1.1" "PolymerElements/iron-behaviors#1 - 2" "0c71l1il76jg8gvyh8bwlqraif53gfnz5700vpg35qyr1biwbr1w")
23 (fetchbower "iron-validatable-behavior" "PolymerElements/iron-validatable-behavior#2.1.0" "PolymerElements/iron-validatable-behavior#1 - 2" "1j65zv7hcxdcyyanzhp2wap3bnx7cz8ghd44m12fad2206jj6ysi")
24 (fetchbower "iron-a11y-keys-behavior" "PolymerElements/iron-a11y-keys-behavior#2.1.1" "PolymerElements/iron-a11y-keys-behavior#1 - 2" "0jsw7wvh4wzcjqdbvxyha99h1ph61lykyyyvdb6hm8m8w40bhs9b")
25 (fetchbower "paper-ripple" "PolymerElements/paper-ripple#2.1.1" "PolymerElements/paper-ripple#1 - 2" "0sam6w83nxf9mss79j6hjfsx0288pf4hwr1bw5xclzgpddcjmrm5")
26 (fetchbower "font-roboto" "PolymerElements/font-roboto#1.1.0" "PolymerElements/font-roboto#^1.0.1" "0z4msvaa5pnr84j2r957g313fmdbdbrknhdw1axy5g48845yv04s")
27 (fetchbower "iron-resizable-behavior" "PolymerElements/iron-resizable-behavior#2.1.1" "PolymerElements/iron-resizable-behavior#1 - 2" "0169rg6kby0ypfiwbkin46ywaszwj7r91yn081yqd96l1115aqnk")
28 (fetchbower "iron-form-element-behavior" "PolymerElements/iron-form-element-behavior#2.1.3" "PolymerElements/iron-form-element-behavior#1 - 2" "1c83kkfqvb5pdlvrhad3l7b11i244a8lykc8kzfnb9ya0xrln0cn")
29 (fetchbower "iron-meta" "PolymerElements/iron-meta#2.1.1" "PolymerElements/iron-meta#1 - 2" "12w1pcl3w97xpxihqddbf2d9dx8xz5i1jd9bz1xrmfsh25isni40")
33 30 ]; }
@@ -1,12 +1,14 b''
1 # This file has been generated by node2nix 1.0.0. Do not edit!
1 # This file has been generated by node2nix 1.6.0. Do not edit!
2 2
3 3 {pkgs ? import <nixpkgs> {
4 4 inherit system;
5 }, system ? builtins.currentSystem}:
5 }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-6_x"}:
6 6
7 7 let
8 8 nodeEnv = import ./node-env.nix {
9 inherit (pkgs) stdenv python utillinux runCommand writeTextFile nodejs;
9 inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile;
10 inherit nodejs;
11 libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
10 12 };
11 13 in
12 14 import ./node-packages.nix {
This diff has been collapsed as it changes many lines, (518 lines changed) Show them Hide them
@@ -1,31 +1,33 b''
1 1 # This file originates from node2nix
2 2
3 {stdenv, python, nodejs, utillinux, runCommand, writeTextFile}:
3 {stdenv, nodejs, python2, utillinux, libtool, runCommand, writeTextFile}:
4 4
5 5 let
6 python = if nodejs ? python then nodejs.python else python2;
7
6 8 # Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
7 9 tarWrapper = runCommand "tarWrapper" {} ''
8 10 mkdir -p $out/bin
9
11
10 12 cat > $out/bin/tar <<EOF
11 13 #! ${stdenv.shell} -e
12 14 $(type -p tar) "\$@" --warning=no-unknown-keyword
13 15 EOF
14
16
15 17 chmod +x $out/bin/tar
16 18 '';
17
19
18 20 # Function that generates a TGZ file from a NPM project
19 21 buildNodeSourceDist =
20 22 { name, version, src, ... }:
21
23
22 24 stdenv.mkDerivation {
23 25 name = "node-tarball-${name}-${version}";
24 26 inherit src;
25 27 buildInputs = [ nodejs ];
26 28 buildPhase = ''
27 29 export HOME=$TMPDIR
28 tgzFile=$(npm pack)
30 tgzFile=$(npm pack | tail -n 1) # Hooks to the pack command will add output (https://docs.npmjs.com/misc/scripts)
29 31 '';
30 32 installPhase = ''
31 33 mkdir -p $out/tarballs
@@ -42,151 +44,322 b' let'
42 44 # Bundle the dependencies of the package
43 45 mkdir -p node_modules
44 46 cd node_modules
45
47
46 48 # Only include dependencies if they don't exist. They may also be bundled in the package.
47 49 if [ ! -e "${dependency.name}" ]
48 50 then
49 51 ${composePackage dependency}
50 52 fi
51
53
52 54 cd ..
53 55 ''
54 56 ) dependencies);
55 57
56 58 # Recursively composes the dependencies of a package
57 59 composePackage = { name, packageName, src, dependencies ? [], ... }@args:
58 let
59 fixImpureDependencies = writeTextFile {
60 name = "fixDependencies.js";
61 text = ''
62 var fs = require('fs');
63 var url = require('url');
64
65 /*
66 * Replaces an impure version specification by *
67 */
68 function replaceImpureVersionSpec(versionSpec) {
69 var parsedUrl = url.parse(versionSpec);
70
71 if(versionSpec == "latest" || versionSpec == "unstable" ||
72 versionSpec.substr(0, 2) == ".." || dependency.substr(0, 2) == "./" || dependency.substr(0, 2) == "~/" || dependency.substr(0, 1) == '/')
73 return '*';
74 else if(parsedUrl.protocol == "git:" || parsedUrl.protocol == "git+ssh:" || parsedUrl.protocol == "git+http:" || parsedUrl.protocol == "git+https:" ||
75 parsedUrl.protocol == "http:" || parsedUrl.protocol == "https:")
76 return '*';
77 else
78 return versionSpec;
79 }
80
81 var packageObj = JSON.parse(fs.readFileSync('./package.json'));
82
83 /* Replace dependencies */
84 if(packageObj.dependencies !== undefined) {
85 for(var dependency in packageObj.dependencies) {
86 var versionSpec = packageObj.dependencies[dependency];
87 packageObj.dependencies[dependency] = replaceImpureVersionSpec(versionSpec);
88 }
89 }
90
91 /* Replace development dependencies */
92 if(packageObj.devDependencies !== undefined) {
93 for(var dependency in packageObj.devDependencies) {
94 var versionSpec = packageObj.devDependencies[dependency];
95 packageObj.devDependencies[dependency] = replaceImpureVersionSpec(versionSpec);
96 }
97 }
98
99 /* Replace optional dependencies */
100 if(packageObj.optionalDependencies !== undefined) {
101 for(var dependency in packageObj.optionalDependencies) {
102 var versionSpec = packageObj.optionalDependencies[dependency];
103 packageObj.optionalDependencies[dependency] = replaceImpureVersionSpec(versionSpec);
104 }
105 }
106
107 /* Write the fixed JSON file */
108 fs.writeFileSync("package.json", JSON.stringify(packageObj));
109 '';
110 };
111 in
112 60 ''
113 61 DIR=$(pwd)
114 62 cd $TMPDIR
115
63
116 64 unpackFile ${src}
117
65
118 66 # Make the base dir in which the target dependency resides first
119 67 mkdir -p "$(dirname "$DIR/${packageName}")"
120 68
121 69 if [ -f "${src}" ]
122 70 then
123 71 # Figure out what directory has been unpacked
124 packageDir=$(find . -type d -maxdepth 1 | tail -1)
125
72 packageDir="$(find . -maxdepth 1 -type d | tail -1)"
73
126 74 # Restore write permissions to make building work
75 find "$packageDir" -type d -print0 | xargs -0 chmod u+x
127 76 chmod -R u+w "$packageDir"
128
77
129 78 # Move the extracted tarball into the output folder
130 79 mv "$packageDir" "$DIR/${packageName}"
131 80 elif [ -d "${src}" ]
132 81 then
82 # Get a stripped name (without hash) of the source directory.
83 # On old nixpkgs it's already set internally.
84 if [ -z "$strippedName" ]
85 then
86 strippedName="$(stripHash ${src})"
87 fi
88
133 89 # Restore write permissions to make building work
134 chmod -R u+w $strippedName
135
136 # Move the extracted directory into the output folder
137 mv $strippedName "$DIR/${packageName}"
90 chmod -R u+w "$strippedName"
91
92 # Move the extracted directory into the output folder
93 mv "$strippedName" "$DIR/${packageName}"
138 94 fi
139
95
140 96 # Unset the stripped name to not confuse the next unpack step
141 97 unset strippedName
142
143 # Some version specifiers (latest, unstable, URLs, file paths) force NPM to make remote connections or consult paths outside the Nix store.
144 # The following JavaScript replaces these by * to prevent that
98
99 # Include the dependencies of the package
145 100 cd "$DIR/${packageName}"
146 node ${fixImpureDependencies}
147
148 # Include the dependencies of the package
149 101 ${includeDependencies { inherit dependencies; }}
150 102 cd ..
151 103 ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
152 104 '';
153 105
106 pinpointDependencies = {dependencies, production}:
107 let
108 pinpointDependenciesFromPackageJSON = writeTextFile {
109 name = "pinpointDependencies.js";
110 text = ''
111 var fs = require('fs');
112 var path = require('path');
113
114 function resolveDependencyVersion(location, name) {
115 if(location == process.env['NIX_STORE']) {
116 return null;
117 } else {
118 var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
119
120 if(fs.existsSync(dependencyPackageJSON)) {
121 var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
122
123 if(dependencyPackageObj.name == name) {
124 return dependencyPackageObj.version;
125 }
126 } else {
127 return resolveDependencyVersion(path.resolve(location, ".."), name);
128 }
129 }
130 }
131
132 function replaceDependencies(dependencies) {
133 if(typeof dependencies == "object" && dependencies !== null) {
134 for(var dependency in dependencies) {
135 var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
136
137 if(resolvedVersion === null) {
138 process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
139 } else {
140 dependencies[dependency] = resolvedVersion;
141 }
142 }
143 }
144 }
145
146 /* Read the package.json configuration */
147 var packageObj = JSON.parse(fs.readFileSync('./package.json'));
148
149 /* Pinpoint all dependencies */
150 replaceDependencies(packageObj.dependencies);
151 if(process.argv[2] == "development") {
152 replaceDependencies(packageObj.devDependencies);
153 }
154 replaceDependencies(packageObj.optionalDependencies);
155
156 /* Write the fixed package.json file */
157 fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
158 '';
159 };
160 in
161 ''
162 node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
163
164 ${stdenv.lib.optionalString (dependencies != [])
165 ''
166 if [ -d node_modules ]
167 then
168 cd node_modules
169 ${stdenv.lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
170 cd ..
171 fi
172 ''}
173 '';
174
175 # Recursively traverses all dependencies of a package and pinpoints all
176 # dependencies in the package.json file to the versions that are actually
177 # being used.
178
179 pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
180 ''
181 if [ -d "${packageName}" ]
182 then
183 cd "${packageName}"
184 ${pinpointDependencies { inherit dependencies production; }}
185 cd ..
186 ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
187 fi
188 '';
189
154 190 # Extract the Node.js source code which is used to compile packages with
155 191 # native bindings
156 192 nodeSources = runCommand "node-sources" {} ''
157 193 tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
158 194 mv node-* $out
159 195 '';
160
196
197 # Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
198 addIntegrityFieldsScript = writeTextFile {
199 name = "addintegrityfields.js";
200 text = ''
201 var fs = require('fs');
202 var path = require('path');
203
204 function augmentDependencies(baseDir, dependencies) {
205 for(var dependencyName in dependencies) {
206 var dependency = dependencies[dependencyName];
207
208 // Open package.json and augment metadata fields
209 var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
210 var packageJSONPath = path.join(packageJSONDir, "package.json");
211
212 if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
213 console.log("Adding metadata fields to: "+packageJSONPath);
214 var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
215
216 if(dependency.integrity) {
217 packageObj["_integrity"] = dependency.integrity;
218 } else {
219 packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
220 }
221
222 packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
223 fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
224 }
225
226 // Augment transitive dependencies
227 if(dependency.dependencies !== undefined) {
228 augmentDependencies(packageJSONDir, dependency.dependencies);
229 }
230 }
231 }
232
233 if(fs.existsSync("./package-lock.json")) {
234 var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
235
236 if(packageLock.lockfileVersion !== 1) {
237 process.stderr.write("Sorry, I only understand lock file version 1!\n");
238 process.exit(1);
239 }
240
241 if(packageLock.dependencies !== undefined) {
242 augmentDependencies(".", packageLock.dependencies);
243 }
244 }
245 '';
246 };
247
248 # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
249 reconstructPackageLock = writeTextFile {
250 name = "addintegrityfields.js";
251 text = ''
252 var fs = require('fs');
253 var path = require('path');
254
255 var packageObj = JSON.parse(fs.readFileSync("package.json"));
256
257 var lockObj = {
258 name: packageObj.name,
259 version: packageObj.version,
260 lockfileVersion: 1,
261 requires: true,
262 dependencies: {}
263 };
264
265 function augmentPackageJSON(filePath, dependencies) {
266 var packageJSON = path.join(filePath, "package.json");
267 if(fs.existsSync(packageJSON)) {
268 var packageObj = JSON.parse(fs.readFileSync(packageJSON));
269 dependencies[packageObj.name] = {
270 version: packageObj.version,
271 integrity: "sha1-000000000000000000000000000=",
272 dependencies: {}
273 };
274 processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies);
275 }
276 }
277
278 function processDependencies(dir, dependencies) {
279 if(fs.existsSync(dir)) {
280 var files = fs.readdirSync(dir);
281
282 files.forEach(function(entry) {
283 var filePath = path.join(dir, entry);
284 var stats = fs.statSync(filePath);
285
286 if(stats.isDirectory()) {
287 if(entry.substr(0, 1) == "@") {
288 // When we encounter a namespace folder, augment all packages belonging to the scope
289 var pkgFiles = fs.readdirSync(filePath);
290
291 pkgFiles.forEach(function(entry) {
292 if(stats.isDirectory()) {
293 var pkgFilePath = path.join(filePath, entry);
294 augmentPackageJSON(pkgFilePath, dependencies);
295 }
296 });
297 } else {
298 augmentPackageJSON(filePath, dependencies);
299 }
300 }
301 });
302 }
303 }
304
305 processDependencies("node_modules", lockObj.dependencies);
306
307 fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
308 '';
309 };
310
161 311 # Builds and composes an NPM package including all its dependencies
162 buildNodePackage = { name, packageName, version, dependencies ? [], production ? true, npmFlags ? "", dontNpmInstall ? false, preRebuild ? "", ... }@args:
163
164 stdenv.lib.makeOverridable stdenv.mkDerivation (builtins.removeAttrs args [ "dependencies" ] // {
312 buildNodePackage =
313 { name
314 , packageName
315 , version
316 , dependencies ? []
317 , buildInputs ? []
318 , production ? true
319 , npmFlags ? ""
320 , dontNpmInstall ? false
321 , bypassCache ? false
322 , preRebuild ? ""
323 , dontStrip ? true
324 , unpackPhase ? "true"
325 , buildPhase ? "true"
326 , ... }@args:
327
328 let
329 forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
330 extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" ];
331 in
332 stdenv.mkDerivation ({
165 333 name = "node-${name}-${version}";
166 buildInputs = [ tarWrapper python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ args.buildInputs or [];
167 dontStrip = args.dontStrip or true; # Striping may fail a build for some package deployments
168
169 inherit dontNpmInstall preRebuild;
170
171 unpackPhase = args.unpackPhase or "true";
172
173 buildPhase = args.buildPhase or "true";
174
334 buildInputs = [ tarWrapper python nodejs ]
335 ++ stdenv.lib.optional (stdenv.isLinux) utillinux
336 ++ stdenv.lib.optional (stdenv.isDarwin) libtool
337 ++ buildInputs;
338
339 inherit dontStrip; # Stripping may fail a build for some package deployments
340 inherit dontNpmInstall preRebuild unpackPhase buildPhase;
341
175 342 compositionScript = composePackage args;
176 passAsFile = [ "compositionScript" ];
177
178 installPhase = args.installPhase or ''
343 pinpointDependenciesScript = pinpointDependenciesOfPackage args;
344
345 passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
346
347 installPhase = ''
179 348 # Create and enter a root node_modules/ folder
180 349 mkdir -p $out/lib/node_modules
181 350 cd $out/lib/node_modules
182
351
183 352 # Compose the package and all its dependencies
184 353 source $compositionScriptPath
185
354
355 # Pinpoint the versions of all dependencies to the ones that are actually being used
356 echo "pinpointing versions of dependencies..."
357 source $pinpointDependenciesScriptPath
358
186 359 # Patch the shebangs of the bundled modules to prevent them from
187 360 # calling executables outside the Nix store as much as possible
188 361 patchShebangs .
189
362
190 363 # Deploy the Node.js package by running npm install. Since the
191 364 # dependencies have been provided already by ourselves, it should not
192 365 # attempt to install them again, which is good, because we want to make
@@ -196,23 +369,37 b' let'
196 369 #
197 370 # The other responsibilities of NPM are kept -- version checks, build
198 371 # steps, postprocessing etc.
199
372
200 373 export HOME=$TMPDIR
201 374 cd "${packageName}"
202 375 runHook preRebuild
203 npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
204
376
377 ${stdenv.lib.optionalString bypassCache ''
378 if [ ! -f package-lock.json ]
379 then
380 echo "No package-lock.json file found, reconstructing..."
381 node ${reconstructPackageLock}
382 fi
383
384 node ${addIntegrityFieldsScript}
385 ''}
386
387 npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
388
205 389 if [ "$dontNpmInstall" != "1" ]
206 390 then
207 npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
391 # NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
392 rm -f npm-shrinkwrap.json
393
394 npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
208 395 fi
209
396
210 397 # Create symlink to the deployed executable folder, if applicable
211 398 if [ -d "$out/lib/node_modules/.bin" ]
212 399 then
213 400 ln -s $out/lib/node_modules/.bin $out/bin
214 401 fi
215
402
216 403 # Create symlinks to the deployed manual page folders, if applicable
217 404 if [ -d "$out/lib/node_modules/${packageName}/man" ]
218 405 then
@@ -226,52 +413,111 b' let'
226 413 done
227 414 done
228 415 fi
416
417 # Run post install hook, if provided
418 runHook postInstall
229 419 '';
230 });
420 } // extraArgs);
231 421
232 422 # Builds a development shell
233 buildNodeShell = { name, packageName, version, src, dependencies ? [], production ? true, npmFlags ? "", dontNpmInstall ? false, ... }@args:
423 buildNodeShell =
424 { name
425 , packageName
426 , version
427 , src
428 , dependencies ? []
429 , buildInputs ? []
430 , production ? true
431 , npmFlags ? ""
432 , dontNpmInstall ? false
433 , bypassCache ? false
434 , dontStrip ? true
435 , unpackPhase ? "true"
436 , buildPhase ? "true"
437 , ... }@args:
438
234 439 let
235 nodeDependencies = stdenv.mkDerivation {
440 forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
441
442 extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
443
444 nodeDependencies = stdenv.mkDerivation ({
236 445 name = "node-dependencies-${name}-${version}";
237
238 buildInputs = [ tarWrapper python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ args.buildInputs or [];
239
446
447 buildInputs = [ tarWrapper python nodejs ]
448 ++ stdenv.lib.optional (stdenv.isLinux) utillinux
449 ++ stdenv.lib.optional (stdenv.isDarwin) libtool
450 ++ buildInputs;
451
452 inherit dontStrip; # Stripping may fail a build for some package deployments
453 inherit dontNpmInstall unpackPhase buildPhase;
454
240 455 includeScript = includeDependencies { inherit dependencies; };
241 passAsFile = [ "includeScript" ];
242
243 buildCommand = ''
244 mkdir -p $out/lib
245 cd $out/lib
456 pinpointDependenciesScript = pinpointDependenciesOfPackage args;
457
458 passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
459
460 installPhase = ''
461 mkdir -p $out/${packageName}
462 cd $out/${packageName}
463
246 464 source $includeScriptPath
247
465
248 466 # Create fake package.json to make the npm commands work properly
249 cat > package.json <<EOF
250 {
251 "name": "${packageName}",
252 "version": "${version}"
253 }
254 EOF
255
467 cp ${src}/package.json .
468 chmod 644 package.json
469 ${stdenv.lib.optionalString bypassCache ''
470 if [ -f ${src}/package-lock.json ]
471 then
472 cp ${src}/package-lock.json .
473 fi
474 ''}
475
476 # Pinpoint the versions of all dependencies to the ones that are actually being used
477 echo "pinpointing versions of dependencies..."
478 cd ..
479 ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
480
481 source $pinpointDependenciesScriptPath
482 cd ${packageName}
483
256 484 # Patch the shebangs of the bundled modules to prevent them from
257 485 # calling executables outside the Nix store as much as possible
258 486 patchShebangs .
259
260 export HOME=$TMPDIR
261 npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
262
263 ${stdenv.lib.optionalString (!dontNpmInstall) ''
264 npm --registry http://www.example.com --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
487
488 export HOME=$PWD
489
490 ${stdenv.lib.optionalString bypassCache ''
491 if [ ! -f package-lock.json ]
492 then
493 echo "No package-lock.json file found, reconstructing..."
494 node ${reconstructPackageLock}
495 fi
496
497 node ${addIntegrityFieldsScript}
265 498 ''}
266 499
500 npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
501
502 ${stdenv.lib.optionalString (!dontNpmInstall) ''
503 # NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
504 rm -f npm-shrinkwrap.json
505
506 npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
507 ''}
508
509 cd ..
510 ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
511
512 mv ${packageName} lib
267 513 ln -s $out/lib/node_modules/.bin $out/bin
268 514 '';
269 };
515 } // extraArgs);
270 516 in
271 stdenv.lib.makeOverridable stdenv.mkDerivation {
517 stdenv.mkDerivation {
272 518 name = "node-shell-${name}-${version}";
273
274 buildInputs = [ python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ args.buildInputs or [];
519
520 buildInputs = [ python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
275 521 buildCommand = ''
276 522 mkdir -p $out/bin
277 523 cat > $out/bin/shell <<EOF
@@ -281,7 +527,7 b' let'
281 527 EOF
282 528 chmod +x $out/bin/shell
283 529 '';
284
530
285 531 # Provide the dependencies in a development shell through the NODE_PATH environment variable
286 532 inherit nodeDependencies;
287 533 shellHook = stdenv.lib.optionalString (dependencies != []) ''
@@ -289,4 +535,8 b' let'
289 535 '';
290 536 };
291 537 in
292 { inherit buildNodeSourceDist buildNodePackage buildNodeShell; }
538 {
539 buildNodeSourceDist = stdenv.lib.makeOverridable buildNodeSourceDist;
540 buildNodePackage = stdenv.lib.makeOverridable buildNodePackage;
541 buildNodeShell = stdenv.lib.makeOverridable buildNodeShell;
542 }
This diff has been collapsed as it changes many lines, (5680 lines changed) Show them Hide them
@@ -1,9 +1,1207 b''
1 # This file has been generated by node2nix 1.0.0. Do not edit!
1 # This file has been generated by node2nix 1.6.0. Do not edit!
2 2
3 {nodeEnv, fetchurl, fetchgit}:
3 {nodeEnv, fetchurl, fetchgit, globalBuildInputs ? []}:
4 4
5 5 let
6 6 sources = {
7 "@types/clone-0.1.30" = {
8 name = "_at_types_slash_clone";
9 packageName = "@types/clone";
10 version = "0.1.30";
11 src = fetchurl {
12 url = "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz";
13 sha1 = "e7365648c1b42136a59c7d5040637b3b5c83b614";
14 };
15 };
16 "@types/node-4.2.23" = {
17 name = "_at_types_slash_node";
18 packageName = "@types/node";
19 version = "4.2.23";
20 src = fetchurl {
21 url = "https://registry.npmjs.org/@types/node/-/node-4.2.23.tgz";
22 sha512 = "U6IchCNLRyswc9p6G6lxWlbE+KwAhZp6mGo6MD2yWpmFomhYmetK+c98OpKyvphNn04CU3aXeJrXdOqbXVTS/w==";
23 };
24 };
25 "@types/node-6.0.114" = {
26 name = "_at_types_slash_node";
27 packageName = "@types/node";
28 version = "6.0.114";
29 src = fetchurl {
30 url = "https://registry.npmjs.org/@types/node/-/node-6.0.114.tgz";
31 sha512 = "5ViC9dwf1VIAtrOFTvOuN04lJgw28eKjuy0Vg2Bd/fSlxKP2feCSkIw04ZgOENL2ywdWrtbkthp1XVLEjJmouw==";
32 };
33 };
34 "@types/parse5-0.0.31" = {
35 name = "_at_types_slash_parse5";
36 packageName = "@types/parse5";
37 version = "0.0.31";
38 src = fetchurl {
39 url = "https://registry.npmjs.org/@types/parse5/-/parse5-0.0.31.tgz";
40 sha1 = "e827a493a443b156e1b582a2e4c3bdc0040f2ee7";
41 };
42 };
43 "abbrev-1.1.1" = {
44 name = "abbrev";
45 packageName = "abbrev";
46 version = "1.1.1";
47 src = fetchurl {
48 url = "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz";
49 sha512 = "nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==";
50 };
51 };
52 "acorn-3.3.0" = {
53 name = "acorn";
54 packageName = "acorn";
55 version = "3.3.0";
56 src = fetchurl {
57 url = "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz";
58 sha1 = "45e37fb39e8da3f25baee3ff5369e2bb5f22017a";
59 };
60 };
61 "acorn-5.7.1" = {
62 name = "acorn";
63 packageName = "acorn";
64 version = "5.7.1";
65 src = fetchurl {
66 url = "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz";
67 sha512 = "d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==";
68 };
69 };
70 "acorn-jsx-3.0.1" = {
71 name = "acorn-jsx";
72 packageName = "acorn-jsx";
73 version = "3.0.1";
74 src = fetchurl {
75 url = "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz";
76 sha1 = "afdf9488fb1ecefc8348f6fb22f464e32a58b36b";
77 };
78 };
79 "ajv-4.11.8" = {
80 name = "ajv";
81 packageName = "ajv";
82 version = "4.11.8";
83 src = fetchurl {
84 url = "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz";
85 sha1 = "82ffb02b29e662ae53bdc20af15947706739c536";
86 };
87 };
88 "amdefine-1.0.1" = {
89 name = "amdefine";
90 packageName = "amdefine";
91 version = "1.0.1";
92 src = fetchurl {
93 url = "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz";
94 sha1 = "4a5282ac164729e93619bcfd3ad151f817ce91f5";
95 };
96 };
97 "ansi-escape-sequences-3.0.0" = {
98 name = "ansi-escape-sequences";
99 packageName = "ansi-escape-sequences";
100 version = "3.0.0";
101 src = fetchurl {
102 url = "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-3.0.0.tgz";
103 sha1 = "1c18394b6af9b76ff9a63509fa497669fd2ce53e";
104 };
105 };
106 "ansi-regex-0.2.1" = {
107 name = "ansi-regex";
108 packageName = "ansi-regex";
109 version = "0.2.1";
110 src = fetchurl {
111 url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz";
112 sha1 = "0d8e946967a3d8143f93e24e298525fc1b2235f9";
113 };
114 };
115 "ansi-regex-2.1.1" = {
116 name = "ansi-regex";
117 packageName = "ansi-regex";
118 version = "2.1.1";
119 src = fetchurl {
120 url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz";
121 sha1 = "c3b33ab5ee360d86e0e628f0468ae7ef27d654df";
122 };
123 };
124 "ansi-styles-1.1.0" = {
125 name = "ansi-styles";
126 packageName = "ansi-styles";
127 version = "1.1.0";
128 src = fetchurl {
129 url = "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz";
130 sha1 = "eaecbf66cd706882760b2f4691582b8f55d7a7de";
131 };
132 };
133 "ansi-styles-2.2.1" = {
134 name = "ansi-styles";
135 packageName = "ansi-styles";
136 version = "2.2.1";
137 src = fetchurl {
138 url = "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz";
139 sha1 = "b432dd3358b634cf75e1e4664368240533c1ddbe";
140 };
141 };
142 "appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1" = {
143 name = "appenlight-client";
144 packageName = "appenlight-client";
145 version = "0.5.1";
146 src = fetchgit {
147 url = "https://git@github.com/AppEnlight/appenlight-client-js.git";
148 rev = "14712c64c230fbbe94fcbc8094aef5eb3b90b307";
149 sha256 = "05146f5b932f166c9a4db601bc9c13ae686899653d1dd03121652631f9bc83d6";
150 };
151 };
152 "aproba-1.2.0" = {
153 name = "aproba";
154 packageName = "aproba";
155 version = "1.2.0";
156 src = fetchurl {
157 url = "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz";
158 sha512 = "Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==";
159 };
160 };
161 "are-we-there-yet-1.1.5" = {
162 name = "are-we-there-yet";
163 packageName = "are-we-there-yet";
164 version = "1.1.5";
165 src = fetchurl {
166 url = "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz";
167 sha512 = "5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==";
168 };
169 };
170 "argparse-0.1.16" = {
171 name = "argparse";
172 packageName = "argparse";
173 version = "0.1.16";
174 src = fetchurl {
175 url = "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz";
176 sha1 = "cfd01e0fbba3d6caed049fbd758d40f65196f57c";
177 };
178 };
179 "array-back-1.0.4" = {
180 name = "array-back";
181 packageName = "array-back";
182 version = "1.0.4";
183 src = fetchurl {
184 url = "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz";
185 sha1 = "644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b";
186 };
187 };
188 "asap-2.0.6" = {
189 name = "asap";
190 packageName = "asap";
191 version = "2.0.6";
192 src = fetchurl {
193 url = "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz";
194 sha1 = "e50347611d7e690943208bbdafebcbc2fb866d46";
195 };
196 };
197 "asn1-0.2.3" = {
198 name = "asn1";
199 packageName = "asn1";
200 version = "0.2.3";
201 src = fetchurl {
202 url = "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz";
203 sha1 = "dac8787713c9966849fc8180777ebe9c1ddf3b86";
204 };
205 };
206 "assert-plus-0.2.0" = {
207 name = "assert-plus";
208 packageName = "assert-plus";
209 version = "0.2.0";
210 src = fetchurl {
211 url = "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz";
212 sha1 = "d74e1b87e7affc0db8aadb7021f3fe48101ab234";
213 };
214 };
215 "assert-plus-1.0.0" = {
216 name = "assert-plus";
217 packageName = "assert-plus";
218 version = "1.0.0";
219 src = fetchurl {
220 url = "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz";
221 sha1 = "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525";
222 };
223 };
224 "async-0.1.22" = {
225 name = "async";
226 packageName = "async";
227 version = "0.1.22";
228 src = fetchurl {
229 url = "https://registry.npmjs.org/async/-/async-0.1.22.tgz";
230 sha1 = "0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061";
231 };
232 };
233 "async-0.2.10" = {
234 name = "async";
235 packageName = "async";
236 version = "0.2.10";
237 src = fetchurl {
238 url = "https://registry.npmjs.org/async/-/async-0.2.10.tgz";
239 sha1 = "b6bbe0b0674b9d719708ca38de8c237cb526c3d1";
240 };
241 };
242 "async-1.0.0" = {
243 name = "async";
244 packageName = "async";
245 version = "1.0.0";
246 src = fetchurl {
247 url = "https://registry.npmjs.org/async/-/async-1.0.0.tgz";
248 sha1 = "f8fc04ca3a13784ade9e1641af98578cfbd647a9";
249 };
250 };
251 "async-2.6.1" = {
252 name = "async";
253 packageName = "async";
254 version = "2.6.1";
255 src = fetchurl {
256 url = "https://registry.npmjs.org/async/-/async-2.6.1.tgz";
257 sha512 = "fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==";
258 };
259 };
260 "asynckit-0.4.0" = {
261 name = "asynckit";
262 packageName = "asynckit";
263 version = "0.4.0";
264 src = fetchurl {
265 url = "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz";
266 sha1 = "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79";
267 };
268 };
269 "aws-sign2-0.6.0" = {
270 name = "aws-sign2";
271 packageName = "aws-sign2";
272 version = "0.6.0";
273 src = fetchurl {
274 url = "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz";
275 sha1 = "14342dd38dbcc94d0e5b87d763cd63612c0e794f";
276 };
277 };
278 "aws4-1.7.0" = {
279 name = "aws4";
280 packageName = "aws4";
281 version = "1.7.0";
282 src = fetchurl {
283 url = "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz";
284 sha512 = "32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==";
285 };
286 };
287 "babel-polyfill-6.26.0" = {
288 name = "babel-polyfill";
289 packageName = "babel-polyfill";
290 version = "6.26.0";
291 src = fetchurl {
292 url = "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz";
293 sha1 = "379937abc67d7895970adc621f284cd966cf2153";
294 };
295 };
296 "babel-runtime-6.26.0" = {
297 name = "babel-runtime";
298 packageName = "babel-runtime";
299 version = "6.26.0";
300 src = fetchurl {
301 url = "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz";
302 sha1 = "965c7058668e82b55d7bfe04ff2337bc8b5647fe";
303 };
304 };
305 "balanced-match-1.0.0" = {
306 name = "balanced-match";
307 packageName = "balanced-match";
308 version = "1.0.0";
309 src = fetchurl {
310 url = "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz";
311 sha1 = "89b4d199ab2bee49de164ea02b89ce462d71b767";
312 };
313 };
314 "base64-js-1.2.3" = {
315 name = "base64-js";
316 packageName = "base64-js";
317 version = "1.2.3";
318 src = fetchurl {
319 url = "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz";
320 sha512 = "MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==";
321 };
322 };
323 "bcrypt-pbkdf-1.0.2" = {
324 name = "bcrypt-pbkdf";
325 packageName = "bcrypt-pbkdf";
326 version = "1.0.2";
327 src = fetchurl {
328 url = "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz";
329 sha1 = "a4301d389b6a43f9b67ff3ca11a3f6637e360e9e";
330 };
331 };
332 "boom-2.10.1" = {
333 name = "boom";
334 packageName = "boom";
335 version = "2.10.1";
336 src = fetchurl {
337 url = "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz";
338 sha1 = "39c8918ceff5799f83f9492a848f625add0c766f";
339 };
340 };
341 "bower-1.8.4" = {
342 name = "bower";
343 packageName = "bower";
344 version = "1.8.4";
345 src = fetchurl {
346 url = "https://registry.npmjs.org/bower/-/bower-1.8.4.tgz";
347 sha1 = "e7876a076deb8137f7d06525dc5e8c66db82f28a";
348 };
349 };
350 "brace-expansion-1.1.11" = {
351 name = "brace-expansion";
352 packageName = "brace-expansion";
353 version = "1.1.11";
354 src = fetchurl {
355 url = "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz";
356 sha512 = "iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==";
357 };
358 };
359 "buffer-from-1.1.1" = {
360 name = "buffer-from";
361 packageName = "buffer-from";
362 version = "1.1.1";
363 src = fetchurl {
364 url = "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz";
365 sha512 = "MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==";
366 };
367 };
368 "builtin-modules-1.1.1" = {
369 name = "builtin-modules";
370 packageName = "builtin-modules";
371 version = "1.1.1";
372 src = fetchurl {
373 url = "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz";
374 sha1 = "270f076c5a72c02f5b65a47df94c5fe3a278892f";
375 };
376 };
377 "builtins-1.0.3" = {
378 name = "builtins";
379 packageName = "builtins";
380 version = "1.0.3";
381 src = fetchurl {
382 url = "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz";
383 sha1 = "cb94faeb61c8696451db36534e1422f94f0aee88";
384 };
385 };
386 "caseless-0.12.0" = {
387 name = "caseless";
388 packageName = "caseless";
389 version = "0.12.0";
390 src = fetchurl {
391 url = "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz";
392 sha1 = "1b681c21ff84033c826543090689420d187151dc";
393 };
394 };
395 "chalk-0.5.1" = {
396 name = "chalk";
397 packageName = "chalk";
398 version = "0.5.1";
399 src = fetchurl {
400 url = "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz";
401 sha1 = "663b3a648b68b55d04690d49167aa837858f2174";
402 };
403 };
404 "chalk-1.1.3" = {
405 name = "chalk";
406 packageName = "chalk";
407 version = "1.1.3";
408 src = fetchurl {
409 url = "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz";
410 sha1 = "a8115c55e4a702fe4d150abd3872822a7e09fc98";
411 };
412 };
413 "cli-1.0.1" = {
414 name = "cli";
415 packageName = "cli";
416 version = "1.0.1";
417 src = fetchurl {
418 url = "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz";
419 sha1 = "22817534f24bfa4950c34d532d48ecbc621b8c14";
420 };
421 };
422 "clipboard-2.0.1" = {
423 name = "clipboard";
424 packageName = "clipboard";
425 version = "2.0.1";
426 src = fetchurl {
427 url = "https://registry.npmjs.org/clipboard/-/clipboard-2.0.1.tgz";
428 sha512 = "7yhQBmtN+uYZmfRjjVjKa0dZdWuabzpSKGtyQZN+9C8xlC788SSJjOHWh7tzurfwTqTD5UDYAhIv5fRJg3sHjQ==";
429 };
430 };
431 "clone-1.0.4" = {
432 name = "clone";
433 packageName = "clone";
434 version = "1.0.4";
435 src = fetchurl {
436 url = "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz";
437 sha1 = "da309cc263df15994c688ca902179ca3c7cd7c7e";
438 };
439 };
440 "co-4.6.0" = {
441 name = "co";
442 packageName = "co";
443 version = "4.6.0";
444 src = fetchurl {
445 url = "https://registry.npmjs.org/co/-/co-4.6.0.tgz";
446 sha1 = "6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184";
447 };
448 };
449 "code-point-at-1.1.0" = {
450 name = "code-point-at";
451 packageName = "code-point-at";
452 version = "1.1.0";
453 src = fetchurl {
454 url = "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz";
455 sha1 = "0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77";
456 };
457 };
458 "coffee-script-1.3.3" = {
459 name = "coffee-script";
460 packageName = "coffee-script";
461 version = "1.3.3";
462 src = fetchurl {
463 url = "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz";
464 sha1 = "150d6b4cb522894369efed6a2101c20bc7f4a4f4";
465 };
466 };
467 "colors-0.6.2" = {
468 name = "colors";
469 packageName = "colors";
470 version = "0.6.2";
471 src = fetchurl {
472 url = "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz";
473 sha1 = "2423fe6678ac0c5dae8852e5d0e5be08c997abcc";
474 };
475 };
476 "colors-1.0.3" = {
477 name = "colors";
478 packageName = "colors";
479 version = "1.0.3";
480 src = fetchurl {
481 url = "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz";
482 sha1 = "0433f44d809680fdeb60ed260f1b0c262e82a40b";
483 };
484 };
485 "combined-stream-1.0.6" = {
486 name = "combined-stream";
487 packageName = "combined-stream";
488 version = "1.0.6";
489 src = fetchurl {
490 url = "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz";
491 sha1 = "723e7df6e801ac5613113a7e445a9b69cb632818";
492 };
493 };
494 "command-line-args-3.0.5" = {
495 name = "command-line-args";
496 packageName = "command-line-args";
497 version = "3.0.5";
498 src = fetchurl {
499 url = "https://registry.npmjs.org/command-line-args/-/command-line-args-3.0.5.tgz";
500 sha1 = "5bd4ad45e7983e5c1344918e40280ee2693c5ac0";
501 };
502 };
503 "command-line-usage-3.0.8" = {
504 name = "command-line-usage";
505 packageName = "command-line-usage";
506 version = "3.0.8";
507 src = fetchurl {
508 url = "https://registry.npmjs.org/command-line-usage/-/command-line-usage-3.0.8.tgz";
509 sha1 = "b6a20978c1b383477f5c11a529428b880bfe0f4d";
510 };
511 };
512 "concat-map-0.0.1" = {
513 name = "concat-map";
514 packageName = "concat-map";
515 version = "0.0.1";
516 src = fetchurl {
517 url = "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz";
518 sha1 = "d8a96bd77fd68df7793a73036a3ba0d5405d477b";
519 };
520 };
521 "concat-stream-1.6.2" = {
522 name = "concat-stream";
523 packageName = "concat-stream";
524 version = "1.6.2";
525 src = fetchurl {
526 url = "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz";
527 sha512 = "27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==";
528 };
529 };
530 "config-chain-1.1.11" = {
531 name = "config-chain";
532 packageName = "config-chain";
533 version = "1.1.11";
534 src = fetchurl {
535 url = "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz";
536 sha1 = "aba09747dfbe4c3e70e766a6e41586e1859fc6f2";
537 };
538 };
539 "console-browserify-1.1.0" = {
540 name = "console-browserify";
541 packageName = "console-browserify";
542 version = "1.1.0";
543 src = fetchurl {
544 url = "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz";
545 sha1 = "f0241c45730a9fc6323b206dbf38edc741d0bb10";
546 };
547 };
548 "console-control-strings-1.1.0" = {
549 name = "console-control-strings";
550 packageName = "console-control-strings";
551 version = "1.1.0";
552 src = fetchurl {
553 url = "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz";
554 sha1 = "3d7cf4464db6446ea644bf4b39507f9851008e8e";
555 };
556 };
557 "core-js-2.5.7" = {
558 name = "core-js";
559 packageName = "core-js";
560 version = "2.5.7";
561 src = fetchurl {
562 url = "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz";
563 sha512 = "RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==";
564 };
565 };
566 "core-util-is-1.0.2" = {
567 name = "core-util-is";
568 packageName = "core-util-is";
569 version = "1.0.2";
570 src = fetchurl {
571 url = "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz";
572 sha1 = "b5fd54220aa2bc5ab57aab7140c940754503c1a7";
573 };
574 };
575 "crisper-1.2.0" = {
576 name = "crisper";
577 packageName = "crisper";
578 version = "1.2.0";
579 src = fetchurl {
580 url = "https://registry.npmjs.org/crisper/-/crisper-1.2.0.tgz";
581 sha1 = "9a91f597d71f6110294e076ad44dbb3408568e46";
582 };
583 };
584 "crisper-2.1.1" = {
585 name = "crisper";
586 packageName = "crisper";
587 version = "2.1.1";
588 src = fetchurl {
589 url = "https://registry.npmjs.org/crisper/-/crisper-2.1.1.tgz";
590 sha512 = "yxfj9nTbFunDASztAxVF8hCPwaZBvTjayNzG3YL/VVQfQaKBXX2+TM3p1xB1Pxd8RYeDQJkJIQRwM3FQSIa+pw==";
591 };
592 };
593 "cryptiles-2.0.5" = {
594 name = "cryptiles";
595 packageName = "cryptiles";
596 version = "2.0.5";
597 src = fetchurl {
598 url = "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz";
599 sha1 = "3bdfecdc608147c1c67202fa291e7dca59eaa3b8";
600 };
601 };
602 "cycle-1.0.3" = {
603 name = "cycle";
604 packageName = "cycle";
605 version = "1.0.3";
606 src = fetchurl {
607 url = "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz";
608 sha1 = "21e80b2be8580f98b468f379430662b046c34ad2";
609 };
610 };
611 "dashdash-1.14.1" = {
612 name = "dashdash";
613 packageName = "dashdash";
614 version = "1.14.1";
615 src = fetchurl {
616 url = "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz";
617 sha1 = "853cfa0f7cbe2fed5de20326b8dd581035f6e2f0";
618 };
619 };
620 "date-now-0.1.4" = {
621 name = "date-now";
622 packageName = "date-now";
623 version = "0.1.4";
624 src = fetchurl {
625 url = "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz";
626 sha1 = "eaf439fd4d4848ad74e5cc7dbef200672b9e345b";
627 };
628 };
629 "dateformat-1.0.2-1.2.3" = {
630 name = "dateformat";
631 packageName = "dateformat";
632 version = "1.0.2-1.2.3";
633 src = fetchurl {
634 url = "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz";
635 sha1 = "b0220c02de98617433b72851cf47de3df2cdbee9";
636 };
637 };
638 "debug-0.7.4" = {
639 name = "debug";
640 packageName = "debug";
641 version = "0.7.4";
642 src = fetchurl {
643 url = "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz";
644 sha1 = "06e1ea8082c2cb14e39806e22e2f6f757f92af39";
645 };
646 };
647 "debug-2.6.9" = {
648 name = "debug";
649 packageName = "debug";
650 version = "2.6.9";
651 src = fetchurl {
652 url = "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz";
653 sha512 = "bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==";
654 };
655 };
656 "deep-extend-0.4.2" = {
657 name = "deep-extend";
658 packageName = "deep-extend";
659 version = "0.4.2";
660 src = fetchurl {
661 url = "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz";
662 sha1 = "48b699c27e334bf89f10892be432f6e4c7d34a7f";
663 };
664 };
665 "deep-is-0.1.3" = {
666 name = "deep-is";
667 packageName = "deep-is";
668 version = "0.1.3";
669 src = fetchurl {
670 url = "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz";
671 sha1 = "b369d6fb5dbc13eecf524f91b070feedc357cf34";
672 };
673 };
674 "delayed-stream-1.0.0" = {
675 name = "delayed-stream";
676 packageName = "delayed-stream";
677 version = "1.0.0";
678 src = fetchurl {
679 url = "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz";
680 sha1 = "df3ae199acadfb7d440aaae0b29e2272b24ec619";
681 };
682 };
683 "delegate-3.2.0" = {
684 name = "delegate";
685 packageName = "delegate";
686 version = "3.2.0";
687 src = fetchurl {
688 url = "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz";
689 sha512 = "IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==";
690 };
691 };
692 "delegates-1.0.0" = {
693 name = "delegates";
694 packageName = "delegates";
695 version = "1.0.0";
696 src = fetchurl {
697 url = "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz";
698 sha1 = "84c6e159b81904fdca59a0ef44cd870d31250f9a";
699 };
700 };
701 "doctrine-0.7.2" = {
702 name = "doctrine";
703 packageName = "doctrine";
704 version = "0.7.2";
705 src = fetchurl {
706 url = "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz";
707 sha1 = "7cb860359ba3be90e040b26b729ce4bfa654c523";
708 };
709 };
710 "dom-serializer-0.1.0" = {
711 name = "dom-serializer";
712 packageName = "dom-serializer";
713 version = "0.1.0";
714 src = fetchurl {
715 url = "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz";
716 sha1 = "073c697546ce0780ce23be4a28e293e40bc30c82";
717 };
718 };
719 "dom5-1.1.0" = {
720 name = "dom5";
721 packageName = "dom5";
722 version = "1.1.0";
723 src = fetchurl {
724 url = "https://registry.npmjs.org/dom5/-/dom5-1.1.0.tgz";
725 sha1 = "3a0c7700c083ab4c4d26938a78b0f0c6dcc37794";
726 };
727 };
728 "dom5-1.3.6" = {
729 name = "dom5";
730 packageName = "dom5";
731 version = "1.3.6";
732 src = fetchurl {
733 url = "https://registry.npmjs.org/dom5/-/dom5-1.3.6.tgz";
734 sha1 = "a7088a9fc5f3b08dc9f6eda4c7abaeb241945e0d";
735 };
736 };
737 "domelementtype-1.1.3" = {
738 name = "domelementtype";
739 packageName = "domelementtype";
740 version = "1.1.3";
741 src = fetchurl {
742 url = "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz";
743 sha1 = "bd28773e2642881aec51544924299c5cd822185b";
744 };
745 };
746 "domelementtype-1.3.0" = {
747 name = "domelementtype";
748 packageName = "domelementtype";
749 version = "1.3.0";
750 src = fetchurl {
751 url = "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz";
752 sha1 = "b17aed82e8ab59e52dd9c19b1756e0fc187204c2";
753 };
754 };
755 "domhandler-2.3.0" = {
756 name = "domhandler";
757 packageName = "domhandler";
758 version = "2.3.0";
759 src = fetchurl {
760 url = "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz";
761 sha1 = "2de59a0822d5027fabff6f032c2b25a2a8abe738";
762 };
763 };
764 "domutils-1.5.1" = {
765 name = "domutils";
766 packageName = "domutils";
767 version = "1.5.1";
768 src = fetchurl {
769 url = "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz";
770 sha1 = "dcd8488a26f563d61079e48c9f7b7e32373682cf";
771 };
772 };
773 "ecc-jsbn-0.1.2" = {
774 name = "ecc-jsbn";
775 packageName = "ecc-jsbn";
776 version = "0.1.2";
777 src = fetchurl {
778 url = "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz";
779 sha1 = "3a83a904e54353287874c564b7549386849a98c9";
780 };
781 };
782 "entities-1.0.0" = {
783 name = "entities";
784 packageName = "entities";
785 version = "1.0.0";
786 src = fetchurl {
787 url = "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz";
788 sha1 = "b2987aa3821347fcde642b24fdfc9e4fb712bf26";
789 };
790 };
791 "entities-1.1.1" = {
792 name = "entities";
793 packageName = "entities";
794 version = "1.1.1";
795 src = fetchurl {
796 url = "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz";
797 sha1 = "6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0";
798 };
799 };
800 "errno-0.1.7" = {
801 name = "errno";
802 packageName = "errno";
803 version = "0.1.7";
804 src = fetchurl {
805 url = "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz";
806 sha512 = "MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==";
807 };
808 };
809 "es6-promise-2.3.0" = {
810 name = "es6-promise";
811 packageName = "es6-promise";
812 version = "2.3.0";
813 src = fetchurl {
814 url = "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz";
815 sha1 = "96edb9f2fdb01995822b263dd8aadab6748181bc";
816 };
817 };
818 "es6-promise-4.2.4" = {
819 name = "es6-promise";
820 packageName = "es6-promise";
821 version = "4.2.4";
822 src = fetchurl {
823 url = "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz";
824 sha512 = "/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==";
825 };
826 };
827 "escape-string-regexp-1.0.5" = {
828 name = "escape-string-regexp";
829 packageName = "escape-string-regexp";
830 version = "1.0.5";
831 src = fetchurl {
832 url = "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz";
833 sha1 = "1b61c0562190a8dff6ae3bb2cf0200ca130b86d4";
834 };
835 };
836 "escodegen-1.11.0" = {
837 name = "escodegen";
838 packageName = "escodegen";
839 version = "1.11.0";
840 src = fetchurl {
841 url = "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz";
842 sha512 = "IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==";
843 };
844 };
845 "espree-3.5.4" = {
846 name = "espree";
847 packageName = "espree";
848 version = "3.5.4";
849 src = fetchurl {
850 url = "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz";
851 sha512 = "yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==";
852 };
853 };
854 "esprima-1.0.4" = {
855 name = "esprima";
856 packageName = "esprima";
857 version = "1.0.4";
858 src = fetchurl {
859 url = "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz";
860 sha1 = "9f557e08fc3b4d26ece9dd34f8fbf476b62585ad";
861 };
862 };
863 "esprima-3.1.3" = {
864 name = "esprima";
865 packageName = "esprima";
866 version = "3.1.3";
867 src = fetchurl {
868 url = "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz";
869 sha1 = "fdca51cee6133895e3c88d535ce49dbff62a4633";
870 };
871 };
872 "estraverse-3.1.0" = {
873 name = "estraverse";
874 packageName = "estraverse";
875 version = "3.1.0";
876 src = fetchurl {
877 url = "https://registry.npmjs.org/estraverse/-/estraverse-3.1.0.tgz";
878 sha1 = "15e28a446b8b82bc700ccc8b96c78af4da0d6cba";
879 };
880 };
881 "estraverse-4.2.0" = {
882 name = "estraverse";
883 packageName = "estraverse";
884 version = "4.2.0";
885 src = fetchurl {
886 url = "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz";
887 sha1 = "0dee3fed31fcd469618ce7342099fc1afa0bdb13";
888 };
889 };
890 "esutils-1.1.6" = {
891 name = "esutils";
892 packageName = "esutils";
893 version = "1.1.6";
894 src = fetchurl {
895 url = "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz";
896 sha1 = "c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375";
897 };
898 };
899 "esutils-2.0.2" = {
900 name = "esutils";
901 packageName = "esutils";
902 version = "2.0.2";
903 src = fetchurl {
904 url = "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz";
905 sha1 = "0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b";
906 };
907 };
908 "eventemitter2-0.4.14" = {
909 name = "eventemitter2";
910 packageName = "eventemitter2";
911 version = "0.4.14";
912 src = fetchurl {
913 url = "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz";
914 sha1 = "8f61b75cde012b2e9eb284d4545583b5643b61ab";
915 };
916 };
917 "exit-0.1.2" = {
918 name = "exit";
919 packageName = "exit";
920 version = "0.1.2";
921 src = fetchurl {
922 url = "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz";
923 sha1 = "0632638f8d877cc82107d30a0fff1a17cba1cd0c";
924 };
925 };
926 "extend-3.0.2" = {
927 name = "extend";
928 packageName = "extend";
929 version = "3.0.2";
930 src = fetchurl {
931 url = "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz";
932 sha512 = "fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==";
933 };
934 };
935 "extract-zip-1.6.7" = {
936 name = "extract-zip";
937 packageName = "extract-zip";
938 version = "1.6.7";
939 src = fetchurl {
940 url = "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz";
941 sha1 = "a840b4b8af6403264c8db57f4f1a74333ef81fe9";
942 };
943 };
944 "extsprintf-1.3.0" = {
945 name = "extsprintf";
946 packageName = "extsprintf";
947 version = "1.3.0";
948 src = fetchurl {
949 url = "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz";
950 sha1 = "96918440e3041a7a414f8c52e3c574eb3c3e1e05";
951 };
952 };
953 "eyes-0.1.8" = {
954 name = "eyes";
955 packageName = "eyes";
956 version = "0.1.8";
957 src = fetchurl {
958 url = "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz";
959 sha1 = "62cf120234c683785d902348a800ef3e0cc20bc0";
960 };
961 };
962 "fast-levenshtein-2.0.6" = {
963 name = "fast-levenshtein";
964 packageName = "fast-levenshtein";
965 version = "2.0.6";
966 src = fetchurl {
967 url = "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz";
968 sha1 = "3d8a5c66883a16a30ca8643e851f19baa7797917";
969 };
970 };
971 "favico.js-0.3.10" = {
972 name = "favico.js";
973 packageName = "favico.js";
974 version = "0.3.10";
975 src = fetchurl {
976 url = "https://registry.npmjs.org/favico.js/-/favico.js-0.3.10.tgz";
977 sha1 = "80586e27a117f24a8d51c18a99bdc714d4339301";
978 };
979 };
980 "faye-websocket-0.4.4" = {
981 name = "faye-websocket";
982 packageName = "faye-websocket";
983 version = "0.4.4";
984 src = fetchurl {
985 url = "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.4.4.tgz";
986 sha1 = "c14c5b3bf14d7417ffbfd990c0a7495cd9f337bc";
987 };
988 };
989 "fd-slicer-1.0.1" = {
990 name = "fd-slicer";
991 packageName = "fd-slicer";
992 version = "1.0.1";
993 src = fetchurl {
994 url = "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz";
995 sha1 = "8b5bcbd9ec327c5041bf9ab023fd6750f1177e65";
996 };
997 };
998 "feature-detect-es6-1.5.0" = {
999 name = "feature-detect-es6";
1000 packageName = "feature-detect-es6";
1001 version = "1.5.0";
1002 src = fetchurl {
1003 url = "https://registry.npmjs.org/feature-detect-es6/-/feature-detect-es6-1.5.0.tgz";
1004 sha512 = "DzWPIGzTnfp3/KK1d/YPfmgLqeDju9F2DQYBL35VusgSApcA7XGqVtXfR4ETOOFEzdFJ3J7zh0Gkk011TiA4uQ==";
1005 };
1006 };
1007 "file-sync-cmp-0.1.1" = {
1008 name = "file-sync-cmp";
1009 packageName = "file-sync-cmp";
1010 version = "0.1.1";
1011 src = fetchurl {
1012 url = "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz";
1013 sha1 = "a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b";
1014 };
1015 };
1016 "find-replace-1.0.3" = {
1017 name = "find-replace";
1018 packageName = "find-replace";
1019 version = "1.0.3";
1020 src = fetchurl {
1021 url = "https://registry.npmjs.org/find-replace/-/find-replace-1.0.3.tgz";
1022 sha1 = "b88e7364d2d9c959559f388c66670d6130441fa0";
1023 };
1024 };
1025 "findit-2.0.0" = {
1026 name = "findit";
1027 packageName = "findit";
1028 version = "2.0.0";
1029 src = fetchurl {
1030 url = "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz";
1031 sha1 = "6509f0126af4c178551cfa99394e032e13a4d56e";
1032 };
1033 };
1034 "findup-sync-0.1.3" = {
1035 name = "findup-sync";
1036 packageName = "findup-sync";
1037 version = "0.1.3";
1038 src = fetchurl {
1039 url = "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz";
1040 sha1 = "7f3e7a97b82392c653bf06589bd85190e93c3683";
1041 };
1042 };
1043 "foreachasync-3.0.0" = {
1044 name = "foreachasync";
1045 packageName = "foreachasync";
1046 version = "3.0.0";
1047 src = fetchurl {
1048 url = "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz";
1049 sha1 = "5502987dc8714be3392097f32e0071c9dee07cf6";
1050 };
1051 };
1052 "forever-agent-0.6.1" = {
1053 name = "forever-agent";
1054 packageName = "forever-agent";
1055 version = "0.6.1";
1056 src = fetchurl {
1057 url = "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz";
1058 sha1 = "fbc71f0c41adeb37f96c577ad1ed42d8fdacca91";
1059 };
1060 };
1061 "form-data-2.1.4" = {
1062 name = "form-data";
1063 packageName = "form-data";
1064 version = "2.1.4";
1065 src = fetchurl {
1066 url = "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz";
1067 sha1 = "33c183acf193276ecaa98143a69e94bfee1750d1";
1068 };
1069 };
1070 "fs-extra-0.6.4" = {
1071 name = "fs-extra";
1072 packageName = "fs-extra";
1073 version = "0.6.4";
1074 src = fetchurl {
1075 url = "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz";
1076 sha1 = "f46f0c75b7841f8d200b3348cd4d691d5a099d15";
1077 };
1078 };
1079 "fs-extra-1.0.0" = {
1080 name = "fs-extra";
1081 packageName = "fs-extra";
1082 version = "1.0.0";
1083 src = fetchurl {
1084 url = "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz";
1085 sha1 = "cd3ce5f7e7cb6145883fcae3191e9877f8587950";
1086 };
1087 };
1088 "fs.extra-1.3.2" = {
1089 name = "fs.extra";
1090 packageName = "fs.extra";
1091 version = "1.3.2";
1092 src = fetchurl {
1093 url = "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz";
1094 sha1 = "dd023f93013bee24531f1b33514c37b20fd93349";
1095 };
1096 };
1097 "fs.realpath-1.0.0" = {
1098 name = "fs.realpath";
1099 packageName = "fs.realpath";
1100 version = "1.0.0";
1101 src = fetchurl {
1102 url = "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz";
1103 sha1 = "1504ad2523158caa40db4a2787cb01411994ea4f";
1104 };
1105 };
1106 "gauge-2.7.4" = {
1107 name = "gauge";
1108 packageName = "gauge";
1109 version = "2.7.4";
1110 src = fetchurl {
1111 url = "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz";
1112 sha1 = "2c03405c7538c39d7eb37b317022e325fb018bf7";
1113 };
1114 };
1115 "gaze-0.5.2" = {
1116 name = "gaze";
1117 packageName = "gaze";
1118 version = "0.5.2";
1119 src = fetchurl {
1120 url = "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz";
1121 sha1 = "40b709537d24d1d45767db5a908689dfe69ac44f";
1122 };
1123 };
1124 "getobject-0.1.0" = {
1125 name = "getobject";
1126 packageName = "getobject";
1127 version = "0.1.0";
1128 src = fetchurl {
1129 url = "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz";
1130 sha1 = "047a449789fa160d018f5486ed91320b6ec7885c";
1131 };
1132 };
1133 "getpass-0.1.7" = {
1134 name = "getpass";
1135 packageName = "getpass";
1136 version = "0.1.7";
1137 src = fetchurl {
1138 url = "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz";
1139 sha1 = "5eff8e3e684d569ae4cb2b1282604e8ba62149fa";
1140 };
1141 };
1142 "glob-3.1.21" = {
1143 name = "glob";
1144 packageName = "glob";
1145 version = "3.1.21";
1146 src = fetchurl {
1147 url = "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz";
1148 sha1 = "d29e0a055dea5138f4d07ed40e8982e83c2066cd";
1149 };
1150 };
1151 "glob-3.2.11" = {
1152 name = "glob";
1153 packageName = "glob";
1154 version = "3.2.11";
1155 src = fetchurl {
1156 url = "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz";
1157 sha1 = "4a973f635b9190f715d10987d5c00fd2815ebe3d";
1158 };
1159 };
1160 "glob-7.1.2" = {
1161 name = "glob";
1162 packageName = "glob";
1163 version = "7.1.2";
1164 src = fetchurl {
1165 url = "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz";
1166 sha512 = "MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==";
1167 };
1168 };
1169 "globule-0.1.0" = {
1170 name = "globule";
1171 packageName = "globule";
1172 version = "0.1.0";
1173 src = fetchurl {
1174 url = "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz";
1175 sha1 = "d9c8edde1da79d125a151b79533b978676346ae5";
1176 };
1177 };
1178 "good-listener-1.2.2" = {
1179 name = "good-listener";
1180 packageName = "good-listener";
1181 version = "1.2.2";
1182 src = fetchurl {
1183 url = "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz";
1184 sha1 = "d53b30cdf9313dffb7dc9a0d477096aa6d145c50";
1185 };
1186 };
1187 "graceful-fs-1.2.3" = {
1188 name = "graceful-fs";
1189 packageName = "graceful-fs";
1190 version = "1.2.3";
1191 src = fetchurl {
1192 url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz";
1193 sha1 = "15a4806a57547cb2d2dbf27f42e89a8c3451b364";
1194 };
1195 };
1196 "graceful-fs-4.1.11" = {
1197 name = "graceful-fs";
1198 packageName = "graceful-fs";
1199 version = "4.1.11";
1200 src = fetchurl {
1201 url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz";
1202 sha1 = "0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658";
1203 };
1204 };
7 1205 "grunt-0.4.5" = {
8 1206 name = "grunt";
9 1207 packageName = "grunt";
@@ -13,6 +1211,15 b' let'
13 1211 sha1 = "56937cd5194324adff6d207631832a9d6ba4e7f0";
14 1212 };
15 1213 };
1214 "grunt-contrib-concat-0.5.1" = {
1215 name = "grunt-contrib-concat";
1216 packageName = "grunt-contrib-concat";
1217 version = "0.5.1";
1218 src = fetchurl {
1219 url = "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.5.1.tgz";
1220 sha1 = "953c6efdfdfd2c107ab9c85077f2d4b24d31cd49";
1221 };
1222 };
16 1223 "grunt-contrib-copy-1.0.0" = {
17 1224 name = "grunt-contrib-copy";
18 1225 packageName = "grunt-contrib-copy";
@@ -22,15 +1229,6 b' let'
22 1229 sha1 = "7060c6581e904b8ab0d00f076e0a8f6e3e7c3573";
23 1230 };
24 1231 };
25 "grunt-contrib-concat-0.5.1" = {
26 name = "grunt-contrib-concat";
27 packageName = "grunt-contrib-concat";
28 version = "0.5.1";
29 src = fetchurl {
30 url = "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.5.1.tgz";
31 sha1 = "953c6efdfdfd2c107ab9c85077f2d4b24d31cd49";
32 };
33 };
34 1232 "grunt-contrib-jshint-0.12.0" = {
35 1233 name = "grunt-contrib-jshint";
36 1234 packageName = "grunt-contrib-jshint";
@@ -58,24 +1256,6 b' let'
58 1256 sha1 = "64fdcba25a635f5b4da1b6ce6f90da0aeb6e3f15";
59 1257 };
60 1258 };
61 "crisper-2.1.1" = {
62 name = "crisper";
63 packageName = "crisper";
64 version = "2.1.1";
65 src = fetchurl {
66 url = "https://registry.npmjs.org/crisper/-/crisper-2.1.1.tgz";
67 sha1 = "4cc7321c3e90f3c5cbdc3503217f118fd7d5c51c";
68 };
69 };
70 "vulcanize-1.16.0" = {
71 name = "vulcanize";
72 packageName = "vulcanize";
73 version = "1.16.0";
74 src = fetchurl {
75 url = "https://registry.npmjs.org/vulcanize/-/vulcanize-1.16.0.tgz";
76 sha1 = "b0ce3b0044d194ad4908ae4f1a6c6110a6e4d5e6";
77 };
78 };
79 1259 "grunt-crisper-1.0.1" = {
80 1260 name = "grunt-crisper";
81 1261 packageName = "grunt-crisper";
@@ -85,6 +1265,33 b' let'
85 1265 sha1 = "e7c091dcaff10deb0091e3035ca7e54008991fe7";
86 1266 };
87 1267 };
1268 "grunt-legacy-log-0.1.3" = {
1269 name = "grunt-legacy-log";
1270 packageName = "grunt-legacy-log";
1271 version = "0.1.3";
1272 src = fetchurl {
1273 url = "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz";
1274 sha1 = "ec29426e803021af59029f87d2f9cd7335a05531";
1275 };
1276 };
1277 "grunt-legacy-log-utils-0.1.1" = {
1278 name = "grunt-legacy-log-utils";
1279 packageName = "grunt-legacy-log-utils";
1280 version = "0.1.1";
1281 src = fetchurl {
1282 url = "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz";
1283 sha1 = "c0706b9dd9064e116f36f23fe4e6b048672c0f7e";
1284 };
1285 };
1286 "grunt-legacy-util-0.2.0" = {
1287 name = "grunt-legacy-util";
1288 packageName = "grunt-legacy-util";
1289 version = "0.2.0";
1290 src = fetchurl {
1291 url = "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz";
1292 sha1 = "93324884dbf7e37a9ff7c026dff451d94a9e554b";
1293 };
1294 };
88 1295 "grunt-vulcanize-1.0.0" = {
89 1296 name = "grunt-vulcanize";
90 1297 packageName = "grunt-vulcanize";
@@ -94,437 +1301,31 b' let'
94 1301 sha1 = "f4d6cfef274f8216c06f6c290e7dbb3b9e9e3b0f";
95 1302 };
96 1303 };
97 "node2nix-1.3.0" = {
98 name = "node2nix";
99 packageName = "node2nix";
100 version = "1.3.0";
101 src = fetchurl {
102 url = "https://registry.npmjs.org/node2nix/-/node2nix-1.3.0.tgz";
103 sha1 = "e830a3bc5880dd22ae47be71a147f776542850cc";
104 };
105 };
106 "jshint-2.9.5" = {
107 name = "jshint";
108 packageName = "jshint";
109 version = "2.9.5";
110 src = fetchurl {
111 url = "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz";
112 sha1 = "1e7252915ce681b40827ee14248c46d34e9aa62c";
113 };
114 };
115 "bower-1.8.2" = {
116 name = "bower";
117 packageName = "bower";
118 version = "1.8.2";
119 src = fetchurl {
120 url = "https://registry.npmjs.org/bower/-/bower-1.8.2.tgz";
121 sha1 = "adf53529c8d4af02ef24fb8d5341c1419d33e2f7";
122 };
123 };
124 "jquery-1.11.3" = {
125 name = "jquery";
126 packageName = "jquery";
127 version = "1.11.3";
128 src = fetchurl {
129 url = "https://registry.npmjs.org/jquery/-/jquery-1.11.3.tgz";
130 sha1 = "dd8b74278b27102d29df63eae28308a8cfa1b583";
131 };
132 };
133 "favico.js-0.3.10" = {
134 name = "favico.js";
135 packageName = "favico.js";
136 version = "0.3.10";
137 src = fetchurl {
138 url = "https://registry.npmjs.org/favico.js/-/favico.js-0.3.10.tgz";
139 sha1 = "80586e27a117f24a8d51c18a99bdc714d4339301";
140 };
141 };
142 "clipboard-1.7.1" = {
143 name = "clipboard";
144 packageName = "clipboard";
145 version = "1.7.1";
146 src = fetchurl {
147 url = "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz";
148 sha1 = "360d6d6946e99a7a1fef395e42ba92b5e9b5a16b";
149 };
150 };
151 "moment-2.18.1" = {
152 name = "moment";
153 packageName = "moment";
154 version = "2.18.1";
155 src = fetchurl {
156 url = "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz";
157 sha1 = "c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f";
158 };
159 };
160 "mousetrap-1.6.1" = {
161 name = "mousetrap";
162 packageName = "mousetrap";
163 version = "1.6.1";
164 src = fetchurl {
165 url = "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.1.tgz";
166 sha1 = "2a085f5c751294c75e7e81f6ec2545b29cbf42d9";
167 };
168 };
169 "appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1" = {
170 name = "appenlight-client";
171 packageName = "appenlight-client";
172 version = "0.5.1";
173 src = fetchgit {
174 url = "https://git@github.com/AppEnlight/appenlight-client-js.git";
175 rev = "14712c64c230fbbe94fcbc8094aef5eb3b90b307";
176 sha256 = "92111f1104cbf0b31303c366c0fa752cf68af7ddde40d0161edd1b5fd9dd07f7";
177 };
178 };
179 "async-0.1.22" = {
180 name = "async";
181 packageName = "async";
182 version = "0.1.22";
183 src = fetchurl {
184 url = "https://registry.npmjs.org/async/-/async-0.1.22.tgz";
185 sha1 = "0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061";
186 };
187 };
188 "coffee-script-1.3.3" = {
189 name = "coffee-script";
190 packageName = "coffee-script";
191 version = "1.3.3";
192 src = fetchurl {
193 url = "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz";
194 sha1 = "150d6b4cb522894369efed6a2101c20bc7f4a4f4";
195 };
196 };
197 "colors-0.6.2" = {
198 name = "colors";
199 packageName = "colors";
200 version = "0.6.2";
201 src = fetchurl {
202 url = "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz";
203 sha1 = "2423fe6678ac0c5dae8852e5d0e5be08c997abcc";
204 };
205 };
206 "dateformat-1.0.2-1.2.3" = {
207 name = "dateformat";
208 packageName = "dateformat";
209 version = "1.0.2-1.2.3";
210 src = fetchurl {
211 url = "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz";
212 sha1 = "b0220c02de98617433b72851cf47de3df2cdbee9";
213 };
214 };
215 "eventemitter2-0.4.14" = {
216 name = "eventemitter2";
217 packageName = "eventemitter2";
218 version = "0.4.14";
219 src = fetchurl {
220 url = "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz";
221 sha1 = "8f61b75cde012b2e9eb284d4545583b5643b61ab";
222 };
223 };
224 "findup-sync-0.1.3" = {
225 name = "findup-sync";
226 packageName = "findup-sync";
227 version = "0.1.3";
228 src = fetchurl {
229 url = "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz";
230 sha1 = "7f3e7a97b82392c653bf06589bd85190e93c3683";
231 };
232 };
233 "glob-3.1.21" = {
234 name = "glob";
235 packageName = "glob";
236 version = "3.1.21";
237 src = fetchurl {
238 url = "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz";
239 sha1 = "d29e0a055dea5138f4d07ed40e8982e83c2066cd";
240 };
241 };
242 "hooker-0.2.3" = {
243 name = "hooker";
244 packageName = "hooker";
245 version = "0.2.3";
246 src = fetchurl {
247 url = "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz";
248 sha1 = "b834f723cc4a242aa65963459df6d984c5d3d959";
249 };
250 };
251 "iconv-lite-0.2.11" = {
252 name = "iconv-lite";
253 packageName = "iconv-lite";
254 version = "0.2.11";
255 src = fetchurl {
256 url = "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz";
257 sha1 = "1ce60a3a57864a292d1321ff4609ca4bb965adc8";
258 };
259 };
260 "minimatch-0.2.14" = {
261 name = "minimatch";
262 packageName = "minimatch";
263 version = "0.2.14";
264 src = fetchurl {
265 url = "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz";
266 sha1 = "c74e780574f63c6f9a090e90efbe6ef53a6a756a";
267 };
268 };
269 "nopt-1.0.10" = {
270 name = "nopt";
271 packageName = "nopt";
272 version = "1.0.10";
273 src = fetchurl {
274 url = "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz";
275 sha1 = "6ddd21bd2a31417b92727dd585f8a6f37608ebee";
276 };
277 };
278 "rimraf-2.2.8" = {
279 name = "rimraf";
280 packageName = "rimraf";
281 version = "2.2.8";
282 src = fetchurl {
283 url = "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz";
284 sha1 = "e439be2aaee327321952730f99a8929e4fc50582";
285 };
286 };
287 "lodash-0.9.2" = {
288 name = "lodash";
289 packageName = "lodash";
290 version = "0.9.2";
291 src = fetchurl {
292 url = "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz";
293 sha1 = "8f3499c5245d346d682e5b0d3b40767e09f1a92c";
294 };
295 };
296 "underscore.string-2.2.1" = {
297 name = "underscore.string";
298 packageName = "underscore.string";
299 version = "2.2.1";
300 src = fetchurl {
301 url = "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz";
302 sha1 = "d7c0fa2af5d5a1a67f4253daee98132e733f0f19";
303 };
304 };
305 "which-1.0.9" = {
306 name = "which";
307 packageName = "which";
308 version = "1.0.9";
309 src = fetchurl {
310 url = "https://registry.npmjs.org/which/-/which-1.0.9.tgz";
311 sha1 = "460c1da0f810103d0321a9b633af9e575e64486f";
312 };
313 };
314 "js-yaml-2.0.5" = {
315 name = "js-yaml";
316 packageName = "js-yaml";
317 version = "2.0.5";
318 src = fetchurl {
319 url = "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz";
320 sha1 = "a25ae6509999e97df278c6719da11bd0687743a8";
321 };
322 };
323 "exit-0.1.2" = {
324 name = "exit";
325 packageName = "exit";
326 version = "0.1.2";
327 src = fetchurl {
328 url = "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz";
329 sha1 = "0632638f8d877cc82107d30a0fff1a17cba1cd0c";
330 };
331 };
332 "getobject-0.1.0" = {
333 name = "getobject";
334 packageName = "getobject";
1304 "har-schema-1.0.5" = {
1305 name = "har-schema";
1306 packageName = "har-schema";
1307 version = "1.0.5";
1308 src = fetchurl {
1309 url = "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz";
1310 sha1 = "d263135f43307c02c602afc8fe95970c0151369e";
1311 };
1312 };
1313 "har-validator-4.2.1" = {
1314 name = "har-validator";
1315 packageName = "har-validator";
1316 version = "4.2.1";
1317 src = fetchurl {
1318 url = "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz";
1319 sha1 = "33481d0f1bbff600dd203d75812a6a5fba002e2a";
1320 };
1321 };
1322 "has-ansi-0.1.0" = {
1323 name = "has-ansi";
1324 packageName = "has-ansi";
335 1325 version = "0.1.0";
336 1326 src = fetchurl {
337 url = "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz";
338 sha1 = "047a449789fa160d018f5486ed91320b6ec7885c";
339 };
340 };
341 "grunt-legacy-util-0.2.0" = {
342 name = "grunt-legacy-util";
343 packageName = "grunt-legacy-util";
344 version = "0.2.0";
345 src = fetchurl {
346 url = "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz";
347 sha1 = "93324884dbf7e37a9ff7c026dff451d94a9e554b";
348 };
349 };
350 "grunt-legacy-log-0.1.3" = {
351 name = "grunt-legacy-log";
352 packageName = "grunt-legacy-log";
353 version = "0.1.3";
354 src = fetchurl {
355 url = "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz";
356 sha1 = "ec29426e803021af59029f87d2f9cd7335a05531";
357 };
358 };
359 "glob-3.2.11" = {
360 name = "glob";
361 packageName = "glob";
362 version = "3.2.11";
363 src = fetchurl {
364 url = "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz";
365 sha1 = "4a973f635b9190f715d10987d5c00fd2815ebe3d";
366 };
367 };
368 "lodash-2.4.2" = {
369 name = "lodash";
370 packageName = "lodash";
371 version = "2.4.2";
372 src = fetchurl {
373 url = "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz";
374 sha1 = "fadd834b9683073da179b3eae6d9c0d15053f73e";
375 };
376 };
377 "inherits-2.0.3" = {
378 name = "inherits";
379 packageName = "inherits";
380 version = "2.0.3";
381 src = fetchurl {
382 url = "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz";
383 sha1 = "633c2c83e3da42a502f52466022480f4208261de";
384 };
385 };
386 "minimatch-0.3.0" = {
387 name = "minimatch";
388 packageName = "minimatch";
389 version = "0.3.0";
390 src = fetchurl {
391 url = "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz";
392 sha1 = "275d8edaac4f1bb3326472089e7949c8394699dd";
393 };
394 };
395 "lru-cache-2.7.3" = {
396 name = "lru-cache";
397 packageName = "lru-cache";
398 version = "2.7.3";
399 src = fetchurl {
400 url = "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz";
401 sha1 = "6d4524e8b955f95d4f5b58851ce21dd72fb4e952";
402 };
403 };
404 "sigmund-1.0.1" = {
405 name = "sigmund";
406 packageName = "sigmund";
407 version = "1.0.1";
408 src = fetchurl {
409 url = "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz";
410 sha1 = "3ff21f198cad2175f9f3b781853fd94d0d19b590";
411 };
412 };
413 "graceful-fs-1.2.3" = {
414 name = "graceful-fs";
415 packageName = "graceful-fs";
416 version = "1.2.3";
417 src = fetchurl {
418 url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz";
419 sha1 = "15a4806a57547cb2d2dbf27f42e89a8c3451b364";
420 };
421 };
422 "inherits-1.0.2" = {
423 name = "inherits";
424 packageName = "inherits";
425 version = "1.0.2";
426 src = fetchurl {
427 url = "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz";
428 sha1 = "ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b";
429 };
430 };
431 "abbrev-1.1.0" = {
432 name = "abbrev";
433 packageName = "abbrev";
434 version = "1.1.0";
435 src = fetchurl {
436 url = "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz";
437 sha1 = "d0554c2256636e2f56e7c2e5ad183f859428d81f";
438 };
439 };
440 "argparse-0.1.16" = {
441 name = "argparse";
442 packageName = "argparse";
443 version = "0.1.16";
444 src = fetchurl {
445 url = "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz";
446 sha1 = "cfd01e0fbba3d6caed049fbd758d40f65196f57c";
447 };
448 };
449 "esprima-1.0.4" = {
450 name = "esprima";
451 packageName = "esprima";
452 version = "1.0.4";
453 src = fetchurl {
454 url = "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz";
455 sha1 = "9f557e08fc3b4d26ece9dd34f8fbf476b62585ad";
456 };
457 };
458 "underscore-1.7.0" = {
459 name = "underscore";
460 packageName = "underscore";
461 version = "1.7.0";
462 src = fetchurl {
463 url = "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz";
464 sha1 = "6bbaf0877500d36be34ecaa584e0db9fef035209";
465 };
466 };
467 "underscore.string-2.4.0" = {
468 name = "underscore.string";
469 packageName = "underscore.string";
470 version = "2.4.0";
471 src = fetchurl {
472 url = "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz";
473 sha1 = "8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b";
474 };
475 };
476 "grunt-legacy-log-utils-0.1.1" = {
477 name = "grunt-legacy-log-utils";
478 packageName = "grunt-legacy-log-utils";
479 version = "0.1.1";
480 src = fetchurl {
481 url = "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz";
482 sha1 = "c0706b9dd9064e116f36f23fe4e6b048672c0f7e";
483 };
484 };
485 "underscore.string-2.3.3" = {
486 name = "underscore.string";
487 packageName = "underscore.string";
488 version = "2.3.3";
489 src = fetchurl {
490 url = "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz";
491 sha1 = "71c08bf6b428b1133f37e78fa3a21c82f7329b0d";
492 };
493 };
494 "chalk-1.1.3" = {
495 name = "chalk";
496 packageName = "chalk";
497 version = "1.1.3";
498 src = fetchurl {
499 url = "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz";
500 sha1 = "a8115c55e4a702fe4d150abd3872822a7e09fc98";
501 };
502 };
503 "file-sync-cmp-0.1.1" = {
504 name = "file-sync-cmp";
505 packageName = "file-sync-cmp";
506 version = "0.1.1";
507 src = fetchurl {
508 url = "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz";
509 sha1 = "a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b";
510 };
511 };
512 "ansi-styles-2.2.1" = {
513 name = "ansi-styles";
514 packageName = "ansi-styles";
515 version = "2.2.1";
516 src = fetchurl {
517 url = "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz";
518 sha1 = "b432dd3358b634cf75e1e4664368240533c1ddbe";
519 };
520 };
521 "escape-string-regexp-1.0.5" = {
522 name = "escape-string-regexp";
523 packageName = "escape-string-regexp";
524 version = "1.0.5";
525 src = fetchurl {
526 url = "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz";
527 sha1 = "1b61c0562190a8dff6ae3bb2cf0200ca130b86d4";
1327 url = "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz";
1328 sha1 = "84f265aae8c0e6a88a12d7022894b7568894c62e";
528 1329 };
529 1330 };
530 1331 "has-ansi-2.0.0" = {
@@ -536,148 +1337,94 b' let'
536 1337 sha1 = "34f5049ce1ecdf2b0649af3ef24e45ed35416d91";
537 1338 };
538 1339 };
539 "strip-ansi-3.0.1" = {
540 name = "strip-ansi";
541 packageName = "strip-ansi";
542 version = "3.0.1";
543 src = fetchurl {
544 url = "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz";
545 sha1 = "6a385fb8853d952d5ff05d0e8aaf94278dc63dcf";
546 };
547 };
548 "supports-color-2.0.0" = {
549 name = "supports-color";
550 packageName = "supports-color";
551 version = "2.0.0";
552 src = fetchurl {
553 url = "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz";
554 sha1 = "535d045ce6b6363fa40117084629995e9df324c7";
555 };
556 };
557 "ansi-regex-2.1.1" = {
558 name = "ansi-regex";
559 packageName = "ansi-regex";
560 version = "2.1.1";
561 src = fetchurl {
562 url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz";
563 sha1 = "c3b33ab5ee360d86e0e628f0468ae7ef27d654df";
564 };
565 };
566 "chalk-0.5.1" = {
567 name = "chalk";
568 packageName = "chalk";
569 version = "0.5.1";
570 src = fetchurl {
571 url = "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz";
572 sha1 = "663b3a648b68b55d04690d49167aa837858f2174";
573 };
574 };
575 "source-map-0.3.0" = {
576 name = "source-map";
577 packageName = "source-map";
578 version = "0.3.0";
579 src = fetchurl {
580 url = "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz";
581 sha1 = "8586fb9a5a005e5b501e21cd18b6f21b457ad1f9";
582 };
583 };
584 "ansi-styles-1.1.0" = {
585 name = "ansi-styles";
586 packageName = "ansi-styles";
587 version = "1.1.0";
588 src = fetchurl {
589 url = "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz";
590 sha1 = "eaecbf66cd706882760b2f4691582b8f55d7a7de";
591 };
592 };
593 "has-ansi-0.1.0" = {
594 name = "has-ansi";
595 packageName = "has-ansi";
596 version = "0.1.0";
597 src = fetchurl {
598 url = "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz";
599 sha1 = "84f265aae8c0e6a88a12d7022894b7568894c62e";
600 };
601 };
602 "strip-ansi-0.3.0" = {
603 name = "strip-ansi";
604 packageName = "strip-ansi";
605 version = "0.3.0";
606 src = fetchurl {
607 url = "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz";
608 sha1 = "25f48ea22ca79187f3174a4db8759347bb126220";
609 };
610 };
611 "supports-color-0.2.0" = {
612 name = "supports-color";
613 packageName = "supports-color";
614 version = "0.2.0";
615 src = fetchurl {
616 url = "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz";
617 sha1 = "d92de2694eb3f67323973d7ae3d8b55b4c22190a";
618 };
619 };
620 "ansi-regex-0.2.1" = {
621 name = "ansi-regex";
622 packageName = "ansi-regex";
623 version = "0.2.1";
624 src = fetchurl {
625 url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz";
626 sha1 = "0d8e946967a3d8143f93e24e298525fc1b2235f9";
627 };
628 };
629 "amdefine-1.0.1" = {
630 name = "amdefine";
631 packageName = "amdefine";
632 version = "1.0.1";
633 src = fetchurl {
634 url = "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz";
635 sha1 = "4a5282ac164729e93619bcfd3ad151f817ce91f5";
636 };
637 };
638 "async-2.5.0" = {
639 name = "async";
640 packageName = "async";
641 version = "2.5.0";
642 src = fetchurl {
643 url = "https://registry.npmjs.org/async/-/async-2.5.0.tgz";
644 sha1 = "843190fd6b7357a0b9e1c956edddd5ec8462b54d";
645 };
646 };
647 "less-2.7.2" = {
648 name = "less";
649 packageName = "less";
650 version = "2.7.2";
651 src = fetchurl {
652 url = "https://registry.npmjs.org/less/-/less-2.7.2.tgz";
653 sha1 = "368d6cc73e1fb03981183280918743c5dcf9b3df";
654 };
655 };
656 "lodash-4.17.4" = {
657 name = "lodash";
658 packageName = "lodash";
659 version = "4.17.4";
660 src = fetchurl {
661 url = "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz";
662 sha1 = "78203a4d1c328ae1d86dca6460e369b57f4055ae";
663 };
664 };
665 "errno-0.1.4" = {
666 name = "errno";
667 packageName = "errno";
668 version = "0.1.4";
669 src = fetchurl {
670 url = "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz";
671 sha1 = "b896e23a9e5e8ba33871fc996abd3635fc9a1c7d";
672 };
673 };
674 "graceful-fs-4.1.11" = {
675 name = "graceful-fs";
676 packageName = "graceful-fs";
677 version = "4.1.11";
678 src = fetchurl {
679 url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz";
680 sha1 = "0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658";
1340 "has-unicode-2.0.1" = {
1341 name = "has-unicode";
1342 packageName = "has-unicode";
1343 version = "2.0.1";
1344 src = fetchurl {
1345 url = "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz";
1346 sha1 = "e0e6fe6a28cf51138855e086d1691e771de2a8b9";
1347 };
1348 };
1349 "hasha-2.2.0" = {
1350 name = "hasha";
1351 packageName = "hasha";
1352 version = "2.2.0";
1353 src = fetchurl {
1354 url = "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz";
1355 sha1 = "78d7cbfc1e6d66303fe79837365984517b2f6ee1";
1356 };
1357 };
1358 "hawk-3.1.3" = {
1359 name = "hawk";
1360 packageName = "hawk";
1361 version = "3.1.3";
1362 src = fetchurl {
1363 url = "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz";
1364 sha1 = "078444bd7c1640b0fe540d2c9b73d59678e8e1c4";
1365 };
1366 };
1367 "hoek-2.16.3" = {
1368 name = "hoek";
1369 packageName = "hoek";
1370 version = "2.16.3";
1371 src = fetchurl {
1372 url = "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz";
1373 sha1 = "20bb7403d3cea398e91dc4710a8ff1b8274a25ed";
1374 };
1375 };
1376 "hooker-0.2.3" = {
1377 name = "hooker";
1378 packageName = "hooker";
1379 version = "0.2.3";
1380 src = fetchurl {
1381 url = "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz";
1382 sha1 = "b834f723cc4a242aa65963459df6d984c5d3d959";
1383 };
1384 };
1385 "hosted-git-info-2.7.1" = {
1386 name = "hosted-git-info";
1387 packageName = "hosted-git-info";
1388 version = "2.7.1";
1389 src = fetchurl {
1390 url = "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz";
1391 sha512 = "7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==";
1392 };
1393 };
1394 "htmlparser2-3.8.3" = {
1395 name = "htmlparser2";
1396 packageName = "htmlparser2";
1397 version = "3.8.3";
1398 src = fetchurl {
1399 url = "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz";
1400 sha1 = "996c28b191516a8be86501a7d79757e5c70c1068";
1401 };
1402 };
1403 "http-signature-1.1.1" = {
1404 name = "http-signature";
1405 packageName = "http-signature";
1406 version = "1.1.1";
1407 src = fetchurl {
1408 url = "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz";
1409 sha1 = "df72e267066cd0ac67fb76adf8e134a8fbcf91bf";
1410 };
1411 };
1412 "hydrolysis-1.25.0" = {
1413 name = "hydrolysis";
1414 packageName = "hydrolysis";
1415 version = "1.25.0";
1416 src = fetchurl {
1417 url = "https://registry.npmjs.org/hydrolysis/-/hydrolysis-1.25.0.tgz";
1418 sha1 = "a4fb14a37a1e03b0db52d8aaa57c682272a14d84";
1419 };
1420 };
1421 "iconv-lite-0.2.11" = {
1422 name = "iconv-lite";
1423 packageName = "iconv-lite";
1424 version = "0.2.11";
1425 src = fetchurl {
1426 url = "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz";
1427 sha1 = "1ce60a3a57864a292d1321ff4609ca4bb965adc8";
681 1428 };
682 1429 };
683 1430 "image-size-0.5.5" = {
@@ -689,166 +1436,67 b' let'
689 1436 sha1 = "09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c";
690 1437 };
691 1438 };
692 "mime-1.4.0" = {
693 name = "mime";
694 packageName = "mime";
695 version = "1.4.0";
696 src = fetchurl {
697 url = "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz";
698 sha1 = "69e9e0db51d44f2a3b56e48b7817d7d137f1a343";
699 };
700 };
701 "mkdirp-0.5.1" = {
702 name = "mkdirp";
703 packageName = "mkdirp";
704 version = "0.5.1";
705 src = fetchurl {
706 url = "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz";
707 sha1 = "30057438eac6cf7f8c4767f38648d6697d75c903";
708 };
709 };
710 "promise-7.3.1" = {
711 name = "promise";
712 packageName = "promise";
713 version = "7.3.1";
714 src = fetchurl {
715 url = "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz";
716 sha1 = "064b72602b18f90f29192b8b1bc418ffd1ebd3bf";
717 };
718 };
719 "source-map-0.5.7" = {
720 name = "source-map";
721 packageName = "source-map";
722 version = "0.5.7";
723 src = fetchurl {
724 url = "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz";
725 sha1 = "8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc";
726 };
727 };
728 "request-2.82.0" = {
729 name = "request";
730 packageName = "request";
731 version = "2.82.0";
732 src = fetchurl {
733 url = "https://registry.npmjs.org/request/-/request-2.82.0.tgz";
734 sha1 = "2ba8a92cd7ac45660ea2b10a53ae67cd247516ea";
735 };
736 };
737 "prr-0.0.0" = {
738 name = "prr";
739 packageName = "prr";
740 version = "0.0.0";
741 src = fetchurl {
742 url = "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz";
743 sha1 = "1a84b85908325501411853d0081ee3fa86e2926a";
744 };
745 };
746 "minimist-0.0.8" = {
747 name = "minimist";
748 packageName = "minimist";
749 version = "0.0.8";
750 src = fetchurl {
751 url = "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz";
752 sha1 = "857fcabfc3397d2625b8228262e86aa7a011b05d";
753 };
754 };
755 "asap-2.0.6" = {
756 name = "asap";
757 packageName = "asap";
758 version = "2.0.6";
759 src = fetchurl {
760 url = "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz";
761 sha1 = "e50347611d7e690943208bbdafebcbc2fb866d46";
762 };
763 };
764 "aws-sign2-0.7.0" = {
765 name = "aws-sign2";
766 packageName = "aws-sign2";
767 version = "0.7.0";
768 src = fetchurl {
769 url = "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz";
770 sha1 = "b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8";
771 };
772 };
773 "aws4-1.6.0" = {
774 name = "aws4";
775 packageName = "aws4";
776 version = "1.6.0";
777 src = fetchurl {
778 url = "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz";
779 sha1 = "83ef5ca860b2b32e4a0deedee8c771b9db57471e";
780 };
781 };
782 "caseless-0.12.0" = {
783 name = "caseless";
784 packageName = "caseless";
785 version = "0.12.0";
786 src = fetchurl {
787 url = "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz";
788 sha1 = "1b681c21ff84033c826543090689420d187151dc";
789 };
790 };
791 "combined-stream-1.0.5" = {
792 name = "combined-stream";
793 packageName = "combined-stream";
794 version = "1.0.5";
795 src = fetchurl {
796 url = "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz";
797 sha1 = "938370a57b4a51dea2c77c15d5c5fdf895164009";
798 };
799 };
800 "extend-3.0.1" = {
801 name = "extend";
802 packageName = "extend";
803 version = "3.0.1";
804 src = fetchurl {
805 url = "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz";
806 sha1 = "a755ea7bc1adfcc5a31ce7e762dbaadc5e636444";
807 };
808 };
809 "forever-agent-0.6.1" = {
810 name = "forever-agent";
811 packageName = "forever-agent";
812 version = "0.6.1";
813 src = fetchurl {
814 url = "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz";
815 sha1 = "fbc71f0c41adeb37f96c577ad1ed42d8fdacca91";
816 };
817 };
818 "form-data-2.3.1" = {
819 name = "form-data";
820 packageName = "form-data";
821 version = "2.3.1";
822 src = fetchurl {
823 url = "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz";
824 sha1 = "6fb94fbd71885306d73d15cc497fe4cc4ecd44bf";
825 };
826 };
827 "har-validator-5.0.3" = {
828 name = "har-validator";
829 packageName = "har-validator";
830 version = "5.0.3";
831 src = fetchurl {
832 url = "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz";
833 sha1 = "ba402c266194f15956ef15e0fcf242993f6a7dfd";
834 };
835 };
836 "hawk-6.0.2" = {
837 name = "hawk";
838 packageName = "hawk";
839 version = "6.0.2";
840 src = fetchurl {
841 url = "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz";
842 sha1 = "af4d914eb065f9b5ce4d9d11c1cb2126eecc3038";
843 };
844 };
845 "http-signature-1.2.0" = {
846 name = "http-signature";
847 packageName = "http-signature";
848 version = "1.2.0";
849 src = fetchurl {
850 url = "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz";
851 sha1 = "9aecd925114772f3d95b65a60abb8f7c18fbace1";
1439 "inflight-1.0.6" = {
1440 name = "inflight";
1441 packageName = "inflight";
1442 version = "1.0.6";
1443 src = fetchurl {
1444 url = "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz";
1445 sha1 = "49bd6331d7d02d0c09bc910a1075ba8165b56df9";
1446 };
1447 };
1448 "inherits-1.0.2" = {
1449 name = "inherits";
1450 packageName = "inherits";
1451 version = "1.0.2";
1452 src = fetchurl {
1453 url = "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz";
1454 sha1 = "ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b";
1455 };
1456 };
1457 "inherits-2.0.3" = {
1458 name = "inherits";
1459 packageName = "inherits";
1460 version = "2.0.3";
1461 src = fetchurl {
1462 url = "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz";
1463 sha1 = "633c2c83e3da42a502f52466022480f4208261de";
1464 };
1465 };
1466 "ini-1.3.5" = {
1467 name = "ini";
1468 packageName = "ini";
1469 version = "1.3.5";
1470 src = fetchurl {
1471 url = "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz";
1472 sha512 = "RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==";
1473 };
1474 };
1475 "is-builtin-module-1.0.0" = {
1476 name = "is-builtin-module";
1477 packageName = "is-builtin-module";
1478 version = "1.0.0";
1479 src = fetchurl {
1480 url = "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz";
1481 sha1 = "540572d34f7ac3119f8f76c30cbc1b1e037affbe";
1482 };
1483 };
1484 "is-fullwidth-code-point-1.0.0" = {
1485 name = "is-fullwidth-code-point";
1486 packageName = "is-fullwidth-code-point";
1487 version = "1.0.0";
1488 src = fetchurl {
1489 url = "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz";
1490 sha1 = "ef9e31386f031a7f0d643af82fde50c457ef00cb";
1491 };
1492 };
1493 "is-stream-1.1.0" = {
1494 name = "is-stream";
1495 packageName = "is-stream";
1496 version = "1.1.0";
1497 src = fetchurl {
1498 url = "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz";
1499 sha1 = "12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44";
852 1500 };
853 1501 };
854 1502 "is-typedarray-1.0.0" = {
@@ -860,6 +1508,33 b' let'
860 1508 sha1 = "e479c80858df0c1b11ddda6940f96011fcda4a9a";
861 1509 };
862 1510 };
1511 "isarray-0.0.1" = {
1512 name = "isarray";
1513 packageName = "isarray";
1514 version = "0.0.1";
1515 src = fetchurl {
1516 url = "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz";
1517 sha1 = "8a18acfca9a8f4177e09abfc6038939b05d1eedf";
1518 };
1519 };
1520 "isarray-1.0.0" = {
1521 name = "isarray";
1522 packageName = "isarray";
1523 version = "1.0.0";
1524 src = fetchurl {
1525 url = "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz";
1526 sha1 = "bb935d48582cba168c06834957a54a3e07124f11";
1527 };
1528 };
1529 "isexe-2.0.0" = {
1530 name = "isexe";
1531 packageName = "isexe";
1532 version = "2.0.0";
1533 src = fetchurl {
1534 url = "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz";
1535 sha1 = "e8fbf374dc556ff8947a10dcb0572d633f2cfa10";
1536 };
1537 };
863 1538 "isstream-0.1.2" = {
864 1539 name = "isstream";
865 1540 packageName = "isstream";
@@ -869,6 +1544,60 b' let'
869 1544 sha1 = "47e63f7af55afa6f92e1500e690eb8b8529c099a";
870 1545 };
871 1546 };
1547 "jquery-1.11.3" = {
1548 name = "jquery";
1549 packageName = "jquery";
1550 version = "1.11.3";
1551 src = fetchurl {
1552 url = "https://registry.npmjs.org/jquery/-/jquery-1.11.3.tgz";
1553 sha1 = "dd8b74278b27102d29df63eae28308a8cfa1b583";
1554 };
1555 };
1556 "js-yaml-2.0.5" = {
1557 name = "js-yaml";
1558 packageName = "js-yaml";
1559 version = "2.0.5";
1560 src = fetchurl {
1561 url = "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz";
1562 sha1 = "a25ae6509999e97df278c6719da11bd0687743a8";
1563 };
1564 };
1565 "jsbn-0.1.1" = {
1566 name = "jsbn";
1567 packageName = "jsbn";
1568 version = "0.1.1";
1569 src = fetchurl {
1570 url = "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz";
1571 sha1 = "a5e654c2e5a2deb5f201d96cefbca80c0ef2f513";
1572 };
1573 };
1574 "jshint-2.9.6" = {
1575 name = "jshint";
1576 packageName = "jshint";
1577 version = "2.9.6";
1578 src = fetchurl {
1579 url = "https://registry.npmjs.org/jshint/-/jshint-2.9.6.tgz";
1580 sha512 = "KO9SIAKTlJQOM4lE64GQUtGBRpTOuvbrRrSZw3AhUxMNG266nX9hK2cKA4SBhXOj0irJGyNyGSLT62HGOVDEOA==";
1581 };
1582 };
1583 "json-schema-0.2.3" = {
1584 name = "json-schema";
1585 packageName = "json-schema";
1586 version = "0.2.3";
1587 src = fetchurl {
1588 url = "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz";
1589 sha1 = "b480c892e59a2f05954ce727bd3f2a4e882f9e13";
1590 };
1591 };
1592 "json-stable-stringify-1.0.1" = {
1593 name = "json-stable-stringify";
1594 packageName = "json-stable-stringify";
1595 version = "1.0.1";
1596 src = fetchurl {
1597 url = "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz";
1598 sha1 = "9a759d39c5f2ff503fd5300646ed445f88c4f9af";
1599 };
1600 };
872 1601 "json-stringify-safe-5.0.1" = {
873 1602 name = "json-stringify-safe";
874 1603 packageName = "json-stringify-safe";
@@ -878,157 +1607,22 b' let'
878 1607 sha1 = "1296a2d58fd45f19a0f6ce01d65701e2c735b6eb";
879 1608 };
880 1609 };
881 "mime-types-2.1.17" = {
882 name = "mime-types";
883 packageName = "mime-types";
884 version = "2.1.17";
885 src = fetchurl {
886 url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz";
887 sha1 = "09d7a393f03e995a79f8af857b70a9e0ab16557a";
888 };
889 };
890 "oauth-sign-0.8.2" = {
891 name = "oauth-sign";
892 packageName = "oauth-sign";
893 version = "0.8.2";
894 src = fetchurl {
895 url = "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz";
896 sha1 = "46a6ab7f0aead8deae9ec0565780b7d4efeb9d43";
897 };
898 };
899 "performance-now-2.1.0" = {
900 name = "performance-now";
901 packageName = "performance-now";
902 version = "2.1.0";
903 src = fetchurl {
904 url = "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz";
905 sha1 = "6309f4e0e5fa913ec1c69307ae364b4b377c9e7b";
906 };
907 };
908 "qs-6.5.1" = {
909 name = "qs";
910 packageName = "qs";
911 version = "6.5.1";
912 src = fetchurl {
913 url = "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz";
914 sha1 = "349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8";
915 };
916 };
917 "safe-buffer-5.1.1" = {
918 name = "safe-buffer";
919 packageName = "safe-buffer";
920 version = "5.1.1";
921 src = fetchurl {
922 url = "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz";
923 sha1 = "893312af69b2123def71f57889001671eeb2c853";
924 };
925 };
926 "stringstream-0.0.5" = {
927 name = "stringstream";
928 packageName = "stringstream";
929 version = "0.0.5";
930 src = fetchurl {
931 url = "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz";
932 sha1 = "4e484cd4de5a0bbbee18e46307710a8a81621878";
933 };
934 };
935 "tough-cookie-2.3.3" = {
936 name = "tough-cookie";
937 packageName = "tough-cookie";
938 version = "2.3.3";
939 src = fetchurl {
940 url = "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz";
941 sha1 = "0b618a5565b6dea90bf3425d04d55edc475a7561";
942 };
943 };
944 "tunnel-agent-0.6.0" = {
945 name = "tunnel-agent";
946 packageName = "tunnel-agent";
947 version = "0.6.0";
948 src = fetchurl {
949 url = "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz";
950 sha1 = "27a5dea06b36b04a0a9966774b290868f0fc40fd";
951 };
952 };
953 "uuid-3.1.0" = {
954 name = "uuid";
955 packageName = "uuid";
956 version = "3.1.0";
957 src = fetchurl {
958 url = "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz";
959 sha1 = "3dd3d3e790abc24d7b0d3a034ffababe28ebbc04";
960 };
961 };
962 "delayed-stream-1.0.0" = {
963 name = "delayed-stream";
964 packageName = "delayed-stream";
965 version = "1.0.0";
966 src = fetchurl {
967 url = "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz";
968 sha1 = "df3ae199acadfb7d440aaae0b29e2272b24ec619";
969 };
970 };
971 "asynckit-0.4.0" = {
972 name = "asynckit";
973 packageName = "asynckit";
974 version = "0.4.0";
975 src = fetchurl {
976 url = "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz";
977 sha1 = "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79";
978 };
979 };
980 "ajv-5.2.2" = {
981 name = "ajv";
982 packageName = "ajv";
983 version = "5.2.2";
984 src = fetchurl {
985 url = "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz";
986 sha1 = "47c68d69e86f5d953103b0074a9430dc63da5e39";
987 };
988 };
989 "har-schema-2.0.0" = {
990 name = "har-schema";
991 packageName = "har-schema";
992 version = "2.0.0";
993 src = fetchurl {
994 url = "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz";
995 sha1 = "a94c2224ebcac04782a0d9035521f24735b7ec92";
996 };
997 };
998 "co-4.6.0" = {
999 name = "co";
1000 packageName = "co";
1001 version = "4.6.0";
1002 src = fetchurl {
1003 url = "https://registry.npmjs.org/co/-/co-4.6.0.tgz";
1004 sha1 = "6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184";
1005 };
1006 };
1007 "fast-deep-equal-1.0.0" = {
1008 name = "fast-deep-equal";
1009 packageName = "fast-deep-equal";
1010 version = "1.0.0";
1011 src = fetchurl {
1012 url = "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz";
1013 sha1 = "96256a3bc975595eb36d82e9929d060d893439ff";
1014 };
1015 };
1016 "json-schema-traverse-0.3.1" = {
1017 name = "json-schema-traverse";
1018 packageName = "json-schema-traverse";
1019 version = "0.3.1";
1020 src = fetchurl {
1021 url = "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz";
1022 sha1 = "349a6d44c53a51de89b40805c5d5e59b417d3340";
1023 };
1024 };
1025 "json-stable-stringify-1.0.1" = {
1026 name = "json-stable-stringify";
1027 packageName = "json-stable-stringify";
1610 "jsonfile-1.0.1" = {
1611 name = "jsonfile";
1612 packageName = "jsonfile";
1028 1613 version = "1.0.1";
1029 1614 src = fetchurl {
1030 url = "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz";
1031 sha1 = "9a759d39c5f2ff503fd5300646ed445f88c4f9af";
1615 url = "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz";
1616 sha1 = "ea5efe40b83690b98667614a7392fc60e842c0dd";
1617 };
1618 };
1619 "jsonfile-2.4.0" = {
1620 name = "jsonfile";
1621 packageName = "jsonfile";
1622 version = "2.4.0";
1623 src = fetchurl {
1624 url = "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz";
1625 sha1 = "3736a2b428b87bbda0cc83b53fa3d633a35c2ae8";
1032 1626 };
1033 1627 };
1034 1628 "jsonify-0.0.0" = {
@@ -1040,60 +1634,6 b' let'
1040 1634 sha1 = "2c74b6ee41d93ca51b7b5aaee8f503631d252a73";
1041 1635 };
1042 1636 };
1043 "hoek-4.2.0" = {
1044 name = "hoek";
1045 packageName = "hoek";
1046 version = "4.2.0";
1047 src = fetchurl {
1048 url = "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz";
1049 sha1 = "72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d";
1050 };
1051 };
1052 "boom-4.3.1" = {
1053 name = "boom";
1054 packageName = "boom";
1055 version = "4.3.1";
1056 src = fetchurl {
1057 url = "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz";
1058 sha1 = "4f8a3005cb4a7e3889f749030fd25b96e01d2e31";
1059 };
1060 };
1061 "cryptiles-3.1.2" = {
1062 name = "cryptiles";
1063 packageName = "cryptiles";
1064 version = "3.1.2";
1065 src = fetchurl {
1066 url = "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz";
1067 sha1 = "a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe";
1068 };
1069 };
1070 "sntp-2.0.2" = {
1071 name = "sntp";
1072 packageName = "sntp";
1073 version = "2.0.2";
1074 src = fetchurl {
1075 url = "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz";
1076 sha1 = "5064110f0af85f7cfdb7d6b67a40028ce52b4b2b";
1077 };
1078 };
1079 "boom-5.2.0" = {
1080 name = "boom";
1081 packageName = "boom";
1082 version = "5.2.0";
1083 src = fetchurl {
1084 url = "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz";
1085 sha1 = "5dd9da6ee3a5f302077436290cb717d3f4a54e02";
1086 };
1087 };
1088 "assert-plus-1.0.0" = {
1089 name = "assert-plus";
1090 packageName = "assert-plus";
1091 version = "1.0.0";
1092 src = fetchurl {
1093 url = "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz";
1094 sha1 = "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525";
1095 };
1096 };
1097 1637 "jsprim-1.4.1" = {
1098 1638 name = "jsprim";
1099 1639 packageName = "jsprim";
@@ -1103,166 +1643,49 b' let'
1103 1643 sha1 = "313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2";
1104 1644 };
1105 1645 };
1106 "sshpk-1.13.1" = {
1107 name = "sshpk";
1108 packageName = "sshpk";
1109 version = "1.13.1";
1110 src = fetchurl {
1111 url = "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz";
1112 sha1 = "512df6da6287144316dc4c18fe1cf1d940739be3";
1113 };
1114 };
1115 "extsprintf-1.3.0" = {
1116 name = "extsprintf";
1117 packageName = "extsprintf";
1118 version = "1.3.0";
1119 src = fetchurl {
1120 url = "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz";
1121 sha1 = "96918440e3041a7a414f8c52e3c574eb3c3e1e05";
1122 };
1123 };
1124 "json-schema-0.2.3" = {
1125 name = "json-schema";
1126 packageName = "json-schema";
1127 version = "0.2.3";
1128 src = fetchurl {
1129 url = "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz";
1130 sha1 = "b480c892e59a2f05954ce727bd3f2a4e882f9e13";
1131 };
1132 };
1133 "verror-1.10.0" = {
1134 name = "verror";
1135 packageName = "verror";
1136 version = "1.10.0";
1137 src = fetchurl {
1138 url = "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz";
1139 sha1 = "3a105ca17053af55d6e270c1f8288682e18da400";
1140 };
1141 };
1142 "core-util-is-1.0.2" = {
1143 name = "core-util-is";
1144 packageName = "core-util-is";
1145 version = "1.0.2";
1146 src = fetchurl {
1147 url = "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz";
1148 sha1 = "b5fd54220aa2bc5ab57aab7140c940754503c1a7";
1149 };
1150 };
1151 "asn1-0.2.3" = {
1152 name = "asn1";
1153 packageName = "asn1";
1154 version = "0.2.3";
1155 src = fetchurl {
1156 url = "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz";
1157 sha1 = "dac8787713c9966849fc8180777ebe9c1ddf3b86";
1158 };
1159 };
1160 "dashdash-1.14.1" = {
1161 name = "dashdash";
1162 packageName = "dashdash";
1163 version = "1.14.1";
1164 src = fetchurl {
1165 url = "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz";
1166 sha1 = "853cfa0f7cbe2fed5de20326b8dd581035f6e2f0";
1167 };
1168 };
1169 "getpass-0.1.7" = {
1170 name = "getpass";
1171 packageName = "getpass";
1172 version = "0.1.7";
1173 src = fetchurl {
1174 url = "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz";
1175 sha1 = "5eff8e3e684d569ae4cb2b1282604e8ba62149fa";
1176 };
1177 };
1178 "jsbn-0.1.1" = {
1179 name = "jsbn";
1180 packageName = "jsbn";
1181 version = "0.1.1";
1182 src = fetchurl {
1183 url = "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz";
1184 sha1 = "a5e654c2e5a2deb5f201d96cefbca80c0ef2f513";
1185 };
1186 };
1187 "tweetnacl-0.14.5" = {
1188 name = "tweetnacl";
1189 packageName = "tweetnacl";
1190 version = "0.14.5";
1191 src = fetchurl {
1192 url = "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz";
1193 sha1 = "5ae68177f192d4456269d108afa93ff8743f4f64";
1194 };
1195 };
1196 "ecc-jsbn-0.1.1" = {
1197 name = "ecc-jsbn";
1198 packageName = "ecc-jsbn";
1199 version = "0.1.1";
1200 src = fetchurl {
1201 url = "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz";
1202 sha1 = "0fc73a9ed5f0d53c38193398523ef7e543777505";
1203 };
1204 };
1205 "bcrypt-pbkdf-1.0.1" = {
1206 name = "bcrypt-pbkdf";
1207 packageName = "bcrypt-pbkdf";
1208 version = "1.0.1";
1209 src = fetchurl {
1210 url = "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz";
1211 sha1 = "63bc5dcb61331b92bc05fd528953c33462a06f8d";
1212 };
1213 };
1214 "mime-db-1.30.0" = {
1215 name = "mime-db";
1216 packageName = "mime-db";
1217 version = "1.30.0";
1218 src = fetchurl {
1219 url = "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz";
1220 sha1 = "74c643da2dd9d6a45399963465b26d5ca7d71f01";
1221 };
1222 };
1223 "punycode-1.4.1" = {
1224 name = "punycode";
1225 packageName = "punycode";
1226 version = "1.4.1";
1227 src = fetchurl {
1228 url = "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz";
1229 sha1 = "c0d5a63b2718800ad8e1eb0fa5269c84dd41845e";
1230 };
1231 };
1232 "gaze-0.5.2" = {
1233 name = "gaze";
1234 packageName = "gaze";
1235 version = "0.5.2";
1236 src = fetchurl {
1237 url = "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz";
1238 sha1 = "40b709537d24d1d45767db5a908689dfe69ac44f";
1239 };
1240 };
1241 "tiny-lr-fork-0.0.5" = {
1242 name = "tiny-lr-fork";
1243 packageName = "tiny-lr-fork";
1244 version = "0.0.5";
1245 src = fetchurl {
1246 url = "https://registry.npmjs.org/tiny-lr-fork/-/tiny-lr-fork-0.0.5.tgz";
1247 sha1 = "1e99e1e2a8469b736ab97d97eefa98c71f76ed0a";
1248 };
1249 };
1250 "async-0.2.10" = {
1251 name = "async";
1252 packageName = "async";
1253 version = "0.2.10";
1254 src = fetchurl {
1255 url = "https://registry.npmjs.org/async/-/async-0.2.10.tgz";
1256 sha1 = "b6bbe0b0674b9d719708ca38de8c237cb526c3d1";
1257 };
1258 };
1259 "globule-0.1.0" = {
1260 name = "globule";
1261 packageName = "globule";
1262 version = "0.1.0";
1263 src = fetchurl {
1264 url = "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz";
1265 sha1 = "d9c8edde1da79d125a151b79533b978676346ae5";
1646 "kew-0.7.0" = {
1647 name = "kew";
1648 packageName = "kew";
1649 version = "0.7.0";
1650 src = fetchurl {
1651 url = "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz";
1652 sha1 = "79d93d2d33363d6fdd2970b335d9141ad591d79b";
1653 };
1654 };
1655 "klaw-1.3.1" = {
1656 name = "klaw";
1657 packageName = "klaw";
1658 version = "1.3.1";
1659 src = fetchurl {
1660 url = "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz";
1661 sha1 = "4088433b46b3b1ba259d78785d8e96f73ba02439";
1662 };
1663 };
1664 "less-2.7.3" = {
1665 name = "less";
1666 packageName = "less";
1667 version = "2.7.3";
1668 src = fetchurl {
1669 url = "https://registry.npmjs.org/less/-/less-2.7.3.tgz";
1670 sha512 = "KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==";
1671 };
1672 };
1673 "levn-0.3.0" = {
1674 name = "levn";
1675 packageName = "levn";
1676 version = "0.3.0";
1677 src = fetchurl {
1678 url = "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz";
1679 sha1 = "3b09924edf9f083c0490fdd4c0bc4421e04764ee";
1680 };
1681 };
1682 "lodash-0.9.2" = {
1683 name = "lodash";
1684 packageName = "lodash";
1685 version = "0.9.2";
1686 src = fetchurl {
1687 url = "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz";
1688 sha1 = "8f3499c5245d346d682e5b0d3b40767e09f1a92c";
1266 1689 };
1267 1690 };
1268 1691 "lodash-1.0.2" = {
@@ -1274,40 +1697,193 b' let'
1274 1697 sha1 = "8f57560c83b59fc270bd3d561b690043430e2551";
1275 1698 };
1276 1699 };
1277 "qs-0.5.6" = {
1278 name = "qs";
1279 packageName = "qs";
1280 version = "0.5.6";
1281 src = fetchurl {
1282 url = "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz";
1283 sha1 = "31b1ad058567651c526921506b9a8793911a0384";
1284 };
1285 };
1286 "faye-websocket-0.4.4" = {
1287 name = "faye-websocket";
1288 packageName = "faye-websocket";
1289 version = "0.4.4";
1290 src = fetchurl {
1291 url = "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.4.4.tgz";
1292 sha1 = "c14c5b3bf14d7417ffbfd990c0a7495cd9f337bc";
1293 };
1294 };
1295 "noptify-0.0.3" = {
1296 name = "noptify";
1297 packageName = "noptify";
1298 version = "0.0.3";
1299 src = fetchurl {
1300 url = "https://registry.npmjs.org/noptify/-/noptify-0.0.3.tgz";
1301 sha1 = "58f654a73d9753df0c51d9686dc92104a67f4bbb";
1302 };
1303 };
1304 "debug-0.7.4" = {
1305 name = "debug";
1306 packageName = "debug";
1307 version = "0.7.4";
1308 src = fetchurl {
1309 url = "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz";
1310 sha1 = "06e1ea8082c2cb14e39806e22e2f6f757f92af39";
1700 "lodash-2.4.2" = {
1701 name = "lodash";
1702 packageName = "lodash";
1703 version = "2.4.2";
1704 src = fetchurl {
1705 url = "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz";
1706 sha1 = "fadd834b9683073da179b3eae6d9c0d15053f73e";
1707 };
1708 };
1709 "lodash-4.17.10" = {
1710 name = "lodash";
1711 packageName = "lodash";
1712 version = "4.17.10";
1713 src = fetchurl {
1714 url = "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz";
1715 sha512 = "UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==";
1716 };
1717 };
1718 "lru-cache-2.7.3" = {
1719 name = "lru-cache";
1720 packageName = "lru-cache";
1721 version = "2.7.3";
1722 src = fetchurl {
1723 url = "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz";
1724 sha1 = "6d4524e8b955f95d4f5b58851ce21dd72fb4e952";
1725 };
1726 };
1727 "mime-1.6.0" = {
1728 name = "mime";
1729 packageName = "mime";
1730 version = "1.6.0";
1731 src = fetchurl {
1732 url = "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz";
1733 sha512 = "x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==";
1734 };
1735 };
1736 "mime-db-1.35.0" = {
1737 name = "mime-db";
1738 packageName = "mime-db";
1739 version = "1.35.0";
1740 src = fetchurl {
1741 url = "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz";
1742 sha512 = "JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==";
1743 };
1744 };
1745 "mime-types-2.1.19" = {
1746 name = "mime-types";
1747 packageName = "mime-types";
1748 version = "2.1.19";
1749 src = fetchurl {
1750 url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz";
1751 sha512 = "P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==";
1752 };
1753 };
1754 "minimatch-0.2.14" = {
1755 name = "minimatch";
1756 packageName = "minimatch";
1757 version = "0.2.14";
1758 src = fetchurl {
1759 url = "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz";
1760 sha1 = "c74e780574f63c6f9a090e90efbe6ef53a6a756a";
1761 };
1762 };
1763 "minimatch-0.3.0" = {
1764 name = "minimatch";
1765 packageName = "minimatch";
1766 version = "0.3.0";
1767 src = fetchurl {
1768 url = "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz";
1769 sha1 = "275d8edaac4f1bb3326472089e7949c8394699dd";
1770 };
1771 };
1772 "minimatch-3.0.4" = {
1773 name = "minimatch";
1774 packageName = "minimatch";
1775 version = "3.0.4";
1776 src = fetchurl {
1777 url = "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz";
1778 sha512 = "yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==";
1779 };
1780 };
1781 "minimist-0.0.8" = {
1782 name = "minimist";
1783 packageName = "minimist";
1784 version = "0.0.8";
1785 src = fetchurl {
1786 url = "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz";
1787 sha1 = "857fcabfc3397d2625b8228262e86aa7a011b05d";
1788 };
1789 };
1790 "minipass-2.3.3" = {
1791 name = "minipass";
1792 packageName = "minipass";
1793 version = "2.3.3";
1794 src = fetchurl {
1795 url = "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz";
1796 sha512 = "/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==";
1797 };
1798 };
1799 "minizlib-1.1.0" = {
1800 name = "minizlib";
1801 packageName = "minizlib";
1802 version = "1.1.0";
1803 src = fetchurl {
1804 url = "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz";
1805 sha512 = "4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==";
1806 };
1807 };
1808 "mkdirp-0.3.5" = {
1809 name = "mkdirp";
1810 packageName = "mkdirp";
1811 version = "0.3.5";
1812 src = fetchurl {
1813 url = "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz";
1814 sha1 = "de3e5f8961c88c787ee1368df849ac4413eca8d7";
1815 };
1816 };
1817 "mkdirp-0.5.1" = {
1818 name = "mkdirp";
1819 packageName = "mkdirp";
1820 version = "0.5.1";
1821 src = fetchurl {
1822 url = "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz";
1823 sha1 = "30057438eac6cf7f8c4767f38648d6697d75c903";
1824 };
1825 };
1826 "moment-2.22.2" = {
1827 name = "moment";
1828 packageName = "moment";
1829 version = "2.22.2";
1830 src = fetchurl {
1831 url = "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz";
1832 sha1 = "3c257f9839fc0e93ff53149632239eb90783ff66";
1833 };
1834 };
1835 "mousetrap-1.6.2" = {
1836 name = "mousetrap";
1837 packageName = "mousetrap";
1838 version = "1.6.2";
1839 src = fetchurl {
1840 url = "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.2.tgz";
1841 sha512 = "jDjhi7wlHwdO6q6DS7YRmSHcuI+RVxadBkLt3KHrhd3C2b+w5pKefg3oj5beTcHZyVFA9Aksf+yEE1y5jxUjVA==";
1842 };
1843 };
1844 "ms-2.0.0" = {
1845 name = "ms";
1846 packageName = "ms";
1847 version = "2.0.0";
1848 src = fetchurl {
1849 url = "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz";
1850 sha1 = "5608aeadfc00be6c2901df5f9861788de0d597c8";
1851 };
1852 };
1853 "ncp-0.4.2" = {
1854 name = "ncp";
1855 packageName = "ncp";
1856 version = "0.4.2";
1857 src = fetchurl {
1858 url = "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz";
1859 sha1 = "abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574";
1860 };
1861 };
1862 "nijs-0.0.25" = {
1863 name = "nijs";
1864 packageName = "nijs";
1865 version = "0.0.25";
1866 src = fetchurl {
1867 url = "https://registry.npmjs.org/nijs/-/nijs-0.0.25.tgz";
1868 sha1 = "04b035cb530d46859d1018839a518c029133f676";
1869 };
1870 };
1871 "node2nix-1.6.0" = {
1872 name = "node2nix";
1873 packageName = "node2nix";
1874 version = "1.6.0";
1875 src = fetchurl {
1876 url = "https://registry.npmjs.org/node2nix/-/node2nix-1.6.0.tgz";
1877 sha512 = "MJY6SsQH3pN59R9N3nMz/L8BsbQ0DlvSF38mgg1fwfwgnaJ+y600s3Nd0vZ+cnETUH+4OPETc4QohflccjPUYw==";
1878 };
1879 };
1880 "nopt-1.0.10" = {
1881 name = "nopt";
1882 packageName = "nopt";
1883 version = "1.0.10";
1884 src = fetchurl {
1885 url = "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz";
1886 sha1 = "6ddd21bd2a31417b92727dd585f8a6f37608ebee";
1311 1887 };
1312 1888 };
1313 1889 "nopt-2.0.0" = {
@@ -1319,204 +1895,6 b' let'
1319 1895 sha1 = "ca7416f20a5e3f9c3b86180f96295fa3d0b52e0d";
1320 1896 };
1321 1897 };
1322 "command-line-args-3.0.5" = {
1323 name = "command-line-args";
1324 packageName = "command-line-args";
1325 version = "3.0.5";
1326 src = fetchurl {
1327 url = "https://registry.npmjs.org/command-line-args/-/command-line-args-3.0.5.tgz";
1328 sha1 = "5bd4ad45e7983e5c1344918e40280ee2693c5ac0";
1329 };
1330 };
1331 "command-line-usage-3.0.8" = {
1332 name = "command-line-usage";
1333 packageName = "command-line-usage";
1334 version = "3.0.8";
1335 src = fetchurl {
1336 url = "https://registry.npmjs.org/command-line-usage/-/command-line-usage-3.0.8.tgz";
1337 sha1 = "b6a20978c1b383477f5c11a529428b880bfe0f4d";
1338 };
1339 };
1340 "dom5-1.3.6" = {
1341 name = "dom5";
1342 packageName = "dom5";
1343 version = "1.3.6";
1344 src = fetchurl {
1345 url = "https://registry.npmjs.org/dom5/-/dom5-1.3.6.tgz";
1346 sha1 = "a7088a9fc5f3b08dc9f6eda4c7abaeb241945e0d";
1347 };
1348 };
1349 "array-back-1.0.4" = {
1350 name = "array-back";
1351 packageName = "array-back";
1352 version = "1.0.4";
1353 src = fetchurl {
1354 url = "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz";
1355 sha1 = "644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b";
1356 };
1357 };
1358 "feature-detect-es6-1.3.1" = {
1359 name = "feature-detect-es6";
1360 packageName = "feature-detect-es6";
1361 version = "1.3.1";
1362 src = fetchurl {
1363 url = "https://registry.npmjs.org/feature-detect-es6/-/feature-detect-es6-1.3.1.tgz";
1364 sha1 = "f888736af9cb0c91f55663bfa4762eb96ee7047f";
1365 };
1366 };
1367 "find-replace-1.0.3" = {
1368 name = "find-replace";
1369 packageName = "find-replace";
1370 version = "1.0.3";
1371 src = fetchurl {
1372 url = "https://registry.npmjs.org/find-replace/-/find-replace-1.0.3.tgz";
1373 sha1 = "b88e7364d2d9c959559f388c66670d6130441fa0";
1374 };
1375 };
1376 "typical-2.6.1" = {
1377 name = "typical";
1378 packageName = "typical";
1379 version = "2.6.1";
1380 src = fetchurl {
1381 url = "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz";
1382 sha1 = "5c080e5d661cbbe38259d2e70a3c7253e873881d";
1383 };
1384 };
1385 "test-value-2.1.0" = {
1386 name = "test-value";
1387 packageName = "test-value";
1388 version = "2.1.0";
1389 src = fetchurl {
1390 url = "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz";
1391 sha1 = "11da6ff670f3471a73b625ca4f3fdcf7bb748291";
1392 };
1393 };
1394 "ansi-escape-sequences-3.0.0" = {
1395 name = "ansi-escape-sequences";
1396 packageName = "ansi-escape-sequences";
1397 version = "3.0.0";
1398 src = fetchurl {
1399 url = "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-3.0.0.tgz";
1400 sha1 = "1c18394b6af9b76ff9a63509fa497669fd2ce53e";
1401 };
1402 };
1403 "table-layout-0.3.0" = {
1404 name = "table-layout";
1405 packageName = "table-layout";
1406 version = "0.3.0";
1407 src = fetchurl {
1408 url = "https://registry.npmjs.org/table-layout/-/table-layout-0.3.0.tgz";
1409 sha1 = "6ee20dc483db371b3e5c87f704ed2f7c799d2c9a";
1410 };
1411 };
1412 "core-js-2.5.1" = {
1413 name = "core-js";
1414 packageName = "core-js";
1415 version = "2.5.1";
1416 src = fetchurl {
1417 url = "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz";
1418 sha1 = "ae6874dc66937789b80754ff5428df66819ca50b";
1419 };
1420 };
1421 "deep-extend-0.4.2" = {
1422 name = "deep-extend";
1423 packageName = "deep-extend";
1424 version = "0.4.2";
1425 src = fetchurl {
1426 url = "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz";
1427 sha1 = "48b699c27e334bf89f10892be432f6e4c7d34a7f";
1428 };
1429 };
1430 "wordwrapjs-2.0.0" = {
1431 name = "wordwrapjs";
1432 packageName = "wordwrapjs";
1433 version = "2.0.0";
1434 src = fetchurl {
1435 url = "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-2.0.0.tgz";
1436 sha1 = "ab55f695e6118da93858fdd70c053d1c5e01ac20";
1437 };
1438 };
1439 "reduce-flatten-1.0.1" = {
1440 name = "reduce-flatten";
1441 packageName = "reduce-flatten";
1442 version = "1.0.1";
1443 src = fetchurl {
1444 url = "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz";
1445 sha1 = "258c78efd153ddf93cb561237f61184f3696e327";
1446 };
1447 };
1448 "@types/clone-0.1.30" = {
1449 name = "@types/clone";
1450 packageName = "@types/clone";
1451 version = "0.1.30";
1452 src = fetchurl {
1453 url = "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz";
1454 sha1 = "e7365648c1b42136a59c7d5040637b3b5c83b614";
1455 };
1456 };
1457 "@types/node-4.2.20" = {
1458 name = "@types/node";
1459 packageName = "@types/node";
1460 version = "4.2.20";
1461 src = fetchurl {
1462 url = "https://registry.npmjs.org/@types/node/-/node-4.2.20.tgz";
1463 sha1 = "3f7dceff43e07cfff4407fc3495d98a533b32267";
1464 };
1465 };
1466 "@types/parse5-0.0.31" = {
1467 name = "@types/parse5";
1468 packageName = "@types/parse5";
1469 version = "0.0.31";
1470 src = fetchurl {
1471 url = "https://registry.npmjs.org/@types/parse5/-/parse5-0.0.31.tgz";
1472 sha1 = "e827a493a443b156e1b582a2e4c3bdc0040f2ee7";
1473 };
1474 };
1475 "clone-1.0.2" = {
1476 name = "clone";
1477 packageName = "clone";
1478 version = "1.0.2";
1479 src = fetchurl {
1480 url = "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz";
1481 sha1 = "260b7a99ebb1edfe247538175f783243cb19d149";
1482 };
1483 };
1484 "parse5-1.5.1" = {
1485 name = "parse5";
1486 packageName = "parse5";
1487 version = "1.5.1";
1488 src = fetchurl {
1489 url = "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz";
1490 sha1 = "9b7f3b0de32be78dc2401b17573ccaf0f6f59d94";
1491 };
1492 };
1493 "@types/node-6.0.88" = {
1494 name = "@types/node";
1495 packageName = "@types/node";
1496 version = "6.0.88";
1497 src = fetchurl {
1498 url = "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz";
1499 sha1 = "f618f11a944f6a18d92b5c472028728a3e3d4b66";
1500 };
1501 };
1502 "es6-promise-2.3.0" = {
1503 name = "es6-promise";
1504 packageName = "es6-promise";
1505 version = "2.3.0";
1506 src = fetchurl {
1507 url = "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz";
1508 sha1 = "96edb9f2fdb01995822b263dd8aadab6748181bc";
1509 };
1510 };
1511 "hydrolysis-1.25.0" = {
1512 name = "hydrolysis";
1513 packageName = "hydrolysis";
1514 version = "1.25.0";
1515 src = fetchurl {
1516 url = "https://registry.npmjs.org/hydrolysis/-/hydrolysis-1.25.0.tgz";
1517 sha1 = "a4fb14a37a1e03b0db52d8aaa57c682272a14d84";
1518 };
1519 };
1520 1898 "nopt-3.0.6" = {
1521 1899 name = "nopt";
1522 1900 packageName = "nopt";
@@ -1526,157 +1904,103 b' let'
1526 1904 sha1 = "c6465dbf08abcd4db359317f79ac68a646b28ff9";
1527 1905 };
1528 1906 };
1529 "path-posix-1.0.0" = {
1530 name = "path-posix";
1531 packageName = "path-posix";
1532 version = "1.0.0";
1533 src = fetchurl {
1534 url = "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz";
1535 sha1 = "06b26113f56beab042545a23bfa88003ccac260f";
1536 };
1537 };
1538 "acorn-3.3.0" = {
1539 name = "acorn";
1540 packageName = "acorn";
1541 version = "3.3.0";
1542 src = fetchurl {
1543 url = "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz";
1544 sha1 = "45e37fb39e8da3f25baee3ff5369e2bb5f22017a";
1545 };
1546 };
1547 "babel-polyfill-6.26.0" = {
1548 name = "babel-polyfill";
1549 packageName = "babel-polyfill";
1550 version = "6.26.0";
1551 src = fetchurl {
1552 url = "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz";
1553 sha1 = "379937abc67d7895970adc621f284cd966cf2153";
1554 };
1555 };
1556 "doctrine-0.7.2" = {
1557 name = "doctrine";
1558 packageName = "doctrine";
1559 version = "0.7.2";
1560 src = fetchurl {
1561 url = "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz";
1562 sha1 = "7cb860359ba3be90e040b26b729ce4bfa654c523";
1563 };
1564 };
1565 "dom5-1.1.0" = {
1566 name = "dom5";
1567 packageName = "dom5";
1568 version = "1.1.0";
1569 src = fetchurl {
1570 url = "https://registry.npmjs.org/dom5/-/dom5-1.1.0.tgz";
1571 sha1 = "3a0c7700c083ab4c4d26938a78b0f0c6dcc37794";
1572 };
1573 };
1574 "escodegen-1.9.0" = {
1575 name = "escodegen";
1576 packageName = "escodegen";
1577 version = "1.9.0";
1578 src = fetchurl {
1579 url = "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz";
1580 sha1 = "9811a2f265dc1cd3894420ee3717064b632b8852";
1581 };
1582 };
1583 "espree-3.5.1" = {
1584 name = "espree";
1585 packageName = "espree";
1586 version = "3.5.1";
1587 src = fetchurl {
1588 url = "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz";
1589 sha1 = "0c988b8ab46db53100a1954ae4ba995ddd27d87e";
1590 };
1591 };
1592 "estraverse-3.1.0" = {
1593 name = "estraverse";
1594 packageName = "estraverse";
1595 version = "3.1.0";
1596 src = fetchurl {
1597 url = "https://registry.npmjs.org/estraverse/-/estraverse-3.1.0.tgz";
1598 sha1 = "15e28a446b8b82bc700ccc8b96c78af4da0d6cba";
1599 };
1600 };
1601 "path-is-absolute-1.0.1" = {
1602 name = "path-is-absolute";
1603 packageName = "path-is-absolute";
1907 "noptify-0.0.3" = {
1908 name = "noptify";
1909 packageName = "noptify";
1910 version = "0.0.3";
1911 src = fetchurl {
1912 url = "https://registry.npmjs.org/noptify/-/noptify-0.0.3.tgz";
1913 sha1 = "58f654a73d9753df0c51d9686dc92104a67f4bbb";
1914 };
1915 };
1916 "normalize-package-data-2.4.0" = {
1917 name = "normalize-package-data";
1918 packageName = "normalize-package-data";
1919 version = "2.4.0";
1920 src = fetchurl {
1921 url = "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz";
1922 sha512 = "9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==";
1923 };
1924 };
1925 "npm-package-arg-6.1.0" = {
1926 name = "npm-package-arg";
1927 packageName = "npm-package-arg";
1928 version = "6.1.0";
1929 src = fetchurl {
1930 url = "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz";
1931 sha512 = "zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==";
1932 };
1933 };
1934 "npm-registry-client-8.5.1" = {
1935 name = "npm-registry-client";
1936 packageName = "npm-registry-client";
1937 version = "8.5.1";
1938 src = fetchurl {
1939 url = "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.5.1.tgz";
1940 sha512 = "7rjGF2eA7hKDidGyEWmHTiKfXkbrcQAsGL/Rh4Rt3x3YNRNHhwaTzVJfW3aNvvlhg4G62VCluif0sLCb/i51Hg==";
1941 };
1942 };
1943 "npmconf-2.1.3" = {
1944 name = "npmconf";
1945 packageName = "npmconf";
1946 version = "2.1.3";
1947 src = fetchurl {
1948 url = "https://registry.npmjs.org/npmconf/-/npmconf-2.1.3.tgz";
1949 sha512 = "iTK+HI68GceCoGOHAQiJ/ik1iDfI7S+cgyG8A+PP18IU3X83kRhQIRhAUNj4Bp2JMx6Zrt5kCiozYa9uGWTjhA==";
1950 };
1951 };
1952 "npmlog-4.1.2" = {
1953 name = "npmlog";
1954 packageName = "npmlog";
1955 version = "4.1.2";
1956 src = fetchurl {
1957 url = "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz";
1958 sha512 = "2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==";
1959 };
1960 };
1961 "number-is-nan-1.0.1" = {
1962 name = "number-is-nan";
1963 packageName = "number-is-nan";
1604 1964 version = "1.0.1";
1605 1965 src = fetchurl {
1606 url = "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz";
1607 sha1 = "174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f";
1608 };
1609 };
1610 "babel-runtime-6.26.0" = {
1611 name = "babel-runtime";
1612 packageName = "babel-runtime";
1613 version = "6.26.0";
1614 src = fetchurl {
1615 url = "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz";
1616 sha1 = "965c7058668e82b55d7bfe04ff2337bc8b5647fe";
1617 };
1618 };
1619 "regenerator-runtime-0.10.5" = {
1620 name = "regenerator-runtime";
1621 packageName = "regenerator-runtime";
1622 version = "0.10.5";
1623 src = fetchurl {
1624 url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz";
1625 sha1 = "336c3efc1220adcedda2c9fab67b5a7955a33658";
1626 };
1627 };
1628 "regenerator-runtime-0.11.0" = {
1629 name = "regenerator-runtime";
1630 packageName = "regenerator-runtime";
1631 version = "0.11.0";
1632 src = fetchurl {
1633 url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz";
1634 sha1 = "7e54fe5b5ccd5d6624ea6255c3473be090b802e1";
1635 };
1636 };
1637 "esutils-1.1.6" = {
1638 name = "esutils";
1639 packageName = "esutils";
1640 version = "1.1.6";
1641 src = fetchurl {
1642 url = "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz";
1643 sha1 = "c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375";
1644 };
1645 };
1646 "isarray-0.0.1" = {
1647 name = "isarray";
1648 packageName = "isarray";
1649 version = "0.0.1";
1650 src = fetchurl {
1651 url = "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz";
1652 sha1 = "8a18acfca9a8f4177e09abfc6038939b05d1eedf";
1653 };
1654 };
1655 "estraverse-4.2.0" = {
1656 name = "estraverse";
1657 packageName = "estraverse";
1658 version = "4.2.0";
1659 src = fetchurl {
1660 url = "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz";
1661 sha1 = "0dee3fed31fcd469618ce7342099fc1afa0bdb13";
1662 };
1663 };
1664 "esutils-2.0.2" = {
1665 name = "esutils";
1666 packageName = "esutils";
1667 version = "2.0.2";
1668 src = fetchurl {
1669 url = "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz";
1670 sha1 = "0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b";
1671 };
1672 };
1673 "esprima-3.1.3" = {
1674 name = "esprima";
1675 packageName = "esprima";
1676 version = "3.1.3";
1677 src = fetchurl {
1678 url = "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz";
1679 sha1 = "fdca51cee6133895e3c88d535ce49dbff62a4633";
1966 url = "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz";
1967 sha1 = "097b602b53422a522c1afb8790318336941a011d";
1968 };
1969 };
1970 "oauth-sign-0.8.2" = {
1971 name = "oauth-sign";
1972 packageName = "oauth-sign";
1973 version = "0.8.2";
1974 src = fetchurl {
1975 url = "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz";
1976 sha1 = "46a6ab7f0aead8deae9ec0565780b7d4efeb9d43";
1977 };
1978 };
1979 "object-assign-4.1.1" = {
1980 name = "object-assign";
1981 packageName = "object-assign";
1982 version = "4.1.1";
1983 src = fetchurl {
1984 url = "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz";
1985 sha1 = "2109adc7965887cfc05cbbd442cac8bfbb360863";
1986 };
1987 };
1988 "once-1.3.3" = {
1989 name = "once";
1990 packageName = "once";
1991 version = "1.3.3";
1992 src = fetchurl {
1993 url = "https://registry.npmjs.org/once/-/once-1.3.3.tgz";
1994 sha1 = "b2e261557ce4c314ec8304f3fa82663e4297ca20";
1995 };
1996 };
1997 "once-1.4.0" = {
1998 name = "once";
1999 packageName = "once";
2000 version = "1.4.0";
2001 src = fetchurl {
2002 url = "https://registry.npmjs.org/once/-/once-1.4.0.tgz";
2003 sha1 = "583b1aa775961d4b113ac17d9c50baef9dd76bd1";
1680 2004 };
1681 2005 };
1682 2006 "optionator-0.8.2" = {
@@ -1688,96 +2012,6 b' let'
1688 2012 sha1 = "364c5e409d3f4d6301d6c0b4c05bba50180aeb64";
1689 2013 };
1690 2014 };
1691 "prelude-ls-1.1.2" = {
1692 name = "prelude-ls";
1693 packageName = "prelude-ls";
1694 version = "1.1.2";
1695 src = fetchurl {
1696 url = "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz";
1697 sha1 = "21932a549f5e52ffd9a827f570e04be62a97da54";
1698 };
1699 };
1700 "deep-is-0.1.3" = {
1701 name = "deep-is";
1702 packageName = "deep-is";
1703 version = "0.1.3";
1704 src = fetchurl {
1705 url = "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz";
1706 sha1 = "b369d6fb5dbc13eecf524f91b070feedc357cf34";
1707 };
1708 };
1709 "wordwrap-1.0.0" = {
1710 name = "wordwrap";
1711 packageName = "wordwrap";
1712 version = "1.0.0";
1713 src = fetchurl {
1714 url = "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz";
1715 sha1 = "27584810891456a4171c8d0226441ade90cbcaeb";
1716 };
1717 };
1718 "type-check-0.3.2" = {
1719 name = "type-check";
1720 packageName = "type-check";
1721 version = "0.3.2";
1722 src = fetchurl {
1723 url = "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz";
1724 sha1 = "5884cab512cf1d355e3fb784f30804b2b520db72";
1725 };
1726 };
1727 "levn-0.3.0" = {
1728 name = "levn";
1729 packageName = "levn";
1730 version = "0.3.0";
1731 src = fetchurl {
1732 url = "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz";
1733 sha1 = "3b09924edf9f083c0490fdd4c0bc4421e04764ee";
1734 };
1735 };
1736 "fast-levenshtein-2.0.6" = {
1737 name = "fast-levenshtein";
1738 packageName = "fast-levenshtein";
1739 version = "2.0.6";
1740 src = fetchurl {
1741 url = "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz";
1742 sha1 = "3d8a5c66883a16a30ca8643e851f19baa7797917";
1743 };
1744 };
1745 "acorn-5.1.2" = {
1746 name = "acorn";
1747 packageName = "acorn";
1748 version = "5.1.2";
1749 src = fetchurl {
1750 url = "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz";
1751 sha1 = "911cb53e036807cf0fa778dc5d370fbd864246d7";
1752 };
1753 };
1754 "acorn-jsx-3.0.1" = {
1755 name = "acorn-jsx";
1756 packageName = "acorn-jsx";
1757 version = "3.0.1";
1758 src = fetchurl {
1759 url = "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz";
1760 sha1 = "afdf9488fb1ecefc8348f6fb22f464e32a58b36b";
1761 };
1762 };
1763 "object-assign-4.1.1" = {
1764 name = "object-assign";
1765 packageName = "object-assign";
1766 version = "4.1.1";
1767 src = fetchurl {
1768 url = "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz";
1769 sha1 = "2109adc7965887cfc05cbbd442cac8bfbb360863";
1770 };
1771 };
1772 "crisper-1.2.0" = {
1773 name = "crisper";
1774 packageName = "crisper";
1775 version = "1.2.0";
1776 src = fetchurl {
1777 url = "https://registry.npmjs.org/crisper/-/crisper-1.2.0.tgz";
1778 sha1 = "9a91f597d71f6110294e076ad44dbb3408568e46";
1779 };
1780 };
1781 2015 "optparse-1.0.5" = {
1782 2016 name = "optparse";
1783 2017 packageName = "optparse";
@@ -1787,303 +2021,6 b' let'
1787 2021 sha1 = "75e75a96506611eb1c65ba89018ff08a981e2c16";
1788 2022 };
1789 2023 };
1790 "semver-5.4.1" = {
1791 name = "semver";
1792 packageName = "semver";
1793 version = "5.4.1";
1794 src = fetchurl {
1795 url = "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz";
1796 sha1 = "e059c09d8571f0540823733433505d3a2f00b18e";
1797 };
1798 };
1799 "npm-registry-client-8.4.0" = {
1800 name = "npm-registry-client";
1801 packageName = "npm-registry-client";
1802 version = "8.4.0";
1803 src = fetchurl {
1804 url = "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.4.0.tgz";
1805 sha1 = "d52b901685647fc62a4c03eafecb6ceaa5018d4c";
1806 };
1807 };
1808 "npmconf-2.1.2" = {
1809 name = "npmconf";
1810 packageName = "npmconf";
1811 version = "2.1.2";
1812 src = fetchurl {
1813 url = "https://registry.npmjs.org/npmconf/-/npmconf-2.1.2.tgz";
1814 sha1 = "66606a4a736f1e77a059aa071a79c94ab781853a";
1815 };
1816 };
1817 "tar-3.1.15" = {
1818 name = "tar";
1819 packageName = "tar";
1820 version = "3.1.15";
1821 src = fetchurl {
1822 url = "https://registry.npmjs.org/tar/-/tar-3.1.15.tgz";
1823 sha1 = "cccdc35b90917d58e4c3837795d5d022d7a1f46f";
1824 };
1825 };
1826 "temp-0.8.3" = {
1827 name = "temp";
1828 packageName = "temp";
1829 version = "0.8.3";
1830 src = fetchurl {
1831 url = "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz";
1832 sha1 = "e0c6bc4d26b903124410e4fed81103014dfc1f59";
1833 };
1834 };
1835 "fs.extra-1.3.2" = {
1836 name = "fs.extra";
1837 packageName = "fs.extra";
1838 version = "1.3.2";
1839 src = fetchurl {
1840 url = "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz";
1841 sha1 = "dd023f93013bee24531f1b33514c37b20fd93349";
1842 };
1843 };
1844 "findit-2.0.0" = {
1845 name = "findit";
1846 packageName = "findit";
1847 version = "2.0.0";
1848 src = fetchurl {
1849 url = "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz";
1850 sha1 = "6509f0126af4c178551cfa99394e032e13a4d56e";
1851 };
1852 };
1853 "base64-js-1.2.1" = {
1854 name = "base64-js";
1855 packageName = "base64-js";
1856 version = "1.2.1";
1857 src = fetchurl {
1858 url = "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz";
1859 sha1 = "a91947da1f4a516ea38e5b4ec0ec3773675e0886";
1860 };
1861 };
1862 "slasp-0.0.4" = {
1863 name = "slasp";
1864 packageName = "slasp";
1865 version = "0.0.4";
1866 src = fetchurl {
1867 url = "https://registry.npmjs.org/slasp/-/slasp-0.0.4.tgz";
1868 sha1 = "9adc26ee729a0f95095851a5489f87a5258d57a9";
1869 };
1870 };
1871 "nijs-0.0.23" = {
1872 name = "nijs";
1873 packageName = "nijs";
1874 version = "0.0.23";
1875 src = fetchurl {
1876 url = "https://registry.npmjs.org/nijs/-/nijs-0.0.23.tgz";
1877 sha1 = "dbf8f4a0acafbe3b8d9b71c24cbd1d851de6c31a";
1878 };
1879 };
1880 "concat-stream-1.6.0" = {
1881 name = "concat-stream";
1882 packageName = "concat-stream";
1883 version = "1.6.0";
1884 src = fetchurl {
1885 url = "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz";
1886 sha1 = "0aac662fd52be78964d5532f694784e70110acf7";
1887 };
1888 };
1889 "normalize-package-data-2.4.0" = {
1890 name = "normalize-package-data";
1891 packageName = "normalize-package-data";
1892 version = "2.4.0";
1893 src = fetchurl {
1894 url = "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz";
1895 sha1 = "12f95a307d58352075a04907b84ac8be98ac012f";
1896 };
1897 };
1898 "npm-package-arg-5.1.2" = {
1899 name = "npm-package-arg";
1900 packageName = "npm-package-arg";
1901 version = "5.1.2";
1902 src = fetchurl {
1903 url = "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz";
1904 sha1 = "fb18d17bb61e60900d6312619919bd753755ab37";
1905 };
1906 };
1907 "once-1.4.0" = {
1908 name = "once";
1909 packageName = "once";
1910 version = "1.4.0";
1911 src = fetchurl {
1912 url = "https://registry.npmjs.org/once/-/once-1.4.0.tgz";
1913 sha1 = "583b1aa775961d4b113ac17d9c50baef9dd76bd1";
1914 };
1915 };
1916 "retry-0.10.1" = {
1917 name = "retry";
1918 packageName = "retry";
1919 version = "0.10.1";
1920 src = fetchurl {
1921 url = "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz";
1922 sha1 = "e76388d217992c252750241d3d3956fed98d8ff4";
1923 };
1924 };
1925 "slide-1.1.6" = {
1926 name = "slide";
1927 packageName = "slide";
1928 version = "1.1.6";
1929 src = fetchurl {
1930 url = "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz";
1931 sha1 = "56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707";
1932 };
1933 };
1934 "ssri-4.1.6" = {
1935 name = "ssri";
1936 packageName = "ssri";
1937 version = "4.1.6";
1938 src = fetchurl {
1939 url = "https://registry.npmjs.org/ssri/-/ssri-4.1.6.tgz";
1940 sha1 = "0cb49b6ac84457e7bdd466cb730c3cb623e9a25b";
1941 };
1942 };
1943 "npmlog-4.1.2" = {
1944 name = "npmlog";
1945 packageName = "npmlog";
1946 version = "4.1.2";
1947 src = fetchurl {
1948 url = "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz";
1949 sha1 = "08a7f2a8bf734604779a9efa4ad5cc717abb954b";
1950 };
1951 };
1952 "typedarray-0.0.6" = {
1953 name = "typedarray";
1954 packageName = "typedarray";
1955 version = "0.0.6";
1956 src = fetchurl {
1957 url = "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz";
1958 sha1 = "867ac74e3864187b1d3d47d996a78ec5c8830777";
1959 };
1960 };
1961 "readable-stream-2.3.3" = {
1962 name = "readable-stream";
1963 packageName = "readable-stream";
1964 version = "2.3.3";
1965 src = fetchurl {
1966 url = "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz";
1967 sha1 = "368f2512d79f9d46fdfc71349ae7878bbc1eb95c";
1968 };
1969 };
1970 "isarray-1.0.0" = {
1971 name = "isarray";
1972 packageName = "isarray";
1973 version = "1.0.0";
1974 src = fetchurl {
1975 url = "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz";
1976 sha1 = "bb935d48582cba168c06834957a54a3e07124f11";
1977 };
1978 };
1979 "process-nextick-args-1.0.7" = {
1980 name = "process-nextick-args";
1981 packageName = "process-nextick-args";
1982 version = "1.0.7";
1983 src = fetchurl {
1984 url = "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz";
1985 sha1 = "150e20b756590ad3f91093f25a4f2ad8bff30ba3";
1986 };
1987 };
1988 "string_decoder-1.0.3" = {
1989 name = "string_decoder";
1990 packageName = "string_decoder";
1991 version = "1.0.3";
1992 src = fetchurl {
1993 url = "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz";
1994 sha1 = "0fc67d7c141825de94282dd536bec6b9bce860ab";
1995 };
1996 };
1997 "util-deprecate-1.0.2" = {
1998 name = "util-deprecate";
1999 packageName = "util-deprecate";
2000 version = "1.0.2";
2001 src = fetchurl {
2002 url = "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz";
2003 sha1 = "450d4dc9fa70de732762fbd2d4a28981419a0ccf";
2004 };
2005 };
2006 "hosted-git-info-2.5.0" = {
2007 name = "hosted-git-info";
2008 packageName = "hosted-git-info";
2009 version = "2.5.0";
2010 src = fetchurl {
2011 url = "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz";
2012 sha1 = "6d60e34b3abbc8313062c3b798ef8d901a07af3c";
2013 };
2014 };
2015 "is-builtin-module-1.0.0" = {
2016 name = "is-builtin-module";
2017 packageName = "is-builtin-module";
2018 version = "1.0.0";
2019 src = fetchurl {
2020 url = "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz";
2021 sha1 = "540572d34f7ac3119f8f76c30cbc1b1e037affbe";
2022 };
2023 };
2024 "validate-npm-package-license-3.0.1" = {
2025 name = "validate-npm-package-license";
2026 packageName = "validate-npm-package-license";
2027 version = "3.0.1";
2028 src = fetchurl {
2029 url = "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz";
2030 sha1 = "2804babe712ad3379459acfbe24746ab2c303fbc";
2031 };
2032 };
2033 "builtin-modules-1.1.1" = {
2034 name = "builtin-modules";
2035 packageName = "builtin-modules";
2036 version = "1.1.1";
2037 src = fetchurl {
2038 url = "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz";
2039 sha1 = "270f076c5a72c02f5b65a47df94c5fe3a278892f";
2040 };
2041 };
2042 "spdx-correct-1.0.2" = {
2043 name = "spdx-correct";
2044 packageName = "spdx-correct";
2045 version = "1.0.2";
2046 src = fetchurl {
2047 url = "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz";
2048 sha1 = "4b3073d933ff51f3912f03ac5519498a4150db40";
2049 };
2050 };
2051 "spdx-expression-parse-1.0.4" = {
2052 name = "spdx-expression-parse";
2053 packageName = "spdx-expression-parse";
2054 version = "1.0.4";
2055 src = fetchurl {
2056 url = "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz";
2057 sha1 = "9bdf2f20e1f40ed447fbe273266191fced51626c";
2058 };
2059 };
2060 "spdx-license-ids-1.2.2" = {
2061 name = "spdx-license-ids";
2062 packageName = "spdx-license-ids";
2063 version = "1.2.2";
2064 src = fetchurl {
2065 url = "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz";
2066 sha1 = "c9df7a3424594ade6bd11900d596696dc06bac57";
2067 };
2068 };
2069 "osenv-0.1.4" = {
2070 name = "osenv";
2071 packageName = "osenv";
2072 version = "0.1.4";
2073 src = fetchurl {
2074 url = "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz";
2075 sha1 = "42fe6d5953df06c8064be6f176c3d05aaaa34644";
2076 };
2077 };
2078 "validate-npm-package-name-3.0.0" = {
2079 name = "validate-npm-package-name";
2080 packageName = "validate-npm-package-name";
2081 version = "3.0.0";
2082 src = fetchurl {
2083 url = "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz";
2084 sha1 = "5fa912d81eb7d0c74afc140de7317f0ca7df437e";
2085 };
2086 };
2087 2024 "os-homedir-1.0.2" = {
2088 2025 name = "os-homedir";
2089 2026 packageName = "os-homedir";
@@ -2102,184 +2039,130 b' let'
2102 2039 sha1 = "bbe67406c79aa85c5cfec766fe5734555dfa1274";
2103 2040 };
2104 2041 };
2105 "builtins-1.0.3" = {
2106 name = "builtins";
2107 packageName = "builtins";
2108 version = "1.0.3";
2109 src = fetchurl {
2110 url = "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz";
2111 sha1 = "cb94faeb61c8696451db36534e1422f94f0aee88";
2112 };
2113 };
2114 "wrappy-1.0.2" = {
2115 name = "wrappy";
2116 packageName = "wrappy";
2117 version = "1.0.2";
2118 src = fetchurl {
2119 url = "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz";
2120 sha1 = "b5243d8f3ec1aa35f1364605bc0d1036e30ab69f";
2121 };
2122 };
2123 "are-we-there-yet-1.1.4" = {
2124 name = "are-we-there-yet";
2125 packageName = "are-we-there-yet";
2126 version = "1.1.4";
2127 src = fetchurl {
2128 url = "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz";
2129 sha1 = "bb5dca382bb94f05e15194373d16fd3ba1ca110d";
2130 };
2131 };
2132 "console-control-strings-1.1.0" = {
2133 name = "console-control-strings";
2134 packageName = "console-control-strings";
2135 version = "1.1.0";
2136 src = fetchurl {
2137 url = "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz";
2138 sha1 = "3d7cf4464db6446ea644bf4b39507f9851008e8e";
2139 };
2140 };
2141 "gauge-2.7.4" = {
2142 name = "gauge";
2143 packageName = "gauge";
2144 version = "2.7.4";
2145 src = fetchurl {
2146 url = "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz";
2147 sha1 = "2c03405c7538c39d7eb37b317022e325fb018bf7";
2148 };
2149 };
2150 "set-blocking-2.0.0" = {
2151 name = "set-blocking";
2152 packageName = "set-blocking";
2153 version = "2.0.0";
2154 src = fetchurl {
2155 url = "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz";
2156 sha1 = "045f9782d011ae9a6803ddd382b24392b3d890f7";
2157 };
2158 };
2159 "delegates-1.0.0" = {
2160 name = "delegates";
2161 packageName = "delegates";
2042 "osenv-0.1.5" = {
2043 name = "osenv";
2044 packageName = "osenv";
2045 version = "0.1.5";
2046 src = fetchurl {
2047 url = "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz";
2048 sha512 = "0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==";
2049 };
2050 };
2051 "parse5-1.5.1" = {
2052 name = "parse5";
2053 packageName = "parse5";
2054 version = "1.5.1";
2055 src = fetchurl {
2056 url = "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz";
2057 sha1 = "9b7f3b0de32be78dc2401b17573ccaf0f6f59d94";
2058 };
2059 };
2060 "path-is-absolute-1.0.1" = {
2061 name = "path-is-absolute";
2062 packageName = "path-is-absolute";
2063 version = "1.0.1";
2064 src = fetchurl {
2065 url = "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz";
2066 sha1 = "174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f";
2067 };
2068 };
2069 "path-posix-1.0.0" = {
2070 name = "path-posix";
2071 packageName = "path-posix";
2162 2072 version = "1.0.0";
2163 2073 src = fetchurl {
2164 url = "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz";
2165 sha1 = "84c6e159b81904fdca59a0ef44cd870d31250f9a";
2166 };
2167 };
2168 "aproba-1.2.0" = {
2169 name = "aproba";
2170 packageName = "aproba";
2074 url = "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz";
2075 sha1 = "06b26113f56beab042545a23bfa88003ccac260f";
2076 };
2077 };
2078 "pend-1.2.0" = {
2079 name = "pend";
2080 packageName = "pend";
2171 2081 version = "1.2.0";
2172 2082 src = fetchurl {
2173 url = "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz";
2174 sha1 = "6802e6264efd18c790a1b0d517f0f2627bf2c94a";
2175 };
2176 };
2177 "has-unicode-2.0.1" = {
2178 name = "has-unicode";
2179 packageName = "has-unicode";
2083 url = "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz";
2084 sha1 = "7a57eb550a6783f9115331fcf4663d5c8e007a50";
2085 };
2086 };
2087 "performance-now-0.2.0" = {
2088 name = "performance-now";
2089 packageName = "performance-now";
2090 version = "0.2.0";
2091 src = fetchurl {
2092 url = "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz";
2093 sha1 = "33ef30c5c77d4ea21c5a53869d91b56d8f2555e5";
2094 };
2095 };
2096 "phantom-4.0.12" = {
2097 name = "phantom";
2098 packageName = "phantom";
2099 version = "4.0.12";
2100 src = fetchurl {
2101 url = "https://registry.npmjs.org/phantom/-/phantom-4.0.12.tgz";
2102 sha512 = "Tz82XhtPmwCk1FFPmecy7yRGZG2btpzY2KI9fcoPT7zT9det0CcMyfBFPp1S8DqzsnQnm8ZYEfdy528mwVtksA==";
2103 };
2104 };
2105 "phantomjs-prebuilt-2.1.16" = {
2106 name = "phantomjs-prebuilt";
2107 packageName = "phantomjs-prebuilt";
2108 version = "2.1.16";
2109 src = fetchurl {
2110 url = "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz";
2111 sha1 = "efd212a4a3966d3647684ea8ba788549be2aefef";
2112 };
2113 };
2114 "pinkie-2.0.4" = {
2115 name = "pinkie";
2116 packageName = "pinkie";
2117 version = "2.0.4";
2118 src = fetchurl {
2119 url = "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz";
2120 sha1 = "72556b80cfa0d48a974e80e77248e80ed4f7f870";
2121 };
2122 };
2123 "pinkie-promise-2.0.1" = {
2124 name = "pinkie-promise";
2125 packageName = "pinkie-promise";
2180 2126 version = "2.0.1";
2181 2127 src = fetchurl {
2182 url = "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz";
2183 sha1 = "e0e6fe6a28cf51138855e086d1691e771de2a8b9";
2184 };
2185 };
2186 "signal-exit-3.0.2" = {
2187 name = "signal-exit";
2188 packageName = "signal-exit";
2189 version = "3.0.2";
2190 src = fetchurl {
2191 url = "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz";
2192 sha1 = "b5fdc08f1287ea1178628e415e25132b73646c6d";
2193 };
2194 };
2195 "string-width-1.0.2" = {
2196 name = "string-width";
2197 packageName = "string-width";
2198 version = "1.0.2";
2199 src = fetchurl {
2200 url = "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz";
2201 sha1 = "118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3";
2202 };
2203 };
2204 "wide-align-1.1.2" = {
2205 name = "wide-align";
2206 packageName = "wide-align";
2128 url = "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz";
2129 sha1 = "2135d6dfa7a358c069ac9b178776288228450ffa";
2130 };
2131 };
2132 "prelude-ls-1.1.2" = {
2133 name = "prelude-ls";
2134 packageName = "prelude-ls";
2207 2135 version = "1.1.2";
2208 2136 src = fetchurl {
2209 url = "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz";
2210 sha1 = "571e0f1b0604636ebc0dfc21b0339bbe31341710";
2211 };
2212 };
2213 "code-point-at-1.1.0" = {
2214 name = "code-point-at";
2215 packageName = "code-point-at";
2216 version = "1.1.0";
2217 src = fetchurl {
2218 url = "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz";
2219 sha1 = "0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77";
2220 };
2221 };
2222 "is-fullwidth-code-point-1.0.0" = {
2223 name = "is-fullwidth-code-point";
2224 packageName = "is-fullwidth-code-point";
2225 version = "1.0.0";
2226 src = fetchurl {
2227 url = "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz";
2228 sha1 = "ef9e31386f031a7f0d643af82fde50c457ef00cb";
2229 };
2230 };
2231 "number-is-nan-1.0.1" = {
2232 name = "number-is-nan";
2233 packageName = "number-is-nan";
2234 version = "1.0.1";
2235 src = fetchurl {
2236 url = "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz";
2237 sha1 = "097b602b53422a522c1afb8790318336941a011d";
2238 };
2239 };
2240 "config-chain-1.1.11" = {
2241 name = "config-chain";
2242 packageName = "config-chain";
2243 version = "1.1.11";
2244 src = fetchurl {
2245 url = "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz";
2246 sha1 = "aba09747dfbe4c3e70e766a6e41586e1859fc6f2";
2247 };
2248 };
2249 "ini-1.3.4" = {
2250 name = "ini";
2251 packageName = "ini";
2252 version = "1.3.4";
2253 src = fetchurl {
2254 url = "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz";
2255 sha1 = "0537cb79daf59b59a1a517dff706c86ec039162e";
2256 };
2257 };
2258 "once-1.3.3" = {
2259 name = "once";
2260 packageName = "once";
2261 version = "1.3.3";
2262 src = fetchurl {
2263 url = "https://registry.npmjs.org/once/-/once-1.3.3.tgz";
2264 sha1 = "b2e261557ce4c314ec8304f3fa82663e4297ca20";
2265 };
2266 };
2267 "semver-4.3.6" = {
2268 name = "semver";
2269 packageName = "semver";
2270 version = "4.3.6";
2271 src = fetchurl {
2272 url = "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz";
2273 sha1 = "300bc6e0e86374f7ba61068b5b1ecd57fc6532da";
2274 };
2275 };
2276 "uid-number-0.0.5" = {
2277 name = "uid-number";
2278 packageName = "uid-number";
2279 version = "0.0.5";
2280 src = fetchurl {
2281 url = "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz";
2282 sha1 = "5a3db23ef5dbd55b81fce0ec9a2ac6fccdebb81e";
2137 url = "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz";
2138 sha1 = "21932a549f5e52ffd9a827f570e04be62a97da54";
2139 };
2140 };
2141 "process-nextick-args-2.0.0" = {
2142 name = "process-nextick-args";
2143 packageName = "process-nextick-args";
2144 version = "2.0.0";
2145 src = fetchurl {
2146 url = "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz";
2147 sha512 = "MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==";
2148 };
2149 };
2150 "progress-1.1.8" = {
2151 name = "progress";
2152 packageName = "progress";
2153 version = "1.1.8";
2154 src = fetchurl {
2155 url = "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz";
2156 sha1 = "e260c78f6161cdd9b0e56cc3e0a85de17c7a57be";
2157 };
2158 };
2159 "promise-7.3.1" = {
2160 name = "promise";
2161 packageName = "promise";
2162 version = "7.3.1";
2163 src = fetchurl {
2164 url = "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz";
2165 sha512 = "nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==";
2283 2166 };
2284 2167 };
2285 2168 "proto-list-1.2.4" = {
@@ -2291,238 +2174,49 b' let'
2291 2174 sha1 = "212d5bfe1318306a420f6402b8e26ff39647a849";
2292 2175 };
2293 2176 };
2294 "minipass-2.2.1" = {
2295 name = "minipass";
2296 packageName = "minipass";
2297 version = "2.2.1";
2298 src = fetchurl {
2299 url = "https://registry.npmjs.org/minipass/-/minipass-2.2.1.tgz";
2300 sha1 = "5ada97538b1027b4cf7213432428578cb564011f";
2301 };
2302 };
2303 "minizlib-1.0.3" = {
2304 name = "minizlib";
2305 packageName = "minizlib";
2306 version = "1.0.3";
2307 src = fetchurl {
2308 url = "https://registry.npmjs.org/minizlib/-/minizlib-1.0.3.tgz";
2309 sha1 = "d5c1abf77be154619952e253336eccab9b2a32f5";
2310 };
2311 };
2312 "yallist-3.0.2" = {
2313 name = "yallist";
2314 packageName = "yallist";
2315 version = "3.0.2";
2316 src = fetchurl {
2317 url = "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz";
2318 sha1 = "8452b4bb7e83c7c188d8041c1a837c773d6d8bb9";
2319 };
2320 };
2321 "fs-extra-0.6.4" = {
2322 name = "fs-extra";
2323 packageName = "fs-extra";
2324 version = "0.6.4";
2325 src = fetchurl {
2326 url = "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz";
2327 sha1 = "f46f0c75b7841f8d200b3348cd4d691d5a099d15";
2328 };
2329 };
2330 "mkdirp-0.3.5" = {
2331 name = "mkdirp";
2332 packageName = "mkdirp";
2333 version = "0.3.5";
2334 src = fetchurl {
2335 url = "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz";
2336 sha1 = "de3e5f8961c88c787ee1368df849ac4413eca8d7";
2337 };
2338 };
2339 "walk-2.3.9" = {
2340 name = "walk";
2341 packageName = "walk";
2342 version = "2.3.9";
2343 src = fetchurl {
2344 url = "https://registry.npmjs.org/walk/-/walk-2.3.9.tgz";
2345 sha1 = "31b4db6678f2ae01c39ea9fb8725a9031e558a7b";
2346 };
2347 };
2348 "ncp-0.4.2" = {
2349 name = "ncp";
2350 packageName = "ncp";
2351 version = "0.4.2";
2352 src = fetchurl {
2353 url = "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz";
2354 sha1 = "abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574";
2355 };
2356 };
2357 "jsonfile-1.0.1" = {
2358 name = "jsonfile";
2359 packageName = "jsonfile";
2360 version = "1.0.1";
2361 src = fetchurl {
2362 url = "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz";
2363 sha1 = "ea5efe40b83690b98667614a7392fc60e842c0dd";
2364 };
2365 };
2366 "foreachasync-3.0.0" = {
2367 name = "foreachasync";
2368 packageName = "foreachasync";
2369 version = "3.0.0";
2370 src = fetchurl {
2371 url = "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz";
2372 sha1 = "5502987dc8714be3392097f32e0071c9dee07cf6";
2373 };
2374 };
2375 "cli-1.0.1" = {
2376 name = "cli";
2377 packageName = "cli";
2177 "prr-1.0.1" = {
2178 name = "prr";
2179 packageName = "prr";
2378 2180 version = "1.0.1";
2379 2181 src = fetchurl {
2380 url = "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz";
2381 sha1 = "22817534f24bfa4950c34d532d48ecbc621b8c14";
2382 };
2383 };
2384 "console-browserify-1.1.0" = {
2385 name = "console-browserify";
2386 packageName = "console-browserify";
2387 version = "1.1.0";
2388 src = fetchurl {
2389 url = "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz";
2390 sha1 = "f0241c45730a9fc6323b206dbf38edc741d0bb10";
2391 };
2392 };
2393 "htmlparser2-3.8.3" = {
2394 name = "htmlparser2";
2395 packageName = "htmlparser2";
2396 version = "3.8.3";
2397 src = fetchurl {
2398 url = "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz";
2399 sha1 = "996c28b191516a8be86501a7d79757e5c70c1068";
2400 };
2401 };
2402 "minimatch-3.0.4" = {
2403 name = "minimatch";
2404 packageName = "minimatch";
2405 version = "3.0.4";
2406 src = fetchurl {
2407 url = "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz";
2408 sha1 = "5166e286457f03306064be5497e8dbb0c3d32083";
2409 };
2410 };
2411 "shelljs-0.3.0" = {
2412 name = "shelljs";
2413 packageName = "shelljs";
2414 version = "0.3.0";
2415 src = fetchurl {
2416 url = "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz";
2417 sha1 = "3596e6307a781544f591f37da618360f31db57b1";
2418 };
2419 };
2420 "strip-json-comments-1.0.4" = {
2421 name = "strip-json-comments";
2422 packageName = "strip-json-comments";
2423 version = "1.0.4";
2424 src = fetchurl {
2425 url = "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz";
2426 sha1 = "1e15fbcac97d3ee99bf2d73b4c656b082bbafb91";
2427 };
2428 };
2429 "lodash-3.7.0" = {
2430 name = "lodash";
2431 packageName = "lodash";
2432 version = "3.7.0";
2433 src = fetchurl {
2434 url = "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz";
2435 sha1 = "3678bd8ab995057c07ade836ed2ef087da811d45";
2436 };
2437 };
2438 "glob-7.1.2" = {
2439 name = "glob";
2440 packageName = "glob";
2441 version = "7.1.2";
2442 src = fetchurl {
2443 url = "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz";
2444 sha1 = "c19c9df9a028702d678612384a6552404c636d15";
2445 };
2446 };
2447 "fs.realpath-1.0.0" = {
2448 name = "fs.realpath";
2449 packageName = "fs.realpath";
2450 version = "1.0.0";
2451 src = fetchurl {
2452 url = "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz";
2453 sha1 = "1504ad2523158caa40db4a2787cb01411994ea4f";
2454 };
2455 };
2456 "inflight-1.0.6" = {
2457 name = "inflight";
2458 packageName = "inflight";
2459 version = "1.0.6";
2460 src = fetchurl {
2461 url = "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz";
2462 sha1 = "49bd6331d7d02d0c09bc910a1075ba8165b56df9";
2463 };
2464 };
2465 "brace-expansion-1.1.8" = {
2466 name = "brace-expansion";
2467 packageName = "brace-expansion";
2468 version = "1.1.8";
2469 src = fetchurl {
2470 url = "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz";
2471 sha1 = "c07b211c7c952ec1f8efd51a77ef0d1d3990a292";
2472 };
2473 };
2474 "balanced-match-1.0.0" = {
2475 name = "balanced-match";
2476 packageName = "balanced-match";
2477 version = "1.0.0";
2478 src = fetchurl {
2479 url = "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz";
2480 sha1 = "89b4d199ab2bee49de164ea02b89ce462d71b767";
2481 };
2482 };
2483 "concat-map-0.0.1" = {
2484 name = "concat-map";
2485 packageName = "concat-map";
2486 version = "0.0.1";
2487 src = fetchurl {
2488 url = "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz";
2489 sha1 = "d8a96bd77fd68df7793a73036a3ba0d5405d477b";
2490 };
2491 };
2492 "date-now-0.1.4" = {
2493 name = "date-now";
2494 packageName = "date-now";
2495 version = "0.1.4";
2496 src = fetchurl {
2497 url = "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz";
2498 sha1 = "eaf439fd4d4848ad74e5cc7dbef200672b9e345b";
2499 };
2500 };
2501 "domhandler-2.3.0" = {
2502 name = "domhandler";
2503 packageName = "domhandler";
2504 version = "2.3.0";
2505 src = fetchurl {
2506 url = "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz";
2507 sha1 = "2de59a0822d5027fabff6f032c2b25a2a8abe738";
2508 };
2509 };
2510 "domutils-1.5.1" = {
2511 name = "domutils";
2512 packageName = "domutils";
2513 version = "1.5.1";
2514 src = fetchurl {
2515 url = "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz";
2516 sha1 = "dcd8488a26f563d61079e48c9f7b7e32373682cf";
2517 };
2518 };
2519 "domelementtype-1.3.0" = {
2520 name = "domelementtype";
2521 packageName = "domelementtype";
2522 version = "1.3.0";
2523 src = fetchurl {
2524 url = "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz";
2525 sha1 = "b17aed82e8ab59e52dd9c19b1756e0fc187204c2";
2182 url = "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz";
2183 sha1 = "d3fc114ba06995a45ec6893f484ceb1d78f5f476";
2184 };
2185 };
2186 "punycode-1.4.1" = {
2187 name = "punycode";
2188 packageName = "punycode";
2189 version = "1.4.1";
2190 src = fetchurl {
2191 url = "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz";
2192 sha1 = "c0d5a63b2718800ad8e1eb0fa5269c84dd41845e";
2193 };
2194 };
2195 "qrious-4.0.2" = {
2196 name = "qrious";
2197 packageName = "qrious";
2198 version = "4.0.2";
2199 src = fetchurl {
2200 url = "https://registry.npmjs.org/qrious/-/qrious-4.0.2.tgz";
2201 sha512 = "xWPJIrK1zu5Ypn898fBp8RHkT/9ibquV2Kv24S/JY9VYEhMBMKur1gHVsOiNUh7PHP9uCgejjpZUHUIXXKoU/g==";
2202 };
2203 };
2204 "qs-0.5.6" = {
2205 name = "qs";
2206 packageName = "qs";
2207 version = "0.5.6";
2208 src = fetchurl {
2209 url = "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz";
2210 sha1 = "31b1ad058567651c526921506b9a8793911a0384";
2211 };
2212 };
2213 "qs-6.4.0" = {
2214 name = "qs";
2215 packageName = "qs";
2216 version = "6.4.0";
2217 src = fetchurl {
2218 url = "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz";
2219 sha1 = "13e26d28ad6b0ffaa91312cd3bf708ed351e7233";
2526 2220 };
2527 2221 };
2528 2222 "readable-stream-1.1.14" = {
@@ -2534,58 +2228,94 b' let'
2534 2228 sha1 = "7cf4c54ef648e3813084c636dd2079e166c081d9";
2535 2229 };
2536 2230 };
2537 "entities-1.0.0" = {
2538 name = "entities";
2539 packageName = "entities";
2540 version = "1.0.0";
2541 src = fetchurl {
2542 url = "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz";
2543 sha1 = "b2987aa3821347fcde642b24fdfc9e4fb712bf26";
2544 };
2545 };
2546 "dom-serializer-0.1.0" = {
2547 name = "dom-serializer";
2548 packageName = "dom-serializer";
2549 version = "0.1.0";
2550 src = fetchurl {
2551 url = "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz";
2552 sha1 = "073c697546ce0780ce23be4a28e293e40bc30c82";
2553 };
2554 };
2555 "domelementtype-1.1.3" = {
2556 name = "domelementtype";
2557 packageName = "domelementtype";
2558 version = "1.1.3";
2559 src = fetchurl {
2560 url = "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz";
2561 sha1 = "bd28773e2642881aec51544924299c5cd822185b";
2562 };
2563 };
2564 "entities-1.1.1" = {
2565 name = "entities";
2566 packageName = "entities";
2567 version = "1.1.1";
2568 src = fetchurl {
2569 url = "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz";
2570 sha1 = "6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0";
2571 };
2572 };
2573 "string_decoder-0.10.31" = {
2574 name = "string_decoder";
2575 packageName = "string_decoder";
2576 version = "0.10.31";
2577 src = fetchurl {
2578 url = "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz";
2579 sha1 = "62e203bc41766c6c28c9fc84301dab1c5310fa94";
2580 };
2581 };
2582 "good-listener-1.2.2" = {
2583 name = "good-listener";
2584 packageName = "good-listener";
2585 version = "1.2.2";
2586 src = fetchurl {
2587 url = "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz";
2588 sha1 = "d53b30cdf9313dffb7dc9a0d477096aa6d145c50";
2231 "readable-stream-2.3.6" = {
2232 name = "readable-stream";
2233 packageName = "readable-stream";
2234 version = "2.3.6";
2235 src = fetchurl {
2236 url = "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz";
2237 sha512 = "tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==";
2238 };
2239 };
2240 "reduce-flatten-1.0.1" = {
2241 name = "reduce-flatten";
2242 packageName = "reduce-flatten";
2243 version = "1.0.1";
2244 src = fetchurl {
2245 url = "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz";
2246 sha1 = "258c78efd153ddf93cb561237f61184f3696e327";
2247 };
2248 };
2249 "regenerator-runtime-0.10.5" = {
2250 name = "regenerator-runtime";
2251 packageName = "regenerator-runtime";
2252 version = "0.10.5";
2253 src = fetchurl {
2254 url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz";
2255 sha1 = "336c3efc1220adcedda2c9fab67b5a7955a33658";
2256 };
2257 };
2258 "regenerator-runtime-0.11.1" = {
2259 name = "regenerator-runtime";
2260 packageName = "regenerator-runtime";
2261 version = "0.11.1";
2262 src = fetchurl {
2263 url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz";
2264 sha512 = "MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==";
2265 };
2266 };
2267 "request-2.81.0" = {
2268 name = "request";
2269 packageName = "request";
2270 version = "2.81.0";
2271 src = fetchurl {
2272 url = "https://registry.npmjs.org/request/-/request-2.81.0.tgz";
2273 sha1 = "c6928946a0e06c5f8d6f8a9333469ffda46298a0";
2274 };
2275 };
2276 "request-progress-2.0.1" = {
2277 name = "request-progress";
2278 packageName = "request-progress";
2279 version = "2.0.1";
2280 src = fetchurl {
2281 url = "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz";
2282 sha1 = "5d36bb57961c673aa5b788dbc8141fdf23b44e08";
2283 };
2284 };
2285 "retry-0.10.1" = {
2286 name = "retry";
2287 packageName = "retry";
2288 version = "0.10.1";
2289 src = fetchurl {
2290 url = "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz";
2291 sha1 = "e76388d217992c252750241d3d3956fed98d8ff4";
2292 };
2293 };
2294 "rimraf-2.2.8" = {
2295 name = "rimraf";
2296 packageName = "rimraf";
2297 version = "2.2.8";
2298 src = fetchurl {
2299 url = "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz";
2300 sha1 = "e439be2aaee327321952730f99a8929e4fc50582";
2301 };
2302 };
2303 "safe-buffer-5.1.2" = {
2304 name = "safe-buffer";
2305 packageName = "safe-buffer";
2306 version = "5.1.2";
2307 src = fetchurl {
2308 url = "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz";
2309 sha512 = "Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==";
2310 };
2311 };
2312 "safer-buffer-2.1.2" = {
2313 name = "safer-buffer";
2314 packageName = "safer-buffer";
2315 version = "2.1.2";
2316 src = fetchurl {
2317 url = "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz";
2318 sha512 = "YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==";
2589 2319 };
2590 2320 };
2591 2321 "select-1.1.2" = {
@@ -2597,88 +2327,734 b' let'
2597 2327 sha1 = "0e7350acdec80b1108528786ec1d4418d11b396d";
2598 2328 };
2599 2329 };
2330 "semver-4.3.6" = {
2331 name = "semver";
2332 packageName = "semver";
2333 version = "4.3.6";
2334 src = fetchurl {
2335 url = "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz";
2336 sha1 = "300bc6e0e86374f7ba61068b5b1ecd57fc6532da";
2337 };
2338 };
2339 "semver-5.5.0" = {
2340 name = "semver";
2341 packageName = "semver";
2342 version = "5.5.0";
2343 src = fetchurl {
2344 url = "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz";
2345 sha512 = "4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==";
2346 };
2347 };
2348 "set-blocking-2.0.0" = {
2349 name = "set-blocking";
2350 packageName = "set-blocking";
2351 version = "2.0.0";
2352 src = fetchurl {
2353 url = "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz";
2354 sha1 = "045f9782d011ae9a6803ddd382b24392b3d890f7";
2355 };
2356 };
2357 "shelljs-0.3.0" = {
2358 name = "shelljs";
2359 packageName = "shelljs";
2360 version = "0.3.0";
2361 src = fetchurl {
2362 url = "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz";
2363 sha1 = "3596e6307a781544f591f37da618360f31db57b1";
2364 };
2365 };
2366 "sigmund-1.0.1" = {
2367 name = "sigmund";
2368 packageName = "sigmund";
2369 version = "1.0.1";
2370 src = fetchurl {
2371 url = "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz";
2372 sha1 = "3ff21f198cad2175f9f3b781853fd94d0d19b590";
2373 };
2374 };
2375 "signal-exit-3.0.2" = {
2376 name = "signal-exit";
2377 packageName = "signal-exit";
2378 version = "3.0.2";
2379 src = fetchurl {
2380 url = "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz";
2381 sha1 = "b5fdc08f1287ea1178628e415e25132b73646c6d";
2382 };
2383 };
2384 "slasp-0.0.4" = {
2385 name = "slasp";
2386 packageName = "slasp";
2387 version = "0.0.4";
2388 src = fetchurl {
2389 url = "https://registry.npmjs.org/slasp/-/slasp-0.0.4.tgz";
2390 sha1 = "9adc26ee729a0f95095851a5489f87a5258d57a9";
2391 };
2392 };
2393 "slide-1.1.6" = {
2394 name = "slide";
2395 packageName = "slide";
2396 version = "1.1.6";
2397 src = fetchurl {
2398 url = "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz";
2399 sha1 = "56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707";
2400 };
2401 };
2402 "sntp-1.0.9" = {
2403 name = "sntp";
2404 packageName = "sntp";
2405 version = "1.0.9";
2406 src = fetchurl {
2407 url = "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz";
2408 sha1 = "6541184cc90aeea6c6e7b35e2659082443c66198";
2409 };
2410 };
2411 "source-map-0.3.0" = {
2412 name = "source-map";
2413 packageName = "source-map";
2414 version = "0.3.0";
2415 src = fetchurl {
2416 url = "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz";
2417 sha1 = "8586fb9a5a005e5b501e21cd18b6f21b457ad1f9";
2418 };
2419 };
2420 "source-map-0.5.7" = {
2421 name = "source-map";
2422 packageName = "source-map";
2423 version = "0.5.7";
2424 src = fetchurl {
2425 url = "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz";
2426 sha1 = "8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc";
2427 };
2428 };
2429 "source-map-0.6.1" = {
2430 name = "source-map";
2431 packageName = "source-map";
2432 version = "0.6.1";
2433 src = fetchurl {
2434 url = "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz";
2435 sha512 = "UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==";
2436 };
2437 };
2438 "spdx-correct-3.0.0" = {
2439 name = "spdx-correct";
2440 packageName = "spdx-correct";
2441 version = "3.0.0";
2442 src = fetchurl {
2443 url = "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz";
2444 sha512 = "N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==";
2445 };
2446 };
2447 "spdx-exceptions-2.1.0" = {
2448 name = "spdx-exceptions";
2449 packageName = "spdx-exceptions";
2450 version = "2.1.0";
2451 src = fetchurl {
2452 url = "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz";
2453 sha512 = "4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==";
2454 };
2455 };
2456 "spdx-expression-parse-3.0.0" = {
2457 name = "spdx-expression-parse";
2458 packageName = "spdx-expression-parse";
2459 version = "3.0.0";
2460 src = fetchurl {
2461 url = "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz";
2462 sha512 = "Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==";
2463 };
2464 };
2465 "spdx-license-ids-3.0.0" = {
2466 name = "spdx-license-ids";
2467 packageName = "spdx-license-ids";
2468 version = "3.0.0";
2469 src = fetchurl {
2470 url = "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz";
2471 sha512 = "2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==";
2472 };
2473 };
2474 "split-1.0.1" = {
2475 name = "split";
2476 packageName = "split";
2477 version = "1.0.1";
2478 src = fetchurl {
2479 url = "https://registry.npmjs.org/split/-/split-1.0.1.tgz";
2480 sha512 = "mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==";
2481 };
2482 };
2483 "sshpk-1.14.2" = {
2484 name = "sshpk";
2485 packageName = "sshpk";
2486 version = "1.14.2";
2487 src = fetchurl {
2488 url = "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz";
2489 sha1 = "c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98";
2490 };
2491 };
2492 "ssri-5.3.0" = {
2493 name = "ssri";
2494 packageName = "ssri";
2495 version = "5.3.0";
2496 src = fetchurl {
2497 url = "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz";
2498 sha512 = "XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==";
2499 };
2500 };
2501 "stack-trace-0.0.10" = {
2502 name = "stack-trace";
2503 packageName = "stack-trace";
2504 version = "0.0.10";
2505 src = fetchurl {
2506 url = "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz";
2507 sha1 = "547c70b347e8d32b4e108ea1a2a159e5fdde19c0";
2508 };
2509 };
2510 "string-width-1.0.2" = {
2511 name = "string-width";
2512 packageName = "string-width";
2513 version = "1.0.2";
2514 src = fetchurl {
2515 url = "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz";
2516 sha1 = "118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3";
2517 };
2518 };
2519 "string_decoder-0.10.31" = {
2520 name = "string_decoder";
2521 packageName = "string_decoder";
2522 version = "0.10.31";
2523 src = fetchurl {
2524 url = "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz";
2525 sha1 = "62e203bc41766c6c28c9fc84301dab1c5310fa94";
2526 };
2527 };
2528 "string_decoder-1.1.1" = {
2529 name = "string_decoder";
2530 packageName = "string_decoder";
2531 version = "1.1.1";
2532 src = fetchurl {
2533 url = "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz";
2534 sha512 = "n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==";
2535 };
2536 };
2537 "stringstream-0.0.6" = {
2538 name = "stringstream";
2539 packageName = "stringstream";
2540 version = "0.0.6";
2541 src = fetchurl {
2542 url = "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz";
2543 sha512 = "87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==";
2544 };
2545 };
2546 "strip-ansi-0.3.0" = {
2547 name = "strip-ansi";
2548 packageName = "strip-ansi";
2549 version = "0.3.0";
2550 src = fetchurl {
2551 url = "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz";
2552 sha1 = "25f48ea22ca79187f3174a4db8759347bb126220";
2553 };
2554 };
2555 "strip-ansi-3.0.1" = {
2556 name = "strip-ansi";
2557 packageName = "strip-ansi";
2558 version = "3.0.1";
2559 src = fetchurl {
2560 url = "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz";
2561 sha1 = "6a385fb8853d952d5ff05d0e8aaf94278dc63dcf";
2562 };
2563 };
2564 "strip-json-comments-1.0.4" = {
2565 name = "strip-json-comments";
2566 packageName = "strip-json-comments";
2567 version = "1.0.4";
2568 src = fetchurl {
2569 url = "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz";
2570 sha1 = "1e15fbcac97d3ee99bf2d73b4c656b082bbafb91";
2571 };
2572 };
2573 "supports-color-0.2.0" = {
2574 name = "supports-color";
2575 packageName = "supports-color";
2576 version = "0.2.0";
2577 src = fetchurl {
2578 url = "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz";
2579 sha1 = "d92de2694eb3f67323973d7ae3d8b55b4c22190a";
2580 };
2581 };
2582 "supports-color-2.0.0" = {
2583 name = "supports-color";
2584 packageName = "supports-color";
2585 version = "2.0.0";
2586 src = fetchurl {
2587 url = "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz";
2588 sha1 = "535d045ce6b6363fa40117084629995e9df324c7";
2589 };
2590 };
2591 "table-layout-0.3.0" = {
2592 name = "table-layout";
2593 packageName = "table-layout";
2594 version = "0.3.0";
2595 src = fetchurl {
2596 url = "https://registry.npmjs.org/table-layout/-/table-layout-0.3.0.tgz";
2597 sha1 = "6ee20dc483db371b3e5c87f704ed2f7c799d2c9a";
2598 };
2599 };
2600 "tar-3.1.15" = {
2601 name = "tar";
2602 packageName = "tar";
2603 version = "3.1.15";
2604 src = fetchurl {
2605 url = "https://registry.npmjs.org/tar/-/tar-3.1.15.tgz";
2606 sha512 = "pQNFsg+Wb6VXsrIPUnuQwrHR4wD5ASBR0jRyiT4/AALFA2Nl+CjhkDX5fTmIwCuULRtyQR3Dae2BBnP2EFHscw==";
2607 };
2608 };
2609 "temp-0.8.3" = {
2610 name = "temp";
2611 packageName = "temp";
2612 version = "0.8.3";
2613 src = fetchurl {
2614 url = "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz";
2615 sha1 = "e0c6bc4d26b903124410e4fed81103014dfc1f59";
2616 };
2617 };
2618 "test-value-2.1.0" = {
2619 name = "test-value";
2620 packageName = "test-value";
2621 version = "2.1.0";
2622 src = fetchurl {
2623 url = "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz";
2624 sha1 = "11da6ff670f3471a73b625ca4f3fdcf7bb748291";
2625 };
2626 };
2627 "throttleit-1.0.0" = {
2628 name = "throttleit";
2629 packageName = "throttleit";
2630 version = "1.0.0";
2631 src = fetchurl {
2632 url = "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz";
2633 sha1 = "9e785836daf46743145a5984b6268d828528ac6c";
2634 };
2635 };
2636 "through-2.3.8" = {
2637 name = "through";
2638 packageName = "through";
2639 version = "2.3.8";
2640 src = fetchurl {
2641 url = "https://registry.npmjs.org/through/-/through-2.3.8.tgz";
2642 sha1 = "0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5";
2643 };
2644 };
2600 2645 "tiny-emitter-2.0.2" = {
2601 2646 name = "tiny-emitter";
2602 2647 packageName = "tiny-emitter";
2603 2648 version = "2.0.2";
2604 2649 src = fetchurl {
2605 2650 url = "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz";
2606 sha1 = "82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c";
2607 };
2608 };
2609 "delegate-3.1.3" = {
2610 name = "delegate";
2611 packageName = "delegate";
2612 version = "3.1.3";
2613 src = fetchurl {
2614 url = "https://registry.npmjs.org/delegate/-/delegate-3.1.3.tgz";
2615 sha1 = "9a8251a777d7025faa55737bc3b071742127a9fd";
2651 sha512 = "2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow==";
2652 };
2653 };
2654 "tiny-lr-fork-0.0.5" = {
2655 name = "tiny-lr-fork";
2656 packageName = "tiny-lr-fork";
2657 version = "0.0.5";
2658 src = fetchurl {
2659 url = "https://registry.npmjs.org/tiny-lr-fork/-/tiny-lr-fork-0.0.5.tgz";
2660 sha1 = "1e99e1e2a8469b736ab97d97eefa98c71f76ed0a";
2661 };
2662 };
2663 "tough-cookie-2.3.4" = {
2664 name = "tough-cookie";
2665 packageName = "tough-cookie";
2666 version = "2.3.4";
2667 src = fetchurl {
2668 url = "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz";
2669 sha512 = "TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==";
2670 };
2671 };
2672 "tunnel-agent-0.6.0" = {
2673 name = "tunnel-agent";
2674 packageName = "tunnel-agent";
2675 version = "0.6.0";
2676 src = fetchurl {
2677 url = "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz";
2678 sha1 = "27a5dea06b36b04a0a9966774b290868f0fc40fd";
2679 };
2680 };
2681 "tweetnacl-0.14.5" = {
2682 name = "tweetnacl";
2683 packageName = "tweetnacl";
2684 version = "0.14.5";
2685 src = fetchurl {
2686 url = "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz";
2687 sha1 = "5ae68177f192d4456269d108afa93ff8743f4f64";
2688 };
2689 };
2690 "type-check-0.3.2" = {
2691 name = "type-check";
2692 packageName = "type-check";
2693 version = "0.3.2";
2694 src = fetchurl {
2695 url = "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz";
2696 sha1 = "5884cab512cf1d355e3fb784f30804b2b520db72";
2697 };
2698 };
2699 "typedarray-0.0.6" = {
2700 name = "typedarray";
2701 packageName = "typedarray";
2702 version = "0.0.6";
2703 src = fetchurl {
2704 url = "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz";
2705 sha1 = "867ac74e3864187b1d3d47d996a78ec5c8830777";
2706 };
2707 };
2708 "typical-2.6.1" = {
2709 name = "typical";
2710 packageName = "typical";
2711 version = "2.6.1";
2712 src = fetchurl {
2713 url = "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz";
2714 sha1 = "5c080e5d661cbbe38259d2e70a3c7253e873881d";
2715 };
2716 };
2717 "uid-number-0.0.5" = {
2718 name = "uid-number";
2719 packageName = "uid-number";
2720 version = "0.0.5";
2721 src = fetchurl {
2722 url = "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz";
2723 sha1 = "5a3db23ef5dbd55b81fce0ec9a2ac6fccdebb81e";
2724 };
2725 };
2726 "underscore-1.7.0" = {
2727 name = "underscore";
2728 packageName = "underscore";
2729 version = "1.7.0";
2730 src = fetchurl {
2731 url = "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz";
2732 sha1 = "6bbaf0877500d36be34ecaa584e0db9fef035209";
2733 };
2734 };
2735 "underscore.string-2.2.1" = {
2736 name = "underscore.string";
2737 packageName = "underscore.string";
2738 version = "2.2.1";
2739 src = fetchurl {
2740 url = "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz";
2741 sha1 = "d7c0fa2af5d5a1a67f4253daee98132e733f0f19";
2742 };
2743 };
2744 "underscore.string-2.3.3" = {
2745 name = "underscore.string";
2746 packageName = "underscore.string";
2747 version = "2.3.3";
2748 src = fetchurl {
2749 url = "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz";
2750 sha1 = "71c08bf6b428b1133f37e78fa3a21c82f7329b0d";
2751 };
2752 };
2753 "underscore.string-2.4.0" = {
2754 name = "underscore.string";
2755 packageName = "underscore.string";
2756 version = "2.4.0";
2757 src = fetchurl {
2758 url = "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz";
2759 sha1 = "8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b";
2760 };
2761 };
2762 "unicode-5.2.0-0.7.5" = {
2763 name = "unicode-5.2.0";
2764 packageName = "unicode-5.2.0";
2765 version = "0.7.5";
2766 src = fetchurl {
2767 url = "https://registry.npmjs.org/unicode-5.2.0/-/unicode-5.2.0-0.7.5.tgz";
2768 sha512 = "KVGLW1Bri30x00yv4HNM8kBxoqFXr0Sbo55735nvrlsx4PYBZol3UtoWgO492fSwmsetzPEZzy73rbU8OGXJcA==";
2769 };
2770 };
2771 "util-deprecate-1.0.2" = {
2772 name = "util-deprecate";
2773 packageName = "util-deprecate";
2774 version = "1.0.2";
2775 src = fetchurl {
2776 url = "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz";
2777 sha1 = "450d4dc9fa70de732762fbd2d4a28981419a0ccf";
2778 };
2779 };
2780 "uuid-3.3.2" = {
2781 name = "uuid";
2782 packageName = "uuid";
2783 version = "3.3.2";
2784 src = fetchurl {
2785 url = "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz";
2786 sha512 = "yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==";
2787 };
2788 };
2789 "validate-npm-package-license-3.0.3" = {
2790 name = "validate-npm-package-license";
2791 packageName = "validate-npm-package-license";
2792 version = "3.0.3";
2793 src = fetchurl {
2794 url = "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz";
2795 sha512 = "63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==";
2796 };
2797 };
2798 "validate-npm-package-name-3.0.0" = {
2799 name = "validate-npm-package-name";
2800 packageName = "validate-npm-package-name";
2801 version = "3.0.0";
2802 src = fetchurl {
2803 url = "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz";
2804 sha1 = "5fa912d81eb7d0c74afc140de7317f0ca7df437e";
2805 };
2806 };
2807 "verror-1.10.0" = {
2808 name = "verror";
2809 packageName = "verror";
2810 version = "1.10.0";
2811 src = fetchurl {
2812 url = "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz";
2813 sha1 = "3a105ca17053af55d6e270c1f8288682e18da400";
2814 };
2815 };
2816 "vulcanize-1.16.0" = {
2817 name = "vulcanize";
2818 packageName = "vulcanize";
2819 version = "1.16.0";
2820 src = fetchurl {
2821 url = "https://registry.npmjs.org/vulcanize/-/vulcanize-1.16.0.tgz";
2822 sha512 = "TYlFljSc896b5+0FmMiw0JAMrHNBiHx0IAFC/dQR3Dxdb9Nx43ohm6wMWTlPXQn4sk/0WkqfgoAA6SLxyvPCLQ==";
2823 };
2824 };
2825 "walk-2.3.14" = {
2826 name = "walk";
2827 packageName = "walk";
2828 version = "2.3.14";
2829 src = fetchurl {
2830 url = "https://registry.npmjs.org/walk/-/walk-2.3.14.tgz";
2831 sha512 = "5skcWAUmySj6hkBdH6B6+3ddMjVQYH5Qy9QGbPmN8kVmLteXk+yVXg+yfk1nbX30EYakahLrr8iPcCxJQSCBeg==";
2832 };
2833 };
2834 "which-1.0.9" = {
2835 name = "which";
2836 packageName = "which";
2837 version = "1.0.9";
2838 src = fetchurl {
2839 url = "https://registry.npmjs.org/which/-/which-1.0.9.tgz";
2840 sha1 = "460c1da0f810103d0321a9b633af9e575e64486f";
2841 };
2842 };
2843 "which-1.3.1" = {
2844 name = "which";
2845 packageName = "which";
2846 version = "1.3.1";
2847 src = fetchurl {
2848 url = "https://registry.npmjs.org/which/-/which-1.3.1.tgz";
2849 sha512 = "HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==";
2850 };
2851 };
2852 "wide-align-1.1.3" = {
2853 name = "wide-align";
2854 packageName = "wide-align";
2855 version = "1.1.3";
2856 src = fetchurl {
2857 url = "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz";
2858 sha512 = "QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==";
2859 };
2860 };
2861 "winston-2.4.3" = {
2862 name = "winston";
2863 packageName = "winston";
2864 version = "2.4.3";
2865 src = fetchurl {
2866 url = "https://registry.npmjs.org/winston/-/winston-2.4.3.tgz";
2867 sha512 = "GYKuysPz2pxYAVJD2NPsDLP5Z79SDEzPm9/j4tCjkF/n89iBNGBMJcR+dMUqxgPNgoSs6fVygPi+Vl2oxIpBuw==";
2868 };
2869 };
2870 "wordwrap-1.0.0" = {
2871 name = "wordwrap";
2872 packageName = "wordwrap";
2873 version = "1.0.0";
2874 src = fetchurl {
2875 url = "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz";
2876 sha1 = "27584810891456a4171c8d0226441ade90cbcaeb";
2877 };
2878 };
2879 "wordwrapjs-2.0.0" = {
2880 name = "wordwrapjs";
2881 packageName = "wordwrapjs";
2882 version = "2.0.0";
2883 src = fetchurl {
2884 url = "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-2.0.0.tgz";
2885 sha1 = "ab55f695e6118da93858fdd70c053d1c5e01ac20";
2886 };
2887 };
2888 "wrappy-1.0.2" = {
2889 name = "wrappy";
2890 packageName = "wrappy";
2891 version = "1.0.2";
2892 src = fetchurl {
2893 url = "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz";
2894 sha1 = "b5243d8f3ec1aa35f1364605bc0d1036e30ab69f";
2895 };
2896 };
2897 "yallist-3.0.2" = {
2898 name = "yallist";
2899 packageName = "yallist";
2900 version = "3.0.2";
2901 src = fetchurl {
2902 url = "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz";
2903 sha1 = "8452b4bb7e83c7c188d8041c1a837c773d6d8bb9";
2904 };
2905 };
2906 "yauzl-2.4.1" = {
2907 name = "yauzl";
2908 packageName = "yauzl";
2909 version = "2.4.1";
2910 src = fetchurl {
2911 url = "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz";
2912 sha1 = "9528f442dab1b2284e58b4379bb194e22e0c4005";
2616 2913 };
2617 2914 };
2618 2915 };
2619 2916 args = {
2620 2917 name = "rhodecode-enterprise";
2621 2918 packageName = "rhodecode-enterprise";
2622 version = "0.0.1";
2623 src = ./.;
2919 version = "1.0.0";
2920 src = ./..;
2624 2921 dependencies = [
2625 sources."grunt-0.4.5"
2626 sources."grunt-contrib-copy-1.0.0"
2627 (sources."grunt-contrib-concat-0.5.1" // {
2922 sources."@types/clone-0.1.30"
2923 sources."@types/node-4.2.23"
2924 (sources."@types/parse5-0.0.31" // {
2628 2925 dependencies = [
2629 sources."chalk-0.5.1"
2630 sources."ansi-styles-1.1.0"
2631 sources."has-ansi-0.1.0"
2632 sources."strip-ansi-0.3.0"
2633 sources."supports-color-0.2.0"
2634 sources."ansi-regex-0.2.1"
2926 sources."@types/node-6.0.114"
2927 ];
2928 })
2929 sources."abbrev-1.1.1"
2930 sources."acorn-3.3.0"
2931 sources."acorn-jsx-3.0.1"
2932 sources."ajv-4.11.8"
2933 sources."amdefine-1.0.1"
2934 sources."ansi-escape-sequences-3.0.0"
2935 sources."ansi-regex-2.1.1"
2936 sources."ansi-styles-2.2.1"
2937 sources."appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1"
2938 sources."aproba-1.2.0"
2939 sources."are-we-there-yet-1.1.5"
2940 (sources."argparse-0.1.16" // {
2941 dependencies = [
2942 sources."underscore.string-2.4.0"
2635 2943 ];
2636 2944 })
2637 sources."grunt-contrib-jshint-0.12.0"
2638 (sources."grunt-contrib-less-1.4.1" // {
2945 sources."array-back-1.0.4"
2946 sources."asap-2.0.6"
2947 sources."asn1-0.2.3"
2948 sources."assert-plus-0.2.0"
2949 sources."async-0.1.22"
2950 sources."asynckit-0.4.0"
2951 sources."aws-sign2-0.6.0"
2952 sources."aws4-1.7.0"
2953 sources."babel-polyfill-6.26.0"
2954 (sources."babel-runtime-6.26.0" // {
2639 2955 dependencies = [
2640 sources."async-2.5.0"
2641 sources."lodash-4.17.4"
2956 sources."regenerator-runtime-0.11.1"
2642 2957 ];
2643 2958 })
2644 (sources."grunt-contrib-watch-0.6.1" // {
2959 sources."balanced-match-1.0.0"
2960 sources."base64-js-1.2.3"
2961 sources."bcrypt-pbkdf-1.0.2"
2962 sources."boom-2.10.1"
2963 sources."bower-1.8.4"
2964 sources."brace-expansion-1.1.11"
2965 sources."buffer-from-1.1.1"
2966 sources."builtin-modules-1.1.1"
2967 sources."builtins-1.0.3"
2968 sources."caseless-0.12.0"
2969 sources."chalk-1.1.3"
2970 (sources."cli-1.0.1" // {
2645 2971 dependencies = [
2646 sources."lodash-2.4.2"
2647 sources."async-0.2.10"
2972 sources."glob-7.1.2"
2973 sources."minimatch-3.0.4"
2648 2974 ];
2649 2975 })
2976 sources."clipboard-2.0.1"
2977 sources."clone-1.0.4"
2978 sources."co-4.6.0"
2979 sources."code-point-at-1.1.0"
2980 sources."coffee-script-1.3.3"
2981 sources."colors-0.6.2"
2982 sources."combined-stream-1.0.6"
2983 sources."command-line-args-3.0.5"
2984 sources."command-line-usage-3.0.8"
2985 sources."concat-map-0.0.1"
2986 sources."concat-stream-1.6.2"
2987 sources."config-chain-1.1.11"
2988 sources."console-browserify-1.1.0"
2989 sources."console-control-strings-1.1.0"
2990 sources."core-js-2.5.7"
2991 sources."core-util-is-1.0.2"
2650 2992 sources."crisper-2.1.1"
2651 (sources."vulcanize-1.16.0" // {
2993 sources."cryptiles-2.0.5"
2994 sources."cycle-1.0.3"
2995 (sources."dashdash-1.14.1" // {
2652 2996 dependencies = [
2653 sources."nopt-3.0.6"
2997 sources."assert-plus-1.0.0"
2654 2998 ];
2655 2999 })
2656 sources."grunt-crisper-1.0.1"
2657 (sources."grunt-vulcanize-1.0.0" // {
3000 sources."date-now-0.1.4"
3001 sources."dateformat-1.0.2-1.2.3"
3002 sources."debug-0.7.4"
3003 sources."deep-extend-0.4.2"
3004 sources."deep-is-0.1.3"
3005 sources."delayed-stream-1.0.0"
3006 sources."delegate-3.2.0"
3007 sources."delegates-1.0.0"
3008 sources."doctrine-0.7.2"
3009 (sources."dom-serializer-0.1.0" // {
2658 3010 dependencies = [
2659 sources."crisper-1.2.0"
2660 sources."nopt-3.0.6"
3011 sources."domelementtype-1.1.3"
3012 sources."entities-1.1.1"
2661 3013 ];
2662 3014 })
2663 sources."node2nix-1.3.0"
2664 (sources."jshint-2.9.5" // {
3015 sources."dom5-1.3.6"
3016 sources."domelementtype-1.3.0"
3017 sources."domhandler-2.3.0"
3018 sources."domutils-1.5.1"
3019 sources."ecc-jsbn-0.1.2"
3020 sources."entities-1.0.0"
3021 sources."errno-0.1.7"
3022 sources."es6-promise-2.3.0"
3023 sources."escape-string-regexp-1.0.5"
3024 (sources."escodegen-1.11.0" // {
2665 3025 dependencies = [
2666 sources."minimatch-3.0.4"
2667 sources."lodash-3.7.0"
3026 sources."esprima-3.1.3"
3027 sources."estraverse-4.2.0"
3028 sources."esutils-2.0.2"
3029 sources."source-map-0.6.1"
3030 ];
3031 })
3032 (sources."espree-3.5.4" // {
3033 dependencies = [
3034 sources."acorn-5.7.1"
2668 3035 ];
2669 3036 })
2670 sources."bower-1.8.2"
2671 sources."jquery-1.11.3"
3037 sources."esprima-1.0.4"
3038 sources."estraverse-3.1.0"
3039 sources."esutils-1.1.6"
3040 sources."eventemitter2-0.4.14"
3041 sources."exit-0.1.2"
3042 sources."extend-3.0.2"
3043 (sources."extract-zip-1.6.7" // {
3044 dependencies = [
3045 sources."debug-2.6.9"
3046 ];
3047 })
3048 sources."extsprintf-1.3.0"
3049 sources."eyes-0.1.8"
3050 sources."fast-levenshtein-2.0.6"
2672 3051 sources."favico.js-0.3.10"
2673 sources."clipboard-1.7.1"
2674 sources."moment-2.18.1"
2675 sources."mousetrap-1.6.1"
2676 sources."appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1"
2677 sources."async-0.1.22"
2678 sources."coffee-script-1.3.3"
2679 sources."colors-0.6.2"
2680 sources."dateformat-1.0.2-1.2.3"
2681 sources."eventemitter2-0.4.14"
3052 sources."faye-websocket-0.4.4"
3053 sources."fd-slicer-1.0.1"
3054 sources."feature-detect-es6-1.5.0"
3055 sources."file-sync-cmp-0.1.1"
3056 sources."find-replace-1.0.3"
3057 sources."findit-2.0.0"
2682 3058 (sources."findup-sync-0.1.3" // {
2683 3059 dependencies = [
2684 3060 sources."glob-3.2.11"
@@ -2686,333 +3062,321 b' let'
2686 3062 sources."minimatch-0.3.0"
2687 3063 ];
2688 3064 })
3065 sources."foreachasync-3.0.0"
3066 sources."forever-agent-0.6.1"
3067 sources."form-data-2.1.4"
3068 (sources."fs-extra-0.6.4" // {
3069 dependencies = [
3070 sources."mkdirp-0.3.5"
3071 ];
3072 })
3073 (sources."fs.extra-1.3.2" // {
3074 dependencies = [
3075 sources."mkdirp-0.3.5"
3076 ];
3077 })
3078 sources."fs.realpath-1.0.0"
3079 sources."gauge-2.7.4"
3080 sources."gaze-0.5.2"
3081 sources."getobject-0.1.0"
3082 (sources."getpass-0.1.7" // {
3083 dependencies = [
3084 sources."assert-plus-1.0.0"
3085 ];
3086 })
2689 3087 (sources."glob-3.1.21" // {
2690 3088 dependencies = [
2691 3089 sources."inherits-1.0.2"
2692 3090 ];
2693 3091 })
2694 sources."hooker-0.2.3"
2695 sources."iconv-lite-0.2.11"
2696 sources."minimatch-0.2.14"
2697 sources."nopt-1.0.10"
2698 sources."rimraf-2.2.8"
2699 sources."lodash-0.9.2"
2700 sources."underscore.string-2.2.1"
2701 sources."which-1.0.9"
2702 sources."js-yaml-2.0.5"
2703 sources."exit-0.1.2"
2704 sources."getobject-0.1.0"
2705 sources."grunt-legacy-util-0.2.0"
3092 (sources."globule-0.1.0" // {
3093 dependencies = [
3094 sources."lodash-1.0.2"
3095 ];
3096 })
3097 sources."good-listener-1.2.2"
3098 sources."graceful-fs-1.2.3"
3099 sources."grunt-0.4.5"
3100 (sources."grunt-contrib-concat-0.5.1" // {
3101 dependencies = [
3102 sources."ansi-regex-0.2.1"
3103 sources."ansi-styles-1.1.0"
3104 sources."chalk-0.5.1"
3105 sources."has-ansi-0.1.0"
3106 sources."strip-ansi-0.3.0"
3107 sources."supports-color-0.2.0"
3108 ];
3109 })
3110 sources."grunt-contrib-copy-1.0.0"
3111 sources."grunt-contrib-jshint-0.12.0"
3112 (sources."grunt-contrib-less-1.4.1" // {
3113 dependencies = [
3114 sources."async-2.6.1"
3115 sources."lodash-4.17.10"
3116 ];
3117 })
3118 (sources."grunt-contrib-watch-0.6.1" // {
3119 dependencies = [
3120 sources."async-0.2.10"
3121 sources."lodash-2.4.2"
3122 ];
3123 })
3124 sources."grunt-crisper-1.0.1"
2706 3125 (sources."grunt-legacy-log-0.1.3" // {
2707 3126 dependencies = [
2708 3127 sources."lodash-2.4.2"
2709 3128 sources."underscore.string-2.3.3"
2710 3129 ];
2711 3130 })
2712 sources."inherits-2.0.3"
2713 sources."lru-cache-2.7.3"
2714 sources."sigmund-1.0.1"
2715 sources."graceful-fs-1.2.3"
2716 sources."abbrev-1.1.0"
2717 (sources."argparse-0.1.16" // {
2718 dependencies = [
2719 sources."underscore.string-2.4.0"
2720 ];
2721 })
2722 sources."esprima-1.0.4"
2723 sources."underscore-1.7.0"
2724 3131 (sources."grunt-legacy-log-utils-0.1.1" // {
2725 3132 dependencies = [
2726 3133 sources."lodash-2.4.2"
2727 3134 sources."underscore.string-2.3.3"
2728 3135 ];
2729 3136 })
2730 sources."chalk-1.1.3"
2731 sources."file-sync-cmp-0.1.1"
2732 sources."ansi-styles-2.2.1"
2733 sources."escape-string-regexp-1.0.5"
3137 sources."grunt-legacy-util-0.2.0"
3138 (sources."grunt-vulcanize-1.0.0" // {
3139 dependencies = [
3140 sources."crisper-1.2.0"
3141 sources."nopt-3.0.6"
3142 ];
3143 })
3144 sources."har-schema-1.0.5"
3145 sources."har-validator-4.2.1"
2734 3146 sources."has-ansi-2.0.0"
2735 sources."strip-ansi-3.0.1"
2736 sources."supports-color-2.0.0"
2737 sources."ansi-regex-2.1.1"
2738 sources."source-map-0.3.0"
2739 sources."amdefine-1.0.1"
2740 (sources."less-2.7.2" // {
3147 sources."has-unicode-2.0.1"
3148 sources."hasha-2.2.0"
3149 sources."hawk-3.1.3"
3150 sources."hoek-2.16.3"
3151 sources."hooker-0.2.3"
3152 sources."hosted-git-info-2.7.1"
3153 (sources."htmlparser2-3.8.3" // {
3154 dependencies = [
3155 sources."readable-stream-1.1.14"
3156 sources."string_decoder-0.10.31"
3157 ];
3158 })
3159 sources."http-signature-1.1.1"
3160 (sources."hydrolysis-1.25.0" // {
3161 dependencies = [
3162 sources."dom5-1.1.0"
3163 ];
3164 })
3165 sources."iconv-lite-0.2.11"
3166 sources."image-size-0.5.5"
3167 sources."inflight-1.0.6"
3168 sources."inherits-2.0.3"
3169 sources."ini-1.3.5"
3170 sources."is-builtin-module-1.0.0"
3171 sources."is-fullwidth-code-point-1.0.0"
3172 sources."is-stream-1.1.0"
3173 sources."is-typedarray-1.0.0"
3174 sources."isarray-0.0.1"
3175 sources."isexe-2.0.0"
3176 sources."isstream-0.1.2"
3177 sources."jquery-1.11.3"
3178 sources."js-yaml-2.0.5"
3179 sources."jsbn-0.1.1"
3180 (sources."jshint-2.9.6" // {
3181 dependencies = [
3182 sources."lodash-4.17.10"
3183 sources."minimatch-3.0.4"
3184 ];
3185 })
3186 sources."json-schema-0.2.3"
3187 sources."json-stable-stringify-1.0.1"
3188 sources."json-stringify-safe-5.0.1"
3189 sources."jsonfile-1.0.1"
3190 sources."jsonify-0.0.0"
3191 (sources."jsprim-1.4.1" // {
3192 dependencies = [
3193 sources."assert-plus-1.0.0"
3194 ];
3195 })
3196 sources."kew-0.7.0"
3197 (sources."klaw-1.3.1" // {
3198 dependencies = [
3199 sources."graceful-fs-4.1.11"
3200 ];
3201 })
3202 (sources."less-2.7.3" // {
2741 3203 dependencies = [
2742 3204 sources."graceful-fs-4.1.11"
2743 3205 sources."source-map-0.5.7"
2744 3206 ];
2745 3207 })
2746 sources."errno-0.1.4"
2747 sources."image-size-0.5.5"
2748 sources."mime-1.4.0"
2749 sources."mkdirp-0.5.1"
2750 sources."promise-7.3.1"
2751 sources."request-2.82.0"
2752 sources."prr-0.0.0"
3208 sources."levn-0.3.0"
3209 sources."lodash-0.9.2"
3210 sources."lru-cache-2.7.3"
3211 sources."mime-1.6.0"
3212 sources."mime-db-1.35.0"
3213 sources."mime-types-2.1.19"
3214 sources."minimatch-0.2.14"
2753 3215 sources."minimist-0.0.8"
2754 sources."asap-2.0.6"
2755 sources."aws-sign2-0.7.0"
2756 sources."aws4-1.6.0"
2757 sources."caseless-0.12.0"
2758 sources."combined-stream-1.0.5"
2759 sources."extend-3.0.1"
2760 sources."forever-agent-0.6.1"
2761 sources."form-data-2.3.1"
2762 sources."har-validator-5.0.3"
2763 sources."hawk-6.0.2"
2764 sources."http-signature-1.2.0"
2765 sources."is-typedarray-1.0.0"
2766 sources."isstream-0.1.2"
2767 sources."json-stringify-safe-5.0.1"
2768 sources."mime-types-2.1.17"
2769 sources."oauth-sign-0.8.2"
2770 sources."performance-now-2.1.0"
2771 sources."qs-6.5.1"
2772 sources."safe-buffer-5.1.1"
2773 sources."stringstream-0.0.5"
2774 sources."tough-cookie-2.3.3"
2775 sources."tunnel-agent-0.6.0"
2776 sources."uuid-3.1.0"
2777 sources."delayed-stream-1.0.0"
2778 sources."asynckit-0.4.0"
2779 sources."ajv-5.2.2"
2780 sources."har-schema-2.0.0"
2781 sources."co-4.6.0"
2782 sources."fast-deep-equal-1.0.0"
2783 sources."json-schema-traverse-0.3.1"
2784 sources."json-stable-stringify-1.0.1"
2785 sources."jsonify-0.0.0"
2786 sources."hoek-4.2.0"
2787 sources."boom-4.3.1"
2788 (sources."cryptiles-3.1.2" // {
2789 dependencies = [
2790 sources."boom-5.2.0"
2791 ];
2792 })
2793 sources."sntp-2.0.2"
2794 sources."assert-plus-1.0.0"
2795 sources."jsprim-1.4.1"
2796 sources."sshpk-1.13.1"
2797 sources."extsprintf-1.3.0"
2798 sources."json-schema-0.2.3"
2799 sources."verror-1.10.0"
2800 sources."core-util-is-1.0.2"
2801 sources."asn1-0.2.3"
2802 sources."dashdash-1.14.1"
2803 sources."getpass-0.1.7"
2804 sources."jsbn-0.1.1"
2805 sources."tweetnacl-0.14.5"
2806 sources."ecc-jsbn-0.1.1"
2807 sources."bcrypt-pbkdf-1.0.1"
2808 sources."mime-db-1.30.0"
2809 sources."punycode-1.4.1"
2810 sources."gaze-0.5.2"
2811 (sources."tiny-lr-fork-0.0.5" // {
2812 dependencies = [
2813 sources."qs-0.5.6"
2814 ];
2815 })
2816 (sources."globule-0.1.0" // {
2817 dependencies = [
2818 sources."lodash-1.0.2"
2819 ];
2820 })
2821 sources."faye-websocket-0.4.4"
3216 sources."minipass-2.3.3"
3217 sources."minizlib-1.1.0"
3218 sources."mkdirp-0.5.1"
3219 sources."moment-2.22.2"
3220 sources."mousetrap-1.6.2"
3221 sources."ms-2.0.0"
3222 sources."ncp-0.4.2"
3223 sources."nijs-0.0.25"
3224 sources."node2nix-1.6.0"
3225 sources."nopt-1.0.10"
2822 3226 (sources."noptify-0.0.3" // {
2823 3227 dependencies = [
2824 3228 sources."nopt-2.0.0"
2825 3229 ];
2826 3230 })
2827 sources."debug-0.7.4"
2828 sources."command-line-args-3.0.5"
2829 sources."command-line-usage-3.0.8"
2830 sources."dom5-1.3.6"
2831 sources."array-back-1.0.4"
2832 sources."feature-detect-es6-1.3.1"
2833 sources."find-replace-1.0.3"
2834 sources."typical-2.6.1"
2835 sources."test-value-2.1.0"
2836 sources."ansi-escape-sequences-3.0.0"
2837 sources."table-layout-0.3.0"
2838 sources."core-js-2.5.1"
2839 sources."deep-extend-0.4.2"
2840 sources."wordwrapjs-2.0.0"
2841 sources."reduce-flatten-1.0.1"
2842 sources."@types/clone-0.1.30"
2843 sources."@types/node-4.2.20"
2844 (sources."@types/parse5-0.0.31" // {
2845 dependencies = [
2846 sources."@types/node-6.0.88"
2847 ];
2848 })
2849 sources."clone-1.0.2"
2850 sources."parse5-1.5.1"
2851 sources."es6-promise-2.3.0"
2852 (sources."hydrolysis-1.25.0" // {
2853 dependencies = [
2854 sources."dom5-1.1.0"
2855 ];
2856 })
2857 sources."path-posix-1.0.0"
2858 sources."acorn-3.3.0"
2859 sources."babel-polyfill-6.26.0"
2860 sources."doctrine-0.7.2"
2861 (sources."escodegen-1.9.0" // {
2862 dependencies = [
2863 sources."estraverse-4.2.0"
2864 sources."esutils-2.0.2"
2865 sources."esprima-3.1.3"
2866 sources."source-map-0.5.7"
2867 ];
2868 })
2869 (sources."espree-3.5.1" // {
2870 dependencies = [
2871 sources."acorn-5.1.2"
2872 ];
2873 })
2874 sources."estraverse-3.1.0"
2875 sources."path-is-absolute-1.0.1"
2876 (sources."babel-runtime-6.26.0" // {
2877 dependencies = [
2878 sources."regenerator-runtime-0.11.0"
2879 ];
2880 })
2881 sources."regenerator-runtime-0.10.5"
2882 sources."esutils-1.1.6"
2883 sources."isarray-0.0.1"
2884 sources."optionator-0.8.2"
2885 sources."prelude-ls-1.1.2"
2886 sources."deep-is-0.1.3"
2887 sources."wordwrap-1.0.0"
2888 sources."type-check-0.3.2"
2889 sources."levn-0.3.0"
2890 sources."fast-levenshtein-2.0.6"
2891 sources."acorn-jsx-3.0.1"
2892 sources."object-assign-4.1.1"
2893 sources."optparse-1.0.5"
2894 sources."semver-5.4.1"
2895 (sources."npm-registry-client-8.4.0" // {
3231 sources."normalize-package-data-2.4.0"
3232 sources."npm-package-arg-6.1.0"
3233 (sources."npm-registry-client-8.5.1" // {
2896 3234 dependencies = [
2897 3235 sources."graceful-fs-4.1.11"
2898 3236 ];
2899 3237 })
2900 (sources."npmconf-2.1.2" // {
3238 (sources."npmconf-2.1.3" // {
2901 3239 dependencies = [
2902 3240 sources."nopt-3.0.6"
2903 3241 sources."once-1.3.3"
2904 3242 sources."semver-4.3.6"
2905 3243 ];
2906 3244 })
2907 sources."tar-3.1.15"
2908 sources."temp-0.8.3"
2909 (sources."fs.extra-1.3.2" // {
3245 sources."npmlog-4.1.2"
3246 sources."number-is-nan-1.0.1"
3247 sources."oauth-sign-0.8.2"
3248 sources."object-assign-4.1.1"
3249 sources."once-1.4.0"
3250 sources."optionator-0.8.2"
3251 sources."optparse-1.0.5"
3252 sources."os-homedir-1.0.2"
3253 sources."os-tmpdir-1.0.2"
3254 sources."osenv-0.1.5"
3255 sources."parse5-1.5.1"
3256 sources."path-is-absolute-1.0.1"
3257 sources."path-posix-1.0.0"
3258 sources."pend-1.2.0"
3259 sources."performance-now-0.2.0"
3260 sources."phantom-4.0.12"
3261 (sources."phantomjs-prebuilt-2.1.16" // {
2910 3262 dependencies = [
2911 sources."mkdirp-0.3.5"
3263 sources."es6-promise-4.2.4"
3264 sources."fs-extra-1.0.0"
3265 sources."graceful-fs-4.1.11"
3266 sources."jsonfile-2.4.0"
3267 sources."which-1.3.1"
2912 3268 ];
2913 3269 })
2914 sources."findit-2.0.0"
2915 sources."base64-js-1.2.1"
2916 sources."slasp-0.0.4"
2917 sources."nijs-0.0.23"
2918 sources."concat-stream-1.6.0"
2919 sources."normalize-package-data-2.4.0"
2920 sources."npm-package-arg-5.1.2"
2921 sources."once-1.4.0"
2922 sources."retry-0.10.1"
2923 sources."slide-1.1.6"
2924 sources."ssri-4.1.6"
2925 sources."npmlog-4.1.2"
2926 sources."typedarray-0.0.6"
2927 (sources."readable-stream-2.3.3" // {
3270 sources."pinkie-2.0.4"
3271 sources."pinkie-promise-2.0.1"
3272 sources."prelude-ls-1.1.2"
3273 sources."process-nextick-args-2.0.0"
3274 sources."progress-1.1.8"
3275 sources."promise-7.3.1"
3276 sources."proto-list-1.2.4"
3277 sources."prr-1.0.1"
3278 sources."punycode-1.4.1"
3279 sources."qrious-4.0.2"
3280 sources."qs-6.4.0"
3281 (sources."readable-stream-2.3.6" // {
2928 3282 dependencies = [
2929 3283 sources."isarray-1.0.0"
2930 3284 ];
2931 3285 })
2932 sources."process-nextick-args-1.0.7"
2933 sources."string_decoder-1.0.3"
2934 sources."util-deprecate-1.0.2"
2935 sources."hosted-git-info-2.5.0"
2936 sources."is-builtin-module-1.0.0"
2937 sources."validate-npm-package-license-3.0.1"
2938 sources."builtin-modules-1.1.1"
2939 sources."spdx-correct-1.0.2"
2940 sources."spdx-expression-parse-1.0.4"
2941 sources."spdx-license-ids-1.2.2"
2942 sources."osenv-0.1.4"
2943 sources."validate-npm-package-name-3.0.0"
2944 sources."os-homedir-1.0.2"
2945 sources."os-tmpdir-1.0.2"
2946 sources."builtins-1.0.3"
2947 sources."wrappy-1.0.2"
2948 sources."are-we-there-yet-1.1.4"
2949 sources."console-control-strings-1.1.0"
2950 sources."gauge-2.7.4"
3286 sources."reduce-flatten-1.0.1"
3287 sources."regenerator-runtime-0.10.5"
3288 sources."request-2.81.0"
3289 sources."request-progress-2.0.1"
3290 sources."retry-0.10.1"
3291 sources."rimraf-2.2.8"
3292 sources."safe-buffer-5.1.2"
3293 sources."safer-buffer-2.1.2"
3294 sources."select-1.1.2"
3295 sources."semver-5.5.0"
2951 3296 sources."set-blocking-2.0.0"
2952 sources."delegates-1.0.0"
2953 sources."aproba-1.2.0"
2954 sources."has-unicode-2.0.1"
3297 sources."shelljs-0.3.0"
3298 sources."sigmund-1.0.1"
2955 3299 sources."signal-exit-3.0.2"
2956 sources."string-width-1.0.2"
2957 sources."wide-align-1.1.2"
2958 sources."code-point-at-1.1.0"
2959 sources."is-fullwidth-code-point-1.0.0"
2960 sources."number-is-nan-1.0.1"
2961 sources."config-chain-1.1.11"
2962 sources."ini-1.3.4"
2963 sources."uid-number-0.0.5"
2964 sources."proto-list-1.2.4"
2965 sources."minipass-2.2.1"
2966 sources."minizlib-1.0.3"
2967 sources."yallist-3.0.2"
2968 (sources."fs-extra-0.6.4" // {
3300 sources."slasp-0.0.4"
3301 sources."slide-1.1.6"
3302 sources."sntp-1.0.9"
3303 sources."source-map-0.3.0"
3304 sources."spdx-correct-3.0.0"
3305 sources."spdx-exceptions-2.1.0"
3306 sources."spdx-expression-parse-3.0.0"
3307 sources."spdx-license-ids-3.0.0"
3308 sources."split-1.0.1"
3309 (sources."sshpk-1.14.2" // {
2969 3310 dependencies = [
2970 sources."mkdirp-0.3.5"
3311 sources."assert-plus-1.0.0"
2971 3312 ];
2972 3313 })
2973 sources."walk-2.3.9"
2974 sources."ncp-0.4.2"
2975 sources."jsonfile-1.0.1"
2976 sources."foreachasync-3.0.0"
2977 (sources."cli-1.0.1" // {
3314 sources."ssri-5.3.0"
3315 sources."stack-trace-0.0.10"
3316 sources."string-width-1.0.2"
3317 sources."string_decoder-1.1.1"
3318 sources."stringstream-0.0.6"
3319 sources."strip-ansi-3.0.1"
3320 sources."strip-json-comments-1.0.4"
3321 sources."supports-color-2.0.0"
3322 sources."table-layout-0.3.0"
3323 sources."tar-3.1.15"
3324 sources."temp-0.8.3"
3325 sources."test-value-2.1.0"
3326 sources."throttleit-1.0.0"
3327 sources."through-2.3.8"
3328 sources."tiny-emitter-2.0.2"
3329 (sources."tiny-lr-fork-0.0.5" // {
2978 3330 dependencies = [
2979 sources."glob-7.1.2"
2980 sources."minimatch-3.0.4"
2981 ];
2982 })
2983 sources."console-browserify-1.1.0"
2984 (sources."htmlparser2-3.8.3" // {
2985 dependencies = [
2986 sources."readable-stream-1.1.14"
2987 sources."string_decoder-0.10.31"
3331 sources."qs-0.5.6"
2988 3332 ];
2989 3333 })
2990 sources."shelljs-0.3.0"
2991 sources."strip-json-comments-1.0.4"
2992 sources."fs.realpath-1.0.0"
2993 sources."inflight-1.0.6"
2994 sources."brace-expansion-1.1.8"
2995 sources."balanced-match-1.0.0"
2996 sources."concat-map-0.0.1"
2997 sources."date-now-0.1.4"
2998 sources."domhandler-2.3.0"
2999 sources."domutils-1.5.1"
3000 sources."domelementtype-1.3.0"
3001 sources."entities-1.0.0"
3002 (sources."dom-serializer-0.1.0" // {
3334 sources."tough-cookie-2.3.4"
3335 sources."tunnel-agent-0.6.0"
3336 sources."tweetnacl-0.14.5"
3337 sources."type-check-0.3.2"
3338 sources."typedarray-0.0.6"
3339 sources."typical-2.6.1"
3340 sources."uid-number-0.0.5"
3341 sources."underscore-1.7.0"
3342 sources."underscore.string-2.2.1"
3343 sources."unicode-5.2.0-0.7.5"
3344 sources."util-deprecate-1.0.2"
3345 sources."uuid-3.3.2"
3346 sources."validate-npm-package-license-3.0.3"
3347 sources."validate-npm-package-name-3.0.0"
3348 (sources."verror-1.10.0" // {
3003 3349 dependencies = [
3004 sources."domelementtype-1.1.3"
3005 sources."entities-1.1.1"
3350 sources."assert-plus-1.0.0"
3006 3351 ];
3007 3352 })
3008 sources."good-listener-1.2.2"
3009 sources."select-1.1.2"
3010 sources."tiny-emitter-2.0.2"
3011 sources."delegate-3.1.3"
3353 (sources."vulcanize-1.16.0" // {
3354 dependencies = [
3355 sources."nopt-3.0.6"
3356 ];
3357 })
3358 sources."walk-2.3.14"
3359 sources."which-1.0.9"
3360 sources."wide-align-1.1.3"
3361 (sources."winston-2.4.3" // {
3362 dependencies = [
3363 sources."async-1.0.0"
3364 sources."colors-1.0.3"
3365 ];
3366 })
3367 sources."wordwrap-1.0.0"
3368 sources."wordwrapjs-2.0.0"
3369 sources."wrappy-1.0.2"
3370 sources."yallist-3.0.2"
3371 sources."yauzl-2.4.1"
3012 3372 ];
3373 buildInputs = globalBuildInputs;
3013 3374 meta = {
3375 description = "RhodeCode JS packaged";
3376 license = "SEE LICENSE IN LICENSE.txt";
3014 3377 };
3015 3378 production = false;
3379 bypassCache = false;
3016 3380 };
3017 3381 in
3018 3382 {
1 NO CONTENT: file renamed from pkgs/patch-beaker-lock-func-debug.diff to pkgs/patch_beaker/patch-beaker-lock-func-debug.diff
@@ -4,10 +4,13 b''
4 4 # python-packages.nix. The main objective is to add needed dependencies of C
5 5 # libraries and tweak the build instructions where needed.
6 6
7 { pkgs, basePythonPackages }:
7 { pkgs
8 , basePythonPackages
9 }:
8 10
9 11 let
10 12 sed = "sed -i";
13
11 14 localLicenses = {
12 15 repoze = {
13 16 fullName = "Repoze License";
@@ -19,32 +22,41 b' in'
19 22
20 23 self: super: {
21 24
22 appenlight-client = super.appenlight-client.override (attrs: {
25 "appenlight-client" = super."appenlight-client".override (attrs: {
23 26 meta = {
24 27 license = [ pkgs.lib.licenses.bsdOriginal ];
25 28 };
26 29 });
27 30
28 Beaker = super.Beaker.override (attrs: {
31 "beaker" = super."beaker".override (attrs: {
29 32 patches = [
30 ./patch-beaker-lock-func-debug.diff
33 ./patch_beaker/patch-beaker-lock-func-debug.diff
34 ./patch_beaker/patch-beaker-metadata-reuse.diff
31 35 ];
32 36 });
33 37
34 future = super.future.override (attrs: {
38 "gevent" = super."gevent".override (attrs: {
39 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
40 # NOTE: (marcink) odd requirements from gevent aren't set properly,
41 # thus we need to inject psutil manually
42 self."psutil"
43 ];
44 });
45
46 "future" = super."future".override (attrs: {
35 47 meta = {
36 48 license = [ pkgs.lib.licenses.mit ];
37 49 };
38 50 });
39 51
40 testpath = super.testpath.override (attrs: {
52 "testpath" = super."testpath".override (attrs: {
41 53 meta = {
42 54 license = [ pkgs.lib.licenses.mit ];
43 55 };
44 56 });
45 57
46 gnureadline = super.gnureadline.override (attrs: {
47 buildInputs = attrs.buildInputs ++ [
58 "gnureadline" = super."gnureadline".override (attrs: {
59 buildInputs = [
48 60 pkgs.ncurses
49 61 ];
50 62 patchPhase = ''
@@ -52,56 +64,50 b' self: super: {'
52 64 '';
53 65 });
54 66
55 gunicorn = super.gunicorn.override (attrs: {
56 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
67 "gunicorn" = super."gunicorn".override (attrs: {
68 propagatedBuildInputs = [
57 69 # johbo: futures is needed as long as we are on Python 2, otherwise
58 70 # gunicorn explodes if used with multiple threads per worker.
59 self.futures
71 self."futures"
60 72 ];
61 73 });
62 74
63 nbconvert = super.nbconvert.override (attrs: {
75 "nbconvert" = super."nbconvert".override (attrs: {
64 76 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
65 77 # marcink: plug in jupyter-client for notebook rendering
66 self.jupyter-client
78 self."jupyter-client"
67 79 ];
68 80 });
69 81
70 ipython = super.ipython.override (attrs: {
82 "ipython" = super."ipython".override (attrs: {
71 83 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
72 self.gnureadline
84 self."gnureadline"
73 85 ];
74 86 });
75 87
76 lxml = super.lxml.override (attrs: {
77 # johbo: On 16.09 we need this to compile on darwin, otherwise compilation
78 # fails on Darwin.
79 hardeningDisable = if pkgs.stdenv.isDarwin then [ "format" ] else null;
80 buildInputs = with self; [
88 "lxml" = super."lxml".override (attrs: {
89 buildInputs = [
81 90 pkgs.libxml2
82 91 pkgs.libxslt
83 92 ];
93 propagatedBuildInputs = [
94 # Needed, so that "setup.py bdist_wheel" does work
95 self."wheel"
96 ];
84 97 });
85 98
86 MySQL-python = super.MySQL-python.override (attrs: {
87 buildInputs = attrs.buildInputs ++ [
99 "mysql-python" = super."mysql-python".override (attrs: {
100 buildInputs = [
88 101 pkgs.openssl
89 102 ];
90 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
103 propagatedBuildInputs = [
91 104 pkgs.libmysql
92 105 pkgs.zlib
93 106 ];
94 107 });
95 108
96 psutil = super.psutil.override (attrs: {
97 buildInputs = attrs.buildInputs ++
98 pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.darwin.IOKit;
99 });
100
101 psycopg2 = super.psycopg2.override (attrs: {
102 buildInputs = attrs.buildInputs ++
103 pkgs.lib.optional pkgs.stdenv.isDarwin pkgs.openssl;
104 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
109 "psycopg2" = super."psycopg2".override (attrs: {
110 propagatedBuildInputs = [
105 111 pkgs.postgresql
106 112 ];
107 113 meta = {
@@ -109,8 +115,8 b' self: super: {'
109 115 };
110 116 });
111 117
112 pycurl = super.pycurl.override (attrs: {
113 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
118 "pycurl" = super."pycurl".override (attrs: {
119 propagatedBuildInputs = [
114 120 pkgs.curl
115 121 pkgs.openssl
116 122 ];
@@ -119,30 +125,23 b' self: super: {'
119 125 export PYCURL_SSL_LIBRARY=openssl
120 126 '';
121 127 meta = {
122 # TODO: It is LGPL and MIT
123 128 license = pkgs.lib.licenses.mit;
124 129 };
125 130 });
126 131
127 pyramid = super.pyramid.override (attrs: {
128 postFixup = ''
129 wrapPythonPrograms
130 # TODO: johbo: "wrapPython" adds this magic line which
131 # confuses pserve.
132 ${sed} '/import sys; sys.argv/d' $out/bin/.pserve-wrapped
133 '';
132 "pyramid" = super."pyramid".override (attrs: {
134 133 meta = {
135 134 license = localLicenses.repoze;
136 135 };
137 136 });
138 137
139 pyramid-debugtoolbar = super.pyramid-debugtoolbar.override (attrs: {
138 "pyramid-debugtoolbar" = super."pyramid-debugtoolbar".override (attrs: {
140 139 meta = {
141 140 license = [ pkgs.lib.licenses.bsdOriginal localLicenses.repoze ];
142 141 };
143 142 });
144 143
145 pysqlite = super.pysqlite.override (attrs: {
144 "pysqlite" = super."pysqlite".override (attrs: {
146 145 propagatedBuildInputs = [
147 146 pkgs.sqlite
148 147 ];
@@ -151,41 +150,39 b' self: super: {'
151 150 };
152 151 });
153 152
154 pytest-runner = super.pytest-runner.override (attrs: {
153 "pytest-runner" = super."pytest-runner".override (attrs: {
155 154 propagatedBuildInputs = [
156 self.setuptools-scm
155 self."setuptools-scm"
156 ];
157 });
158
159 "python-ldap" = super."python-ldap".override (attrs: {
160 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
161 pkgs.openldap
162 pkgs.cyrus_sasl
163 pkgs.openssl
157 164 ];
158 165 });
159 166
160 python-ldap = super.python-ldap.override (attrs: {
161 propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
162 pkgs.cyrus_sasl
163 pkgs.openldap
164 pkgs.openssl
167 "python-pam" = super."python-pam".override (attrs: {
168 propagatedBuildInputs = [
169 pkgs.pam
165 170 ];
166 # TODO: johbo: Remove the "or" once we drop 16.03 support.
167 NIX_CFLAGS_COMPILE = "-I${pkgs.cyrus_sasl.dev or pkgs.cyrus_sasl}/include/sasl";
171 # TODO: johbo: Check if this can be avoided, or transform into
172 # a real patch
173 patchPhase = ''
174 substituteInPlace pam.py \
175 --replace 'find_library("pam")' '"${pkgs.pam}/lib/libpam.so.0"'
176 '';
177 });
178
179 "pyzmq" = super."pyzmq".override (attrs: {
180 buildInputs = [
181 pkgs.czmq
182 ];
168 183 });
169 184
170 python-pam = super.python-pam.override (attrs:
171 let
172 includeLibPam = pkgs.stdenv.isLinux;
173 in {
174 # TODO: johbo: Move the option up into the default.nix, we should
175 # include python-pam only on supported platforms.
176 propagatedBuildInputs = attrs.propagatedBuildInputs ++
177 pkgs.lib.optional includeLibPam [
178 pkgs.pam
179 ];
180 # TODO: johbo: Check if this can be avoided, or transform into
181 # a real patch
182 patchPhase = pkgs.lib.optionals includeLibPam ''
183 substituteInPlace pam.py \
184 --replace 'find_library("pam")' '"${pkgs.pam}/lib/libpam.so.0"'
185 '';
186 });
187
188 URLObject = super.URLObject.override (attrs: {
185 "urlobject" = super."urlobject".override (attrs: {
189 186 meta = {
190 187 license = {
191 188 spdxId = "Unlicense";
@@ -195,56 +192,56 b' self: super: {'
195 192 };
196 193 });
197 194
198 docutils = super.docutils.override (attrs: {
195 "docutils" = super."docutils".override (attrs: {
199 196 meta = {
200 197 license = pkgs.lib.licenses.bsd2;
201 198 };
202 199 });
203 200
204 colander = super.colander.override (attrs: {
201 "colander" = super."colander".override (attrs: {
205 202 meta = {
206 203 license = localLicenses.repoze;
207 204 };
208 205 });
209 206
210 pyramid-beaker = super.pyramid-beaker.override (attrs: {
207 "pyramid-beaker" = super."pyramid-beaker".override (attrs: {
211 208 meta = {
212 209 license = localLicenses.repoze;
213 210 };
214 211 });
215 212
216 pyramid-mako = super.pyramid-mako.override (attrs: {
213 "pyramid-mako" = super."pyramid-mako".override (attrs: {
217 214 meta = {
218 215 license = localLicenses.repoze;
219 216 };
220 217 });
221 218
222 repoze.lru = super.repoze.lru.override (attrs: {
219 "repoze.lru" = super."repoze.lru".override (attrs: {
223 220 meta = {
224 221 license = localLicenses.repoze;
225 222 };
226 223 });
227 224
228 python-editor = super.python-editor.override (attrs: {
225 "python-editor" = super."python-editor".override (attrs: {
229 226 meta = {
230 227 license = pkgs.lib.licenses.asl20;
231 228 };
232 229 });
233 230
234 translationstring = super.translationstring.override (attrs: {
231 "translationstring" = super."translationstring".override (attrs: {
235 232 meta = {
236 233 license = localLicenses.repoze;
237 234 };
238 235 });
239 236
240 venusian = super.venusian.override (attrs: {
237 "venusian" = super."venusian".override (attrs: {
241 238 meta = {
242 239 license = localLicenses.repoze;
243 240 };
244 241 });
245 242
246 # Avoid that setuptools is replaced, this leads to trouble
247 # with buildPythonPackage.
248 setuptools = basePythonPackages.setuptools;
243 # Avoid that base packages screw up the build process
244 inherit (basePythonPackages)
245 setuptools;
249 246
250 247 }
This diff has been collapsed as it changes many lines, (2866 lines changed) Show them Hide them
@@ -1,2082 +1,2276 b''
1 # Generated by pip2nix 0.4.0
1 # Generated by pip2nix 0.8.0.dev1
2 2 # See https://github.com/johbo/pip2nix
3 3
4 {
5 Babel = super.buildPythonPackage {
6 name = "Babel-1.3";
7 buildInputs = with self; [];
8 doCheck = false;
9 propagatedBuildInputs = with self; [pytz];
10 src = fetchurl {
11 url = "https://pypi.python.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz";
12 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
13 };
14 meta = {
15 license = [ pkgs.lib.licenses.bsdOriginal ];
16 };
17 };
18 Beaker = super.buildPythonPackage {
19 name = "Beaker-1.9.1";
20 buildInputs = with self; [];
4 { pkgs, fetchurl, fetchgit, fetchhg }:
5
6 self: super: {
7 "alembic" = super.buildPythonPackage {
8 name = "alembic-0.9.9";
21 9 doCheck = false;
22 propagatedBuildInputs = with self; [funcsigs];
10 propagatedBuildInputs = [
11 self."sqlalchemy"
12 self."mako"
13 self."python-editor"
14 self."python-dateutil"
15 ];
23 16 src = fetchurl {
24 url = "https://pypi.python.org/packages/ca/14/a626188d0d0c7b55dd7cf1902046c2743bd392a7078bb53073e13280eb1e/Beaker-1.9.1.tar.gz";
25 md5 = "46fda0a164e2b0d24ccbda51a2310301";
26 };
27 meta = {
28 license = [ pkgs.lib.licenses.bsdOriginal ];
29 };
30 };
31 CProfileV = super.buildPythonPackage {
32 name = "CProfileV-1.0.7";
33 buildInputs = with self; [];
34 doCheck = false;
35 propagatedBuildInputs = with self; [bottle];
36 src = fetchurl {
37 url = "https://pypi.python.org/packages/df/50/d8c1ada7d537c64b0f76453fa31dedb6af6e27b82fcf0331e5f71a4cf98b/CProfileV-1.0.7.tar.gz";
38 md5 = "db4c7640438aa3d8887e194c81c7a019";
17 url = "https://files.pythonhosted.org/packages/89/03/756d5b8e1c90bf283c3f435766aa3f20208d1c3887579dd8f2122e01d5f4/alembic-0.9.9.tar.gz";
18 sha256 = "0bmkq6isjbmy4p7nxfvfpknjsx7rb3xn9g00169y891hcfkkxgc5";
39 19 };
40 20 meta = {
41 21 license = [ pkgs.lib.licenses.mit ];
42 22 };
43 23 };
44 Chameleon = super.buildPythonPackage {
45 name = "Chameleon-2.24";
46 buildInputs = with self; [];
47 doCheck = false;
48 propagatedBuildInputs = with self; [];
49 src = fetchurl {
50 url = "https://pypi.python.org/packages/5a/9e/637379ffa13c5172b5c0e704833ffea6bf51cec7567f93fd6e903d53ed74/Chameleon-2.24.tar.gz";
51 md5 = "1b01f1f6533a8a11d0d2f2366dec5342";
52 };
53 meta = {
54 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
55 };
56 };
57 FormEncode = super.buildPythonPackage {
58 name = "FormEncode-1.2.4";
59 buildInputs = with self; [];
24 "amqp" = super.buildPythonPackage {
25 name = "amqp-2.3.1";
60 26 doCheck = false;
61 propagatedBuildInputs = with self; [];
27 propagatedBuildInputs = [
28 self."vine"
29 ];
62 30 src = fetchurl {
63 url = "https://pypi.python.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz";
64 md5 = "6bc17fb9aed8aea198975e888e2077f4";
65 };
66 meta = {
67 license = [ pkgs.lib.licenses.psfl ];
68 };
69 };
70 Jinja2 = super.buildPythonPackage {
71 name = "Jinja2-2.9.6";
72 buildInputs = with self; [];
73 doCheck = false;
74 propagatedBuildInputs = with self; [MarkupSafe];
75 src = fetchurl {
76 url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
77 md5 = "6411537324b4dba0956aaa8109f3c77b";
31 url = "https://files.pythonhosted.org/packages/1b/32/242ff76cd802766f11c89c72f3389b5c8de4bdfbab406137b90c5fae8b05/amqp-2.3.1.tar.gz";
32 sha256 = "0wlfnvhmfrn7c8qif2jyvsm63ibdxp02ss564qwrvqfhz0di72s0";
78 33 };
79 34 meta = {
80 35 license = [ pkgs.lib.licenses.bsdOriginal ];
81 36 };
82 37 };
83 Mako = super.buildPythonPackage {
84 name = "Mako-1.0.7";
85 buildInputs = with self; [];
86 doCheck = false;
87 propagatedBuildInputs = with self; [MarkupSafe];
88 src = fetchurl {
89 url = "https://pypi.python.org/packages/eb/f3/67579bb486517c0d49547f9697e36582cd19dafb5df9e687ed8e22de57fa/Mako-1.0.7.tar.gz";
90 md5 = "5836cc997b1b773ef389bf6629c30e65";
91 };
92 meta = {
93 license = [ pkgs.lib.licenses.mit ];
94 };
95 };
96 Markdown = super.buildPythonPackage {
97 name = "Markdown-2.6.11";
98 buildInputs = with self; [];
38 "appenlight-client" = super.buildPythonPackage {
39 name = "appenlight-client-0.6.25";
99 40 doCheck = false;
100 propagatedBuildInputs = with self; [];
41 propagatedBuildInputs = [
42 self."webob"
43 self."requests"
44 self."six"
45 ];
101 46 src = fetchurl {
102 url = "https://pypi.python.org/packages/b3/73/fc5c850f44af5889192dff783b7b0d8f3fe8d30b65c8e3f78f8f0265fecf/Markdown-2.6.11.tar.gz";
103 md5 = "a67c1b2914f7d74eeede2ebe0fdae470";
104 };
105 meta = {
106 license = [ pkgs.lib.licenses.bsdOriginal ];
107 };
108 };
109 MarkupSafe = super.buildPythonPackage {
110 name = "MarkupSafe-1.0";
111 buildInputs = with self; [];
112 doCheck = false;
113 propagatedBuildInputs = with self; [];
114 src = fetchurl {
115 url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
116 md5 = "2fcedc9284d50e577b5192e8e3578355";
47 url = "https://files.pythonhosted.org/packages/fa/44/2911ef85ea4f4fe65058fd22959d8dad598fab6a3c84e5bcb569d15c8783/appenlight_client-0.6.25.tar.gz";
48 sha256 = "1r9l2rfg677nxhamdbyb9y4fs1zgy2dy1p19c68fnvqkxz40y627";
117 49 };
118 50 meta = {
119 51 license = [ pkgs.lib.licenses.bsdOriginal ];
120 52 };
121 53 };
122 MySQL-python = super.buildPythonPackage {
123 name = "MySQL-python-1.2.5";
124 buildInputs = with self; [];
54 "atomicwrites" = super.buildPythonPackage {
55 name = "atomicwrites-1.1.5";
125 56 doCheck = false;
126 propagatedBuildInputs = with self; [];
127 57 src = fetchurl {
128 url = "https://pypi.python.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip";
129 md5 = "654f75b302db6ed8dc5a898c625e030c";
58 url = "https://files.pythonhosted.org/packages/a1/e1/2d9bc76838e6e6667fde5814aa25d7feb93d6fa471bf6816daac2596e8b2/atomicwrites-1.1.5.tar.gz";
59 sha256 = "11bm90fwm2avvf4f3ib8g925w7jr4m11vcsinn1bi6ns4bm32214";
130 60 };
131 61 meta = {
132 license = [ pkgs.lib.licenses.gpl1 ];
62 license = [ pkgs.lib.licenses.mit ];
133 63 };
134 64 };
135 Paste = super.buildPythonPackage {
136 name = "Paste-2.0.3";
137 buildInputs = with self; [];
65 "attrs" = super.buildPythonPackage {
66 name = "attrs-18.1.0";
138 67 doCheck = false;
139 propagatedBuildInputs = with self; [six];
140 68 src = fetchurl {
141 url = "https://pypi.python.org/packages/30/c3/5c2f7c7a02e4f58d4454353fa1c32c94f79fa4e36d07a67c0ac295ea369e/Paste-2.0.3.tar.gz";
142 md5 = "1231e14eae62fa7ed76e9130b04bc61e";
69 url = "https://files.pythonhosted.org/packages/e4/ac/a04671e118b57bee87dabca1e0f2d3bda816b7a551036012d0ca24190e71/attrs-18.1.0.tar.gz";
70 sha256 = "0yzqz8wv3w1srav5683a55v49i0szkm47dyrnkd56fqs8j8ypl70";
143 71 };
144 72 meta = {
145 73 license = [ pkgs.lib.licenses.mit ];
146 74 };
147 75 };
148 PasteDeploy = super.buildPythonPackage {
149 name = "PasteDeploy-1.5.2";
150 buildInputs = with self; [];
76 "authomatic" = super.buildPythonPackage {
77 name = "authomatic-0.1.0.post1";
151 78 doCheck = false;
152 propagatedBuildInputs = with self; [];
153 79 src = fetchurl {
154 url = "https://pypi.python.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz";
155 md5 = "352b7205c78c8de4987578d19431af3b";
80 url = "https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801";
81 sha256 = "1cgk0a86sbsjbri06gf5z5l4npwkjdxw6fdnwl4vvfmxs2sx9yxw";
156 82 };
157 83 meta = {
158 84 license = [ pkgs.lib.licenses.mit ];
159 85 };
160 86 };
161 PasteScript = super.buildPythonPackage {
162 name = "PasteScript-2.0.2";
163 buildInputs = with self; [];
87 "babel" = super.buildPythonPackage {
88 name = "babel-1.3";
164 89 doCheck = false;
165 propagatedBuildInputs = with self; [Paste PasteDeploy six];
90 propagatedBuildInputs = [
91 self."pytz"
92 ];
166 93 src = fetchurl {
167 url = "https://pypi.python.org/packages/e5/f0/78e766c3dcc61a4f3a6f71dd8c95168ae9c7a31722b5663d19c1fdf62cb6/PasteScript-2.0.2.tar.gz";
168 md5 = "ccb3045445097192ca71a13b746c77b2";
94 url = "https://files.pythonhosted.org/packages/33/27/e3978243a03a76398c384c83f7ca879bc6e8f1511233a621fcada135606e/Babel-1.3.tar.gz";
95 sha256 = "0bnin777lc53nxd1hp3apq410jj5wx92n08h7h4izpl4f4sx00lz";
96 };
97 meta = {
98 license = [ pkgs.lib.licenses.bsdOriginal ];
99 };
100 };
101 "backports.shutil-get-terminal-size" = super.buildPythonPackage {
102 name = "backports.shutil-get-terminal-size-1.0.0";
103 doCheck = false;
104 src = fetchurl {
105 url = "https://files.pythonhosted.org/packages/ec/9c/368086faa9c016efce5da3e0e13ba392c9db79e3ab740b763fe28620b18b/backports.shutil_get_terminal_size-1.0.0.tar.gz";
106 sha256 = "107cmn7g3jnbkp826zlj8rrj19fam301qvaqf0f3905f5217lgki";
169 107 };
170 108 meta = {
171 109 license = [ pkgs.lib.licenses.mit ];
172 110 };
173 111 };
174 Pygments = super.buildPythonPackage {
175 name = "Pygments-2.2.0";
176 buildInputs = with self; [];
112 "beaker" = super.buildPythonPackage {
113 name = "beaker-1.9.1";
177 114 doCheck = false;
178 propagatedBuildInputs = with self; [];
115 propagatedBuildInputs = [
116 self."funcsigs"
117 ];
179 118 src = fetchurl {
180 url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
181 md5 = "13037baca42f16917cbd5ad2fab50844";
119 url = "https://files.pythonhosted.org/packages/ca/14/a626188d0d0c7b55dd7cf1902046c2743bd392a7078bb53073e13280eb1e/Beaker-1.9.1.tar.gz";
120 sha256 = "08arsn61r255lhz6hcpn2lsiqpg30clla805ysx06wmbhvb6w9rj";
182 121 };
183 122 meta = {
184 123 license = [ pkgs.lib.licenses.bsdOriginal ];
185 124 };
186 125 };
187 Routes = super.buildPythonPackage {
188 name = "Routes-2.4.1";
189 buildInputs = with self; [];
126 "beautifulsoup4" = super.buildPythonPackage {
127 name = "beautifulsoup4-4.6.3";
190 128 doCheck = false;
191 propagatedBuildInputs = with self; [six repoze.lru];
192 129 src = fetchurl {
193 url = "https://pypi.python.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz";
194 md5 = "c058dff6832941dec47e0d0052548ad8";
130 url = "https://files.pythonhosted.org/packages/88/df/86bffad6309f74f3ff85ea69344a078fc30003270c8df6894fca7a3c72ff/beautifulsoup4-4.6.3.tar.gz";
131 sha256 = "041dhalzjciw6qyzzq7a2k4h1yvyk76xigp35hv5ibnn448ydy4h";
195 132 };
196 133 meta = {
197 134 license = [ pkgs.lib.licenses.mit ];
198 135 };
199 136 };
200 SQLAlchemy = super.buildPythonPackage {
201 name = "SQLAlchemy-1.1.15";
202 buildInputs = with self; [];
137 "billiard" = super.buildPythonPackage {
138 name = "billiard-3.5.0.3";
139 doCheck = false;
140 src = fetchurl {
141 url = "https://files.pythonhosted.org/packages/39/ac/f5571210cca2e4f4532e38aaff242f26c8654c5e2436bee966c230647ccc/billiard-3.5.0.3.tar.gz";
142 sha256 = "1riwiiwgb141151md4ykx49qrz749akj5k8g290ji9bsqjyj4yqx";
143 };
144 meta = {
145 license = [ pkgs.lib.licenses.bsdOriginal ];
146 };
147 };
148 "bleach" = super.buildPythonPackage {
149 name = "bleach-2.1.4";
203 150 doCheck = false;
204 propagatedBuildInputs = with self; [];
151 propagatedBuildInputs = [
152 self."six"
153 self."html5lib"
154 ];
205 155 src = fetchurl {
206 url = "https://pypi.python.org/packages/c2/f6/11fcc1ce19a7cb81b1c9377f4e27ce3813265611922e355905e57c44d164/SQLAlchemy-1.1.15.tar.gz";
207 md5 = "077f9bd3339957f53068b5572a152674";
156 url = "https://files.pythonhosted.org/packages/7a/b7/fa555afb61462b030abaf9ed1479b8ea031510f58c7706b06113be9f82ea/bleach-2.1.4.tar.gz";
157 sha256 = "1n337zbdml6z6zia0b1qgv6xiddx3qlwmcg9vk2mk60jcxhmzs8f";
158 };
159 meta = {
160 license = [ pkgs.lib.licenses.asl20 ];
161 };
162 };
163 "bottle" = super.buildPythonPackage {
164 name = "bottle-0.12.13";
165 doCheck = false;
166 src = fetchurl {
167 url = "https://files.pythonhosted.org/packages/bd/99/04dc59ced52a8261ee0f965a8968717a255ea84a36013e527944dbf3468c/bottle-0.12.13.tar.gz";
168 sha256 = "0m9k2a7yxvggc4kw8fsvj381vgsvfcdshg5nzy6vwrxiw2p53drr";
208 169 };
209 170 meta = {
210 171 license = [ pkgs.lib.licenses.mit ];
211 172 };
212 173 };
213 Tempita = super.buildPythonPackage {
214 name = "Tempita-0.5.2";
215 buildInputs = with self; [];
216 doCheck = false;
217 propagatedBuildInputs = with self; [];
218 src = fetchurl {
219 url = "https://pypi.python.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz";
220 md5 = "4c2f17bb9d481821c41b6fbee904cea1";
221 };
222 meta = {
223 license = [ pkgs.lib.licenses.mit ];
224 };
225 };
226 URLObject = super.buildPythonPackage {
227 name = "URLObject-2.4.0";
228 buildInputs = with self; [];
174 "bumpversion" = super.buildPythonPackage {
175 name = "bumpversion-0.5.3";
229 176 doCheck = false;
230 propagatedBuildInputs = with self; [];
231 177 src = fetchurl {
232 url = "https://pypi.python.org/packages/cb/b6/e25e58500f9caef85d664bec71ec67c116897bfebf8622c32cb75d1ca199/URLObject-2.4.0.tar.gz";
233 md5 = "2ed819738a9f0a3051f31dc9924e3065";
234 };
235 meta = {
236 license = [ ];
237 };
238 };
239 WebError = super.buildPythonPackage {
240 name = "WebError-0.10.3";
241 buildInputs = with self; [];
242 doCheck = false;
243 propagatedBuildInputs = with self; [WebOb Tempita Pygments Paste];
244 src = fetchurl {
245 url = "https://pypi.python.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz";
246 md5 = "84b9990b0baae6fd440b1e60cdd06f9a";
178 url = "https://files.pythonhosted.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz";
179 sha256 = "0zn7694yfipxg35ikkfh7kvgl2fissha3dnqad2c5bvsvmrwhi37";
247 180 };
248 181 meta = {
249 182 license = [ pkgs.lib.licenses.mit ];
250 183 };
251 184 };
252 WebHelpers = super.buildPythonPackage {
253 name = "WebHelpers-1.3";
254 buildInputs = with self; [];
185 "celery" = super.buildPythonPackage {
186 name = "celery-4.1.1";
187 doCheck = false;
188 propagatedBuildInputs = [
189 self."pytz"
190 self."billiard"
191 self."kombu"
192 ];
193 src = fetchurl {
194 url = "https://files.pythonhosted.org/packages/e9/cf/a4c0597effca20c57eb586324e41d1180bc8f13a933da41e0646cff69f02/celery-4.1.1.tar.gz";
195 sha256 = "1xbir4vw42n2ir9lanhwl7w69zpmj7lbi66fxm2b7pyvkcss7wni";
196 };
197 meta = {
198 license = [ pkgs.lib.licenses.bsdOriginal ];
199 };
200 };
201 "chameleon" = super.buildPythonPackage {
202 name = "chameleon-2.24";
255 203 doCheck = false;
256 propagatedBuildInputs = with self; [MarkupSafe];
257 204 src = fetchurl {
258 url = "https://pypi.python.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz";
259 md5 = "32749ffadfc40fea51075a7def32588b";
205 url = "https://files.pythonhosted.org/packages/5a/9e/637379ffa13c5172b5c0e704833ffea6bf51cec7567f93fd6e903d53ed74/Chameleon-2.24.tar.gz";
206 sha256 = "0ykqr7syxfa6h9adjfnsv1gdsca2xzm22vmic8859n0f0j09abj5";
207 };
208 meta = {
209 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
210 };
211 };
212 "channelstream" = super.buildPythonPackage {
213 name = "channelstream-0.5.2";
214 doCheck = false;
215 propagatedBuildInputs = [
216 self."gevent"
217 self."ws4py"
218 self."pyramid"
219 self."pyramid-jinja2"
220 self."itsdangerous"
221 self."requests"
222 self."six"
223 ];
224 src = fetchurl {
225 url = "https://files.pythonhosted.org/packages/2b/31/29a8e085cf5bf97fa88e7b947adabfc581a18a3463adf77fb6dada34a65f/channelstream-0.5.2.tar.gz";
226 sha256 = "1qbm4xdl5hfkja683x546bncg3rqq8qv79w1m1a1wd48cqqzb6rm";
260 227 };
261 228 meta = {
262 229 license = [ pkgs.lib.licenses.bsdOriginal ];
263 230 };
264 231 };
265 WebHelpers2 = super.buildPythonPackage {
266 name = "WebHelpers2-2.0";
267 buildInputs = with self; [];
232 "click" = super.buildPythonPackage {
233 name = "click-6.6";
268 234 doCheck = false;
269 propagatedBuildInputs = with self; [MarkupSafe six];
270 235 src = fetchurl {
271 url = "https://pypi.python.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz";
272 md5 = "0f6b68d70c12ee0aed48c00b24da13d3";
236 url = "https://files.pythonhosted.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz";
237 sha256 = "1sggipyz52crrybwbr9xvwxd4aqigvplf53k9w3ygxmzivd1jsnc";
273 238 };
274 239 meta = {
275 license = [ pkgs.lib.licenses.mit ];
240 license = [ pkgs.lib.licenses.bsdOriginal ];
276 241 };
277 242 };
278 WebOb = super.buildPythonPackage {
279 name = "WebOb-1.7.4";
280 buildInputs = with self; [];
243 "colander" = super.buildPythonPackage {
244 name = "colander-1.4";
281 245 doCheck = false;
282 propagatedBuildInputs = with self; [];
246 propagatedBuildInputs = [
247 self."translationstring"
248 self."iso8601"
249 ];
283 250 src = fetchurl {
284 url = "https://pypi.python.org/packages/75/34/731e23f52371852dfe7490a61644826ba7fe70fd52a377aaca0f4956ba7f/WebOb-1.7.4.tar.gz";
285 md5 = "397e46892d7f199b1a07eb20a2d3d9bd";
251 url = "https://files.pythonhosted.org/packages/cc/e2/c4e716ac4a426d8ad4dfe306c34f0018a22275d2420815784005bf771c84/colander-1.4.tar.gz";
252 sha256 = "0wjfphyr5aakv5hw73q287lbc15cbm0aardajv7i2mqf377rl3p2";
286 253 };
287 254 meta = {
288 license = [ pkgs.lib.licenses.mit ];
255 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
289 256 };
290 257 };
291 WebTest = super.buildPythonPackage {
292 name = "WebTest-2.0.29";
293 buildInputs = with self; [];
258 "configobj" = super.buildPythonPackage {
259 name = "configobj-5.0.6";
294 260 doCheck = false;
295 propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4];
261 propagatedBuildInputs = [
262 self."six"
263 ];
296 264 src = fetchurl {
297 url = "https://pypi.python.org/packages/94/de/8f94738be649997da99c47b104aa3c3984ecec51a1d8153ed09638253d56/WebTest-2.0.29.tar.gz";
298 md5 = "30b4cf0d340b9a5335fac4389e6f84fc";
265 url = "https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c";
266 sha256 = "1hhcxirwvg58grlfr177b3awhbq8hlx1l3lh69ifl1ki7lfd1s1x";
267 };
268 meta = {
269 license = [ pkgs.lib.licenses.bsdOriginal ];
270 };
271 };
272 "configparser" = super.buildPythonPackage {
273 name = "configparser-3.5.0";
274 doCheck = false;
275 src = fetchurl {
276 url = "https://files.pythonhosted.org/packages/7c/69/c2ce7e91c89dc073eb1aa74c0621c3eefbffe8216b3f9af9d3885265c01c/configparser-3.5.0.tar.gz";
277 sha256 = "0fi7vf09vi1588jd8f16a021m5y6ih2hy7rpbjb408xw45qb822k";
299 278 };
300 279 meta = {
301 280 license = [ pkgs.lib.licenses.mit ];
302 281 };
303 282 };
304 Whoosh = super.buildPythonPackage {
305 name = "Whoosh-2.7.4";
306 buildInputs = with self; [];
283 "cov-core" = super.buildPythonPackage {
284 name = "cov-core-1.15.0";
307 285 doCheck = false;
308 propagatedBuildInputs = with self; [];
286 propagatedBuildInputs = [
287 self."coverage"
288 ];
309 289 src = fetchurl {
310 url = "https://pypi.python.org/packages/25/2b/6beed2107b148edc1321da0d489afc4617b9ed317ef7b72d4993cad9b684/Whoosh-2.7.4.tar.gz";
311 md5 = "c2710105f20b3e29936bd2357383c325";
312 };
313 meta = {
314 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ];
315 };
316 };
317 alembic = super.buildPythonPackage {
318 name = "alembic-0.9.8";
319 buildInputs = with self; [];
320 doCheck = false;
321 propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil];
322 src = fetchurl {
323 url = "https://pypi.python.org/packages/a1/95/2252783859df9ec76b9a25d968c2827ed75a43ba34c6e8d38f87a5c0fb26/alembic-0.9.8.tar.gz";
324 md5 = "5cfef58641c9a94d4a5d547e951a7dda";
290 url = "https://files.pythonhosted.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
291 sha256 = "0k3np9ymh06yv1ib96sb6wfsxjkqhmik8qfsn119vnhga9ywc52a";
325 292 };
326 293 meta = {
327 294 license = [ pkgs.lib.licenses.mit ];
328 295 };
329 296 };
330 amqp = super.buildPythonPackage {
331 name = "amqp-2.2.2";
332 buildInputs = with self; [];
297 "coverage" = super.buildPythonPackage {
298 name = "coverage-3.7.1";
333 299 doCheck = false;
334 propagatedBuildInputs = with self; [vine];
335 300 src = fetchurl {
336 url = "https://pypi.python.org/packages/e0/70/9ab9ccd8247fb7d2adb717e9f6a0ed358c9e1ab2c349048b0352f9e80ee2/amqp-2.2.2.tar.gz";
337 md5 = "0971a3fd2d635ded45c349cfc17106bd";
301 url = "https://files.pythonhosted.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz";
302 sha256 = "0knlbq79g2ww6xzsyknj9rirrgrgc983dpa2d9nkdf31mb2a3bni";
338 303 };
339 304 meta = {
340 305 license = [ pkgs.lib.licenses.bsdOriginal ];
341 306 };
342 307 };
343 appenlight-client = super.buildPythonPackage {
344 name = "appenlight-client-0.6.25";
345 buildInputs = with self; [];
308 "cprofilev" = super.buildPythonPackage {
309 name = "cprofilev-1.0.7";
346 310 doCheck = false;
347 propagatedBuildInputs = with self; [WebOb requests six];
311 propagatedBuildInputs = [
312 self."bottle"
313 ];
348 314 src = fetchurl {
349 url = "https://pypi.python.org/packages/fa/44/2911ef85ea4f4fe65058fd22959d8dad598fab6a3c84e5bcb569d15c8783/appenlight_client-0.6.25.tar.gz";
350 md5 = "76dd2f9d42659fae8f290982078dc880";
351 };
352 meta = {
353 license = [ pkgs.lib.licenses.bsdOriginal ];
354 };
355 };
356 authomatic = super.buildPythonPackage {
357 name = "authomatic-0.1.0.post1";
358 buildInputs = with self; [];
359 doCheck = false;
360 propagatedBuildInputs = with self; [];
361 src = fetchurl {
362 url = "https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801";
363 md5 = "3c68720a1322b25254009518d1ff6801";
315 url = "https://files.pythonhosted.org/packages/df/50/d8c1ada7d537c64b0f76453fa31dedb6af6e27b82fcf0331e5f71a4cf98b/CProfileV-1.0.7.tar.gz";
316 sha256 = "0xwszfhxgndpcjkpq89dix6vi02hj1gzvhr7r716hd1x3y5p94c7";
364 317 };
365 318 meta = {
366 319 license = [ pkgs.lib.licenses.mit ];
367 320 };
368 321 };
369 backports.shutil-get-terminal-size = super.buildPythonPackage {
370 name = "backports.shutil-get-terminal-size-1.0.0";
371 buildInputs = with self; [];
372 doCheck = false;
373 propagatedBuildInputs = with self; [];
374 src = fetchurl {
375 url = "https://pypi.python.org/packages/ec/9c/368086faa9c016efce5da3e0e13ba392c9db79e3ab740b763fe28620b18b/backports.shutil_get_terminal_size-1.0.0.tar.gz";
376 md5 = "03267762480bd86b50580dc19dff3c66";
377 };
378 meta = {
379 license = [ pkgs.lib.licenses.mit ];
380 };
381 };
382 beautifulsoup4 = super.buildPythonPackage {
383 name = "beautifulsoup4-4.6.0";
384 buildInputs = with self; [];
322 "cssselect" = super.buildPythonPackage {
323 name = "cssselect-1.0.3";
385 324 doCheck = false;
386 propagatedBuildInputs = with self; [];
387 325 src = fetchurl {
388 url = "https://pypi.python.org/packages/fa/8d/1d14391fdaed5abada4e0f63543fef49b8331a34ca60c88bd521bcf7f782/beautifulsoup4-4.6.0.tar.gz";
389 md5 = "c17714d0f91a23b708a592cb3c697728";
390 };
391 meta = {
392 license = [ pkgs.lib.licenses.mit ];
393 };
394 };
395 billiard = super.buildPythonPackage {
396 name = "billiard-3.5.0.3";
397 buildInputs = with self; [];
398 doCheck = false;
399 propagatedBuildInputs = with self; [];
400 src = fetchurl {
401 url = "https://pypi.python.org/packages/39/ac/f5571210cca2e4f4532e38aaff242f26c8654c5e2436bee966c230647ccc/billiard-3.5.0.3.tar.gz";
402 md5 = "113ba481e48400adbf6fbbf59a2f8554";
326 url = "https://files.pythonhosted.org/packages/52/ea/f31e1d2e9eb130fda2a631e22eac369dc644e8807345fbed5113f2d6f92b/cssselect-1.0.3.tar.gz";
327 sha256 = "011jqa2jhmydhi0iz4v1w3cr540z5zas8g2bw8brdw4s4b2qnv86";
403 328 };
404 329 meta = {
405 330 license = [ pkgs.lib.licenses.bsdOriginal ];
406 331 };
407 332 };
408 bleach = super.buildPythonPackage {
409 name = "bleach-2.1.2";
410 buildInputs = with self; [];
333 "decorator" = super.buildPythonPackage {
334 name = "decorator-4.1.2";
411 335 doCheck = false;
412 propagatedBuildInputs = with self; [six html5lib];
413 336 src = fetchurl {
414 url = "https://pypi.python.org/packages/b3/5f/0da670d30d3ffbc57cc97fa82947f81bbe3eab8d441e2d42e661f215baf2/bleach-2.1.2.tar.gz";
415 md5 = "d0b14ae43a437ee0c650e04c6063eedd";
337 url = "https://files.pythonhosted.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz";
338 sha256 = "1d8npb11kxyi36mrvjdpcjij76l5zfyrz2f820brf0l0rcw4vdkw";
339 };
340 meta = {
341 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
342 };
343 };
344 "deform" = super.buildPythonPackage {
345 name = "deform-2.0.5";
346 doCheck = false;
347 propagatedBuildInputs = [
348 self."chameleon"
349 self."colander"
350 self."iso8601"
351 self."peppercorn"
352 self."translationstring"
353 self."zope.deprecation"
354 ];
355 src = fetchurl {
356 url = "https://files.pythonhosted.org/packages/0c/b1/ba711d5808c12538c8504f534d79c124ed834f19ac36f0ac5391c3bbd1c1/deform-2.0.5.tar.gz";
357 sha256 = "0ybg9zsnfac1kaxrjanmkjk0xaklf4d3piywxwr08l1cl1336kc7";
416 358 };
417 359 meta = {
418 license = [ pkgs.lib.licenses.asl20 ];
360 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
361 };
362 };
363 "docutils" = super.buildPythonPackage {
364 name = "docutils-0.14";
365 doCheck = false;
366 src = fetchurl {
367 url = "https://files.pythonhosted.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
368 sha256 = "0x22fs3pdmr42kvz6c654756wja305qv6cx1zbhwlagvxgr4xrji";
369 };
370 meta = {
371 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 ];
419 372 };
420 373 };
421 bottle = super.buildPythonPackage {
422 name = "bottle-0.12.13";
423 buildInputs = with self; [];
374 "dogpile.cache" = super.buildPythonPackage {
375 name = "dogpile.cache-0.6.6";
376 doCheck = false;
377 src = fetchurl {
378 url = "https://files.pythonhosted.org/packages/48/ca/604154d835c3668efb8a31bd979b0ea4bf39c2934a40ffecc0662296cb51/dogpile.cache-0.6.6.tar.gz";
379 sha256 = "1h8n1lxd4l2qvahfkiinljkqz7pww7w3sgag0j8j9ixbl2h4wk84";
380 };
381 meta = {
382 license = [ pkgs.lib.licenses.bsdOriginal ];
383 };
384 };
385 "dogpile.core" = super.buildPythonPackage {
386 name = "dogpile.core-0.4.1";
424 387 doCheck = false;
425 propagatedBuildInputs = with self; [];
426 388 src = fetchurl {
427 url = "https://pypi.python.org/packages/bd/99/04dc59ced52a8261ee0f965a8968717a255ea84a36013e527944dbf3468c/bottle-0.12.13.tar.gz";
428 md5 = "d2fe1b48c1d49217e78bf326b1cad437";
389 url = "https://files.pythonhosted.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz";
390 sha256 = "0xpdvg4kr1isfkrh1rfsh7za4q5a5s6l2kf9wpvndbwf3aqjyrdy";
391 };
392 meta = {
393 license = [ pkgs.lib.licenses.bsdOriginal ];
394 };
395 };
396 "ecdsa" = super.buildPythonPackage {
397 name = "ecdsa-0.13";
398 doCheck = false;
399 src = fetchurl {
400 url = "https://files.pythonhosted.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz";
401 sha256 = "1yj31j0asmrx4an9xvsaj2icdmzy6pw0glfpqrrkrphwdpi1xkv4";
429 402 };
430 403 meta = {
431 404 license = [ pkgs.lib.licenses.mit ];
432 405 };
433 406 };
434 bumpversion = super.buildPythonPackage {
435 name = "bumpversion-0.5.3";
436 buildInputs = with self; [];
407 "elasticsearch" = super.buildPythonPackage {
408 name = "elasticsearch-2.3.0";
409 doCheck = false;
410 propagatedBuildInputs = [
411 self."urllib3"
412 ];
413 src = fetchurl {
414 url = "https://files.pythonhosted.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz";
415 sha256 = "10ad2dk73xsys9vajwsncibs69asa63w1hgwz6lz1prjpyi80c5y";
416 };
417 meta = {
418 license = [ pkgs.lib.licenses.asl20 ];
419 };
420 };
421 "elasticsearch-dsl" = super.buildPythonPackage {
422 name = "elasticsearch-dsl-2.2.0";
437 423 doCheck = false;
438 propagatedBuildInputs = with self; [];
424 propagatedBuildInputs = [
425 self."six"
426 self."python-dateutil"
427 self."elasticsearch"
428 ];
439 429 src = fetchurl {
440 url = "https://pypi.python.org/packages/14/41/8c9da3549f8e00c84f0432c3a8cf8ed6898374714676aab91501d48760db/bumpversion-0.5.3.tar.gz";
441 md5 = "c66a3492eafcf5ad4b024be9fca29820";
430 url = "https://files.pythonhosted.org/packages/66/2f/52a086968788e58461641570f45c3207a52d46ebbe9b77dc22b6a8ffda66/elasticsearch-dsl-2.2.0.tar.gz";
431 sha256 = "1g4kxzxsdwlsl2a9kscmx11pafgimhj7y8wrfksv8pgvpkfb9fwr";
432 };
433 meta = {
434 license = [ pkgs.lib.licenses.asl20 ];
435 };
436 };
437 "entrypoints" = super.buildPythonPackage {
438 name = "entrypoints-0.2.2";
439 doCheck = false;
440 propagatedBuildInputs = [
441 self."configparser"
442 ];
443 src = fetchurl {
444 url = "https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313";
445 sha256 = "0bihrdp8ahsys437kxdhk52gz6kib8rxjv71i93wkw7594fcaxll";
442 446 };
443 447 meta = {
444 448 license = [ pkgs.lib.licenses.mit ];
445 449 };
446 450 };
447 celery = super.buildPythonPackage {
448 name = "celery-4.1.0";
449 buildInputs = with self; [];
451 "enum34" = super.buildPythonPackage {
452 name = "enum34-1.1.6";
450 453 doCheck = false;
451 propagatedBuildInputs = with self; [pytz billiard kombu];
452 454 src = fetchurl {
453 url = "https://pypi.python.org/packages/07/65/88a2a45fc80f487872c93121a701a53bbbc3d3d832016876fac84fc8d46a/celery-4.1.0.tar.gz";
454 md5 = "db91e1d26936381127f01e150fe3054a";
455 url = "https://files.pythonhosted.org/packages/bf/3e/31d502c25302814a7c2f1d3959d2a3b3f78e509002ba91aea64993936876/enum34-1.1.6.tar.gz";
456 sha256 = "1cgm5ng2gcfrkrm3hc22brl6chdmv67b9zvva9sfs7gn7dwc9n4a";
455 457 };
456 458 meta = {
457 459 license = [ pkgs.lib.licenses.bsdOriginal ];
458 460 };
459 461 };
460 channelstream = super.buildPythonPackage {
461 name = "channelstream-0.5.2";
462 buildInputs = with self; [];
462 "formencode" = super.buildPythonPackage {
463 name = "formencode-1.2.4";
463 464 doCheck = false;
464 propagatedBuildInputs = with self; [gevent ws4py pyramid pyramid-jinja2 itsdangerous requests six];
465 465 src = fetchurl {
466 url = "https://pypi.python.org/packages/2b/31/29a8e085cf5bf97fa88e7b947adabfc581a18a3463adf77fb6dada34a65f/channelstream-0.5.2.tar.gz";
467 md5 = "1c5eb2a8a405be6f1073da94da6d81d3";
466 url = "https://files.pythonhosted.org/packages/8e/59/0174271a6f004512e0201188593e6d319db139d14cb7490e488bbb078015/FormEncode-1.2.4.tar.gz";
467 sha256 = "1fgy04sdy4yry5xcjls3x3xy30dqwj58ycnkndim819jx0788w42";
468 468 };
469 469 meta = {
470 license = [ pkgs.lib.licenses.bsdOriginal ];
470 license = [ pkgs.lib.licenses.psfl ];
471 471 };
472 472 };
473 click = super.buildPythonPackage {
474 name = "click-6.6";
475 buildInputs = with self; [];
473 "funcsigs" = super.buildPythonPackage {
474 name = "funcsigs-1.0.2";
476 475 doCheck = false;
477 propagatedBuildInputs = with self; [];
478 476 src = fetchurl {
479 url = "https://pypi.python.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz";
480 md5 = "d0b09582123605220ad6977175f3e51d";
477 url = "https://files.pythonhosted.org/packages/94/4a/db842e7a0545de1cdb0439bb80e6e42dfe82aaeaadd4072f2263a4fbed23/funcsigs-1.0.2.tar.gz";
478 sha256 = "0l4g5818ffyfmfs1a924811azhjj8ax9xd1cffr1mzd3ycn0zfx7";
481 479 };
482 480 meta = {
483 license = [ pkgs.lib.licenses.bsdOriginal ];
481 license = [ { fullName = "ASL"; } pkgs.lib.licenses.asl20 ];
482 };
483 };
484 "functools32" = super.buildPythonPackage {
485 name = "functools32-3.2.3.post2";
486 doCheck = false;
487 src = fetchurl {
488 url = "https://files.pythonhosted.org/packages/c5/60/6ac26ad05857c601308d8fb9e87fa36d0ebf889423f47c3502ef034365db/functools32-3.2.3-2.tar.gz";
489 sha256 = "0v8ya0b58x47wp216n1zamimv4iw57cxz3xxhzix52jkw3xks9gn";
490 };
491 meta = {
492 license = [ pkgs.lib.licenses.psfl ];
484 493 };
485 494 };
486 colander = super.buildPythonPackage {
487 name = "colander-1.4";
488 buildInputs = with self; [];
495 "future" = super.buildPythonPackage {
496 name = "future-0.14.3";
489 497 doCheck = false;
490 propagatedBuildInputs = with self; [translationstring iso8601];
491 498 src = fetchurl {
492 url = "https://pypi.python.org/packages/cc/e2/c4e716ac4a426d8ad4dfe306c34f0018a22275d2420815784005bf771c84/colander-1.4.tar.gz";
493 md5 = "cbb8e403c2ba05aeaa419d51fdb93736";
499 url = "https://files.pythonhosted.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz";
500 sha256 = "1savk7jx7hal032f522c5ajhh8fra6gmnadrj9adv5qxi18pv1b2";
494 501 };
495 502 meta = {
496 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
503 license = [ { fullName = "OSI Approved"; } pkgs.lib.licenses.mit ];
497 504 };
498 505 };
499 configobj = super.buildPythonPackage {
500 name = "configobj-5.0.6";
501 buildInputs = with self; [];
506 "futures" = super.buildPythonPackage {
507 name = "futures-3.0.2";
502 508 doCheck = false;
503 propagatedBuildInputs = with self; [six];
504 509 src = fetchurl {
505 url = "https://pypi.python.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz";
506 md5 = "e472a3a1c2a67bb0ec9b5d54c13a47d6";
510 url = "https://files.pythonhosted.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz";
511 sha256 = "0mz2pbgxbc2nbib1szifi07whjbfs4r02pv2z390z7p410awjgyw";
507 512 };
508 513 meta = {
509 514 license = [ pkgs.lib.licenses.bsdOriginal ];
510 515 };
511 516 };
512 configparser = super.buildPythonPackage {
513 name = "configparser-3.5.0";
514 buildInputs = with self; [];
517 "gevent" = super.buildPythonPackage {
518 name = "gevent-1.3.5";
515 519 doCheck = false;
516 propagatedBuildInputs = with self; [];
520 propagatedBuildInputs = [
521 self."greenlet"
522 ];
517 523 src = fetchurl {
518 url = "https://pypi.python.org/packages/7c/69/c2ce7e91c89dc073eb1aa74c0621c3eefbffe8216b3f9af9d3885265c01c/configparser-3.5.0.tar.gz";
519 md5 = "cfdd915a5b7a6c09917a64a573140538";
524 url = "https://files.pythonhosted.org/packages/e6/0a/fc345c6e6161f84484870dbcaa58e427c10bd9bdcd08a69bed3d6b398bf1/gevent-1.3.5.tar.gz";
525 sha256 = "1w3gydxirgd2f60c5yv579w4903ds9s4g3587ik4jby97hgqc5bz";
520 526 };
521 527 meta = {
522 528 license = [ pkgs.lib.licenses.mit ];
523 529 };
524 530 };
525 cov-core = super.buildPythonPackage {
526 name = "cov-core-1.15.0";
527 buildInputs = with self; [];
531 "gnureadline" = super.buildPythonPackage {
532 name = "gnureadline-6.3.8";
533 doCheck = false;
534 src = fetchurl {
535 url = "https://files.pythonhosted.org/packages/50/64/86085c823cd78f9df9d8e33dce0baa71618016f8860460b82cf6610e1eb3/gnureadline-6.3.8.tar.gz";
536 sha256 = "0ddhj98x2nv45iz4aadk4b9m0b1kpsn1xhcbypn5cd556knhiqjq";
537 };
538 meta = {
539 license = [ { fullName = "GNU General Public License v3 (GPLv3)"; } pkgs.lib.licenses.gpl1 ];
540 };
541 };
542 "gprof2dot" = super.buildPythonPackage {
543 name = "gprof2dot-2017.9.19";
528 544 doCheck = false;
529 propagatedBuildInputs = with self; [coverage];
545 src = fetchurl {
546 url = "https://files.pythonhosted.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz";
547 sha256 = "17ih23ld2nzgc3xwgbay911l6lh96jp1zshmskm17n1gg2i7mg6f";
548 };
549 meta = {
550 license = [ { fullName = "GNU Lesser General Public License v3 or later (LGPLv3+)"; } { fullName = "LGPL"; } ];
551 };
552 };
553 "graphviz" = super.buildPythonPackage {
554 name = "graphviz-0.9";
555 doCheck = false;
530 556 src = fetchurl {
531 url = "https://pypi.python.org/packages/4b/87/13e75a47b4ba1be06f29f6d807ca99638bedc6b57fa491cd3de891ca2923/cov-core-1.15.0.tar.gz";
532 md5 = "f519d4cb4c4e52856afb14af52919fe6";
557 url = "https://files.pythonhosted.org/packages/2b/e6/71521bab8fb99833133f08f6ac0460e2f6b425a7f75ac4b02323c3c3b512/graphviz-0.9.zip";
558 sha256 = "14r9brj4r31b3qy1nnn34v3l4h0n39bqxg9sn2fz4p3pp5mglnl6";
559 };
560 meta = {
561 license = [ pkgs.lib.licenses.mit ];
562 };
563 };
564 "greenlet" = super.buildPythonPackage {
565 name = "greenlet-0.4.13";
566 doCheck = false;
567 src = fetchurl {
568 url = "https://files.pythonhosted.org/packages/13/de/ba92335e9e76040ca7274224942282a80d54f85e342a5e33c5277c7f87eb/greenlet-0.4.13.tar.gz";
569 sha256 = "1r412gfx25jrdiv444prmz5a8igrfabwnwqyr6b52ypq7ga87vqg";
533 570 };
534 571 meta = {
535 572 license = [ pkgs.lib.licenses.mit ];
536 573 };
537 574 };
538 coverage = super.buildPythonPackage {
539 name = "coverage-3.7.1";
540 buildInputs = with self; [];
575 "gunicorn" = super.buildPythonPackage {
576 name = "gunicorn-19.9.0";
541 577 doCheck = false;
542 propagatedBuildInputs = with self; [];
543 578 src = fetchurl {
544 url = "https://pypi.python.org/packages/09/4f/89b06c7fdc09687bca507dc411c342556ef9c5a3b26756137a4878ff19bf/coverage-3.7.1.tar.gz";
545 md5 = "c47b36ceb17eaff3ecfab3bcd347d0df";
579 url = "https://files.pythonhosted.org/packages/47/52/68ba8e5e8ba251e54006a49441f7ccabca83b6bef5aedacb4890596c7911/gunicorn-19.9.0.tar.gz";
580 sha256 = "1wzlf4xmn6qjirh5w81l6i6kqjnab1n1qqkh7zsj1yb6gh4n49ps";
546 581 };
547 582 meta = {
548 license = [ pkgs.lib.licenses.bsdOriginal ];
583 license = [ pkgs.lib.licenses.mit ];
549 584 };
550 585 };
551 cssselect = super.buildPythonPackage {
552 name = "cssselect-1.0.1";
553 buildInputs = with self; [];
586 "html5lib" = super.buildPythonPackage {
587 name = "html5lib-1.0.1";
554 588 doCheck = false;
555 propagatedBuildInputs = with self; [];
589 propagatedBuildInputs = [
590 self."six"
591 self."webencodings"
592 ];
556 593 src = fetchurl {
557 url = "https://pypi.python.org/packages/77/ff/9c865275cd19290feba56344eba570e719efb7ca5b34d67ed12b22ebbb0d/cssselect-1.0.1.tar.gz";
558 md5 = "3fa03bf82a9f0b1223c0f1eb1369e139";
594 url = "https://files.pythonhosted.org/packages/85/3e/cf449cf1b5004e87510b9368e7a5f1acd8831c2d6691edd3c62a0823f98f/html5lib-1.0.1.tar.gz";
595 sha256 = "0dipzfrycv6j1jw82v9b7d8lzggx3x8xngx6l4xrqkxwvg7hvjv6";
559 596 };
560 597 meta = {
561 license = [ pkgs.lib.licenses.bsdOriginal ];
562 };
563 };
564 decorator = super.buildPythonPackage {
565 name = "decorator-4.1.2";
566 buildInputs = with self; [];
567 doCheck = false;
568 propagatedBuildInputs = with self; [];
569 src = fetchurl {
570 url = "https://pypi.python.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz";
571 md5 = "a0f7f4fe00ae2dde93494d90c192cf8c";
572 };
573 meta = {
574 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ];
598 license = [ pkgs.lib.licenses.mit ];
575 599 };
576 600 };
577 deform = super.buildPythonPackage {
578 name = "deform-2.0.4";
579 buildInputs = with self; [];
601 "hupper" = super.buildPythonPackage {
602 name = "hupper-1.3";
580 603 doCheck = false;
581 propagatedBuildInputs = with self; [Chameleon colander iso8601 peppercorn translationstring zope.deprecation];
582 604 src = fetchurl {
583 url = "https://pypi.python.org/packages/66/3b/eefcb07abcab7a97f6665aa2d0cf1af741d9d6e78a2e4657fd2b89f89880/deform-2.0.4.tar.gz";
584 md5 = "34756e42cf50dd4b4430809116c4ec0a";
585 };
586 meta = {
587 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
588 };
589 };
590 docutils = super.buildPythonPackage {
591 name = "docutils-0.14";
592 buildInputs = with self; [];
593 doCheck = false;
594 propagatedBuildInputs = with self; [];
595 src = fetchurl {
596 url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz";
597 md5 = "c53768d63db3873b7d452833553469de";
605 url = "https://files.pythonhosted.org/packages/51/0c/96335b1f2f32245fb871eea5bb9773196505ddb71fad15190056a282df9e/hupper-1.3.tar.gz";
606 sha256 = "1pkyrm9c2crc32ps00k1ahnc5clj3pjwiarc7j0x8aykwih7ff10";
598 607 };
599 608 meta = {
600 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.publicDomain pkgs.lib.licenses.gpl1 { fullName = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; } pkgs.lib.licenses.psfl ];
609 license = [ pkgs.lib.licenses.mit ];
601 610 };
602 611 };
603 dogpile.cache = super.buildPythonPackage {
604 name = "dogpile.cache-0.6.4";
605 buildInputs = with self; [];
612 "infrae.cache" = super.buildPythonPackage {
613 name = "infrae.cache-1.0.1";
606 614 doCheck = false;
607 propagatedBuildInputs = with self; [];
615 propagatedBuildInputs = [
616 self."beaker"
617 self."repoze.lru"
618 ];
608 619 src = fetchurl {
609 url = "https://pypi.python.org/packages/b6/3d/35c05ca01c070bb70d9d422f2c4858ecb021b05b21af438fec5ccd7b945c/dogpile.cache-0.6.4.tar.gz";
610 md5 = "66e0a6cae6c08cb1ea25f89d0eadfeb0";
620 url = "https://files.pythonhosted.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz";
621 sha256 = "1dvqsjn8vw253wz9d1pz17j79mf4bs53dvp2qxck2qdp1am1njw4";
611 622 };
612 623 meta = {
613 license = [ pkgs.lib.licenses.bsdOriginal ];
624 license = [ pkgs.lib.licenses.zpl21 ];
614 625 };
615 626 };
616 dogpile.core = super.buildPythonPackage {
617 name = "dogpile.core-0.4.1";
618 buildInputs = with self; [];
627 "invoke" = super.buildPythonPackage {
628 name = "invoke-0.13.0";
619 629 doCheck = false;
620 propagatedBuildInputs = with self; [];
621 630 src = fetchurl {
622 url = "https://pypi.python.org/packages/0e/77/e72abc04c22aedf874301861e5c1e761231c288b5de369c18be8f4b5c9bb/dogpile.core-0.4.1.tar.gz";
623 md5 = "01cb19f52bba3e95c9b560f39341f045";
631 url = "https://files.pythonhosted.org/packages/47/bf/d07ef52fa1ac645468858bbac7cb95b246a972a045e821493d17d89c81be/invoke-0.13.0.tar.gz";
632 sha256 = "0794vhgxfmkh0vzkkg5cfv1w82g3jc3xr18wim29far9qpx9468s";
624 633 };
625 634 meta = {
626 635 license = [ pkgs.lib.licenses.bsdOriginal ];
627 636 };
628 637 };
629 ecdsa = super.buildPythonPackage {
630 name = "ecdsa-0.13";
631 buildInputs = with self; [];
638 "ipaddress" = super.buildPythonPackage {
639 name = "ipaddress-1.0.22";
632 640 doCheck = false;
633 propagatedBuildInputs = with self; [];
634 641 src = fetchurl {
635 url = "https://pypi.python.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz";
636 md5 = "1f60eda9cb5c46722856db41a3ae6670";
642 url = "https://files.pythonhosted.org/packages/97/8d/77b8cedcfbf93676148518036c6b1ce7f8e14bf07e95d7fd4ddcb8cc052f/ipaddress-1.0.22.tar.gz";
643 sha256 = "0b570bm6xqpjwqis15pvdy6lyvvzfndjvkynilcddjj5x98wfimi";
637 644 };
638 645 meta = {
639 license = [ pkgs.lib.licenses.mit ];
646 license = [ pkgs.lib.licenses.psfl ];
640 647 };
641 648 };
642 elasticsearch = super.buildPythonPackage {
643 name = "elasticsearch-2.3.0";
644 buildInputs = with self; [];
649 "ipdb" = super.buildPythonPackage {
650 name = "ipdb-0.11";
645 651 doCheck = false;
646 propagatedBuildInputs = with self; [urllib3];
652 propagatedBuildInputs = [
653 self."setuptools"
654 self."ipython"
655 ];
647 656 src = fetchurl {
648 url = "https://pypi.python.org/packages/10/35/5fd52c5f0b0ee405ed4b5195e8bce44c5e041787680dc7b94b8071cac600/elasticsearch-2.3.0.tar.gz";
649 md5 = "2550f3b51629cf1ef9636608af92c340";
657 url = "https://files.pythonhosted.org/packages/80/fe/4564de08f174f3846364b3add8426d14cebee228f741c27e702b2877e85b/ipdb-0.11.tar.gz";
658 sha256 = "02m0l8wrhhd3z7dg3czn5ys1g5pxib516hpshdzp7rxzsxgcd0bh";
650 659 };
651 660 meta = {
652 license = [ pkgs.lib.licenses.asl20 ];
661 license = [ pkgs.lib.licenses.bsdOriginal ];
653 662 };
654 663 };
655 elasticsearch-dsl = super.buildPythonPackage {
656 name = "elasticsearch-dsl-2.2.0";
657 buildInputs = with self; [];
664 "ipython" = super.buildPythonPackage {
665 name = "ipython-5.1.0";
658 666 doCheck = false;
659 propagatedBuildInputs = with self; [six python-dateutil elasticsearch];
667 propagatedBuildInputs = [
668 self."setuptools"
669 self."decorator"
670 self."pickleshare"
671 self."simplegeneric"
672 self."traitlets"
673 self."prompt-toolkit"
674 self."pygments"
675 self."pexpect"
676 self."backports.shutil-get-terminal-size"
677 self."pathlib2"
678 self."pexpect"
679 ];
660 680 src = fetchurl {
661 url = "https://pypi.python.org/packages/66/2f/52a086968788e58461641570f45c3207a52d46ebbe9b77dc22b6a8ffda66/elasticsearch-dsl-2.2.0.tar.gz";
662 md5 = "fa6bd3c87ea3caa8f0f051bc37c53221";
681 url = "https://files.pythonhosted.org/packages/89/63/a9292f7cd9d0090a0f995e1167f3f17d5889dcbc9a175261719c513b9848/ipython-5.1.0.tar.gz";
682 sha256 = "0qdrf6aj9kvjczd5chj1my8y2iq09am9l8bb2a1334a52d76kx3y";
663 683 };
664 684 meta = {
665 license = [ pkgs.lib.licenses.asl20 ];
685 license = [ pkgs.lib.licenses.bsdOriginal ];
666 686 };
667 687 };
668 entrypoints = super.buildPythonPackage {
669 name = "entrypoints-0.2.2";
670 buildInputs = with self; [];
688 "ipython-genutils" = super.buildPythonPackage {
689 name = "ipython-genutils-0.2.0";
671 690 doCheck = false;
672 propagatedBuildInputs = with self; [configparser];
673 691 src = fetchurl {
674 url = "https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313";
675 md5 = "7db37771aea9ac9fefe093e5d6987313";
692 url = "https://files.pythonhosted.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz";
693 sha256 = "1a4bc9y8hnvq6cp08qs4mckgm6i6ajpndp4g496rvvzcfmp12bpb";
694 };
695 meta = {
696 license = [ pkgs.lib.licenses.bsdOriginal ];
697 };
698 };
699 "iso8601" = super.buildPythonPackage {
700 name = "iso8601-0.1.11";
701 doCheck = false;
702 src = fetchurl {
703 url = "https://files.pythonhosted.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz";
704 sha256 = "0c7gh3lsdjds262h0v1sqc66l7hqgfwbakn96qrhdbl0i3vm5yz8";
676 705 };
677 706 meta = {
678 707 license = [ pkgs.lib.licenses.mit ];
679 708 };
680 709 };
681 enum34 = super.buildPythonPackage {
682 name = "enum34-1.1.6";
683 buildInputs = with self; [];
710 "itsdangerous" = super.buildPythonPackage {
711 name = "itsdangerous-0.24";
684 712 doCheck = false;
685 propagatedBuildInputs = with self; [];
686 713 src = fetchurl {
687 url = "https://pypi.python.org/packages/bf/3e/31d502c25302814a7c2f1d3959d2a3b3f78e509002ba91aea64993936876/enum34-1.1.6.tar.gz";
688 md5 = "5f13a0841a61f7fc295c514490d120d0";
714 url = "https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz";
715 sha256 = "06856q6x675ly542ig0plbqcyab6ksfzijlyf1hzhgg3sgwgrcyb";
689 716 };
690 717 meta = {
691 718 license = [ pkgs.lib.licenses.bsdOriginal ];
692 719 };
693 720 };
694 funcsigs = super.buildPythonPackage {
695 name = "funcsigs-1.0.2";
696 buildInputs = with self; [];
721 "jinja2" = super.buildPythonPackage {
722 name = "jinja2-2.9.6";
697 723 doCheck = false;
698 propagatedBuildInputs = with self; [];
699 src = fetchurl {
700 url = "https://pypi.python.org/packages/94/4a/db842e7a0545de1cdb0439bb80e6e42dfe82aaeaadd4072f2263a4fbed23/funcsigs-1.0.2.tar.gz";
701 md5 = "7e583285b1fb8a76305d6d68f4ccc14e";
702 };
703 meta = {
704 license = [ { fullName = "ASL"; } pkgs.lib.licenses.asl20 ];
705 };
706 };
707 functools32 = super.buildPythonPackage {
708 name = "functools32-3.2.3.post2";
709 buildInputs = with self; [];
710 doCheck = false;
711 propagatedBuildInputs = with self; [];
724 propagatedBuildInputs = [
725 self."markupsafe"
726 ];
712 727 src = fetchurl {
713 url = "https://pypi.python.org/packages/c5/60/6ac26ad05857c601308d8fb9e87fa36d0ebf889423f47c3502ef034365db/functools32-3.2.3-2.tar.gz";
714 md5 = "09f24ffd9af9f6cd0f63cb9f4e23d4b2";
715 };
716 meta = {
717 license = [ pkgs.lib.licenses.psfl ];
718 };
719 };
720 future = super.buildPythonPackage {
721 name = "future-0.14.3";
722 buildInputs = with self; [];
723 doCheck = false;
724 propagatedBuildInputs = with self; [];
725 src = fetchurl {
726 url = "https://pypi.python.org/packages/83/80/8ef3a11a15f8eaafafa0937b20c1b3f73527e69ab6b3fa1cf94a5a96aabb/future-0.14.3.tar.gz";
727 md5 = "e94079b0bd1fc054929e8769fc0f6083";
728 };
729 meta = {
730 license = [ { fullName = "OSI Approved"; } pkgs.lib.licenses.mit ];
731 };
732 };
733 futures = super.buildPythonPackage {
734 name = "futures-3.0.2";
735 buildInputs = with self; [];
736 doCheck = false;
737 propagatedBuildInputs = with self; [];
738 src = fetchurl {
739 url = "https://pypi.python.org/packages/f8/e7/fc0fcbeb9193ba2d4de00b065e7fd5aecd0679e93ce95a07322b2b1434f4/futures-3.0.2.tar.gz";
740 md5 = "42aaf1e4de48d6e871d77dc1f9d96d5a";
728 url = "https://files.pythonhosted.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz";
729 sha256 = "1zzrkywhziqffrzks14kzixz7nd4yh2vc0fb04a68vfd2ai03anx";
741 730 };
742 731 meta = {
743 732 license = [ pkgs.lib.licenses.bsdOriginal ];
744 733 };
745 734 };
746 gevent = super.buildPythonPackage {
747 name = "gevent-1.2.2";
748 buildInputs = with self; [];
735 "jsonschema" = super.buildPythonPackage {
736 name = "jsonschema-2.6.0";
749 737 doCheck = false;
750 propagatedBuildInputs = with self; [greenlet];
738 propagatedBuildInputs = [
739 self."functools32"
740 ];
751 741 src = fetchurl {
752 url = "https://pypi.python.org/packages/1b/92/b111f76e54d2be11375b47b213b56687214f258fd9dae703546d30b837be/gevent-1.2.2.tar.gz";
753 md5 = "7f0baf355384fe5ff2ecf66853422554";
742 url = "https://files.pythonhosted.org/packages/58/b9/171dbb07e18c6346090a37f03c7e74410a1a56123f847efed59af260a298/jsonschema-2.6.0.tar.gz";
743 sha256 = "00kf3zmpp9ya4sydffpifn0j0mzm342a2vzh82p6r0vh10cg7xbg";
754 744 };
755 745 meta = {
756 746 license = [ pkgs.lib.licenses.mit ];
757 747 };
758 748 };
759 gnureadline = super.buildPythonPackage {
760 name = "gnureadline-6.3.8";
761 buildInputs = with self; [];
749 "jupyter-client" = super.buildPythonPackage {
750 name = "jupyter-client-5.0.0";
762 751 doCheck = false;
763 propagatedBuildInputs = with self; [];
752 propagatedBuildInputs = [
753 self."traitlets"
754 self."jupyter-core"
755 self."pyzmq"
756 self."python-dateutil"
757 ];
764 758 src = fetchurl {
765 url = "https://pypi.python.org/packages/50/64/86085c823cd78f9df9d8e33dce0baa71618016f8860460b82cf6610e1eb3/gnureadline-6.3.8.tar.gz";
766 md5 = "ba341f4b907250bd1f47dbc06290604f";
759 url = "https://files.pythonhosted.org/packages/e5/6f/65412ed462202b90134b7e761b0b7e7f949e07a549c1755475333727b3d0/jupyter_client-5.0.0.tar.gz";
760 sha256 = "0nxw4rqk4wsjhc87gjqd7pv89cb9dnimcfnmcmp85bmrvv1gjri7";
767 761 };
768 762 meta = {
769 license = [ { fullName = "GNU General Public License v3 (GPLv3)"; } pkgs.lib.licenses.gpl1 ];
763 license = [ pkgs.lib.licenses.bsdOriginal ];
770 764 };
771 765 };
772 gprof2dot = super.buildPythonPackage {
773 name = "gprof2dot-2017.9.19";
774 buildInputs = with self; [];
766 "jupyter-core" = super.buildPythonPackage {
767 name = "jupyter-core-4.4.0";
775 768 doCheck = false;
776 propagatedBuildInputs = with self; [];
769 propagatedBuildInputs = [
770 self."traitlets"
771 ];
777 772 src = fetchurl {
778 url = "https://pypi.python.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz";
779 md5 = "cda2d552bb0d0b9f16e6824a9aabd225";
773 url = "https://files.pythonhosted.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
774 sha256 = "1dy083rarba8prn9f9srxq3c7n7vyql02ycrqq306c40lr57aw5s";
780 775 };
781 776 meta = {
782 license = [ { fullName = "GNU Lesser General Public License v3 or later (LGPLv3+)"; } { fullName = "LGPL"; } ];
777 license = [ pkgs.lib.licenses.bsdOriginal ];
778 };
779 };
780 "kombu" = super.buildPythonPackage {
781 name = "kombu-4.2.0";
782 doCheck = false;
783 propagatedBuildInputs = [
784 self."amqp"
785 ];
786 src = fetchurl {
787 url = "https://files.pythonhosted.org/packages/ab/b1/46a7a8babf5e60f3b2ca081a100af8edfcf132078a726375f52a054e70cf/kombu-4.2.0.tar.gz";
788 sha256 = "1yz19qlqf0inl1mnwlpq9j6kj9r67clpy0xg99phyg4329rw80fn";
789 };
790 meta = {
791 license = [ pkgs.lib.licenses.bsdOriginal ];
783 792 };
784 793 };
785 graphviz = super.buildPythonPackage {
786 name = "graphviz-0.8.2";
787 buildInputs = with self; [];
794 "lxml" = super.buildPythonPackage {
795 name = "lxml-3.7.3";
788 796 doCheck = false;
789 propagatedBuildInputs = with self; [];
790 797 src = fetchurl {
791 url = "https://pypi.python.org/packages/fa/d1/63b62dee9e55368f60b5ea445e6afb361bb47e692fc27553f3672e16efb8/graphviz-0.8.2.zip";
792 md5 = "50866e780f43e1cb0d073c70424fcaff";
798 url = "https://files.pythonhosted.org/packages/39/e8/a8e0b1fa65dd021d48fe21464f71783655f39a41f218293c1c590d54eb82/lxml-3.7.3.tar.gz";
799 sha256 = "1iv1jgkqn1hdh1xyxri6g0y1s67h01jzjkw2nhkx3rqylmw2sl5a";
793 800 };
794 801 meta = {
795 license = [ pkgs.lib.licenses.mit ];
802 license = [ pkgs.lib.licenses.bsdOriginal ];
796 803 };
797 804 };
798 greenlet = super.buildPythonPackage {
799 name = "greenlet-0.4.13";
800 buildInputs = with self; [];
805 "mako" = super.buildPythonPackage {
806 name = "mako-1.0.7";
801 807 doCheck = false;
802 propagatedBuildInputs = with self; [];
808 propagatedBuildInputs = [
809 self."markupsafe"
810 ];
803 811 src = fetchurl {
804 url = "https://pypi.python.org/packages/13/de/ba92335e9e76040ca7274224942282a80d54f85e342a5e33c5277c7f87eb/greenlet-0.4.13.tar.gz";
805 md5 = "6e0b9dd5385f81d478451ec8ed1d62b3";
812 url = "https://files.pythonhosted.org/packages/eb/f3/67579bb486517c0d49547f9697e36582cd19dafb5df9e687ed8e22de57fa/Mako-1.0.7.tar.gz";
813 sha256 = "1bi5gnr8r8dva06qpyx4kgjc6spm2k1y908183nbbaylggjzs0jf";
806 814 };
807 815 meta = {
808 816 license = [ pkgs.lib.licenses.mit ];
809 817 };
810 818 };
811 gunicorn = super.buildPythonPackage {
812 name = "gunicorn-19.7.1";
813 buildInputs = with self; [];
819 "markdown" = super.buildPythonPackage {
820 name = "markdown-2.6.11";
814 821 doCheck = false;
815 propagatedBuildInputs = with self; [];
816 822 src = fetchurl {
817 url = "https://pypi.python.org/packages/30/3a/10bb213cede0cc4d13ac2263316c872a64bf4c819000c8ccd801f1d5f822/gunicorn-19.7.1.tar.gz";
818 md5 = "174d3c3cd670a5be0404d84c484e590c";
823 url = "https://files.pythonhosted.org/packages/b3/73/fc5c850f44af5889192dff783b7b0d8f3fe8d30b65c8e3f78f8f0265fecf/Markdown-2.6.11.tar.gz";
824 sha256 = "108g80ryzykh8bj0i7jfp71510wrcixdi771lf2asyghgyf8cmm8";
819 825 };
820 826 meta = {
821 license = [ pkgs.lib.licenses.mit ];
827 license = [ pkgs.lib.licenses.bsdOriginal ];
822 828 };
823 829 };
824 html5lib = super.buildPythonPackage {
825 name = "html5lib-1.0.1";
826 buildInputs = with self; [];
830 "markupsafe" = super.buildPythonPackage {
831 name = "markupsafe-1.0";
827 832 doCheck = false;
828 propagatedBuildInputs = with self; [six webencodings];
829 833 src = fetchurl {
830 url = "https://pypi.python.org/packages/85/3e/cf449cf1b5004e87510b9368e7a5f1acd8831c2d6691edd3c62a0823f98f/html5lib-1.0.1.tar.gz";
831 md5 = "942a0688d6bdf20d087c9805c40182ad";
834 url = "https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz";
835 sha256 = "0rdn1s8x9ni7ss8rfiacj7x1085lx8mh2zdwqslnw8xc3l4nkgm6";
832 836 };
833 837 meta = {
834 license = [ pkgs.lib.licenses.mit ];
838 license = [ pkgs.lib.licenses.bsdOriginal ];
835 839 };
836 840 };
837 hupper = super.buildPythonPackage {
838 name = "hupper-1.0";
839 buildInputs = with self; [];
841 "meld3" = super.buildPythonPackage {
842 name = "meld3-1.0.2";
840 843 doCheck = false;
841 propagatedBuildInputs = with self; [];
842 844 src = fetchurl {
843 url = "https://pypi.python.org/packages/2e/07/df892c564dc09bb3cf6f6deb976c26adf9117db75ba218cb4353dbc9d826/hupper-1.0.tar.gz";
844 md5 = "26e77da7d5ac5858f59af050d1a6eb5a";
845 url = "https://files.pythonhosted.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz";
846 sha256 = "0n4mkwlpsqnmn0dm0wm5hn9nkda0nafl0jdy5sdl5977znh59dzp";
845 847 };
846 848 meta = {
847 license = [ pkgs.lib.licenses.mit ];
849 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
848 850 };
849 851 };
850 infrae.cache = super.buildPythonPackage {
851 name = "infrae.cache-1.0.1";
852 buildInputs = with self; [];
852 "mistune" = super.buildPythonPackage {
853 name = "mistune-0.8.3";
853 854 doCheck = false;
854 propagatedBuildInputs = with self; [Beaker repoze.lru];
855 855 src = fetchurl {
856 url = "https://pypi.python.org/packages/bb/f0/e7d5e984cf6592fd2807dc7bc44a93f9d18e04e6a61f87fdfb2622422d74/infrae.cache-1.0.1.tar.gz";
857 md5 = "b09076a766747e6ed2a755cc62088e32";
856 url = "https://files.pythonhosted.org/packages/9d/be/e06d4346cc608a01dec6bf770d7d0303a4fd6db588b318ced18f5f257145/mistune-0.8.3.tar.gz";
857 sha256 = "06b662p6kf46wh2jsabaqhaq4bz1srh2zxkrnx4yg96azlxw645w";
858 858 };
859 859 meta = {
860 license = [ pkgs.lib.licenses.zpt21 ];
860 license = [ pkgs.lib.licenses.bsdOriginal ];
861 861 };
862 862 };
863 invoke = super.buildPythonPackage {
864 name = "invoke-0.13.0";
865 buildInputs = with self; [];
863 "mock" = super.buildPythonPackage {
864 name = "mock-1.0.1";
866 865 doCheck = false;
867 propagatedBuildInputs = with self; [];
868 866 src = fetchurl {
869 url = "https://pypi.python.org/packages/47/bf/d07ef52fa1ac645468858bbac7cb95b246a972a045e821493d17d89c81be/invoke-0.13.0.tar.gz";
870 md5 = "c0d1ed4bfb34eaab551662d8cfee6540";
867 url = "https://files.pythonhosted.org/packages/a2/52/7edcd94f0afb721a2d559a5b9aae8af4f8f2c79bc63fdbe8a8a6c9b23bbe/mock-1.0.1.tar.gz";
868 sha256 = "0kzlsbki6q0awf89rc287f3aj8x431lrajf160a70z0ikhnxsfdq";
871 869 };
872 870 meta = {
873 871 license = [ pkgs.lib.licenses.bsdOriginal ];
874 872 };
875 873 };
876 ipaddress = super.buildPythonPackage {
877 name = "ipaddress-1.0.19";
878 buildInputs = with self; [];
879 doCheck = false;
880 propagatedBuildInputs = with self; [];
881 src = fetchurl {
882 url = "https://pypi.python.org/packages/f0/ba/860a4a3e283456d6b7e2ab39ce5cf11a3490ee1a363652ac50abf9f0f5df/ipaddress-1.0.19.tar.gz";
883 md5 = "d0687efaf93a32476d81e90ba0609c57";
884 };
885 meta = {
886 license = [ pkgs.lib.licenses.psfl ];
887 };
888 };
889 ipdb = super.buildPythonPackage {
890 name = "ipdb-0.10.3";
891 buildInputs = with self; [];
892 doCheck = false;
893 propagatedBuildInputs = with self; [setuptools ipython];
894 src = fetchurl {
895 url = "https://pypi.python.org/packages/ad/cc/0e7298e1fbf2efd52667c9354a12aa69fb6f796ce230cca03525051718ef/ipdb-0.10.3.tar.gz";
896 md5 = "def1f6ac075d54bdee07e6501263d4fa";
897 };
898 meta = {
899 license = [ pkgs.lib.licenses.bsdOriginal ];
900 };
901 };
902 ipython = super.buildPythonPackage {
903 name = "ipython-5.1.0";
904 buildInputs = with self; [];
874 "more-itertools" = super.buildPythonPackage {
875 name = "more-itertools-4.3.0";
905 876 doCheck = false;
906 propagatedBuildInputs = with self; [setuptools decorator pickleshare simplegeneric traitlets prompt-toolkit Pygments pexpect backports.shutil-get-terminal-size pathlib2 pexpect];
907 src = fetchurl {
908 url = "https://pypi.python.org/packages/89/63/a9292f7cd9d0090a0f995e1167f3f17d5889dcbc9a175261719c513b9848/ipython-5.1.0.tar.gz";
909 md5 = "47c8122420f65b58784cb4b9b4af35e3";
910 };
911 meta = {
912 license = [ pkgs.lib.licenses.bsdOriginal ];
913 };
914 };
915 ipython-genutils = super.buildPythonPackage {
916 name = "ipython-genutils-0.2.0";
917 buildInputs = with self; [];
918 doCheck = false;
919 propagatedBuildInputs = with self; [];
877 propagatedBuildInputs = [
878 self."six"
879 ];
920 880 src = fetchurl {
921 url = "https://pypi.python.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz";
922 md5 = "5a4f9781f78466da0ea1a648f3e1f79f";
923 };
924 meta = {
925 license = [ pkgs.lib.licenses.bsdOriginal ];
926 };
927 };
928 iso8601 = super.buildPythonPackage {
929 name = "iso8601-0.1.12";
930 buildInputs = with self; [];
931 doCheck = false;
932 propagatedBuildInputs = with self; [];
933 src = fetchurl {
934 url = "https://pypi.python.org/packages/45/13/3db24895497345fb44c4248c08b16da34a9eb02643cea2754b21b5ed08b0/iso8601-0.1.12.tar.gz";
935 md5 = "4de940f691c5ea759fb254384c8ddcf6";
881 url = "https://files.pythonhosted.org/packages/88/ff/6d485d7362f39880810278bdc906c13300db05485d9c65971dec1142da6a/more-itertools-4.3.0.tar.gz";
882 sha256 = "17h3na0rdh8xq30w4b9pizgkdxmm51896bxw600x84jflg9vaxn4";
936 883 };
937 884 meta = {
938 885 license = [ pkgs.lib.licenses.mit ];
939 886 };
940 887 };
941 itsdangerous = super.buildPythonPackage {
942 name = "itsdangerous-0.24";
943 buildInputs = with self; [];
888 "msgpack-python" = super.buildPythonPackage {
889 name = "msgpack-python-0.5.6";
890 doCheck = false;
891 src = fetchurl {
892 url = "https://files.pythonhosted.org/packages/8a/20/6eca772d1a5830336f84aca1d8198e5a3f4715cd1c7fc36d3cc7f7185091/msgpack-python-0.5.6.tar.gz";
893 sha256 = "16wh8qgybmfh4pjp8vfv78mdlkxfmcasg78lzlnm6nslsfkci31p";
894 };
895 meta = {
896 license = [ pkgs.lib.licenses.asl20 ];
897 };
898 };
899 "mysql-python" = super.buildPythonPackage {
900 name = "mysql-python-1.2.5";
944 901 doCheck = false;
945 propagatedBuildInputs = with self; [];
946 902 src = fetchurl {
947 url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz";
948 md5 = "a3d55aa79369aef5345c036a8a26307f";
903 url = "https://files.pythonhosted.org/packages/a5/e9/51b544da85a36a68debe7a7091f068d802fc515a3a202652828c73453cad/MySQL-python-1.2.5.zip";
904 sha256 = "0x0c2jg0bb3pp84njaqiic050qkyd7ymwhfvhipnimg58yv40441";
905 };
906 meta = {
907 license = [ pkgs.lib.licenses.gpl1 ];
908 };
909 };
910 "nbconvert" = super.buildPythonPackage {
911 name = "nbconvert-5.3.1";
912 doCheck = false;
913 propagatedBuildInputs = [
914 self."mistune"
915 self."jinja2"
916 self."pygments"
917 self."traitlets"
918 self."jupyter-core"
919 self."nbformat"
920 self."entrypoints"
921 self."bleach"
922 self."pandocfilters"
923 self."testpath"
924 ];
925 src = fetchurl {
926 url = "https://files.pythonhosted.org/packages/b9/a4/d0a0938ad6f5eeb4dea4e73d255c617ef94b0b2849d51194c9bbdb838412/nbconvert-5.3.1.tar.gz";
927 sha256 = "1f9dkvpx186xjm4xab0qbph588mncp4vqk3fmxrsnqs43mks9c8j";
949 928 };
950 929 meta = {
951 930 license = [ pkgs.lib.licenses.bsdOriginal ];
952 931 };
953 932 };
954 jsonschema = super.buildPythonPackage {
955 name = "jsonschema-2.6.0";
956 buildInputs = with self; [];
933 "nbformat" = super.buildPythonPackage {
934 name = "nbformat-4.4.0";
957 935 doCheck = false;
958 propagatedBuildInputs = with self; [functools32];
936 propagatedBuildInputs = [
937 self."ipython-genutils"
938 self."traitlets"
939 self."jsonschema"
940 self."jupyter-core"
941 ];
959 942 src = fetchurl {
960 url = "https://pypi.python.org/packages/58/b9/171dbb07e18c6346090a37f03c7e74410a1a56123f847efed59af260a298/jsonschema-2.6.0.tar.gz";
961 md5 = "50c6b69a373a8b55ff1e0ec6e78f13f4";
962 };
963 meta = {
964 license = [ pkgs.lib.licenses.mit ];
965 };
966 };
967 jupyter-client = super.buildPythonPackage {
968 name = "jupyter-client-5.0.0";
969 buildInputs = with self; [];
970 doCheck = false;
971 propagatedBuildInputs = with self; [traitlets jupyter-core pyzmq python-dateutil];
972 src = fetchurl {
973 url = "https://pypi.python.org/packages/e5/6f/65412ed462202b90134b7e761b0b7e7f949e07a549c1755475333727b3d0/jupyter_client-5.0.0.tar.gz";
974 md5 = "1acd331b5c9fb4d79dae9939e79f2426";
943 url = "https://files.pythonhosted.org/packages/6e/0e/160754f7ae3e984863f585a3743b0ed1702043a81245907c8fae2d537155/nbformat-4.4.0.tar.gz";
944 sha256 = "00nlf08h8yc4q73nphfvfhxrcnilaqanb8z0mdy6nxk0vzq4wjgp";
975 945 };
976 946 meta = {
977 947 license = [ pkgs.lib.licenses.bsdOriginal ];
978 948 };
979 949 };
980 jupyter-core = super.buildPythonPackage {
981 name = "jupyter-core-4.4.0";
982 buildInputs = with self; [];
950 "objgraph" = super.buildPythonPackage {
951 name = "objgraph-3.1.1";
983 952 doCheck = false;
984 propagatedBuildInputs = with self; [traitlets];
953 propagatedBuildInputs = [
954 self."graphviz"
955 ];
985 956 src = fetchurl {
986 url = "https://pypi.python.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
987 md5 = "7829fc07884ed98459e170f217e2a5ba";
957 url = "https://files.pythonhosted.org/packages/be/58/9ca81a20cc837054e94866df1475d899caaa94f3732b8a46006858b015f7/objgraph-3.1.1.tar.gz";
958 sha256 = "17aq4cwainiwvj8x61j0hx45c313bkwza5fijnmmw8v8glyy2bcc";
959 };
960 meta = {
961 license = [ pkgs.lib.licenses.mit ];
962 };
963 };
964 "packaging" = super.buildPythonPackage {
965 name = "packaging-15.2";
966 doCheck = false;
967 src = fetchurl {
968 url = "https://files.pythonhosted.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz";
969 sha256 = "1zn60w84bxvw6wypffka18ca66pa1k2cfrq3cq8fnsfja5m3k4ng";
970 };
971 meta = {
972 license = [ pkgs.lib.licenses.asl20 ];
973 };
974 };
975 "pandocfilters" = super.buildPythonPackage {
976 name = "pandocfilters-1.4.2";
977 doCheck = false;
978 src = fetchurl {
979 url = "https://files.pythonhosted.org/packages/4c/ea/236e2584af67bb6df960832731a6e5325fd4441de001767da328c33368ce/pandocfilters-1.4.2.tar.gz";
980 sha256 = "1a8d9b7s48gmq9zj0pmbyv2sivn5i7m6mybgpkk4jm5vd7hp1pdk";
988 981 };
989 982 meta = {
990 983 license = [ pkgs.lib.licenses.bsdOriginal ];
991 984 };
992 985 };
993 kombu = super.buildPythonPackage {
994 name = "kombu-4.1.0";
995 buildInputs = with self; [];
986 "paste" = super.buildPythonPackage {
987 name = "paste-2.0.3";
996 988 doCheck = false;
997 propagatedBuildInputs = with self; [amqp];
989 propagatedBuildInputs = [
990 self."six"
991 ];
998 992 src = fetchurl {
999 url = "https://pypi.python.org/packages/03/5e/1a47d1e543d4943d65330af4e4406049f443878818fb65bfdc651bb93a96/kombu-4.1.0.tar.gz";
1000 md5 = "2fb2be9fec0e6514231bba23a3779439";
993 url = "https://files.pythonhosted.org/packages/30/c3/5c2f7c7a02e4f58d4454353fa1c32c94f79fa4e36d07a67c0ac295ea369e/Paste-2.0.3.tar.gz";
994 sha256 = "062jk0nlxf6lb2wwj6zc20rlvrwsnikpkh90y0dn8cjch93s6ii3";
1001 995 };
1002 996 meta = {
1003 license = [ pkgs.lib.licenses.bsdOriginal ];
997 license = [ pkgs.lib.licenses.mit ];
998 };
999 };
1000 "pastedeploy" = super.buildPythonPackage {
1001 name = "pastedeploy-1.5.2";
1002 doCheck = false;
1003 src = fetchurl {
1004 url = "https://files.pythonhosted.org/packages/0f/90/8e20cdae206c543ea10793cbf4136eb9a8b3f417e04e40a29d72d9922cbd/PasteDeploy-1.5.2.tar.gz";
1005 sha256 = "1jz3m4hq8v6hyhfjz9425nd3nvn52cvbfipdcd72krjmla4qz1fm";
1006 };
1007 meta = {
1008 license = [ pkgs.lib.licenses.mit ];
1004 1009 };
1005 1010 };
1006 lxml = super.buildPythonPackage {
1007 name = "lxml-3.7.3";
1008 buildInputs = with self; [];
1011 "pastescript" = super.buildPythonPackage {
1012 name = "pastescript-2.0.2";
1009 1013 doCheck = false;
1010 propagatedBuildInputs = with self; [];
1014 propagatedBuildInputs = [
1015 self."paste"
1016 self."pastedeploy"
1017 self."six"
1018 ];
1011 1019 src = fetchurl {
1012 url = "https://pypi.python.org/packages/39/e8/a8e0b1fa65dd021d48fe21464f71783655f39a41f218293c1c590d54eb82/lxml-3.7.3.tar.gz";
1013 md5 = "075692ce442e69bbd604d44e21c02753";
1020 url = "https://files.pythonhosted.org/packages/e5/f0/78e766c3dcc61a4f3a6f71dd8c95168ae9c7a31722b5663d19c1fdf62cb6/PasteScript-2.0.2.tar.gz";
1021 sha256 = "1h3nnhn45kf4pbcv669ik4faw04j58k8vbj1hwrc532k0nc28gy0";
1014 1022 };
1015 1023 meta = {
1016 license = [ pkgs.lib.licenses.bsdOriginal ];
1024 license = [ pkgs.lib.licenses.mit ];
1017 1025 };
1018 1026 };
1019 meld3 = super.buildPythonPackage {
1020 name = "meld3-1.0.2";
1021 buildInputs = with self; [];
1027 "pathlib2" = super.buildPythonPackage {
1028 name = "pathlib2-2.3.0";
1022 1029 doCheck = false;
1023 propagatedBuildInputs = with self; [];
1030 propagatedBuildInputs = [
1031 self."six"
1032 self."scandir"
1033 ];
1024 1034 src = fetchurl {
1025 url = "https://pypi.python.org/packages/45/a0/317c6422b26c12fe0161e936fc35f36552069ba8e6f7ecbd99bbffe32a5f/meld3-1.0.2.tar.gz";
1026 md5 = "3ccc78cd79cffd63a751ad7684c02c91";
1035 url = "https://files.pythonhosted.org/packages/a1/14/df0deb867c2733f7d857523c10942b3d6612a1b222502fdffa9439943dfb/pathlib2-2.3.0.tar.gz";
1036 sha256 = "1cx5gs2v9j2vnzmcrbq5l8fq2mwrr1h6pyf1sjdji2w1bavm09fk";
1037 };
1038 meta = {
1039 license = [ pkgs.lib.licenses.mit ];
1040 };
1041 };
1042 "peppercorn" = super.buildPythonPackage {
1043 name = "peppercorn-0.5";
1044 doCheck = false;
1045 src = fetchurl {
1046 url = "https://files.pythonhosted.org/packages/45/ec/a62ec317d1324a01567c5221b420742f094f05ee48097e5157d32be3755c/peppercorn-0.5.tar.gz";
1047 sha256 = "0jvp144zn7yqk9kbpxc059167mlqk85i5lpvl1niw8gsa5fvl74j";
1027 1048 };
1028 1049 meta = {
1029 1050 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1030 1051 };
1031 1052 };
1032 mistune = super.buildPythonPackage {
1033 name = "mistune-0.8.3";
1034 buildInputs = with self; [];
1035 doCheck = false;
1036 propagatedBuildInputs = with self; [];
1037 src = fetchurl {
1038 url = "https://pypi.python.org/packages/9d/be/e06d4346cc608a01dec6bf770d7d0303a4fd6db588b318ced18f5f257145/mistune-0.8.3.tar.gz";
1039 md5 = "a5e4043e93fb8f9082e27f29eeb5e054";
1040 };
1041 meta = {
1042 license = [ pkgs.lib.licenses.bsdOriginal ];
1043 };
1044 };
1045 mock = super.buildPythonPackage {
1046 name = "mock-1.0.1";
1047 buildInputs = with self; [];
1053 "pexpect" = super.buildPythonPackage {
1054 name = "pexpect-4.6.0";
1048 1055 doCheck = false;
1049 propagatedBuildInputs = with self; [];
1056 propagatedBuildInputs = [
1057 self."ptyprocess"
1058 ];
1050 1059 src = fetchurl {
1051 url = "https://pypi.python.org/packages/a2/52/7edcd94f0afb721a2d559a5b9aae8af4f8f2c79bc63fdbe8a8a6c9b23bbe/mock-1.0.1.tar.gz";
1052 md5 = "c3971991738caa55ec7c356bbc154ee2";
1053 };
1054 meta = {
1055 license = [ pkgs.lib.licenses.bsdOriginal ];
1056 };
1057 };
1058 msgpack-python = super.buildPythonPackage {
1059 name = "msgpack-python-0.4.8";
1060 buildInputs = with self; [];
1061 doCheck = false;
1062 propagatedBuildInputs = with self; [];
1063 src = fetchurl {
1064 url = "https://pypi.python.org/packages/21/27/8a1d82041c7a2a51fcc73675875a5f9ea06c2663e02fcfeb708be1d081a0/msgpack-python-0.4.8.tar.gz";
1065 md5 = "dcd854fb41ee7584ebbf35e049e6be98";
1060 url = "https://files.pythonhosted.org/packages/89/43/07d07654ee3e25235d8cea4164cdee0ec39d1fda8e9203156ebe403ffda4/pexpect-4.6.0.tar.gz";
1061 sha256 = "1fla85g47iaxxpjhp9vkxdnv4pgc7rplfy6ja491smrrk0jqi3ia";
1066 1062 };
1067 1063 meta = {
1068 license = [ pkgs.lib.licenses.asl20 ];
1069 };
1070 };
1071 nbconvert = super.buildPythonPackage {
1072 name = "nbconvert-5.3.1";
1073 buildInputs = with self; [];
1074 doCheck = false;
1075 propagatedBuildInputs = with self; [mistune Jinja2 Pygments traitlets jupyter-core nbformat entrypoints bleach pandocfilters testpath];
1076 src = fetchurl {
1077 url = "https://pypi.python.org/packages/b9/a4/d0a0938ad6f5eeb4dea4e73d255c617ef94b0b2849d51194c9bbdb838412/nbconvert-5.3.1.tar.gz";
1078 md5 = "c128d0d93d02f70a85429a383dae96d2";
1079 };
1080 meta = {
1081 license = [ pkgs.lib.licenses.bsdOriginal ];
1064 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
1082 1065 };
1083 1066 };
1084 nbformat = super.buildPythonPackage {
1085 name = "nbformat-4.4.0";
1086 buildInputs = with self; [];
1067 "pickleshare" = super.buildPythonPackage {
1068 name = "pickleshare-0.7.4";
1087 1069 doCheck = false;
1088 propagatedBuildInputs = with self; [ipython-genutils traitlets jsonschema jupyter-core];
1070 propagatedBuildInputs = [
1071 self."pathlib2"
1072 ];
1089 1073 src = fetchurl {
1090 url = "https://pypi.python.org/packages/6e/0e/160754f7ae3e984863f585a3743b0ed1702043a81245907c8fae2d537155/nbformat-4.4.0.tar.gz";
1091 md5 = "2d5f873138d9fbc2a3f9eaaebca3b8a1";
1092 };
1093 meta = {
1094 license = [ pkgs.lib.licenses.bsdOriginal ];
1095 };
1096 };
1097 objgraph = super.buildPythonPackage {
1098 name = "objgraph-3.1.1";
1099 buildInputs = with self; [];
1100 doCheck = false;
1101 propagatedBuildInputs = with self; [graphviz];
1102 src = fetchurl {
1103 url = "https://pypi.python.org/packages/be/58/9ca81a20cc837054e94866df1475d899caaa94f3732b8a46006858b015f7/objgraph-3.1.1.tar.gz";
1104 md5 = "253af9944763377877c3678d8aaebb8b";
1074 url = "https://files.pythonhosted.org/packages/69/fe/dd137d84daa0fd13a709e448138e310d9ea93070620c9db5454e234af525/pickleshare-0.7.4.tar.gz";
1075 sha256 = "0yvk14dzxk7g6qpr7iw23vzqbsr0dh4ij4xynkhnzpfz4xr2bac4";
1105 1076 };
1106 1077 meta = {
1107 1078 license = [ pkgs.lib.licenses.mit ];
1108 1079 };
1109 1080 };
1110 packaging = super.buildPythonPackage {
1111 name = "packaging-15.2";
1112 buildInputs = with self; [];
1081 "plaster" = super.buildPythonPackage {
1082 name = "plaster-1.0";
1113 1083 doCheck = false;
1114 propagatedBuildInputs = with self; [];
1084 propagatedBuildInputs = [
1085 self."setuptools"
1086 ];
1115 1087 src = fetchurl {
1116 url = "https://pypi.python.org/packages/24/c4/185da1304f07047dc9e0c46c31db75c0351bd73458ac3efad7da3dbcfbe1/packaging-15.2.tar.gz";
1117 md5 = "c16093476f6ced42128bf610e5db3784";
1088 url = "https://files.pythonhosted.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz";
1089 sha256 = "1hy8k0nv2mxq94y5aysk6hjk9ryb4bsd13g83m60hcyzxz3wflc3";
1118 1090 };
1119 1091 meta = {
1120 license = [ pkgs.lib.licenses.asl20 ];
1092 license = [ pkgs.lib.licenses.mit ];
1121 1093 };
1122 1094 };
1123 pandocfilters = super.buildPythonPackage {
1124 name = "pandocfilters-1.4.2";
1125 buildInputs = with self; [];
1095 "plaster-pastedeploy" = super.buildPythonPackage {
1096 name = "plaster-pastedeploy-0.6";
1126 1097 doCheck = false;
1127 propagatedBuildInputs = with self; [];
1098 propagatedBuildInputs = [
1099 self."pastedeploy"
1100 self."plaster"
1101 ];
1128 1102 src = fetchurl {
1129 url = "https://pypi.python.org/packages/4c/ea/236e2584af67bb6df960832731a6e5325fd4441de001767da328c33368ce/pandocfilters-1.4.2.tar.gz";
1130 md5 = "dc391791ef54c7de1572d7b46b63361f";
1103 url = "https://files.pythonhosted.org/packages/3f/e7/6a6833158d2038ec40085433308a1e164fd1dac595513f6dd556d5669bb8/plaster_pastedeploy-0.6.tar.gz";
1104 sha256 = "1bkggk18f4z2bmsmxyxabvf62znvjwbivzh880419r3ap0616cf2";
1131 1105 };
1132 1106 meta = {
1133 license = [ pkgs.lib.licenses.bsdOriginal ];
1107 license = [ pkgs.lib.licenses.mit ];
1134 1108 };
1135 1109 };
1136 pathlib2 = super.buildPythonPackage {
1137 name = "pathlib2-2.3.0";
1138 buildInputs = with self; [];
1110 "pluggy" = super.buildPythonPackage {
1111 name = "pluggy-0.6.0";
1139 1112 doCheck = false;
1140 propagatedBuildInputs = with self; [six scandir];
1141 1113 src = fetchurl {
1142 url = "https://pypi.python.org/packages/a1/14/df0deb867c2733f7d857523c10942b3d6612a1b222502fdffa9439943dfb/pathlib2-2.3.0.tar.gz";
1143 md5 = "89c90409d11fd5947966b6a30a47d18c";
1114 url = "https://files.pythonhosted.org/packages/11/bf/cbeb8cdfaffa9f2ea154a30ae31a9d04a1209312e2919138b4171a1f8199/pluggy-0.6.0.tar.gz";
1115 sha256 = "1zqckndfn85l1cd8pndw212zg1bq9fkg1nnj32kp2mppppsyg2kz";
1144 1116 };
1145 1117 meta = {
1146 1118 license = [ pkgs.lib.licenses.mit ];
1147 1119 };
1148 1120 };
1149 peppercorn = super.buildPythonPackage {
1150 name = "peppercorn-0.5";
1151 buildInputs = with self; [];
1121 "prompt-toolkit" = super.buildPythonPackage {
1122 name = "prompt-toolkit-1.0.15";
1152 1123 doCheck = false;
1153 propagatedBuildInputs = with self; [];
1124 propagatedBuildInputs = [
1125 self."six"
1126 self."wcwidth"
1127 ];
1154 1128 src = fetchurl {
1155 url = "https://pypi.python.org/packages/45/ec/a62ec317d1324a01567c5221b420742f094f05ee48097e5157d32be3755c/peppercorn-0.5.tar.gz";
1156 md5 = "f08efbca5790019ab45d76b7244abd40";
1129 url = "https://files.pythonhosted.org/packages/8a/ad/cf6b128866e78ad6d7f1dc5b7f99885fb813393d9860778b2984582e81b5/prompt_toolkit-1.0.15.tar.gz";
1130 sha256 = "05v9h5nydljwpj5nm8n804ms0glajwfy1zagrzqrg91wk3qqi1c5";
1157 1131 };
1158 1132 meta = {
1159 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1133 license = [ pkgs.lib.licenses.bsdOriginal ];
1160 1134 };
1161 1135 };
1162 pexpect = super.buildPythonPackage {
1163 name = "pexpect-4.4.0";
1164 buildInputs = with self; [];
1136 "psutil" = super.buildPythonPackage {
1137 name = "psutil-5.4.6";
1165 1138 doCheck = false;
1166 propagatedBuildInputs = with self; [ptyprocess];
1167 1139 src = fetchurl {
1168 url = "https://pypi.python.org/packages/fa/c3/60c0cbf96f242d0b47a82e9ca634dcd6dcb043832cf05e17540812e1c707/pexpect-4.4.0.tar.gz";
1169 md5 = "e9b07f0765df8245ac72201d757baaef";
1140 url = "https://files.pythonhosted.org/packages/51/9e/0f8f5423ce28c9109807024f7bdde776ed0b1161de20b408875de7e030c3/psutil-5.4.6.tar.gz";
1141 sha256 = "1xmw4qi6hnrhw81xqzkvmsm9im7j2vkk4v26ycjwq2jczqsmlvk8";
1170 1142 };
1171 1143 meta = {
1172 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
1144 license = [ pkgs.lib.licenses.bsdOriginal ];
1145 };
1146 };
1147 "psycopg2" = super.buildPythonPackage {
1148 name = "psycopg2-2.7.4";
1149 doCheck = false;
1150 src = fetchurl {
1151 url = "https://files.pythonhosted.org/packages/74/83/51580322ed0e82cba7ad8e0af590b8fb2cf11bd5aaa1ed872661bd36f462/psycopg2-2.7.4.tar.gz";
1152 sha256 = "02b2yaf1hlwb91xkscbzmajpfj5z3d8yikzh5r48fs8gss8i3xcb";
1153 };
1154 meta = {
1155 license = [ pkgs.lib.licenses.zpl21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
1173 1156 };
1174 1157 };
1175 pickleshare = super.buildPythonPackage {
1176 name = "pickleshare-0.7.4";
1177 buildInputs = with self; [];
1158 "ptyprocess" = super.buildPythonPackage {
1159 name = "ptyprocess-0.6.0";
1178 1160 doCheck = false;
1179 propagatedBuildInputs = with self; [pathlib2];
1180 1161 src = fetchurl {
1181 url = "https://pypi.python.org/packages/69/fe/dd137d84daa0fd13a709e448138e310d9ea93070620c9db5454e234af525/pickleshare-0.7.4.tar.gz";
1182 md5 = "6a9e5dd8dfc023031f6b7b3f824cab12";
1162 url = "https://files.pythonhosted.org/packages/7d/2d/e4b8733cf79b7309d84c9081a4ab558c89d8c89da5961bf4ddb050ca1ce0/ptyprocess-0.6.0.tar.gz";
1163 sha256 = "1h4lcd3w5nrxnsk436ar7fwkiy5rfn5wj2xwy9l0r4mdqnf2jgwj";
1183 1164 };
1184 1165 meta = {
1185 license = [ pkgs.lib.licenses.mit ];
1166 license = [ ];
1186 1167 };
1187 1168 };
1188 plaster = super.buildPythonPackage {
1189 name = "plaster-1.0";
1190 buildInputs = with self; [];
1169 "py" = super.buildPythonPackage {
1170 name = "py-1.5.3";
1191 1171 doCheck = false;
1192 propagatedBuildInputs = with self; [setuptools];
1193 1172 src = fetchurl {
1194 url = "https://pypi.python.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz";
1195 md5 = "80e6beb4760c16fea31754babcc0576e";
1173 url = "https://files.pythonhosted.org/packages/f7/84/b4c6e84672c4ceb94f727f3da8344037b62cee960d80e999b1cd9b832d83/py-1.5.3.tar.gz";
1174 sha256 = "10gq2lckvgwlk9w6yzijhzkarx44hsaknd0ypa08wlnpjnsgmj99";
1196 1175 };
1197 1176 meta = {
1198 1177 license = [ pkgs.lib.licenses.mit ];
1199 1178 };
1200 1179 };
1201 plaster-pastedeploy = super.buildPythonPackage {
1202 name = "plaster-pastedeploy-0.4.2";
1203 buildInputs = with self; [];
1180 "py-bcrypt" = super.buildPythonPackage {
1181 name = "py-bcrypt-0.4";
1204 1182 doCheck = false;
1205 propagatedBuildInputs = with self; [PasteDeploy plaster];
1206 1183 src = fetchurl {
1207 url = "https://pypi.python.org/packages/2c/62/0daf9c0be958e785023e583e51baac15863699e956bfb3d448898d80edd8/plaster_pastedeploy-0.4.2.tar.gz";
1208 md5 = "58fd7852002909378e818c9d5b71e90a";
1184 url = "https://files.pythonhosted.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz";
1185 sha256 = "0y6smdggwi5s72v6p1nn53dg6w05hna3d264cq6kas0lap73p8az";
1209 1186 };
1210 1187 meta = {
1211 license = [ pkgs.lib.licenses.mit ];
1188 license = [ pkgs.lib.licenses.bsdOriginal ];
1212 1189 };
1213 1190 };
1214 prompt-toolkit = super.buildPythonPackage {
1215 name = "prompt-toolkit-1.0.15";
1216 buildInputs = with self; [];
1191 "py-gfm" = super.buildPythonPackage {
1192 name = "py-gfm-0.1.3";
1217 1193 doCheck = false;
1218 propagatedBuildInputs = with self; [six wcwidth];
1194 propagatedBuildInputs = [
1195 self."setuptools"
1196 self."markdown"
1197 ];
1219 1198 src = fetchurl {
1220 url = "https://pypi.python.org/packages/8a/ad/cf6b128866e78ad6d7f1dc5b7f99885fb813393d9860778b2984582e81b5/prompt_toolkit-1.0.15.tar.gz";
1221 md5 = "8fe70295006dbc8afedd43e5eba99032";
1199 url = "https://files.pythonhosted.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
1200 sha256 = "162ggwwj0af9g3s1k8m4bfwbvis03x9pinnf35mj79pb90rf81zi";
1201 };
1202 meta = {
1203 license = [ pkgs.lib.licenses.bsdOriginal ];
1204 };
1205 };
1206 "pyasn1" = super.buildPythonPackage {
1207 name = "pyasn1-0.4.4";
1208 doCheck = false;
1209 src = fetchurl {
1210 url = "https://files.pythonhosted.org/packages/10/46/059775dc8e50f722d205452bced4b3cc965d27e8c3389156acd3b1123ae3/pyasn1-0.4.4.tar.gz";
1211 sha256 = "0drilmx5j25aplfr5wrml0030cs5fgxp9yp94fhllxgx28yjm3zm";
1222 1212 };
1223 1213 meta = {
1224 1214 license = [ pkgs.lib.licenses.bsdOriginal ];
1225 1215 };
1226 1216 };
1227 psutil = super.buildPythonPackage {
1228 name = "psutil-5.4.3";
1229 buildInputs = with self; [];
1217 "pyasn1-modules" = super.buildPythonPackage {
1218 name = "pyasn1-modules-0.2.2";
1230 1219 doCheck = false;
1231 propagatedBuildInputs = with self; [];
1220 propagatedBuildInputs = [
1221 self."pyasn1"
1222 ];
1232 1223 src = fetchurl {
1233 url = "https://pypi.python.org/packages/e2/e1/600326635f97fee89bf8426fef14c5c29f4849c79f68fd79f433d8c1bd96/psutil-5.4.3.tar.gz";
1234 md5 = "3b291833dbea631db9d271aa602a169a";
1224 url = "https://files.pythonhosted.org/packages/37/33/74ebdc52be534e683dc91faf263931bc00ae05c6073909fde53999088541/pyasn1-modules-0.2.2.tar.gz";
1225 sha256 = "0ivm850yi7ajjbi8j115qpsj95bgxdsx48nbjzg0zip788c3xkx0";
1235 1226 };
1236 1227 meta = {
1237 1228 license = [ pkgs.lib.licenses.bsdOriginal ];
1238 1229 };
1239 1230 };
1240 psycopg2 = super.buildPythonPackage {
1241 name = "psycopg2-2.7.3.2";
1242 buildInputs = with self; [];
1231 "pycrypto" = super.buildPythonPackage {
1232 name = "pycrypto-2.6.1";
1243 1233 doCheck = false;
1244 propagatedBuildInputs = with self; [];
1245 1234 src = fetchurl {
1246 url = "https://pypi.python.org/packages/dd/47/000b405d73ca22980684fd7bd3318690cc03cfa3b2ae1c5b7fff8050b28a/psycopg2-2.7.3.2.tar.gz";
1247 md5 = "8114e672d5f23fa5329874a4314fbd6f";
1235 url = "https://files.pythonhosted.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz";
1236 sha256 = "0g0ayql5b9mkjam8hym6zyg6bv77lbh66rv1fyvgqb17kfc1xkpj";
1248 1237 };
1249 1238 meta = {
1250 license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
1239 license = [ pkgs.lib.licenses.publicDomain ];
1251 1240 };
1252 1241 };
1253 ptyprocess = super.buildPythonPackage {
1254 name = "ptyprocess-0.5.2";
1255 buildInputs = with self; [];
1242 "pycurl" = super.buildPythonPackage {
1243 name = "pycurl-7.43.0.2";
1256 1244 doCheck = false;
1257 propagatedBuildInputs = with self; [];
1258 1245 src = fetchurl {
1259 url = "https://pypi.python.org/packages/51/83/5d07dc35534640b06f9d9f1a1d2bc2513fb9cc7595a1b0e28ae5477056ce/ptyprocess-0.5.2.tar.gz";
1260 md5 = "d3b8febae1b8c53b054bd818d0bb8665";
1246 url = "https://files.pythonhosted.org/packages/e8/e4/0dbb8735407189f00b33d84122b9be52c790c7c3b25286826f4e1bdb7bde/pycurl-7.43.0.2.tar.gz";
1247 sha256 = "1915kb04k1j4y6k1dx1sgnbddxrl9r1n4q928if2lkrdm73xy30g";
1261 1248 };
1262 1249 meta = {
1263 license = [ ];
1250 license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1264 1251 };
1265 1252 };
1266 py = super.buildPythonPackage {
1267 name = "py-1.5.2";
1268 buildInputs = with self; [];
1253 "pyflakes" = super.buildPythonPackage {
1254 name = "pyflakes-0.8.1";
1269 1255 doCheck = false;
1270 propagatedBuildInputs = with self; [];
1271 1256 src = fetchurl {
1272 url = "https://pypi.python.org/packages/90/e3/e075127d39d35f09a500ebb4a90afd10f9ef0a1d28a6d09abeec0e444fdd/py-1.5.2.tar.gz";
1273 md5 = "279ca69c632069e1b71e11b14641ca28";
1257 url = "https://files.pythonhosted.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
1258 sha256 = "0sbpq6pqm1i9wqi41mlfrsc5rk92jv4mskvlyxmnhlbdnc80ma1z";
1274 1259 };
1275 1260 meta = {
1276 1261 license = [ pkgs.lib.licenses.mit ];
1277 1262 };
1278 1263 };
1279 py-bcrypt = super.buildPythonPackage {
1280 name = "py-bcrypt-0.4";
1281 buildInputs = with self; [];
1264 "pygments" = super.buildPythonPackage {
1265 name = "pygments-2.2.0";
1282 1266 doCheck = false;
1283 propagatedBuildInputs = with self; [];
1284 1267 src = fetchurl {
1285 url = "https://pypi.python.org/packages/68/b1/1c3068c5c4d2e35c48b38dcc865301ebfdf45f54507086ac65ced1fd3b3d/py-bcrypt-0.4.tar.gz";
1286 md5 = "dd8b367d6b716a2ea2e72392525f4e36";
1287 };
1288 meta = {
1289 license = [ pkgs.lib.licenses.bsdOriginal ];
1290 };
1291 };
1292 py-gfm = super.buildPythonPackage {
1293 name = "py-gfm-0.1.3";
1294 buildInputs = with self; [];
1295 doCheck = false;
1296 propagatedBuildInputs = with self; [setuptools Markdown];
1297 src = fetchurl {
1298 url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
1299 md5 = "e588d9e69640a241b97e2c59c22527a6";
1268 url = "https://files.pythonhosted.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz";
1269 sha256 = "1k78qdvir1yb1c634nkv6rbga8wv4289xarghmsbbvzhvr311bnv";
1300 1270 };
1301 1271 meta = {
1302 1272 license = [ pkgs.lib.licenses.bsdOriginal ];
1303 1273 };
1304 1274 };
1305 pycrypto = super.buildPythonPackage {
1306 name = "pycrypto-2.6.1";
1307 buildInputs = with self; [];
1275 "pygments-markdown-lexer" = super.buildPythonPackage {
1276 name = "pygments-markdown-lexer-0.1.0.dev39";
1308 1277 doCheck = false;
1309 propagatedBuildInputs = with self; [];
1278 propagatedBuildInputs = [
1279 self."pygments"
1280 ];
1310 1281 src = fetchurl {
1311 url = "https://pypi.python.org/packages/60/db/645aa9af249f059cc3a368b118de33889219e0362141e75d4eaf6f80f163/pycrypto-2.6.1.tar.gz";
1312 md5 = "55a61a054aa66812daf5161a0d5d7eda";
1282 url = "https://files.pythonhosted.org/packages/c3/12/674cdee66635d638cedb2c5d9c85ce507b7b2f91bdba29e482f1b1160ff6/pygments-markdown-lexer-0.1.0.dev39.zip";
1283 sha256 = "1pzb5wy23q3fhs0rqzasjnw6hdzwjngpakb73i98cn0b8lk8q4jc";
1313 1284 };
1314 1285 meta = {
1315 license = [ pkgs.lib.licenses.publicDomain ];
1286 license = [ pkgs.lib.licenses.asl20 ];
1316 1287 };
1317 1288 };
1318 pycurl = super.buildPythonPackage {
1319 name = "pycurl-7.19.5";
1320 buildInputs = with self; [];
1289 "pymysql" = super.buildPythonPackage {
1290 name = "pymysql-0.8.1";
1321 1291 doCheck = false;
1322 propagatedBuildInputs = with self; [];
1323 1292 src = fetchurl {
1324 url = "https://pypi.python.org/packages/6c/48/13bad289ef6f4869b1d8fc11ae54de8cfb3cc4a2eb9f7419c506f763be46/pycurl-7.19.5.tar.gz";
1325 md5 = "47b4eac84118e2606658122104e62072";
1326 };
1327 meta = {
1328 license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1329 };
1330 };
1331 pyflakes = super.buildPythonPackage {
1332 name = "pyflakes-0.8.1";
1333 buildInputs = with self; [];
1334 doCheck = false;
1335 propagatedBuildInputs = with self; [];
1336 src = fetchurl {
1337 url = "https://pypi.python.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
1338 md5 = "905fe91ad14b912807e8fdc2ac2e2c23";
1293 url = "https://files.pythonhosted.org/packages/44/39/6bcb83cae0095a31b6be4511707fdf2009d3e29903a55a0494d3a9a2fac0/PyMySQL-0.8.1.tar.gz";
1294 sha256 = "0a96crz55bw4h6myh833skrli7b0ck89m3x673y2z2ryy7zrpq9l";
1339 1295 };
1340 1296 meta = {
1341 1297 license = [ pkgs.lib.licenses.mit ];
1342 1298 };
1343 1299 };
1344 pygments-markdown-lexer = super.buildPythonPackage {
1345 name = "pygments-markdown-lexer-0.1.0.dev39";
1346 buildInputs = with self; [];
1300 "pyotp" = super.buildPythonPackage {
1301 name = "pyotp-2.2.6";
1347 1302 doCheck = false;
1348 propagatedBuildInputs = with self; [Pygments];
1349 1303 src = fetchurl {
1350 url = "https://pypi.python.org/packages/c3/12/674cdee66635d638cedb2c5d9c85ce507b7b2f91bdba29e482f1b1160ff6/pygments-markdown-lexer-0.1.0.dev39.zip";
1351 md5 = "6360fe0f6d1f896e35b7a0142ce6459c";
1304 url = "https://files.pythonhosted.org/packages/67/69/131f5ad63de40c30f3be88d891e4a2ea1b69398528db99bc1e5c543422fa/pyotp-2.2.6.tar.gz";
1305 sha256 = "0sdxxvr3j4j0pk26v258jpxhgpbnpmyqhvzhl24hsd50j7fk14fx";
1352 1306 };
1353 1307 meta = {
1354 license = [ pkgs.lib.licenses.asl20 ];
1308 license = [ pkgs.lib.licenses.bsdOriginal ];
1355 1309 };
1356 1310 };
1357 pyparsing = super.buildPythonPackage {
1311 "pyparsing" = super.buildPythonPackage {
1358 1312 name = "pyparsing-1.5.7";
1359 buildInputs = with self; [];
1360 1313 doCheck = false;
1361 propagatedBuildInputs = with self; [];
1362 1314 src = fetchurl {
1363 url = "https://pypi.python.org/packages/6f/2c/47457771c02a8ff0f302b695e094ec309e30452232bd79198ee94fda689f/pyparsing-1.5.7.tar.gz";
1364 md5 = "9be0fcdcc595199c646ab317c1d9a709";
1315 url = "https://files.pythonhosted.org/packages/6f/2c/47457771c02a8ff0f302b695e094ec309e30452232bd79198ee94fda689f/pyparsing-1.5.7.tar.gz";
1316 sha256 = "17z7ws076z977sclj628fvwrp8y9j2rvdjcsq42v129n1gwi8vk4";
1365 1317 };
1366 1318 meta = {
1367 1319 license = [ pkgs.lib.licenses.mit ];
1368 1320 };
1369 1321 };
1370 pyramid = super.buildPythonPackage {
1371 name = "pyramid-1.9.1";
1372 buildInputs = with self; [];
1322 "pyramid" = super.buildPythonPackage {
1323 name = "pyramid-1.9.2";
1373 1324 doCheck = false;
1374 propagatedBuildInputs = with self; [setuptools WebOb repoze.lru zope.interface zope.deprecation venusian translationstring PasteDeploy plaster plaster-pastedeploy hupper];
1325 propagatedBuildInputs = [
1326 self."setuptools"
1327 self."webob"
1328 self."repoze.lru"
1329 self."zope.interface"
1330 self."zope.deprecation"
1331 self."venusian"
1332 self."translationstring"
1333 self."pastedeploy"
1334 self."plaster"
1335 self."plaster-pastedeploy"
1336 self."hupper"
1337 ];
1375 1338 src = fetchurl {
1376 url = "https://pypi.python.org/packages/9a/57/73447be9e7d0512d601e3f0a1fb9d7d1efb941911f49efdfe036d2826507/pyramid-1.9.1.tar.gz";
1377 md5 = "0163e19c58c2d12976a3b6fdb57e052d";
1339 url = "https://files.pythonhosted.org/packages/a0/c1/b321d07cfc4870541989ad131c86a1d593bfe802af0eca9718a0dadfb97a/pyramid-1.9.2.tar.gz";
1340 sha256 = "09drsl0346nchgxp2j7sa5hlk7mkhfld9wvbd0wicacrp26a92fg";
1378 1341 };
1379 1342 meta = {
1380 1343 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1381 1344 };
1382 1345 };
1383 pyramid-beaker = super.buildPythonPackage {
1346 "pyramid-beaker" = super.buildPythonPackage {
1384 1347 name = "pyramid-beaker-0.8";
1385 buildInputs = with self; [];
1386 1348 doCheck = false;
1387 propagatedBuildInputs = with self; [pyramid Beaker];
1349 propagatedBuildInputs = [
1350 self."pyramid"
1351 self."beaker"
1352 ];
1388 1353 src = fetchurl {
1389 url = "https://pypi.python.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
1390 md5 = "22f14be31b06549f80890e2c63a93834";
1354 url = "https://files.pythonhosted.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
1355 sha256 = "0hflx3qkcdml1mwpq53sz46s7jickpfn0zy0ns2c7j445j66bp3p";
1391 1356 };
1392 1357 meta = {
1393 1358 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1394 1359 };
1395 1360 };
1396 pyramid-debugtoolbar = super.buildPythonPackage {
1397 name = "pyramid-debugtoolbar-4.3";
1398 buildInputs = with self; [];
1361 "pyramid-debugtoolbar" = super.buildPythonPackage {
1362 name = "pyramid-debugtoolbar-4.4";
1399 1363 doCheck = false;
1400 propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress];
1364 propagatedBuildInputs = [
1365 self."pyramid"
1366 self."pyramid-mako"
1367 self."repoze.lru"
1368 self."pygments"
1369 self."ipaddress"
1370 ];
1401 1371 src = fetchurl {
1402 url = "https://pypi.python.org/packages/a4/40/f09d8800bfc3c09bdb6c95f37bb61c890dc62c19c4e7caa304da7aa77403/pyramid_debugtoolbar-4.3.tar.gz";
1403 md5 = "9c49029e9f0695130499ef6416ffaaf8";
1372 url = "https://files.pythonhosted.org/packages/00/6f/c04eb4e715a7a5a4b24079ab7ffd1dceb1f70b2e24fc17686a2922dbac0a/pyramid_debugtoolbar-4.4.tar.gz";
1373 sha256 = "17p7nxvapvy2hab1rah3ndq2kbs4v83pixj8x2n4m7008ai9lxsz";
1404 1374 };
1405 1375 meta = {
1406 1376 license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ];
1407 1377 };
1408 1378 };
1409 pyramid-jinja2 = super.buildPythonPackage {
1379 "pyramid-jinja2" = super.buildPythonPackage {
1410 1380 name = "pyramid-jinja2-2.7";
1411 buildInputs = with self; [];
1412 1381 doCheck = false;
1413 propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe];
1382 propagatedBuildInputs = [
1383 self."pyramid"
1384 self."zope.deprecation"
1385 self."jinja2"
1386 self."markupsafe"
1387 ];
1414 1388 src = fetchurl {
1415 url = "https://pypi.python.org/packages/d8/80/d60a7233823de22ce77bd864a8a83736a1fe8b49884b08303a2e68b2c853/pyramid_jinja2-2.7.tar.gz";
1416 md5 = "c2f8b2cd7b73a6f1d9a311fcfaf4fb92";
1389 url = "https://files.pythonhosted.org/packages/d8/80/d60a7233823de22ce77bd864a8a83736a1fe8b49884b08303a2e68b2c853/pyramid_jinja2-2.7.tar.gz";
1390 sha256 = "1sz5s0pp5jqhf4w22w9527yz8hgdi4mhr6apd6vw1gm5clghh8aw";
1417 1391 };
1418 1392 meta = {
1419 1393 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1420 1394 };
1421 1395 };
1422 pyramid-mako = super.buildPythonPackage {
1396 "pyramid-mako" = super.buildPythonPackage {
1423 1397 name = "pyramid-mako-1.0.2";
1424 buildInputs = with self; [];
1425 1398 doCheck = false;
1426 propagatedBuildInputs = with self; [pyramid Mako];
1399 propagatedBuildInputs = [
1400 self."pyramid"
1401 self."mako"
1402 ];
1427 1403 src = fetchurl {
1428 url = "https://pypi.python.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz";
1429 md5 = "ee25343a97eb76bd90abdc2a774eb48a";
1404 url = "https://files.pythonhosted.org/packages/f1/92/7e69bcf09676d286a71cb3bbb887b16595b96f9ba7adbdc239ffdd4b1eb9/pyramid_mako-1.0.2.tar.gz";
1405 sha256 = "18gk2vliq8z4acblsl6yzgbvnr9rlxjlcqir47km7kvlk1xri83d";
1430 1406 };
1431 1407 meta = {
1432 1408 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1433 1409 };
1434 1410 };
1435 pysqlite = super.buildPythonPackage {
1411 "pysqlite" = super.buildPythonPackage {
1436 1412 name = "pysqlite-2.8.3";
1437 buildInputs = with self; [];
1438 1413 doCheck = false;
1439 propagatedBuildInputs = with self; [];
1440 1414 src = fetchurl {
1441 url = "https://pypi.python.org/packages/42/02/981b6703e3c83c5b25a829c6e77aad059f9481b0bbacb47e6e8ca12bd731/pysqlite-2.8.3.tar.gz";
1442 md5 = "033f17b8644577715aee55e8832ac9fc";
1415 url = "https://files.pythonhosted.org/packages/42/02/981b6703e3c83c5b25a829c6e77aad059f9481b0bbacb47e6e8ca12bd731/pysqlite-2.8.3.tar.gz";
1416 sha256 = "1424gwq9sil2ffmnizk60q36vydkv8rxs6m7xs987kz8cdc37lqp";
1443 1417 };
1444 1418 meta = {
1445 1419 license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ];
1446 1420 };
1447 1421 };
1448 pytest = super.buildPythonPackage {
1449 name = "pytest-3.2.5";
1450 buildInputs = with self; [];
1422 "pytest" = super.buildPythonPackage {
1423 name = "pytest-3.6.0";
1451 1424 doCheck = false;
1452 propagatedBuildInputs = with self; [py setuptools];
1425 propagatedBuildInputs = [
1426 self."py"
1427 self."six"
1428 self."setuptools"
1429 self."attrs"
1430 self."more-itertools"
1431 self."atomicwrites"
1432 self."pluggy"
1433 self."funcsigs"
1434 ];
1453 1435 src = fetchurl {
1454 url = "https://pypi.python.org/packages/1f/f8/8cd74c16952163ce0db0bd95fdd8810cbf093c08be00e6e665ebf0dc3138/pytest-3.2.5.tar.gz";
1455 md5 = "6dbe9bb093883f75394a689a1426ac6f";
1436 url = "https://files.pythonhosted.org/packages/67/6a/5bcdc22f8dbada1d2910d6e1a3a03f6b14306c78f81122890735b28be4bf/pytest-3.6.0.tar.gz";
1437 sha256 = "0bdfazvjjbxssqzyvkb3m2x2in7xv56ipr899l00s87k7815sm9r";
1456 1438 };
1457 1439 meta = {
1458 1440 license = [ pkgs.lib.licenses.mit ];
1459 1441 };
1460 1442 };
1461 pytest-catchlog = super.buildPythonPackage {
1462 name = "pytest-catchlog-1.2.2";
1463 buildInputs = with self; [];
1443 "pytest-cov" = super.buildPythonPackage {
1444 name = "pytest-cov-2.5.1";
1464 1445 doCheck = false;
1465 propagatedBuildInputs = with self; [py pytest];
1446 propagatedBuildInputs = [
1447 self."pytest"
1448 self."coverage"
1449 ];
1466 1450 src = fetchurl {
1467 url = "https://pypi.python.org/packages/f2/2b/2faccdb1a978fab9dd0bf31cca9f6847fbe9184a0bdcc3011ac41dd44191/pytest-catchlog-1.2.2.zip";
1468 md5 = "09d890c54c7456c818102b7ff8c182c8";
1469 };
1470 meta = {
1471 license = [ pkgs.lib.licenses.mit ];
1472 };
1473 };
1474 pytest-cov = super.buildPythonPackage {
1475 name = "pytest-cov-2.5.1";
1476 buildInputs = with self; [];
1477 doCheck = false;
1478 propagatedBuildInputs = with self; [pytest coverage];
1479 src = fetchurl {
1480 url = "https://pypi.python.org/packages/24/b4/7290d65b2f3633db51393bdf8ae66309b37620bc3ec116c5e357e3e37238/pytest-cov-2.5.1.tar.gz";
1481 md5 = "5acf38d4909e19819eb5c1754fbfc0ac";
1451 url = "https://files.pythonhosted.org/packages/24/b4/7290d65b2f3633db51393bdf8ae66309b37620bc3ec116c5e357e3e37238/pytest-cov-2.5.1.tar.gz";
1452 sha256 = "0bbfpwdh9k3636bxc88vz9fa7vf4akchgn513ql1vd0xy4n7bah3";
1482 1453 };
1483 1454 meta = {
1484 1455 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ];
1485 1456 };
1486 1457 };
1487 pytest-profiling = super.buildPythonPackage {
1488 name = "pytest-profiling-1.2.11";
1489 buildInputs = with self; [];
1458 "pytest-profiling" = super.buildPythonPackage {
1459 name = "pytest-profiling-1.3.0";
1490 1460 doCheck = false;
1491 propagatedBuildInputs = with self; [six pytest gprof2dot];
1461 propagatedBuildInputs = [
1462 self."six"
1463 self."pytest"
1464 self."gprof2dot"
1465 ];
1492 1466 src = fetchurl {
1493 url = "https://pypi.python.org/packages/c0/4a/b4aa786e93c07a86f1f87c581a36bf355a9e06a9da7e00dbd05047626bd2/pytest-profiling-1.2.11.tar.gz";
1494 md5 = "9ef6b60248731be5d44477980408e8f7";
1467 url = "https://files.pythonhosted.org/packages/f5/34/4626126e041a51ef50a80d0619519b18d20aef249aac25b0d0fdd47e57ee/pytest-profiling-1.3.0.tar.gz";
1468 sha256 = "08r5afx5z22yvpmsnl91l4amsy1yxn8qsmm61mhp06mz8zjs51kb";
1495 1469 };
1496 1470 meta = {
1497 1471 license = [ pkgs.lib.licenses.mit ];
1498 1472 };
1499 1473 };
1500 pytest-runner = super.buildPythonPackage {
1501 name = "pytest-runner-3.0";
1502 buildInputs = with self; [];
1474 "pytest-runner" = super.buildPythonPackage {
1475 name = "pytest-runner-4.2";
1503 1476 doCheck = false;
1504 propagatedBuildInputs = with self; [];
1505 1477 src = fetchurl {
1506 url = "https://pypi.python.org/packages/65/b4/ae89338cd2d81e2cc54bd6db2e962bfe948f612303610d68ab24539ac2d1/pytest-runner-3.0.tar.gz";
1507 md5 = "8f8363a52bbabc4cedd5e239beb2ba11";
1478 url = "https://files.pythonhosted.org/packages/9e/b7/fe6e8f87f9a756fd06722216f1b6698ccba4d269eac6329d9f0c441d0f93/pytest-runner-4.2.tar.gz";
1479 sha256 = "1gkpyphawxz38ni1gdq1fmwyqcg02m7ypzqvv46z06crwdxi2gyj";
1508 1480 };
1509 1481 meta = {
1510 1482 license = [ pkgs.lib.licenses.mit ];
1511 1483 };
1512 1484 };
1513 pytest-sugar = super.buildPythonPackage {
1514 name = "pytest-sugar-0.9.0";
1515 buildInputs = with self; [];
1485 "pytest-sugar" = super.buildPythonPackage {
1486 name = "pytest-sugar-0.9.1";
1516 1487 doCheck = false;
1517 propagatedBuildInputs = with self; [pytest termcolor];
1488 propagatedBuildInputs = [
1489 self."pytest"
1490 self."termcolor"
1491 ];
1518 1492 src = fetchurl {
1519 url = "https://pypi.python.org/packages/49/d8/c5ff6cca3ce2ebd8b73eec89779bf6b4a7737456a70e8ea4d44c1ff90f71/pytest-sugar-0.9.0.tar.gz";
1520 md5 = "89fbff17277fa6a95a560a04b68cb9f9";
1493 url = "https://files.pythonhosted.org/packages/3e/6a/a3f909083079d03bde11d06ab23088886bbe25f2c97fbe4bb865e2bf05bc/pytest-sugar-0.9.1.tar.gz";
1494 sha256 = "0b4av40dv30727m54v211r0nzwjp2ajkjgxix6j484qjmwpw935b";
1521 1495 };
1522 1496 meta = {
1523 1497 license = [ pkgs.lib.licenses.bsdOriginal ];
1524 1498 };
1525 1499 };
1526 pytest-timeout = super.buildPythonPackage {
1527 name = "pytest-timeout-1.2.0";
1528 buildInputs = with self; [];
1500 "pytest-timeout" = super.buildPythonPackage {
1501 name = "pytest-timeout-1.2.1";
1529 1502 doCheck = false;
1530 propagatedBuildInputs = with self; [pytest];
1503 propagatedBuildInputs = [
1504 self."pytest"
1505 ];
1531 1506 src = fetchurl {
1532 url = "https://pypi.python.org/packages/cc/b7/b2a61365ea6b6d2e8881360ae7ed8dad0327ad2df89f2f0be4a02304deb2/pytest-timeout-1.2.0.tar.gz";
1533 md5 = "83607d91aa163562c7ee835da57d061d";
1507 url = "https://files.pythonhosted.org/packages/be/e9/a9106b8bc87521c6813060f50f7d1fdc15665bc1bbbe71c0ffc1c571aaa2/pytest-timeout-1.2.1.tar.gz";
1508 sha256 = "1kdp6qbh5v1168l99rba5yfzvy05gmzkmkhldgp36p9xcdjd5dv8";
1534 1509 };
1535 1510 meta = {
1536 1511 license = [ pkgs.lib.licenses.mit { fullName = "DFSG approved"; } ];
1537 1512 };
1538 1513 };
1539 python-dateutil = super.buildPythonPackage {
1540 name = "python-dateutil-2.6.1";
1541 buildInputs = with self; [];
1514 "python-dateutil" = super.buildPythonPackage {
1515 name = "python-dateutil-2.7.3";
1542 1516 doCheck = false;
1543 propagatedBuildInputs = with self; [six];
1517 propagatedBuildInputs = [
1518 self."six"
1519 ];
1544 1520 src = fetchurl {
1545 url = "https://pypi.python.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz";
1546 md5 = "db38f6b4511cefd76014745bb0cc45a4";
1521 url = "https://files.pythonhosted.org/packages/a0/b0/a4e3241d2dee665fea11baec21389aec6886655cd4db7647ddf96c3fad15/python-dateutil-2.7.3.tar.gz";
1522 sha256 = "1f7h54lg0w2ckch7592xpjkh8dg87k2br256h0iw49zn6bg02w72";
1547 1523 };
1548 1524 meta = {
1549 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "Simplified BSD"; } ];
1525 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.asl20 { fullName = "Dual License"; } ];
1550 1526 };
1551 1527 };
1552 python-editor = super.buildPythonPackage {
1528 "python-editor" = super.buildPythonPackage {
1553 1529 name = "python-editor-1.0.3";
1554 buildInputs = with self; [];
1555 1530 doCheck = false;
1556 propagatedBuildInputs = with self; [];
1557 1531 src = fetchurl {
1558 url = "https://pypi.python.org/packages/65/1e/adf6e000ea5dc909aa420352d6ba37f16434c8a3c2fa030445411a1ed545/python-editor-1.0.3.tar.gz";
1559 md5 = "0aca5f2ef176ce68e98a5b7e31372835";
1532 url = "https://files.pythonhosted.org/packages/65/1e/adf6e000ea5dc909aa420352d6ba37f16434c8a3c2fa030445411a1ed545/python-editor-1.0.3.tar.gz";
1533 sha256 = "0rf5xz8vw93v7mhdcvind7fkykipzga430wkcd7wk892xsn6dh53";
1560 1534 };
1561 1535 meta = {
1562 1536 license = [ pkgs.lib.licenses.asl20 { fullName = "Apache"; } ];
1563 1537 };
1564 1538 };
1565 python-ldap = super.buildPythonPackage {
1566 name = "python-ldap-2.4.45";
1567 buildInputs = with self; [];
1539 "python-ldap" = super.buildPythonPackage {
1540 name = "python-ldap-3.1.0";
1568 1541 doCheck = false;
1569 propagatedBuildInputs = with self; [setuptools];
1542 propagatedBuildInputs = [
1543 self."pyasn1"
1544 self."pyasn1-modules"
1545 ];
1570 1546 src = fetchurl {
1571 url = "https://pypi.python.org/packages/ce/52/6b5372d0166820f4a4b0a88ed73dc7504219355049fc1d266d8ccdb7942e/python-ldap-2.4.45.tar.gz";
1572 md5 = "6108e189a44eea8bc7d1cc281c222978";
1573 };
1574 meta = {
1575 license = [ pkgs.lib.licenses.psfl ];
1576 };
1577 };
1578 python-memcached = super.buildPythonPackage {
1579 name = "python-memcached-1.58";
1580 buildInputs = with self; [];
1581 doCheck = false;
1582 propagatedBuildInputs = with self; [six];
1583 src = fetchurl {
1584 url = "https://pypi.python.org/packages/f7/62/14b2448cfb04427366f24104c9da97cf8ea380d7258a3233f066a951a8d8/python-memcached-1.58.tar.gz";
1585 md5 = "23b258105013d14d899828d334e6b044";
1547 url = "https://files.pythonhosted.org/packages/7f/1c/28d721dff2fcd2fef9d55b40df63a00be26ec8a11e8c6fc612ae642f9cfd/python-ldap-3.1.0.tar.gz";
1548 sha256 = "1i97nwfnraylyn0myxlf3vciicrf5h6fymrcff9c00k581wmx5s1";
1586 1549 };
1587 1550 meta = {
1588 1551 license = [ pkgs.lib.licenses.psfl ];
1589 1552 };
1590 1553 };
1591 python-pam = super.buildPythonPackage {
1592 name = "python-pam-1.8.2";
1593 buildInputs = with self; [];
1594 doCheck = false;
1595 propagatedBuildInputs = with self; [];
1596 src = fetchurl {
1597 url = "https://pypi.python.org/packages/de/8c/f8f5d38b4f26893af267ea0b39023d4951705ab0413a39e0cf7cf4900505/python-pam-1.8.2.tar.gz";
1598 md5 = "db71b6b999246fb05d78ecfbe166629d";
1599 };
1600 meta = {
1601 license = [ { fullName = "License :: OSI Approved :: MIT License"; } pkgs.lib.licenses.mit ];
1602 };
1603 };
1604 pytz = super.buildPythonPackage {
1605 name = "pytz-2018.3";
1606 buildInputs = with self; [];
1607 doCheck = false;
1608 propagatedBuildInputs = with self; [];
1609 src = fetchurl {
1610 url = "https://pypi.python.org/packages/1b/50/4cdc62fc0753595fc16c8f722a89740f487c6e5670c644eb8983946777be/pytz-2018.3.tar.gz";
1611 md5 = "abb07c09c79f78d7c04f222a550c99ef";
1612 };
1613 meta = {
1614 license = [ pkgs.lib.licenses.mit ];
1615 };
1616 };
1617 pyzmq = super.buildPythonPackage {
1618 name = "pyzmq-14.6.0";
1619 buildInputs = with self; [];
1620 doCheck = false;
1621 propagatedBuildInputs = with self; [];
1622 src = fetchurl {
1623 url = "https://pypi.python.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz";
1624 md5 = "395b5de95a931afa5b14c9349a5b8024";
1625 };
1626 meta = {
1627 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1628 };
1629 };
1630 redis = super.buildPythonPackage {
1631 name = "redis-2.10.6";
1632 buildInputs = with self; [];
1554 "python-memcached" = super.buildPythonPackage {
1555 name = "python-memcached-1.59";
1633 1556 doCheck = false;
1634 propagatedBuildInputs = with self; [];
1635 src = fetchurl {
1636 url = "https://pypi.python.org/packages/09/8d/6d34b75326bf96d4139a2ddd8e74b80840f800a0a79f9294399e212cb9a7/redis-2.10.6.tar.gz";
1637 md5 = "048348d8cfe0b5d0bba2f4d835005c3b";
1638 };
1639 meta = {
1640 license = [ pkgs.lib.licenses.mit ];
1641 };
1642 };
1643 repoze.lru = super.buildPythonPackage {
1644 name = "repoze.lru-0.7";
1645 buildInputs = with self; [];
1646 doCheck = false;
1647 propagatedBuildInputs = with self; [];
1648 src = fetchurl {
1649 url = "https://pypi.python.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz";
1650 md5 = "c08cc030387e0b1fc53c5c7d964b35e2";
1651 };
1652 meta = {
1653 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1654 };
1655 };
1656 requests = super.buildPythonPackage {
1657 name = "requests-2.9.1";
1658 buildInputs = with self; [];
1659 doCheck = false;
1660 propagatedBuildInputs = with self; [];
1661 src = fetchurl {
1662 url = "https://pypi.python.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz";
1663 md5 = "0b7f480d19012ec52bab78292efd976d";
1664 };
1665 meta = {
1666 license = [ pkgs.lib.licenses.asl20 ];
1667 };
1668 };
1669 rhodecode-enterprise-ce = super.buildPythonPackage {
1670 name = "rhodecode-enterprise-ce-4.12.4";
1671 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
1672 doCheck = true;
1673 propagatedBuildInputs = with self; [setuptools-scm amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz tzlocal pyzmq py-gfm redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 supervisor Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
1674 src = ./.;
1675 meta = {
1676 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1677 };
1678 };
1679 rhodecode-tools = super.buildPythonPackage {
1680 name = "rhodecode-tools-0.14.1";
1681 buildInputs = with self; [];
1682 doCheck = false;
1683 propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh];
1684 src = fetchurl {
1685 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2";
1686 md5 = "0b9c2caad160b68889f8172ea54af7b2";
1687 };
1688 meta = {
1689 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1690 };
1691 };
1692 scandir = super.buildPythonPackage {
1693 name = "scandir-1.7";
1694 buildInputs = with self; [];
1695 doCheck = false;
1696 propagatedBuildInputs = with self; [];
1557 propagatedBuildInputs = [
1558 self."six"
1559 ];
1697 1560 src = fetchurl {
1698 url = "https://pypi.python.org/packages/13/bb/e541b74230bbf7a20a3949a2ee6631be299378a784f5445aa5d0047c192b/scandir-1.7.tar.gz";
1699 md5 = "037e5f24d1a0e78b17faca72dea9555f";
1700 };
1701 meta = {
1702 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
1703 };
1704 };
1705 setproctitle = super.buildPythonPackage {
1706 name = "setproctitle-1.1.10";
1707 buildInputs = with self; [];
1708 doCheck = false;
1709 propagatedBuildInputs = with self; [];
1710 src = fetchurl {
1711 url = "https://pypi.python.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz";
1712 md5 = "2dcdd1b761700a5a13252fea3dfd1977";
1713 };
1714 meta = {
1715 license = [ pkgs.lib.licenses.bsdOriginal ];
1716 };
1717 };
1718 setuptools = super.buildPythonPackage {
1719 name = "setuptools-30.1.0";
1720 buildInputs = with self; [];
1721 doCheck = false;
1722 propagatedBuildInputs = with self; [];
1723 src = fetchurl {
1724 url = "https://pypi.python.org/packages/1e/43/002c8616db9a3e7be23c2556e39b90a32bb40ba0dc652de1999d5334d372/setuptools-30.1.0.tar.gz";
1725 md5 = "cac497f42e5096ac8df29e38d3f81c3e";
1726 };
1727 meta = {
1728 license = [ pkgs.lib.licenses.mit ];
1729 };
1730 };
1731 setuptools-scm = super.buildPythonPackage {
1732 name = "setuptools-scm-1.15.6";
1733 buildInputs = with self; [];
1734 doCheck = false;
1735 propagatedBuildInputs = with self; [];
1736 src = fetchurl {
1737 url = "https://pypi.python.org/packages/03/6d/aafdd01edd227ee879b691455bf19895091872af7e48192bea1758c82032/setuptools_scm-1.15.6.tar.gz";
1738 md5 = "f17493d53f0d842bb0152f214775640b";
1739 };
1740 meta = {
1741 license = [ pkgs.lib.licenses.mit ];
1742 };
1743 };
1744 simplegeneric = super.buildPythonPackage {
1745 name = "simplegeneric-0.8.1";
1746 buildInputs = with self; [];
1747 doCheck = false;
1748 propagatedBuildInputs = with self; [];
1749 src = fetchurl {
1750 url = "https://pypi.python.org/packages/3d/57/4d9c9e3ae9a255cd4e1106bb57e24056d3d0709fc01b2e3e345898e49d5b/simplegeneric-0.8.1.zip";
1751 md5 = "f9c1fab00fd981be588fc32759f474e3";
1752 };
1753 meta = {
1754 license = [ pkgs.lib.licenses.zpt21 ];
1755 };
1756 };
1757 simplejson = super.buildPythonPackage {
1758 name = "simplejson-3.11.1";
1759 buildInputs = with self; [];
1760 doCheck = false;
1761 propagatedBuildInputs = with self; [];
1762 src = fetchurl {
1763 url = "https://pypi.python.org/packages/08/48/c97b668d6da7d7bebe7ea1817a6f76394b0ec959cb04214ca833c34359df/simplejson-3.11.1.tar.gz";
1764 md5 = "6e2f1bd5fb0a926facf5d89d217a7183";
1765 };
1766 meta = {
1767 license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ];
1768 };
1769 };
1770 six = super.buildPythonPackage {
1771 name = "six-1.11.0";
1772 buildInputs = with self; [];
1773 doCheck = false;
1774 propagatedBuildInputs = with self; [];
1775 src = fetchurl {
1776 url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
1777 md5 = "d12789f9baf7e9fb2524c0c64f1773f8";
1778 };
1779 meta = {
1780 license = [ pkgs.lib.licenses.mit ];
1781 };
1782 };
1783 sshpubkeys = super.buildPythonPackage {
1784 name = "sshpubkeys-2.2.0";
1785 buildInputs = with self; [];
1786 doCheck = false;
1787 propagatedBuildInputs = with self; [pycrypto ecdsa];
1788 src = fetchurl {
1789 url = "https://pypi.python.org/packages/27/da/337fabeb3dca6b62039a93ceaa636f25065e0ae92b575b1235342076cf0a/sshpubkeys-2.2.0.tar.gz";
1790 md5 = "458e45f6b92b1afa84f0ffe1f1c90935";
1791 };
1792 meta = {
1793 license = [ pkgs.lib.licenses.bsdOriginal ];
1794 };
1795 };
1796 subprocess32 = super.buildPythonPackage {
1797 name = "subprocess32-3.2.7";
1798 buildInputs = with self; [];
1799 doCheck = false;
1800 propagatedBuildInputs = with self; [];
1801 src = fetchurl {
1802 url = "https://pypi.python.org/packages/b8/2f/49e53b0d0e94611a2dc624a1ad24d41b6d94d0f1b0a078443407ea2214c2/subprocess32-3.2.7.tar.gz";
1803 md5 = "824c801e479d3e916879aae3e9c15e16";
1561 url = "https://files.pythonhosted.org/packages/90/59/5faf6e3cd8a568dd4f737ddae4f2e54204fd8c51f90bf8df99aca6c22318/python-memcached-1.59.tar.gz";
1562 sha256 = "0kvyapavbirk2x3n1jx4yb9nyigrj1s3x15nm3qhpvhkpqvqdqm2";
1804 1563 };
1805 1564 meta = {
1806 1565 license = [ pkgs.lib.licenses.psfl ];
1807 1566 };
1808 1567 };
1809 supervisor = super.buildPythonPackage {
1810 name = "supervisor-3.3.4";
1811 buildInputs = with self; [];
1568 "python-pam" = super.buildPythonPackage {
1569 name = "python-pam-1.8.4";
1812 1570 doCheck = false;
1813 propagatedBuildInputs = with self; [meld3];
1814 1571 src = fetchurl {
1815 url = "https://pypi.python.org/packages/44/60/698e54b4a4a9b956b2d709b4b7b676119c833d811d53ee2500f1b5e96dc3/supervisor-3.3.4.tar.gz";
1816 md5 = "f1814d71d820ddfa8c86d46a72314cec";
1572 url = "https://files.pythonhosted.org/packages/01/16/544d01cae9f28e0292dbd092b6b8b0bf222b528f362ee768a5bed2140111/python-pam-1.8.4.tar.gz";
1573 sha256 = "16whhc0vr7gxsbzvsnq65nq8fs3wwmx755cavm8kkczdkz4djmn8";
1574 };
1575 meta = {
1576 license = [ { fullName = "License :: OSI Approved :: MIT License"; } pkgs.lib.licenses.mit ];
1577 };
1578 };
1579 "pytz" = super.buildPythonPackage {
1580 name = "pytz-2018.4";
1581 doCheck = false;
1582 src = fetchurl {
1583 url = "https://files.pythonhosted.org/packages/10/76/52efda4ef98e7544321fd8d5d512e11739c1df18b0649551aeccfb1c8376/pytz-2018.4.tar.gz";
1584 sha256 = "0jgpqx3kk2rhv81j1izjxvmx8d0x7hzs1857pgqnixic5wq2ar60";
1817 1585 };
1818 1586 meta = {
1819 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1587 license = [ pkgs.lib.licenses.mit ];
1820 1588 };
1821 1589 };
1822 termcolor = super.buildPythonPackage {
1823 name = "termcolor-1.1.0";
1824 buildInputs = with self; [];
1590 "pyzmq" = super.buildPythonPackage {
1591 name = "pyzmq-14.6.0";
1825 1592 doCheck = false;
1826 propagatedBuildInputs = with self; [];
1827 1593 src = fetchurl {
1828 url = "https://pypi.python.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
1829 md5 = "043e89644f8909d462fbbfa511c768df";
1594 url = "https://files.pythonhosted.org/packages/8a/3b/5463d5a9d712cd8bbdac335daece0d69f6a6792da4e3dd89956c0db4e4e6/pyzmq-14.6.0.tar.gz";
1595 sha256 = "1frmbjykvhmdg64g7sn20c9fpamrsfxwci1nhhg8q7jgz5pq0ikp";
1596 };
1597 meta = {
1598 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "LGPL+BSD"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
1599 };
1600 };
1601 "redis" = super.buildPythonPackage {
1602 name = "redis-2.10.6";
1603 doCheck = false;
1604 src = fetchurl {
1605 url = "https://files.pythonhosted.org/packages/09/8d/6d34b75326bf96d4139a2ddd8e74b80840f800a0a79f9294399e212cb9a7/redis-2.10.6.tar.gz";
1606 sha256 = "03vcgklykny0g0wpvqmy8p6azi2s078317wgb2xjv5m2rs9sjb52";
1830 1607 };
1831 1608 meta = {
1832 1609 license = [ pkgs.lib.licenses.mit ];
1833 1610 };
1834 1611 };
1835 testpath = super.buildPythonPackage {
1836 name = "testpath-0.3.1";
1837 buildInputs = with self; [];
1612 "repoze.lru" = super.buildPythonPackage {
1613 name = "repoze.lru-0.7";
1614 doCheck = false;
1615 src = fetchurl {
1616 url = "https://files.pythonhosted.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz";
1617 sha256 = "0xzz1aw2smy8hdszrq8yhnklx6w1r1mf55061kalw3iq35gafa84";
1618 };
1619 meta = {
1620 license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1621 };
1622 };
1623 "requests" = super.buildPythonPackage {
1624 name = "requests-2.9.1";
1838 1625 doCheck = false;
1839 propagatedBuildInputs = with self; [];
1840 1626 src = fetchurl {
1841 url = "https://pypi.python.org/packages/f4/8b/b71e9ee10e5f751e9d959bc750ab122ba04187f5aa52aabdc4e63b0e31a7/testpath-0.3.1.tar.gz";
1842 md5 = "2cd5ed5522fda781bb497c9d80ae2fc9";
1627 url = "https://files.pythonhosted.org/packages/f9/6d/07c44fb1ebe04d069459a189e7dab9e4abfe9432adcd4477367c25332748/requests-2.9.1.tar.gz";
1628 sha256 = "0zsqrzlybf25xscgi7ja4s48y2abf9wvjkn47wh984qgs1fq2xy5";
1629 };
1630 meta = {
1631 license = [ pkgs.lib.licenses.asl20 ];
1632 };
1633 };
1634 "rhodecode-enterprise-ce" = super.buildPythonPackage {
1635 name = "rhodecode-enterprise-ce-4.13.0";
1636 buildInputs = [
1637 self."pytest"
1638 self."py"
1639 self."pytest-cov"
1640 self."pytest-sugar"
1641 self."pytest-runner"
1642 self."pytest-profiling"
1643 self."gprof2dot"
1644 self."pytest-timeout"
1645 self."mock"
1646 self."webtest"
1647 self."cov-core"
1648 self."coverage"
1649 self."configobj"
1650 ];
1651 doCheck = true;
1652 propagatedBuildInputs = [
1653 self."setuptools-scm"
1654 self."amqp"
1655 self."authomatic"
1656 self."babel"
1657 self."beaker"
1658 self."celery"
1659 self."chameleon"
1660 self."channelstream"
1661 self."click"
1662 self."colander"
1663 self."configobj"
1664 self."cssselect"
1665 self."decorator"
1666 self."deform"
1667 self."docutils"
1668 self."dogpile.cache"
1669 self."dogpile.core"
1670 self."ecdsa"
1671 self."formencode"
1672 self."future"
1673 self."futures"
1674 self."gnureadline"
1675 self."infrae.cache"
1676 self."iso8601"
1677 self."itsdangerous"
1678 self."jinja2"
1679 self."billiard"
1680 self."kombu"
1681 self."lxml"
1682 self."mako"
1683 self."markdown"
1684 self."markupsafe"
1685 self."msgpack-python"
1686 self."mysql-python"
1687 self."pymysql"
1688 self."pyotp"
1689 self."objgraph"
1690 self."packaging"
1691 self."paste"
1692 self."pastedeploy"
1693 self."pastescript"
1694 self."pathlib2"
1695 self."peppercorn"
1696 self."psutil"
1697 self."psycopg2"
1698 self."py-bcrypt"
1699 self."pycrypto"
1700 self."pycurl"
1701 self."pyflakes"
1702 self."pygments-markdown-lexer"
1703 self."pygments"
1704 self."pyparsing"
1705 self."pyramid-beaker"
1706 self."pyramid-debugtoolbar"
1707 self."pyramid-jinja2"
1708 self."pyramid-mako"
1709 self."pyramid"
1710 self."pysqlite"
1711 self."python-dateutil"
1712 self."python-ldap"
1713 self."python-memcached"
1714 self."python-pam"
1715 self."pytz"
1716 self."tzlocal"
1717 self."pyzmq"
1718 self."py-gfm"
1719 self."redis"
1720 self."repoze.lru"
1721 self."requests"
1722 self."routes"
1723 self."setproctitle"
1724 self."simplejson"
1725 self."six"
1726 self."sqlalchemy"
1727 self."sshpubkeys"
1728 self."subprocess32"
1729 self."supervisor"
1730 self."tempita"
1731 self."translationstring"
1732 self."trollius"
1733 self."urllib3"
1734 self."urlobject"
1735 self."venusian"
1736 self."weberror"
1737 self."webhelpers2"
1738 self."webhelpers"
1739 self."webob"
1740 self."whoosh"
1741 self."wsgiref"
1742 self."zope.cachedescriptors"
1743 self."zope.deprecation"
1744 self."zope.event"
1745 self."zope.interface"
1746 self."nbconvert"
1747 self."bleach"
1748 self."nbformat"
1749 self."jupyter-client"
1750 self."alembic"
1751 self."invoke"
1752 self."bumpversion"
1753 self."gevent"
1754 self."greenlet"
1755 self."gunicorn"
1756 self."waitress"
1757 self."ipdb"
1758 self."ipython"
1759 self."cprofilev"
1760 self."bottle"
1761 self."rhodecode-tools"
1762 self."appenlight-client"
1763 self."pytest"
1764 self."py"
1765 self."pytest-cov"
1766 self."pytest-sugar"
1767 self."pytest-runner"
1768 self."pytest-profiling"
1769 self."gprof2dot"
1770 self."pytest-timeout"
1771 self."mock"
1772 self."webtest"
1773 self."cov-core"
1774 self."coverage"
1775 ];
1776 src = ./.;
1777 meta = {
1778 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
1779 };
1780 };
1781 "rhodecode-tools" = super.buildPythonPackage {
1782 name = "rhodecode-tools-0.16.0";
1783 doCheck = false;
1784 propagatedBuildInputs = [
1785 self."click"
1786 self."future"
1787 self."six"
1788 self."mako"
1789 self."markupsafe"
1790 self."requests"
1791 self."elasticsearch"
1792 self."elasticsearch-dsl"
1793 self."urllib3"
1794 self."whoosh"
1795 ];
1796 src = fetchurl {
1797 url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.16.0.tar.gz?md5=87f81286b49156c2ac36f1a1acfa2164";
1798 sha256 = "00xcc2mj99lx9d0ksml0p2xrd00kf5ypwyigg58cc9j9bznx7mzr";
1799 };
1800 meta = {
1801 license = [ { fullName = "AGPLv3 and Proprietary"; } ];
1802 };
1803 };
1804 "routes" = super.buildPythonPackage {
1805 name = "routes-2.4.1";
1806 doCheck = false;
1807 propagatedBuildInputs = [
1808 self."six"
1809 self."repoze.lru"
1810 ];
1811 src = fetchurl {
1812 url = "https://files.pythonhosted.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz";
1813 sha256 = "1zamff3m0kc4vyfniyhxpkkcqv1rrgnmh37ykxv34nna1ws47vi6";
1843 1814 };
1844 1815 meta = {
1845 1816 license = [ pkgs.lib.licenses.mit ];
1846 1817 };
1847 1818 };
1848 traitlets = super.buildPythonPackage {
1849 name = "traitlets-4.3.2";
1850 buildInputs = with self; [];
1819 "scandir" = super.buildPythonPackage {
1820 name = "scandir-1.9.0";
1851 1821 doCheck = false;
1852 propagatedBuildInputs = with self; [ipython-genutils six decorator enum34];
1853 1822 src = fetchurl {
1854 url = "https://pypi.python.org/packages/a5/98/7f5ef2fe9e9e071813aaf9cb91d1a732e0a68b6c44a32b38cb8e14c3f069/traitlets-4.3.2.tar.gz";
1855 md5 = "3068663f2f38fd939a9eb3a500ccc154";
1823 url = "https://files.pythonhosted.org/packages/16/2a/557af1181e6b4e30254d5a6163b18f5053791ca66e251e77ab08887e8fe3/scandir-1.9.0.tar.gz";
1824 sha256 = "0r3hvf1a9jm1rkqgx40gxkmccknkaiqjavs8lccgq9s8khh5x5s4";
1825 };
1826 meta = {
1827 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
1828 };
1829 };
1830 "setproctitle" = super.buildPythonPackage {
1831 name = "setproctitle-1.1.10";
1832 doCheck = false;
1833 src = fetchurl {
1834 url = "https://files.pythonhosted.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz";
1835 sha256 = "163kplw9dcrw0lffq1bvli5yws3rngpnvrxrzdw89pbphjjvg0v2";
1856 1836 };
1857 1837 meta = {
1858 1838 license = [ pkgs.lib.licenses.bsdOriginal ];
1859 1839 };
1860 1840 };
1861 transifex-client = super.buildPythonPackage {
1862 name = "transifex-client-0.12.5";
1863 buildInputs = with self; [];
1841 "setuptools" = super.buildPythonPackage {
1842 name = "setuptools-40.1.0";
1864 1843 doCheck = false;
1865 propagatedBuildInputs = with self; [urllib3 six];
1866 1844 src = fetchurl {
1867 url = "https://pypi.python.org/packages/7b/86/60f31a0c9b8d0b1266ce15b6c80b55f88522140c8acfc395d5aec5e23475/transifex-client-0.12.5.tar.gz";
1868 md5 = "e6e278117b23f60702c06e203b7e51ae";
1869 };
1870 meta = {
1871 license = [ pkgs.lib.licenses.gpl2 ];
1872 };
1873 };
1874 translationstring = super.buildPythonPackage {
1875 name = "translationstring-1.3";
1876 buildInputs = with self; [];
1877 doCheck = false;
1878 propagatedBuildInputs = with self; [];
1879 src = fetchurl {
1880 url = "https://pypi.python.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
1881 md5 = "a4b62e0f3c189c783a1685b3027f7c90";
1845 url = "https://files.pythonhosted.org/packages/5a/df/b2e3d9693bb0dcbeac516a73dd7a9eb82b126ae52e4a74605a9b01beddd5/setuptools-40.1.0.zip";
1846 sha256 = "0w1blx5ajga5y15dci0mddk49cf2xpq0mp7rp7jrqr2diqk00ib6";
1882 1847 };
1883 1848 meta = {
1884 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
1849 license = [ pkgs.lib.licenses.mit ];
1885 1850 };
1886 1851 };
1887 trollius = super.buildPythonPackage {
1888 name = "trollius-1.0.4";
1889 buildInputs = with self; [];
1852 "setuptools-scm" = super.buildPythonPackage {
1853 name = "setuptools-scm-2.1.0";
1890 1854 doCheck = false;
1891 propagatedBuildInputs = with self; [futures];
1892 1855 src = fetchurl {
1893 url = "https://pypi.python.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz";
1894 md5 = "3631a464d49d0cbfd30ab2918ef2b783";
1895 };
1896 meta = {
1897 license = [ pkgs.lib.licenses.asl20 ];
1898 };
1899 };
1900 tzlocal = super.buildPythonPackage {
1901 name = "tzlocal-1.5.1";
1902 buildInputs = with self; [];
1903 doCheck = false;
1904 propagatedBuildInputs = with self; [pytz];
1905 src = fetchurl {
1906 url = "https://pypi.python.org/packages/cb/89/e3687d3ed99bc882793f82634e9824e62499fdfdc4b1ae39e211c5b05017/tzlocal-1.5.1.tar.gz";
1907 md5 = "4553be891efa0812c4adfb0c6e818eec";
1856 url = "https://files.pythonhosted.org/packages/e5/62/f9e1ac314464eb5945c97542acb6bf6f3381dfa5d7a658de7730c36f31a1/setuptools_scm-2.1.0.tar.gz";
1857 sha256 = "0yb364cgk15sfw3x8ln4ssh98z1dj6n8iiz4r2rw1cfsxhgi8rx7";
1908 1858 };
1909 1859 meta = {
1910 1860 license = [ pkgs.lib.licenses.mit ];
1911 1861 };
1912 1862 };
1913 uWSGI = super.buildPythonPackage {
1914 name = "uWSGI-2.0.15";
1915 buildInputs = with self; [];
1863 "simplegeneric" = super.buildPythonPackage {
1864 name = "simplegeneric-0.8.1";
1916 1865 doCheck = false;
1917 propagatedBuildInputs = with self; [];
1918 1866 src = fetchurl {
1919 url = "https://pypi.python.org/packages/bb/0a/45e5aa80dc135889594bb371c082d20fb7ee7303b174874c996888cc8511/uwsgi-2.0.15.tar.gz";
1920 md5 = "fc50bd9e83b7602fa474b032167010a7";
1867 url = "https://files.pythonhosted.org/packages/3d/57/4d9c9e3ae9a255cd4e1106bb57e24056d3d0709fc01b2e3e345898e49d5b/simplegeneric-0.8.1.zip";
1868 sha256 = "0wwi1c6md4vkbcsfsf8dklf3vr4mcdj4mpxkanwgb6jb1432x5yw";
1869 };
1870 meta = {
1871 license = [ pkgs.lib.licenses.zpl21 ];
1872 };
1873 };
1874 "simplejson" = super.buildPythonPackage {
1875 name = "simplejson-3.11.1";
1876 doCheck = false;
1877 src = fetchurl {
1878 url = "https://files.pythonhosted.org/packages/08/48/c97b668d6da7d7bebe7ea1817a6f76394b0ec959cb04214ca833c34359df/simplejson-3.11.1.tar.gz";
1879 sha256 = "1rr58dppsq73p0qcd9bsw066cdd3v63sqv7j6sqni8frvm4jv8h1";
1921 1880 };
1922 1881 meta = {
1923 license = [ pkgs.lib.licenses.gpl2 ];
1882 license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ];
1924 1883 };
1925 1884 };
1926 urllib3 = super.buildPythonPackage {
1927 name = "urllib3-1.16";
1928 buildInputs = with self; [];
1885 "six" = super.buildPythonPackage {
1886 name = "six-1.11.0";
1929 1887 doCheck = false;
1930 propagatedBuildInputs = with self; [];
1931 1888 src = fetchurl {
1932 url = "https://pypi.python.org/packages/3b/f0/e763169124e3f5db0926bc3dbfcd580a105f9ca44cf5d8e6c7a803c9f6b5/urllib3-1.16.tar.gz";
1933 md5 = "fcaab1c5385c57deeb7053d3d7d81d59";
1889 url = "https://files.pythonhosted.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz";
1890 sha256 = "1scqzwc51c875z23phj48gircqjgnn3af8zy2izjwmnlxrxsgs3h";
1891 };
1892 meta = {
1893 license = [ pkgs.lib.licenses.mit ];
1894 };
1895 };
1896 "sqlalchemy" = super.buildPythonPackage {
1897 name = "sqlalchemy-1.1.18";
1898 doCheck = false;
1899 src = fetchurl {
1900 url = "https://files.pythonhosted.org/packages/cc/4d/96d93ff77cd67aca7618e402191eee3490d8f5f245d6ab7622d35fe504f4/SQLAlchemy-1.1.18.tar.gz";
1901 sha256 = "1ab4ysip6irajfbxl9wy27kv76miaz8h6759hfx92499z4dcf3lb";
1934 1902 };
1935 1903 meta = {
1936 1904 license = [ pkgs.lib.licenses.mit ];
1937 1905 };
1938 1906 };
1939 venusian = super.buildPythonPackage {
1940 name = "venusian-1.1.0";
1941 buildInputs = with self; [];
1907 "sshpubkeys" = super.buildPythonPackage {
1908 name = "sshpubkeys-2.2.0";
1942 1909 doCheck = false;
1943 propagatedBuildInputs = with self; [];
1910 propagatedBuildInputs = [
1911 self."pycrypto"
1912 self."ecdsa"
1913 ];
1944 1914 src = fetchurl {
1945 url = "https://pypi.python.org/packages/38/24/b4b470ab9e0a2e2e9b9030c7735828c8934b4c6b45befd1bb713ec2aeb2d/venusian-1.1.0.tar.gz";
1946 md5 = "56bc5e6756e4bda37bcdb94f74a72b8f";
1947 };
1948 meta = {
1949 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1950 };
1951 };
1952 vine = super.buildPythonPackage {
1953 name = "vine-1.1.4";
1954 buildInputs = with self; [];
1955 doCheck = false;
1956 propagatedBuildInputs = with self; [];
1957 src = fetchurl {
1958 url = "https://pypi.python.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz";
1959 md5 = "9fdb971e7fd15b181b84f3bfcf20d11c";
1915 url = "https://files.pythonhosted.org/packages/27/da/337fabeb3dca6b62039a93ceaa636f25065e0ae92b575b1235342076cf0a/sshpubkeys-2.2.0.tar.gz";
1916 sha256 = "0r4kpwzmg96a2x56pllik7dmc3fnqk189v3sfgsi07q2ryrhr6xm";
1960 1917 };
1961 1918 meta = {
1962 1919 license = [ pkgs.lib.licenses.bsdOriginal ];
1963 1920 };
1964 1921 };
1965 waitress = super.buildPythonPackage {
1966 name = "waitress-1.1.0";
1967 buildInputs = with self; [];
1922 "subprocess32" = super.buildPythonPackage {
1923 name = "subprocess32-3.5.1";
1968 1924 doCheck = false;
1969 propagatedBuildInputs = with self; [];
1970 1925 src = fetchurl {
1971 url = "https://pypi.python.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz";
1972 md5 = "0f1eb7fdfdbf2e6d18decbda1733045c";
1926 url = "https://files.pythonhosted.org/packages/de/fb/fd3e91507021e2aecdb081d1b920082628d6b8869ead845e3e87b3d2e2ca/subprocess32-3.5.1.tar.gz";
1927 sha256 = "0wgi3bfnssid1g6h0v803z3k1wjal6il16nr3r9c587cfzwfkv0q";
1973 1928 };
1974 1929 meta = {
1975 license = [ pkgs.lib.licenses.zpt21 ];
1930 license = [ pkgs.lib.licenses.psfl ];
1931 };
1932 };
1933 "supervisor" = super.buildPythonPackage {
1934 name = "supervisor-3.3.4";
1935 doCheck = false;
1936 propagatedBuildInputs = [
1937 self."meld3"
1938 ];
1939 src = fetchurl {
1940 url = "https://files.pythonhosted.org/packages/44/60/698e54b4a4a9b956b2d709b4b7b676119c833d811d53ee2500f1b5e96dc3/supervisor-3.3.4.tar.gz";
1941 sha256 = "0wp62z9xprvz2krg02xnbwcnq6pxfq3byd8cxx8c2d8xznih28i1";
1942 };
1943 meta = {
1944 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1976 1945 };
1977 1946 };
1978 wcwidth = super.buildPythonPackage {
1979 name = "wcwidth-0.1.7";
1980 buildInputs = with self; [];
1947 "tempita" = super.buildPythonPackage {
1948 name = "tempita-0.5.2";
1981 1949 doCheck = false;
1982 propagatedBuildInputs = with self; [];
1983 1950 src = fetchurl {
1984 url = "https://pypi.python.org/packages/55/11/e4a2bb08bb450fdbd42cc709dd40de4ed2c472cf0ccb9e64af22279c5495/wcwidth-0.1.7.tar.gz";
1985 md5 = "b3b6a0a08f0c8a34d1de8cf44150a4ad";
1951 url = "https://files.pythonhosted.org/packages/56/c8/8ed6eee83dbddf7b0fc64dd5d4454bc05e6ccaafff47991f73f2894d9ff4/Tempita-0.5.2.tar.gz";
1952 sha256 = "177wwq45slfyajd8csy477bmdmzipyw0dm7i85k3akb7m85wzkna";
1953 };
1954 meta = {
1955 license = [ pkgs.lib.licenses.mit ];
1956 };
1957 };
1958 "termcolor" = super.buildPythonPackage {
1959 name = "termcolor-1.1.0";
1960 doCheck = false;
1961 src = fetchurl {
1962 url = "https://files.pythonhosted.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz";
1963 sha256 = "0fv1vq14rpqwgazxg4981904lfyp84mnammw7y046491cv76jv8x";
1986 1964 };
1987 1965 meta = {
1988 1966 license = [ pkgs.lib.licenses.mit ];
1989 1967 };
1990 1968 };
1991 webencodings = super.buildPythonPackage {
1992 name = "webencodings-0.5.1";
1993 buildInputs = with self; [];
1969 "testpath" = super.buildPythonPackage {
1970 name = "testpath-0.3.1";
1971 doCheck = false;
1972 src = fetchurl {
1973 url = "https://files.pythonhosted.org/packages/f4/8b/b71e9ee10e5f751e9d959bc750ab122ba04187f5aa52aabdc4e63b0e31a7/testpath-0.3.1.tar.gz";
1974 sha256 = "02bnmkvm6a8a1p5kcygylcd19v2s040qw3zp1n8ab3bqkj1kflqd";
1975 };
1976 meta = {
1977 license = [ ];
1978 };
1979 };
1980 "traitlets" = super.buildPythonPackage {
1981 name = "traitlets-4.3.2";
1982 doCheck = false;
1983 propagatedBuildInputs = [
1984 self."ipython-genutils"
1985 self."six"
1986 self."decorator"
1987 self."enum34"
1988 ];
1989 src = fetchurl {
1990 url = "https://files.pythonhosted.org/packages/a5/98/7f5ef2fe9e9e071813aaf9cb91d1a732e0a68b6c44a32b38cb8e14c3f069/traitlets-4.3.2.tar.gz";
1991 sha256 = "0dbq7sx26xqz5ixs711k5nc88p8a0nqyz6162pwks5dpcz9d4jww";
1992 };
1993 meta = {
1994 license = [ pkgs.lib.licenses.bsdOriginal ];
1995 };
1996 };
1997 "translationstring" = super.buildPythonPackage {
1998 name = "translationstring-1.3";
1999 doCheck = false;
2000 src = fetchurl {
2001 url = "https://files.pythonhosted.org/packages/5e/eb/bee578cc150b44c653b63f5ebe258b5d0d812ddac12497e5f80fcad5d0b4/translationstring-1.3.tar.gz";
2002 sha256 = "0bdpcnd9pv0131dl08h4zbcwmgc45lyvq3pa224xwan5b3x4rr2f";
2003 };
2004 meta = {
2005 license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
2006 };
2007 };
2008 "trollius" = super.buildPythonPackage {
2009 name = "trollius-1.0.4";
1994 2010 doCheck = false;
1995 propagatedBuildInputs = with self; [];
2011 propagatedBuildInputs = [
2012 self."futures"
2013 ];
2014 src = fetchurl {
2015 url = "https://files.pythonhosted.org/packages/aa/e6/4141db437f55e6ee7a3fb69663239e3fde7841a811b4bef293145ad6c836/trollius-1.0.4.tar.gz";
2016 sha256 = "0xny8y12x3wrflmyn6xi8a7n3m3ac80fgmgzphx5jbbaxkjcm148";
2017 };
2018 meta = {
2019 license = [ pkgs.lib.licenses.asl20 ];
2020 };
2021 };
2022 "tzlocal" = super.buildPythonPackage {
2023 name = "tzlocal-1.5.1";
2024 doCheck = false;
2025 propagatedBuildInputs = [
2026 self."pytz"
2027 ];
2028 src = fetchurl {
2029 url = "https://files.pythonhosted.org/packages/cb/89/e3687d3ed99bc882793f82634e9824e62499fdfdc4b1ae39e211c5b05017/tzlocal-1.5.1.tar.gz";
2030 sha256 = "0kiciwiqx0bv0fbc913idxibc4ygg4cb7f8rcpd9ij2shi4bigjf";
2031 };
2032 meta = {
2033 license = [ pkgs.lib.licenses.mit ];
2034 };
2035 };
2036 "urllib3" = super.buildPythonPackage {
2037 name = "urllib3-1.21";
2038 doCheck = false;
1996 2039 src = fetchurl {
1997 url = "https://pypi.python.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz";
1998 md5 = "32f6e261d52e57bf7e1c4d41546d15b8";
2040 url = "https://files.pythonhosted.org/packages/34/95/7b28259d0006ed681c424cd71a668363265eac92b67dddd018eb9a22bff8/urllib3-1.21.tar.gz";
2041 sha256 = "0irnj4wvh2y36s4q3l2vas9qr9m766w6w418nb490j3mf8a8zw6h";
2042 };
2043 meta = {
2044 license = [ pkgs.lib.licenses.mit ];
2045 };
2046 };
2047 "urlobject" = super.buildPythonPackage {
2048 name = "urlobject-2.4.3";
2049 doCheck = false;
2050 src = fetchurl {
2051 url = "https://files.pythonhosted.org/packages/e2/b8/1d0a916f4b34c4618846e6da0e4eeaa8fcb4a2f39e006434fe38acb74b34/URLObject-2.4.3.tar.gz";
2052 sha256 = "1ahc8ficzfvr2avln71immfh4ls0zyv6cdaa5xmkdj5rd87f5cj7";
2053 };
2054 meta = {
2055 license = [ pkgs.lib.licenses.publicDomain ];
2056 };
2057 };
2058 "venusian" = super.buildPythonPackage {
2059 name = "venusian-1.1.0";
2060 doCheck = false;
2061 src = fetchurl {
2062 url = "https://files.pythonhosted.org/packages/38/24/b4b470ab9e0a2e2e9b9030c7735828c8934b4c6b45befd1bb713ec2aeb2d/venusian-1.1.0.tar.gz";
2063 sha256 = "0zapz131686qm0gazwy8bh11vr57pr89jbwbl50s528sqy9f80lr";
2064 };
2065 meta = {
2066 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
2067 };
2068 };
2069 "vine" = super.buildPythonPackage {
2070 name = "vine-1.1.4";
2071 doCheck = false;
2072 src = fetchurl {
2073 url = "https://files.pythonhosted.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz";
2074 sha256 = "0wkskb2hb494v9gixqnf4bl972p4ibcmxdykzpwjlfa5picns4aj";
1999 2075 };
2000 2076 meta = {
2001 2077 license = [ pkgs.lib.licenses.bsdOriginal ];
2002 2078 };
2003 2079 };
2004 ws4py = super.buildPythonPackage {
2005 name = "ws4py-0.4.3";
2006 buildInputs = with self; [];
2080 "waitress" = super.buildPythonPackage {
2081 name = "waitress-1.1.0";
2082 doCheck = false;
2083 src = fetchurl {
2084 url = "https://files.pythonhosted.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz";
2085 sha256 = "1a85gyji0kajc3p0s1pwwfm06w4wfxjkvvl4rnrz3h164kbd6g6k";
2086 };
2087 meta = {
2088 license = [ pkgs.lib.licenses.zpl21 ];
2089 };
2090 };
2091 "wcwidth" = super.buildPythonPackage {
2092 name = "wcwidth-0.1.7";
2093 doCheck = false;
2094 src = fetchurl {
2095 url = "https://files.pythonhosted.org/packages/55/11/e4a2bb08bb450fdbd42cc709dd40de4ed2c472cf0ccb9e64af22279c5495/wcwidth-0.1.7.tar.gz";
2096 sha256 = "0pn6dflzm609m4r3i8ik5ni9ijjbb5fa3vg1n7hn6vkd49r77wrx";
2097 };
2098 meta = {
2099 license = [ pkgs.lib.licenses.mit ];
2100 };
2101 };
2102 "webencodings" = super.buildPythonPackage {
2103 name = "webencodings-0.5.1";
2007 2104 doCheck = false;
2008 propagatedBuildInputs = with self; [];
2009 2105 src = fetchurl {
2010 url = "https://pypi.python.org/packages/fa/a1/33c43a4304ac3b4dc81deb93cbd329de9297dd034d75c47cce64fda806bc/ws4py-0.4.3.tar.gz";
2011 md5 = "d5834cf7d3965bb0da31bbb02bd8513a";
2106 url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz";
2107 sha256 = "08qrgrc4hrximb2gqnl69g01s93rhf2842jfxdjljc1dbwj1qsmk";
2108 };
2109 meta = {
2110 license = [ pkgs.lib.licenses.bsdOriginal ];
2111 };
2112 };
2113 "weberror" = super.buildPythonPackage {
2114 name = "weberror-0.10.3";
2115 doCheck = false;
2116 propagatedBuildInputs = [
2117 self."webob"
2118 self."tempita"
2119 self."pygments"
2120 self."paste"
2121 ];
2122 src = fetchurl {
2123 url = "https://files.pythonhosted.org/packages/35/76/e7e5c2ce7e9c7f31b54c1ff295a495886d1279a002557d74dd8957346a79/WebError-0.10.3.tar.gz";
2124 sha256 = "0frg4kvycqpj5bi8asfqfs6bxsr2cvjvb6b56c4d1ai1z57kbjx6";
2125 };
2126 meta = {
2127 license = [ pkgs.lib.licenses.mit ];
2128 };
2129 };
2130 "webhelpers" = super.buildPythonPackage {
2131 name = "webhelpers-1.3";
2132 doCheck = false;
2133 propagatedBuildInputs = [
2134 self."markupsafe"
2135 ];
2136 src = fetchurl {
2137 url = "https://files.pythonhosted.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz";
2138 sha256 = "10x5i82qdkrvyw18gsybwggfhfpl869siaab89vnndi9x62g51pa";
2012 2139 };
2013 2140 meta = {
2014 2141 license = [ pkgs.lib.licenses.bsdOriginal ];
2015 2142 };
2016 2143 };
2017 wsgiref = super.buildPythonPackage {
2018 name = "wsgiref-0.1.2";
2019 buildInputs = with self; [];
2144 "webhelpers2" = super.buildPythonPackage {
2145 name = "webhelpers2-2.0";
2146 doCheck = false;
2147 propagatedBuildInputs = [
2148 self."markupsafe"
2149 self."six"
2150 ];
2151 src = fetchurl {
2152 url = "https://files.pythonhosted.org/packages/ff/30/56342c6ea522439e3662427c8d7b5e5b390dff4ff2dc92d8afcb8ab68b75/WebHelpers2-2.0.tar.gz";
2153 sha256 = "0aphva1qmxh83n01p53f5fd43m4srzbnfbz5ajvbx9aj2aipwmcs";
2154 };
2155 meta = {
2156 license = [ pkgs.lib.licenses.mit ];
2157 };
2158 };
2159 "webob" = super.buildPythonPackage {
2160 name = "webob-1.7.4";
2161 doCheck = false;
2162 src = fetchurl {
2163 url = "https://files.pythonhosted.org/packages/75/34/731e23f52371852dfe7490a61644826ba7fe70fd52a377aaca0f4956ba7f/WebOb-1.7.4.tar.gz";
2164 sha256 = "1na01ljg04z40il7vcrn8g29vaw7nvg1xvhk64cr4jys5wcay44d";
2165 };
2166 meta = {
2167 license = [ pkgs.lib.licenses.mit ];
2168 };
2169 };
2170 "webtest" = super.buildPythonPackage {
2171 name = "webtest-2.0.29";
2020 2172 doCheck = false;
2021 propagatedBuildInputs = with self; [];
2173 propagatedBuildInputs = [
2174 self."six"
2175 self."webob"
2176 self."waitress"
2177 self."beautifulsoup4"
2178 ];
2179 src = fetchurl {
2180 url = "https://files.pythonhosted.org/packages/94/de/8f94738be649997da99c47b104aa3c3984ecec51a1d8153ed09638253d56/WebTest-2.0.29.tar.gz";
2181 sha256 = "0bcj1ica5lnmj5zbvk46x28kgphcsgh7sfnwjmn0cr94mhawrg6v";
2182 };
2183 meta = {
2184 license = [ pkgs.lib.licenses.mit ];
2185 };
2186 };
2187 "whoosh" = super.buildPythonPackage {
2188 name = "whoosh-2.7.4";
2189 doCheck = false;
2022 2190 src = fetchurl {
2023 url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip";
2024 md5 = "29b146e6ebd0f9fb119fe321f7bcf6cb";
2191 url = "https://files.pythonhosted.org/packages/25/2b/6beed2107b148edc1321da0d489afc4617b9ed317ef7b72d4993cad9b684/Whoosh-2.7.4.tar.gz";
2192 sha256 = "10qsqdjpbc85fykc1vgcs8xwbgn4l2l52c8d83xf1q59pwyn79bw";
2193 };
2194 meta = {
2195 license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.bsd2 ];
2196 };
2197 };
2198 "ws4py" = super.buildPythonPackage {
2199 name = "ws4py-0.5.1";
2200 doCheck = false;
2201 src = fetchurl {
2202 url = "https://files.pythonhosted.org/packages/53/20/4019a739b2eefe9282d3822ef6a225250af964b117356971bd55e274193c/ws4py-0.5.1.tar.gz";
2203 sha256 = "10slbbf2jm4hpr92jx7kh7mhf48sjl01v2w4d8z3f1p0ybbp7l19";
2204 };
2205 meta = {
2206 license = [ pkgs.lib.licenses.bsdOriginal ];
2207 };
2208 };
2209 "wsgiref" = super.buildPythonPackage {
2210 name = "wsgiref-0.1.2";
2211 doCheck = false;
2212 src = fetchurl {
2213 url = "https://files.pythonhosted.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip";
2214 sha256 = "0y8fyjmpq7vwwm4x732w97qbkw78rjwal5409k04cw4m03411rn7";
2025 2215 };
2026 2216 meta = {
2027 2217 license = [ { fullName = "PSF or ZPL"; } ];
2028 2218 };
2029 2219 };
2030 zope.cachedescriptors = super.buildPythonPackage {
2220 "zope.cachedescriptors" = super.buildPythonPackage {
2031 2221 name = "zope.cachedescriptors-4.3.1";
2032 buildInputs = with self; [];
2033 2222 doCheck = false;
2034 propagatedBuildInputs = with self; [setuptools];
2223 propagatedBuildInputs = [
2224 self."setuptools"
2225 ];
2035 2226 src = fetchurl {
2036 url = "https://pypi.python.org/packages/2f/89/ebe1890cc6d3291ebc935558fa764d5fffe571018dbbee200e9db78762cb/zope.cachedescriptors-4.3.1.tar.gz";
2037 md5 = "42f3693f43bc93f3b1eb86940f58acf3";
2227 url = "https://files.pythonhosted.org/packages/2f/89/ebe1890cc6d3291ebc935558fa764d5fffe571018dbbee200e9db78762cb/zope.cachedescriptors-4.3.1.tar.gz";
2228 sha256 = "0jhr3m5p74c6r7k8iv0005b8bfsialih9d7zl5vx38rf5xq1lk8z";
2038 2229 };
2039 2230 meta = {
2040 license = [ pkgs.lib.licenses.zpt21 ];
2231 license = [ pkgs.lib.licenses.zpl21 ];
2041 2232 };
2042 2233 };
2043 zope.deprecation = super.buildPythonPackage {
2234 "zope.deprecation" = super.buildPythonPackage {
2044 2235 name = "zope.deprecation-4.3.0";
2045 buildInputs = with self; [];
2046 2236 doCheck = false;
2047 propagatedBuildInputs = with self; [setuptools];
2237 propagatedBuildInputs = [
2238 self."setuptools"
2239 ];
2048 2240 src = fetchurl {
2049 url = "https://pypi.python.org/packages/a1/18/2dc5e6bfe64fdc3b79411b67464c55bb0b43b127051a20f7f492ab767758/zope.deprecation-4.3.0.tar.gz";
2050 md5 = "2166b2cb7e0e96a21104e6f8f9b696bb";
2241 url = "https://files.pythonhosted.org/packages/a1/18/2dc5e6bfe64fdc3b79411b67464c55bb0b43b127051a20f7f492ab767758/zope.deprecation-4.3.0.tar.gz";
2242 sha256 = "095jas41wbxgmw95kwdxqhbc3bgihw2hzj9b3qpdg85apcsf2lkx";
2051 2243 };
2052 2244 meta = {
2053 license = [ pkgs.lib.licenses.zpt21 ];
2245 license = [ pkgs.lib.licenses.zpl21 ];
2054 2246 };
2055 2247 };
2056 zope.event = super.buildPythonPackage {
2248 "zope.event" = super.buildPythonPackage {
2057 2249 name = "zope.event-4.3.0";
2058 buildInputs = with self; [];
2059 2250 doCheck = false;
2060 propagatedBuildInputs = with self; [setuptools];
2251 propagatedBuildInputs = [
2252 self."setuptools"
2253 ];
2061 2254 src = fetchurl {
2062 url = "https://pypi.python.org/packages/9e/d0/54ba59f19a0635f6591b74be259cf6fbf67e73f4edda27b5cd0cf4d26efa/zope.event-4.3.0.tar.gz";
2063 md5 = "8ca737960741c6fd112972f3313303bd";
2255 url = "https://files.pythonhosted.org/packages/9e/d0/54ba59f19a0635f6591b74be259cf6fbf67e73f4edda27b5cd0cf4d26efa/zope.event-4.3.0.tar.gz";
2256 sha256 = "1rrkyx42bcq8dkpj23c2v99kczlrg8d39c06q5qpr0vs4hjfmv70";
2064 2257 };
2065 2258 meta = {
2066 license = [ pkgs.lib.licenses.zpt21 ];
2259 license = [ pkgs.lib.licenses.zpl21 ];
2067 2260 };
2068 2261 };
2069 zope.interface = super.buildPythonPackage {
2070 name = "zope.interface-4.4.3";
2071 buildInputs = with self; [];
2262 "zope.interface" = super.buildPythonPackage {
2263 name = "zope.interface-4.5.0";
2072 2264 doCheck = false;
2073 propagatedBuildInputs = with self; [setuptools];
2265 propagatedBuildInputs = [
2266 self."setuptools"
2267 ];
2074 2268 src = fetchurl {
2075 url = "https://pypi.python.org/packages/bd/d2/25349ed41f9dcff7b3baf87bd88a4c82396cf6e02f1f42bb68657a3132af/zope.interface-4.4.3.tar.gz";
2076 md5 = "8700a4f527c1203b34b10c2b4e7a6912";
2269 url = "https://files.pythonhosted.org/packages/ac/8a/657532df378c2cd2a1fe6b12be3b4097521570769d4852ec02c24bd3594e/zope.interface-4.5.0.tar.gz";
2270 sha256 = "0k67m60ij06wkg82n15qgyn96waf4pmrkhv0njpkfzpmv5q89hsp";
2077 2271 };
2078 2272 meta = {
2079 license = [ pkgs.lib.licenses.zpt21 ];
2273 license = [ pkgs.lib.licenses.zpl21 ];
2080 2274 };
2081 2275 };
2082 2276
@@ -1,6 +1,7 b''
1 1 [pytest]
2 2 testpaths = rhodecode
3 3 norecursedirs = rhodecode/public rhodecode/templates tests/scripts
4 cache_dir = /tmp/.pytest_cache
4 5
5 6 pyramid_config = rhodecode/tests/rhodecode.ini
6 7 vcsserver_protocol = http
@@ -1,232 +1,21 b''
1 #
2 # About
3 # =====
4 #
5 # This file defines jobs for our CI system and the attribute "build" is used
6 # as the input for packaging.
7 #
8 #
9 # CI details
10 # ==========
11 #
12 # This file defines an attribute set of derivations. Each of these attributes is
13 # then used in our CI system as one job to run. This way we keep the
14 # configuration for the CI jobs as well under version control.
15 #
16 # Run CI jobs locally
17 # -------------------
18 #
19 # Since it is all based on normal Nix derivations, the jobs can be tested
20 # locally with a run of "nix-build" like the following example:
21 #
22 # nix-build release.nix -A test-api -I vcsserver=~/rhodecode-vcsserver
23 #
24 # Note: Replace "~/rhodecode-vcsserver" with a path where a clone of the
25 # vcsserver resides.
1 # This file defines how to "build" for packaging.
26 2
27 3 { pkgs ? import <nixpkgs> {}
28 , doCheck ? true
4 , doCheck ? false
29 5 }:
30 6
31 7 let
32
33 inherit (pkgs)
34 stdenv
35 system;
36
37 testing = import <nixpkgs/nixos/lib/testing.nix> {
38 inherit system;
39 };
40
41 runInMachine = testing.runInMachine;
42
43 sphinx = import ./docs/default.nix {};
44
45 mkDocs = kind: stdenv.mkDerivation {
46 name = kind;
47 srcs = [
48 (./. + (builtins.toPath "/${kind}"))
49 (builtins.filterSource
50 (path: type: baseNameOf path == "VERSION")
51 ./rhodecode)
52 ];
53 sourceRoot = kind;
54 buildInputs = [ sphinx ];
55 configurePhase = null;
56 buildPhase = ''
57 make SPHINXBUILD=sphinx-build html
58 '';
59 installPhase = ''
60 mkdir -p $out
61 mv _build/html $out/
62
63 mkdir -p $out/nix-support
64 echo "doc manual $out/html index.html" >> \
65 "$out/nix-support/hydra-build-products"
66 '';
67 };
68
69 enterprise = import ./default.nix {
8 enterprise_ce = import ./default.nix {
70 9 inherit
10 doCheck
71 11 pkgs;
72 12
73 # TODO: for quick local testing
74 doCheck = false;
75 };
13 # disable checkPhase for build
14 checkPhase = ''
15 '';
76 16
77 test-cfg = stdenv.mkDerivation {
78 name = "test-cfg";
79 unpackPhase = "true";
80 buildInputs = [
81 enterprise.src
82 ];
83 installPhase = ''
84 mkdir -p $out/etc
85 cp ${enterprise.src}/test.ini $out/etc/enterprise.ini
86 # TODO: johbo: Needed, so that the login works, this causes
87 # probably some side effects
88 substituteInPlace $out/etc/enterprise.ini --replace "is_test = True" ""
89
90 # Gevent configuration
91 cp $out/etc/enterprise.ini $out/etc/enterprise-gevent.ini;
92 cat >> $out/etc/enterprise-gevent.ini <<EOF
93
94 [server:main]
95 use = egg:gunicorn#main
96 worker_class = gevent
97 EOF
98
99 cp ${enterprise.src}/vcsserver/test.ini $out/etc/vcsserver.ini
100 '';
101 };
102
103 ac-test-drv = import ./acceptance_tests {
104 withExternals = false;
105 17 };
106 18
107 # TODO: johbo: Currently abusing buildPythonPackage to make the
108 # needed environment for the ac-test tools.
109 mkAcTests = {
110 # Path to an INI file which will be used to run Enterprise.
111 #
112 # Intended usage is to provide different configuration files to
113 # run the tests against a different configuration.
114 enterpriseCfg ? "${test-cfg}/etc/enterprise.ini"
115
116 # Path to an INI file which will be used to run the VCSServer.
117 , vcsserverCfg ? "${test-cfg}/etc/vcsserver.ini"
118 }: pkgs.pythonPackages.buildPythonPackage {
119 name = "enterprise-ac-tests";
120 src = ./acceptance_tests;
121
122 buildInputs = with pkgs; [
123 curl
124 enterprise
125 ac-test-drv
126 ];
127
128 buildPhase = ''
129 cp ${enterpriseCfg} enterprise.ini
130
131 echo "Creating a fake home directory"
132 mkdir fake-home
133 export HOME=$PWD/fake-home
134
135 echo "Creating a repository directory"
136 mkdir repos
137
138 echo "Preparing the database"
139 rc-setup-app \
140 --user=admin \
141 --email=admin@example.com \
142 --password=secret \
143 --api-key=9999999999999999999999999999999999999999 \
144 --force-yes \
145 --repos=$PWD/repos \
146 enterprise.ini > /dev/null
147
148 echo "Starting rc-server"
149 vcsserver --config ${vcsserverCfg} >vcsserver.log 2>&1 &
150 rc-server enterprise.ini >rc-server.log 2>&1 &
151
152 while ! curl -f -s http://localhost:5000 > /dev/null
153 do
154 echo "Waiting for server to be ready..."
155 sleep 3
156 done
157 echo "Webserver is ready."
158
159 echo "Starting the test run"
160 py.test -c example.ini -vs --maxfail=5 tests
161
162 echo "Kill rc-server"
163 kill %2
164 kill %1
165 '';
166
167 # TODO: johbo: Use the install phase again once the normal mkDerivation
168 # can be used again.
169 postInstall = ''
170 mkdir -p $out
171 cp enterprise.ini $out
172 cp ${vcsserverCfg} $out/vcsserver.ini
173 cp rc-server.log $out
174 cp vcsserver.log $out
175
176 mkdir -p $out/nix-support
177 echo "report config $out enterprise.ini" >> $out/nix-support/hydra-build-products
178 echo "report config $out vcsserver.ini" >> $out/nix-support/hydra-build-products
179 echo "report rc-server $out rc-server.log" >> $out/nix-support/hydra-build-products
180 echo "report vcsserver $out vcsserver.log" >> $out/nix-support/hydra-build-products
181 '';
182 };
183
184 vcsserver = import <vcsserver> {
185 inherit pkgs;
186
187 # TODO: johbo: Think of a more elegant solution to this problem
188 pythonExternalOverrides = self: super: (enterprise.myPythonPackagesUnfix self);
189 };
190
191 runTests = optionString: (enterprise.override (attrs: {
192 doCheck = true;
193 name = "test-run";
194 buildInputs = attrs.buildInputs ++ [
195 vcsserver
196 ];
197 checkPhase = ''
198 py.test ${optionString} -vv -ra
199 '';
200 buildPhase = attrs.shellHook;
201 installPhase = ''
202 echo "Intentionally not installing anything"
203 '';
204 meta.description = "Enterprise test run ${optionString}";
205 }));
206
207 jobs = {
208
209 build = enterprise;
210
211 # johbo: Currently this is simply running the tests against the sources. Nicer
212 # would be to run xdist and against the installed application, so that we also
213 # cover the impact of installing the application.
214 test-api = runTests "rhodecode/api";
215 test-functional = runTests "rhodecode/tests/functional";
216 test-rest = runTests "rhodecode/tests --ignore=rhodecode/tests/functional";
217 test-full = runTests "rhodecode";
218
219 docs = mkDocs "docs";
220
221 aggregate = pkgs.releaseTools.aggregate {
222 name = "aggregated-jobs";
223 constituents = [
224 jobs.build
225 jobs.test-api
226 jobs.test-rest
227 jobs.docs
228 ];
229 };
230 };
231
232 in jobs
19 in {
20 build = enterprise_ce;
21 }
@@ -1,129 +1,129 b''
1 ## core
2 setuptools==30.1.0
3 setuptools-scm==1.15.6
1 ## dependencies
4 2
5 amqp==2.2.2
3 setuptools-scm==2.1.0
4 amqp==2.3.1
6 5 # not released authomatic that has updated some oauth providers
7 6 https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801#egg=authomatic==0.1.0.post1
8 Babel==1.3
9 Beaker==1.9.1
10 celery==4.1.0
11 Chameleon==2.24
7 babel==1.3
8 beaker==1.9.1
9 celery==4.1.1
10 chameleon==2.24
12 11 channelstream==0.5.2
13 12 click==6.6
14 13 colander==1.4.0
15 configobj==5.0.6
16 cssselect==1.0.1
14 # our custom configobj
15 https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c#egg=configobj==5.0.6
16 cssselect==1.0.3
17 17 decorator==4.1.2
18 deform==2.0.4
18 deform==2.0.5
19 19 docutils==0.14.0
20 dogpile.cache==0.6.4
20 dogpile.cache==0.6.6
21 21 dogpile.core==0.4.1
22 22 ecdsa==0.13
23 FormEncode==1.2.4
23 formencode==1.2.4
24 24 future==0.14.3
25 25 futures==3.0.2
26 26 gnureadline==6.3.8
27 27 infrae.cache==1.0.1
28 iso8601==0.1.12
28 iso8601==0.1.11
29 29 itsdangerous==0.24
30 Jinja2==2.9.6
30 jinja2==2.9.6
31 31 billiard==3.5.0.3
32 kombu==4.1.0
32 kombu==4.2.0
33 33 lxml==3.7.3
34 Mako==1.0.7
35 Markdown==2.6.11
36 MarkupSafe==1.0.0
37 msgpack-python==0.4.8
38 MySQL-python==1.2.5
34 mako==1.0.7
35 markdown==2.6.11
36 markupsafe==1.0.0
37 msgpack-python==0.5.6
38 mysql-python==1.2.5
39 pymysql==0.8.1
40 pyotp==2.2.6
39 41 objgraph==3.1.1
40 42 packaging==15.2
41 Paste==2.0.3
42 PasteDeploy==1.5.2
43 PasteScript==2.0.2
43 paste==2.0.3
44 pastedeploy==1.5.2
45 pastescript==2.0.2
44 46 pathlib2==2.3.0
45 47 peppercorn==0.5
46 psutil==5.4.3
47 psycopg2==2.7.3.2
48 psutil==5.4.6
49 psycopg2==2.7.4
48 50 py-bcrypt==0.4
49 51 pycrypto==2.6.1
50 pycurl==7.19.5
52 pycurl==7.43.0.2
51 53 pyflakes==0.8.1
52 54 pygments-markdown-lexer==0.1.0.dev39
53 Pygments==2.2.0
55 pygments==2.2.0
54 56 pyparsing==1.5.7
55 57 pyramid-beaker==0.8
56 pyramid-debugtoolbar==4.3.0
58 pyramid-debugtoolbar==4.4.0
57 59 pyramid-jinja2==2.7
58 60 pyramid-mako==1.0.2
59 pyramid==1.9.1
61 pyramid==1.9.2
60 62 pysqlite==2.8.3
61 63 python-dateutil
62 python-ldap==2.4.45
63 python-memcached==1.58
64 python-pam==1.8.2
65 pytz==2018.3
64 python-ldap==3.1.0
65 python-memcached==1.59
66 python-pam==1.8.4
67 pytz==2018.4
66 68 tzlocal==1.5.1
67 69 pyzmq==14.6.0
68 70 py-gfm==0.1.3
69 71 redis==2.10.6
70 72 repoze.lru==0.7
71 73 requests==2.9.1
72 Routes==2.4.1
74 routes==2.4.1
73 75 setproctitle==1.1.10
74 76 simplejson==3.11.1
75 77 six==1.11.0
76 SQLAlchemy==1.1.15
78 sqlalchemy==1.1.18
77 79 sshpubkeys==2.2.0
78 subprocess32==3.2.7
80 subprocess32==3.5.1
79 81 supervisor==3.3.4
80 Tempita==0.5.2
82 tempita==0.5.2
81 83 translationstring==1.3
82 84 trollius==1.0.4
83 urllib3==1.16
84 URLObject==2.4.0
85 urllib3==1.21
86 urlobject==2.4.3
85 87 venusian==1.1.0
86 WebError==0.10.3
87 WebHelpers2==2.0
88 WebHelpers==1.3
89 WebOb==1.7.4
90 Whoosh==2.7.4
88 weberror==0.10.3
89 webhelpers2==2.0
90 webhelpers==1.3
91 webob==1.7.4
92 whoosh==2.7.4
91 93 wsgiref==0.1.2
92 94 zope.cachedescriptors==4.3.1
93 95 zope.deprecation==4.3.0
94 96 zope.event==4.3.0
95 zope.interface==4.4.3
97 zope.interface==4.5.0
96 98
97 99
98 100 # IPYTHON RENDERING
99 101 # entrypoints backport, pypi version doesn't support egg installs
100 102 https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1
101 103 nbconvert==5.3.1
102 bleach==2.1.2
104 bleach==2.1.4
103 105 nbformat==4.4.0
104 106 jupyter_client==5.0.0
105 107
106 108 ## cli tools
107 alembic==0.9.8
109 alembic==0.9.9
108 110 invoke==0.13.0
109 111 bumpversion==0.5.3
110 transifex-client==0.12.5
111 112
112 113 ## http servers
113 gevent==1.2.2
114 gevent==1.3.5
114 115 greenlet==0.4.13
115 gunicorn==19.7.1
116 gunicorn==19.9.0
116 117 waitress==1.1.0
117 uWSGI==2.0.15
118 118
119 119 ## debug
120 ipdb==0.10.3
120 ipdb==0.11.0
121 121 ipython==5.1.0
122 CProfileV==1.0.7
122 cprofilev==1.0.7
123 123 bottle==0.12.13
124 124
125 125 ## rhodecode-tools, special case
126 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2#egg=rhodecode-tools==0.14.1
126 https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.16.0.tar.gz?md5=87f81286b49156c2ac36f1a1acfa2164#egg=rhodecode-tools==0.16.0
127 127
128 128 ## appenlight
129 129 appenlight-client==0.6.25
@@ -1,15 +1,14 b''
1 1 # test related requirements
2 pytest==3.2.5
3 py==1.5.2
2 pytest==3.6.0
3 py==1.5.3
4 4 pytest-cov==2.5.1
5 pytest-sugar==0.9.0
6 pytest-runner==3.0.0
7 pytest-catchlog==1.2.2
8 pytest-profiling==1.2.11
5 pytest-sugar==0.9.1
6 pytest-runner==4.2.0
7 pytest-profiling==1.3.0
9 8 gprof2dot==2017.9.19
10 pytest-timeout==1.2.0
9 pytest-timeout==1.2.1
11 10
12 11 mock==1.0.1
13 WebTest==2.0.29
12 webtest==2.0.29
14 13 cov-core==1.15.0
15 14 coverage==3.7.1
@@ -1,1 +1,1 b''
1 4.12.4 No newline at end of file
1 4.13.0 No newline at end of file
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}'
51 51 EXTENSIONS = {}
52 52
53 53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 86 # defines current db version for migrations
54 __dbversion__ = 90 # defines current db version for migrations
55 55 __platform__ = platform.system()
56 56 __license__ = 'AGPLv3, and Commercial License'
57 57 __author__ = 'RhodeCode GmbH'
@@ -208,6 +208,7 b' def request_view(request):'
208 208
209 209 # register our auth-user
210 210 request.rpc_user = auth_u
211 request.environ['rc_auth_user_id'] = auth_u.user_id
211 212
212 213 # now check if token is valid for API
213 214 auth_token = request.rpc_api_key
@@ -119,6 +119,7 b' class TestCreatePullRequestApi(object):'
119 119 'mandatory': True},
120 120 ]
121 121 data['reviewers'] = reviewers
122
122 123 id_, params = build_data(
123 124 self.apikey_regular, 'create_pull_request', **data)
124 125 response = api_call(self.app, params)
@@ -251,8 +252,9 b' class TestCreatePullRequestApi(object):'
251 252 id_, params = build_data(
252 253 self.apikey_regular, 'create_pull_request', **data)
253 254 response = api_call(self.app, params)
254 expected_message = 'The specified branch `{}` does not exist'.format(
255 branch_name)
255 expected_message = 'The specified value:{type}:`{name}` ' \
256 'does not exist, or is not allowed.'.format(type='branch',
257 name=branch_name)
256 258 assert_error(id_, expected_message, given=response.body)
257 259
258 260 @pytest.mark.backends("git", "hg")
@@ -316,6 +318,7 b' class TestCreatePullRequestApi(object):'
316 318 self.commit_ids = backend.create_master_repo(commits)
317 319 self.source = backend.create_repo(heads=[source_head])
318 320 self.target = backend.create_repo(heads=[target_head])
321
319 322 data = {
320 323 'source_repo': self.source.repo_name,
321 324 'target_repo': self.target.repo_name,
@@ -76,6 +76,8 b' class TestUpdateUser(object):'
76 76 'user': ret
77 77 }
78 78 expected = ret
79 expected['user']['last_activity'] = response.json['result']['user'][
80 'last_activity']
79 81 assert_ok(id_, expected, given=response.body)
80 82
81 83 def test_api_update_user_by_user_id(self):
@@ -91,6 +93,8 b' class TestUpdateUser(object):'
91 93 'user': ret
92 94 }
93 95 expected = ret
96 expected['user']['last_activity'] = response.json['result']['user'][
97 'last_activity']
94 98 assert_ok(id_, expected, given=response.body)
95 99
96 100 def test_api_update_user_default_user(self):
@@ -87,7 +87,8 b' class TestResolveRefOrError(object):'
87 87 ref = 'ancestor:ref'
88 88 with pytest.raises(JSONRPCError) as excinfo:
89 89 utils.resolve_ref_or_error(ref, repo)
90 expected_message = 'The specified ancestor `ref` does not exist'
90 expected_message = (
91 'The specified value:ancestor:`ref` does not exist, or is not allowed.')
91 92 assert excinfo.value.message == expected_message
92 93
93 94 def test_branch_is_not_found(self):
@@ -99,7 +100,7 b' class TestResolveRefOrError(object):'
99 100 with pytest.raises(JSONRPCError) as excinfo:
100 101 utils.resolve_ref_or_error(ref, repo)
101 102 expected_message = (
102 'The specified branch `non-existing-one` does not exist')
103 'The specified value:branch:`non-existing-one` does not exist, or is not allowed.')
103 104 assert excinfo.value.message == expected_message
104 105
105 106 def test_bookmark_is_not_found(self):
@@ -111,7 +112,7 b' class TestResolveRefOrError(object):'
111 112 with pytest.raises(JSONRPCError) as excinfo:
112 113 utils.resolve_ref_or_error(ref, repo)
113 114 expected_message = (
114 'The specified bookmark `non-existing-one` does not exist')
115 'The specified value:bookmark:`non-existing-one` does not exist, or is not allowed.')
115 116 assert excinfo.value.message == expected_message
116 117
117 118 @pytest.mark.parametrize("ref", ['ref', '12345', 'a:b:c:d'])
@@ -403,7 +403,7 b' def resolve_ref_or_error(ref, repo):'
403 403 ref_hash = ref_hash or _get_ref_hash(repo, ref_type, ref_name)
404 404 except (KeyError, ValueError):
405 405 raise JSONRPCError(
406 'The specified {type} `{name}` does not exist'.format(
406 'The specified value:{type}:`{name}` does not exist, or is not allowed.'.format(
407 407 type=ref_type, name=ref_name))
408 408
409 409 return ':'.join([ref_type, ref_name, ref_hash])
@@ -431,7 +431,6 b' def _get_commit_dict('
431 431 }
432 432
433 433
434 # TODO: mikhail: Think about moving this function to some library
435 434 def _get_ref_hash(repo, type_, name):
436 435 vcs_repo = repo.scm_instance()
437 436 if type_ == 'branch' and vcs_repo.alias in ('hg', 'git'):
@@ -284,7 +284,7 b' def merge_pull_request('
284 284 raise JSONRPCError('userid is not the same as your user')
285 285
286 286 check = MergeCheck.validate(
287 pull_request, user=apiuser, translator=request.translate)
287 pull_request, auth_user=apiuser, translator=request.translate)
288 288 merge_possible = not check.failed
289 289
290 290 if not merge_possible:
@@ -302,7 +302,7 b' def merge_pull_request('
302 302 request.environ, repo_name=target_repo.repo_name,
303 303 username=apiuser.username, action='push',
304 304 scm=target_repo.repo_type)
305 merge_response = PullRequestModel().merge(
305 merge_response = PullRequestModel().merge_repo(
306 306 pull_request, apiuser, extras=extras)
307 307 if merge_response.executed:
308 308 PullRequestModel().close_pull_request(
@@ -548,7 +548,8 b' def comment_pull_request('
548 548 closing_pr=False,
549 549 renderer=renderer,
550 550 comment_type=comment_type,
551 resolves_comment_id=resolves_comment_id
551 resolves_comment_id=resolves_comment_id,
552 auth_user=apiuser
552 553 )
553 554
554 555 if allowed_to_change_status and status:
@@ -573,7 +574,8 b' def comment_pull_request('
573 574 @jsonrpc_method()
574 575 def create_pull_request(
575 576 request, apiuser, source_repo, target_repo, source_ref, target_ref,
576 title=Optional(''), description=Optional(''), reviewers=Optional(None)):
577 title=Optional(''), description=Optional(''), description_renderer=Optional(''),
578 reviewers=Optional(None)):
577 579 """
578 580 Creates a new pull request.
579 581
@@ -598,6 +600,10 b' def create_pull_request('
598 600 :type title: str
599 601 :param description: Set the pull request description.
600 602 :type description: Optional(str)
603 :type description_renderer: Optional(str)
604 :param description_renderer: Set pull request renderer for the description.
605 It should be 'rst', 'markdown' or 'plain'. If not give default
606 system renderer will be used
601 607 :param reviewers: Set the new pull request reviewers list.
602 608 Reviewer defined by review rules will be added automatically to the
603 609 defined list.
@@ -607,7 +613,7 b' def create_pull_request('
607 613 [{'username': 'nick', 'reasons': ['original author'], 'mandatory': <bool>}]
608 614 """
609 615
610 source_db_repo = get_repo_or_error(source_repo)
616 source_db_repo = get_repo_or_error(source_repo)
611 617 target_db_repo = get_repo_or_error(target_repo)
612 618 if not has_superadmin_permission(apiuser):
613 619 _perms = ('repository.admin', 'repository.write', 'repository.read',)
@@ -678,7 +684,11 b' def create_pull_request('
678 684 source_ref=title_source_ref,
679 685 target=target_repo
680 686 )
687 # fetch renderer, if set fallback to plain in case of PR
688 rc_config = SettingsModel().get_all_settings()
689 default_system_renderer = rc_config.get('rhodecode_markup_renderer', 'plain')
681 690 description = Optional.extract(description)
691 description_renderer = Optional.extract(description_renderer) or default_system_renderer
682 692
683 693 pull_request = PullRequestModel().create(
684 694 created_by=apiuser.user_id,
@@ -690,7 +700,9 b' def create_pull_request('
690 700 reviewers=reviewers,
691 701 title=title,
692 702 description=description,
703 description_renderer=description_renderer,
693 704 reviewer_data=reviewer_rules,
705 auth_user=apiuser
694 706 )
695 707
696 708 Session().commit()
@@ -704,8 +716,8 b' def create_pull_request('
704 716 @jsonrpc_method()
705 717 def update_pull_request(
706 718 request, apiuser, pullrequestid, repoid=Optional(None),
707 title=Optional(''), description=Optional(''), reviewers=Optional(None),
708 update_commits=Optional(None)):
719 title=Optional(''), description=Optional(''), description_renderer=Optional(''),
720 reviewers=Optional(None), update_commits=Optional(None)):
709 721 """
710 722 Updates a pull request.
711 723
@@ -719,6 +731,9 b' def update_pull_request('
719 731 :type title: str
720 732 :param description: Update pull request description.
721 733 :type description: Optional(str)
734 :type description_renderer: Optional(str)
735 :param description_renderer: Update pull request renderer for the description.
736 It should be 'rst', 'markdown' or 'plain'
722 737 :param reviewers: Update pull request reviewers list with new value.
723 738 :type reviewers: Optional(list)
724 739 Accepts username strings or objects of the format:
@@ -801,10 +816,15 b' def update_pull_request('
801 816
802 817 title = Optional.extract(title)
803 818 description = Optional.extract(description)
819 description_renderer = Optional.extract(description_renderer)
820
804 821 if title or description:
805 822 PullRequestModel().edit(
806 pull_request, title or pull_request.title,
807 description or pull_request.description, apiuser)
823 pull_request,
824 title or pull_request.title,
825 description or pull_request.description,
826 description_renderer or pull_request.description_renderer,
827 apiuser)
808 828 Session().commit()
809 829
810 830 commit_changes = {"added": [], "common": [], "removed": []}
@@ -1469,7 +1469,8 b' def comment_commit('
1469 1469 status_change_type=status,
1470 1470 renderer=renderer,
1471 1471 comment_type=comment_type,
1472 resolves_comment_id=resolves_comment_id
1472 resolves_comment_id=resolves_comment_id,
1473 auth_user=apiuser
1473 1474 )
1474 1475 if status:
1475 1476 # also do a status change
@@ -461,31 +461,38 b' class RepoRoutePredicate(object):'
461 461 phash = text
462 462
463 463 def __call__(self, info, request):
464
465 464 if hasattr(request, 'vcs_call'):
466 465 # skip vcs calls
467 466 return
468 467
469 468 repo_name = info['match']['repo_name']
470 469 repo_model = repo.RepoModel()
471 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
470
471 by_name_match = repo_model.get_by_repo_name(repo_name, cache=False)
472 472
473 def redirect_if_creating(db_repo):
473 def redirect_if_creating(route_info, db_repo):
474 skip_views = ['edit_repo_advanced_delete']
475 route = route_info['route']
476 # we should skip delete view so we can actually "remove" repositories
477 # if they get stuck in creating state.
478 if route.name in skip_views:
479 return
480
474 481 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
475 raise HTTPFound(
476 request.route_path('repo_creating',
477 repo_name=db_repo.repo_name))
482 repo_creating_url = request.route_path(
483 'repo_creating', repo_name=db_repo.repo_name)
484 raise HTTPFound(repo_creating_url)
478 485
479 486 if by_name_match:
480 487 # register this as request object we can re-use later
481 488 request.db_repo = by_name_match
482 redirect_if_creating(by_name_match)
489 redirect_if_creating(info, by_name_match)
483 490 return True
484 491
485 492 by_id_match = repo_model.get_repo_by_id(repo_name)
486 493 if by_id_match:
487 494 request.db_repo = by_id_match
488 redirect_if_creating(by_id_match)
495 redirect_if_creating(info, by_id_match)
489 496 return True
490 497
491 498 return False
@@ -516,7 +523,7 b' class RepoTypeRoutePredicate(object):'
516 523 else:
517 524 log.warning('Current view is not supported for repo type:%s',
518 525 rhodecode_db_repo.repo_type)
519 #
526
520 527 # h.flash(h.literal(
521 528 # _('Action not supported for %s.' % rhodecode_repo.alias)),
522 529 # category='warning')
@@ -542,8 +549,7 b' class RepoGroupRoutePredicate(object):'
542 549
543 550 repo_group_name = info['match']['repo_group_name']
544 551 repo_group_model = repo_group.RepoGroupModel()
545 by_name_match = repo_group_model.get_by_group_name(
546 repo_group_name, cache=True)
552 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
547 553
548 554 if by_name_match:
549 555 # register this as request object we can re-use later
@@ -569,8 +575,7 b' class UserGroupRoutePredicate(object):'
569 575
570 576 user_group_id = info['match']['user_group_id']
571 577 user_group_model = user_group.UserGroup()
572 by_id_match = user_group_model.get(
573 user_group_id, cache=True)
578 by_id_match = user_group_model.get(user_group_id, cache=False)
574 579
575 580 if by_id_match:
576 581 # register this as request object we can re-use later
@@ -596,8 +601,7 b' class UserRoutePredicateBase(object):'
596 601
597 602 user_id = info['match']['user_id']
598 603 user_model = user.User()
599 by_id_match = user_model.get(
600 user_id, cache=True)
604 by_id_match = user_model.get(user_id, cache=False)
601 605
602 606 if by_id_match:
603 607 # register this as request object we can re-use later
@@ -60,6 +60,19 b' def admin_routes(config):'
60 60 pattern='/settings/system/updates')
61 61
62 62 config.add_route(
63 name='admin_settings_exception_tracker',
64 pattern='/settings/exceptions')
65 config.add_route(
66 name='admin_settings_exception_tracker_delete_all',
67 pattern='/settings/exceptions/delete')
68 config.add_route(
69 name='admin_settings_exception_tracker_show',
70 pattern='/settings/exceptions/{exception_id}')
71 config.add_route(
72 name='admin_settings_exception_tracker_delete',
73 pattern='/settings/exceptions/{exception_id}/delete')
74
75 config.add_route(
63 76 name='admin_settings_sessions',
64 77 pattern='/settings/sessions')
65 78 config.add_route(
@@ -197,6 +210,11 b' def admin_routes(config):'
197 210 name='admin_permissions_object_update',
198 211 pattern='/permissions/object/update')
199 212
213 # Branch perms EE feature
214 config.add_route(
215 name='admin_permissions_branch',
216 pattern='/permissions/branch')
217
200 218 config.add_route(
201 219 name='admin_permissions_ips',
202 220 pattern='/permissions/ips')
@@ -356,6 +374,16 b' def admin_routes(config):'
356 374 name='edit_user_audit_logs',
357 375 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
358 376
377 # user caches
378 config.add_route(
379 name='edit_user_caches',
380 pattern='/users/{user_id:\d+}/edit/caches',
381 user_route=True)
382 config.add_route(
383 name='edit_user_caches_update',
384 pattern='/users/{user_id:\d+}/edit/caches/update',
385 user_route=True)
386
359 387 # user-groups admin
360 388 config.add_route(
361 389 name='user_groups',
@@ -410,5 +438,7 b' def includeme(config):'
410 438 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
411 439 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
412 440
441 config.include('.subscribers')
442
413 443 # Scan module for configuration decorators.
414 444 config.scan('.views', ignore='.tests')
@@ -89,6 +89,9 b' class NavigationRegistry(object):'
89 89 'global_integrations_home'),
90 90 NavEntry('system', _('System Info'),
91 91 'admin_settings_system'),
92 NavEntry('exceptions', _('Exceptions Tracker'),
93 'admin_settings_exception_tracker',
94 active_list=['exceptions', 'exceptions_browse']),
92 95 NavEntry('process_management', _('Processes'),
93 96 'admin_settings_process_management'),
94 97 NavEntry('sessions', _('User Sessions'),
@@ -67,6 +67,7 b' class TestAdminMainView(TestController):'
67 67 self.log_user()
68 68 pull_request = pr_util.create_pull_request()
69 69 pull_request_id = pull_request.pull_request_id
70 repo_name = pull_request.target_repo.repo_name
70 71
71 72 response = self.app.get(
72 73 route_path(view, pull_request_id=pull_request_id),
@@ -74,9 +75,8 b' class TestAdminMainView(TestController):'
74 75 assert response.location.endswith(
75 76 'pull-request/{}'.format(pull_request_id))
76 77
77 repo_name = pull_request.target_repo.repo_name
78 78 redirect_url = route_path(
79 79 'pullrequest_show', repo_name=repo_name,
80 pull_request_id=pull_request.pull_request_id)
80 pull_request_id=pull_request_id)
81 81
82 82 assert redirect_url in response.location
@@ -25,7 +25,7 b' from rhodecode.model.meta import Session'
25 25 from rhodecode.model.permission import PermissionModel
26 26 from rhodecode.model.ssh_key import SshKeyModel
27 27 from rhodecode.tests import (
28 TestController, clear_all_caches, assert_session_flash)
28 TestController, clear_cache_regions, assert_session_flash)
29 29
30 30
31 31 def route_path(name, params=None, **kwargs):
@@ -221,22 +221,21 b' class TestAdminPermissionsController(Tes'
221 221 def test_index_ips(self):
222 222 self.log_user()
223 223 response = self.app.get(route_path('admin_permissions_ips'))
224 # TODO: Test response...
225 224 response.mustcontain('All IP addresses are allowed')
226 225
227 226 def test_add_delete_ips(self):
227 clear_cache_regions(['sql_cache_short'])
228 228 self.log_user()
229 clear_all_caches()
230 229
231 230 # ADD
232 231 default_user_id = User.get_default_user().user_id
233 232 self.app.post(
234 233 route_path('edit_user_ips_add', user_id=default_user_id),
235 params={'new_ip': '127.0.0.0/24', 'csrf_token': self.csrf_token})
234 params={'new_ip': '0.0.0.0/24', 'csrf_token': self.csrf_token})
236 235
237 236 response = self.app.get(route_path('admin_permissions_ips'))
238 response.mustcontain('127.0.0.0/24')
239 response.mustcontain('127.0.0.0 - 127.0.0.255')
237 response.mustcontain('0.0.0.0/24')
238 response.mustcontain('0.0.0.0 - 0.0.0.255')
240 239
241 240 # DELETE
242 241 default_user_id = User.get_default_user().user_id
@@ -249,11 +248,11 b' class TestAdminPermissionsController(Tes'
249 248
250 249 assert_session_flash(response, 'Removed ip address from user whitelist')
251 250
252 clear_all_caches()
251 clear_cache_regions(['sql_cache_short'])
253 252 response = self.app.get(route_path('admin_permissions_ips'))
254 253 response.mustcontain('All IP addresses are allowed')
255 response.mustcontain(no=['127.0.0.0/24'])
256 response.mustcontain(no=['127.0.0.0 - 127.0.0.255'])
254 response.mustcontain(no=['0.0.0.0/24'])
255 response.mustcontain(no=['0.0.0.0 - 0.0.0.255'])
257 256
258 257 def test_index_overview(self):
259 258 self.log_user()
@@ -72,10 +72,11 b' class TestAdminRepos(object):'
72 72
73 73 def test_repo_list(self, autologin_user, user_util):
74 74 repo = user_util.create_repo()
75 repo_name = repo.repo_name
75 76 response = self.app.get(
76 77 route_path('repos'), status=200)
77 78
78 response.mustcontain(repo.repo_name)
79 response.mustcontain(repo_name)
79 80
80 81 def test_create_page_restricted_to_single_backend(self, autologin_user, backend):
81 82 with mock.patch('rhodecode.BACKENDS', {'git': 'git'}):
@@ -226,12 +227,14 b' class TestAdminRepos(object):'
226 227 group_description='test',
227 228 owner=TEST_USER_ADMIN_LOGIN)
228 229 Session().commit()
230 repo_group_id = gr.group_id
229 231
230 232 group_name_allowed = 'reg_sometest_allowed_%s' % backend.alias
231 233 gr_allowed = RepoGroupModel().create(
232 234 group_name=group_name_allowed,
233 235 group_description='test',
234 236 owner=TEST_USER_REGULAR_LOGIN)
237 allowed_repo_group_id = gr_allowed.group_id
235 238 Session().commit()
236 239
237 240 repo_name = 'ingroup'
@@ -243,7 +246,7 b' class TestAdminRepos(object):'
243 246 repo_name=repo_name,
244 247 repo_type=backend.alias,
245 248 repo_description=description,
246 repo_group=gr.group_id,
249 repo_group=repo_group_id,
247 250 csrf_token=csrf_token))
248 251
249 252 response.mustcontain('Invalid value')
@@ -260,7 +263,7 b' class TestAdminRepos(object):'
260 263 repo_name=repo_name,
261 264 repo_type=backend.alias,
262 265 repo_description=description,
263 repo_group=gr_allowed.group_id,
266 repo_group=allowed_repo_group_id,
264 267 csrf_token=csrf_token))
265 268
266 269 # TODO: johbo: Cleanup in pytest fixture
@@ -293,7 +296,7 b' class TestAdminRepos(object):'
293 296
294 297 # add repo permissions
295 298 Session().commit()
296
299 repo_group_id = gr.group_id
297 300 repo_name = 'ingroup_inherited_%s' % backend.alias
298 301 repo_name_full = RepoGroup.url_sep().join([group_name, repo_name])
299 302 description = 'description for newly created repo'
@@ -304,7 +307,7 b' class TestAdminRepos(object):'
304 307 repo_name=repo_name,
305 308 repo_type=backend.alias,
306 309 repo_description=description,
307 repo_group=gr.group_id,
310 repo_group=repo_group_id,
308 311 repo_copy_permissions=True,
309 312 csrf_token=csrf_token))
310 313
@@ -167,4 +167,4 b' class TestAdminUserGroupsView(TestContro'
167 167 'csrf_token': self.csrf_token}, status=200)
168 168
169 169 response.mustcontain(
170 'User group `{}` already exists'.format(user_group.users_group_name))
170 'User group `{}` already exists'.format(duplicate_name))
@@ -137,9 +137,11 b' class TestAdminUsersView(TestController)'
137 137 self.log_user()
138 138
139 139 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
140 user_id = user.user_id
141 auth_tokens = user.auth_tokens
140 142 response = self.app.get(
141 route_path('edit_user_auth_tokens', user_id=user.user_id))
142 for token in user.auth_tokens:
143 route_path('edit_user_auth_tokens', user_id=user_id))
144 for token in auth_tokens:
143 145 response.mustcontain(token)
144 146 response.mustcontain('never')
145 147
@@ -182,7 +182,8 b' class AdminPermissionsView(BaseAppView, '
182 182 self.request.translate,
183 183 [x[0] for x in c.repo_perms_choices],
184 184 [x[0] for x in c.group_perms_choices],
185 [x[0] for x in c.user_group_perms_choices])()
185 [x[0] for x in c.user_group_perms_choices],
186 )()
186 187
187 188 try:
188 189 form_result = _form.to_python(dict(self.request.POST))
@@ -218,6 +219,30 b' class AdminPermissionsView(BaseAppView, '
218 219 @LoginRequired()
219 220 @HasPermissionAllDecorator('hg.admin')
220 221 @view_config(
222 route_name='admin_permissions_branch', request_method='GET',
223 renderer='rhodecode:templates/admin/permissions/permissions.mako')
224 def permissions_branch(self):
225 c = self.load_default_context()
226 c.active = 'branch'
227
228 c.user = User.get_default_user(refresh=True)
229 defaults = {}
230 defaults.update(c.user.get_default_perms())
231
232 data = render(
233 'rhodecode:templates/admin/permissions/permissions.mako',
234 self._get_template_context(c), self.request)
235 html = formencode.htmlfill.render(
236 data,
237 defaults=defaults,
238 encoding="UTF-8",
239 force_defaults=False
240 )
241 return Response(html)
242
243 @LoginRequired()
244 @HasPermissionAllDecorator('hg.admin')
245 @view_config(
221 246 route_name='admin_permissions_global', request_method='GET',
222 247 renderer='rhodecode:templates/admin/permissions/permissions.mako')
223 248 def permissions_global(self):
@@ -27,6 +27,7 b' from pyramid.view import view_config'
27 27 from pyramid.renderers import render
28 28 from pyramid.response import Response
29 29
30 from rhodecode import events
30 31 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 32
32 33 from rhodecode.lib.ext_json import json
@@ -200,6 +201,7 b' class AdminRepoGroupsView(BaseAppView, D'
200 201 % repo_group_name, category='error')
201 202 raise HTTPFound(h.route_path('home'))
202 203
204 events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
203 205 raise HTTPFound(
204 206 h.route_path('repo_group_home',
205 207 repo_group_name=form_result['group_name_full']))
@@ -27,6 +27,7 b' from pyramid.view import view_config'
27 27 from pyramid.renderers import render
28 28 from pyramid.response import Response
29 29
30 from rhodecode import events
30 31 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 32 from rhodecode.lib.celerylib.utils import get_task_id
32 33
@@ -175,6 +176,8 b' class AdminReposView(BaseAppView, DataGr'
175 176 h.flash(msg, category='error')
176 177 raise HTTPFound(h.route_path('home'))
177 178
179 events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
180
178 181 raise HTTPFound(
179 182 h.route_path('repo_creating',
180 183 repo_name=form_result['repo_name_full'],
@@ -112,6 +112,7 b' class AdminSystemInfoSettingsView(BaseAp'
112 112 # Platform/Python
113 113 (_('Platform'), val('platform')['name'], state('platform')),
114 114 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
115 (_('Lang'), val('locale'), state('locale')),
115 116 (_('Python version'), val('python')['version'], state('python')),
116 117 (_('Python path'), val('python')['executable'], state('python')),
117 118 ('', '', ''), # spacer
@@ -28,6 +28,7 b' from pyramid.view import view_config'
28 28 from pyramid.response import Response
29 29 from pyramid.renderers import render
30 30
31 from rhodecode import events
31 32 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 33 from rhodecode.lib.auth import (
33 34 LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator)
@@ -41,6 +42,7 b' from rhodecode.model.db import ('
41 42 or_, count, User, UserGroup, UserGroupMember)
42 43 from rhodecode.model.meta import Session
43 44 from rhodecode.model.user_group import UserGroupModel
45 from rhodecode.model.db import true
44 46
45 47 log = logging.getLogger(__name__)
46 48
@@ -108,6 +110,10 b' class AdminUserGroupsView(BaseAppView, D'
108 110 .filter(UserGroup.users_group_id.in_(allowed_ids))\
109 111 .count()
110 112
113 user_groups_data_total_inactive_count = UserGroup.query()\
114 .filter(UserGroup.users_group_id.in_(allowed_ids))\
115 .filter(UserGroup.users_group_active != true()).count()
116
111 117 member_count = count(UserGroupMember.user_id)
112 118 base_q = Session.query(
113 119 UserGroup.users_group_name,
@@ -123,13 +129,17 b' class AdminUserGroupsView(BaseAppView, D'
123 129 .join(User, User.user_id == UserGroup.user_id) \
124 130 .group_by(UserGroup, User)
125 131
132 base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
133
126 134 if search_q:
127 135 like_expression = u'%{}%'.format(safe_unicode(search_q))
128 136 base_q = base_q.filter(or_(
129 137 UserGroup.users_group_name.ilike(like_expression),
130 138 ))
139 base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
131 140
132 141 user_groups_data_total_filtered_count = base_q.count()
142 user_groups_data_total_filtered_inactive_count = base_q_inactive.count()
133 143
134 144 if order_by == 'members_total':
135 145 sort_col = member_count
@@ -171,7 +181,9 b' class AdminUserGroupsView(BaseAppView, D'
171 181 'draw': draw,
172 182 'data': user_groups_data,
173 183 'recordsTotal': user_groups_data_total_count,
184 'recordsTotalInactive': user_groups_data_total_inactive_count,
174 185 'recordsFiltered': user_groups_data_total_filtered_count,
186 'recordsFilteredInactive': user_groups_data_total_filtered_inactive_count,
175 187 })
176 188
177 189 return data
@@ -242,5 +254,6 b' class AdminUserGroupsView(BaseAppView, D'
242 254 % user_group_name, category='error')
243 255 raise HTTPFound(h.route_path('user_groups_new'))
244 256
257 events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
245 258 raise HTTPFound(
246 259 h.route_path('edit_user_group', user_group_id=user_group_id))
@@ -32,8 +32,9 b' from rhodecode.apps._base import BaseApp'
32 32 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
33 33 from rhodecode.authentication.plugins import auth_rhodecode
34 34 from rhodecode.events import trigger
35 from rhodecode.model.db import true
35 36
36 from rhodecode.lib import audit_logger
37 from rhodecode.lib import audit_logger, rc_cache
37 38 from rhodecode.lib.exceptions import (
38 39 UserCreationError, UserOwnsReposException, UserOwnsRepoGroupsException,
39 40 UserOwnsUserGroupsException, DefaultUserException)
@@ -89,7 +90,6 b' class AdminUsersView(BaseAppView, DataGr'
89 90 draw, start, limit = self._extract_chunk(self.request)
90 91 search_q, order_by, order_dir = self._extract_ordering(
91 92 self.request, column_map=column_map)
92
93 93 _render = self.request.get_partial_renderer(
94 94 'rhodecode:templates/data_table/_dt_elements.mako')
95 95
@@ -100,8 +100,14 b' class AdminUsersView(BaseAppView, DataGr'
100 100 .filter(User.username != User.DEFAULT_USER) \
101 101 .count()
102 102
103 users_data_total_inactive_count = User.query()\
104 .filter(User.username != User.DEFAULT_USER) \
105 .filter(User.active != true())\
106 .count()
107
103 108 # json generate
104 109 base_q = User.query().filter(User.username != User.DEFAULT_USER)
110 base_inactive_q = base_q.filter(User.active != true())
105 111
106 112 if search_q:
107 113 like_expression = u'%{}%'.format(safe_unicode(search_q))
@@ -111,8 +117,10 b' class AdminUsersView(BaseAppView, DataGr'
111 117 User.name.ilike(like_expression),
112 118 User.lastname.ilike(like_expression),
113 119 ))
120 base_inactive_q = base_q.filter(User.active != true())
114 121
115 122 users_data_total_filtered_count = base_q.count()
123 users_data_total_filtered_inactive_count = base_inactive_q.count()
116 124
117 125 sort_col = getattr(User, order_by, None)
118 126 if sort_col:
@@ -148,12 +156,13 b' class AdminUsersView(BaseAppView, DataGr'
148 156 "extern_name": user.extern_name,
149 157 "action": user_actions(user.user_id, user.username),
150 158 })
151
152 159 data = ({
153 160 'draw': draw,
154 161 'data': users_data,
155 162 'recordsTotal': users_data_total_count,
156 163 'recordsFiltered': users_data_total_filtered_count,
164 'recordsTotalInactive': users_data_total_inactive_count,
165 'recordsFilteredInactive': users_data_total_filtered_inactive_count
157 166 })
158 167
159 168 return data
@@ -725,11 +734,12 b' class UsersView(UserAppView):'
725 734 description = self.request.POST.get('description')
726 735 role = self.request.POST.get('role')
727 736
728 token = AuthTokenModel().create(
729 c.user.user_id, description, lifetime, role)
737 token = UserModel().add_auth_token(
738 user=c.user.user_id,
739 lifetime_minutes=lifetime, role=role, description=description,
740 scope_callback=self.maybe_attach_token_scope)
730 741 token_data = token.get_api_data()
731 742
732 self.maybe_attach_token_scope(token)
733 743 audit_logger.store_web(
734 744 'user.edit.token.add', action_data={
735 745 'data': {'token': token_data, 'user': user_data}},
@@ -1189,3 +1199,44 b' class UsersView(UserAppView):'
1189 1199 perm_user = self.db_user.AuthUser(ip_addr=self.request.remote_addr)
1190 1200
1191 1201 return perm_user.permissions
1202
1203 @LoginRequired()
1204 @HasPermissionAllDecorator('hg.admin')
1205 @view_config(
1206 route_name='edit_user_caches', request_method='GET',
1207 renderer='rhodecode:templates/admin/users/user_edit.mako')
1208 def user_caches(self):
1209 _ = self.request.translate
1210 c = self.load_default_context()
1211 c.user = self.db_user
1212
1213 c.active = 'caches'
1214 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1215
1216 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1217 c.region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1218 c.backend = c.region.backend
1219 c.user_keys = sorted(c.region.backend.list_keys(prefix=cache_namespace_uid))
1220
1221 return self._get_template_context(c)
1222
1223 @LoginRequired()
1224 @HasPermissionAllDecorator('hg.admin')
1225 @CSRFRequired()
1226 @view_config(
1227 route_name='edit_user_caches_update', request_method='POST')
1228 def user_caches_update(self):
1229 _ = self.request.translate
1230 c = self.load_default_context()
1231 c.user = self.db_user
1232
1233 c.active = 'caches'
1234 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1235
1236 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1237 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
1238
1239 h.flash(_("Deleted {} cache keys").format(del_keys), category='success')
1240
1241 return HTTPFound(h.route_path(
1242 'edit_user_caches', user_id=c.user.user_id))
@@ -42,6 +42,10 b' def includeme(config):'
42 42 name='goto_switcher_data',
43 43 pattern='/_goto_data')
44 44
45 config.add_route(
46 name='markup_preview',
47 pattern='/_markup_preview')
48
45 49 # register our static links via redirection mechanism
46 50 routing_links.connect_redirection_links(config)
47 51
@@ -19,22 +19,44 b''
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 def assert_and_get_content(result):
22 def assert_and_get_main_filter_content(result):
23 23 repos = []
24 24 groups = []
25 25 commits = []
26 users = []
27 for data_item in result:
28 assert data_item['id']
29 assert data_item['value']
30 assert data_item['value_display']
31 assert data_item['url']
32
33 if data_item['type'] == 'search':
34 assert data_item['value_display'].startswith('Full text search for:')
35 elif data_item['type'] == 'repo':
36 repos.append(data_item)
37 elif data_item['type'] == 'repo_group':
38 groups.append(data_item)
39 elif data_item['type'] == 'user':
40 users.append(data_item)
41 elif data_item['type'] == 'commit':
42 commits.append(data_item)
43 else:
44 raise Exception('invalid type `%s`' % data_item['type'])
45
46 return repos, groups, users, commits
47
48
49 def assert_and_get_repo_list_content(result):
50 repos = []
26 51 for data in result:
27 52 for data_item in data['children']:
28 53 assert data_item['id']
29 54 assert data_item['text']
30 55 assert data_item['url']
56
31 57 if data_item['type'] == 'repo':
32 58 repos.append(data_item)
33 elif data_item['type'] == 'group':
34 groups.append(data_item)
35 elif data_item['type'] == 'commit':
36 commits.append(data_item)
37 59 else:
38 60 raise Exception('invalid type %s' % data_item['type'])
39 61
40 return repos, groups, commits No newline at end of file
62 return repos
@@ -22,7 +22,7 b' import json'
22 22
23 23 import pytest
24 24
25 from . import assert_and_get_content
25 from . import assert_and_get_main_filter_content
26 26 from rhodecode.tests import TestController, TEST_USER_ADMIN_LOGIN
27 27 from rhodecode.tests.fixture import Fixture
28 28
@@ -103,19 +103,15 b' class TestGotoSwitcherData(TestControlle'
103 103 RepoGroupModel().delete(el, force_delete=True)
104 104 Session().commit()
105 105
106 def test_returns_list_of_repos_and_groups(self, xhr_header):
106 def test_empty_query(self, xhr_header):
107 107 self.log_user()
108 108
109 109 response = self.app.get(
110 110 route_path('goto_switcher_data'),
111 111 extra_environ=xhr_header, status=200)
112 result = json.loads(response.body)['results']
113
114 repos, groups, commits = assert_and_get_content(result)
112 result = json.loads(response.body)['suggestions']
115 113
116 assert len(repos) == len(Repository.get_all())
117 assert len(groups) == len(RepoGroup.get_all())
118 assert len(commits) == 0
114 assert result == []
119 115
120 116 def test_returns_list_of_repos_and_groups_filtered(self, xhr_header):
121 117 self.log_user()
@@ -124,14 +120,47 b' class TestGotoSwitcherData(TestControlle'
124 120 route_path('goto_switcher_data'),
125 121 params={'query': 'abc'},
126 122 extra_environ=xhr_header, status=200)
127 result = json.loads(response.body)['results']
123 result = json.loads(response.body)['suggestions']
128 124
129 repos, groups, commits = assert_and_get_content(result)
125 repos, groups, users, commits = assert_and_get_main_filter_content(result)
130 126
131 127 assert len(repos) == 13
132 128 assert len(groups) == 5
129 assert len(users) == 0
133 130 assert len(commits) == 0
134 131
132 def test_returns_list_of_users_filtered(self, xhr_header):
133 self.log_user()
134
135 response = self.app.get(
136 route_path('goto_switcher_data'),
137 params={'query': 'user:admin'},
138 extra_environ=xhr_header, status=200)
139 result = json.loads(response.body)['suggestions']
140
141 repos, groups, users, commits = assert_and_get_main_filter_content(result)
142
143 assert len(repos) == 0
144 assert len(groups) == 0
145 assert len(users) == 1
146 assert len(commits) == 0
147
148 def test_returns_list_of_commits_filtered(self, xhr_header):
149 self.log_user()
150
151 response = self.app.get(
152 route_path('goto_switcher_data'),
153 params={'query': 'commit:e8'},
154 extra_environ=xhr_header, status=200)
155 result = json.loads(response.body)['suggestions']
156
157 repos, groups, users, commits = assert_and_get_main_filter_content(result)
158
159 assert len(repos) == 0
160 assert len(groups) == 0
161 assert len(users) == 0
162 assert len(commits) == 5
163
135 164 def test_returns_list_of_properly_sorted_and_filtered(self, xhr_header):
136 165 self.log_user()
137 166
@@ -139,13 +168,13 b' class TestGotoSwitcherData(TestControlle'
139 168 route_path('goto_switcher_data'),
140 169 params={'query': 'abc'},
141 170 extra_environ=xhr_header, status=200)
142 result = json.loads(response.body)['results']
171 result = json.loads(response.body)['suggestions']
143 172
144 repos, groups, commits = assert_and_get_content(result)
173 repos, groups, users, commits = assert_and_get_main_filter_content(result)
145 174
146 test_repos = [x['text'] for x in repos[:4]]
175 test_repos = [x['value_display'] for x in repos[:4]]
147 176 assert ['abc', 'abcd', 'a/abc', 'abcde'] == test_repos
148 177
149 test_groups = [x['text'] for x in groups[:4]]
178 test_groups = [x['value_display'] for x in groups[:4]]
150 179 assert ['abc_repos', 'repos_abc',
151 180 'forked-abc', 'forked-abc/a'] == test_groups
@@ -20,7 +20,7 b''
20 20
21 21 import json
22 22
23 from . import assert_and_get_content
23 from . import assert_and_get_repo_list_content
24 24 from rhodecode.tests import TestController
25 25 from rhodecode.tests.fixture import Fixture
26 26 from rhodecode.model.db import Repository
@@ -50,11 +50,9 b' class TestRepoListData(TestController):'
50 50 extra_environ=xhr_header, status=200)
51 51 result = json.loads(response.body)['results']
52 52
53 repos, groups, commits = assert_and_get_content(result)
53 repos = assert_and_get_repo_list_content(result)
54 54
55 55 assert len(repos) == len(Repository.get_all())
56 assert len(groups) == 0
57 assert len(commits) == 0
58 56
59 57 def test_returns_list_of_repos_and_groups_filtered(self, xhr_header):
60 58 self.log_user()
@@ -65,12 +63,10 b' class TestRepoListData(TestController):'
65 63 extra_environ=xhr_header, status=200)
66 64 result = json.loads(response.body)['results']
67 65
68 repos, groups, commits = assert_and_get_content(result)
66 repos = assert_and_get_repo_list_content(result)
69 67
70 68 assert len(repos) == len(Repository.query().filter(
71 69 Repository.repo_name.ilike('%vcs_test_git%')).all())
72 assert len(groups) == 0
73 assert len(commits) == 0
74 70
75 71 def test_returns_list_of_repos_and_groups_filtered_with_type(self, xhr_header):
76 72 self.log_user()
@@ -81,12 +77,10 b' class TestRepoListData(TestController):'
81 77 extra_environ=xhr_header, status=200)
82 78 result = json.loads(response.body)['results']
83 79
84 repos, groups, commits = assert_and_get_content(result)
80 repos = assert_and_get_repo_list_content(result)
85 81
86 82 assert len(repos) == len(Repository.query().filter(
87 83 Repository.repo_name.ilike('%vcs_test_git%')).all())
88 assert len(groups) == 0
89 assert len(commits) == 0
90 84
91 85 def test_returns_list_of_repos_non_ascii_query(self, xhr_header):
92 86 self.log_user()
@@ -96,8 +90,6 b' class TestRepoListData(TestController):'
96 90 extra_environ=xhr_header, status=200)
97 91 result = json.loads(response.body)['results']
98 92
99 repos, groups, commits = assert_and_get_content(result)
93 repos = assert_and_get_repo_list_content(result)
100 94
101 95 assert len(repos) == 0
102 assert len(groups) == 0
103 assert len(commits) == 0
@@ -20,18 +20,20 b''
20 20
21 21 import re
22 22 import logging
23 import collections
23 24
24 25 from pyramid.view import view_config
25 26
26 27 from rhodecode.apps._base import BaseAppView
27 28 from rhodecode.lib import helpers as h
28 29 from rhodecode.lib.auth import (
29 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator)
30 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator,
31 CSRFRequired)
30 32 from rhodecode.lib.index import searcher_from_config
31 from rhodecode.lib.utils2 import safe_unicode, str2bool
33 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
32 34 from rhodecode.lib.ext_json import json
33 35 from rhodecode.model.db import (
34 func, or_, in_filter_generator, Repository, RepoGroup)
36 func, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
35 37 from rhodecode.model.repo import RepoModel
36 38 from rhodecode.model.repo_group import RepoGroupModel
37 39 from rhodecode.model.scm import RepoGroupList, RepoList
@@ -104,6 +106,7 b' class HomeView(BaseAppView):'
104 106 return {'suggestions': _user_groups}
105 107
106 108 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
109 org_query = name_contains
107 110 allowed_ids = self._rhodecode_user.repo_acl_ids(
108 111 ['repository.read', 'repository.write', 'repository.admin'],
109 112 cache=False, name_filter=name_contains) or [-1]
@@ -125,20 +128,24 b' class HomeView(BaseAppView):'
125 128 Repository.repo_name.ilike(ilike_expression))
126 129 query = query.limit(limit)
127 130
128 acl_repo_iter = query
131 acl_iter = query
129 132
130 133 return [
131 134 {
132 135 'id': obj.repo_name,
136 'value': org_query,
137 'value_display': obj.repo_name,
133 138 'text': obj.repo_name,
134 139 'type': 'repo',
135 'obj': {'repo_type': obj.repo_type, 'private': obj.private,
136 'repo_id': obj.repo_id},
140 'repo_id': obj.repo_id,
141 'repo_type': obj.repo_type,
142 'private': obj.private,
137 143 'url': h.route_path('repo_summary', repo_name=obj.repo_name)
138 144 }
139 for obj in acl_repo_iter]
145 for obj in acl_iter]
140 146
141 147 def _get_repo_group_list(self, name_contains=None, limit=20):
148 org_query = name_contains
142 149 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
143 150 ['group.read', 'group.write', 'group.admin'],
144 151 cache=False, name_filter=name_contains) or [-1]
@@ -157,20 +164,89 b' class HomeView(BaseAppView):'
157 164 RepoGroup.group_name.ilike(ilike_expression))
158 165 query = query.limit(limit)
159 166
160 acl_repo_iter = query
167 acl_iter = query
161 168
162 169 return [
163 170 {
164 171 'id': obj.group_name,
165 'text': obj.group_name,
166 'type': 'group',
167 'obj': {},
172 'value': org_query,
173 'value_display': obj.group_name,
174 'type': 'repo_group',
168 175 'url': h.route_path(
169 176 'repo_group_home', repo_group_name=obj.group_name)
170 177 }
171 for obj in acl_repo_iter]
178 for obj in acl_iter]
179
180 def _get_user_list(self, name_contains=None, limit=20):
181 org_query = name_contains
182 if not name_contains:
183 return []
184
185 name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
186 if len(name_contains) != 1:
187 return []
188 name_contains = name_contains[0]
189
190 query = User.query()\
191 .order_by(func.length(User.username))\
192 .order_by(User.username) \
193 .filter(User.username != User.DEFAULT_USER)
194
195 if name_contains:
196 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
197 query = query.filter(
198 User.username.ilike(ilike_expression))
199 query = query.limit(limit)
200
201 acl_iter = query
172 202
173 def _get_hash_commit_list(self, auth_user, query=None):
203 return [
204 {
205 'id': obj.user_id,
206 'value': org_query,
207 'value_display': obj.username,
208 'type': 'user',
209 'icon_link': h.gravatar_url(obj.email, 30),
210 'url': h.route_path(
211 'user_profile', username=obj.username)
212 }
213 for obj in acl_iter]
214
215 def _get_user_groups_list(self, name_contains=None, limit=20):
216 org_query = name_contains
217 if not name_contains:
218 return []
219
220 name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
221 if len(name_contains) != 1:
222 return []
223 name_contains = name_contains[0]
224
225 query = UserGroup.query()\
226 .order_by(func.length(UserGroup.users_group_name))\
227 .order_by(UserGroup.users_group_name)
228
229 if name_contains:
230 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
231 query = query.filter(
232 UserGroup.users_group_name.ilike(ilike_expression))
233 query = query.limit(limit)
234
235 acl_iter = query
236
237 return [
238 {
239 'id': obj.users_group_id,
240 'value': org_query,
241 'value_display': obj.users_group_name,
242 'type': 'user_group',
243 'url': h.route_path(
244 'user_group_profile', user_group_name=obj.users_group_name)
245 }
246 for obj in acl_iter]
247
248 def _get_hash_commit_list(self, auth_user, query):
249 org_query = query
174 250 if not query or len(query) < 3:
175 251 return []
176 252
@@ -178,20 +254,21 b' class HomeView(BaseAppView):'
178 254
179 255 if len(commit_hashes) != 1:
180 256 return []
181
182 commit_hash_prefix = commit_hashes[0]
257 commit_hash = commit_hashes[0]
183 258
184 259 searcher = searcher_from_config(self.request.registry.settings)
185 260 result = searcher.search(
186 'commit_id:%s*' % commit_hash_prefix, 'commit', auth_user,
261 'commit_id:%s*' % commit_hash, 'commit', auth_user,
187 262 raise_on_exc=False)
188 263
189 264 return [
190 265 {
191 266 'id': entry['commit_id'],
192 'text': entry['commit_id'],
267 'value': org_query,
268 'value_display': 'repo `{}` commit: {}'.format(
269 entry['repository'], entry['commit_id']),
193 270 'type': 'commit',
194 'obj': {'repo': entry['repository']},
271 'repo': entry['repository'],
195 272 'url': h.route_path(
196 273 'repo_commit',
197 274 repo_name=entry['repository'], commit_id=entry['commit_id'])
@@ -235,41 +312,67 b' class HomeView(BaseAppView):'
235 312 _ = self.request.translate
236 313
237 314 query = self.request.GET.get('query')
238 log.debug('generating goto switcher list, query %s', query)
315 log.debug('generating main filter data, query %s', query)
316
317 default_search_val = u'Full text search for: `{}`'.format(query)
318 res = []
319 if not query:
320 return {'suggestions': res}
239 321
240 res = []
322 res.append({
323 'id': -1,
324 'value': query,
325 'value_display': default_search_val,
326 'type': 'search',
327 'url': h.route_path(
328 'search', _query={'q': query})
329 })
330 repo_group_id = safe_int(self.request.GET.get('repo_group_id'))
331 if repo_group_id:
332 repo_group = RepoGroup.get(repo_group_id)
333 composed_hint = '{}/{}'.format(repo_group.group_name, query)
334 show_hint = not query.startswith(repo_group.group_name)
335 if repo_group and show_hint:
336 hint = u'Group search: `{}`'.format(composed_hint)
337 res.append({
338 'id': -1,
339 'value': composed_hint,
340 'value_display': hint,
341 'type': 'hint',
342 'url': ""
343 })
344
241 345 repo_groups = self._get_repo_group_list(query)
242 if repo_groups:
243 res.append({
244 'text': _('Groups'),
245 'children': repo_groups
246 })
346 for serialized_repo_group in repo_groups:
347 res.append(serialized_repo_group)
247 348
248 349 repos = self._get_repo_list(query)
249 if repos:
250 res.append({
251 'text': _('Repositories'),
252 'children': repos
253 })
350 for serialized_repo in repos:
351 res.append(serialized_repo)
352
353 # TODO(marcink): permissions for that ?
354 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
355 if allowed_user_search:
356 users = self._get_user_list(query)
357 for serialized_user in users:
358 res.append(serialized_user)
359
360 user_groups = self._get_user_groups_list(query)
361 for serialized_user_group in user_groups:
362 res.append(serialized_user_group)
254 363
255 364 commits = self._get_hash_commit_list(c.auth_user, query)
256 365 if commits:
257 unique_repos = {}
366 unique_repos = collections.OrderedDict()
258 367 for commit in commits:
259 unique_repos.setdefault(commit['obj']['repo'], []
260 ).append(commit)
368 repo_name = commit['repo']
369 unique_repos.setdefault(repo_name, []).append(commit)
261 370
262 for repo in unique_repos:
263 res.append({
264 'text': _('Commits in %(repo)s') % {'repo': repo},
265 'children': unique_repos[repo]
266 })
371 for repo, commits in unique_repos.items():
372 for commit in commits:
373 res.append(commit)
267 374
268 data = {
269 'more': False,
270 'results': res
271 }
272 return data
375 return {'suggestions': res}
273 376
274 377 def _get_groups_and_repos(self, repo_group_id=None):
275 378 # repo groups groups
@@ -323,3 +426,21 b' class HomeView(BaseAppView):'
323 426 c.repo_groups_data = json.dumps(repo_group_data)
324 427
325 428 return self._get_template_context(c)
429
430 @LoginRequired()
431 @CSRFRequired()
432 @view_config(
433 route_name='markup_preview', request_method='POST',
434 renderer='string', xhr=True)
435 def markup_preview(self):
436 # Technically a CSRF token is not needed as no state changes with this
437 # call. However, as this is a POST is better to have it, so automated
438 # tools don't flag it as potential CSRF.
439 # Post is required because the payload could be bigger than the maximum
440 # allowed by GET.
441
442 text = self.request.POST.get('text')
443 renderer = self.request.POST.get('renderer') or 'rst'
444 if text:
445 return h.render(text, renderer=renderer, mentions=True)
446 return ''
@@ -22,7 +22,7 b' import pytest'
22 22
23 23 from rhodecode.lib import helpers as h
24 24 from rhodecode.tests import (
25 TestController, clear_all_caches,
25 TestController, clear_cache_regions,
26 26 TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
27 27 from rhodecode.tests.fixture import Fixture
28 28 from rhodecode.tests.utils import AssertResponse
@@ -64,7 +64,7 b' class TestPasswordReset(TestController):'
64 64 ])
65 65 def test_password_reset_settings(
66 66 self, pwd_reset_setting, show_link, show_reset):
67 clear_all_caches()
67 clear_cache_regions()
68 68 self.log_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
69 69 params = {
70 70 'csrf_token': self.csrf_token,
@@ -133,7 +133,7 b' class LoginView(BaseAppView):'
133 133 'response': captcha_rs,
134 134 'remoteip': get_ip_addr(self.request.environ)
135 135 }
136 verify_rs = requests.get(url, params=params, verify=True)
136 verify_rs = requests.get(url, params=params, verify=True, timeout=60)
137 137 verify_rs = verify_rs.json()
138 138 captcha_status = verify_rs.get('success', False)
139 139 captcha_errors = verify_rs.get('error-codes', [])
@@ -299,9 +299,15 b' class LoginView(BaseAppView):'
299 299
300 300 action_data = {'data': new_user.get_api_data(),
301 301 'user_agent': self.request.user_agent}
302
303 audit_user = audit_logger.UserWrap(
304 username=new_user.username,
305 user_id=new_user.user_id,
306 ip_addr=self.request.remote_addr)
307
302 308 audit_logger.store_web(
303 309 'user.register', action_data=action_data,
304 user=new_user)
310 user=audit_user)
305 311
306 312 event = UserRegistered(user=new_user, session=self.session)
307 313 trigger(event)
@@ -373,13 +379,14 b' class LoginView(BaseAppView):'
373 379 # Generate reset URL and send mail.
374 380 user = User.get_by_email(user_email)
375 381
376 # generate password reset token that expires in 10minutes
377 desc = 'Generated token for password reset from {}'.format(
382 # generate password reset token that expires in 10 minutes
383 description = u'Generated token for password reset from {}'.format(
378 384 datetime.datetime.now().isoformat())
379 reset_token = AuthTokenModel().create(
380 user, lifetime=10,
381 description=desc,
382 role=UserApiKeys.ROLE_PASSWORD_RESET)
385
386 reset_token = UserModel().add_auth_token(
387 user=user, lifetime_minutes=10,
388 role=UserModel.auth_token_role.ROLE_PASSWORD_RESET,
389 description=description)
383 390 Session().commit()
384 391
385 392 log.debug('Successfully created password recovery token')
@@ -155,6 +155,7 b' class TestNotificationsController(TestCo'
155 155 notification = NotificationModel().create(
156 156 created_by=cur_user, notification_subject=subject,
157 157 notification_body=notif_body, recipients=[cur_user, u1, u2])
158 Session().commit()
158 159
159 160 response = self.app.get(
160 161 route_path('notifications_show',
@@ -180,11 +180,12 b' class MyAccountView(BaseAppView, DataGri'
180 180 description = self.request.POST.get('description')
181 181 role = self.request.POST.get('role')
182 182
183 token = AuthTokenModel().create(
184 c.user.user_id, description, lifetime, role)
183 token = UserModel().add_auth_token(
184 user=c.user.user_id,
185 lifetime_minutes=lifetime, role=role, description=description,
186 scope_callback=self.maybe_attach_token_scope)
185 187 token_data = token.get_api_data()
186 188
187 self.maybe_attach_token_scope(token)
188 189 audit_logger.store_web(
189 190 'user.edit.token.add', action_data={
190 191 'data': {'token': token_data, 'user': 'self'}},
@@ -20,6 +20,8 b''
20 20
21 21 import pytest
22 22
23 from rhodecode.tests.utils import permission_update_data_generator
24
23 25
24 26 def route_path(name, params=None, **kwargs):
25 27 import urllib
@@ -37,13 +39,48 b' def route_path(name, params=None, **kwar'
37 39
38 40
39 41 @pytest.mark.usefixtures("app")
40 class TestRepoGroupsPermissionsView(object):
42 class TestRepoGroupPermissionsView(object):
41 43
42 def test_edit_repo_group_perms(self, user_util, autologin_user):
44 def test_edit_perms_view(self, user_util, autologin_user):
43 45 repo_group = user_util.create_repo_group()
46
44 47 self.app.get(
45 48 route_path('edit_repo_group_perms',
46 49 repo_group_name=repo_group.group_name), status=200)
47 50
48 def test_update_permissions(self):
49 pass
51 def test_update_permissions(self, csrf_token, user_util):
52 repo_group = user_util.create_repo_group()
53 repo_group_name = repo_group.group_name
54 user = user_util.create_user()
55 user_id = user.user_id
56 username = user.username
57
58 # grant new
59 form_data = permission_update_data_generator(
60 csrf_token,
61 default='group.write',
62 grant=[(user_id, 'group.write', username, 'user')])
63
64 # recursive flag required for repo groups
65 form_data.extend([('recursive', u'none')])
66
67 response = self.app.post(
68 route_path('edit_repo_group_perms_update',
69 repo_group_name=repo_group_name), form_data).follow()
70
71 assert 'Repository Group permissions updated' in response
72
73 # revoke given
74 form_data = permission_update_data_generator(
75 csrf_token,
76 default='group.read',
77 revoke=[(user_id, 'user')])
78
79 # recursive flag required for repo groups
80 form_data.extend([('recursive', u'none')])
81
82 response = self.app.post(
83 route_path('edit_repo_group_perms_update',
84 repo_group_name=repo_group_name), form_data).follow()
85
86 assert 'Repository Group permissions updated' in response
@@ -23,6 +23,7 b' import logging'
23 23 from pyramid.view import view_config
24 24 from pyramid.httpexceptions import HTTPFound
25 25
26 from rhodecode import events
26 27 from rhodecode.apps._base import RepoGroupAppView
27 28 from rhodecode.lib import helpers as h
28 29 from rhodecode.lib import audit_logger
@@ -95,6 +96,14 b' class RepoGroupPermissionsView(RepoGroup'
95 96
96 97 Session().commit()
97 98 h.flash(_('Repository Group permissions updated'), category='success')
99
100 affected_user_ids = []
101 for change in changes['added'] + changes['updated'] + changes['deleted']:
102 if change['type'] == 'user':
103 affected_user_ids.append(change['id'])
104
105 events.trigger(events.UserPermissionsChange(affected_user_ids))
106
98 107 raise HTTPFound(
99 108 h.route_path('edit_repo_group_perms',
100 109 repo_group_name=self.db_repo_group_name))
@@ -24,6 +24,7 b' import deform'
24 24 from pyramid.view import view_config
25 25 from pyramid.httpexceptions import HTTPFound
26 26
27 from rhodecode import events
27 28 from rhodecode.apps._base import RepoGroupAppView
28 29 from rhodecode.forms import RcForm
29 30 from rhodecode.lib import helpers as h
@@ -31,7 +32,7 b' from rhodecode.lib import audit_logger'
31 32 from rhodecode.lib.auth import (
32 33 LoginRequired, HasPermissionAll,
33 34 HasRepoGroupPermissionAny, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
34 from rhodecode.model.db import Session, RepoGroup
35 from rhodecode.model.db import Session, RepoGroup, User
35 36 from rhodecode.model.scm import RepoGroupList
36 37 from rhodecode.model.repo_group import RepoGroupModel
37 38 from rhodecode.model.validation_schema.schemas import repo_group_schema
@@ -72,8 +73,6 b' class RepoGroupSettingsView(RepoGroupApp'
72 73 if add_parent_group:
73 74 c.repo_groups_choices.append(parent_group.group_id)
74 75 c.repo_groups.append(RepoGroup._generate_choice(parent_group))
75
76
77 76 return c
78 77
79 78 def _can_create_repo_group(self, parent_group_id=None):
@@ -179,5 +178,12 b' class RepoGroupSettingsView(RepoGroupApp'
179 178 h.flash(_('Error occurred during update of repository group %s')
180 179 % old_repo_group_name, category='error')
181 180
181 name_changed = old_repo_group_name != new_repo_group_name
182 if name_changed:
183 owner = User.get_by_username(schema_data['repo_group_owner'])
184 owner_id = owner.user_id if owner else self._rhodecode_user.user_id
185 events.trigger(events.UserPermissionsChange([
186 self._rhodecode_user.user_id, owner_id]))
187
182 188 raise HTTPFound(
183 189 h.route_path('edit_repo_group', repo_group_name=new_repo_group_name))
@@ -345,6 +345,15 b' def includeme(config):'
345 345 name='edit_repo_perms',
346 346 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
347 347
348 # Permissions Branch (EE feature)
349 config.add_route(
350 name='edit_repo_perms_branch',
351 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions', repo_route=True)
352 config.add_route(
353 name='edit_repo_perms_branch_delete',
354 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions/{rule_id}/delete',
355 repo_route=True)
356
348 357 # Maintenance
349 358 config.add_route(
350 359 name='edit_repo_maintenance',
@@ -32,6 +32,7 b' from rhodecode.lib.vcs import nodes'
32 32 from rhodecode.lib.vcs.conf import settings
33 33 from rhodecode.tests import assert_session_flash
34 34 from rhodecode.tests.fixture import Fixture
35 from rhodecode.model.db import Session
35 36
36 37 fixture = Fixture()
37 38
@@ -166,8 +167,8 b' class TestFilesViews(object):'
166 167 {'message': 'b', 'branch': new_branch}
167 168 ]
168 169 backend.create_repo(commits)
169
170 170 backend.repo.landing_rev = "branch:%s" % new_branch
171 Session().commit()
171 172
172 173 # get response based on tip and not new commit
173 174 response = self.app.get(
@@ -368,8 +368,9 b' class TestPullrequestsView(object):'
368 368 ('target_repo', target.repo_name),
369 369 ('target_ref', 'branch:default:' + commit_ids['ancestor']),
370 370 ('common_ancestor', commit_ids['ancestor']),
371 ('pullrequest_title', 'Title'),
371 372 ('pullrequest_desc', 'Description'),
372 ('pullrequest_title', 'Title'),
373 ('description_renderer', 'markdown'),
373 374 ('__start__', 'review_members:sequence'),
374 375 ('__start__', 'reviewer:mapping'),
375 376 ('user_id', '1'),
@@ -427,8 +428,9 b' class TestPullrequestsView(object):'
427 428 ('target_repo', target.repo_name),
428 429 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
429 430 ('common_ancestor', commit_ids['ancestor']),
431 ('pullrequest_title', 'Title'),
430 432 ('pullrequest_desc', 'Description'),
431 ('pullrequest_title', 'Title'),
433 ('description_renderer', 'markdown'),
432 434 ('__start__', 'review_members:sequence'),
433 435 ('__start__', 'reviewer:mapping'),
434 436 ('user_id', '2'),
@@ -493,8 +495,9 b' class TestPullrequestsView(object):'
493 495 ('target_repo', target.repo_name),
494 496 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
495 497 ('common_ancestor', commit_ids['ancestor']),
498 ('pullrequest_title', 'Title'),
496 499 ('pullrequest_desc', 'Description'),
497 ('pullrequest_title', 'Title'),
500 ('description_renderer', 'markdown'),
498 501 ('__start__', 'review_members:sequence'),
499 502 ('__start__', 'reviewer:mapping'),
500 503 ('user_id', '1'),
@@ -618,7 +621,7 b' class TestPullrequestsView(object):'
618 621
619 622 model_patcher = mock.patch.multiple(
620 623 PullRequestModel,
621 merge=mock.Mock(return_value=MergeResponse(
624 merge_repo=mock.Mock(return_value=MergeResponse(
622 625 True, False, 'STUB_COMMIT_ID', MergeFailureReason.PUSH_FAILED)),
623 626 merge_status=mock.Mock(return_value=(True, 'WRONG_MESSAGE')))
624 627
@@ -747,6 +750,69 b' class TestPullrequestsView(object):'
747 750 assert 'Pull request updated to' in response.body
748 751 assert 'with 1 added, 1 removed commits.' in response.body
749 752
753 def test_update_target_revision_with_removal_of_1_commit_git(self, backend_git, csrf_token):
754 backend = backend_git
755 commits = [
756 {'message': 'master-commit-1'},
757 {'message': 'master-commit-2-change-1'},
758 {'message': 'master-commit-3-change-2'},
759
760 {'message': 'feat-commit-1', 'parents': ['master-commit-1']},
761 {'message': 'feat-commit-2'},
762 ]
763 commit_ids = backend.create_master_repo(commits)
764 target = backend.create_repo(heads=['master-commit-3-change-2'])
765 source = backend.create_repo(heads=['feat-commit-2'])
766
767 # create pr from a in source to A in target
768 pull_request = PullRequest()
769 pull_request.source_repo = source
770 # TODO: johbo: Make sure that we write the source ref this way!
771 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
772 branch=backend.default_branch_name,
773 commit_id=commit_ids['master-commit-3-change-2'])
774
775 pull_request.target_repo = target
776 # TODO: johbo: Target ref should be branch based, since tip can jump
777 # from branch to branch
778 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
779 branch=backend.default_branch_name,
780 commit_id=commit_ids['feat-commit-2'])
781
782 pull_request.revisions = [
783 commit_ids['feat-commit-1'],
784 commit_ids['feat-commit-2']
785 ]
786 pull_request.title = u"Test"
787 pull_request.description = u"Description"
788 pull_request.author = UserModel().get_by_username(
789 TEST_USER_ADMIN_LOGIN)
790 Session().add(pull_request)
791 Session().commit()
792 pull_request_id = pull_request.pull_request_id
793
794 # PR is created, now we simulate a force-push into target,
795 # that drops a 2 last commits
796 vcsrepo = target.scm_instance()
797 vcsrepo.config.clear_section('hooks')
798 vcsrepo.run_git_command(['reset', '--soft', 'HEAD~2'])
799
800 # update PR
801 self.app.post(
802 route_path('pullrequest_update',
803 repo_name=target.repo_name,
804 pull_request_id=pull_request_id),
805 params={'update_commits': 'true',
806 'csrf_token': csrf_token},
807 status=200)
808
809 response = self.app.get(route_path(
810 'pullrequest_new',
811 repo_name=target.repo_name))
812 assert response.status_int == 200
813 response.mustcontain('Pull request updated to')
814 response.mustcontain('with 0 added, 0 removed commits.')
815
750 816 def test_update_of_ancestor_reference(self, backend, csrf_token):
751 817 commits = [
752 818 {'message': 'ancestor'},
@@ -27,7 +27,7 b' from pyramid.view import view_config'
27 27 from rhodecode.apps._base import RepoAppView
28 28 from rhodecode.lib.auth import (
29 29 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
30 from rhodecode.lib import helpers as h
30 from rhodecode.lib import helpers as h, rc_cache
31 31 from rhodecode.lib import system_info
32 32 from rhodecode.model.meta import Session
33 33 from rhodecode.model.scm import ScmModel
@@ -53,6 +53,12 b' class RepoCachesView(RepoAppView):'
53 53 c.cached_diff_size = 0
54 54 if os.path.isdir(cached_diffs_dir):
55 55 c.cached_diff_size = system_info.get_storage_size(cached_diffs_dir)
56 c.shadow_repos = c.rhodecode_db_repo.shadow_repos()
57
58 cache_namespace_uid = 'cache_repo.{}'.format(self.db_repo.repo_id)
59 c.region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
60 c.backend = c.region.backend
61 c.repo_keys = sorted(c.region.backend.list_keys(prefix=cache_namespace_uid))
56 62
57 63 return self._get_template_context(c)
58 64
@@ -68,7 +74,9 b' class RepoCachesView(RepoAppView):'
68 74
69 75 try:
70 76 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
77
71 78 Session().commit()
79
72 80 h.flash(_('Cache invalidation successful'),
73 81 category='success')
74 82 except Exception:
@@ -89,7 +89,7 b' class RepoChangelogView(RepoAppView):'
89 89 data = dict(
90 90 raw_id=commit.raw_id,
91 91 idx=commit.idx,
92 branch=commit.branch,
92 branch=h.escape(commit.branch),
93 93 )
94 94 if parents:
95 95 data['parents'] = [
@@ -437,7 +437,8 b' class RepoCommitsView(RepoAppView):'
437 437 if status else None),
438 438 status_change_type=status,
439 439 comment_type=comment_type,
440 resolves_comment_id=resolves_comment_id
440 resolves_comment_id=resolves_comment_id,
441 auth_user=self._rhodecode_user
441 442 )
442 443
443 444 # get status if set !
@@ -528,7 +529,7 b' class RepoCommitsView(RepoAppView):'
528 529 comment_repo_admin = is_repo_admin and is_repo_comment
529 530
530 531 if super_admin or comment_owner or comment_repo_admin:
531 CommentsModel().delete(comment=comment, user=self._rhodecode_db_user)
532 CommentsModel().delete(comment=comment, auth_user=self._rhodecode_user)
532 533 Session().commit()
533 534 return True
534 535 else:
@@ -17,17 +17,16 b''
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 20 import pytz
22 21 import logging
23 22
24 from beaker.cache import cache_region
25 23 from pyramid.view import view_config
26 24 from pyramid.response import Response
27 25 from webhelpers.feedgenerator import Rss201rev2Feed, Atom1Feed
28 26
29 27 from rhodecode.apps._base import RepoAppView
30 28 from rhodecode.lib import audit_logger
29 from rhodecode.lib import rc_cache
31 30 from rhodecode.lib import helpers as h
32 31 from rhodecode.lib.auth import (
33 32 LoginRequired, HasRepoPermissionAnyDecorator)
@@ -124,11 +123,23 b' class RepoFeedView(RepoAppView):'
124 123 """
125 124 self.load_default_context()
126 125
127 def _generate_feed():
126 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
127 self.db_repo.repo_id, CacheKey.CACHE_TYPE_FEED)
128 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
129 repo_id=self.db_repo.repo_id)
130
131 region = rc_cache.get_or_create_region('cache_repo_longterm',
132 cache_namespace_uid)
133
134 condition = not self.path_filter.is_enabled
135
136 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
137 condition=condition)
138 def generate_atom_feed(repo_id, _repo_name, _feed_type):
128 139 feed = Atom1Feed(
129 title=self.title % self.db_repo_name,
130 link=h.route_url('repo_summary', repo_name=self.db_repo_name),
131 description=self.description % self.db_repo_name,
140 title=self.title % _repo_name,
141 link=h.route_url('repo_summary', repo_name=_repo_name),
142 description=self.description % _repo_name,
132 143 language=self.language,
133 144 ttl=self.ttl
134 145 )
@@ -136,30 +147,29 b' class RepoFeedView(RepoAppView):'
136 147 for commit in reversed(self._get_commits()):
137 148 date = self._set_timezone(commit.date)
138 149 feed.add_item(
139 unique_id=self.uid(self.db_repo.repo_id, commit.raw_id),
150 unique_id=self.uid(repo_id, commit.raw_id),
140 151 title=self._get_title(commit),
141 152 author_name=commit.author,
142 153 description=self._get_description(commit),
143 154 link=h.route_url(
144 'repo_commit', repo_name=self.db_repo_name,
155 'repo_commit', repo_name=_repo_name,
145 156 commit_id=commit.raw_id),
146 157 pubdate=date,)
147 158
148 159 return feed.mime_type, feed.writeString('utf-8')
149 160
150 @cache_region('long_term')
151 def _generate_feed_and_cache(cache_key):
152 return _generate_feed()
161 inv_context_manager = rc_cache.InvalidationContext(
162 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
163 with inv_context_manager as invalidation_context:
164 args = (self.db_repo.repo_id, self.db_repo.repo_name, 'atom',)
165 # re-compute and store cache if we get invalidate signal
166 if invalidation_context.should_invalidate():
167 mime_type, feed = generate_atom_feed.refresh(*args)
168 else:
169 mime_type, feed = generate_atom_feed(*args)
153 170
154 if self.path_filter.is_enabled:
155 mime_type, feed = _generate_feed()
156 else:
157 invalidator_context = CacheKey.repo_context_cache(
158 _generate_feed_and_cache, self.db_repo_name,
159 CacheKey.CACHE_TYPE_ATOM)
160 with invalidator_context as context:
161 context.invalidate()
162 mime_type, feed = context.compute()
171 log.debug('Repo ATOM feed computed in %.3fs',
172 inv_context_manager.compute_time)
163 173
164 174 response = Response(feed)
165 175 response.content_type = mime_type
@@ -177,11 +187,22 b' class RepoFeedView(RepoAppView):'
177 187 """
178 188 self.load_default_context()
179 189
180 def _generate_feed():
190 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
191 self.db_repo.repo_id, CacheKey.CACHE_TYPE_FEED)
192 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
193 repo_id=self.db_repo.repo_id)
194 region = rc_cache.get_or_create_region('cache_repo_longterm',
195 cache_namespace_uid)
196
197 condition = not self.path_filter.is_enabled
198
199 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
200 condition=condition)
201 def generate_rss_feed(repo_id, _repo_name, _feed_type):
181 202 feed = Rss201rev2Feed(
182 title=self.title % self.db_repo_name,
183 link=h.route_url('repo_summary', repo_name=self.db_repo_name),
184 description=self.description % self.db_repo_name,
203 title=self.title % _repo_name,
204 link=h.route_url('repo_summary', repo_name=_repo_name),
205 description=self.description % _repo_name,
185 206 language=self.language,
186 207 ttl=self.ttl
187 208 )
@@ -189,31 +210,28 b' class RepoFeedView(RepoAppView):'
189 210 for commit in reversed(self._get_commits()):
190 211 date = self._set_timezone(commit.date)
191 212 feed.add_item(
192 unique_id=self.uid(self.db_repo.repo_id, commit.raw_id),
213 unique_id=self.uid(repo_id, commit.raw_id),
193 214 title=self._get_title(commit),
194 215 author_name=commit.author,
195 216 description=self._get_description(commit),
196 217 link=h.route_url(
197 'repo_commit', repo_name=self.db_repo_name,
218 'repo_commit', repo_name=_repo_name,
198 219 commit_id=commit.raw_id),
199 220 pubdate=date,)
200 221
201 222 return feed.mime_type, feed.writeString('utf-8')
202 223
203 @cache_region('long_term')
204 def _generate_feed_and_cache(cache_key):
205 return _generate_feed()
206
207 if self.path_filter.is_enabled:
208 mime_type, feed = _generate_feed()
209 else:
210 invalidator_context = CacheKey.repo_context_cache(
211 _generate_feed_and_cache, self.db_repo_name,
212 CacheKey.CACHE_TYPE_RSS)
213
214 with invalidator_context as context:
215 context.invalidate()
216 mime_type, feed = context.compute()
224 inv_context_manager = rc_cache.InvalidationContext(
225 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
226 with inv_context_manager as invalidation_context:
227 args = (self.db_repo.repo_id, self.db_repo.repo_name, 'rss',)
228 # re-compute and store cache if we get invalidate signal
229 if invalidation_context.should_invalidate():
230 mime_type, feed = generate_rss_feed.refresh(*args)
231 else:
232 mime_type, feed = generate_rss_feed(*args)
233 log.debug(
234 'Repo RSS feed computed in %.3fs', inv_context_manager.compute_time)
217 235
218 236 response = Response(feed)
219 237 response.content_type = mime_type
@@ -30,16 +30,17 b' from pyramid.view import view_config'
30 30 from pyramid.renderers import render
31 31 from pyramid.response import Response
32 32
33 import rhodecode
33 34 from rhodecode.apps._base import RepoAppView
34 35
35 36 from rhodecode.controllers.utils import parse_path_ref
36 from rhodecode.lib import diffs, helpers as h, caches
37 from rhodecode.lib import diffs, helpers as h, rc_cache
37 38 from rhodecode.lib import audit_logger
38 39 from rhodecode.lib.exceptions import NonRelativePathError
39 40 from rhodecode.lib.codeblocks import (
40 41 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
41 42 from rhodecode.lib.utils2 import (
42 convert_line_endings, detect_mode, safe_str, str2bool)
43 convert_line_endings, detect_mode, safe_str, str2bool, safe_int)
43 44 from rhodecode.lib.auth import (
44 45 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
45 46 from rhodecode.lib.vcs import path as vcspath
@@ -80,10 +81,7 b' class RepoFilesView(RepoAppView):'
80 81
81 82 def load_default_context(self):
82 83 c = self._get_local_tmpl_context(include_app_defaults=True)
83
84 84 c.rhodecode_repo = self.rhodecode_vcs_repo
85
86
87 85 return c
88 86
89 87 def _ensure_not_locked(self):
@@ -100,6 +98,20 b' class RepoFilesView(RepoAppView):'
100 98 repo_name=self.db_repo_name, commit_id='tip')
101 99 raise HTTPFound(files_url)
102 100
101 def check_branch_permission(self, branch_name):
102 _ = self.request.translate
103
104 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
105 self.db_repo_name, branch_name)
106 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
107 h.flash(
108 _('Branch `{}` changes forbidden by rule {}.').format(branch_name, rule),
109 'warning')
110 files_url = h.route_path(
111 'repo_files:default_path',
112 repo_name=self.db_repo_name, commit_id='tip')
113 raise HTTPFound(files_url)
114
103 115 def _get_commit_and_path(self):
104 116 default_commit_id = self.db_repo.landing_rev[1]
105 117 default_f_path = '/'
@@ -178,44 +190,66 b' class RepoFilesView(RepoAppView):'
178 190 return file_node
179 191
180 192 def _is_valid_head(self, commit_id, repo):
181 # check if commit is a branch identifier- basically we cannot
182 # create multiple heads via file editing
183 valid_heads = repo.branches.keys() + repo.branches.values()
193 branch_name = sha_commit_id = ''
194 is_head = False
184 195
185 196 if h.is_svn(repo) and not repo.is_empty():
186 # Note: Subversion only has one head, we add it here in case there
187 # is no branch matched.
188 valid_heads.append(repo.get_commit(commit_idx=-1).raw_id)
197 # Note: Subversion only has one head.
198 if commit_id == repo.get_commit(commit_idx=-1).raw_id:
199 is_head = True
200 return branch_name, sha_commit_id, is_head
189 201
190 # check if commit is a branch name or branch hash
191 return commit_id in valid_heads
202 for _branch_name, branch_commit_id in repo.branches.items():
203 # simple case we pass in branch name, it's a HEAD
204 if commit_id == _branch_name:
205 is_head = True
206 branch_name = _branch_name
207 sha_commit_id = branch_commit_id
208 break
209 # case when we pass in full sha commit_id, which is a head
210 elif commit_id == branch_commit_id:
211 is_head = True
212 branch_name = _branch_name
213 sha_commit_id = branch_commit_id
214 break
192 215
193 def _get_tree_cache_manager(self, namespace_type):
194 _namespace = caches.get_repo_namespace_key(
195 namespace_type, self.db_repo_name)
196 return caches.get_cache_manager('repo_cache_long', _namespace)
216 # checked branches, means we only need to try to get the branch/commit_sha
217 if not repo.is_empty:
218 commit = repo.get_commit(commit_id=commit_id)
219 if commit:
220 branch_name = commit.branch
221 sha_commit_id = commit.raw_id
222
223 return branch_name, sha_commit_id, is_head
197 224
198 225 def _get_tree_at_commit(
199 self, c, commit_id, f_path, full_load=False, force=False):
200 def _cached_tree():
201 log.debug('Generating cached file tree for %s, %s, %s',
202 self.db_repo_name, commit_id, f_path)
226 self, c, commit_id, f_path, full_load=False):
227
228 repo_id = self.db_repo.repo_id
229
230 cache_seconds = safe_int(
231 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
232 cache_on = cache_seconds > 0
233 log.debug(
234 'Computing FILE TREE for repo_id %s commit_id `%s` and path `%s`'
235 'with caching: %s[TTL: %ss]' % (
236 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
237
238 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
239 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
240
241 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
242 condition=cache_on)
243 def compute_file_tree(repo_id, commit_id, f_path, full_load):
244 log.debug('Generating cached file tree for repo_id: %s, %s, %s',
245 repo_id, commit_id, f_path)
203 246
204 247 c.full_load = full_load
205 248 return render(
206 249 'rhodecode:templates/files/files_browser_tree.mako',
207 250 self._get_template_context(c), self.request)
208 251
209 cache_manager = self._get_tree_cache_manager(caches.FILE_TREE)
210
211 cache_key = caches.compute_key_from_params(
212 self.db_repo_name, commit_id, f_path)
213
214 if force:
215 # we want to force recompute of caches
216 cache_manager.remove_value(cache_key)
217
218 return cache_manager.get(cache_key, createfunc=_cached_tree)
252 return compute_file_tree(self.db_repo.repo_id, commit_id, f_path, full_load)
219 253
220 254 def _get_archive_spec(self, fname):
221 255 log.debug('Detecting archive spec for: `%s`', fname)
@@ -281,6 +315,7 b' class RepoFilesView(RepoAppView):'
281 315 use_cached_archive = False
282 316 archive_cache_enabled = CONFIG.get(
283 317 'archive_cache_dir') and not self.request.GET.get('no_cache')
318 cached_archive_path = None
284 319
285 320 if archive_cache_enabled:
286 321 # check if we it's ok to write
@@ -322,16 +357,16 b' class RepoFilesView(RepoAppView):'
322 357 commit=True
323 358 )
324 359
325 def get_chunked_archive(archive):
326 with open(archive, 'rb') as stream:
360 def get_chunked_archive(archive_path):
361 with open(archive_path, 'rb') as stream:
327 362 while True:
328 363 data = stream.read(16 * 1024)
329 364 if not data:
330 365 if fd: # fd means we used temporary file
331 366 os.close(fd)
332 367 if not archive_cache_enabled:
333 log.debug('Destroying temp archive %s', archive)
334 os.remove(archive)
368 log.debug('Destroying temp archive %s', archive_path)
369 os.remove(archive_path)
335 370 break
336 371 yield data
337 372
@@ -572,8 +607,9 b' class RepoFilesView(RepoAppView):'
572 607 if not c.renderer:
573 608 c.lines = filenode_as_lines_tokens(c.file)
574 609
575 c.on_branch_head = self._is_valid_head(
610 _branch_name, _sha_commit_id, is_head = self._is_valid_head(
576 611 commit_id, self.rhodecode_vcs_repo)
612 c.on_branch_head = is_head
577 613
578 614 branch = c.commit.branch if (
579 615 c.commit.branch and '/' not in c.commit.branch) else None
@@ -667,12 +703,8 b' class RepoFilesView(RepoAppView):'
667 703 c.file = dir_node
668 704 c.commit = commit
669 705
670 # using force=True here, make a little trick. We flush the cache and
671 # compute it using the same key as without previous full_load, so now
672 # the fully loaded tree is now returned instead of partial,
673 # and we store this in caches
674 706 html = self._get_tree_at_commit(
675 c, commit.raw_id, dir_node.path, full_load=True, force=True)
707 c, commit.raw_id, dir_node.path, full_load=True)
676 708
677 709 return Response(html)
678 710
@@ -787,10 +819,24 b' class RepoFilesView(RepoAppView):'
787 819
788 820 return response
789 821
790 def _get_nodelist_at_commit(self, repo_name, commit_id, f_path):
791 def _cached_nodes():
792 log.debug('Generating cached nodelist for %s, %s, %s',
793 repo_name, commit_id, f_path)
822 def _get_nodelist_at_commit(self, repo_name, repo_id, commit_id, f_path):
823
824 cache_seconds = safe_int(
825 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
826 cache_on = cache_seconds > 0
827 log.debug(
828 'Computing FILE SEARCH for repo_id %s commit_id `%s` and path `%s`'
829 'with caching: %s[TTL: %ss]' % (
830 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
831
832 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
833 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
834
835 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
836 condition=cache_on)
837 def compute_file_search(repo_id, commit_id, f_path):
838 log.debug('Generating cached nodelist for repo_id:%s, %s, %s',
839 repo_id, commit_id, f_path)
794 840 try:
795 841 _d, _f = ScmModel().get_nodes(
796 842 repo_name, commit_id, f_path, flat=False)
@@ -802,12 +848,7 b' class RepoFilesView(RepoAppView):'
802 848 commit_id='tip', f_path='/'))
803 849 return _d + _f
804 850
805 cache_manager = self._get_tree_cache_manager(
806 caches.FILE_SEARCH_TREE_META)
807
808 cache_key = caches.compute_key_from_params(
809 repo_name, commit_id, f_path)
810 return cache_manager.get(cache_key, createfunc=_cached_nodes)
851 return compute_file_search(self.db_repo.repo_id, commit_id, f_path)
811 852
812 853 @LoginRequired()
813 854 @HasRepoPermissionAnyDecorator(
@@ -822,7 +863,7 b' class RepoFilesView(RepoAppView):'
822 863 commit = self._get_commit_or_redirect(commit_id)
823 864
824 865 metadata = self._get_nodelist_at_commit(
825 self.db_repo_name, commit.raw_id, f_path)
866 self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path)
826 867 return {'nodes': metadata}
827 868
828 869 def _create_references(
@@ -982,15 +1023,18 b' class RepoFilesView(RepoAppView):'
982 1023 commit_id, f_path = self._get_commit_and_path()
983 1024
984 1025 self._ensure_not_locked()
1026 _branch_name, _sha_commit_id, is_head = \
1027 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
985 1028
986 if not self._is_valid_head(commit_id, self.rhodecode_vcs_repo):
1029 if not is_head:
987 1030 h.flash(_('You can only delete files with commit '
988 'being a valid branch '), category='warning')
1031 'being a valid branch head.'), category='warning')
989 1032 raise HTTPFound(
990 1033 h.route_path('repo_files',
991 1034 repo_name=self.db_repo_name, commit_id='tip',
992 1035 f_path=f_path))
993 1036
1037 self.check_branch_permission(_branch_name)
994 1038 c.commit = self._get_commit_or_redirect(commit_id)
995 1039 c.file = self._get_filenode_or_redirect(c.commit, f_path)
996 1040
@@ -1013,14 +1057,17 b' class RepoFilesView(RepoAppView):'
1013 1057 commit_id, f_path = self._get_commit_and_path()
1014 1058
1015 1059 self._ensure_not_locked()
1060 _branch_name, _sha_commit_id, is_head = \
1061 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1016 1062
1017 if not self._is_valid_head(commit_id, self.rhodecode_vcs_repo):
1063 if not is_head:
1018 1064 h.flash(_('You can only delete files with commit '
1019 'being a valid branch '), category='warning')
1065 'being a valid branch head.'), category='warning')
1020 1066 raise HTTPFound(
1021 1067 h.route_path('repo_files',
1022 1068 repo_name=self.db_repo_name, commit_id='tip',
1023 1069 f_path=f_path))
1070 self.check_branch_permission(_branch_name)
1024 1071
1025 1072 c.commit = self._get_commit_or_redirect(commit_id)
1026 1073 c.file = self._get_filenode_or_redirect(c.commit, f_path)
@@ -1066,14 +1113,17 b' class RepoFilesView(RepoAppView):'
1066 1113 commit_id, f_path = self._get_commit_and_path()
1067 1114
1068 1115 self._ensure_not_locked()
1116 _branch_name, _sha_commit_id, is_head = \
1117 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1069 1118
1070 if not self._is_valid_head(commit_id, self.rhodecode_vcs_repo):
1119 if not is_head:
1071 1120 h.flash(_('You can only edit files with commit '
1072 'being a valid branch '), category='warning')
1121 'being a valid branch head.'), category='warning')
1073 1122 raise HTTPFound(
1074 1123 h.route_path('repo_files',
1075 1124 repo_name=self.db_repo_name, commit_id='tip',
1076 1125 f_path=f_path))
1126 self.check_branch_permission(_branch_name)
1077 1127
1078 1128 c.commit = self._get_commit_or_redirect(commit_id)
1079 1129 c.file = self._get_filenode_or_redirect(c.commit, f_path)
@@ -1103,15 +1153,19 b' class RepoFilesView(RepoAppView):'
1103 1153 commit_id, f_path = self._get_commit_and_path()
1104 1154
1105 1155 self._ensure_not_locked()
1156 _branch_name, _sha_commit_id, is_head = \
1157 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1106 1158
1107 if not self._is_valid_head(commit_id, self.rhodecode_vcs_repo):
1159 if not is_head:
1108 1160 h.flash(_('You can only edit files with commit '
1109 'being a valid branch '), category='warning')
1161 'being a valid branch head.'), category='warning')
1110 1162 raise HTTPFound(
1111 1163 h.route_path('repo_files',
1112 1164 repo_name=self.db_repo_name, commit_id='tip',
1113 1165 f_path=f_path))
1114 1166
1167 self.check_branch_permission(_branch_name)
1168
1115 1169 c.commit = self._get_commit_or_redirect(commit_id)
1116 1170 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1117 1171
@@ -1191,6 +1245,25 b' class RepoFilesView(RepoAppView):'
1191 1245 c.default_message = (_('Added file via RhodeCode Enterprise'))
1192 1246 c.f_path = f_path.lstrip('/') # ensure not relative path
1193 1247
1248 if self.rhodecode_vcs_repo.is_empty:
1249 # for empty repository we cannot check for current branch, we rely on
1250 # c.commit.branch instead
1251 _branch_name = c.commit.branch
1252 is_head = True
1253 else:
1254 _branch_name, _sha_commit_id, is_head = \
1255 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1256
1257 if not is_head:
1258 h.flash(_('You can only add files with commit '
1259 'being a valid branch head.'), category='warning')
1260 raise HTTPFound(
1261 h.route_path('repo_files',
1262 repo_name=self.db_repo_name, commit_id='tip',
1263 f_path=f_path))
1264
1265 self.check_branch_permission(_branch_name)
1266
1194 1267 return self._get_template_context(c)
1195 1268
1196 1269 @LoginRequired()
@@ -1212,6 +1285,26 b' class RepoFilesView(RepoAppView):'
1212 1285 commit_id, redirect_after=False)
1213 1286 if c.commit is None:
1214 1287 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1288
1289 if self.rhodecode_vcs_repo.is_empty:
1290 # for empty repository we cannot check for current branch, we rely on
1291 # c.commit.branch instead
1292 _branch_name = c.commit.branch
1293 is_head = True
1294 else:
1295 _branch_name, _sha_commit_id, is_head = \
1296 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1297
1298 if not is_head:
1299 h.flash(_('You can only add files with commit '
1300 'being a valid branch head.'), category='warning')
1301 raise HTTPFound(
1302 h.route_path('repo_files',
1303 repo_name=self.db_repo_name, commit_id='tip',
1304 f_path=f_path))
1305
1306 self.check_branch_permission(_branch_name)
1307
1215 1308 c.default_message = (_('Added file via RhodeCode Enterprise'))
1216 1309 c.f_path = f_path
1217 1310 unix_mode = 0
@@ -28,6 +28,7 b' from pyramid.view import view_config'
28 28 from pyramid.renderers import render
29 29 from pyramid.response import Response
30 30
31 from rhodecode import events
31 32 from rhodecode.apps._base import RepoAppView, DataGridAppView
32 33 from rhodecode.lib.auth import (
33 34 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
@@ -154,7 +155,7 b' class RepoForksView(RepoAppView, DataGri'
154 155 forks_data.append({
155 156 "username": h.gravatar_with_user(self.request, fork.user.username),
156 157 "fork_name": fork_name(fork),
157 "description": fork.description,
158 "description": fork.description_safe,
158 159 "fork_date": h.age_component(fork.created_on, time_is_local=True),
159 160 "last_activity": h.format_date(fork.updated_on),
160 161 "action": fork_actions(fork),
@@ -253,6 +254,9 b' class RepoForksView(RepoAppView, DataGri'
253 254 h.flash(msg, category='error')
254 255
255 256 repo_name = form_result.get('repo_name_full', self.db_repo_name)
257
258 events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
259
256 260 raise HTTPFound(
257 261 h.route_path('repo_creating',
258 262 repo_name=repo_name,
@@ -23,6 +23,7 b' import logging'
23 23 from pyramid.httpexceptions import HTTPFound
24 24 from pyramid.view import view_config
25 25
26 from rhodecode import events
26 27 from rhodecode.apps._base import RepoAppView
27 28 from rhodecode.lib import helpers as h
28 29 from rhodecode.lib import audit_logger
@@ -39,8 +40,6 b' class RepoSettingsPermissionsView(RepoAp'
39 40
40 41 def load_default_context(self):
41 42 c = self._get_local_tmpl_context()
42
43
44 43 return c
45 44
46 45 @LoginRequired()
@@ -85,5 +84,12 b' class RepoSettingsPermissionsView(RepoAp'
85 84 Session().commit()
86 85 h.flash(_('Repository permissions updated'), category='success')
87 86
87 affected_user_ids = []
88 for change in changes['added'] + changes['updated'] + changes['deleted']:
89 if change['type'] == 'user':
90 affected_user_ids.append(change['id'])
91
92 events.trigger(events.UserPermissionsChange(affected_user_ids))
93
88 94 raise HTTPFound(
89 95 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
@@ -61,7 +61,8 b' class RepoPullRequestsView(RepoAppView, '
61 61 c = self._get_local_tmpl_context(include_app_defaults=True)
62 62 c.REVIEW_STATUS_APPROVED = ChangesetStatus.STATUS_APPROVED
63 63 c.REVIEW_STATUS_REJECTED = ChangesetStatus.STATUS_REJECTED
64
64 # backward compat., we use for OLD PRs a plain renderer
65 c.renderer = 'plain'
65 66 return c
66 67
67 68 def _get_pull_requests_list(
@@ -248,6 +249,7 b' class RepoPullRequestsView(RepoAppView, '
248 249 from_version = self.request.GET.get('from_version') or version
249 250 merge_checks = self.request.GET.get('merge_checks')
250 251 c.fulldiff = str2bool(self.request.GET.get('fulldiff'))
252 force_refresh = str2bool(self.request.GET.get('force_refresh'))
251 253
252 254 (pull_request_latest,
253 255 pull_request_at_ver,
@@ -296,6 +298,7 b' class RepoPullRequestsView(RepoAppView, '
296 298 pull_request_at_ver)
297 299
298 300 c.pull_request = pull_request_display_obj
301 c.renderer = pull_request_at_ver.description_renderer or c.renderer
299 302 c.pull_request_latest = pull_request_latest
300 303
301 304 if compare or (at_version and not at_version == 'latest'):
@@ -338,8 +341,9 b' class RepoPullRequestsView(RepoAppView, '
338 341
339 342 # check merge capabilities
340 343 _merge_check = MergeCheck.validate(
341 pull_request_latest, user=self._rhodecode_user,
342 translator=self.request.translate)
344 pull_request_latest, auth_user=self._rhodecode_user,
345 translator=self.request.translate,
346 force_shadow_repo_refresh=force_refresh)
343 347 c.pr_merge_errors = _merge_check.error_details
344 348 c.pr_merge_possible = not _merge_check.failed
345 349 c.pr_merge_message = _merge_check.merge_msg
@@ -432,12 +436,14 b' class RepoPullRequestsView(RepoAppView, '
432 436 source_scm = source_repo.scm_instance()
433 437 target_scm = target_repo.scm_instance()
434 438
435 # try first shadow repo, fallback to regular repo
439 shadow_scm = None
436 440 try:
437 commits_source_repo = pull_request_latest.get_shadow_repo()
441 shadow_scm = pull_request_latest.get_shadow_repo()
438 442 except Exception:
439 443 log.debug('Failed to get shadow repo', exc_info=True)
440 commits_source_repo = source_scm
444 # try first the existing source_repo, and then shadow
445 # repo if we can obtain one
446 commits_source_repo = source_scm or shadow_scm
441 447
442 448 c.commits_source_repo = commits_source_repo
443 449 c.ancestor = None # set it to None, to hide it from PR view
@@ -766,7 +772,10 b' class RepoPullRequestsView(RepoAppView, '
766 772 'id': obj['name'],
767 773 'text': obj['name'],
768 774 'type': 'repo',
769 'obj': obj['dbrepo']
775 'repo_id': obj['dbrepo']['repo_id'],
776 'repo_type': obj['dbrepo']['repo_type'],
777 'private': obj['dbrepo']['private'],
778
770 779 })
771 780
772 781 data = {
@@ -861,9 +870,22 b' class RepoPullRequestsView(RepoAppView, '
861 870 ancestor = source_scm.get_common_ancestor(
862 871 source_commit.raw_id, target_commit.raw_id, target_scm)
863 872
873 # recalculate target ref based on ancestor
864 874 target_ref_type, target_ref_name, __ = _form['target_ref'].split(':')
865 875 target_ref = ':'.join((target_ref_type, target_ref_name, ancestor))
866 876
877 get_default_reviewers_data, validate_default_reviewers = \
878 PullRequestModel().get_reviewer_functions()
879
880 # recalculate reviewers logic, to make sure we can validate this
881 reviewer_rules = get_default_reviewers_data(
882 self._rhodecode_db_user, source_db_repo,
883 source_commit, target_db_repo, target_commit)
884
885 given_reviewers = _form['review_members']
886 reviewers = validate_default_reviewers(
887 given_reviewers, reviewer_rules)
888
867 889 pullrequest_title = _form['pullrequest_title']
868 890 title_source_ref = source_ref.split(':', 2)[1]
869 891 if not pullrequest_title:
@@ -874,23 +896,22 b' class RepoPullRequestsView(RepoAppView, '
874 896 )
875 897
876 898 description = _form['pullrequest_desc']
877
878 get_default_reviewers_data, validate_default_reviewers = \
879 PullRequestModel().get_reviewer_functions()
880
881 # recalculate reviewers logic, to make sure we can validate this
882 reviewer_rules = get_default_reviewers_data(
883 self._rhodecode_db_user, source_db_repo,
884 source_commit, target_db_repo, target_commit)
885
886 given_reviewers = _form['review_members']
887 reviewers = validate_default_reviewers(given_reviewers, reviewer_rules)
899 description_renderer = _form['description_renderer']
888 900
889 901 try:
890 902 pull_request = PullRequestModel().create(
891 self._rhodecode_user.user_id, source_repo, source_ref,
892 target_repo, target_ref, commit_ids, reviewers,
893 pullrequest_title, description, reviewer_rules
903 created_by=self._rhodecode_user.user_id,
904 source_repo=source_repo,
905 source_ref=source_ref,
906 target_repo=target_repo,
907 target_ref=target_ref,
908 revisions=commit_ids,
909 reviewers=reviewers,
910 title=pullrequest_title,
911 description=description,
912 description_renderer=description_renderer,
913 reviewer_data=reviewer_rules,
914 auth_user=self._rhodecode_user
894 915 )
895 916 Session().commit()
896 917
@@ -953,10 +974,14 b' class RepoPullRequestsView(RepoAppView, '
953 974
954 975 def _edit_pull_request(self, pull_request):
955 976 _ = self.request.translate
977
956 978 try:
957 979 PullRequestModel().edit(
958 pull_request, self.request.POST.get('title'),
959 self.request.POST.get('description'), self._rhodecode_user)
980 pull_request,
981 self.request.POST.get('title'),
982 self.request.POST.get('description'),
983 self.request.POST.get('description_renderer'),
984 self._rhodecode_user)
960 985 except ValueError:
961 986 msg = _(u'Cannot update closed pull requests.')
962 987 h.flash(msg, category='error')
@@ -1031,8 +1056,9 b' class RepoPullRequestsView(RepoAppView, '
1031 1056 self.request.matchdict['pull_request_id'])
1032 1057
1033 1058 self.load_default_context()
1034 check = MergeCheck.validate(pull_request, self._rhodecode_db_user,
1035 translator=self.request.translate)
1059 check = MergeCheck.validate(
1060 pull_request, auth_user=self._rhodecode_user,
1061 translator=self.request.translate)
1036 1062 merge_possible = not check.failed
1037 1063
1038 1064 for err_type, error_msg in check.errors:
@@ -1056,7 +1082,7 b' class RepoPullRequestsView(RepoAppView, '
1056 1082
1057 1083 def _merge_pull_request(self, pull_request, user, extras):
1058 1084 _ = self.request.translate
1059 merge_resp = PullRequestModel().merge(pull_request, user, extras=extras)
1085 merge_resp = PullRequestModel().merge_repo(pull_request, user, extras=extras)
1060 1086
1061 1087 if merge_resp.executed:
1062 1088 log.debug("The merge was successful, closing the pull request.")
@@ -1199,7 +1225,8 b' class RepoPullRequestsView(RepoAppView, '
1199 1225 status_change_type=(status
1200 1226 if status and allowed_to_change_status else None),
1201 1227 comment_type=comment_type,
1202 resolves_comment_id=resolves_comment_id
1228 resolves_comment_id=resolves_comment_id,
1229 auth_user=self._rhodecode_user
1203 1230 )
1204 1231
1205 1232 if allowed_to_change_status:
@@ -1285,7 +1312,7 b' class RepoPullRequestsView(RepoAppView, '
1285 1312
1286 1313 if super_admin or comment_owner or comment_repo_admin:
1287 1314 old_calculated_status = comment.pull_request.calculated_review_status()
1288 CommentsModel().delete(comment=comment, user=self._rhodecode_user)
1315 CommentsModel().delete(comment=comment, auth_user=self._rhodecode_user)
1289 1316 Session().commit()
1290 1317 calculated_status = comment.pull_request.calculated_review_status()
1291 1318 if old_calculated_status != calculated_status:
@@ -24,13 +24,14 b' import deform'
24 24 from pyramid.httpexceptions import HTTPFound
25 25 from pyramid.view import view_config
26 26
27 from rhodecode import events
27 28 from rhodecode.apps._base import RepoAppView
28 29 from rhodecode.forms import RcForm
29 30 from rhodecode.lib import helpers as h
30 31 from rhodecode.lib import audit_logger
31 32 from rhodecode.lib.auth import (
32 33 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
33 from rhodecode.model.db import RepositoryField, RepoGroup, Repository
34 from rhodecode.model.db import RepositoryField, RepoGroup, Repository, User
34 35 from rhodecode.model.meta import Session
35 36 from rhodecode.model.repo import RepoModel
36 37 from rhodecode.model.scm import RepoGroupList, ScmModel
@@ -71,8 +72,6 b' class RepoSettingsView(RepoAppView):'
71 72 c.personal_repo_group = c.auth_user.personal_repo_group
72 73 c.repo_fields = RepositoryField.query()\
73 74 .filter(RepositoryField.repository == self.db_repo).all()
74
75
76 75 return c
77 76
78 77 def _get_schema(self, c, old_values=None):
@@ -176,6 +175,13 b' class RepoSettingsView(RepoAppView):'
176 175 h.flash(_('Error occurred during update of repository {}').format(
177 176 old_repo_name), category='error')
178 177
178 name_changed = old_repo_name != new_repo_name
179 if name_changed:
180 owner = User.get_by_username(schema_data['repo_owner'])
181 owner_id = owner.user_id if owner else self._rhodecode_user.user_id
182 events.trigger(events.UserPermissionsChange([
183 self._rhodecode_user.user_id, owner_id]))
184
179 185 raise HTTPFound(
180 186 h.route_path('edit_repo', repo_name=new_repo_name))
181 187
@@ -242,6 +242,7 b' class RepoSettingsView(RepoAppView):'
242 242 _ = self.request.translate
243 243 self.load_default_context()
244 244 self.rhodecode_vcs_repo.install_hooks(force=True)
245 h.flash(_('installed hooks repository'), category='success')
245 h.flash(_('installed updated hooks into this repository'),
246 category='success')
246 247 raise HTTPFound(
247 248 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
@@ -20,22 +20,21 b''
20 20
21 21 import logging
22 22 import string
23 import rhodecode
23 24
24 25 from pyramid.view import view_config
25 from beaker.cache import cache_region
26 26
27 27 from rhodecode.controllers import utils
28 28 from rhodecode.apps._base import RepoAppView
29 29 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
30 from rhodecode.lib import caches, helpers as h
31 from rhodecode.lib.helpers import RepoPage
30 from rhodecode.lib import helpers as h, rc_cache
32 31 from rhodecode.lib.utils2 import safe_str, safe_int
33 32 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 33 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
35 34 from rhodecode.lib.ext_json import json
36 35 from rhodecode.lib.vcs.backends.base import EmptyCommit
37 from rhodecode.lib.vcs.exceptions import CommitError, EmptyRepositoryError, \
38 CommitDoesNotExistError
36 from rhodecode.lib.vcs.exceptions import (
37 CommitError, EmptyRepositoryError, CommitDoesNotExistError)
39 38 from rhodecode.model.db import Statistics, CacheKey, User
40 39 from rhodecode.model.meta import Session
41 40 from rhodecode.model.repo import ReadmeFinder
@@ -53,26 +52,32 b' class RepoSummaryView(RepoAppView):'
53 52 c.rhodecode_repo = self.rhodecode_vcs_repo
54 53 return c
55 54
56 def _get_readme_data(self, db_repo, default_renderer):
57 repo_name = db_repo.repo_name
55 def _get_readme_data(self, db_repo, renderer_type):
56
58 57 log.debug('Looking for README file')
59 58
60 @cache_region('long_term')
61 def _generate_readme(cache_key):
59 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
60 db_repo.repo_id, CacheKey.CACHE_TYPE_README)
61 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
62 repo_id=self.db_repo.repo_id)
63 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
64
65 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
66 def generate_repo_readme(repo_id, _repo_name, _renderer_type):
62 67 readme_data = None
63 68 readme_node = None
64 69 readme_filename = None
65 70 commit = self._get_landing_commit_or_none(db_repo)
66 71 if commit:
67 72 log.debug("Searching for a README file.")
68 readme_node = ReadmeFinder(default_renderer).search(commit)
73 readme_node = ReadmeFinder(_renderer_type).search(commit)
69 74 if readme_node:
70 75 relative_urls = {
71 76 'raw': h.route_path(
72 'repo_file_raw', repo_name=repo_name,
77 'repo_file_raw', repo_name=_repo_name,
73 78 commit_id=commit.raw_id, f_path=readme_node.path),
74 79 'standard': h.route_path(
75 'repo_files', repo_name=repo_name,
80 'repo_files', repo_name=_repo_name,
76 81 commit_id=commit.raw_id, f_path=readme_node.path),
77 82 }
78 83 readme_data = self._render_readme_or_none(
@@ -80,14 +85,20 b' class RepoSummaryView(RepoAppView):'
80 85 readme_filename = readme_node.path
81 86 return readme_data, readme_filename
82 87
83 invalidator_context = CacheKey.repo_context_cache(
84 _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
88 inv_context_manager = rc_cache.InvalidationContext(
89 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
90 with inv_context_manager as invalidation_context:
91 args = (db_repo.repo_id, db_repo.repo_name, renderer_type,)
92 # re-compute and store cache if we get invalidate signal
93 if invalidation_context.should_invalidate():
94 instance = generate_repo_readme.refresh(*args)
95 else:
96 instance = generate_repo_readme(*args)
85 97
86 with invalidator_context as context:
87 context.invalidate()
88 computed = context.compute()
89
90 return computed
98 log.debug(
99 'Repo readme generated and computed in %.3fs',
100 inv_context_manager.compute_time)
101 return instance
91 102
92 103 def _get_landing_commit_or_none(self, db_repo):
93 104 log.debug("Getting the landing commit.")
@@ -134,7 +145,7 b' class RepoSummaryView(RepoAppView):'
134 145 except EmptyRepositoryError:
135 146 collection = self.rhodecode_vcs_repo
136 147
137 c.repo_commits = RepoPage(
148 c.repo_commits = h.RepoPage(
138 149 collection, page=p, items_per_page=size, url=url_generator)
139 150 page_ids = [x.raw_id for x in c.repo_commits]
140 151 c.comments = self.db_repo.get_comments(page_ids)
@@ -247,16 +258,23 b' class RepoSummaryView(RepoAppView):'
247 258 renderer='json_ext')
248 259 def repo_stats(self):
249 260 commit_id = self.get_request_commit_id()
261 show_stats = bool(self.db_repo.enable_statistics)
262 repo_id = self.db_repo.repo_id
250 263
251 _namespace = caches.get_repo_namespace_key(
252 caches.SUMMARY_STATS, self.db_repo_name)
253 show_stats = bool(self.db_repo.enable_statistics)
254 cache_manager = caches.get_cache_manager(
255 'repo_cache_long', _namespace)
256 _cache_key = caches.compute_key_from_params(
257 self.db_repo_name, commit_id, show_stats)
264 cache_seconds = safe_int(
265 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
266 cache_on = cache_seconds > 0
267 log.debug(
268 'Computing REPO TREE for repo_id %s commit_id `%s` '
269 'with caching: %s[TTL: %ss]' % (
270 repo_id, commit_id, cache_on, cache_seconds or 0))
258 271
259 def compute_stats():
272 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
273 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
274
275 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
276 condition=cache_on)
277 def compute_stats(repo_id, commit_id, show_stats):
260 278 code_stats = {}
261 279 size = 0
262 280 try:
@@ -279,7 +297,7 b' class RepoSummaryView(RepoAppView):'
279 297 return {'size': h.format_byte_size_binary(size),
280 298 'code_stats': code_stats}
281 299
282 stats = cache_manager.get(_cache_key, createfunc=compute_stats)
300 stats = compute_stats(self.db_repo.repo_id, commit_id, show_stats)
283 301 return stats
284 302
285 303 @LoginRequired()
@@ -62,7 +62,8 b' class SshWrapper(object):'
62 62 key.accessed_on = datetime.datetime.utcnow()
63 63 Session().add(key)
64 64 Session().commit()
65 log.debug('Update key `%s` access time', key_id)
65 log.debug('Update key id:`%s` fingerprint:`%s` access time',
66 key_id, key.ssh_key_fingerprint)
66 67
67 68 def get_connection_info(self):
68 69 """
@@ -119,11 +120,25 b' class SshWrapper(object):'
119 120
120 121 return vcs_type, repo_name, mode
121 122
122 def serve(self, vcs, repo, mode, user, permissions):
123 def serve(self, vcs, repo, mode, user, permissions, branch_permissions):
123 124 store = ScmModel().repos_path
124 125
126 check_branch_perms = False
127 detect_force_push = False
128
129 if branch_permissions:
130 check_branch_perms = True
131 detect_force_push = True
132
125 133 log.debug(
126 'VCS detected:`%s` mode: `%s` repo_name: %s', vcs, mode, repo)
134 'VCS detected:`%s` mode: `%s` repo_name: %s, branch_permission_checks:%s',
135 vcs, mode, repo, check_branch_perms)
136
137 # detect if we have to check branch permissions
138 extras = {
139 'detect_force_push': detect_force_push,
140 'check_branch_perms': check_branch_perms,
141 }
127 142
128 143 if vcs == 'hg':
129 144 server = MercurialServer(
@@ -131,7 +146,7 b' class SshWrapper(object):'
131 146 repo_name=repo, user=user,
132 147 user_permissions=permissions, config=self.config, env=self.env)
133 148 self.server_impl = server
134 return server.run()
149 return server.run(tunnel_extras=extras)
135 150
136 151 elif vcs == 'git':
137 152 server = GitServer(
@@ -139,7 +154,7 b' class SshWrapper(object):'
139 154 repo_name=repo, repo_mode=mode, user=user,
140 155 user_permissions=permissions, config=self.config, env=self.env)
141 156 self.server_impl = server
142 return server.run()
157 return server.run(tunnel_extras=extras)
143 158
144 159 elif vcs == 'svn':
145 160 server = SubversionServer(
@@ -147,7 +162,7 b' class SshWrapper(object):'
147 162 repo_name=None, user=user,
148 163 user_permissions=permissions, config=self.config, env=self.env)
149 164 self.server_impl = server
150 return server.run()
165 return server.run(tunnel_extras=extras)
151 166
152 167 else:
153 168 raise Exception('Unrecognised VCS: {}'.format(vcs))
@@ -187,10 +202,11 b' class SshWrapper(object):'
187 202
188 203 auth_user = user.AuthUser()
189 204 permissions = auth_user.permissions['repositories']
190
205 repo_branch_permissions = auth_user.get_branch_permissions(scm_repo)
191 206 try:
192 207 exit_code, is_updated = self.serve(
193 scm_detected, scm_repo, scm_mode, user, permissions)
208 scm_detected, scm_repo, scm_mode, user, permissions,
209 repo_branch_permissions)
194 210 except Exception:
195 211 log.exception('Error occurred during execution of SshWrapper')
196 212 exit_code = -1
@@ -70,6 +70,11 b' class VcsServer(object):'
70 70 'permission for %s on %s are: %s',
71 71 self.user, self.repo_name, permission)
72 72
73 if not permission:
74 log.error('user `%s` permissions to repo:%s are empty. Forbidding access.',
75 self.user, self.repo_name)
76 return -2
77
73 78 if action == 'pull':
74 79 if permission in self.read_perms:
75 80 log.info(
@@ -83,8 +88,8 b' class VcsServer(object):'
83 88 self.user, self.repo_name)
84 89 return 0
85 90
86 log.error('Cannot properly fetch or allow user %s permissions. '
87 'Return value is: %s, req action: %s',
91 log.error('Cannot properly fetch or verify user `%s` permissions. '
92 'Permissions: %s, vcs action: %s',
88 93 self.user, permission, action)
89 94 return -2
90 95
@@ -101,11 +106,15 b' class VcsServer(object):'
101 106 'make_lock': None,
102 107 'locked_by': [None, None],
103 108 'server_url': None,
104 'is_shadow_repo': False,
105 'hooks_module': 'rhodecode.lib.hooks_daemon',
109 'user_agent': 'ssh-user-agent',
106 110 'hooks': ['push', 'pull'],
111 'hooks_module': 'rhodecode.lib.hooks_daemon',
112 'is_shadow_repo': False,
113 'detect_force_push': False,
114 'check_branch_perms': False,
115
107 116 'SSH': True,
108 'SSH_PERMISSIONS': self.user_permissions.get(self.repo_name)
117 'SSH_PERMISSIONS': self.user_permissions.get(self.repo_name),
109 118 }
110 119 if extras:
111 120 scm_data.update(extras)
@@ -134,11 +143,14 b' class VcsServer(object):'
134 143
135 144 return exit_code, action == "push"
136 145
137 def run(self):
146 def run(self, tunnel_extras=None):
147 tunnel_extras = tunnel_extras or {}
138 148 extras = {}
149 extras.update(tunnel_extras)
139 150
140 151 callback_daemon, extras = prepare_callback_daemon(
141 152 extras, protocol=vcs_settings.HOOKS_PROTOCOL,
153 host=vcs_settings.HOOKS_HOST,
142 154 use_direct_calls=False)
143 155
144 156 with callback_daemon:
@@ -139,6 +139,9 b' class TestGitServer(object):'
139 139 'hooks': ['push', 'pull'],
140 140 'is_shadow_repo': False,
141 141 'hooks_module': 'rhodecode.lib.hooks_daemon',
142 'check_branch_perms': False,
143 'detect_force_push': False,
144 'user_agent': u'ssh-user-agent',
142 145 'SSH': True,
143 146 'SSH_PERMISSIONS': 'repository.admin',
144 147 }
@@ -27,7 +27,7 b' class TestSSHWrapper(object):'
27 27 with pytest.raises(Exception) as exc_info:
28 28 ssh_wrapper.serve(
29 29 vcs='microsoft-tfs', repo='test-repo', mode=None, user='test',
30 permissions={})
30 permissions={}, branch_permissions={})
31 31 assert exc_info.value.message == 'Unrecognised VCS: microsoft-tfs'
32 32
33 33 def test_parse_config(self, ssh_wrapper):
@@ -28,6 +28,7 b' from pyramid.view import view_config'
28 28 from pyramid.response import Response
29 29 from pyramid.renderers import render
30 30
31 from rhodecode import events
31 32 from rhodecode.lib.exceptions import (
32 33 RepoGroupAssignmentError, UserGroupAssignedException)
33 34 from rhodecode.model.forms import (
@@ -139,6 +140,9 b' class UserGroupsView(UserGroupAppView):'
139 140 user_group = self.db_user_group
140 141 user_group_id = user_group.users_group_id
141 142
143 old_user_group_name = self.db_user_group_name
144 new_user_group_name = old_user_group_name
145
142 146 c = self.load_default_context()
143 147 c.user_group = user_group
144 148 c.group_members_obj = [x.user for x in c.user_group.members]
@@ -151,7 +155,7 b' class UserGroupsView(UserGroupAppView):'
151 155 old_data=c.user_group.get_dict(), allow_disabled=True)()
152 156
153 157 old_values = c.user_group.get_api_data()
154 user_group_name = self.request.POST.get('users_group_name')
158
155 159 try:
156 160 form_result = users_group_form.to_python(self.request.POST)
157 161 pstruct = peppercorn.parse(self.request.POST.items())
@@ -159,7 +163,7 b' class UserGroupsView(UserGroupAppView):'
159 163
160 164 user_group, added_members, removed_members = \
161 165 UserGroupModel().update(c.user_group, form_result)
162 updated_user_group = form_result['users_group_name']
166 new_user_group_name = form_result['users_group_name']
163 167
164 168 for user_id in added_members:
165 169 user = User.get(user_id)
@@ -181,8 +185,22 b' class UserGroupsView(UserGroupAppView):'
181 185 'user_group.edit', action_data={'old_data': old_values},
182 186 user=self._rhodecode_user)
183 187
184 h.flash(_('Updated user group %s') % updated_user_group,
188 h.flash(_('Updated user group %s') % new_user_group_name,
185 189 category='success')
190
191 affected_user_ids = []
192 for user_id in added_members + removed_members:
193 affected_user_ids.append(user_id)
194
195 name_changed = old_user_group_name != new_user_group_name
196 if name_changed:
197 owner = User.get_by_username(form_result['user'])
198 owner_id = owner.user_id if owner else self._rhodecode_user.user_id
199 affected_user_ids.append(self._rhodecode_user.user_id)
200 affected_user_ids.append(owner_id)
201
202 events.trigger(events.UserPermissionsChange(affected_user_ids))
203
186 204 Session().commit()
187 205 except formencode.Invalid as errors:
188 206 defaults = errors.value
@@ -204,7 +222,7 b' class UserGroupsView(UserGroupAppView):'
204 222 except Exception:
205 223 log.exception("Exception during update of user group")
206 224 h.flash(_('Error occurred during update of user group %s')
207 % user_group_name, category='error')
225 % new_user_group_name, category='error')
208 226
209 227 raise HTTPFound(
210 228 h.route_path('edit_user_group', user_group_id=user_group_id))
@@ -354,6 +372,14 b' class UserGroupsView(UserGroupAppView):'
354 372
355 373 Session().commit()
356 374 h.flash(_('User Group permissions updated'), category='success')
375
376 affected_user_ids = []
377 for change in changes['added'] + changes['updated'] + changes['deleted']:
378 if change['type'] == 'user':
379 affected_user_ids.append(change['id'])
380
381 events.trigger(events.UserPermissionsChange(affected_user_ids))
382
357 383 raise HTTPFound(
358 384 h.route_path('edit_user_group_perms', user_group_id=user_group_id))
359 385
@@ -37,6 +37,7 b' log = logging.getLogger(__name__)'
37 37 # Plugin ID prefixes to distinct between normal and legacy plugins.
38 38 plugin_prefix = 'egg:'
39 39 legacy_plugin_prefix = 'py:'
40 plugin_default_auth_ttl = 30
40 41
41 42
42 43 # TODO: Currently this is only used to discover the authentication plugins.
@@ -35,7 +35,7 b' from pyramid.threadlocal import get_curr'
35 35
36 36 from rhodecode.authentication.interface import IAuthnPluginRegistry
37 37 from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
38 from rhodecode.lib import caches
38 from rhodecode.lib import rc_cache
39 39 from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt
40 40 from rhodecode.lib.utils2 import safe_int, safe_str
41 41 from rhodecode.lib.exceptions import LdapConnectionError
@@ -439,7 +439,11 b' class RhodeCodeAuthPluginBase(object):'
439 439
440 440 def get_ttl_cache(self, settings=None):
441 441 plugin_settings = settings or self.get_settings()
442 cache_ttl = 0
442 # we set default to 30, we make a compromise here,
443 # performance > security, mostly due to LDAP/SVN, majority
444 # of users pick cache_ttl to be enabled
445 from rhodecode.authentication import plugin_default_auth_ttl
446 cache_ttl = plugin_default_auth_ttl
443 447
444 448 if isinstance(self.AUTH_CACHE_TTL, (int, long)):
445 449 # plugin cache set inside is more important than the settings value
@@ -633,22 +637,6 b' def get_authn_registry(registry=None):'
633 637 return authn_registry
634 638
635 639
636 def get_auth_cache_manager(custom_ttl=None, suffix=None):
637 cache_name = 'rhodecode.authentication'
638 if suffix:
639 cache_name = 'rhodecode.authentication.{}'.format(suffix)
640 return caches.get_cache_manager(
641 'auth_plugins', cache_name, custom_ttl)
642
643
644 def get_perms_cache_manager(custom_ttl=None, suffix=None):
645 cache_name = 'rhodecode.permissions'
646 if suffix:
647 cache_name = 'rhodecode.permissions.{}'.format(suffix)
648 return caches.get_cache_manager(
649 'auth_plugins', cache_name, custom_ttl)
650
651
652 640 def authenticate(username, password, environ=None, auth_type=None,
653 641 skip_missing=False, registry=None, acl_repo_name=None):
654 642 """
@@ -707,45 +695,37 b' def authenticate(username, password, env'
707 695
708 696 plugin_cache_active, cache_ttl = plugin.get_ttl_cache(plugin_settings)
709 697
710 # get instance of cache manager configured for a namespace
711 cache_manager = get_auth_cache_manager(
712 custom_ttl=cache_ttl, suffix=user.user_id if user else '')
713
714 698 log.debug('AUTH_CACHE_TTL for plugin `%s` active: %s (TTL: %s)',
715 699 plugin.get_id(), plugin_cache_active, cache_ttl)
716 700
717 # for environ based password can be empty, but then the validation is
718 # on the server that fills in the env data needed for authentication
719
720 _password_hash = caches.compute_key_from_params(
721 plugin.name, username, (password or ''))
701 user_id = user.user_id if user else None
702 # don't cache for empty users
703 plugin_cache_active = plugin_cache_active and user_id
704 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
705 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
722 706
723 # _authenticate is a wrapper for .auth() method of plugin.
724 # it checks if .auth() sends proper data.
725 # For RhodeCodeExternalAuthPlugin it also maps users to
726 # Database and maps the attributes returned from .auth()
727 # to RhodeCode database. If this function returns data
728 # then auth is correct.
729 start = time.time()
730 log.debug('Running plugin `%s` _authenticate method', plugin.get_id())
707 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
708 expiration_time=cache_ttl,
709 condition=plugin_cache_active)
710 def compute_auth(
711 cache_name, plugin_name, username, password):
731 712
732 def auth_func():
733 """
734 This function is used internally in Cache of Beaker to calculate
735 Results
736 """
737 log.debug('auth: calculating password access now...')
713 # _authenticate is a wrapper for .auth() method of plugin.
714 # it checks if .auth() sends proper data.
715 # For RhodeCodeExternalAuthPlugin it also maps users to
716 # Database and maps the attributes returned from .auth()
717 # to RhodeCode database. If this function returns data
718 # then auth is correct.
719 log.debug('Running plugin `%s` _authenticate method '
720 'using username and password', plugin.get_id())
738 721 return plugin._authenticate(
739 722 user, username, password, plugin_settings,
740 723 environ=environ or {})
741 724
742 if plugin_cache_active:
743 log.debug('Trying to fetch cached auth by pwd hash `...%s`',
744 _password_hash[:6])
745 plugin_user = cache_manager.get(
746 _password_hash, createfunc=auth_func)
747 else:
748 plugin_user = auth_func()
725 start = time.time()
726 # for environ based auth, password can be empty, but then the validation is
727 # on the server that fills in the env data needed for authentication
728 plugin_user = compute_auth('auth', plugin.name, username, (password or ''))
749 729
750 730 auth_time = time.time() - start
751 731 log.debug('Authentication for plugin `%s` completed in %.3fs, '
@@ -52,6 +52,7 b' except ImportError:'
52 52 class LdapError(Exception):
53 53 pass
54 54
55
55 56 def plugin_factory(plugin_id, *args, **kwds):
56 57 """
57 58 Factory function that is called during plugin discovery.
@@ -111,8 +111,8 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
111 111 if not username or not password:
112 112 log.debug('Empty username or password skipping...')
113 113 return None
114
115 auth_result = pam.authenticate(username, password, settings["service"])
114 _pam = pam.pam()
115 auth_result = _pam.authenticate(username, password, settings["service"])
116 116
117 117 if not auth_result:
118 118 log.error("PAM was unable to authenticate user: %s" % (username, ))
@@ -20,6 +20,7 b''
20 20
21 21 import colander
22 22
23 from rhodecode.authentication import plugin_default_auth_ttl
23 24 from rhodecode.translation import _
24 25
25 26
@@ -39,7 +40,7 b' class AuthnPluginSettingsSchemaBase(cola'
39 40 )
40 41 cache_ttl = colander.SchemaNode(
41 42 colander.Int(),
42 default=0,
43 default=plugin_default_auth_ttl,
43 44 description=_('Amount of seconds to cache the authentication and '
44 45 'permissions check response call for this plugin. \n'
45 46 'Useful for expensive calls like LDAP to improve the '
@@ -30,10 +30,7 b' class EnabledAuthPlugin(object):'
30 30 """
31 31
32 32 def __init__(self, plugin):
33 self.new_value = set([
34 'egg:rhodecode-enterprise-ce#rhodecode',
35 plugin.get_id()
36 ])
33 self.new_value = {'egg:rhodecode-enterprise-ce#rhodecode', plugin.get_id()}
37 34
38 35 def __enter__(self):
39 36 from rhodecode.model.settings import SettingsModel
@@ -47,7 +44,7 b' class EnabledAuthPlugin(object):'
47 44 'auth_plugins', ','.join(self._old_value))
48 45
49 46
50 class DisabledAuthPlugin():
47 class DisabledAuthPlugin(object):
51 48 """
52 49 Context manager that updates the 'auth_plugins' setting in DB to disable
53 50 a plugin. Previous setting is restored on exit.
@@ -27,12 +27,10 b' from pyramid.renderers import render'
27 27 from pyramid.response import Response
28 28
29 29 from rhodecode.apps._base import BaseAppView
30 from rhodecode.authentication.base import (
31 get_auth_cache_manager, get_perms_cache_manager, get_authn_registry)
30 from rhodecode.authentication.base import get_authn_registry
32 31 from rhodecode.lib import helpers as h
33 32 from rhodecode.lib.auth import (
34 33 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
35 from rhodecode.lib.caches import clear_cache_manager
36 34 from rhodecode.model.forms import AuthSettingsForm
37 35 from rhodecode.model.meta import Session
38 36 from rhodecode.model.settings import SettingsModel
@@ -102,16 +100,6 b' class AuthnPluginViewBase(BaseAppView):'
102 100 self.plugin.create_or_update_setting(name, value)
103 101 Session().commit()
104 102
105 # cleanup cache managers in case of change for plugin
106 # TODO(marcink): because we can register multiple namespaces
107 # we should at some point figure out how to retrieve ALL namespace
108 # cache managers and clear them...
109 cache_manager = get_auth_cache_manager()
110 clear_cache_manager(cache_manager)
111
112 cache_manager = get_perms_cache_manager()
113 clear_cache_manager(cache_manager)
114
115 103 # Display success message and redirect.
116 104 h.flash(_('Auth settings updated successfully.'), category='success')
117 105 redirect_to = self.request.resource_path(
@@ -18,12 +18,10 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21
22 21 import os
23 22 import logging
24 23 import rhodecode
25 24
26
27 25 from rhodecode.config import utils
28 26
29 27 from rhodecode.lib.utils import load_rcextensions
@@ -52,6 +50,8 b' def load_pyramid_environment(global_conf'
52 50 if settings['is_test']:
53 51 rhodecode.is_test = True
54 52 rhodecode.disable_error_handler = True
53 from rhodecode import authentication
54 authentication.plugin_default_auth_ttl = 0
55 55
56 56 utils.initialize_test_environment(settings_merged)
57 57
@@ -310,11 +310,7 b''
310 310 },
311 311 "python2.7-requests-2.9.1": {
312 312 "Apache License 2.0": "http://spdx.org/licenses/Apache-2.0"
313 },
314 "python2.7-setuptools-19.4": {
315 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0",
316 "Zope Public License 2.0": "http://spdx.org/licenses/ZPL-2.0"
317 },
313 },
318 314 "python2.7-setuptools-scm-1.15.6": {
319 315 "MIT License": "http://spdx.org/licenses/MIT"
320 316 },
@@ -18,18 +18,20 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 import os
22 import sys
21 23 import logging
22 import traceback
23 24 import collections
25 import tempfile
24 26
25 27 from paste.gzipper import make_gzip_middleware
28 import pyramid.events
26 29 from pyramid.wsgi import wsgiapp
27 30 from pyramid.authorization import ACLAuthorizationPolicy
28 31 from pyramid.config import Configurator
29 32 from pyramid.settings import asbool, aslist
30 33 from pyramid.httpexceptions import (
31 34 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
32 from pyramid.events import ApplicationCreated
33 35 from pyramid.renderers import render_to_response
34 36
35 37 from rhodecode.model import meta
@@ -37,7 +39,9 b' from rhodecode.config import patches'
37 39 from rhodecode.config import utils as config_utils
38 40 from rhodecode.config.environment import load_pyramid_environment
39 41
42 import rhodecode.events
40 43 from rhodecode.lib.middleware.vcs import VCSMiddleware
44 from rhodecode.lib.request import Request
41 45 from rhodecode.lib.vcs import VCSCommunicationError
42 46 from rhodecode.lib.exceptions import VCSServerUnavailable
43 47 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
@@ -45,6 +49,7 b' from rhodecode.lib.middleware.https_fixu'
45 49 from rhodecode.lib.celerylib.loader import configure_celery
46 50 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
47 51 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
52 from rhodecode.lib.exc_tracking import store_exception
48 53 from rhodecode.subscribers import (
49 54 scan_repositories_if_enabled, write_js_routes_if_enabled,
50 55 write_metadata_if_needed, inject_app_settings)
@@ -70,6 +75,15 b' def make_pyramid_app(global_config, **se'
70 75 cases when these fragments are assembled from another place.
71 76
72 77 """
78
79 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
80 # will be replaced by the value of the environment variable "NAME" in this case.
81 environ = {
82 'ENV_{}'.format(key): value for key, value in os.environ.items()}
83
84 global_config = _substitute_values(global_config, environ)
85 settings = _substitute_values(settings, environ)
86
73 87 sanitize_settings_and_apply_defaults(settings)
74 88
75 89 config = Configurator(settings=settings)
@@ -160,7 +174,17 b' def error_handler(exception, request):'
160 174 c.causes = base_response.causes
161 175
162 176 c.messages = helpers.flash.pop_messages(request=request)
163 c.traceback = traceback.format_exc()
177
178 exc_info = sys.exc_info()
179 c.exception_id = id(exc_info)
180 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
181 or base_response.status_code > 499
182 c.exception_id_url = request.route_url(
183 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
184
185 if c.show_exception_id:
186 store_exception(c.exception_id, exc_info)
187
164 188 response = render_to_response(
165 189 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
166 190 response=base_response)
@@ -192,6 +216,7 b' def includeme_first(config):'
192 216
193 217 def includeme(config):
194 218 settings = config.registry.settings
219 config.set_request_factory(Request)
195 220
196 221 # plugin information
197 222 config.registry.rhodecode_plugins = collections.OrderedDict()
@@ -207,7 +232,7 b' def includeme(config):'
207 232 # Includes which are required. The application would fail without them.
208 233 config.include('pyramid_mako')
209 234 config.include('pyramid_beaker')
210 config.include('rhodecode.lib.caches')
235 config.include('rhodecode.lib.rc_cache')
211 236
212 237 config.include('rhodecode.authentication')
213 238 config.include('rhodecode.integrations')
@@ -243,16 +268,14 b' def includeme(config):'
243 268 settings['default_locale_name'] = settings.get('lang', 'en')
244 269
245 270 # Add subscribers.
246 config.add_subscriber(inject_app_settings, ApplicationCreated)
247 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
248 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
249 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
250
251 # events
252 # TODO(marcink): this should be done when pyramid migration is finished
253 # config.add_subscriber(
254 # 'rhodecode.integrations.integrations_event_handler',
255 # 'rhodecode.events.RhodecodeEvent')
271 config.add_subscriber(inject_app_settings,
272 pyramid.events.ApplicationCreated)
273 config.add_subscriber(scan_repositories_if_enabled,
274 pyramid.events.ApplicationCreated)
275 config.add_subscriber(write_metadata_if_needed,
276 pyramid.events.ApplicationCreated)
277 config.add_subscriber(write_js_routes_if_enabled,
278 pyramid.events.ApplicationCreated)
256 279
257 280 # request custom methods
258 281 config.add_request_method(
@@ -290,14 +313,15 b' def wrap_app_in_wsgi_middlewares(pyramid'
290 313 """
291 314 Apply outer WSGI middlewares around the application.
292 315 """
293 settings = config.registry.settings
316 registry = config.registry
317 settings = registry.settings
294 318
295 319 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
296 320 pyramid_app = HttpsFixup(pyramid_app, settings)
297 321
298 322 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
299 323 pyramid_app, settings)
300 config.registry.ae_client = _ae_client
324 registry.ae_client = _ae_client
301 325
302 326 if settings['gzip_responses']:
303 327 pyramid_app = make_gzip_middleware(
@@ -318,6 +342,7 b' def wrap_app_in_wsgi_middlewares(pyramid'
318 342 # if not, then something, somewhere is leaving a connection open
319 343 pool = meta.Base.metadata.bind.engine.pool
320 344 log.debug('sa pool status: %s', pool.status())
345 log.debug('Request processing finalized')
321 346
322 347 return pyramid_app_with_cleanup
323 348
@@ -370,6 +395,7 b' def sanitize_settings_and_apply_defaults'
370 395 # Call split out functions that sanitize settings for each topic.
371 396 _sanitize_appenlight_settings(settings)
372 397 _sanitize_vcs_settings(settings)
398 _sanitize_cache_settings(settings)
373 399
374 400 # configure instance id
375 401 config_utils.set_instance_id(settings)
@@ -389,6 +415,7 b' def _sanitize_vcs_settings(settings):'
389 415 _string_setting(settings, 'vcs.svn.compatible_version', '')
390 416 _string_setting(settings, 'git_rev_filter', '--all')
391 417 _string_setting(settings, 'vcs.hooks.protocol', 'http')
418 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
392 419 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
393 420 _string_setting(settings, 'vcs.server', '')
394 421 _string_setting(settings, 'vcs.server.log_level', 'debug')
@@ -401,13 +428,87 b' def _sanitize_vcs_settings(settings):'
401 428 _int_setting(settings, 'vcs.connection_timeout', 3600)
402 429
403 430 # Support legacy values of vcs.scm_app_implementation. Legacy
404 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
405 # which is now mapped to 'http'.
431 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
432 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
406 433 scm_app_impl = settings['vcs.scm_app_implementation']
407 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
434 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
408 435 settings['vcs.scm_app_implementation'] = 'http'
409 436
410 437
438 def _sanitize_cache_settings(settings):
439 _string_setting(settings, 'cache_dir',
440 os.path.join(tempfile.gettempdir(), 'rc_cache'))
441 # cache_perms
442 _string_setting(
443 settings,
444 'rc_cache.cache_perms.backend',
445 'dogpile.cache.rc.file_namespace')
446 _int_setting(
447 settings,
448 'rc_cache.cache_perms.expiration_time',
449 60)
450 _string_setting(
451 settings,
452 'rc_cache.cache_perms.arguments.filename',
453 os.path.join(tempfile.gettempdir(), 'rc_cache_1'))
454
455 # cache_repo
456 _string_setting(
457 settings,
458 'rc_cache.cache_repo.backend',
459 'dogpile.cache.rc.file_namespace')
460 _int_setting(
461 settings,
462 'rc_cache.cache_repo.expiration_time',
463 60)
464 _string_setting(
465 settings,
466 'rc_cache.cache_repo.arguments.filename',
467 os.path.join(tempfile.gettempdir(), 'rc_cache_2'))
468
469 # cache_license
470 _string_setting(
471 settings,
472 'rc_cache.cache_license.backend',
473 'dogpile.cache.rc.file_namespace')
474 _int_setting(
475 settings,
476 'rc_cache.cache_license.expiration_time',
477 5*60)
478 _string_setting(
479 settings,
480 'rc_cache.cache_license.arguments.filename',
481 os.path.join(tempfile.gettempdir(), 'rc_cache_3'))
482
483 # cache_repo_longterm memory, 96H
484 _string_setting(
485 settings,
486 'rc_cache.cache_repo_longterm.backend',
487 'dogpile.cache.rc.memory_lru')
488 _int_setting(
489 settings,
490 'rc_cache.cache_repo_longterm.expiration_time',
491 345600)
492 _int_setting(
493 settings,
494 'rc_cache.cache_repo_longterm.max_size',
495 10000)
496
497 # sql_cache_short
498 _string_setting(
499 settings,
500 'rc_cache.sql_cache_short.backend',
501 'dogpile.cache.rc.memory_lru')
502 _int_setting(
503 settings,
504 'rc_cache.sql_cache_short.expiration_time',
505 30)
506 _int_setting(
507 settings,
508 'rc_cache.sql_cache_short.max_size',
509 10000)
510
511
411 512 def _int_setting(settings, name, default):
412 513 settings[name] = int(settings.get(name, default))
413 514
@@ -436,3 +537,20 b' def _string_setting(settings, name, defa'
436 537 if lower:
437 538 value = value.lower()
438 539 settings[name] = value
540
541
542 def _substitute_values(mapping, substitutions):
543
544 try:
545 result = {
546 # Note: Cannot use regular replacements, since they would clash
547 # with the implementation of ConfigParser. Using "format" instead.
548 key: value.format(**substitutions)
549 for key, value in mapping.items()
550 }
551 except KeyError as e:
552 raise ValueError(
553 'Failed to substitute env variable: {}. '
554 'Make sure you have specified this env variable without ENV_ prefix'.format(e))
555
556 return result
@@ -25,12 +25,13 b' import platform'
25 25 from rhodecode.model import init_model
26 26
27 27
28
29 28 def configure_vcs(config):
30 29 """
31 30 Patch VCS config with some RhodeCode specific stuff
32 31 """
33 32 from rhodecode.lib.vcs import conf
33 import rhodecode.lib.vcs.conf.settings
34
34 35 conf.settings.BACKENDS = {
35 36 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
36 37 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
@@ -38,6 +39,7 b' def configure_vcs(config):'
38 39 }
39 40
40 41 conf.settings.HOOKS_PROTOCOL = config['vcs.hooks.protocol']
42 conf.settings.HOOKS_HOST = config['vcs.hooks.host']
41 43 conf.settings.HOOKS_DIRECT_CALLS = config['vcs.hooks.direct_calls']
42 44 conf.settings.GIT_REV_FILTER = shlex.split(config['git_rev_filter'])
43 45 conf.settings.DEFAULT_ENCODINGS = config['default_encoding']
@@ -18,7 +18,7 b''
18 18
19 19 import logging
20 20 from pyramid.threadlocal import get_current_registry
21 from rhodecode.events.base import RhodecodeEvent
21 from rhodecode.events.base import RhodeCodeIntegrationEvent
22 22
23 23
24 24 log = logging.getLogger(__name__)
@@ -32,28 +32,24 b' def trigger(event, registry=None):'
32 32 # For the first step we are using pyramids thread locals here. If the
33 33 # event mechanism works out as a good solution we should think about
34 34 # passing the registry as an argument to get rid of it.
35 event_name = event.__class__
36 log.debug('event %s sent for execution', event_name)
35 37 registry = registry or get_current_registry()
36 38 registry.notify(event)
37 log.debug('event %s triggered using registry %s', event, registry)
38
39 # Until we can work around the problem that VCS operations do not have a
40 # pyramid context to work with, we send the events to integrations directly
39 log.debug('event %s triggered using registry %s', event_name, registry)
41 40
42 # Later it will be possible to use regular pyramid subscribers ie:
43 # config.add_subscriber(
44 # 'rhodecode.integrations.integrations_event_handler',
45 # 'rhodecode.events.RhodecodeEvent')
46 # trigger(event, request.registry)
41 # Send the events to integrations directly
42 from rhodecode.integrations import integrations_event_handler
43 if isinstance(event, RhodeCodeIntegrationEvent):
44 integrations_event_handler(event)
47 45
48 from rhodecode.integrations import integrations_event_handler
49 if isinstance(event, RhodecodeEvent):
50 integrations_event_handler(event)
51 46
52 47 from rhodecode.events.user import ( # noqa
53 48 UserPreCreate,
54 49 UserPostCreate,
55 50 UserPreUpdate,
56 UserRegistered
51 UserRegistered,
52 UserPermissionsChange,
57 53 )
58 54
59 55 from rhodecode.events.repo import ( # noqa
@@ -110,3 +110,9 b' class RhodecodeEvent(object):'
110 110 'server_url': self.server_url
111 111 }
112 112 return data
113
114
115 class RhodeCodeIntegrationEvent(RhodecodeEvent):
116 """
117 Special subclass for Integration events
118 """
@@ -22,7 +22,7 b' import datetime'
22 22
23 23 from rhodecode.translation import lazy_ugettext
24 24 from rhodecode.model.db import User, Repository, Session
25 from rhodecode.events.base import RhodecodeEvent
25 from rhodecode.events.base import RhodeCodeIntegrationEvent
26 26 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
27 27
28 28 log = logging.getLogger(__name__)
@@ -147,7 +147,7 b' def _issues_as_dict(commits):'
147 147 return issues
148 148
149 149
150 class RepoEvent(RhodecodeEvent):
150 class RepoEvent(RhodeCodeIntegrationEvent):
151 151 """
152 152 Base class for events acting on a repository.
153 153
@@ -19,13 +19,13 b''
19 19 import logging
20 20
21 21 from rhodecode.translation import lazy_ugettext
22 from rhodecode.events.base import RhodecodeEvent
22 from rhodecode.events.base import RhodeCodeIntegrationEvent
23 23
24 24
25 25 log = logging.getLogger(__name__)
26 26
27 27
28 class RepoGroupEvent(RhodecodeEvent):
28 class RepoGroupEvent(RhodeCodeIntegrationEvent):
29 29 """
30 30 Base class for events acting on a repository group.
31 31
@@ -20,7 +20,7 b' import logging'
20 20 from zope.interface import implementer
21 21
22 22 from rhodecode.translation import lazy_ugettext
23 from rhodecode.events.base import RhodecodeEvent
23 from rhodecode.events.base import RhodecodeEvent, RhodeCodeIntegrationEvent
24 24 from rhodecode.events.interfaces import (
25 25 IUserRegistered, IUserPreCreate, IUserPreUpdate)
26 26
@@ -28,7 +28,7 b' log = logging.getLogger(__name__)'
28 28
29 29
30 30 @implementer(IUserRegistered)
31 class UserRegistered(RhodecodeEvent):
31 class UserRegistered(RhodeCodeIntegrationEvent):
32 32 """
33 33 An instance of this class is emitted as an :term:`event` whenever a user
34 34 account is registered.
@@ -43,7 +43,7 b' class UserRegistered(RhodecodeEvent):'
43 43
44 44
45 45 @implementer(IUserPreCreate)
46 class UserPreCreate(RhodecodeEvent):
46 class UserPreCreate(RhodeCodeIntegrationEvent):
47 47 """
48 48 An instance of this class is emitted as an :term:`event` before a new user
49 49 object is created.
@@ -57,7 +57,7 b' class UserPreCreate(RhodecodeEvent):'
57 57
58 58
59 59 @implementer(IUserPreCreate)
60 class UserPostCreate(RhodecodeEvent):
60 class UserPostCreate(RhodeCodeIntegrationEvent):
61 61 """
62 62 An instance of this class is emitted as an :term:`event` after a new user
63 63 object is created.
@@ -71,7 +71,7 b' class UserPostCreate(RhodecodeEvent):'
71 71
72 72
73 73 @implementer(IUserPreUpdate)
74 class UserPreUpdate(RhodecodeEvent):
74 class UserPreUpdate(RhodeCodeIntegrationEvent):
75 75 """
76 76 An instance of this class is emitted as an :term:`event` before a user
77 77 object is updated.
@@ -83,3 +83,22 b' class UserPreUpdate(RhodecodeEvent):'
83 83 super(UserPreUpdate, self).__init__()
84 84 self.user = user
85 85 self.user_data = user_data
86
87
88 class UserPermissionsChange(RhodecodeEvent):
89 """
90 This event should be triggered on an event that permissions of user might changed.
91 Currently this should be triggered on:
92
93 - user added/removed from user group
94 - repo permissions changed
95 - repo group permissions changed
96 - user group permissions changed
97
98 """
99 name = 'user-permissions-change'
100 display_name = lazy_ugettext('user permissions change')
101
102 def __init__(self, user_ids):
103 super(UserPermissionsChange, self).__init__()
104 self.user_ids = user_ids
This diff has been collapsed as it changes many lines, (3101 lines changed) Show them Hide them
@@ -6,9 +6,9 b''
6 6 #, fuzzy
7 7 msgid ""
8 8 msgstr ""
9 "Project-Id-Version: rhodecode-enterprise-ce 4.12.0\n"
9 "Project-Id-Version: rhodecode-enterprise-ce 4.13.0\n"
10 10 "Report-Msgid-Bugs-To: marcin@rhodecode.com\n"
11 "POT-Creation-Date: 2018-04-23 15:50+0200\n"
11 "POT-Creation-Date: 2018-09-04 13:25+0200\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -24,7 +24,7 b' msgid "Global"'
24 24 msgstr ""
25 25
26 26 #: rhodecode/apps/admin/navigation.py:74
27 #: rhodecode/templates/admin/repos/repo_edit.mako:55
27 #: rhodecode/templates/admin/repos/repo_edit.mako:58
28 28 msgid "VCS"
29 29 msgstr ""
30 30
@@ -37,17 +37,17 b' msgid "Remap and Rescan"'
37 37 msgstr ""
38 38
39 39 #: rhodecode/apps/admin/navigation.py:80
40 #: rhodecode/templates/admin/repos/repo_edit.mako:61
40 #: rhodecode/templates/admin/repos/repo_edit.mako:64
41 41 msgid "Issue Tracker"
42 42 msgstr ""
43 43
44 44 #: rhodecode/apps/admin/navigation.py:82
45 45 #: rhodecode/integrations/types/email.py:176
46 #: rhodecode/templates/register.mako:76
46 #: rhodecode/templates/register.mako:91
47 47 #: rhodecode/templates/admin/my_account/my_account_profile.mako:48
48 48 #: rhodecode/templates/admin/users/user_add.mako:86
49 49 #: rhodecode/templates/admin/users/user_edit_profile.mako:65
50 #: rhodecode/templates/admin/users/users.mako:65
50 #: rhodecode/templates/admin/users/users.mako:73
51 51 #: rhodecode/templates/email_templates/user_registration.mako:25
52 52 #: rhodecode/templates/users/user_profile.mako:51
53 53 msgid "Email"
@@ -74,7 +74,7 b' msgstr ""'
74 74 #: rhodecode/templates/admin/integrations/new.mako:17
75 75 #: rhodecode/templates/admin/integrations/new.mako:23
76 76 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:51
77 #: rhodecode/templates/admin/repos/repo_edit.mako:75
77 #: rhodecode/templates/admin/repos/repo_edit.mako:78
78 78 #: rhodecode/templates/base/base.mako:84
79 79 msgid "Integrations"
80 80 msgstr ""
@@ -85,23 +85,27 b' msgid "System Info"'
85 85 msgstr ""
86 86
87 87 #: rhodecode/apps/admin/navigation.py:92
88 msgid "Exceptions Tracker"
89 msgstr ""
90
91 #: rhodecode/apps/admin/navigation.py:95
88 92 msgid "Processes"
89 93 msgstr ""
90 94
91 #: rhodecode/apps/admin/navigation.py:94
95 #: rhodecode/apps/admin/navigation.py:97
92 96 msgid "User Sessions"
93 97 msgstr ""
94 98
95 #: rhodecode/apps/admin/navigation.py:96
99 #: rhodecode/apps/admin/navigation.py:99
96 100 msgid "Open Source Licenses"
97 101 msgstr ""
98 102
99 #: rhodecode/apps/admin/navigation.py:98
100 #: rhodecode/templates/admin/repos/repo_edit.mako:83
103 #: rhodecode/apps/admin/navigation.py:101
104 #: rhodecode/templates/admin/repos/repo_edit.mako:86
101 105 msgid "Automation"
102 106 msgstr ""
103 107
104 #: rhodecode/apps/admin/navigation.py:102
108 #: rhodecode/apps/admin/navigation.py:105
105 109 msgid "Labs"
106 110 msgstr ""
107 111
@@ -113,25 +117,33 b' msgstr ""'
113 117 msgid "Error occurred during update of default values"
114 118 msgstr ""
115 119
120 #: rhodecode/apps/admin/views/exception_tracker.py:136
121 msgid "Removed {} Exceptions"
122 msgstr ""
123
124 #: rhodecode/apps/admin/views/exception_tracker.py:153
125 msgid "Removed Exception {}"
126 msgstr ""
127
116 128 #: rhodecode/apps/admin/views/permissions.py:120
117 129 msgid "Application permissions updated successfully"
118 130 msgstr ""
119 131
120 132 #: rhodecode/apps/admin/views/permissions.py:141
121 #: rhodecode/apps/admin/views/permissions.py:213
122 #: rhodecode/apps/admin/views/permissions.py:288
133 #: rhodecode/apps/admin/views/permissions.py:214
134 #: rhodecode/apps/admin/views/permissions.py:313
123 135 msgid "Error occurred during update of permissions"
124 136 msgstr ""
125 137
126 #: rhodecode/apps/admin/views/permissions.py:193
138 #: rhodecode/apps/admin/views/permissions.py:194
127 139 msgid "Object permissions updated successfully"
128 140 msgstr ""
129 141
130 #: rhodecode/apps/admin/views/permissions.py:268
142 #: rhodecode/apps/admin/views/permissions.py:293
131 143 msgid "Global permissions updated successfully"
132 144 msgstr ""
133 145
134 #: rhodecode/apps/admin/views/permissions.py:450
146 #: rhodecode/apps/admin/views/permissions.py:475
135 147 #: rhodecode/templates/admin/gists/show.mako:63
136 148 #: rhodecode/templates/admin/integrations/list.mako:174
137 149 #: rhodecode/templates/admin/my_account/my_account_profile.mako:5
@@ -146,27 +158,27 b' msgstr ""'
146 158 #: rhodecode/templates/files/files_edit.mako:168
147 159 #: rhodecode/templates/files/files_source.mako:54
148 160 #: rhodecode/templates/files/files_source.mako:57
149 #: rhodecode/templates/pullrequests/pullrequest_show.mako:63
150 #: rhodecode/templates/pullrequests/pullrequest_show.mako:345
161 #: rhodecode/templates/pullrequests/pullrequest_show.mako:64
162 #: rhodecode/templates/pullrequests/pullrequest_show.mako:347
151 163 #: rhodecode/templates/user_group/profile.mako:7
152 164 #: rhodecode/templates/users/user_profile.mako:7
153 165 msgid "Edit"
154 166 msgstr ""
155 167
156 #: rhodecode/apps/admin/views/permissions.py:478
168 #: rhodecode/apps/admin/views/permissions.py:503
157 169 msgid "Updated SSH keys file: {}"
158 170 msgstr ""
159 171
160 #: rhodecode/apps/admin/views/permissions.py:481
172 #: rhodecode/apps/admin/views/permissions.py:506
161 173 msgid "SSH key support is disabled in .ini file"
162 174 msgstr ""
163 175
164 #: rhodecode/apps/admin/views/repo_groups.py:181
176 #: rhodecode/apps/admin/views/repo_groups.py:182
165 177 #, python-format
166 178 msgid "Created repository group %s"
167 179 msgstr ""
168 180
169 #: rhodecode/apps/admin/views/repo_groups.py:199
181 #: rhodecode/apps/admin/views/repo_groups.py:200
170 182 #, python-format
171 183 msgid "Error occurred during creation of repository group %s"
172 184 msgstr ""
@@ -326,289 +338,297 b' msgid "Platform UUID"'
326 338 msgstr ""
327 339
328 340 #: rhodecode/apps/admin/views/system_info.py:115
329 msgid "Python version"
341 msgid "Lang"
330 342 msgstr ""
331 343
332 344 #: rhodecode/apps/admin/views/system_info.py:116
345 msgid "Python version"
346 msgstr ""
347
348 #: rhodecode/apps/admin/views/system_info.py:117
333 349 msgid "Python path"
334 350 msgstr ""
335 351
336 #: rhodecode/apps/admin/views/system_info.py:120
337 msgid "CPU"
338 msgstr ""
339
340 352 #: rhodecode/apps/admin/views/system_info.py:121
341 msgid "Load"
353 msgid "CPU"
342 354 msgstr ""
343 355
344 356 #: rhodecode/apps/admin/views/system_info.py:122
345 msgid "Memory"
357 msgid "Load"
346 358 msgstr ""
347 359
348 360 #: rhodecode/apps/admin/views/system_info.py:123
361 msgid "Memory"
362 msgstr ""
363
364 #: rhodecode/apps/admin/views/system_info.py:124
349 365 msgid "Uptime"
350 366 msgstr ""
351 367
352 #: rhodecode/apps/admin/views/system_info.py:127
368 #: rhodecode/apps/admin/views/system_info.py:128
353 369 msgid "Ulimit"
354 370 msgstr ""
355 371
356 #: rhodecode/apps/admin/views/system_info.py:130
357 msgid "Storage location"
358 msgstr ""
359
360 372 #: rhodecode/apps/admin/views/system_info.py:131
361 msgid "Storage info"
373 msgid "Storage location"
362 374 msgstr ""
363 375
364 376 #: rhodecode/apps/admin/views/system_info.py:132
377 msgid "Storage info"
378 msgstr ""
379
380 #: rhodecode/apps/admin/views/system_info.py:133
365 381 msgid "Storage inodes"
366 382 msgstr ""
367 383
368 #: rhodecode/apps/admin/views/system_info.py:134
369 msgid "Gist storage location"
370 msgstr ""
371
372 384 #: rhodecode/apps/admin/views/system_info.py:135
385 msgid "Gist storage location"
386 msgstr ""
387
388 #: rhodecode/apps/admin/views/system_info.py:136
373 389 msgid "Gist storage info"
374 390 msgstr ""
375 391
376 #: rhodecode/apps/admin/views/system_info.py:137
377 msgid "Archive cache storage location"
378 msgstr ""
379
380 392 #: rhodecode/apps/admin/views/system_info.py:138
393 msgid "Archive cache storage location"
394 msgstr ""
395
396 #: rhodecode/apps/admin/views/system_info.py:139
381 397 msgid "Archive cache info"
382 398 msgstr ""
383 399
384 #: rhodecode/apps/admin/views/system_info.py:140
385 msgid "Temp storage location"
386 msgstr ""
387
388 400 #: rhodecode/apps/admin/views/system_info.py:141
401 msgid "Temp storage location"
402 msgstr ""
403
404 #: rhodecode/apps/admin/views/system_info.py:142
389 405 msgid "Temp storage info"
390 406 msgstr ""
391 407
392 #: rhodecode/apps/admin/views/system_info.py:143
393 msgid "Search info"
394 msgstr ""
395
396 408 #: rhodecode/apps/admin/views/system_info.py:144
409 msgid "Search info"
410 msgstr ""
411
412 #: rhodecode/apps/admin/views/system_info.py:145
397 413 msgid "Search location"
398 414 msgstr ""
399 415
400 #: rhodecode/apps/admin/views/system_info.py:148
401 msgid "VCS Backends"
402 msgstr ""
403
404 416 #: rhodecode/apps/admin/views/system_info.py:149
405 msgid "VCS Server"
417 msgid "VCS Backends"
406 418 msgstr ""
407 419
408 420 #: rhodecode/apps/admin/views/system_info.py:150
409 msgid "GIT"
421 msgid "VCS Server"
410 422 msgstr ""
411 423
412 424 #: rhodecode/apps/admin/views/system_info.py:151
413 msgid "HG"
425 msgid "GIT"
414 426 msgstr ""
415 427
416 428 #: rhodecode/apps/admin/views/system_info.py:152
429 msgid "HG"
430 msgstr ""
431
432 #: rhodecode/apps/admin/views/system_info.py:153
417 433 msgid "SVN"
418 434 msgstr ""
419 435
420 #: rhodecode/apps/admin/views/user_groups.py:219
436 #: rhodecode/apps/admin/views/user_groups.py:231
421 437 #, python-format
422 438 msgid "Created user group %(user_group_link)s"
423 439 msgstr ""
424 440
425 #: rhodecode/apps/admin/views/user_groups.py:241
441 #: rhodecode/apps/admin/views/user_groups.py:253
426 442 #, python-format
427 443 msgid "Error occurred during creation of user group %s"
428 444 msgstr ""
429 445
430 #: rhodecode/apps/admin/views/users.py:209
446 #: rhodecode/apps/admin/views/users.py:218
431 447 #, python-format
432 448 msgid "Created user %(user_link)s"
433 449 msgstr ""
434 450
435 #: rhodecode/apps/admin/views/users.py:230
451 #: rhodecode/apps/admin/views/users.py:239
436 452 #, python-format
437 453 msgid "Error occurred during creation of user %s"
438 454 msgstr ""
439 455
440 #: rhodecode/apps/admin/views/users.py:304
456 #: rhodecode/apps/admin/views/users.py:313
441 457 msgid "User updated successfully"
442 458 msgstr ""
443 459
444 #: rhodecode/apps/admin/views/users.py:322
460 #: rhodecode/apps/admin/views/users.py:331
445 461 #, python-format
446 462 msgid "Error occurred during update of user %s"
447 463 msgstr ""
448 464
449 #: rhodecode/apps/admin/views/users.py:354
465 #: rhodecode/apps/admin/views/users.py:363
450 466 #, python-format
451 467 msgid "Detached %s repositories"
452 468 msgstr ""
453 469
454 #: rhodecode/apps/admin/views/users.py:359
470 #: rhodecode/apps/admin/views/users.py:368
455 471 #, python-format
456 472 msgid "Deleted %s repositories"
457 473 msgstr ""
458 474
459 #: rhodecode/apps/admin/views/users.py:367
475 #: rhodecode/apps/admin/views/users.py:376
460 476 #, python-format
461 477 msgid "Detached %s repository groups"
462 478 msgstr ""
463 479
464 #: rhodecode/apps/admin/views/users.py:372
480 #: rhodecode/apps/admin/views/users.py:381
465 481 #, python-format
466 482 msgid "Deleted %s repository groups"
467 483 msgstr ""
468 484
469 #: rhodecode/apps/admin/views/users.py:380
485 #: rhodecode/apps/admin/views/users.py:389
470 486 #, python-format
471 487 msgid "Detached %s user groups"
472 488 msgstr ""
473 489
474 #: rhodecode/apps/admin/views/users.py:385
490 #: rhodecode/apps/admin/views/users.py:394
475 491 #, python-format
476 492 msgid "Deleted %s user groups"
477 493 msgstr ""
478 494
479 #: rhodecode/apps/admin/views/users.py:402
495 #: rhodecode/apps/admin/views/users.py:411
480 496 msgid "Successfully deleted user"
481 497 msgstr ""
482 498
483 #: rhodecode/apps/admin/views/users.py:408
499 #: rhodecode/apps/admin/views/users.py:417
484 500 msgid "An error occurred during deletion of user"
485 501 msgstr ""
486 502
487 #: rhodecode/apps/admin/views/users.py:473
503 #: rhodecode/apps/admin/views/users.py:482
488 504 msgid ""
489 505 "The user participates as reviewer in {} pull request and cannot be deleted. \n"
490 506 "You can set the user to \"{}\" instead of deleting it."
491 507 msgstr ""
492 508
493 #: rhodecode/apps/admin/views/users.py:479
509 #: rhodecode/apps/admin/views/users.py:488
494 510 msgid ""
495 511 "The user participates as reviewer in {} pull requests and cannot be deleted. \n"
496 512 "You can set the user to \"{}\" instead of deleting it."
497 513 msgstr ""
498 514
499 #: rhodecode/apps/admin/views/users.py:567
515 #: rhodecode/apps/admin/views/users.py:576
500 516 msgid "User global permissions updated successfully"
501 517 msgstr ""
502 518
503 #: rhodecode/apps/admin/views/users.py:585
504 #: rhodecode/apps/user_group/views/__init__.py:448
519 #: rhodecode/apps/admin/views/users.py:594
520 #: rhodecode/apps/user_group/views/__init__.py:474
505 521 msgid "An error occurred during permissions saving"
506 522 msgstr ""
507 523
508 #: rhodecode/apps/admin/views/users.py:610
524 #: rhodecode/apps/admin/views/users.py:619
509 525 msgid "Force password change disabled for user"
510 526 msgstr ""
511 527
512 #: rhodecode/apps/admin/views/users.py:615
513 msgid "Force password change enabled for user"
514 msgstr ""
515
516 528 #: rhodecode/apps/admin/views/users.py:624
529 msgid "Force password change enabled for user"
530 msgstr ""
531
532 #: rhodecode/apps/admin/views/users.py:633
517 533 msgid "An error occurred during password reset for user"
518 534 msgstr ""
519 535
520 #: rhodecode/apps/admin/views/users.py:663
536 #: rhodecode/apps/admin/views/users.py:672
521 537 #, python-format
522 538 msgid "Linked repository group `%s` as personal"
523 539 msgstr ""
524 540
525 #: rhodecode/apps/admin/views/users.py:669
526 #, python-format
527 msgid "Created repository group `%s`"
528 msgstr ""
529
530 #: rhodecode/apps/admin/views/users.py:673
531 #, python-format
532 msgid "Repository group `%s` is already taken"
533 msgstr ""
534
535 541 #: rhodecode/apps/admin/views/users.py:678
542 #, python-format
543 msgid "Created repository group `%s`"
544 msgstr ""
545
546 #: rhodecode/apps/admin/views/users.py:682
547 #, python-format
548 msgid "Repository group `%s` is already taken"
549 msgstr ""
550
551 #: rhodecode/apps/admin/views/users.py:687
536 552 msgid "An error occurred during repository group creation for user"
537 553 msgstr ""
538 554
539 #: rhodecode/apps/admin/views/users.py:701
555 #: rhodecode/apps/admin/views/users.py:710
540 556 #: rhodecode/apps/my_account/views/my_account.py:160
541 557 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:16
542 558 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:16
543 559 msgid "Role"
544 560 msgstr ""
545 561
546 #: rhodecode/apps/admin/views/users.py:739
547 #: rhodecode/apps/my_account/views/my_account.py:194
562 #: rhodecode/apps/admin/views/users.py:749
563 #: rhodecode/apps/my_account/views/my_account.py:195
548 564 msgid "Auth token successfully created"
549 565 msgstr ""
550 566
551 #: rhodecode/apps/admin/views/users.py:768
552 #: rhodecode/apps/my_account/views/my_account.py:218
567 #: rhodecode/apps/admin/views/users.py:778
568 #: rhodecode/apps/my_account/views/my_account.py:219
553 569 msgid "Auth token successfully deleted"
554 570 msgstr ""
555 571
556 #: rhodecode/apps/admin/views/users.py:841
572 #: rhodecode/apps/admin/views/users.py:851
557 573 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:113
558 574 msgid "Ssh Key successfully created"
559 575 msgstr ""
560 576
561 #: rhodecode/apps/admin/views/users.py:847
562 #: rhodecode/apps/admin/views/users.py:851
577 #: rhodecode/apps/admin/views/users.py:857
578 #: rhodecode/apps/admin/views/users.py:861
563 579 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:119
564 580 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:123
565 581 msgid "An error occurred during ssh key saving: {}"
566 582 msgstr ""
567 583
568 #: rhodecode/apps/admin/views/users.py:885
584 #: rhodecode/apps/admin/views/users.py:895
569 585 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:153
570 586 msgid "Ssh key successfully deleted"
571 587 msgstr ""
572 588
573 #: rhodecode/apps/admin/views/users.py:931
574 #, python-format
575 msgid "Added new email address `%s` for user account"
576 msgstr ""
577
578 #: rhodecode/apps/admin/views/users.py:937
579 msgid "Email `{}` is already registered for another user."
580 msgstr ""
581
582 589 #: rhodecode/apps/admin/views/users.py:941
590 #, python-format
591 msgid "Added new email address `%s` for user account"
592 msgstr ""
593
594 #: rhodecode/apps/admin/views/users.py:947
595 msgid "Email `{}` is already registered for another user."
596 msgstr ""
597
598 #: rhodecode/apps/admin/views/users.py:951
583 599 msgid "An error occurred during email saving"
584 600 msgstr ""
585 601
586 #: rhodecode/apps/admin/views/users.py:968
602 #: rhodecode/apps/admin/views/users.py:978
587 603 msgid "Removed email address from user account"
588 604 msgstr ""
589 605
590 #: rhodecode/apps/admin/views/users.py:1014
606 #: rhodecode/apps/admin/views/users.py:1024
591 607 #, python-format
592 608 msgid "An error occurred during ip saving:%s"
593 609 msgstr ""
594 610
595 #: rhodecode/apps/admin/views/users.py:1036
611 #: rhodecode/apps/admin/views/users.py:1046
596 612 msgid "An error occurred during ip saving"
597 613 msgstr ""
598 614
599 #: rhodecode/apps/admin/views/users.py:1040
615 #: rhodecode/apps/admin/views/users.py:1050
600 616 #, python-format
601 617 msgid "Added ips %s to user whitelist"
602 618 msgstr ""
603 619
604 #: rhodecode/apps/admin/views/users.py:1070
620 #: rhodecode/apps/admin/views/users.py:1080
605 621 msgid "Removed ip address from user whitelist"
606 622 msgstr ""
607 623
608 #: rhodecode/apps/admin/views/users.py:1135
624 #: rhodecode/apps/admin/views/users.py:1145
609 625 msgid "Groups successfully changed"
610 626 msgstr ""
611 627
628 #: rhodecode/apps/admin/views/users.py:1239
629 msgid "Deleted {} cache keys"
630 msgstr ""
631
612 632 #: rhodecode/apps/gist/views.py:57 rhodecode/model/auth_token.py:51
613 633 msgid "forever"
614 634 msgstr ""
@@ -630,8 +650,8 b' msgid "1 month"'
630 650 msgstr ""
631 651
632 652 #: rhodecode/apps/gist/views.py:64
633 #: rhodecode/public/js/rhodecode-components.js:49292
634 #: rhodecode/public/js/scripts.js:41140
653 #: rhodecode/public/js/rhodecode-components.js:54572
654 #: rhodecode/public/js/scripts.js:41322
635 655 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:21
636 656 #: rhodecode/public/js/src/rhodecode.js:502
637 657 msgid "Lifetime"
@@ -684,27 +704,18 b' msgstr ""'
684 704 msgid "Error occurred during update of gist %s"
685 705 msgstr ""
686 706
687 #: rhodecode/apps/home/views.py:218 rhodecode/apps/home/views.py:251
688 #: rhodecode/apps/repository/views/repo_pull_requests.py:775
707 #: rhodecode/apps/home/views.py:295
708 #: rhodecode/apps/repository/views/repo_pull_requests.py:784
689 709 #: rhodecode/templates/admin/my_account/my_account.mako:41
690 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:126
710 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:197
691 711 #: rhodecode/templates/admin/repos/repo_add.mako:15
692 712 #: rhodecode/templates/admin/repos/repo_add.mako:19
693 713 #: rhodecode/templates/admin/users/user_edit_advanced.mako:11
694 714 #: rhodecode/templates/base/base.mako:78 rhodecode/templates/base/base.mako:150
695 #: rhodecode/templates/base/base.mako:584
715 #: rhodecode/templates/base/base.mako:655
696 716 msgid "Repositories"
697 717 msgstr ""
698 718
699 #: rhodecode/apps/home/views.py:244
700 msgid "Groups"
701 msgstr ""
702
703 #: rhodecode/apps/home/views.py:264
704 #, python-format
705 msgid "Commits in %(repo)s"
706 msgstr ""
707
708 719 #: rhodecode/apps/journal/views.py:132 rhodecode/apps/journal/views.py:178
709 720 msgid "public journal"
710 721 msgstr ""
@@ -713,27 +724,27 b' msgstr ""'
713 724 msgid "journal"
714 725 msgstr ""
715 726
716 #: rhodecode/apps/login/views.py:272 rhodecode/apps/login/views.py:349
727 #: rhodecode/apps/login/views.py:293 rhodecode/apps/login/views.py:374
717 728 msgid "Bad captcha"
718 729 msgstr ""
719 730
720 #: rhodecode/apps/login/views.py:288
731 #: rhodecode/apps/login/views.py:315
721 732 msgid "You have successfully registered with RhodeCode"
722 733 msgstr ""
723 734
724 #: rhodecode/apps/login/views.py:325
735 #: rhodecode/apps/login/views.py:352
725 736 msgid "If such email exists, a password reset link was sent to it."
726 737 msgstr ""
727 738
728 #: rhodecode/apps/login/views.py:331
739 #: rhodecode/apps/login/views.py:358
729 740 msgid "Password reset has been disabled."
730 741 msgstr ""
731 742
732 #: rhodecode/apps/login/views.py:420
743 #: rhodecode/apps/login/views.py:446
733 744 msgid "Given reset token is invalid"
734 745 msgstr ""
735 746
736 #: rhodecode/apps/login/views.py:428
747 #: rhodecode/apps/login/views.py:454
737 748 msgid "Your password reset was successful, a new password has been sent to your email"
738 749 msgstr ""
739 750
@@ -745,23 +756,23 b' msgstr ""'
745 756 msgid "Successfully updated password"
746 757 msgstr ""
747 758
748 #: rhodecode/apps/my_account/views/my_account.py:282
759 #: rhodecode/apps/my_account/views/my_account.py:283
749 760 msgid "Error occurred during adding email"
750 761 msgstr ""
751 762
752 #: rhodecode/apps/my_account/views/my_account.py:285
763 #: rhodecode/apps/my_account/views/my_account.py:286
753 764 msgid "Successfully added email"
754 765 msgstr ""
755 766
756 #: rhodecode/apps/my_account/views/my_account.py:307
767 #: rhodecode/apps/my_account/views/my_account.py:308
757 768 msgid "Email successfully deleted"
758 769 msgstr ""
759 770
760 #: rhodecode/apps/my_account/views/my_account.py:490
771 #: rhodecode/apps/my_account/views/my_account.py:491
761 772 msgid "Your account was updated successfully"
762 773 msgstr ""
763 774
764 #: rhodecode/apps/my_account/views/my_account.py:497
775 #: rhodecode/apps/my_account/views/my_account.py:498
765 776 msgid "Error occurred during update of user"
766 777 msgstr ""
767 778
@@ -775,42 +786,42 b' msgstr ""'
775 786 msgid "Error occurred during deletion of repository group %s"
776 787 msgstr ""
777 788
778 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:73
779 #: rhodecode/apps/user_group/views/__init__.py:328
789 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:74
790 #: rhodecode/apps/user_group/views/__init__.py:346
780 791 msgid "Cannot change permission for yourself as admin"
781 792 msgstr ""
782 793
783 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:97
794 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:98
784 795 msgid "Repository Group permissions updated"
785 796 msgstr ""
786 797
787 #: rhodecode/apps/repo_group/views/repo_group_settings.py:174
798 #: rhodecode/apps/repo_group/views/repo_group_settings.py:173
788 799 msgid "Repository Group `{}` updated successfully"
789 800 msgstr ""
790 801
791 #: rhodecode/apps/repo_group/views/repo_group_settings.py:179
802 #: rhodecode/apps/repo_group/views/repo_group_settings.py:178
792 803 #, python-format
793 804 msgid "Error occurred during update of repository group %s"
794 805 msgstr ""
795 806
796 #: rhodecode/apps/repository/views/repo_caches.py:72
807 #: rhodecode/apps/repository/views/repo_caches.py:80
797 808 msgid "Cache invalidation successful"
798 809 msgstr ""
799 810
800 #: rhodecode/apps/repository/views/repo_caches.py:76
811 #: rhodecode/apps/repository/views/repo_caches.py:84
801 812 msgid "An error occurred during cache invalidation"
802 813 msgstr ""
803 814
804 815 #: rhodecode/apps/repository/views/repo_changelog.py:66
805 816 #: rhodecode/apps/repository/views/repo_compare.py:66
806 #: rhodecode/apps/repository/views/repo_pull_requests.py:641
817 #: rhodecode/apps/repository/views/repo_pull_requests.py:647
807 818 msgid "There are no commits yet"
808 819 msgstr ""
809 820
810 821 #: rhodecode/apps/repository/views/repo_changelog.py:71
811 822 #: rhodecode/apps/repository/views/repo_commits.py:199
812 #: rhodecode/apps/repository/views/repo_files.py:150
813 #: rhodecode/apps/repository/views/repo_files.py:170
823 #: rhodecode/apps/repository/views/repo_files.py:162
824 #: rhodecode/apps/repository/views/repo_files.py:182
814 825 msgid "No such commit exists for this repository"
815 826 msgstr ""
816 827
@@ -854,12 +865,12 b' msgid "Increase context for all diffs"'
854 865 msgstr ""
855 866
856 867 #: rhodecode/apps/repository/views/repo_commits.py:415
857 #: rhodecode/apps/repository/views/repo_pull_requests.py:1185
868 #: rhodecode/apps/repository/views/repo_pull_requests.py:1211
858 869 #, python-format
859 870 msgid "Status change %(transition_icon)s %(status)s"
860 871 msgstr ""
861 872
862 #: rhodecode/apps/repository/views/repo_commits.py:459
873 #: rhodecode/apps/repository/views/repo_commits.py:460
863 874 msgid "Changing the status of a commit associated with a closed pull request is not allowed"
864 875 msgstr ""
865 876
@@ -888,215 +899,224 b' msgstr ""'
888 899 msgid "Repositories unrelated. Cannot compare commit %(commit1)s from repository %(repo1)s with commit %(commit2)s from repository %(repo2)s."
889 900 msgstr ""
890 901
891 #: rhodecode/apps/repository/views/repo_feed.py:70
902 #: rhodecode/apps/repository/views/repo_feed.py:69
892 903 #, python-format
893 904 msgid "Changes on %s repository"
894 905 msgstr ""
895 906
896 #: rhodecode/apps/repository/views/repo_feed.py:71
907 #: rhodecode/apps/repository/views/repo_feed.py:70
897 908 #, python-format
898 909 msgid "%s %s feed"
899 910 msgstr ""
900 911
901 #: rhodecode/apps/repository/views/repo_files.py:94
912 #: rhodecode/apps/repository/views/repo_files.py:92
902 913 #, python-format
903 914 msgid "This repository has been locked by %s on %s"
904 915 msgstr ""
905 916
906 #: rhodecode/apps/repository/views/repo_files.py:140
917 #: rhodecode/apps/repository/views/repo_files.py:108
918 msgid "Branch `{}` changes forbidden by rule {}."
919 msgstr ""
920
921 #: rhodecode/apps/repository/views/repo_files.py:152
907 922 msgid "Click here to add a new file."
908 923 msgstr ""
909 924
910 #: rhodecode/apps/repository/views/repo_files.py:145
925 #: rhodecode/apps/repository/views/repo_files.py:157
911 926 #, python-format
912 927 msgid "There are no files yet. %s"
913 928 msgstr ""
914 929
915 #: rhodecode/apps/repository/views/repo_files.py:259
930 #: rhodecode/apps/repository/views/repo_files.py:293
916 931 msgid "Downloads disabled"
917 932 msgstr ""
918 933
919 #: rhodecode/apps/repository/views/repo_files.py:265
934 #: rhodecode/apps/repository/views/repo_files.py:299
920 935 msgid "Unknown archive type for: `{}`"
921 936 msgstr ""
922 937
923 #: rhodecode/apps/repository/views/repo_files.py:271
924 msgid "Unknown commit_id {}"
925 msgstr ""
926
927 #: rhodecode/apps/repository/views/repo_files.py:274
928 msgid "Empty repository"
929 msgstr ""
930
931 938 #: rhodecode/apps/repository/views/repo_files.py:305
939 msgid "Unknown commit_id {}"
940 msgstr ""
941
942 #: rhodecode/apps/repository/views/repo_files.py:308
943 msgid "Empty repository"
944 msgstr ""
945
946 #: rhodecode/apps/repository/views/repo_files.py:340
932 947 msgid "Unknown archive type"
933 948 msgstr ""
934 949
935 #: rhodecode/apps/repository/views/repo_files.py:865
950 #: rhodecode/apps/repository/views/repo_files.py:906
936 951 msgid "Changesets"
937 952 msgstr ""
938 953
939 #: rhodecode/apps/repository/views/repo_files.py:886
940 #: rhodecode/apps/repository/views/repo_summary.py:322
941 #: rhodecode/model/pull_request.py:1421 rhodecode/model/scm.py:789
954 #: rhodecode/apps/repository/views/repo_files.py:927
955 #: rhodecode/apps/repository/views/repo_summary.py:340
956 #: rhodecode/model/pull_request.py:1445 rhodecode/model/scm.py:795
942 957 #: rhodecode/templates/base/vcs_settings.mako:235
943 958 msgid "Branches"
944 959 msgstr ""
945 960
946 #: rhodecode/apps/repository/views/repo_files.py:890 rhodecode/model/scm.py:804
961 #: rhodecode/apps/repository/views/repo_files.py:931 rhodecode/model/scm.py:810
947 962 #: rhodecode/templates/base/vcs_settings.mako:260
948 963 msgid "Tags"
949 964 msgstr ""
950 965
951 #: rhodecode/apps/repository/views/repo_files.py:987
952 #: rhodecode/apps/repository/views/repo_files.py:1018
953 msgid "You can only delete files with commit being a valid branch "
954 msgstr ""
955
956 #: rhodecode/apps/repository/views/repo_files.py:997
957 #: rhodecode/apps/repository/views/repo_files.py:1028
966 #: rhodecode/apps/repository/views/repo_files.py:1030
967 #: rhodecode/apps/repository/views/repo_files.py:1064
968 msgid "You can only delete files with commit being a valid branch head."
969 msgstr ""
970
971 #: rhodecode/apps/repository/views/repo_files.py:1041
972 #: rhodecode/apps/repository/views/repo_files.py:1075
958 973 msgid "Deleted file {} via RhodeCode Enterprise"
959 974 msgstr ""
960 975
961 #: rhodecode/apps/repository/views/repo_files.py:1049
976 #: rhodecode/apps/repository/views/repo_files.py:1096
962 977 msgid "Successfully deleted file `{}`"
963 978 msgstr ""
964 979
965 #: rhodecode/apps/repository/views/repo_files.py:1053
966 #: rhodecode/apps/repository/views/repo_files.py:1171
967 #: rhodecode/apps/repository/views/repo_files.py:1290
980 #: rhodecode/apps/repository/views/repo_files.py:1100
981 #: rhodecode/apps/repository/views/repo_files.py:1225
982 #: rhodecode/apps/repository/views/repo_files.py:1383
968 983 msgid "Error occurred during commit"
969 984 msgstr ""
970 985
971 #: rhodecode/apps/repository/views/repo_files.py:1071
972 #: rhodecode/apps/repository/views/repo_files.py:1108
973 msgid "You can only edit files with commit being a valid branch "
974 msgstr ""
975
976 #: rhodecode/apps/repository/views/repo_files.py:1088
977 #: rhodecode/apps/repository/views/repo_files.py:1125
986 #: rhodecode/apps/repository/views/repo_files.py:1120
987 #: rhodecode/apps/repository/views/repo_files.py:1160
988 msgid "You can only edit files with commit being a valid branch head."
989 msgstr ""
990
991 #: rhodecode/apps/repository/views/repo_files.py:1138
992 #: rhodecode/apps/repository/views/repo_files.py:1179
978 993 msgid "Edited file {} via RhodeCode Enterprise"
979 994 msgstr ""
980 995
981 #: rhodecode/apps/repository/views/repo_files.py:1143
996 #: rhodecode/apps/repository/views/repo_files.py:1197
982 997 msgid "No changes"
983 998 msgstr ""
984 999
985 #: rhodecode/apps/repository/views/repo_files.py:1167
1000 #: rhodecode/apps/repository/views/repo_files.py:1221
986 1001 msgid "Successfully committed changes to file `{}`"
987 1002 msgstr ""
988 1003
989 #: rhodecode/apps/repository/views/repo_files.py:1191
990 #: rhodecode/apps/repository/views/repo_files.py:1215
1004 #: rhodecode/apps/repository/views/repo_files.py:1245
1005 #: rhodecode/apps/repository/views/repo_files.py:1308
991 1006 msgid "Added file via RhodeCode Enterprise"
992 1007 msgstr ""
993 1008
994 #: rhodecode/apps/repository/views/repo_files.py:1248
1009 #: rhodecode/apps/repository/views/repo_files.py:1258
1010 #: rhodecode/apps/repository/views/repo_files.py:1299
1011 msgid "You can only add files with commit being a valid branch head."
1012 msgstr ""
1013
1014 #: rhodecode/apps/repository/views/repo_files.py:1341
995 1015 msgid "No filename"
996 1016 msgstr ""
997 1017
998 #: rhodecode/apps/repository/views/repo_files.py:1278
1018 #: rhodecode/apps/repository/views/repo_files.py:1371
999 1019 msgid "Successfully committed new file `{}`"
1000 1020 msgstr ""
1001 1021
1002 #: rhodecode/apps/repository/views/repo_files.py:1282
1022 #: rhodecode/apps/repository/views/repo_files.py:1375
1003 1023 msgid "The location specified must be a relative path and must not contain .. in the path"
1004 1024 msgstr ""
1005 1025
1006 #: rhodecode/apps/repository/views/repo_forks.py:146
1026 #: rhodecode/apps/repository/views/repo_forks.py:147
1007 1027 #: rhodecode/templates/base/base.mako:264
1008 1028 msgid "Compare fork"
1009 1029 msgstr ""
1010 1030
1011 #: rhodecode/apps/repository/views/repo_forks.py:251
1031 #: rhodecode/apps/repository/views/repo_forks.py:252
1012 1032 #, python-format
1013 1033 msgid "An error occurred during repository forking %s"
1014 1034 msgstr ""
1015 1035
1016 #: rhodecode/apps/repository/views/repo_permissions.py:86
1036 #: rhodecode/apps/repository/views/repo_permissions.py:85
1017 1037 msgid "Repository permissions updated"
1018 1038 msgstr ""
1019 1039
1020 #: rhodecode/apps/repository/views/repo_pull_requests.py:671
1040 #: rhodecode/apps/repository/views/repo_pull_requests.py:677
1021 1041 msgid "Commit does not exist"
1022 1042 msgstr ""
1023 1043
1024 #: rhodecode/apps/repository/views/repo_pull_requests.py:806
1044 #: rhodecode/apps/repository/views/repo_pull_requests.py:815
1025 1045 msgid "Error creating pull request: {}"
1026 1046 msgstr ""
1027 1047
1028 #: rhodecode/apps/repository/views/repo_pull_requests.py:831
1048 #: rhodecode/apps/repository/views/repo_pull_requests.py:840
1029 1049 msgid "Not Enough permissions to source repo `{}`."
1030 1050 msgstr ""
1031 1051
1032 #: rhodecode/apps/repository/views/repo_pull_requests.py:846
1052 #: rhodecode/apps/repository/views/repo_pull_requests.py:855
1033 1053 msgid "Not Enough permissions to target repo `{}`."
1034 1054 msgstr ""
1035 1055
1036 #: rhodecode/apps/repository/views/repo_pull_requests.py:897
1056 #: rhodecode/apps/repository/views/repo_pull_requests.py:918
1037 1057 msgid "Successfully opened new pull request"
1038 1058 msgstr ""
1039 1059
1040 #: rhodecode/apps/repository/views/repo_pull_requests.py:900
1060 #: rhodecode/apps/repository/views/repo_pull_requests.py:921
1041 1061 msgid "Error occurred during creation of this pull request."
1042 1062 msgstr ""
1043 1063
1044 #: rhodecode/apps/repository/views/repo_pull_requests.py:931
1045 #: rhodecode/apps/repository/views/repo_pull_requests.py:961
1064 #: rhodecode/apps/repository/views/repo_pull_requests.py:952
1065 #: rhodecode/apps/repository/views/repo_pull_requests.py:986
1046 1066 msgid "Cannot update closed pull requests."
1047 1067 msgstr ""
1048 1068
1049 #: rhodecode/apps/repository/views/repo_pull_requests.py:967
1069 #: rhodecode/apps/repository/views/repo_pull_requests.py:992
1050 1070 msgid "Pull request title & description updated."
1051 1071 msgstr ""
1052 1072
1053 #: rhodecode/apps/repository/views/repo_pull_requests.py:986
1073 #: rhodecode/apps/repository/views/repo_pull_requests.py:1011
1054 1074 msgid "Pull request updated to \"{source_commit_id}\" with {count_added} added, {count_removed} removed commits. Source of changes: {change_source}"
1055 1075 msgstr ""
1056 1076
1057 #: rhodecode/apps/repository/views/repo_pull_requests.py:1002
1077 #: rhodecode/apps/repository/views/repo_pull_requests.py:1027
1058 1078 msgid "Reload page"
1059 1079 msgstr ""
1060 1080
1061 #: rhodecode/apps/repository/views/repo_pull_requests.py:1066
1081 #: rhodecode/apps/repository/views/repo_pull_requests.py:1092
1062 1082 msgid "Pull request was successfully merged and closed."
1063 1083 msgstr ""
1064 1084
1065 #: rhodecode/apps/repository/views/repo_pull_requests.py:1090
1066 msgid "Pull request reviewers updated."
1067 msgstr ""
1068
1069 1085 #: rhodecode/apps/repository/views/repo_pull_requests.py:1116
1086 msgid "Pull request reviewers updated."
1087 msgstr ""
1088
1089 #: rhodecode/apps/repository/views/repo_pull_requests.py:1142
1070 1090 msgid "Successfully deleted pull request"
1071 1091 msgstr ""
1072 1092
1073 #: rhodecode/apps/repository/views/repo_settings.py:172
1093 #: rhodecode/apps/repository/views/repo_settings.py:171
1074 1094 msgid "Repository `{}` updated successfully"
1075 1095 msgstr ""
1076 1096
1077 #: rhodecode/apps/repository/views/repo_settings.py:176
1097 #: rhodecode/apps/repository/views/repo_settings.py:175
1078 1098 msgid "Error occurred during update of repository {}"
1079 1099 msgstr ""
1080 1100
1081 #: rhodecode/apps/repository/views/repo_settings.py:198
1101 #: rhodecode/apps/repository/views/repo_settings.py:204
1082 1102 msgid "Unlocked"
1083 1103 msgstr ""
1084 1104
1085 #: rhodecode/apps/repository/views/repo_settings.py:203
1086 msgid "Locked"
1087 msgstr ""
1088
1089 #: rhodecode/apps/repository/views/repo_settings.py:205
1090 #, python-format
1091 msgid "Repository has been %s"
1092 msgstr ""
1093
1094 1105 #: rhodecode/apps/repository/views/repo_settings.py:209
1106 msgid "Locked"
1107 msgstr ""
1108
1109 #: rhodecode/apps/repository/views/repo_settings.py:211
1110 #, python-format
1111 msgid "Repository has been %s"
1112 msgstr ""
1113
1114 #: rhodecode/apps/repository/views/repo_settings.py:215
1095 1115 #: rhodecode/apps/repository/views/repo_settings_advanced.py:228
1096 1116 msgid "An error occurred during unlocking"
1097 1117 msgstr ""
1098 1118
1099 #: rhodecode/apps/repository/views/repo_settings.py:253
1119 #: rhodecode/apps/repository/views/repo_settings.py:259
1100 1120 msgid "An error occurred during deletion of repository stats"
1101 1121 msgstr ""
1102 1122
@@ -1158,7 +1178,7 b' msgid "Unlocked repository"'
1158 1178 msgstr ""
1159 1179
1160 1180 #: rhodecode/apps/repository/views/repo_settings_advanced.py:245
1161 msgid "installed hooks repository"
1181 msgid "installed updated hooks into this repository"
1162 1182 msgstr ""
1163 1183
1164 1184 #: rhodecode/apps/repository/views/repo_settings_fields.py:86
@@ -1185,19 +1205,21 b' msgstr ""'
1185 1205 msgid "Error occurred during updating repository VCS settings"
1186 1206 msgstr ""
1187 1207
1188 #: rhodecode/apps/repository/views/repo_summary.py:297
1208 #: rhodecode/apps/repository/views/repo_summary.py:315
1209 #: rhodecode/templates/admin/permissions/permissions.mako:42
1210 #: rhodecode/templates/files/files_add.mako:15
1189 1211 msgid "Branch"
1190 1212 msgstr ""
1191 1213
1192 #: rhodecode/apps/repository/views/repo_summary.py:298
1214 #: rhodecode/apps/repository/views/repo_summary.py:316
1193 1215 msgid "Tag"
1194 1216 msgstr ""
1195 1217
1196 #: rhodecode/apps/repository/views/repo_summary.py:299
1218 #: rhodecode/apps/repository/views/repo_summary.py:317
1197 1219 msgid "Bookmark"
1198 1220 msgstr ""
1199 1221
1200 #: rhodecode/apps/repository/views/repo_summary.py:323
1222 #: rhodecode/apps/repository/views/repo_summary.py:341
1201 1223 msgid "Closed branches"
1202 1224 msgstr ""
1203 1225
@@ -1209,80 +1231,80 b' msgstr ""'
1209 1231 msgid "Configuration for Apache mad_dav_svn changed."
1210 1232 msgstr ""
1211 1233
1212 #: rhodecode/apps/user_group/views/__init__.py:184
1234 #: rhodecode/apps/user_group/views/__init__.py:188
1213 1235 #, python-format
1214 1236 msgid "Updated user group %s"
1215 1237 msgstr ""
1216 1238
1217 #: rhodecode/apps/user_group/views/__init__.py:206
1239 #: rhodecode/apps/user_group/views/__init__.py:224
1218 1240 #, python-format
1219 1241 msgid "Error occurred during update of user group %s"
1220 1242 msgstr ""
1221 1243
1222 #: rhodecode/apps/user_group/views/__init__.py:232
1244 #: rhodecode/apps/user_group/views/__init__.py:250
1223 1245 msgid "Successfully deleted user group"
1224 1246 msgstr ""
1225 1247
1226 #: rhodecode/apps/user_group/views/__init__.py:237
1248 #: rhodecode/apps/user_group/views/__init__.py:255
1227 1249 msgid "An error occurred during deletion of user group"
1228 1250 msgstr ""
1229 1251
1230 #: rhodecode/apps/user_group/views/__init__.py:341
1252 #: rhodecode/apps/user_group/views/__init__.py:359
1231 1253 msgid "Target group cannot be the same"
1232 1254 msgstr ""
1233 1255
1234 #: rhodecode/apps/user_group/views/__init__.py:356
1256 #: rhodecode/apps/user_group/views/__init__.py:374
1235 1257 msgid "User Group permissions updated"
1236 1258 msgstr ""
1237 1259
1238 #: rhodecode/apps/user_group/views/__init__.py:428
1260 #: rhodecode/apps/user_group/views/__init__.py:454
1239 1261 msgid "User Group global permissions updated successfully"
1240 1262 msgstr ""
1241 1263
1242 #: rhodecode/apps/user_group/views/__init__.py:510
1264 #: rhodecode/apps/user_group/views/__init__.py:536
1243 1265 msgid "User Group synchronization updated successfully"
1244 1266 msgstr ""
1245 1267
1246 #: rhodecode/apps/user_group/views/__init__.py:514
1268 #: rhodecode/apps/user_group/views/__init__.py:540
1247 1269 msgid "An error occurred during synchronization update"
1248 1270 msgstr ""
1249 1271
1250 #: rhodecode/authentication/schema.py:35
1272 #: rhodecode/authentication/schema.py:36
1251 1273 msgid "Enable or disable this authentication plugin."
1252 1274 msgstr ""
1253 1275
1254 #: rhodecode/authentication/schema.py:37 rhodecode/integrations/schema.py:32
1255 #: rhodecode/model/permission.py:101 rhodecode/model/permission.py:105
1256 #: rhodecode/model/permission.py:109 rhodecode/model/permission.py:113
1257 #: rhodecode/model/permission.py:117 rhodecode/model/permission.py:121
1258 #: rhodecode/model/validation_schema/schemas/integration_schema.py:197
1276 #: rhodecode/authentication/schema.py:38 rhodecode/integrations/schema.py:32
1277 #: rhodecode/model/permission.py:110 rhodecode/model/permission.py:114
1278 #: rhodecode/model/permission.py:118 rhodecode/model/permission.py:122
1279 #: rhodecode/model/permission.py:126 rhodecode/model/permission.py:130
1280 #: rhodecode/model/validation_schema/schemas/integration_schema.py:195
1259 1281 #: rhodecode/templates/admin/integrations/list.mako:71
1260 1282 msgid "Enabled"
1261 1283 msgstr ""
1262 1284
1263 #: rhodecode/authentication/schema.py:43
1285 #: rhodecode/authentication/schema.py:44
1264 1286 msgid ""
1265 1287 "Amount of seconds to cache the authentication and permissions check response call for this plugin. \n"
1266 1288 "Useful for expensive calls like LDAP to improve the performance of the system (0 means disabled)."
1267 1289 msgstr ""
1268 1290
1269 #: rhodecode/authentication/schema.py:48
1291 #: rhodecode/authentication/schema.py:49
1270 1292 msgid "Auth Cache TTL"
1271 1293 msgstr ""
1272 1294
1273 #: rhodecode/authentication/views.py:94
1295 #: rhodecode/authentication/views.py:92
1274 1296 msgid "Errors exist when saving plugin settings. Please check the form inputs."
1275 1297 msgstr ""
1276 1298
1277 #: rhodecode/authentication/views.py:116 rhodecode/authentication/views.py:175
1299 #: rhodecode/authentication/views.py:104 rhodecode/authentication/views.py:163
1278 1300 msgid "Auth settings updated successfully."
1279 1301 msgstr ""
1280 1302
1281 #: rhodecode/authentication/views.py:178
1303 #: rhodecode/authentication/views.py:166
1282 1304 msgid "Errors exist when saving plugin setting. Please check the form inputs."
1283 1305 msgstr ""
1284 1306
1285 #: rhodecode/authentication/views.py:186
1307 #: rhodecode/authentication/views.py:174
1286 1308 msgid "Error occurred during update of auth settings."
1287 1309 msgstr ""
1288 1310
@@ -1299,7 +1321,7 b' msgid "The Port in use by the Atlassian '
1299 1321 msgstr ""
1300 1322
1301 1323 #: rhodecode/authentication/plugins/auth_crowd.py:69
1302 #: rhodecode/authentication/plugins/auth_ldap.py:91
1324 #: rhodecode/authentication/plugins/auth_ldap.py:89
1303 1325 msgid "Port"
1304 1326 msgstr ""
1305 1327
@@ -1371,46 +1393,46 b' msgstr ""'
1371 1393 msgid "Jasig-CAS"
1372 1394 msgstr ""
1373 1395
1374 #: rhodecode/authentication/plugins/auth_ldap.py:79
1396 #: rhodecode/authentication/plugins/auth_ldap.py:77
1375 1397 msgid ""
1376 1398 "Host[s] of the LDAP Server \n"
1377 1399 "(e.g., 192.168.2.154, or ldap-server.domain.com.\n"
1378 1400 " Multiple servers can be specified using commas"
1379 1401 msgstr ""
1380 1402
1381 #: rhodecode/authentication/plugins/auth_ldap.py:83
1403 #: rhodecode/authentication/plugins/auth_ldap.py:81
1382 1404 msgid "LDAP Host"
1383 1405 msgstr ""
1384 1406
1385 #: rhodecode/authentication/plugins/auth_ldap.py:88
1407 #: rhodecode/authentication/plugins/auth_ldap.py:86
1386 1408 msgid "Custom port that the LDAP server is listening on. Default value is: 389"
1387 1409 msgstr ""
1388 1410
1411 #: rhodecode/authentication/plugins/auth_ldap.py:96
1412 msgid "Timeout for LDAP connection"
1413 msgstr ""
1414
1389 1415 #: rhodecode/authentication/plugins/auth_ldap.py:98
1390 msgid "Timeout for LDAP connection"
1391 msgstr ""
1392
1393 #: rhodecode/authentication/plugins/auth_ldap.py:100
1394 1416 msgid "Connection timeout"
1395 1417 msgstr ""
1396 1418
1397 #: rhodecode/authentication/plugins/auth_ldap.py:107
1419 #: rhodecode/authentication/plugins/auth_ldap.py:105
1398 1420 msgid ""
1399 1421 "Optional user DN/account to connect to LDAP if authentication is required. \n"
1400 1422 "e.g., cn=admin,dc=mydomain,dc=com, or uid=root,cn=users,dc=mydomain,dc=com, or admin@mydomain.com"
1401 1423 msgstr ""
1402 1424
1403 #: rhodecode/authentication/plugins/auth_ldap.py:112
1425 #: rhodecode/authentication/plugins/auth_ldap.py:110
1404 1426 msgid "Account"
1405 1427 msgstr ""
1406 1428
1407 #: rhodecode/authentication/plugins/auth_ldap.py:117
1429 #: rhodecode/authentication/plugins/auth_ldap.py:115
1408 1430 msgid "Password to authenticate for given user DN."
1409 1431 msgstr ""
1410 1432
1411 #: rhodecode/authentication/plugins/auth_ldap.py:120
1433 #: rhodecode/authentication/plugins/auth_ldap.py:118
1412 1434 #: rhodecode/integrations/types/webhook.py:92 rhodecode/templates/login.mako:50
1413 #: rhodecode/templates/register.mako:48
1435 #: rhodecode/templates/register.mako:58
1414 1436 #: rhodecode/templates/admin/my_account/my_account.mako:30
1415 1437 #: rhodecode/templates/admin/users/user_add.mako:44
1416 1438 #: rhodecode/templates/base/base.mako:326
@@ -1418,93 +1440,93 b' msgstr ""'
1418 1440 msgid "Password"
1419 1441 msgstr ""
1420 1442
1421 #: rhodecode/authentication/plugins/auth_ldap.py:125
1443 #: rhodecode/authentication/plugins/auth_ldap.py:123
1422 1444 msgid "TLS Type"
1423 1445 msgstr ""
1424 1446
1425 #: rhodecode/authentication/plugins/auth_ldap.py:126
1447 #: rhodecode/authentication/plugins/auth_ldap.py:124
1426 1448 msgid "Connection Security"
1427 1449 msgstr ""
1428 1450
1429 #: rhodecode/authentication/plugins/auth_ldap.py:132
1451 #: rhodecode/authentication/plugins/auth_ldap.py:130
1430 1452 msgid ""
1431 1453 "Require Cert over TLS?. Self-signed and custom certificates can be used when\n"
1432 1454 " `RhodeCode Certificate` found in admin > settings > system info page is extended."
1433 1455 msgstr ""
1434 1456
1435 #: rhodecode/authentication/plugins/auth_ldap.py:135
1457 #: rhodecode/authentication/plugins/auth_ldap.py:133
1436 1458 msgid "Certificate Checks"
1437 1459 msgstr ""
1438 1460
1439 #: rhodecode/authentication/plugins/auth_ldap.py:141
1461 #: rhodecode/authentication/plugins/auth_ldap.py:139
1440 1462 msgid ""
1441 1463 "Base DN to search. Dynamic bind is supported. Add `$login` marker in it to be replaced with current user credentials \n"
1442 1464 "(e.g., dc=mydomain,dc=com, or ou=Users,dc=mydomain,dc=com)"
1443 1465 msgstr ""
1444 1466
1445 #: rhodecode/authentication/plugins/auth_ldap.py:146
1467 #: rhodecode/authentication/plugins/auth_ldap.py:144
1446 1468 msgid "Base DN"
1447 1469 msgstr ""
1448 1470
1449 #: rhodecode/authentication/plugins/auth_ldap.py:151
1471 #: rhodecode/authentication/plugins/auth_ldap.py:149
1450 1472 msgid ""
1451 1473 "Filter to narrow results \n"
1452 1474 "(e.g., (&(objectCategory=Person)(objectClass=user)), or \n"
1453 1475 "(memberof=cn=rc-login,ou=groups,ou=company,dc=mydomain,dc=com)))"
1454 1476 msgstr ""
1455 1477
1456 #: rhodecode/authentication/plugins/auth_ldap.py:156
1478 #: rhodecode/authentication/plugins/auth_ldap.py:154
1457 1479 msgid "LDAP Search Filter"
1458 1480 msgstr ""
1459 1481
1460 #: rhodecode/authentication/plugins/auth_ldap.py:162
1482 #: rhodecode/authentication/plugins/auth_ldap.py:160
1461 1483 msgid "How deep to search LDAP. If unsure set to SUBTREE"
1462 1484 msgstr ""
1463 1485
1464 #: rhodecode/authentication/plugins/auth_ldap.py:163
1486 #: rhodecode/authentication/plugins/auth_ldap.py:161
1465 1487 msgid "LDAP Search Scope"
1466 1488 msgstr ""
1467 1489
1490 #: rhodecode/authentication/plugins/auth_ldap.py:167
1491 msgid "LDAP Attribute to map to user name (e.g., uid, or sAMAccountName)"
1492 msgstr ""
1493
1468 1494 #: rhodecode/authentication/plugins/auth_ldap.py:169
1469 msgid "LDAP Attribute to map to user name (e.g., uid, or sAMAccountName)"
1470 msgstr ""
1471
1472 #: rhodecode/authentication/plugins/auth_ldap.py:171
1473 1495 msgid "Login Attribute"
1474 1496 msgstr ""
1475 1497
1476 #: rhodecode/authentication/plugins/auth_ldap.py:172
1498 #: rhodecode/authentication/plugins/auth_ldap.py:170
1477 1499 msgid "The LDAP Login attribute of the CN must be specified"
1478 1500 msgstr ""
1479 1501
1480 #: rhodecode/authentication/plugins/auth_ldap.py:177
1502 #: rhodecode/authentication/plugins/auth_ldap.py:175
1481 1503 msgid "LDAP Attribute to map to first name (e.g., givenName)"
1482 1504 msgstr ""
1483 1505
1484 #: rhodecode/authentication/plugins/auth_ldap.py:180
1506 #: rhodecode/authentication/plugins/auth_ldap.py:178
1485 1507 msgid "First Name Attribute"
1486 1508 msgstr ""
1487 1509
1488 #: rhodecode/authentication/plugins/auth_ldap.py:185
1510 #: rhodecode/authentication/plugins/auth_ldap.py:183
1489 1511 msgid "LDAP Attribute to map to last name (e.g., sn)"
1490 1512 msgstr ""
1491 1513
1492 #: rhodecode/authentication/plugins/auth_ldap.py:188
1514 #: rhodecode/authentication/plugins/auth_ldap.py:186
1493 1515 msgid "Last Name Attribute"
1494 1516 msgstr ""
1495 1517
1496 #: rhodecode/authentication/plugins/auth_ldap.py:193
1518 #: rhodecode/authentication/plugins/auth_ldap.py:191
1497 1519 msgid ""
1498 1520 "LDAP Attribute to map to email address (e.g., mail).\n"
1499 1521 "Emails are a crucial part of RhodeCode. \n"
1500 1522 "If possible add a valid email attribute to ldap users."
1501 1523 msgstr ""
1502 1524
1503 #: rhodecode/authentication/plugins/auth_ldap.py:198
1525 #: rhodecode/authentication/plugins/auth_ldap.py:196
1504 1526 msgid "Email Attribute"
1505 1527 msgstr ""
1506 1528
1507 #: rhodecode/authentication/plugins/auth_ldap.py:426
1529 #: rhodecode/authentication/plugins/auth_ldap.py:390
1508 1530 msgid "LDAP"
1509 1531 msgstr ""
1510 1532
@@ -1620,17 +1642,21 b' msgstr ""'
1620 1642 msgid "user pre update"
1621 1643 msgstr ""
1622 1644
1645 #: rhodecode/events/user.py:100
1646 msgid "user permissions change"
1647 msgstr ""
1648
1623 1649 #: rhodecode/forms/__init__.py:35 rhodecode/templates/admin/gists/new.mako:62
1624 1650 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:87
1625 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:68
1651 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:70
1626 1652 #: rhodecode/templates/admin/permissions/permissions_application.mako:60
1627 1653 #: rhodecode/templates/admin/permissions/permissions_ips.mako:64
1628 #: rhodecode/templates/admin/permissions/permissions_objects.mako:57
1629 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:134
1654 #: rhodecode/templates/admin/permissions/permissions_objects.mako:60
1655 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:205
1630 1656 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:84
1631 1657 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:66
1632 1658 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:80
1633 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:110
1659 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:187
1634 1660 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:244
1635 1661 #: rhodecode/templates/admin/repos/repo_edit_vcs.mako:44
1636 1662 #: rhodecode/templates/admin/settings/settings_global.mako:140
@@ -1638,12 +1664,12 b' msgstr ""'
1638 1664 #: rhodecode/templates/admin/settings/settings_labs.mako:49
1639 1665 #: rhodecode/templates/admin/settings/settings_vcs.mako:14
1640 1666 #: rhodecode/templates/admin/settings/settings_visual.mako:215
1641 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:121
1667 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:192
1642 1668 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:83
1643 1669 #: rhodecode/templates/admin/users/user_edit_emails.mako:63
1644 1670 #: rhodecode/templates/admin/users/user_edit_ips.mako:71
1645 1671 #: rhodecode/templates/admin/users/user_edit_profile.mako:135
1646 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:63
1672 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:65
1647 1673 #: rhodecode/templates/base/default_perms_box.mako:89
1648 1674 msgid "Reset"
1649 1675 msgstr ""
@@ -1652,7 +1678,7 b' msgstr ""'
1652 1678 #: rhodecode/templates/admin/integrations/list.mako:181
1653 1679 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:49
1654 1680 #: rhodecode/templates/admin/my_account/my_account_emails.mako:32
1655 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:31
1681 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:33
1656 1682 #: rhodecode/templates/admin/notifications/notifications_data.mako:22
1657 1683 #: rhodecode/templates/admin/notifications/notifications_show.mako:35
1658 1684 #: rhodecode/templates/admin/permissions/permissions_ips.mako:29
@@ -1661,13 +1687,13 b' msgstr ""'
1661 1687 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:45
1662 1688 #: rhodecode/templates/admin/users/user_edit_emails.mako:31
1663 1689 #: rhodecode/templates/admin/users/user_edit_ips.mako:35
1664 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:28
1690 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:30
1665 1691 #: rhodecode/templates/base/issue_tracker_settings.mako:69
1666 1692 #: rhodecode/templates/base/vcs_settings.mako:244
1667 1693 #: rhodecode/templates/base/vcs_settings.mako:269
1668 #: rhodecode/templates/changeset/changeset_file_comment.mako:143
1669 #: rhodecode/templates/changeset/changeset_file_comment.mako:145
1670 #: rhodecode/templates/changeset/changeset_file_comment.mako:148
1694 #: rhodecode/templates/changeset/changeset_file_comment.mako:144
1695 #: rhodecode/templates/changeset/changeset_file_comment.mako:146
1696 #: rhodecode/templates/changeset/changeset_file_comment.mako:149
1671 1697 #: rhodecode/templates/data_table/_dt_elements.mako:171
1672 1698 #: rhodecode/templates/data_table/_dt_elements.mako:244
1673 1699 #: rhodecode/templates/data_table/_dt_elements.mako:258
@@ -1676,23 +1702,23 b' msgstr ""'
1676 1702 #: rhodecode/templates/files/files_source.mako:51
1677 1703 #: rhodecode/templates/files/files_source.mako:55
1678 1704 #: rhodecode/templates/files/files_source.mako:58
1679 #: rhodecode/templates/pullrequests/pullrequest_show.mako:56
1680 #: rhodecode/templates/pullrequests/pullrequest_show.mako:60
1705 #: rhodecode/templates/pullrequests/pullrequest_show.mako:57
1706 #: rhodecode/templates/pullrequests/pullrequest_show.mako:61
1681 1707 msgid "Delete"
1682 1708 msgstr ""
1683 1709
1684 1710 #: rhodecode/integrations/schema.py:30
1685 #: rhodecode/model/validation_schema/schemas/integration_schema.py:195
1711 #: rhodecode/model/validation_schema/schemas/integration_schema.py:193
1686 1712 msgid "Enable or disable this integration."
1687 1713 msgstr ""
1688 1714
1689 1715 #: rhodecode/integrations/schema.py:37
1690 #: rhodecode/model/validation_schema/schemas/integration_schema.py:176
1716 #: rhodecode/model/validation_schema/schemas/integration_schema.py:174
1691 1717 msgid "Short name for this integration."
1692 1718 msgstr ""
1693 1719
1694 1720 #: rhodecode/integrations/schema.py:39
1695 #: rhodecode/model/validation_schema/schemas/integration_schema.py:178
1721 #: rhodecode/model/validation_schema/schemas/integration_schema.py:176
1696 1722 msgid "Integration name"
1697 1723 msgstr ""
1698 1724
@@ -1815,7 +1841,7 b' msgstr ""'
1815 1841
1816 1842 #: rhodecode/integrations/types/slack.py:60
1817 1843 #: rhodecode/integrations/types/webhook.py:82 rhodecode/templates/login.mako:43
1818 #: rhodecode/templates/register.mako:41
1844 #: rhodecode/templates/register.mako:46
1819 1845 #: rhodecode/templates/admin/admin_log_base.mako:7
1820 1846 #: rhodecode/templates/admin/my_account/my_account_profile.mako:24
1821 1847 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:23
@@ -1823,7 +1849,7 b' msgstr ""'
1823 1849 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:70
1824 1850 #: rhodecode/templates/admin/users/user_add.mako:35
1825 1851 #: rhodecode/templates/admin/users/user_edit_profile.mako:39
1826 #: rhodecode/templates/admin/users/users.mako:63
1852 #: rhodecode/templates/admin/users/users.mako:71
1827 1853 #: rhodecode/templates/base/base.mako:317
1828 1854 #: rhodecode/templates/debug_style/login.html:36
1829 1855 #: rhodecode/templates/email_templates/user_registration.mako:23
@@ -2006,7 +2032,7 b' msgid "fork name %s"'
2006 2032 msgstr ""
2007 2033
2008 2034 #: rhodecode/lib/action_parser.py:191
2009 #: rhodecode/templates/pullrequests/pullrequest_show.mako:51
2035 #: rhodecode/templates/pullrequests/pullrequest_show.mako:52
2010 2036 #, python-format
2011 2037 msgid "Pull request #%s"
2012 2038 msgstr ""
@@ -2039,16 +2065,16 b' msgstr ""'
2039 2065 msgid "Commit not found"
2040 2066 msgstr ""
2041 2067
2042 #: rhodecode/lib/auth.py:1441
2068 #: rhodecode/lib/auth.py:1600
2043 2069 #, python-format
2044 2070 msgid "IP %s not allowed"
2045 2071 msgstr ""
2046 2072
2047 #: rhodecode/lib/auth.py:1531
2073 #: rhodecode/lib/auth.py:1687
2048 2074 msgid "You need to be a registered user to perform this action"
2049 2075 msgstr ""
2050 2076
2051 #: rhodecode/lib/auth.py:1575
2077 #: rhodecode/lib/auth.py:1731
2052 2078 msgid "You need to be signed in to view this page"
2053 2079 msgstr ""
2054 2080
@@ -2056,7 +2082,7 b' msgstr ""'
2056 2082 msgid "Click to select line"
2057 2083 msgstr ""
2058 2084
2059 #: rhodecode/lib/helpers.py:1868
2085 #: rhodecode/lib/helpers.py:1881
2060 2086 msgid ""
2061 2087 "Example filter terms:\n"
2062 2088 " repository:vcs\n"
@@ -2067,6 +2093,8 b' msgid ""'
2067 2093 " date:20120101\n"
2068 2094 " date:[20120101100000 TO 20120102]\n"
2069 2095 "\n"
2096 "Actions: {actions}\n"
2097 "\n"
2070 2098 "Generate wildcards using '*' character:\n"
2071 2099 " \"repository:vcs*\" - search everything starting with 'vcs'\n"
2072 2100 " \"repository:*vcs*\" - search for repository containing 'vcs'\n"
@@ -2076,7 +2104,7 b' msgid ""'
2076 2104 " \"username:test AND repository:test*\"\n"
2077 2105 msgstr ""
2078 2106
2079 #: rhodecode/lib/helpers.py:1892
2107 #: rhodecode/lib/helpers.py:1907
2080 2108 msgid ""
2081 2109 "Example filter terms for `{searcher}` search:\n"
2082 2110 "{terms}\n"
@@ -2090,46 +2118,46 b' msgid ""'
2090 2118 "More: {search_doc}"
2091 2119 msgstr ""
2092 2120
2093 #: rhodecode/lib/helpers.py:1909
2121 #: rhodecode/lib/helpers.py:1924
2094 2122 #, python-format
2095 2123 msgid "%s repository is not mapped to db perhaps it was created or renamed from the filesystem please run the application again in order to rescan repositories"
2096 2124 msgstr ""
2097 2125
2098 #: rhodecode/lib/utils2.py:524
2126 #: rhodecode/lib/utils2.py:535
2099 2127 msgid "in ${ago}"
2100 2128 msgstr ""
2101 2129
2102 #: rhodecode/lib/utils2.py:530
2103 msgid "${ago} ago"
2104 msgstr ""
2105
2106 #: rhodecode/lib/utils2.py:539
2107 msgid "${val}, ${detail}"
2108 msgstr ""
2109
2110 2130 #: rhodecode/lib/utils2.py:541
2131 msgid "${ago} ago"
2132 msgstr ""
2133
2134 #: rhodecode/lib/utils2.py:550
2135 msgid "${val}, ${detail}"
2136 msgstr ""
2137
2138 #: rhodecode/lib/utils2.py:552
2111 2139 msgid "${val}, ${detail} ago"
2112 2140 msgstr ""
2113 2141
2114 #: rhodecode/lib/utils2.py:543
2142 #: rhodecode/lib/utils2.py:554
2115 2143 msgid "in ${val}, ${detail}"
2116 2144 msgstr ""
2117 2145
2118 #: rhodecode/lib/utils2.py:545
2146 #: rhodecode/lib/utils2.py:556
2119 2147 msgid "${val} and ${detail}"
2120 2148 msgstr ""
2121 2149
2122 #: rhodecode/lib/utils2.py:547
2150 #: rhodecode/lib/utils2.py:558
2123 2151 msgid "${val} and ${detail} ago"
2124 2152 msgstr ""
2125 2153
2126 #: rhodecode/lib/utils2.py:549
2154 #: rhodecode/lib/utils2.py:560
2127 2155 msgid "in ${val} and ${detail}"
2128 2156 msgstr ""
2129 2157
2130 #: rhodecode/lib/utils2.py:553
2131 #: rhodecode/public/js/rhodecode-components.js:30702
2132 #: rhodecode/public/js/scripts.js:22550
2158 #: rhodecode/lib/utils2.py:564
2159 #: rhodecode/public/js/rhodecode-components.js:35750
2160 #: rhodecode/public/js/scripts.js:22544
2133 2161 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:84
2134 2162 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:174
2135 2163 msgid "just now"
@@ -2158,15 +2186,16 b' msgstr ""'
2158 2186 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:823
2159 2187 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:945
2160 2188 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:970
2161 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2599
2162 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2287
2163 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2279
2164 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2279
2165 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2283
2166 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2283
2167 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2333
2168 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2334
2169 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2535 rhodecode/model/db.py:2662
2189 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2588
2190 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2654
2191 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2276
2192 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2268
2193 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2268
2194 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2272
2195 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2272
2196 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2322
2197 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2323
2198 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2524 rhodecode/model/db.py:2717
2170 2199 msgid "Repository no access"
2171 2200 msgstr ""
2172 2201
@@ -2193,15 +2222,16 b' msgstr ""'
2193 2222 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824
2194 2223 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946
2195 2224 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971
2196 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2600
2197 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2288
2198 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2280
2199 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2280
2200 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2284
2201 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2284
2202 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2334
2203 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2335
2204 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2536 rhodecode/model/db.py:2663
2225 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2589
2226 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2655
2227 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2277
2228 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2269
2229 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2269
2230 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2273
2231 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2273
2232 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2323
2233 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2324
2234 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2525 rhodecode/model/db.py:2718
2205 2235 msgid "Repository read access"
2206 2236 msgstr ""
2207 2237
@@ -2228,15 +2258,16 b' msgstr ""'
2228 2258 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:825
2229 2259 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:947
2230 2260 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:972
2231 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2601
2232 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2289
2233 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2281
2234 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2281
2235 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2285
2236 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2285
2237 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2335
2238 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2336
2239 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2537 rhodecode/model/db.py:2664
2261 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2590
2262 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2656
2263 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2278
2264 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2270
2265 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2270
2266 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2274
2267 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2274
2268 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2324
2269 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2325
2270 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2526 rhodecode/model/db.py:2719
2240 2271 msgid "Repository write access"
2241 2272 msgstr ""
2242 2273
@@ -2263,15 +2294,16 b' msgstr ""'
2263 2294 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826
2264 2295 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948
2265 2296 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973
2266 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2602
2267 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2290
2268 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2282
2269 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2282
2270 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2286
2271 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2286
2272 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2336
2273 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2337
2274 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2538 rhodecode/model/db.py:2665
2297 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2591
2298 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2657
2299 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2279
2300 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2271
2301 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2271
2302 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2275
2303 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2275
2304 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2325
2305 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2326
2306 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2527 rhodecode/model/db.py:2720
2275 2307 msgid "Repository admin access"
2276 2308 msgstr ""
2277 2309
@@ -2338,15 +2370,16 b' msgstr ""'
2338 2370 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844
2339 2371 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966
2340 2372 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991
2341 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2620
2342 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2308
2343 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2300
2344 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2300
2345 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2304
2346 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2304
2347 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2354
2348 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2355
2349 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2556 rhodecode/model/db.py:2683
2373 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2609
2374 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2680
2375 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2297
2376 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2289
2377 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2289
2378 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2293
2379 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2293
2380 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2343
2381 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2344
2382 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2545 rhodecode/model/db.py:2743
2350 2383 msgid "Repository creation disabled"
2351 2384 msgstr ""
2352 2385
@@ -2373,15 +2406,16 b' msgstr ""'
2373 2406 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845
2374 2407 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967
2375 2408 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992
2376 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2621
2377 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2309
2378 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2301
2379 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2301
2380 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2305
2381 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2305
2382 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2355
2383 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2356
2384 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2557 rhodecode/model/db.py:2684
2409 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2610
2410 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2681
2411 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2298
2412 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2290
2413 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2290
2414 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2294
2415 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2294
2416 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2344
2417 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2345
2418 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2546 rhodecode/model/db.py:2744
2385 2419 msgid "Repository creation enabled"
2386 2420 msgstr ""
2387 2421
@@ -2408,15 +2442,16 b' msgstr ""'
2408 2442 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849
2409 2443 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971
2410 2444 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996
2411 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2625
2412 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2313
2413 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2305
2414 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2305
2415 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2309
2416 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2309
2417 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2359
2418 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2360
2419 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2561 rhodecode/model/db.py:2688
2445 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2614
2446 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2685
2447 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2302
2448 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2294
2449 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2294
2450 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2298
2451 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2298
2452 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2348
2453 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2349
2454 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2550 rhodecode/model/db.py:2748
2420 2455 msgid "Repository forking disabled"
2421 2456 msgstr ""
2422 2457
@@ -2443,15 +2478,16 b' msgstr ""'
2443 2478 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850
2444 2479 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972
2445 2480 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997
2446 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2626
2447 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2314
2448 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2306
2449 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2306
2450 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2310
2451 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2310
2452 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2360
2453 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2361
2454 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2562 rhodecode/model/db.py:2689
2481 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2615
2482 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2686
2483 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2303
2484 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2295
2485 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2295
2486 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2299
2487 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2299
2488 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2349
2489 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2350
2490 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2551 rhodecode/model/db.py:2749
2455 2491 msgid "Repository forking enabled"
2456 2492 msgstr ""
2457 2493
@@ -2499,17 +2535,18 b' msgstr ""'
2499 2535 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1195
2500 2536 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1317
2501 2537 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1342
2502 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3328
2503 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2946
2504 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2940
2505 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2940
2506 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2944
2507 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2944
2508 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3044
2509 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3045
2510 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3264 rhodecode/model/db.py:3391
2511 #: rhodecode/public/js/rhodecode-components.js:48219
2512 #: rhodecode/public/js/scripts.js:40067
2538 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3296
2539 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3379
2540 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2916
2541 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2908
2542 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2909
2543 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2912
2544 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2912
2545 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3012
2546 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3013
2547 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3232 rhodecode/model/db.py:3466
2548 #: rhodecode/public/js/rhodecode-components.js:53541
2549 #: rhodecode/public/js/scripts.js:40291
2513 2550 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:39
2514 2551 #: rhodecode/public/js/src/rhodecode/pullrequests.js:319
2515 2552 msgid "Not Reviewed"
@@ -2538,15 +2575,16 b' msgstr ""'
2538 2575 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1196
2539 2576 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1318
2540 2577 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1343
2541 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3329
2542 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2947
2543 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2941
2544 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2941
2545 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2945
2546 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2945
2547 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3045
2548 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3046
2549 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3265 rhodecode/model/db.py:3392
2578 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3297
2579 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3380
2580 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2917
2581 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2909
2582 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2910
2583 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2913
2584 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2913
2585 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3013
2586 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3014
2587 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3233 rhodecode/model/db.py:3467
2550 2588 msgid "Approved"
2551 2589 msgstr ""
2552 2590
@@ -2573,15 +2611,16 b' msgstr ""'
2573 2611 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1197
2574 2612 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1319
2575 2613 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1344
2576 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3330
2577 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2948
2578 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2942
2579 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2942
2580 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2946
2581 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2946
2582 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3046
2583 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3047
2584 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3266 rhodecode/model/db.py:3393
2614 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3298
2615 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3381
2616 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2918
2617 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2910
2618 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2911
2619 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2914
2620 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2914
2621 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3014
2622 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3015
2623 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3234 rhodecode/model/db.py:3468
2585 2624 msgid "Rejected"
2586 2625 msgstr ""
2587 2626
@@ -2608,15 +2647,16 b' msgstr ""'
2608 2647 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198
2609 2648 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320
2610 2649 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345
2611 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3331
2612 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2949
2613 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2943
2614 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2943
2615 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2947
2616 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2947
2617 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3047
2618 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3048
2619 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3267 rhodecode/model/db.py:3394
2650 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3299
2651 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3382
2652 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2919
2653 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2911
2654 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2912
2655 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2915
2656 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2915
2657 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3015
2658 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3016
2659 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3235 rhodecode/model/db.py:3469
2620 2660 msgid "Under Review"
2621 2661 msgstr ""
2622 2662
@@ -2640,15 +2680,16 b' msgstr ""'
2640 2680 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828
2641 2681 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950
2642 2682 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975
2643 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2604
2644 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2292
2645 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2284
2646 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2284
2647 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2288
2648 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2288
2649 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2338
2650 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2339
2651 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2540 rhodecode/model/db.py:2667
2683 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2593
2684 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2659
2685 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2281
2686 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2273
2687 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2273
2688 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2277
2689 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2277
2690 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2327
2691 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2328
2692 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2529 rhodecode/model/db.py:2722
2652 2693 msgid "Repository group no access"
2653 2694 msgstr ""
2654 2695
@@ -2672,15 +2713,16 b' msgstr ""'
2672 2713 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829
2673 2714 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951
2674 2715 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976
2675 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2605
2676 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2293
2677 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2285
2678 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2285
2679 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2289
2680 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2289
2681 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2339
2682 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2340
2683 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2541 rhodecode/model/db.py:2668
2716 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2594
2717 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2660
2718 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2282
2719 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2274
2720 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2274
2721 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2278
2722 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2278
2723 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2328
2724 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2329
2725 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2530 rhodecode/model/db.py:2723
2684 2726 msgid "Repository group read access"
2685 2727 msgstr ""
2686 2728
@@ -2704,15 +2746,16 b' msgstr ""'
2704 2746 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:830
2705 2747 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:952
2706 2748 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:977
2707 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2606
2708 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2294
2709 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2286
2710 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2286
2711 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2290
2712 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2290
2713 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2340
2714 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2341
2715 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2542 rhodecode/model/db.py:2669
2749 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2595
2750 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2661
2751 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2283
2752 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2275
2753 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2275
2754 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2279
2755 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2279
2756 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2329
2757 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2330
2758 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2531 rhodecode/model/db.py:2724
2716 2759 msgid "Repository group write access"
2717 2760 msgstr ""
2718 2761
@@ -2736,15 +2779,16 b' msgstr ""'
2736 2779 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831
2737 2780 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953
2738 2781 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978
2739 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2607
2740 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2295
2741 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2287
2742 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2287
2743 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2291
2744 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2291
2745 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2341
2746 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2342
2747 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2543 rhodecode/model/db.py:2670
2782 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2596
2783 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2662
2784 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2284
2785 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2276
2786 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2276
2787 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2280
2788 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2280
2789 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2330
2790 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2331
2791 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2532 rhodecode/model/db.py:2725
2748 2792 msgid "Repository group admin access"
2749 2793 msgstr ""
2750 2794
@@ -2767,15 +2811,16 b' msgstr ""'
2767 2811 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833
2768 2812 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955
2769 2813 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980
2770 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2609
2771 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2297
2772 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2289
2773 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2289
2774 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2293
2775 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2293
2776 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2343
2777 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2344
2778 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2545 rhodecode/model/db.py:2672
2814 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2598
2815 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2664
2816 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2286
2817 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2278
2818 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2278
2819 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2282
2820 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2282
2821 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2332
2822 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2333
2823 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2534 rhodecode/model/db.py:2727
2779 2824 msgid "User group no access"
2780 2825 msgstr ""
2781 2826
@@ -2798,15 +2843,16 b' msgstr ""'
2798 2843 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834
2799 2844 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956
2800 2845 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981
2801 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2610
2802 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2298
2803 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2290
2804 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2290
2805 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2294
2806 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2294
2807 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2344
2808 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2345
2809 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2546 rhodecode/model/db.py:2673
2846 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2599
2847 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2665
2848 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2287
2849 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2279
2850 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2279
2851 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2283
2852 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2283
2853 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2333
2854 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2334
2855 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2535 rhodecode/model/db.py:2728
2810 2856 msgid "User group read access"
2811 2857 msgstr ""
2812 2858
@@ -2829,15 +2875,16 b' msgstr ""'
2829 2875 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:835
2830 2876 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:957
2831 2877 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:982
2832 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2611
2833 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2299
2834 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2291
2835 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2291
2836 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2295
2837 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2295
2838 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2345
2839 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2346
2840 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2547 rhodecode/model/db.py:2674
2878 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2600
2879 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2666
2880 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2288
2881 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2280
2882 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2280
2883 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2284
2884 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2284
2885 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2334
2886 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2335
2887 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2536 rhodecode/model/db.py:2729
2841 2888 msgid "User group write access"
2842 2889 msgstr ""
2843 2890
@@ -2860,15 +2907,16 b' msgstr ""'
2860 2907 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836
2861 2908 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958
2862 2909 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983
2863 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2612
2864 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2300
2865 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2292
2866 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2292
2867 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2296
2868 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2296
2869 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2346
2870 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2347
2871 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2548 rhodecode/model/db.py:2675
2910 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2601
2911 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2667
2912 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2289
2913 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2281
2914 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2281
2915 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2285
2916 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2285
2917 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2335
2918 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2336
2919 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2537 rhodecode/model/db.py:2730
2872 2920 msgid "User group admin access"
2873 2921 msgstr ""
2874 2922
@@ -2891,15 +2939,16 b' msgstr ""'
2891 2939 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838
2892 2940 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960
2893 2941 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985
2894 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2614
2895 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2302
2896 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2294
2897 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2294
2898 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2298
2899 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2298
2900 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2348
2901 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2349
2902 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2550 rhodecode/model/db.py:2677
2942 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2603
2943 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2674
2944 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2291
2945 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2283
2946 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2283
2947 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2287
2948 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2287
2949 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2337
2950 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2338
2951 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2539 rhodecode/model/db.py:2737
2903 2952 msgid "Repository Group creation disabled"
2904 2953 msgstr ""
2905 2954
@@ -2922,15 +2971,16 b' msgstr ""'
2922 2971 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839
2923 2972 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961
2924 2973 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986
2925 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2615
2926 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2303
2927 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2295
2928 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2295
2929 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2299
2930 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2299
2931 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2349
2932 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2350
2933 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2551 rhodecode/model/db.py:2678
2974 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2604
2975 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2675
2976 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2292
2977 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2284
2978 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2284
2979 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2288
2980 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2288
2981 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2338
2982 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2339
2983 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2540 rhodecode/model/db.py:2738
2934 2984 msgid "Repository Group creation enabled"
2935 2985 msgstr ""
2936 2986
@@ -2953,15 +3003,16 b' msgstr ""'
2953 3003 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841
2954 3004 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963
2955 3005 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988
2956 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2617
2957 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2305
2958 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2297
2959 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2297
2960 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2301
2961 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2301
2962 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2351
2963 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2352
2964 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2553 rhodecode/model/db.py:2680
3006 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2606
3007 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2677
3008 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2294
3009 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2286
3010 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2286
3011 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2290
3012 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2290
3013 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2340
3014 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2341
3015 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2542 rhodecode/model/db.py:2740
2965 3016 msgid "User Group creation disabled"
2966 3017 msgstr ""
2967 3018
@@ -2984,15 +3035,16 b' msgstr ""'
2984 3035 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842
2985 3036 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964
2986 3037 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989
2987 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2618
2988 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2306
2989 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2298
2990 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2298
2991 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2302
2992 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2302
2993 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2352
2994 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2353
2995 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2554 rhodecode/model/db.py:2681
3038 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2607
3039 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2678
3040 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2295
3041 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2287
3042 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2287
3043 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2291
3044 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2291
3045 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2341
3046 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2342
3047 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2543 rhodecode/model/db.py:2741
2996 3048 msgid "User Group creation enabled"
2997 3049 msgstr ""
2998 3050
@@ -3015,15 +3067,16 b' msgstr ""'
3015 3067 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852
3016 3068 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974
3017 3069 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999
3018 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2628
3019 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2316
3020 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2308
3021 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2308
3022 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2312
3023 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2312
3024 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2362
3025 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2363
3026 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2564 rhodecode/model/db.py:2691
3070 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2617
3071 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2688
3072 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2305
3073 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2297
3074 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2297
3075 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2301
3076 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2301
3077 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2351
3078 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2352
3079 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2553 rhodecode/model/db.py:2751
3027 3080 msgid "Registration disabled"
3028 3081 msgstr ""
3029 3082
@@ -3046,15 +3099,16 b' msgstr ""'
3046 3099 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853
3047 3100 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975
3048 3101 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000
3049 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2629
3050 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2317
3051 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2309
3052 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2309
3053 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2313
3054 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2313
3055 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2363
3056 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2364
3057 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2565 rhodecode/model/db.py:2692
3102 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2618
3103 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2689
3104 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2306
3105 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2298
3106 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2298
3107 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2302
3108 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2302
3109 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2352
3110 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2353
3111 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2554 rhodecode/model/db.py:2752
3058 3112 msgid "User Registration with manual account activation"
3059 3113 msgstr ""
3060 3114
@@ -3077,15 +3131,16 b' msgstr ""'
3077 3131 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:854
3078 3132 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:976
3079 3133 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1001
3080 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2630
3081 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2318
3082 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2310
3083 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2310
3084 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2314
3085 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2314
3086 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2364
3087 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2365
3088 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2566 rhodecode/model/db.py:2693
3134 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2619
3135 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2690
3136 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2307
3137 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2299
3138 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2299
3139 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2303
3140 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2303
3141 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2353
3142 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2354
3143 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2555 rhodecode/model/db.py:2753
3089 3144 msgid "User Registration with automatic account activation"
3090 3145 msgstr ""
3091 3146
@@ -3108,16 +3163,17 b' msgstr ""'
3108 3163 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856
3109 3164 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978
3110 3165 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003
3111 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2636
3112 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2320
3113 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2312
3114 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2312
3115 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2316
3116 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2316
3117 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2370
3118 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2371
3119 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2572 rhodecode/model/db.py:2699
3120 #: rhodecode/model/permission.py:96
3166 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2625
3167 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2696
3168 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2309
3169 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2301
3170 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2301
3171 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2305
3172 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2305
3173 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2359
3174 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2360
3175 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2561 rhodecode/model/db.py:2759
3176 #: rhodecode/model/permission.py:105
3121 3177 msgid "Manual activation of external account"
3122 3178 msgstr ""
3123 3179
@@ -3140,16 +3196,17 b' msgstr ""'
3140 3196 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857
3141 3197 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979
3142 3198 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004
3143 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2637
3144 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2321
3145 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2313
3146 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2313
3147 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2317
3148 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2317
3149 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2371
3150 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2372
3151 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2573 rhodecode/model/db.py:2700
3152 #: rhodecode/model/permission.py:97
3199 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2626
3200 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2697
3201 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2310
3202 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2302
3203 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2302
3204 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2306
3205 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2306
3206 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2360
3207 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2361
3208 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2562 rhodecode/model/db.py:2760
3209 #: rhodecode/model/permission.py:106
3153 3210 msgid "Automatic activation of external account"
3154 3211 msgstr ""
3155 3212
@@ -3166,15 +3223,16 b' msgstr ""'
3166 3223 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:846
3167 3224 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:968
3168 3225 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:993
3169 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2622
3170 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2310
3171 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2302
3172 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2302
3173 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2306
3174 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2306
3175 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2356
3176 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2357
3177 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2558 rhodecode/model/db.py:2685
3226 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2611
3227 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2682
3228 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2299
3229 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2291
3230 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2291
3231 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2295
3232 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2295
3233 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2345
3234 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2346
3235 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2547 rhodecode/model/db.py:2745
3178 3236 msgid "Repository creation enabled with write permission to a repository group"
3179 3237 msgstr ""
3180 3238
@@ -3191,15 +3249,16 b' msgstr ""'
3191 3249 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847
3192 3250 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969
3193 3251 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994
3194 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2623
3195 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2311
3196 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2303
3197 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2303
3198 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2307
3199 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2307
3200 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2357
3201 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2358
3202 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2559 rhodecode/model/db.py:2686
3252 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2612
3253 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2683
3254 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2300
3255 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2292
3256 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2292
3257 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2296
3258 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2296
3259 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2346
3260 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2347
3261 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2548 rhodecode/model/db.py:2746
3203 3262 msgid "Repository creation disabled with write permission to a repository group"
3204 3263 msgstr ""
3205 3264
@@ -3213,15 +3272,16 b' msgstr ""'
3213 3272 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:821
3214 3273 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:943
3215 3274 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:968
3216 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2597
3217 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2285
3218 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2277
3219 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2277
3220 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2281
3221 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2281
3222 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2331
3223 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2332
3224 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2533 rhodecode/model/db.py:2660
3275 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2586
3276 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2652
3277 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2274
3278 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2266
3279 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2266
3280 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2270
3281 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2270
3282 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2320
3283 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2321
3284 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2522 rhodecode/model/db.py:2715
3225 3285 msgid "RhodeCode Super Administrator"
3226 3286 msgstr ""
3227 3287
@@ -3233,15 +3293,16 b' msgstr ""'
3233 3293 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859
3234 3294 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981
3235 3295 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006
3236 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2639
3237 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2323
3238 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2315
3239 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2315
3240 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2319
3241 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2319
3242 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2373
3243 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2374
3244 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2575 rhodecode/model/db.py:2702
3296 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2628
3297 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2699
3298 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2312
3299 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2304
3300 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2304
3301 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2308
3302 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2308
3303 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2362
3304 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2363
3305 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2564 rhodecode/model/db.py:2762
3245 3306 msgid "Inherit object permissions from default user disabled"
3246 3307 msgstr ""
3247 3308
@@ -3253,19 +3314,21 b' msgstr ""'
3253 3314 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860
3254 3315 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982
3255 3316 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007
3256 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2640
3257 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2324
3258 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2316
3259 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2316
3260 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2320
3261 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2320
3262 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2374
3263 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2375
3264 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2576 rhodecode/model/db.py:2703
3317 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2629
3318 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2700
3319 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2313
3320 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2305
3321 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2305
3322 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2309
3323 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2309
3324 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2363
3325 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2364
3326 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2565 rhodecode/model/db.py:2763
3265 3327 msgid "Inherit object permissions from default user enabled"
3266 3328 msgstr ""
3267 3329
3268 3330 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1103
3331 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1107
3269 3332 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:910
3270 3333 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:911
3271 3334 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:911
@@ -3273,11 +3336,12 b' msgstr ""'
3273 3336 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:913
3274 3337 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:955
3275 3338 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:956
3276 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1051 rhodecode/model/db.py:1107
3339 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1051 rhodecode/model/db.py:1103
3277 3340 msgid "all"
3278 3341 msgstr ""
3279 3342
3280 3343 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1104
3344 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1108
3281 3345 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:911
3282 3346 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:912
3283 3347 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:912
@@ -3285,11 +3349,12 b' msgstr ""'
3285 3349 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:914
3286 3350 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:956
3287 3351 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:957
3288 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1052 rhodecode/model/db.py:1108
3352 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1052 rhodecode/model/db.py:1104
3289 3353 msgid "http/web interface"
3290 3354 msgstr ""
3291 3355
3292 3356 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1105
3357 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1109
3293 3358 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:912
3294 3359 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:913
3295 3360 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:913
@@ -3297,11 +3362,12 b' msgstr ""'
3297 3362 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:915
3298 3363 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:957
3299 3364 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:958
3300 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1053 rhodecode/model/db.py:1109
3365 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1053 rhodecode/model/db.py:1105
3301 3366 msgid "vcs (git/hg/svn protocol)"
3302 3367 msgstr ""
3303 3368
3304 3369 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1106
3370 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1110
3305 3371 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:913
3306 3372 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:914
3307 3373 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:914
@@ -3309,11 +3375,12 b' msgstr ""'
3309 3375 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:916
3310 3376 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:958
3311 3377 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:959
3312 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1054 rhodecode/model/db.py:1110
3378 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1054 rhodecode/model/db.py:1106
3313 3379 msgid "api calls"
3314 3380 msgstr ""
3315 3381
3316 3382 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1107
3383 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1111
3317 3384 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:914
3318 3385 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:915
3319 3386 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:915
@@ -3321,43 +3388,67 b' msgstr ""'
3321 3388 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:917
3322 3389 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:959
3323 3390 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:960
3324 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1055 rhodecode/model/db.py:1111
3391 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1055 rhodecode/model/db.py:1107
3325 3392 msgid "feed access"
3326 3393 msgstr ""
3327 3394
3328 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2360
3329 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2063
3330 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2055
3331 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2055
3332 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2059
3333 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2059
3334 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2102
3335 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2103
3336 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2297 rhodecode/model/db.py:2423
3395 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2349
3396 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2415
3397 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2052
3398 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2044
3399 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2044
3400 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2048
3401 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2048
3402 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2091
3403 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2092
3404 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2286 rhodecode/model/db.py:2468
3337 3405 msgid "No parent"
3338 3406 msgstr ""
3339 3407
3340 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2632
3341 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2366
3342 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2367
3343 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2568 rhodecode/model/db.py:2695
3408 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2621
3409 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2692
3410 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2355
3411 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2356
3412 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2557 rhodecode/model/db.py:2755
3344 3413 msgid "Password reset enabled"
3345 3414 msgstr ""
3346 3415
3347 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2633
3348 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2367
3349 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2368
3350 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2569 rhodecode/model/db.py:2696
3416 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2622
3417 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2693
3418 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2356
3419 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2357
3420 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2558 rhodecode/model/db.py:2756
3351 3421 msgid "Password reset hidden"
3352 3422 msgstr ""
3353 3423
3354 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2634
3355 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2368
3356 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2369
3357 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2570 rhodecode/model/db.py:2697
3424 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2623
3425 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2694
3426 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2357
3427 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2358
3428 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2559 rhodecode/model/db.py:2757
3358 3429 msgid "Password reset disabled"
3359 3430 msgstr ""
3360 3431
3432 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2669
3433 #: rhodecode/model/db.py:2732
3434 msgid "Branch no permissions"
3435 msgstr ""
3436
3437 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2670
3438 #: rhodecode/model/db.py:2733
3439 msgid "Branch access by web merge"
3440 msgstr ""
3441
3442 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2671
3443 #: rhodecode/model/db.py:2734
3444 msgid "Branch access by push"
3445 msgstr ""
3446
3447 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2672
3448 #: rhodecode/model/db.py:2735
3449 msgid "Branch access by push with force"
3450 msgstr ""
3451
3361 3452 #: rhodecode/lib/index/whoosh.py:164
3362 3453 msgid "Index Type"
3363 3454 msgstr ""
@@ -3394,11 +3485,11 b' msgstr ""'
3394 3485 msgid "1 month {end_date}"
3395 3486 msgstr ""
3396 3487
3397 #: rhodecode/model/comment.py:382
3488 #: rhodecode/model/comment.py:384
3398 3489 msgid "made a comment"
3399 3490 msgstr ""
3400 3491
3401 #: rhodecode/model/comment.py:383
3492 #: rhodecode/model/comment.py:385
3402 3493 msgid "Show it now"
3403 3494 msgstr ""
3404 3495
@@ -3480,35 +3571,36 b' msgstr ""'
3480 3571 msgid "%(user)s commented on pull request at %(date_or_age)s"
3481 3572 msgstr ""
3482 3573
3483 #: rhodecode/model/permission.py:68 rhodecode/model/permission.py:74
3484 #: rhodecode/model/permission.py:80
3574 #: rhodecode/model/permission.py:71 rhodecode/model/permission.py:77
3575 #: rhodecode/model/permission.py:83
3485 3576 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:11
3486 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:124
3577 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:195
3487 3578 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:11
3488 3579 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:11
3489 3580 msgid "None"
3490 3581 msgstr ""
3491 3582
3492 #: rhodecode/model/permission.py:69 rhodecode/model/permission.py:75
3493 #: rhodecode/model/permission.py:81
3583 #: rhodecode/model/permission.py:72 rhodecode/model/permission.py:78
3584 #: rhodecode/model/permission.py:84
3494 3585 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:12
3495 3586 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:12
3496 3587 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:12
3497 3588 msgid "Read"
3498 3589 msgstr ""
3499 3590
3500 #: rhodecode/model/permission.py:70 rhodecode/model/permission.py:76
3501 #: rhodecode/model/permission.py:82
3591 #: rhodecode/model/permission.py:73 rhodecode/model/permission.py:79
3592 #: rhodecode/model/permission.py:85
3502 3593 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:13
3503 3594 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:13
3504 3595 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:13
3505 #: rhodecode/templates/changeset/changeset_file_comment.mako:272
3506 #: rhodecode/templates/changeset/changeset_file_comment.mako:322
3596 #: rhodecode/templates/changeset/changeset_file_comment.mako:273
3597 #: rhodecode/templates/changeset/changeset_file_comment.mako:323
3598 #: rhodecode/templates/data_table/_dt_elements.mako:386
3507 3599 msgid "Write"
3508 3600 msgstr ""
3509 3601
3510 #: rhodecode/model/permission.py:71 rhodecode/model/permission.py:77
3511 #: rhodecode/model/permission.py:83
3602 #: rhodecode/model/permission.py:74 rhodecode/model/permission.py:80
3603 #: rhodecode/model/permission.py:86
3512 3604 #: rhodecode/templates/admin/auth/auth_settings.mako:12
3513 3605 #: rhodecode/templates/admin/auth/plugin_settings.mako:12
3514 3606 #: rhodecode/templates/admin/defaults/defaults.mako:12
@@ -3536,36 +3628,52 b' msgstr ""'
3536 3628 #: rhodecode/templates/admin/users/user_add.mako:11
3537 3629 #: rhodecode/templates/admin/users/user_edit.mako:12
3538 3630 #: rhodecode/templates/admin/users/users.mako:13
3539 #: rhodecode/templates/admin/users/users.mako:76
3540 #: rhodecode/templates/base/base.mako:421
3541 #: rhodecode/templates/base/base.mako:428
3631 #: rhodecode/templates/admin/users/users.mako:84
3632 #: rhodecode/templates/base/base.mako:452
3633 #: rhodecode/templates/base/base.mako:459
3542 3634 msgid "Admin"
3543 3635 msgstr ""
3544 3636
3545 #: rhodecode/model/permission.py:86 rhodecode/model/permission.py:100
3546 #: rhodecode/model/permission.py:104 rhodecode/model/permission.py:108
3547 #: rhodecode/model/permission.py:112 rhodecode/model/permission.py:116
3548 #: rhodecode/model/permission.py:120
3549 msgid "Disabled"
3550 msgstr ""
3551
3552 #: rhodecode/model/permission.py:87
3553 msgid "Allowed with manual account activation"
3554 msgstr ""
3555
3556 #: rhodecode/model/permission.py:88
3557 msgid "Allowed with automatic account activation"
3637 #: rhodecode/model/permission.py:89
3638 msgid "Protected/No Access"
3639 msgstr ""
3640
3641 #: rhodecode/model/permission.py:90
3642 msgid "Web merge"
3558 3643 msgstr ""
3559 3644
3560 3645 #: rhodecode/model/permission.py:91
3561 msgid "Allow password recovery"
3646 msgid "Push"
3562 3647 msgstr ""
3563 3648
3564 3649 #: rhodecode/model/permission.py:92
3650 msgid "Force Push"
3651 msgstr ""
3652
3653 #: rhodecode/model/permission.py:95 rhodecode/model/permission.py:109
3654 #: rhodecode/model/permission.py:113 rhodecode/model/permission.py:117
3655 #: rhodecode/model/permission.py:121 rhodecode/model/permission.py:125
3656 #: rhodecode/model/permission.py:129
3657 msgid "Disabled"
3658 msgstr ""
3659
3660 #: rhodecode/model/permission.py:96
3661 msgid "Allowed with manual account activation"
3662 msgstr ""
3663
3664 #: rhodecode/model/permission.py:97
3665 msgid "Allowed with automatic account activation"
3666 msgstr ""
3667
3668 #: rhodecode/model/permission.py:100
3669 msgid "Allow password recovery"
3670 msgstr ""
3671
3672 #: rhodecode/model/permission.py:101
3565 3673 msgid "Hide password recovery link"
3566 3674 msgstr ""
3567 3675
3568 #: rhodecode/model/permission.py:93
3676 #: rhodecode/model/permission.py:102
3569 3677 msgid "Disable password recovery"
3570 3678 msgstr ""
3571 3679
@@ -3641,71 +3749,75 b' msgstr ""'
3641 3749 msgid "This pull request cannot be updated because the source reference is missing."
3642 3750 msgstr ""
3643 3751
3644 #: rhodecode/model/pull_request.py:1218
3752 #: rhodecode/model/pull_request.py:1236
3645 3753 msgid "Server-side pull request merging is disabled."
3646 3754 msgstr ""
3647 3755
3648 #: rhodecode/model/pull_request.py:1220
3756 #: rhodecode/model/pull_request.py:1238
3649 3757 msgid "This pull request is closed."
3650 3758 msgstr ""
3651 3759
3652 #: rhodecode/model/pull_request.py:1233
3760 #: rhodecode/model/pull_request.py:1253
3653 3761 msgid "Pull request merging is not supported."
3654 3762 msgstr ""
3655 3763
3656 #: rhodecode/model/pull_request.py:1252
3764 #: rhodecode/model/pull_request.py:1272
3657 3765 msgid "Target repository large files support is disabled."
3658 3766 msgstr ""
3659 3767
3660 #: rhodecode/model/pull_request.py:1255
3768 #: rhodecode/model/pull_request.py:1275
3661 3769 msgid "Source repository large files support is disabled."
3662 3770 msgstr ""
3663 3771
3664 #: rhodecode/model/pull_request.py:1420 rhodecode/model/scm.py:797
3772 #: rhodecode/model/pull_request.py:1444 rhodecode/model/scm.py:803
3665 3773 msgid "Bookmarks"
3666 3774 msgstr ""
3667 3775
3668 #: rhodecode/model/pull_request.py:1425
3776 #: rhodecode/model/pull_request.py:1449
3669 3777 msgid "Commit IDs"
3670 3778 msgstr ""
3671 3779
3672 #: rhodecode/model/pull_request.py:1428
3780 #: rhodecode/model/pull_request.py:1452
3673 3781 msgid "Closed Branches"
3674 3782 msgstr ""
3675 3783
3676 #: rhodecode/model/pull_request.py:1588
3784 #: rhodecode/model/pull_request.py:1613
3677 3785 msgid "User `{}` not allowed to perform merge."
3678 3786 msgstr ""
3679 3787
3680 #: rhodecode/model/pull_request.py:1601
3788 #: rhodecode/model/pull_request.py:1631
3789 msgid "Target branch `{}` changes rejected by rule {}."
3790 msgstr ""
3791
3792 #: rhodecode/model/pull_request.py:1645
3681 3793 msgid "Pull request reviewer approval is pending."
3682 3794 msgstr ""
3683 3795
3684 #: rhodecode/model/pull_request.py:1616
3796 #: rhodecode/model/pull_request.py:1660
3685 3797 msgid "Cannot merge, {} TODO still not resolved."
3686 3798 msgstr ""
3687 3799
3688 #: rhodecode/model/pull_request.py:1619
3800 #: rhodecode/model/pull_request.py:1663
3689 3801 msgid "Cannot merge, {} TODOs still not resolved."
3690 3802 msgstr ""
3691 3803
3692 #: rhodecode/model/pull_request.py:1654
3804 #: rhodecode/model/pull_request.py:1699
3693 3805 msgid "Merge strategy: rebase"
3694 3806 msgstr ""
3695 3807
3696 #: rhodecode/model/pull_request.py:1659
3808 #: rhodecode/model/pull_request.py:1704
3697 3809 msgid "Merge strategy: explicit merge commit"
3698 3810 msgstr ""
3699 3811
3700 #: rhodecode/model/pull_request.py:1666
3812 #: rhodecode/model/pull_request.py:1711
3701 3813 msgid "Source branch will be closed after merge."
3702 3814 msgstr ""
3703 3815
3704 #: rhodecode/model/pull_request.py:1668
3816 #: rhodecode/model/pull_request.py:1713
3705 3817 msgid "Source branch will be deleted after merge."
3706 3818 msgstr ""
3707 3819
3708 #: rhodecode/model/scm.py:775
3820 #: rhodecode/model/scm.py:781
3709 3821 msgid "latest tip"
3710 3822 msgstr ""
3711 3823
@@ -3967,19 +4079,19 b' msgstr ""'
3967 4079 msgid "Only superadmins can create global integrations"
3968 4080 msgstr ""
3969 4081
3970 #: rhodecode/model/validation_schema/schemas/integration_schema.py:183
4082 #: rhodecode/model/validation_schema/schemas/integration_schema.py:181
3971 4083 msgid "Scope of the integration. Recursive means the integration runs on all repos of that group and children recursively."
3972 4084 msgstr ""
3973 4085
3974 #: rhodecode/model/validation_schema/schemas/integration_schema.py:186
4086 #: rhodecode/model/validation_schema/schemas/integration_schema.py:184
3975 4087 msgid "Integration scope"
3976 4088 msgstr ""
3977 4089
3978 #: rhodecode/model/validation_schema/schemas/integration_schema.py:216
4090 #: rhodecode/model/validation_schema/schemas/integration_schema.py:214
3979 4091 msgid "General integration options"
3980 4092 msgstr ""
3981 4093
3982 #: rhodecode/model/validation_schema/schemas/integration_schema.py:219
4094 #: rhodecode/model/validation_schema/schemas/integration_schema.py:217
3983 4095 msgid "{integration_type} settings"
3984 4096 msgstr ""
3985 4097
@@ -4043,459 +4155,459 b' msgstr ""'
4043 4155 msgid "Additional emails can be specified at <a href=\"{}\">extra emails</a> page."
4044 4156 msgstr ""
4045 4157
4046 #: rhodecode/public/js/rhodecode-components.js:28706
4047 #: rhodecode/public/js/scripts.js:20554
4158 #: rhodecode/public/js/rhodecode-components.js:13225
4159 #: rhodecode/public/js/scripts.js:19
4160 msgid ": , "
4161 msgstr ""
4162
4163 #: rhodecode/public/js/rhodecode-components.js:33754
4164 #: rhodecode/public/js/scripts.js:20548
4048 4165 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:34
4049 4166 #: rhodecode/public/js/src/plugins/jquery.autocomplete.js:87
4050 4167 msgid "No results"
4051 4168 msgstr ""
4052 4169
4053 #: rhodecode/public/js/rhodecode-components.js:30637
4054 #: rhodecode/public/js/scripts.js:22485
4055 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:108
4170 #: rhodecode/public/js/rhodecode-components.js:35685
4171 #: rhodecode/public/js/scripts.js:22479
4172 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:112
4056 4173 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:109
4057 4174 msgid "{0} year"
4058 4175 msgstr ""
4059 4176
4060 #: rhodecode/public/js/rhodecode-components.js:30638
4061 #: rhodecode/public/js/scripts.js:22486
4062 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:102
4177 #: rhodecode/public/js/rhodecode-components.js:35686
4178 #: rhodecode/public/js/scripts.js:22480
4179 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:104
4063 4180 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:110
4064 4181 msgid "{0} month"
4065 4182 msgstr ""
4066 4183
4067 #: rhodecode/public/js/rhodecode-components.js:30639
4068 #: rhodecode/public/js/scripts.js:22487
4069 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:97
4184 #: rhodecode/public/js/rhodecode-components.js:35687
4185 #: rhodecode/public/js/scripts.js:22481
4186 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:99
4070 4187 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:111
4071 4188 msgid "{0} day"
4072 4189 msgstr ""
4073 4190
4074 #: rhodecode/public/js/rhodecode-components.js:30640
4075 #: rhodecode/public/js/scripts.js:22488
4076 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:99
4191 #: rhodecode/public/js/rhodecode-components.js:35688
4192 #: rhodecode/public/js/scripts.js:22482
4193 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:101
4077 4194 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:112
4078 4195 msgid "{0} hour"
4079 4196 msgstr ""
4080 4197
4081 #: rhodecode/public/js/rhodecode-components.js:30641
4082 #: rhodecode/public/js/scripts.js:22489
4083 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:101
4198 #: rhodecode/public/js/rhodecode-components.js:35689
4199 #: rhodecode/public/js/scripts.js:22483
4200 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:103
4084 4201 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:113
4085 4202 msgid "{0} min"
4086 4203 msgstr ""
4087 4204
4088 #: rhodecode/public/js/rhodecode-components.js:30642
4089 #: rhodecode/public/js/scripts.js:22490
4090 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:107
4205 #: rhodecode/public/js/rhodecode-components.js:35690
4206 #: rhodecode/public/js/scripts.js:22484
4207 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:109
4091 4208 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:114
4092 4209 msgid "{0} sec"
4093 4210 msgstr ""
4094 4211
4095 #: rhodecode/public/js/rhodecode-components.js:30662
4096 #: rhodecode/public/js/scripts.js:22510
4212 #: rhodecode/public/js/rhodecode-components.js:35710
4213 #: rhodecode/public/js/scripts.js:22504
4097 4214 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:81
4098 4215 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:134
4099 4216 msgid "in {0}"
4100 4217 msgstr ""
4101 4218
4102 #: rhodecode/public/js/rhodecode-components.js:30670
4103 #: rhodecode/public/js/scripts.js:22518
4104 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:94
4219 #: rhodecode/public/js/rhodecode-components.js:35718
4220 #: rhodecode/public/js/scripts.js:22512
4221 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:96
4105 4222 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:142
4106 4223 msgid "{0} ago"
4107 4224 msgstr ""
4108 4225
4109 #: rhodecode/public/js/rhodecode-components.js:30682
4110 #: rhodecode/public/js/scripts.js:22530
4111 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:110
4226 #: rhodecode/public/js/rhodecode-components.js:35730
4227 #: rhodecode/public/js/scripts.js:22524
4228 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:114
4112 4229 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:154
4113 4230 msgid "{0}, {1} ago"
4114 4231 msgstr ""
4115 4232
4116 #: rhodecode/public/js/rhodecode-components.js:30684
4117 #: rhodecode/public/js/scripts.js:22532
4233 #: rhodecode/public/js/rhodecode-components.js:35732
4234 #: rhodecode/public/js/scripts.js:22526
4118 4235 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:83
4119 4236 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:156
4120 4237 msgid "in {0}, {1}"
4121 4238 msgstr ""
4122 4239
4123 #: rhodecode/public/js/rhodecode-components.js:30688
4124 #: rhodecode/public/js/scripts.js:22536
4125 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:95
4240 #: rhodecode/public/js/rhodecode-components.js:35736
4241 #: rhodecode/public/js/scripts.js:22530
4242 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:97
4126 4243 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:160
4127 4244 msgid "{0} and {1}"
4128 4245 msgstr ""
4129 4246
4130 #: rhodecode/public/js/rhodecode-components.js:30690
4131 #: rhodecode/public/js/scripts.js:22538
4132 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:96
4247 #: rhodecode/public/js/rhodecode-components.js:35738
4248 #: rhodecode/public/js/scripts.js:22532
4249 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:98
4133 4250 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:162
4134 4251 msgid "{0} and {1} ago"
4135 4252 msgstr ""
4136 4253
4137 #: rhodecode/public/js/rhodecode-components.js:30692
4138 #: rhodecode/public/js/scripts.js:22540
4254 #: rhodecode/public/js/rhodecode-components.js:35740
4255 #: rhodecode/public/js/scripts.js:22534
4139 4256 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:82
4140 4257 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:164
4141 4258 msgid "in {0} and {1}"
4142 4259 msgstr ""
4143 4260
4144 #: rhodecode/public/js/rhodecode-components.js:44751
4145 #: rhodecode/public/js/scripts.js:36599
4261 #: rhodecode/public/js/rhodecode-components.js:49799
4146 4262 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:24
4147 4263 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:4
4148 4264 msgid "Loading more results..."
4149 4265 msgstr ""
4150 4266
4151 #: rhodecode/public/js/rhodecode-components.js:44754
4152 #: rhodecode/public/js/scripts.js:36602
4267 #: rhodecode/public/js/rhodecode-components.js:49802
4153 4268 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:50
4154 4269 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:7
4155 4270 msgid "Searching..."
4156 4271 msgstr ""
4157 4272
4158 #: rhodecode/public/js/rhodecode-components.js:44757
4159 #: rhodecode/public/js/scripts.js:36605
4273 #: rhodecode/public/js/rhodecode-components.js:49805
4160 4274 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:29
4161 4275 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:10
4162 4276 msgid "No matches found"
4163 4277 msgstr ""
4164 4278
4165 #: rhodecode/public/js/rhodecode-components.js:44760
4166 #: rhodecode/public/js/scripts.js:36608
4279 #: rhodecode/public/js/rhodecode-components.js:49808
4167 4280 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:23
4168 4281 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:13
4169 4282 msgid "Loading failed"
4170 4283 msgstr ""
4171 4284
4172 #: rhodecode/public/js/rhodecode-components.js:44764
4173 #: rhodecode/public/js/scripts.js:36612
4285 #: rhodecode/public/js/rhodecode-components.js:49812
4174 4286 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:41
4175 4287 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:17
4176 4288 msgid "One result is available, press enter to select it."
4177 4289 msgstr ""
4178 4290
4179 #: rhodecode/public/js/rhodecode-components.js:44766
4180 #: rhodecode/public/js/scripts.js:36614
4181 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:106
4291 #: rhodecode/public/js/rhodecode-components.js:49814
4292 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:108
4182 4293 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:19
4183 4294 msgid "{0} results are available, use up and down arrow keys to navigate."
4184 4295 msgstr ""
4185 4296
4186 #: rhodecode/public/js/rhodecode-components.js:44771
4187 #: rhodecode/public/js/scripts.js:36619
4297 #: rhodecode/public/js/rhodecode-components.js:49819
4188 4298 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:46
4189 4299 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:24
4190 4300 msgid "Please enter {0} or more character"
4191 4301 msgstr ""
4192 4302
4193 #: rhodecode/public/js/rhodecode-components.js:44773
4194 #: rhodecode/public/js/scripts.js:36621
4303 #: rhodecode/public/js/rhodecode-components.js:49821
4195 4304 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:47
4196 4305 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:26
4197 4306 msgid "Please enter {0} or more characters"
4198 4307 msgstr ""
4199 4308
4200 #: rhodecode/public/js/rhodecode-components.js:44778
4201 #: rhodecode/public/js/scripts.js:36626
4309 #: rhodecode/public/js/rhodecode-components.js:49826
4202 4310 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:44
4203 4311 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:31
4204 4312 msgid "Please delete {0} character"
4205 4313 msgstr ""
4206 4314
4207 #: rhodecode/public/js/rhodecode-components.js:44780
4208 #: rhodecode/public/js/scripts.js:36628
4315 #: rhodecode/public/js/rhodecode-components.js:49828
4209 4316 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:45
4210 4317 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:33
4211 4318 msgid "Please delete {0} characters"
4212 4319 msgstr ""
4213 4320
4214 #: rhodecode/public/js/rhodecode-components.js:44784
4215 #: rhodecode/public/js/scripts.js:36632
4321 #: rhodecode/public/js/rhodecode-components.js:49832
4216 4322 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:73
4217 4323 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:37
4218 4324 msgid "You can only select {0} item"
4219 4325 msgstr ""
4220 4326
4221 #: rhodecode/public/js/rhodecode-components.js:44786
4222 #: rhodecode/public/js/scripts.js:36634
4327 #: rhodecode/public/js/rhodecode-components.js:49834
4223 4328 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:74
4224 4329 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:39
4225 4330 msgid "You can only select {0} items"
4226 4331 msgstr ""
4227 4332
4228 #: rhodecode/public/js/rhodecode-components.js:45724
4229 #: rhodecode/public/js/scripts.js:37572
4333 #: rhodecode/public/js/rhodecode-components.js:50772
4334 #: rhodecode/public/js/scripts.js:37522
4230 4335 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:88
4231 4336 #: rhodecode/public/js/src/rhodecode/changelog.js:35
4232 4337 msgid "showing {0} out of {1} commit"
4233 4338 msgstr ""
4234 4339
4235 #: rhodecode/public/js/rhodecode-components.js:45726
4236 #: rhodecode/public/js/scripts.js:37574
4340 #: rhodecode/public/js/rhodecode-components.js:50774
4341 #: rhodecode/public/js/scripts.js:37524
4237 4342 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:89
4238 4343 #: rhodecode/public/js/src/rhodecode/changelog.js:37
4239 4344 msgid "showing {0} out of {1} commits"
4240 4345 msgstr ""
4241 4346
4242 #: rhodecode/public/js/rhodecode-components.js:46172
4243 #: rhodecode/public/js/scripts.js:38020
4347 #: rhodecode/public/js/rhodecode-components.js:51282
4348 #: rhodecode/public/js/scripts.js:38032
4244 4349 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:53
4245 #: rhodecode/public/js/src/rhodecode/codemirror.js:297
4350 #: rhodecode/public/js/src/rhodecode/codemirror.js:359
4246 4351 msgid "Set status to Approved"
4247 4352 msgstr ""
4248 4353
4249 #: rhodecode/public/js/rhodecode-components.js:46191
4250 #: rhodecode/public/js/scripts.js:38039
4354 #: rhodecode/public/js/rhodecode-components.js:51301
4355 #: rhodecode/public/js/scripts.js:38051
4251 4356 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:54
4252 #: rhodecode/public/js/src/rhodecode/codemirror.js:316
4357 #: rhodecode/public/js/src/rhodecode/codemirror.js:378
4253 4358 msgid "Set status to Rejected"
4254 4359 msgstr ""
4255 4360
4256 #: rhodecode/public/js/rhodecode-components.js:46210
4257 #: rhodecode/public/js/scripts.js:38058
4361 #: rhodecode/public/js/rhodecode-components.js:51320
4362 #: rhodecode/public/js/scripts.js:38070
4258 4363 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:66
4259 #: rhodecode/public/js/src/rhodecode/codemirror.js:335
4364 #: rhodecode/public/js/src/rhodecode/codemirror.js:397
4260 4365 #: rhodecode/templates/email_templates/commit_comment.mako:99
4261 4366 #: rhodecode/templates/email_templates/pull_request_comment.mako:107
4262 4367 msgid "TODO comment"
4263 4368 msgstr ""
4264 4369
4265 #: rhodecode/public/js/rhodecode-components.js:46230
4266 #: rhodecode/public/js/scripts.js:38078
4370 #: rhodecode/public/js/rhodecode-components.js:51340
4371 #: rhodecode/public/js/scripts.js:38090
4267 4372 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:40
4268 #: rhodecode/public/js/src/rhodecode/codemirror.js:355
4373 #: rhodecode/public/js/src/rhodecode/codemirror.js:417
4269 4374 msgid "Note Comment"
4270 4375 msgstr ""
4271 4376
4272 #: rhodecode/public/js/rhodecode-components.js:46597
4273 #: rhodecode/public/js/scripts.js:38445
4274 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:87
4275 #: rhodecode/public/js/src/rhodecode/comments.js:126
4276 msgid "resolve comment"
4277 msgstr ""
4278
4279 #: rhodecode/public/js/rhodecode-components.js:46681
4280 #: rhodecode/public/js/scripts.js:38529
4377 #: rhodecode/public/js/rhodecode-components.js:51653
4378 #: rhodecode/public/js/rhodecode-components.js:52007
4379 #: rhodecode/public/js/scripts.js:38403 rhodecode/public/js/scripts.js:38757
4281 4380 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:61
4282 #: rhodecode/public/js/src/rhodecode/comments.js:210
4381 #: rhodecode/public/js/src/rhodecode/codemirror.js:730
4382 #: rhodecode/public/js/src/rhodecode/comments.js:233
4283 4383 msgid "Status Review"
4284 4384 msgstr ""
4285 4385
4286 #: rhodecode/public/js/rhodecode-components.js:46696
4287 #: rhodecode/public/js/scripts.js:38544
4386 #: rhodecode/public/js/rhodecode-components.js:51668
4387 #: rhodecode/public/js/rhodecode-components.js:52022
4388 #: rhodecode/public/js/scripts.js:38418 rhodecode/public/js/scripts.js:38772
4288 4389 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:11
4289 #: rhodecode/public/js/src/rhodecode/comments.js:225
4390 #: rhodecode/public/js/src/rhodecode/codemirror.js:745
4391 #: rhodecode/public/js/src/rhodecode/comments.js:248
4290 4392 msgid "Comment text will be set automatically based on currently selected status ({0}) ..."
4291 4393 msgstr ""
4292 4394
4293 #: rhodecode/public/js/rhodecode-components.js:46853
4294 #: rhodecode/public/js/scripts.js:38701
4295 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:63
4296 #: rhodecode/public/js/src/rhodecode/comments.js:382
4297 msgid "Submitting..."
4298 msgstr ""
4299
4300 #: rhodecode/public/js/rhodecode-components.js:46904
4301 #: rhodecode/public/js/scripts.js:38752
4395 #: rhodecode/public/js/rhodecode-components.js:51749
4396 #: rhodecode/public/js/rhodecode-components.js:52217
4397 #: rhodecode/public/js/scripts.js:38499 rhodecode/public/js/scripts.js:38967
4302 4398 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:22
4303 #: rhodecode/public/js/src/rhodecode/comments.js:433
4399 #: rhodecode/public/js/src/rhodecode/codemirror.js:826
4400 #: rhodecode/public/js/src/rhodecode/comments.js:443
4304 4401 #: rhodecode/templates/files/files_browser_tree.mako:51
4305 4402 msgid "Loading ..."
4306 4403 msgstr ""
4307 4404
4308 #: rhodecode/public/js/rhodecode-components.js:47014
4309 #: rhodecode/public/js/scripts.js:38862
4405 #: rhodecode/public/js/rhodecode-components.js:51923
4406 #: rhodecode/public/js/scripts.js:38673
4407 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:87
4408 #: rhodecode/public/js/src/rhodecode/comments.js:149
4409 msgid "resolve comment"
4410 msgstr ""
4411
4412 #: rhodecode/public/js/rhodecode-components.js:52166
4413 #: rhodecode/public/js/scripts.js:38916
4414 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:63
4415 #: rhodecode/public/js/src/rhodecode/comments.js:392
4416 msgid "Submitting..."
4417 msgstr ""
4418
4419 #: rhodecode/public/js/rhodecode-components.js:52331
4420 #: rhodecode/public/js/scripts.js:39081
4310 4421 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:13
4311 #: rhodecode/public/js/src/rhodecode/comments.js:543
4422 #: rhodecode/public/js/src/rhodecode/comments.js:557
4312 4423 msgid "Delete this comment?"
4313 4424 msgstr ""
4314 4425
4315 #: rhodecode/public/js/rhodecode-components.js:47086
4316 #: rhodecode/public/js/scripts.js:38934
4426 #: rhodecode/public/js/rhodecode-components.js:52403
4427 #: rhodecode/public/js/scripts.js:39153
4317 4428 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:20
4318 #: rhodecode/public/js/src/rhodecode/comments.js:615
4429 #: rhodecode/public/js/src/rhodecode/comments.js:629
4319 4430 msgid "Leave a comment, or click resolve button to resolve TODO comment #{0}"
4320 4431 msgstr ""
4321 4432
4322 #: rhodecode/public/js/rhodecode-components.js:47163
4323 #: rhodecode/public/js/scripts.js:39011
4433 #: rhodecode/public/js/rhodecode-components.js:52480
4434 #: rhodecode/public/js/scripts.js:39230
4324 4435 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:19
4325 #: rhodecode/public/js/src/rhodecode/comments.js:692
4436 #: rhodecode/public/js/src/rhodecode/comments.js:706
4326 4437 msgid "Leave a comment on line {0}."
4327 4438 msgstr ""
4328 4439
4329 #: rhodecode/public/js/rhodecode-components.js:47277
4330 #: rhodecode/public/js/scripts.js:39125
4440 #: rhodecode/public/js/rhodecode-components.js:52598
4441 #: rhodecode/public/js/scripts.js:39348
4331 4442 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:67
4332 #: rhodecode/public/js/src/rhodecode/comments.js:806
4443 #: rhodecode/public/js/src/rhodecode/comments.js:824
4333 4444 msgid "TODO from comment {0} was fixed."
4334 4445 msgstr ""
4335 4446
4336 #: rhodecode/public/js/rhodecode-components.js:47457
4337 #: rhodecode/public/js/scripts.js:39305
4447 #: rhodecode/public/js/rhodecode-components.js:52778
4448 #: rhodecode/public/js/scripts.js:39528
4338 4449 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:91
4339 4450 #: rhodecode/public/js/src/rhodecode/files.js:150
4340 4451 msgid "truncated result"
4341 4452 msgstr ""
4342 4453
4343 #: rhodecode/public/js/rhodecode-components.js:47459
4344 #: rhodecode/public/js/scripts.js:39307
4454 #: rhodecode/public/js/rhodecode-components.js:52780
4455 #: rhodecode/public/js/scripts.js:39530
4345 4456 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:92
4346 4457 #: rhodecode/public/js/src/rhodecode/files.js:152
4347 4458 msgid "truncated results"
4348 4459 msgstr ""
4349 4460
4350 #: rhodecode/public/js/rhodecode-components.js:47468
4351 #: rhodecode/public/js/scripts.js:39316
4461 #: rhodecode/public/js/rhodecode-components.js:52789
4462 #: rhodecode/public/js/scripts.js:39539
4352 4463 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:30
4353 4464 #: rhodecode/public/js/src/rhodecode/files.js:161
4354 4465 msgid "No matching files"
4355 4466 msgstr ""
4356 4467
4357 #: rhodecode/public/js/rhodecode-components.js:47603
4358 #: rhodecode/public/js/scripts.js:39451
4468 #: rhodecode/public/js/rhodecode-components.js:52924
4469 #: rhodecode/public/js/scripts.js:39674
4359 4470 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:51
4360 4471 #: rhodecode/public/js/src/rhodecode/files.js:296
4361 4472 msgid "Selection link"
4362 4473 msgstr ""
4363 4474
4364 #: rhodecode/public/js/rhodecode-components.js:47643
4365 #: rhodecode/public/js/scripts.js:39491
4475 #: rhodecode/public/js/rhodecode-components.js:52964
4476 #: rhodecode/public/js/scripts.js:39714
4366 4477 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:62
4367 4478 #: rhodecode/public/js/src/rhodecode/followers.js:26
4368 4479 msgid "Stop following this repository"
4369 4480 msgstr ""
4370 4481
4371 #: rhodecode/public/js/rhodecode-components.js:47644
4372 #: rhodecode/public/js/scripts.js:39492
4482 #: rhodecode/public/js/rhodecode-components.js:52965
4483 #: rhodecode/public/js/scripts.js:39715
4373 4484 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:69
4374 4485 #: rhodecode/public/js/src/rhodecode/followers.js:27
4375 4486 msgid "Unfollow"
4376 4487 msgstr ""
4377 4488
4378 #: rhodecode/public/js/rhodecode-components.js:47653
4379 #: rhodecode/public/js/scripts.js:39501
4489 #: rhodecode/public/js/rhodecode-components.js:52974
4490 #: rhodecode/public/js/scripts.js:39724
4380 4491 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:60
4381 4492 #: rhodecode/public/js/src/rhodecode/followers.js:36
4382 4493 msgid "Start following this repository"
4383 4494 msgstr ""
4384 4495
4385 #: rhodecode/public/js/rhodecode-components.js:47654
4386 #: rhodecode/public/js/scripts.js:39502
4496 #: rhodecode/public/js/rhodecode-components.js:52975
4497 #: rhodecode/public/js/scripts.js:39725
4387 4498 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:17
4388 4499 #: rhodecode/public/js/src/rhodecode/followers.js:37
4389 4500 msgid "Follow"
4390 4501 msgstr ""
4391 4502
4392 #: rhodecode/public/js/rhodecode-components.js:48034
4393 #: rhodecode/public/js/scripts.js:39882
4503 #: rhodecode/public/js/rhodecode-components.js:53356
4504 #: rhodecode/public/js/scripts.js:40106
4394 4505 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:6
4395 4506 #: rhodecode/public/js/src/rhodecode/pullrequests.js:134
4396 4507 msgid "All reviewers must vote."
4397 4508 msgstr ""
4398 4509
4399 #: rhodecode/public/js/rhodecode-components.js:48043
4400 #: rhodecode/public/js/scripts.js:39891
4510 #: rhodecode/public/js/rhodecode-components.js:53365
4511 #: rhodecode/public/js/scripts.js:40115
4401 4512 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:5
4402 4513 #: rhodecode/public/js/src/rhodecode/pullrequests.js:143
4403 4514 msgid "All individual reviewers must vote."
4404 4515 msgstr ""
4405 4516
4406 #: rhodecode/public/js/rhodecode-components.js:48048
4407 #: rhodecode/public/js/scripts.js:39896
4517 #: rhodecode/public/js/rhodecode-components.js:53370
4518 #: rhodecode/public/js/scripts.js:40120
4408 4519 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:7
4409 4520 #: rhodecode/public/js/src/rhodecode/pullrequests.js:148
4410 4521 msgid "At least {0} reviewer must vote."
4411 4522 msgstr ""
4412 4523
4413 #: rhodecode/public/js/rhodecode-components.js:48054
4414 #: rhodecode/public/js/scripts.js:39902
4524 #: rhodecode/public/js/rhodecode-components.js:53376
4525 #: rhodecode/public/js/scripts.js:40126
4415 4526 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:8
4416 4527 #: rhodecode/public/js/src/rhodecode/pullrequests.js:154
4417 4528 msgid "At least {0} reviewers must vote."
4418 4529 msgstr ""
4419 4530
4420 #: rhodecode/public/js/rhodecode-components.js:48070
4421 #: rhodecode/public/js/scripts.js:39918
4531 #: rhodecode/public/js/rhodecode-components.js:53392
4532 #: rhodecode/public/js/scripts.js:40142
4422 4533 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:48
4423 4534 #: rhodecode/public/js/src/rhodecode/pullrequests.js:170
4424 4535 msgid "Reviewers picked from source code changes."
4425 4536 msgstr ""
4426 4537
4427 #: rhodecode/public/js/rhodecode-components.js:48077
4428 #: rhodecode/public/js/scripts.js:39925
4538 #: rhodecode/public/js/rhodecode-components.js:53399
4539 #: rhodecode/public/js/scripts.js:40149
4429 4540 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:4
4430 4541 #: rhodecode/public/js/src/rhodecode/pullrequests.js:177
4431 4542 msgid "Adding new reviewers is forbidden."
4432 4543 msgstr ""
4433 4544
4434 #: rhodecode/public/js/rhodecode-components.js:48084
4435 #: rhodecode/public/js/scripts.js:39932
4545 #: rhodecode/public/js/rhodecode-components.js:53406
4546 #: rhodecode/public/js/scripts.js:40156
4436 4547 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:9
4437 4548 #: rhodecode/public/js/src/rhodecode/pullrequests.js:184
4438 4549 msgid "Author is not allowed to be a reviewer."
4439 4550 msgstr ""
4440 4551
4441 #: rhodecode/public/js/rhodecode-components.js:48098
4442 #: rhodecode/public/js/scripts.js:39946
4552 #: rhodecode/public/js/rhodecode-components.js:53420
4553 #: rhodecode/public/js/scripts.js:40170
4443 4554 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:12
4444 4555 #: rhodecode/public/js/src/rhodecode/pullrequests.js:198
4445 4556 msgid "Commit Authors are not allowed to be a reviewer."
4446 4557 msgstr ""
4447 4558
4448 #: rhodecode/public/js/rhodecode-components.js:48206
4449 #: rhodecode/public/js/scripts.js:40054
4559 #: rhodecode/public/js/rhodecode-components.js:53528
4560 #: rhodecode/public/js/scripts.js:40278
4450 4561 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:72
4451 4562 #: rhodecode/public/js/src/rhodecode/pullrequests.js:306
4452 4563 msgid "User `{0}` not allowed to be a reviewer"
4453 4564 msgstr ""
4454 4565
4455 #: rhodecode/public/js/rhodecode-components.js:48212
4456 #: rhodecode/public/js/scripts.js:40060
4566 #: rhodecode/public/js/rhodecode-components.js:53534
4567 #: rhodecode/public/js/scripts.js:40284
4457 4568 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:71
4458 4569 #: rhodecode/public/js/src/rhodecode/pullrequests.js:312
4459 4570 msgid "User `{0}` already in reviewers"
4460 4571 msgstr ""
4461 4572
4462 #: rhodecode/public/js/rhodecode-components.js:48342
4463 #: rhodecode/public/js/scripts.js:40190
4573 #: rhodecode/public/js/rhodecode-components.js:53622
4574 #: rhodecode/public/js/scripts.js:40372
4464 4575 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:75
4465 #: rhodecode/public/js/src/rhodecode/pullrequests.js:442
4576 #: rhodecode/public/js/src/rhodecode/pullrequests.js:400
4466 4577 msgid "added manually by \"{0}\""
4467 4578 msgstr ""
4468 4579
4469 #: rhodecode/public/js/rhodecode-components.js:48346
4470 #: rhodecode/public/js/scripts.js:40194
4580 #: rhodecode/public/js/rhodecode-components.js:53626
4581 #: rhodecode/public/js/scripts.js:40376
4471 4582 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:86
4472 #: rhodecode/public/js/src/rhodecode/pullrequests.js:446
4583 #: rhodecode/public/js/src/rhodecode/pullrequests.js:404
4473 4584 msgid "member of \"{0}\""
4474 4585 msgstr ""
4475 4586
4476 #: rhodecode/public/js/rhodecode-components.js:48932
4477 #: rhodecode/public/js/scripts.js:40780
4587 #: rhodecode/public/js/rhodecode-components.js:54212
4588 #: rhodecode/public/js/scripts.js:40962
4478 4589 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:79
4479 4590 #: rhodecode/public/js/src/rhodecode.js:142
4480 4591 msgid "file"
4481 4592 msgstr ""
4482 4593
4483 #: rhodecode/public/js/rhodecode-components.js:48952
4484 #: rhodecode/public/js/scripts.js:40800
4594 #: rhodecode/public/js/rhodecode-components.js:54232
4595 #: rhodecode/public/js/scripts.js:40982
4485 4596 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:56
4486 4597 #: rhodecode/public/js/src/rhodecode.js:162
4598 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:33
4487 4599 msgid "Show more"
4488 4600 msgstr ""
4489 4601
4490 #: rhodecode/public/js/rhodecode-components.js:49328
4491 #: rhodecode/public/js/scripts.js:41176
4602 #: rhodecode/public/js/rhodecode-components.js:54608
4603 #: rhodecode/public/js/scripts.js:41358
4492 4604 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:76
4493 4605 #: rhodecode/public/js/src/rhodecode.js:538
4494 4606 msgid "date not in future"
4495 4607 msgstr ""
4496 4608
4497 #: rhodecode/public/js/rhodecode-components.js:49336
4498 #: rhodecode/public/js/scripts.js:41184
4609 #: rhodecode/public/js/rhodecode-components.js:54616
4610 #: rhodecode/public/js/scripts.js:41366
4499 4611 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:59
4500 4612 #: rhodecode/public/js/src/rhodecode.js:546
4501 4613 msgid "Specified expiration date"
@@ -4506,14 +4618,14 b' msgid "(from usergroup {0})"'
4506 4618 msgstr ""
4507 4619
4508 4620 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:3
4509 #: rhodecode/templates/codeblocks/diffs.mako:497
4510 4621 #: rhodecode/templates/codeblocks/diffs.mako:502
4622 #: rhodecode/templates/codeblocks/diffs.mako:507
4511 4623 msgid "Add another comment"
4512 4624 msgstr ""
4513 4625
4514 4626 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:10
4515 4627 #: rhodecode/public/js/src/i18n_messages.js:5
4516 #: rhodecode/templates/pullrequests/pullrequest_show.mako:331
4628 #: rhodecode/templates/pullrequests/pullrequest_show.mako:333
4517 4629 msgid "Close"
4518 4630 msgstr ""
4519 4631
@@ -4593,7 +4705,7 b' msgstr ""'
4593 4705
4594 4706 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:52
4595 4707 #: rhodecode/public/js/src/i18n_messages.js:6
4596 #: rhodecode/templates/admin/settings/settings_email.mako:48
4708 #: rhodecode/templates/admin/settings/settings_email.mako:52
4597 4709 msgid "Send"
4598 4710 msgstr ""
4599 4711
@@ -4642,7 +4754,7 b' msgid "files"'
4642 4754 msgstr ""
4643 4755
4644 4756 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:85
4645 #: rhodecode/templates/pullrequests/pullrequest.mako:140
4757 #: rhodecode/templates/pullrequests/pullrequest.mako:141
4646 4758 msgid "loading..."
4647 4759 msgstr ""
4648 4760
@@ -4651,30 +4763,46 b' msgid "specify commit"'
4651 4763 msgstr ""
4652 4764
4653 4765 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:93
4766 msgid "{0} ({1} inactive) of {2} user groups ({3} inactive)"
4767 msgstr ""
4768
4769 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:94
4770 msgid "{0} ({1} inactive) of {2} users ({3} inactive)"
4771 msgstr ""
4772
4773 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:95
4654 4774 msgid "{0} active out of {1} users"
4655 4775 msgstr ""
4656 4776
4657 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:98
4658 msgid "{0} days"
4659 msgstr ""
4660
4661 4777 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:100
4778 msgid "{0} days"
4779 msgstr ""
4780
4781 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:102
4662 4782 msgid "{0} hours"
4663 4783 msgstr ""
4664 4784
4665 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:103
4666 msgid "{0} months"
4667 msgstr ""
4668
4669 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:104
4670 msgid "{0} out of {1} ssh keys"
4671 msgstr ""
4672
4673 4785 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:105
4786 msgid "{0} months"
4787 msgstr ""
4788
4789 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:106
4790 msgid "{0} out of {1} ssh keys"
4791 msgstr ""
4792
4793 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:107
4674 4794 msgid "{0} out of {1} users"
4675 4795 msgstr ""
4676 4796
4677 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:109
4797 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:110
4798 msgid "{0} user groups ({1} inactive)"
4799 msgstr ""
4800
4801 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:111
4802 msgid "{0} users ({1} inactive)"
4803 msgstr ""
4804
4805 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:113
4678 4806 msgid "{0} years"
4679 4807 msgstr ""
4680 4808
@@ -4706,54 +4834,38 b' msgstr ""'
4706 4834 msgid "Dashboard"
4707 4835 msgstr ""
4708 4836
4709 #: rhodecode/templates/index_base.mako:8
4710 #: rhodecode/templates/admin/gists/index.mako:18
4711 #: rhodecode/templates/admin/my_account/my_account_repos.mako:7
4712 #: rhodecode/templates/admin/my_account/my_account_watched.mako:7
4713 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:11
4714 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:12
4715 #: rhodecode/templates/admin/repos/repos.mako:12
4716 #: rhodecode/templates/admin/user_groups/user_groups.mako:12
4717 #: rhodecode/templates/admin/users/users.mako:12
4718 #: rhodecode/templates/bookmarks/bookmarks.mako:12
4719 #: rhodecode/templates/branches/branches.mako:12
4720 #: rhodecode/templates/journal/journal.mako:13
4721 #: rhodecode/templates/tags/tags.mako:12
4722 msgid "quick filter..."
4723 msgstr ""
4724
4725 #: rhodecode/templates/index_base.mako:10
4837 #: rhodecode/templates/index_base.mako:9
4726 4838 msgid "matches"
4727 4839 msgstr ""
4728 4840
4729 #: rhodecode/templates/index_base.mako:30
4730 #: rhodecode/templates/index_base.mako:39
4841 #: rhodecode/templates/index_base.mako:29
4842 #: rhodecode/templates/index_base.mako:38
4731 4843 #: rhodecode/templates/admin/repos/repo_add.mako:22
4732 4844 #: rhodecode/templates/admin/repos/repos.mako:27
4733 4845 msgid "Add Repository"
4734 4846 msgstr ""
4735 4847
4736 #: rhodecode/templates/index_base.mako:34
4737 #: rhodecode/templates/index_base.mako:42
4848 #: rhodecode/templates/index_base.mako:33
4849 #: rhodecode/templates/index_base.mako:41
4738 4850 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:16
4739 4851 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:27
4740 4852 msgid "Add Repository Group"
4741 4853 msgstr ""
4742 4854
4743 #: rhodecode/templates/index_base.mako:45
4855 #: rhodecode/templates/index_base.mako:44
4744 4856 msgid "You have admin right to this group, and can edit it"
4745 4857 msgstr ""
4746 4858
4747 #: rhodecode/templates/index_base.mako:45
4859 #: rhodecode/templates/index_base.mako:44
4748 4860 msgid "Edit Repository Group"
4749 4861 msgstr ""
4750 4862
4751 #: rhodecode/templates/index_base.mako:68
4863 #: rhodecode/templates/index_base.mako:67
4752 4864 msgid "No repositories or repositories groups exists here."
4753 4865 msgstr ""
4754 4866
4755 #: rhodecode/templates/index_base.mako:86
4756 #: rhodecode/templates/index_base.mako:116
4867 #: rhodecode/templates/index_base.mako:85
4868 #: rhodecode/templates/index_base.mako:115
4757 4869 #: rhodecode/templates/admin/gists/index.mako:112
4758 4870 #: rhodecode/templates/admin/integrations/list.mako:72
4759 4871 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:55
@@ -4764,9 +4876,10 b' msgstr ""'
4764 4876 #: rhodecode/templates/admin/repos/repo_add_base.mako:9
4765 4877 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:16
4766 4878 #: rhodecode/templates/admin/repos/repos.mako:54
4767 #: rhodecode/templates/admin/user_groups/user_groups.mako:61
4879 #: rhodecode/templates/admin/user_groups/user_groups.mako:73
4768 4880 #: rhodecode/templates/admin/users/user_edit_groups.mako:54
4769 #: rhodecode/templates/base/perms_summary.mako:149
4881 #: rhodecode/templates/base/perms_summary.mako:168
4882 #: rhodecode/templates/base/perms_summary.mako:242
4770 4883 #: rhodecode/templates/bookmarks/bookmarks.mako:59
4771 4884 #: rhodecode/templates/branches/branches.mako:58
4772 4885 #: rhodecode/templates/files/files_browser_tree.mako:5
@@ -4775,31 +4888,31 b' msgstr ""'
4775 4888 msgid "Name"
4776 4889 msgstr ""
4777 4890
4778 #: rhodecode/templates/index_base.mako:89
4779 #: rhodecode/templates/index_base.mako:119
4891 #: rhodecode/templates/index_base.mako:88
4892 #: rhodecode/templates/index_base.mako:118
4780 4893 #: rhodecode/templates/admin/gists/index.mako:114
4781 4894 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:15
4782 4895 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:71
4783 4896 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:10
4784 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:55
4897 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:57
4785 4898 #: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:44
4786 4899 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:49
4787 4900 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:45
4788 4901 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:55
4789 4902 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:56
4790 #: rhodecode/templates/admin/repos/repo_add_base.mako:43
4903 #: rhodecode/templates/admin/repos/repo_add_base.mako:52
4791 4904 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:29
4792 4905 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:170
4793 4906 #: rhodecode/templates/admin/repos/repos.mako:57
4794 4907 #: rhodecode/templates/admin/user_groups/user_group_add.mako:43
4795 4908 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:42
4796 #: rhodecode/templates/admin/user_groups/user_groups.mako:63
4909 #: rhodecode/templates/admin/user_groups/user_groups.mako:75
4797 4910 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:15
4798 4911 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:67
4799 4912 #: rhodecode/templates/admin/users/user_edit_groups.mako:59
4800 4913 #: rhodecode/templates/admin/users/user_edit_ips.mako:12
4801 4914 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:10
4802 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:50
4915 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:52
4803 4916 #: rhodecode/templates/base/issue_tracker_settings.mako:10
4804 4917 #: rhodecode/templates/changeset/changeset.mako:76
4805 4918 #: rhodecode/templates/compare/compare_commits.mako:21
@@ -4809,23 +4922,23 b' msgstr ""'
4809 4922 #: rhodecode/templates/files/file_tree_detail.mako:5
4810 4923 #: rhodecode/templates/files/file_tree_detail.mako:12
4811 4924 #: rhodecode/templates/forks/fork.mako:48
4812 #: rhodecode/templates/forks/forks.mako:72
4813 #: rhodecode/templates/pullrequests/pullrequest.mako:54
4814 #: rhodecode/templates/pullrequests/pullrequest_show.mako:169
4815 #: rhodecode/templates/pullrequests/pullrequest_show.mako:481
4925 #: rhodecode/templates/forks/forks.mako:64
4926 #: rhodecode/templates/pullrequests/pullrequest.mako:55
4927 #: rhodecode/templates/pullrequests/pullrequest_show.mako:170
4928 #: rhodecode/templates/pullrequests/pullrequest_show.mako:484
4816 4929 #: rhodecode/templates/summary/components.mako:88
4817 4930 msgid "Description"
4818 4931 msgstr ""
4819 4932
4820 #: rhodecode/templates/index_base.mako:92
4821 #: rhodecode/templates/index_base.mako:122
4933 #: rhodecode/templates/index_base.mako:91
4934 #: rhodecode/templates/index_base.mako:121
4822 4935 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:59
4823 4936 #: rhodecode/templates/admin/repos/repos.mako:60
4824 4937 msgid "Last Change"
4825 4938 msgstr ""
4826 4939
4827 #: rhodecode/templates/index_base.mako:94
4828 #: rhodecode/templates/index_base.mako:127
4940 #: rhodecode/templates/index_base.mako:93
4941 #: rhodecode/templates/index_base.mako:126
4829 4942 #: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:50
4830 4943 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:5
4831 4944 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:37
@@ -4835,15 +4948,15 b' msgstr ""'
4835 4948 #: rhodecode/templates/admin/repos/repos.mako:65
4836 4949 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:5
4837 4950 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:24
4838 #: rhodecode/templates/admin/user_groups/user_groups.mako:71
4951 #: rhodecode/templates/admin/user_groups/user_groups.mako:83
4839 4952 #: rhodecode/templates/admin/users/user_edit_groups.mako:65
4840 #: rhodecode/templates/forks/forks.mako:68
4953 #: rhodecode/templates/forks/forks.mako:60
4841 4954 #: rhodecode/templates/summary/components.mako:209
4842 4955 #: rhodecode/templates/user_group/profile.mako:23
4843 4956 msgid "Owner"
4844 4957 msgstr ""
4845 4958
4846 #: rhodecode/templates/index_base.mako:125
4959 #: rhodecode/templates/index_base.mako:124
4847 4960 #: rhodecode/templates/admin/my_account/my_account_repos.mako:35
4848 4961 #: rhodecode/templates/admin/my_account/my_account_watched.mako:35
4849 4962 #: rhodecode/templates/admin/repos/repos.mako:63
@@ -4855,7 +4968,7 b' msgstr ""'
4855 4968 #: rhodecode/templates/email_templates/commit_comment.mako:49
4856 4969 #: rhodecode/templates/email_templates/commit_comment.mako:88
4857 4970 #: rhodecode/templates/files/file_authors_box.mako:31
4858 #: rhodecode/templates/pullrequests/pullrequest_show.mako:479
4971 #: rhodecode/templates/pullrequests/pullrequest_show.mako:482
4859 4972 #: rhodecode/templates/search/search_commit.mako:6
4860 4973 #: rhodecode/templates/summary/summary_commits.mako:8
4861 4974 #: rhodecode/templates/tags/tags.mako:66
@@ -4895,7 +5008,6 b' msgstr ""'
4895 5008
4896 5009 #: rhodecode/templates/login.mako:68 rhodecode/templates/password_reset.mako:37
4897 5010 #: rhodecode/templates/base/base.mako:48
4898 #: rhodecode/templates/errors/error_document.mako:63
4899 5011 msgid "Support"
4900 5012 msgstr ""
4901 5013
@@ -4925,58 +5037,62 b' msgstr ""'
4925 5037 msgid "Email Address"
4926 5038 msgstr ""
4927 5039
4928 #: rhodecode/templates/password_reset.mako:61
4929 #: rhodecode/templates/register.mako:85
5040 #: rhodecode/templates/password_reset.mako:58
5041 msgid "Password reset link will be sent to matching email address"
5042 msgstr ""
5043
5044 #: rhodecode/templates/password_reset.mako:62
5045 #: rhodecode/templates/register.mako:100
4930 5046 msgid "Captcha"
4931 5047 msgstr ""
4932 5048
4933 #: rhodecode/templates/password_reset.mako:71
5049 #: rhodecode/templates/password_reset.mako:73
4934 5050 msgid "Send password reset email"
4935 5051 msgstr ""
4936 5052
4937 #: rhodecode/templates/password_reset.mako:72
4938 msgid "Password reset link will be sent to matching email address"
4939 msgstr ""
4940
4941 5053 #: rhodecode/templates/register.mako:5
4942 5054 msgid "Create an Account"
4943 5055 msgstr ""
4944 5056
4945 #: rhodecode/templates/register.mako:35
5057 #: rhodecode/templates/register.mako:36
5058 msgid "Create an account linked with {}"
5059 msgstr ""
5060
5061 #: rhodecode/templates/register.mako:38
4946 5062 msgid "Create an account"
4947 5063 msgstr ""
4948 5064
4949 #: rhodecode/templates/register.mako:36
5065 #: rhodecode/templates/register.mako:41
4950 5066 msgid "Go to the login page to sign in with an existing account."
4951 5067 msgstr ""
4952 5068
4953 #: rhodecode/templates/register.mako:55
5069 #: rhodecode/templates/register.mako:65
4954 5070 msgid "Re-enter password"
4955 5071 msgstr ""
4956 5072
4957 #: rhodecode/templates/register.mako:62
5073 #: rhodecode/templates/register.mako:77
4958 5074 #: rhodecode/templates/admin/my_account/my_account_profile.mako:32
4959 5075 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:32
4960 5076 #: rhodecode/templates/admin/users/user_add.mako:68
4961 5077 #: rhodecode/templates/admin/users/user_edit_profile.mako:47
4962 #: rhodecode/templates/admin/users/users.mako:67
5078 #: rhodecode/templates/admin/users/users.mako:75
4963 5079 msgid "First Name"
4964 5080 msgstr ""
4965 5081
4966 #: rhodecode/templates/register.mako:69
5082 #: rhodecode/templates/register.mako:84
4967 5083 #: rhodecode/templates/admin/my_account/my_account_profile.mako:40
4968 5084 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:41
4969 5085 #: rhodecode/templates/admin/users/user_add.mako:77
4970 5086 #: rhodecode/templates/admin/users/user_edit_profile.mako:56
4971 #: rhodecode/templates/admin/users/users.mako:69
5087 #: rhodecode/templates/admin/users/users.mako:77
4972 5088 msgid "Last Name"
4973 5089 msgstr ""
4974 5090
4975 #: rhodecode/templates/register.mako:97
5091 #: rhodecode/templates/register.mako:112
4976 5092 msgid "Account activation requires admin approval."
4977 5093 msgstr ""
4978 5094
4979 #: rhodecode/templates/register.mako:104
5095 #: rhodecode/templates/register.mako:119
4980 5096 msgid "Create Account"
4981 5097 msgstr ""
4982 5098
@@ -5010,19 +5126,19 b' msgstr ""'
5010 5126 #: rhodecode/templates/admin/admin_log_base.mako:8
5011 5127 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:18
5012 5128 #: rhodecode/templates/admin/my_account/my_account_repos.mako:37
5013 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:12
5129 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:13
5014 5130 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:55
5015 5131 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:65
5016 5132 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:13
5017 5133 #: rhodecode/templates/admin/repos/repos.mako:69
5018 5134 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:71
5019 #: rhodecode/templates/admin/user_groups/user_groups.mako:73
5135 #: rhodecode/templates/admin/user_groups/user_groups.mako:85
5020 5136 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:18
5021 5137 #: rhodecode/templates/admin/users/user_edit_groups.mako:73
5022 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:12
5023 #: rhodecode/templates/admin/users/users.mako:80
5138 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:13
5139 #: rhodecode/templates/admin/users/users.mako:88
5024 5140 #: rhodecode/templates/files/files_detail.mako:58
5025 #: rhodecode/templates/forks/forks.mako:79
5141 #: rhodecode/templates/forks/forks.mako:71
5026 5142 msgid "Action"
5027 5143 msgstr ""
5028 5144
@@ -5039,7 +5155,7 b' msgstr ""'
5039 5155 #: rhodecode/templates/admin/admin_audit_log_entry.mako:92
5040 5156 #: rhodecode/templates/admin/admin_log_base.mako:10
5041 5157 #: rhodecode/templates/admin/defaults/defaults.mako:31
5042 #: rhodecode/templates/admin/permissions/permissions_objects.mako:13
5158 #: rhodecode/templates/admin/permissions/permissions_objects.mako:16
5043 5159 #: rhodecode/templates/search/search_commit.mako:5
5044 5160 #: rhodecode/templates/search/search_path.mako:3
5045 5161 msgid "Repository"
@@ -5057,19 +5173,20 b' msgstr ""'
5057 5173 #: rhodecode/templates/admin/admin_audit_logs.mako:14
5058 5174 #: rhodecode/templates/admin/repos/repo_edit_audit.mako:15
5059 5175 #: rhodecode/templates/admin/users/user_edit_audit.mako:15
5176 #: rhodecode/templates/journal/journal.mako:13
5060 5177 msgid "filter"
5061 5178 msgstr ""
5062 5179
5063 5180 #: rhodecode/templates/admin/admin_audit_logs.mako:15
5064 #: rhodecode/templates/admin/repos/repo_edit.mako:92
5181 #: rhodecode/templates/admin/repos/repo_edit.mako:95
5065 5182 #: rhodecode/templates/admin/users/user_edit.mako:47
5066 5183 msgid "Audit logs"
5067 5184 msgstr ""
5068 5185
5069 5186 #: rhodecode/templates/admin/admin_audit_logs.mako:17
5070 #: rhodecode/templates/admin/repos/repo_edit_audit.mako:17
5071 #: rhodecode/templates/admin/users/user_edit_audit.mako:17
5072 #: rhodecode/templates/journal/journal.mako:18
5187 #: rhodecode/templates/admin/repos/repo_edit_audit.mako:18
5188 #: rhodecode/templates/admin/users/user_edit_audit.mako:18
5189 #: rhodecode/templates/journal/journal.mako:16
5073 5190 #: rhodecode/templates/search/search.mako:76
5074 5191 msgid "Example Queries"
5075 5192 msgstr ""
@@ -5118,18 +5235,18 b' msgstr ""'
5118 5235 #: rhodecode/templates/admin/auth/plugin_settings.mako:87
5119 5236 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:63
5120 5237 #: rhodecode/templates/admin/permissions/permissions_application.mako:59
5121 #: rhodecode/templates/admin/permissions/permissions_objects.mako:56
5238 #: rhodecode/templates/admin/permissions/permissions_objects.mako:59
5122 5239 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:78
5123 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:133
5240 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:204
5124 5241 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:83
5125 5242 #: rhodecode/templates/admin/repos/repo_add_base.mako:106
5126 5243 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:79
5127 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:109
5244 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:186
5128 5245 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:243
5129 5246 #: rhodecode/templates/admin/settings/settings_hooks.mako:63
5130 5247 #: rhodecode/templates/admin/settings/settings_issuetracker.mako:15
5131 5248 #: rhodecode/templates/admin/user_groups/user_group_add.mako:60
5132 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:120
5249 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:191
5133 5250 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:102
5134 5251 #: rhodecode/templates/admin/users/user_add.mako:128
5135 5252 #: rhodecode/templates/admin/users/user_edit_groups.mako:27
@@ -5154,7 +5271,7 b' msgstr ""'
5154 5271 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:14
5155 5272 #: rhodecode/templates/admin/gists/index.mako:110
5156 5273 #: rhodecode/templates/admin/integrations/list.mako:73
5157 #: rhodecode/templates/admin/repos/repo_add_base.mako:80
5274 #: rhodecode/templates/admin/repos/repo_add_base.mako:43
5158 5275 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:12
5159 5276 msgid "Type"
5160 5277 msgstr ""
@@ -5167,7 +5284,7 b' msgstr ""'
5167 5284 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:27
5168 5285 #: rhodecode/templates/admin/repos/repo_add_base.mako:102
5169 5286 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:192
5170 #: rhodecode/templates/forks/fork.mako:92
5287 #: rhodecode/templates/forks/fork.mako:102
5171 5288 msgid "Private repositories are only visible to people explicitly added as collaborators."
5172 5289 msgstr ""
5173 5290
@@ -5228,12 +5345,12 b' msgstr ""'
5228 5345
5229 5346 #: rhodecode/templates/admin/gists/edit.mako:102
5230 5347 #: rhodecode/templates/base/issue_tracker_settings.mako:73
5231 #: rhodecode/templates/changeset/changeset_file_comment.mako:391
5348 #: rhodecode/templates/changeset/changeset_file_comment.mako:392
5232 5349 #: rhodecode/templates/codeblocks/diffs.mako:72
5233 5350 #: rhodecode/templates/files/files_add.mako:108
5234 5351 #: rhodecode/templates/files/files_delete.mako:69
5235 5352 #: rhodecode/templates/files/files_edit.mako:108
5236 #: rhodecode/templates/pullrequests/pullrequest_show.mako:64
5353 #: rhodecode/templates/pullrequests/pullrequest_show.mako:65
5237 5354 msgid "Cancel"
5238 5355 msgstr ""
5239 5356
@@ -5258,6 +5375,21 b' msgstr ""'
5258 5375 msgid "Public Gists"
5259 5376 msgstr ""
5260 5377
5378 #: rhodecode/templates/admin/gists/index.mako:18
5379 #: rhodecode/templates/admin/my_account/my_account_repos.mako:7
5380 #: rhodecode/templates/admin/my_account/my_account_watched.mako:7
5381 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:11
5382 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:12
5383 #: rhodecode/templates/admin/repos/repos.mako:12
5384 #: rhodecode/templates/admin/user_groups/user_groups.mako:12
5385 #: rhodecode/templates/admin/users/users.mako:12
5386 #: rhodecode/templates/bookmarks/bookmarks.mako:12
5387 #: rhodecode/templates/branches/branches.mako:12
5388 #: rhodecode/templates/journal/journal.mako:12
5389 #: rhodecode/templates/tags/tags.mako:12
5390 msgid "quick filter..."
5391 msgstr ""
5392
5261 5393 #: rhodecode/templates/admin/gists/index.mako:24
5262 5394 #, python-format
5263 5395 msgid "All Gists for user %s"
@@ -5300,7 +5432,7 b' msgstr ""'
5300 5432 #: rhodecode/templates/changeset/changeset.mako:203
5301 5433 #: rhodecode/templates/compare/compare_commits.mako:18
5302 5434 #: rhodecode/templates/files/files_browser_tree.mako:9
5303 #: rhodecode/templates/pullrequests/pullrequest_show.mako:478
5435 #: rhodecode/templates/pullrequests/pullrequest_show.mako:481
5304 5436 #: rhodecode/templates/pullrequests/pullrequests.mako:112
5305 5437 #: rhodecode/templates/search/search_commit.mako:16
5306 5438 #: rhodecode/templates/summary/summary_commits.mako:11
@@ -5309,11 +5441,13 b' msgid "Author"'
5309 5441 msgstr ""
5310 5442
5311 5443 #: rhodecode/templates/admin/gists/index.mako:116
5444 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:11
5312 5445 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:51
5313 5446 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:6
5314 5447 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:6
5315 5448 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:6
5316 5449 #: rhodecode/templates/admin/users/user_edit_advanced.mako:5
5450 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:11
5317 5451 msgid "Created on"
5318 5452 msgstr ""
5319 5453
@@ -5389,9 +5523,9 b' msgstr ""'
5389 5523 #: rhodecode/templates/admin/integrations/form.mako:17
5390 5524 #: rhodecode/templates/admin/integrations/list.mako:10
5391 5525 #: rhodecode/templates/admin/integrations/new.mako:13
5392 #: rhodecode/templates/admin/permissions/permissions_objects.mako:28
5526 #: rhodecode/templates/admin/permissions/permissions_objects.mako:31
5393 5527 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:14
5394 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:125
5528 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:196
5395 5529 msgid "Repository Groups"
5396 5530 msgstr ""
5397 5531
@@ -5521,7 +5655,7 b' msgstr ""'
5521 5655
5522 5656 #: rhodecode/templates/admin/my_account/my_account.mako:32
5523 5657 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:3
5524 #: rhodecode/templates/admin/permissions/permissions.mako:48
5658 #: rhodecode/templates/admin/permissions/permissions.mako:51
5525 5659 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:4
5526 5660 #: rhodecode/templates/admin/users/user_edit.mako:40
5527 5661 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:3
@@ -5608,13 +5742,13 b' msgid "Repository scope works only with '
5608 5742 msgstr ""
5609 5743
5610 5744 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:86
5611 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:67
5745 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:69
5612 5746 #: rhodecode/templates/admin/permissions/permissions_ips.mako:63
5613 5747 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:65
5614 5748 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:82
5615 5749 #: rhodecode/templates/admin/users/user_edit_emails.mako:62
5616 5750 #: rhodecode/templates/admin/users/user_edit_ips.mako:70
5617 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:62
5751 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:64
5618 5752 msgid "Add"
5619 5753 msgstr ""
5620 5754
@@ -5646,15 +5780,27 b' msgstr ""'
5646 5780 msgid "No additional emails specified"
5647 5781 msgstr ""
5648 5782
5649 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:21
5783 #: rhodecode/templates/admin/my_account/my_account_emails.mako:51
5784 #: rhodecode/templates/admin/my_account/my_account_password.mako:6
5785 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:17
5786 msgid "Your user account details are managed by an external source. Details cannot be managed here."
5787 msgstr ""
5788
5789 #: rhodecode/templates/admin/my_account/my_account_emails.mako:52
5790 #: rhodecode/templates/admin/my_account/my_account_password.mako:7
5791 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:18
5792 msgid "Source type"
5793 msgstr ""
5794
5795 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:22
5650 5796 msgid "Your Live Notification Settings"
5651 5797 msgstr ""
5652 5798
5653 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:33
5799 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:34
5654 5800 msgid "Notifications Status"
5655 5801 msgstr ""
5656 5802
5657 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:46
5803 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:47
5658 5804 msgid "Test Notifications"
5659 5805 msgstr ""
5660 5806
@@ -5662,16 +5808,6 b' msgstr ""'
5662 5808 msgid "Change Your Account Password"
5663 5809 msgstr ""
5664 5810
5665 #: rhodecode/templates/admin/my_account/my_account_password.mako:6
5666 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:17
5667 msgid "Your user account details are managed by an external source. Details cannot be managed here."
5668 msgstr ""
5669
5670 #: rhodecode/templates/admin/my_account/my_account_password.mako:7
5671 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:18
5672 msgid "Source type"
5673 msgstr ""
5674
5675 5811 #: rhodecode/templates/admin/my_account/my_account_profile.mako:4
5676 5812 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:4
5677 5813 msgid "My Profile"
@@ -5717,7 +5853,7 b' msgstr ""'
5717 5853 #: rhodecode/templates/admin/settings/settings_global.mako:9
5718 5854 #: rhodecode/templates/email_templates/pull_request_review.mako:39
5719 5855 #: rhodecode/templates/email_templates/pull_request_review.mako:72
5720 #: rhodecode/templates/pullrequests/pullrequest.mako:45
5856 #: rhodecode/templates/pullrequests/pullrequest.mako:46
5721 5857 #: rhodecode/templates/pullrequests/pullrequests.mako:114
5722 5858 msgid "Title"
5723 5859 msgstr ""
@@ -5737,44 +5873,44 b' msgstr ""'
5737 5873 msgid "Fingerprint"
5738 5874 msgstr ""
5739 5875
5740 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:11
5741 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:11
5742 #: rhodecode/templates/data_table/_dt_elements.mako:183
5743 msgid "Created"
5744 msgstr ""
5745
5746 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:15
5876 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:12
5877 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:53
5878 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:12
5879 msgid "Accessed on"
5880 msgstr ""
5881
5882 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:16
5747 5883 msgid "SSH Keys usage is currently disabled, please ask your administrator to enable them."
5748 5884 msgstr ""
5749 5885
5750 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:30
5751 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:27
5886 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:32
5887 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:29
5752 5888 #, python-format
5753 5889 msgid "Confirm to remove ssh key %s"
5754 5890 msgstr ""
5755 5891
5756 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:38
5757 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:35
5892 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:40
5893 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:37
5758 5894 msgid "No additional ssh keys specified"
5759 5895 msgstr ""
5760 5896
5761 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:52
5762 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:47
5897 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:54
5898 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:49
5763 5899 msgid "New ssh key"
5764 5900 msgstr ""
5765 5901
5766 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:56
5767 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:51
5902 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:58
5903 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:53
5768 5904 msgid "Generate random RSA key"
5769 5905 msgstr ""
5770 5906
5771 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:62
5772 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:57
5907 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:64
5908 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:59
5773 5909 msgid "Public key, begins with 'ssh-rsa', 'ssh-dss', 'ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', or 'ecdsa-sha2-nistp521'"
5774 5910 msgstr ""
5775 5911
5776 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:71
5777 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:66
5912 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:73
5913 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:68
5778 5914 msgid "Click add to use this generate SSH key"
5779 5915 msgstr ""
5780 5916
@@ -5782,11 +5918,11 b' msgstr ""'
5782 5918 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:41
5783 5919 #: rhodecode/templates/admin/user_groups/user_group_add.mako:52
5784 5920 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:51
5785 #: rhodecode/templates/admin/user_groups/user_groups.mako:69
5921 #: rhodecode/templates/admin/user_groups/user_groups.mako:81
5786 5922 #: rhodecode/templates/admin/users/user_add.mako:97
5787 5923 #: rhodecode/templates/admin/users/user_edit_groups.mako:64
5788 5924 #: rhodecode/templates/admin/users/user_edit_profile.mako:90
5789 #: rhodecode/templates/admin/users/users.mako:74
5925 #: rhodecode/templates/admin/users/users.mako:82
5790 5926 #: rhodecode/templates/user_group/profile.mako:33
5791 5927 msgid "Active"
5792 5928 msgstr ""
@@ -5852,15 +5988,15 b' msgstr ""'
5852 5988 msgid "Object"
5853 5989 msgstr ""
5854 5990
5855 #: rhodecode/templates/admin/permissions/permissions.mako:42
5991 #: rhodecode/templates/admin/permissions/permissions.mako:45
5856 5992 msgid "IP Whitelist"
5857 5993 msgstr ""
5858 5994
5859 #: rhodecode/templates/admin/permissions/permissions.mako:45
5995 #: rhodecode/templates/admin/permissions/permissions.mako:48
5860 5996 msgid "AuthToken Access"
5861 5997 msgstr ""
5862 5998
5863 #: rhodecode/templates/admin/permissions/permissions.mako:51
5999 #: rhodecode/templates/admin/permissions/permissions.mako:54
5864 6000 msgid "Overview"
5865 6001 msgstr ""
5866 6002
@@ -5905,6 +6041,19 b' msgstr ""'
5905 6041 msgid "List of views available for usage in whitelist access"
5906 6042 msgstr ""
5907 6043
6044 #: rhodecode/templates/admin/permissions/permissions_branch.mako:3
6045 msgid "Default Permissions for Branches."
6046 msgstr ""
6047
6048 #: rhodecode/templates/admin/permissions/permissions_branch.mako:6
6049 #: rhodecode/templates/admin/repos/repo_edit_automation.mako:6
6050 #: rhodecode/templates/admin/repos/repo_edit_permissions_branch.mako:6
6051 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:62
6052 #: rhodecode/templates/admin/repos/repo_edit_reviewers.mako:6
6053 #: rhodecode/templates/admin/settings/settings_automation.mako:6
6054 msgid "This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license."
6055 msgstr ""
6056
5908 6057 #: rhodecode/templates/admin/permissions/permissions_ips.mako:5
5909 6058 msgid "Default IP Whitelist For All Users"
5910 6059 msgstr ""
@@ -5946,31 +6095,35 b' msgstr ""'
5946 6095 msgid "Default Permissions for Repositories, User Groups and Repository Groups."
5947 6096 msgstr ""
5948 6097
5949 #: rhodecode/templates/admin/permissions/permissions_objects.mako:6
5950 msgid "Default system permissions. Each permissions management entity will be created with the following default settings. Check the overwrite checkbox to force any permission changes on already existing settings."
5951 msgstr ""
5952
5953 #: rhodecode/templates/admin/permissions/permissions_objects.mako:20
6098 #: rhodecode/templates/admin/permissions/permissions_objects.mako:7
6099 msgid "Default access permissions. This defines permissions for the `default` user from which other users inherit permissions."
6100 msgstr ""
6101
6102 #: rhodecode/templates/admin/permissions/permissions_objects.mako:9
6103 msgid "Check the overwrite checkbox to force change all previously defined permissions for `default` user to the new selected value."
6104 msgstr ""
6105
6106 #: rhodecode/templates/admin/permissions/permissions_objects.mako:23
5954 6107 msgid "All default permissions on each repository will be reset to chosen permission, note that all custom default permission on repositories will be lost"
5955 6108 msgstr ""
5956 6109
5957 #: rhodecode/templates/admin/permissions/permissions_objects.mako:21
5958 #: rhodecode/templates/admin/permissions/permissions_objects.mako:35
5959 #: rhodecode/templates/admin/permissions/permissions_objects.mako:49
6110 #: rhodecode/templates/admin/permissions/permissions_objects.mako:24
6111 #: rhodecode/templates/admin/permissions/permissions_objects.mako:38
6112 #: rhodecode/templates/admin/permissions/permissions_objects.mako:52
5960 6113 msgid "Overwrite Existing Settings"
5961 6114 msgstr ""
5962 6115
5963 #: rhodecode/templates/admin/permissions/permissions_objects.mako:34
6116 #: rhodecode/templates/admin/permissions/permissions_objects.mako:37
5964 6117 msgid "All default permissions on each repository group will be reset to chosen permission, note that all custom default permission on repository groups will be lost"
5965 6118 msgstr ""
5966 6119
5967 #: rhodecode/templates/admin/permissions/permissions_objects.mako:42
6120 #: rhodecode/templates/admin/permissions/permissions_objects.mako:45
5968 6121 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:14
5969 6122 msgid "User Groups"
5970 6123 msgstr ""
5971 6124
5972 #: rhodecode/templates/admin/permissions/permissions_objects.mako:48
5973 msgid "All default permissions on each user group will be reset to chosen permission, note that all custom default permission on repository groups will be lost"
6125 #: rhodecode/templates/admin/permissions/permissions_objects.mako:51
6126 msgid "All default permissions on each user group will be reset to chosen permission, note that all custom default permission on user groups will be lost"
5974 6127 msgstr ""
5975 6128
5976 6129 #: rhodecode/templates/admin/permissions/permissions_perms.mako:1
@@ -5981,10 +6134,6 b' msgstr ""'
5981 6134 msgid "Update SSH keys file"
5982 6135 msgstr ""
5983 6136
5984 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:53
5985 msgid "Accessed on"
5986 msgstr ""
5987
5988 6137 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:5
5989 6138 msgid "Add repository group"
5990 6139 msgstr ""
@@ -6011,7 +6160,7 b' msgid "Group Parent"'
6011 6160 msgstr ""
6012 6161
6013 6162 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:69
6014 #: rhodecode/templates/admin/repos/repo_add_base.mako:71
6163 #: rhodecode/templates/admin/repos/repo_add_base.mako:89
6015 6164 msgid "Copy Parent Group Permissions"
6016 6165 msgstr ""
6017 6166
@@ -6029,7 +6178,7 b' msgid "Add Child Group"'
6029 6178 msgstr ""
6030 6179
6031 6180 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:50
6032 #: rhodecode/templates/admin/repos/repo_edit.mako:52
6181 #: rhodecode/templates/admin/repos/repo_edit.mako:55
6033 6182 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:35
6034 6183 #: rhodecode/templates/admin/users/user_edit.mako:41
6035 6184 msgid "Advanced"
@@ -6079,54 +6228,64 b' msgstr ""'
6079 6228 msgid "User/User Group"
6080 6229 msgstr ""
6081 6230
6082 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:30
6083 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:30
6084 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:31
6231 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:32
6232 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:31
6233 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:33
6085 6234 msgid "super admin"
6086 6235 msgstr ""
6087 6236
6088 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:33
6089 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:33
6090 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:34
6237 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:35
6238 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:34
6239 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:36
6091 6240 msgid "owner"
6092 6241 msgstr ""
6093 6242
6094 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:50
6095 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:74
6096 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:60
6097 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:52
6098 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:76
6099 msgid "permission for all other users"
6100 msgstr ""
6101
6102 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:60
6243 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:64
6103 6244 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:107
6104 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:70
6105 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:98
6106 msgid "Revoke"
6107 msgstr ""
6108
6109 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:78
6110 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:80
6111 msgid "delegated admin"
6112 msgstr ""
6113
6114 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:116
6245 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:86
6246 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:66
6247 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:109
6248 msgid "permission for all other users"
6249 msgstr ""
6250
6251 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:68
6252 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:111
6253 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:90
6254 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:70
6255 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:113
6256 msgid "inactive duplicate"
6257 msgstr ""
6258
6259 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:77
6260 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:155
6115 6261 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:106
6116 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:117
6117 #: rhodecode/templates/base/issue_tracker_settings.mako:83
6118 msgid "Add new"
6119 msgstr ""
6120
6121 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:121
6262 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:150
6263 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:46
6264 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:79
6265 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:157
6266 msgid "Remove"
6267 msgstr ""
6268
6269 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:114
6270 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:116
6271 msgid "delegated admin"
6272 msgstr ""
6273
6274 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:182
6275 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:177
6276 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:183
6277 msgid "Add user/user group"
6278 msgstr ""
6279
6280 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:192
6122 6281 msgid "Apply to children"
6123 6282 msgstr ""
6124 6283
6125 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:127
6284 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:198
6126 6285 msgid "Both"
6127 6286 msgstr ""
6128 6287
6129 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:128
6288 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:199
6130 6289 msgid "Set or revoke permissions to selected types of children of this group, including non-private repositories and other groups if chosen."
6131 6290 msgstr ""
6132 6291
@@ -6180,43 +6339,43 b' msgstr ""'
6180 6339 msgid "Clone from"
6181 6340 msgstr ""
6182 6341
6183 #: rhodecode/templates/admin/repos/repo_add_base.mako:48
6184 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:177
6185 #: rhodecode/templates/forks/fork.mako:53
6186 msgid "Plain text format with support of {metatags}. Add a README file for longer descriptions"
6342 #: rhodecode/templates/admin/repos/repo_add_base.mako:47
6343 msgid "Set the type of repository to create."
6187 6344 msgstr ""
6188 6345
6189 6346 #: rhodecode/templates/admin/repos/repo_add_base.mako:57
6190 msgid "Repository Group"
6191 msgstr ""
6192
6193 #: rhodecode/templates/admin/repos/repo_add_base.mako:63
6194 #: rhodecode/templates/forks/fork.mako:69
6195 #, python-format
6196 msgid "Select my personal group (%(repo_group_name)s)"
6347 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:177
6348 #: rhodecode/templates/forks/fork.mako:53
6349 msgid "Plain text format with support of {metatags}. Add a README file for longer descriptions"
6197 6350 msgstr ""
6198 6351
6199 6352 #: rhodecode/templates/admin/repos/repo_add_base.mako:66
6200 #: rhodecode/templates/forks/fork.mako:72
6201 msgid "Optionally select a group to put this repository into."
6353 msgid "Repository Group"
6354 msgstr ""
6355
6356 #: rhodecode/templates/admin/repos/repo_add_base.mako:72
6357 #: rhodecode/templates/forks/fork.mako:69
6358 #, python-format
6359 msgid "Select my personal group (%(repo_group_name)s)"
6202 6360 msgstr ""
6203 6361
6204 6362 #: rhodecode/templates/admin/repos/repo_add_base.mako:75
6205 msgid "Copy permission set from the parent repository group."
6363 #: rhodecode/templates/forks/fork.mako:72
6364 msgid "Optionally select a group to put this repository into."
6365 msgstr ""
6366
6367 #: rhodecode/templates/admin/repos/repo_add_base.mako:80
6368 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:141
6369 #: rhodecode/templates/forks/fork.mako:78
6370 msgid "Landing commit"
6206 6371 msgstr ""
6207 6372
6208 6373 #: rhodecode/templates/admin/repos/repo_add_base.mako:84
6209 msgid "Set the type of repository to create."
6210 msgstr ""
6211
6212 #: rhodecode/templates/admin/repos/repo_add_base.mako:89
6213 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:141
6214 #: rhodecode/templates/forks/fork.mako:78
6215 msgid "Landing commit"
6374 msgid "The default commit for file pages, downloads, full text search index, and README generation."
6216 6375 msgstr ""
6217 6376
6218 6377 #: rhodecode/templates/admin/repos/repo_add_base.mako:93
6219 msgid "The default commit for file pages, downloads, full text search index, and README generation."
6378 msgid "Copy permission set from the parent repository group."
6220 6379 msgstr ""
6221 6380
6222 6381 #: rhodecode/templates/admin/repos/repo_creating.mako:5
@@ -6237,33 +6396,39 b' msgstr ""'
6237 6396 msgid "%s repository settings"
6238 6397 msgstr ""
6239 6398
6240 #: rhodecode/templates/admin/repos/repo_edit.mako:58
6399 #: rhodecode/templates/admin/repos/repo_edit.mako:52
6400 msgid "Branch Permissions"
6401 msgstr ""
6402
6403 #: rhodecode/templates/admin/repos/repo_edit.mako:61
6241 6404 msgid "Extra Fields"
6242 6405 msgstr ""
6243 6406
6244 #: rhodecode/templates/admin/repos/repo_edit.mako:64
6407 #: rhodecode/templates/admin/repos/repo_edit.mako:67
6408 #: rhodecode/templates/admin/users/user_edit.mako:48
6409 #: rhodecode/templates/admin/users/user_edit_caches.mako:5
6245 6410 msgid "Caches"
6246 6411 msgstr ""
6247 6412
6248 #: rhodecode/templates/admin/repos/repo_edit.mako:68
6413 #: rhodecode/templates/admin/repos/repo_edit.mako:71
6249 6414 msgid "Remote sync"
6250 6415 msgstr ""
6251 6416
6252 #: rhodecode/templates/admin/repos/repo_edit.mako:72
6417 #: rhodecode/templates/admin/repos/repo_edit.mako:75
6253 6418 #: rhodecode/templates/summary/components.mako:149
6254 6419 msgid "Statistics"
6255 6420 msgstr ""
6256 6421
6257 #: rhodecode/templates/admin/repos/repo_edit.mako:79
6422 #: rhodecode/templates/admin/repos/repo_edit.mako:82
6258 6423 msgid "Reviewer Rules"
6259 6424 msgstr ""
6260 6425
6261 #: rhodecode/templates/admin/repos/repo_edit.mako:86
6262 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:3
6263 msgid "Maintenance"
6264 msgstr ""
6265
6266 6426 #: rhodecode/templates/admin/repos/repo_edit.mako:89
6427 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:3
6428 msgid "Maintenance"
6429 msgstr ""
6430
6431 #: rhodecode/templates/admin/repos/repo_edit.mako:92
6267 6432 msgid "Strip"
6268 6433 msgstr ""
6269 6434
@@ -6392,13 +6557,6 b' msgstr ""'
6392 6557 msgid "Repo Automation"
6393 6558 msgstr ""
6394 6559
6395 #: rhodecode/templates/admin/repos/repo_edit_automation.mako:6
6396 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:62
6397 #: rhodecode/templates/admin/repos/repo_edit_reviewers.mako:6
6398 #: rhodecode/templates/admin/settings/settings_automation.mako:6
6399 msgid "This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license."
6400 msgstr ""
6401
6402 6560 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:3
6403 6561 msgid "Invalidate Cache for Repository"
6404 6562 msgstr ""
@@ -6420,29 +6578,44 b' msgid "Confirm to invalidate repository '
6420 6578 msgstr ""
6421 6579
6422 6580 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:39
6423 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:32
6424 #: rhodecode/templates/base/issue_tracker_settings.mako:13
6425 msgid "Prefix"
6581 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:11
6582 msgid "Key"
6426 6583 msgstr ""
6427 6584
6428 6585 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:40
6429 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:11
6430 msgid "Key"
6586 msgid "Namespace"
6431 6587 msgstr ""
6432 6588
6433 6589 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:58
6590 msgid "Cache keys"
6591 msgstr ""
6592
6593 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:74
6594 #: rhodecode/templates/admin/users/user_edit_caches.mako:19
6595 msgid "Show all"
6596 msgstr ""
6597
6598 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:92
6599 msgid "Shadow Repositories"
6600 msgstr ""
6601
6602 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:104
6603 msgid "No Shadow repositories exist for this repository."
6604 msgstr ""
6605
6606 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:115
6434 6607 msgid "Diff Caches"
6435 6608 msgstr ""
6436 6609
6437 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:63
6610 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:120
6438 6611 msgid "Cached diff name"
6439 6612 msgstr ""
6440 6613
6441 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:67
6614 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:124
6442 6615 msgid "Cached diff files"
6443 6616 msgstr ""
6444 6617
6445 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:71
6618 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:128
6446 6619 msgid "Cached diff size"
6447 6620 msgstr ""
6448 6621
@@ -6498,6 +6671,7 b' msgstr ""'
6498 6671
6499 6672 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:30
6500 6673 #: rhodecode/templates/base/issue_tracker_settings.mako:11
6674 #: rhodecode/templates/base/perms_summary.mako:169
6501 6675 msgid "Pattern"
6502 6676 msgstr ""
6503 6677
@@ -6506,6 +6680,11 b' msgstr ""'
6506 6680 msgid "Url"
6507 6681 msgstr ""
6508 6682
6683 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:32
6684 #: rhodecode/templates/base/issue_tracker_settings.mako:13
6685 msgid "Prefix"
6686 msgstr ""
6687
6509 6688 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:70
6510 6689 #: rhodecode/templates/admin/settings/settings_issuetracker.mako:5
6511 6690 msgid "Issue Tracker / Wiki Patterns"
@@ -6544,14 +6723,26 b' msgstr ""'
6544 6723 msgid "Repository Permissions"
6545 6724 msgstr ""
6546 6725
6547 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:42
6726 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:55
6548 6727 msgid "private repository"
6549 6728 msgstr ""
6550 6729
6551 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:47
6730 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:60
6552 6731 msgid "only users/user groups explicitly added here will have access"
6553 6732 msgstr ""
6554 6733
6734 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:94
6735 msgid "used by {} branch rule, requires write+ permissions"
6736 msgstr ""
6737
6738 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:96
6739 msgid "used by {} branch rules, requires write+ permissions"
6740 msgstr ""
6741
6742 #: rhodecode/templates/admin/repos/repo_edit_permissions_branch.mako:3
6743 msgid "Repository Branch Permissions."
6744 msgstr ""
6745
6555 6746 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:3
6556 6747 msgid "Remote Sync"
6557 6748 msgstr ""
@@ -6642,9 +6833,10 b' msgstr ""'
6642 6833
6643 6834 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:60
6644 6835 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:102
6645 #: rhodecode/templates/base/perms_summary.mako:92
6646 #: rhodecode/templates/base/perms_summary.mako:210
6647 #: rhodecode/templates/base/perms_summary.mako:212
6836 #: rhodecode/templates/base/perms_summary.mako:111
6837 #: rhodecode/templates/base/perms_summary.mako:228
6838 #: rhodecode/templates/base/perms_summary.mako:306
6839 #: rhodecode/templates/base/perms_summary.mako:308
6648 6840 #: rhodecode/templates/debug_style/form-elements.html:45
6649 6841 msgid "edit"
6650 6842 msgstr ""
@@ -6769,10 +6961,6 b' msgstr ""'
6769 6961 msgid "Sorry this functionality is not available for SVN repository"
6770 6962 msgstr ""
6771 6963
6772 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:46
6773 msgid "Remove"
6774 msgstr ""
6775
6776 6964 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:114
6777 6965 msgid "Checking commits"
6778 6966 msgstr ""
@@ -6873,18 +7061,74 b' msgstr ""'
6873 7061 msgid "SMTP auth"
6874 7062 msgstr ""
6875 7063
6876 #: rhodecode/templates/admin/settings/settings_email.mako:34
7064 #: rhodecode/templates/admin/settings/settings_email.mako:30
7065 msgid "You can adjust those settings in [DEFAULT] section of .ini file located at"
7066 msgstr ""
7067
7068 #: rhodecode/templates/admin/settings/settings_email.mako:38
6877 7069 msgid "Test Email"
6878 7070 msgstr ""
6879 7071
6880 #: rhodecode/templates/admin/settings/settings_email.mako:40
6881 msgid "enter valid email"
6882 msgstr ""
6883
6884 7072 #: rhodecode/templates/admin/settings/settings_email.mako:44
7073 msgid "enter valid email"
7074 msgstr ""
7075
7076 #: rhodecode/templates/admin/settings/settings_email.mako:48
6885 7077 msgid "Send an auto-generated email from this server to above email..."
6886 7078 msgstr ""
6887 7079
7080 #: rhodecode/templates/admin/settings/settings_exceptions.mako:3
7081 msgid "Exceptions Tracker - Exception ID"
7082 msgstr ""
7083
7084 #: rhodecode/templates/admin/settings/settings_exceptions.mako:8
7085 msgid "Exception `{}` generated on UTC date: {}"
7086 msgstr ""
7087
7088 #: rhodecode/templates/admin/settings/settings_exceptions.mako:12
7089 msgid "Unable to Read Exception. It might be removed or non-existing."
7090 msgstr ""
7091
7092 #: rhodecode/templates/admin/settings/settings_exceptions.mako:21
7093 msgid "Delete this Exception"
7094 msgstr ""
7095
7096 #: rhodecode/templates/admin/settings/settings_exceptions.mako:29
7097 msgid "Confirm to delete this exception"
7098 msgstr ""
7099
7100 #: rhodecode/templates/admin/settings/settings_exceptions.mako:31
7101 msgid "Delete This Exception"
7102 msgstr ""
7103
7104 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:3
7105 msgid "Exceptions Tracker "
7106 msgstr ""
7107
7108 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:7
7109 msgid "There is {} stored exception."
7110 msgstr ""
7111
7112 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:9
7113 msgid "There are {} stored exceptions."
7114 msgstr ""
7115
7116 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:11
7117 msgid "Store directory"
7118 msgstr ""
7119
7120 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:18
7121 msgid "Confirm to delete all exceptions"
7122 msgstr ""
7123
7124 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:20
7125 msgid "Delete All"
7126 msgstr ""
7127
7128 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:32
7129 msgid "Exceptions Tracker - Showing the last {} Exceptions"
7130 msgstr ""
7131
6888 7132 #: rhodecode/templates/admin/settings/settings_global.mako:5
6889 7133 msgid "Branding"
6890 7134 msgstr ""
@@ -6935,19 +7179,19 b' msgid "Registration Captcha"'
6935 7179 msgstr ""
6936 7180
6937 7181 #: rhodecode/templates/admin/settings/settings_global.mako:68
6938 msgid "Google ReCaptcha public key"
7182 msgid "Google reCaptcha v2 site key."
6939 7183 msgstr ""
6940 7184
6941 7185 #: rhodecode/templates/admin/settings/settings_global.mako:75
6942 msgid "Public key for reCaptcha system."
7186 msgid "Site key for reCaptcha v2 system."
6943 7187 msgstr ""
6944 7188
6945 7189 #: rhodecode/templates/admin/settings/settings_global.mako:80
6946 msgid "Google ReCaptcha private key"
7190 msgid "Google reCaptcha v2 secret key."
6947 7191 msgstr ""
6948 7192
6949 7193 #: rhodecode/templates/admin/settings/settings_global.mako:87
6950 msgid "Private key for reCaptcha system. Setting this value will enable captcha on registration"
7194 msgid "Secret key for reCaptcha v2 system. Setting this value will enable captcha on registration and password reset forms."
6951 7195 msgstr ""
6952 7196
6953 7197 #: rhodecode/templates/admin/settings/settings_global.mako:95
@@ -7352,7 +7596,7 b' msgid "Permissions summary"'
7352 7596 msgstr ""
7353 7597
7354 7598 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:8
7355 #: rhodecode/templates/admin/user_groups/user_groups.mako:65
7599 #: rhodecode/templates/admin/user_groups/user_groups.mako:77
7356 7600 #: rhodecode/templates/debug_style/form-elements.html:509
7357 7601 #: rhodecode/templates/user_group/profile.mako:42
7358 7602 msgid "Members"
@@ -7426,11 +7670,6 b' msgstr ""'
7426 7670 msgid "User Group Permissions"
7427 7671 msgstr ""
7428 7672
7429 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:62
7430 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:109
7431 msgid "revoke"
7432 msgstr ""
7433
7434 7673 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:36
7435 7674 msgid "Change owner of this user group."
7436 7675 msgstr ""
@@ -7449,11 +7688,7 b' msgstr ""'
7449 7688 msgid "User groups administration"
7450 7689 msgstr ""
7451 7690
7452 #: rhodecode/templates/admin/user_groups/user_groups.mako:13
7453 msgid "user groups"
7454 msgstr ""
7455
7456 #: rhodecode/templates/admin/user_groups/user_groups.mako:67
7691 #: rhodecode/templates/admin/user_groups/user_groups.mako:79
7457 7692 msgid "Sync"
7458 7693 msgstr ""
7459 7694
@@ -7543,8 +7778,8 b' msgid "Last login"'
7543 7778 msgstr ""
7544 7779
7545 7780 #: rhodecode/templates/admin/users/user_edit_advanced.mako:9
7546 #: rhodecode/templates/admin/users/users.mako:72
7547 #: rhodecode/templates/forks/forks.mako:77
7781 #: rhodecode/templates/admin/users/users.mako:80
7782 #: rhodecode/templates/forks/forks.mako:69
7548 7783 msgid "Last activity"
7549 7784 msgstr ""
7550 7785
@@ -7634,6 +7869,14 b' msgstr ""'
7634 7869 msgid "User Audit Logs"
7635 7870 msgstr ""
7636 7871
7872 #: rhodecode/templates/admin/users/user_edit_caches.mako:33
7873 msgid "Invalidate user cache"
7874 msgstr ""
7875
7876 #: rhodecode/templates/admin/users/user_edit_caches.mako:33
7877 msgid "Confirm to invalidate user cache"
7878 msgstr ""
7879
7637 7880 #: rhodecode/templates/admin/users/user_edit_emails.mako:5
7638 7881 msgid "Additional Email Addresses"
7639 7882 msgstr ""
@@ -7739,7 +7982,7 b' msgstr ""'
7739 7982 msgid "Users administration"
7740 7983 msgstr ""
7741 7984
7742 #: rhodecode/templates/admin/users/users.mako:78
7985 #: rhodecode/templates/admin/users/users.mako:86
7743 7986 msgid "Auth type"
7744 7987 msgstr ""
7745 7988
@@ -7818,7 +8061,7 b' msgid "Compare fork with %s"'
7818 8061 msgstr ""
7819 8062
7820 8063 #: rhodecode/templates/base/base.mako:269
7821 #: rhodecode/templates/base/base.mako:415
8064 #: rhodecode/templates/base/base.mako:446
7822 8065 #: rhodecode/templates/search/search.mako:64
7823 8066 msgid "Search"
7824 8067 msgstr ""
@@ -7871,46 +8114,49 b' msgstr ""'
7871 8114 msgid "Sign Out"
7872 8115 msgstr ""
7873 8116
7874 #: rhodecode/templates/base/base.mako:397
8117 #: rhodecode/templates/base/base.mako:403
8118 msgid "search / go to..."
8119 msgstr ""
8120
8121 #: rhodecode/templates/base/base.mako:428
7875 8122 msgid "Show activity journal"
7876 8123 msgstr ""
7877 8124
7878 #: rhodecode/templates/base/base.mako:398
8125 #: rhodecode/templates/base/base.mako:429
7879 8126 #: rhodecode/templates/journal/journal.mako:4
7880 #: rhodecode/templates/journal/journal.mako:15
8127 #: rhodecode/templates/journal/journal.mako:14
7881 8128 msgid "Journal"
7882 8129 msgstr ""
7883 8130
7884 #: rhodecode/templates/base/base.mako:403
8131 #: rhodecode/templates/base/base.mako:434
7885 8132 msgid "Show Public activity journal"
7886 8133 msgstr ""
7887 8134
7888 #: rhodecode/templates/base/base.mako:404
8135 #: rhodecode/templates/base/base.mako:435
7889 8136 msgid "Public journal"
7890 8137 msgstr ""
7891 8138
7892 #: rhodecode/templates/base/base.mako:409
8139 #: rhodecode/templates/base/base.mako:440
7893 8140 msgid "Show Gists"
7894 8141 msgstr ""
7895 8142
7896 #: rhodecode/templates/base/base.mako:410
8143 #: rhodecode/templates/base/base.mako:441
7897 8144 msgid "Gists"
7898 8145 msgstr ""
7899 8146
7900 #: rhodecode/templates/base/base.mako:414
8147 #: rhodecode/templates/base/base.mako:445
7901 8148 msgid "Search in repositories you have access to"
7902 8149 msgstr ""
7903 8150
7904 #: rhodecode/templates/base/base.mako:420
8151 #: rhodecode/templates/base/base.mako:451
7905 8152 msgid "Admin settings"
7906 8153 msgstr ""
7907 8154
7908 #: rhodecode/templates/base/base.mako:427
8155 #: rhodecode/templates/base/base.mako:458
7909 8156 msgid "Delegated Admin settings"
7910 8157 msgstr ""
7911 8158
7912 #: rhodecode/templates/base/base.mako:437
7913 #: rhodecode/templates/base/base.mako:438
8159 #: rhodecode/templates/base/base.mako:471
7914 8160 #: rhodecode/templates/debug_style/alerts.html:5
7915 8161 #: rhodecode/templates/debug_style/buttons.html:5
7916 8162 #: rhodecode/templates/debug_style/code-block.html:6
@@ -7932,15 +8178,15 b' msgstr ""'
7932 8178 msgid "Style"
7933 8179 msgstr ""
7934 8180
7935 #: rhodecode/templates/base/base.mako:495
7936 msgid "Go to"
7937 msgstr ""
7938
7939 #: rhodecode/templates/base/base.mako:548
8181 #: rhodecode/templates/base/base.mako:472
8182 msgid "[Style]"
8183 msgstr ""
8184
8185 #: rhodecode/templates/base/base.mako:619
7940 8186 msgid "Keyboard shortcuts"
7941 8187 msgstr ""
7942 8188
7943 #: rhodecode/templates/base/base.mako:556
8189 #: rhodecode/templates/base/base.mako:627
7944 8190 msgid "Site-wide shortcuts"
7945 8191 msgstr ""
7946 8192
@@ -8023,6 +8269,10 b' msgstr ""'
8023 8269 msgid "Read more"
8024 8270 msgstr ""
8025 8271
8272 #: rhodecode/templates/base/issue_tracker_settings.mako:83
8273 msgid "Add new"
8274 msgstr ""
8275
8026 8276 #: rhodecode/templates/base/issue_tracker_settings.mako:91
8027 8277 msgid "New Entry"
8028 8278 msgstr ""
@@ -8032,8 +8282,9 b' msgid "Confirm to remove this pattern:"'
8032 8282 msgstr ""
8033 8283
8034 8284 #: rhodecode/templates/base/issue_tracker_settings.mako:191
8035 #: rhodecode/templates/changeset/changeset_file_comment.mako:275
8036 #: rhodecode/templates/changeset/changeset_file_comment.mako:325
8285 #: rhodecode/templates/changeset/changeset_file_comment.mako:276
8286 #: rhodecode/templates/changeset/changeset_file_comment.mako:326
8287 #: rhodecode/templates/data_table/_dt_elements.mako:389
8037 8288 #: rhodecode/templates/files/files_add.mako:84
8038 8289 #: rhodecode/templates/files/files_add.mako:230
8039 8290 #: rhodecode/templates/files/files_edit.mako:85
@@ -8045,94 +8296,116 b' msgstr ""'
8045 8296 msgid "Test Pattern Preview"
8046 8297 msgstr ""
8047 8298
8048 #: rhodecode/templates/base/perms_summary.mako:14
8299 #: rhodecode/templates/base/perms_summary.mako:26
8049 8300 msgid "in JSON format"
8050 8301 msgstr ""
8051 8302
8052 #: rhodecode/templates/base/perms_summary.mako:23
8303 #: rhodecode/templates/base/perms_summary.mako:35
8304 #: rhodecode/templates/base/perms_summary.mako:43
8053 8305 msgid "show"
8054 8306 msgstr ""
8055 8307
8056 #: rhodecode/templates/base/perms_summary.mako:24
8308 #: rhodecode/templates/base/perms_summary.mako:36
8309 #: rhodecode/templates/base/perms_summary.mako:44
8057 8310 msgid "none"
8058 8311 msgstr ""
8059 8312
8060 #: rhodecode/templates/base/perms_summary.mako:25
8313 #: rhodecode/templates/base/perms_summary.mako:37
8314 #: rhodecode/templates/changelog/changelog_elements.mako:107
8315 #: rhodecode/templates/changeset/changeset.mako:109
8316 #: rhodecode/templates/files/base.mako:4
8317 msgid "merge"
8318 msgstr ""
8319
8320 #: rhodecode/templates/base/perms_summary.mako:38
8321 msgid "push"
8322 msgstr ""
8323
8324 #: rhodecode/templates/base/perms_summary.mako:39
8325 msgid "push force"
8326 msgstr ""
8327
8328 #: rhodecode/templates/base/perms_summary.mako:45
8061 8329 msgid "read"
8062 8330 msgstr ""
8063 8331
8064 #: rhodecode/templates/base/perms_summary.mako:26
8332 #: rhodecode/templates/base/perms_summary.mako:46
8065 8333 msgid "write"
8066 8334 msgstr ""
8067 8335
8068 #: rhodecode/templates/base/perms_summary.mako:27
8336 #: rhodecode/templates/base/perms_summary.mako:47
8069 8337 msgid "admin"
8070 8338 msgstr ""
8071 8339
8072 #: rhodecode/templates/base/perms_summary.mako:34
8340 #: rhodecode/templates/base/perms_summary.mako:55
8073 8341 msgid "No permissions defined"
8074 8342 msgstr ""
8075 8343
8076 #: rhodecode/templates/base/perms_summary.mako:42
8077 #: rhodecode/templates/base/perms_summary.mako:150
8344 #: rhodecode/templates/base/perms_summary.mako:63
8345 #: rhodecode/templates/base/perms_summary.mako:170
8346 #: rhodecode/templates/base/perms_summary.mako:243
8078 8347 msgid "Permission"
8079 8348 msgstr ""
8080 8349
8081 #: rhodecode/templates/base/perms_summary.mako:44
8082 #: rhodecode/templates/base/perms_summary.mako:152
8350 #: rhodecode/templates/base/perms_summary.mako:65
8351 #: rhodecode/templates/base/perms_summary.mako:245
8083 8352 msgid "Edit Permission"
8084 8353 msgstr ""
8085 8354
8086 #: rhodecode/templates/base/perms_summary.mako:100
8087 #: rhodecode/templates/base/perms_summary.mako:109
8355 #: rhodecode/templates/base/perms_summary.mako:119
8356 #: rhodecode/templates/base/perms_summary.mako:128
8088 8357 msgid "edit global"
8089 8358 msgstr ""
8090 8359
8091 #: rhodecode/templates/base/perms_summary.mako:117
8360 #: rhodecode/templates/base/perms_summary.mako:136
8092 8361 msgid "Repository default permission"
8093 8362 msgstr ""
8094 8363
8095 #: rhodecode/templates/base/perms_summary.mako:120
8364 #: rhodecode/templates/base/perms_summary.mako:139
8096 8365 msgid "Repository group default permission"
8097 8366 msgstr ""
8098 8367
8099 #: rhodecode/templates/base/perms_summary.mako:123
8368 #: rhodecode/templates/base/perms_summary.mako:142
8100 8369 msgid "User group default permission"
8101 8370 msgstr ""
8102 8371
8103 #: rhodecode/templates/base/perms_summary.mako:126
8372 #: rhodecode/templates/base/perms_summary.mako:145
8104 8373 msgid "Super admin"
8105 8374 msgstr ""
8106 8375
8107 #: rhodecode/templates/base/perms_summary.mako:129
8376 #: rhodecode/templates/base/perms_summary.mako:148
8108 8377 msgid "Inherit permissions"
8109 8378 msgstr ""
8110 8379
8111 #: rhodecode/templates/base/perms_summary.mako:132
8380 #: rhodecode/templates/base/perms_summary.mako:151
8112 8381 msgid "Create repositories"
8113 8382 msgstr ""
8114 8383
8115 #: rhodecode/templates/base/perms_summary.mako:135
8384 #: rhodecode/templates/base/perms_summary.mako:154
8116 8385 msgid "Fork repositories"
8117 8386 msgstr ""
8118 8387
8119 #: rhodecode/templates/base/perms_summary.mako:138
8388 #: rhodecode/templates/base/perms_summary.mako:157
8120 8389 msgid "Create repository groups"
8121 8390 msgstr ""
8122 8391
8123 #: rhodecode/templates/base/perms_summary.mako:141
8392 #: rhodecode/templates/base/perms_summary.mako:160
8124 8393 msgid "Create user groups"
8125 8394 msgstr ""
8126 8395
8127 #: rhodecode/templates/base/perms_summary.mako:190
8396 #: rhodecode/templates/base/perms_summary.mako:172
8397 msgid "Edit Branch Permission"
8398 msgstr ""
8399
8400 #: rhodecode/templates/base/perms_summary.mako:286
8128 8401 msgid "overridden by"
8129 8402 msgstr ""
8130 8403
8131 #: rhodecode/templates/base/perms_summary.mako:223
8132 msgid "No permission defined"
8133 msgstr ""
8134
8135 #: rhodecode/templates/base/root.mako:165
8404 #: rhodecode/templates/base/perms_summary.mako:321
8405 msgid "No matching permission defined"
8406 msgstr ""
8407
8408 #: rhodecode/templates/base/root.mako:142
8136 8409 msgid "Please enable JavaScript to use RhodeCode Enterprise"
8137 8410 msgstr ""
8138 8411
@@ -8500,17 +8773,11 b' msgstr ""'
8500 8773
8501 8774 #: rhodecode/templates/changelog/changelog_elements.mako:83
8502 8775 #: rhodecode/templates/compare/compare_commits.mako:50
8503 #: rhodecode/templates/pullrequests/pullrequest_show.mako:516
8776 #: rhodecode/templates/pullrequests/pullrequest_show.mako:519
8504 8777 #: rhodecode/templates/search/search_commit.mako:36
8505 8778 msgid "Expand commit message"
8506 8779 msgstr ""
8507 8780
8508 #: rhodecode/templates/changelog/changelog_elements.mako:107
8509 #: rhodecode/templates/changeset/changeset.mako:109
8510 #: rhodecode/templates/files/base.mako:4
8511 msgid "merge"
8512 msgstr ""
8513
8514 8781 #: rhodecode/templates/changelog/changelog_elements.mako:129
8515 8782 #: rhodecode/templates/changeset/changeset.mako:122
8516 8783 #: rhodecode/templates/files/base.mako:17
@@ -8538,7 +8805,7 b' msgid "Parent Commit"'
8538 8805 msgstr ""
8539 8806
8540 8807 #: rhodecode/templates/changeset/changeset.mako:65
8541 msgid "Parent"
8808 msgid "parent"
8542 8809 msgstr ""
8543 8810
8544 8811 #: rhodecode/templates/changeset/changeset.mako:69
@@ -8546,7 +8813,7 b' msgid "Child Commit"'
8546 8813 msgstr ""
8547 8814
8548 8815 #: rhodecode/templates/changeset/changeset.mako:69
8549 msgid "Child"
8816 msgid "child"
8550 8817 msgstr ""
8551 8818
8552 8819 #: rhodecode/templates/changeset/changeset.mako:81
@@ -8555,7 +8822,7 b' msgstr ""'
8555 8822
8556 8823 #: rhodecode/templates/changeset/changeset.mako:89
8557 8824 #: rhodecode/templates/changeset/changeset.mako:95
8558 #: rhodecode/templates/changeset/changeset_file_comment.mako:82
8825 #: rhodecode/templates/changeset/changeset_file_comment.mako:83
8559 8826 #: rhodecode/templates/compare/compare_diff.mako:159
8560 8827 msgid "Commit status"
8561 8828 msgstr ""
@@ -8571,8 +8838,8 b' msgid "Diff options"'
8571 8838 msgstr ""
8572 8839
8573 8840 #: rhodecode/templates/changeset/changeset.mako:142
8574 #: rhodecode/templates/codeblocks/diffs.mako:455
8575 #: rhodecode/templates/codeblocks/diffs.mako:458
8841 #: rhodecode/templates/codeblocks/diffs.mako:460
8842 #: rhodecode/templates/codeblocks/diffs.mako:463
8576 8843 msgid "Raw diff"
8577 8844 msgstr ""
8578 8845
@@ -8589,8 +8856,8 b' msgid "Patch Diff"'
8589 8856 msgstr ""
8590 8857
8591 8858 #: rhodecode/templates/changeset/changeset.mako:150
8592 #: rhodecode/templates/codeblocks/diffs.mako:462
8593 #: rhodecode/templates/codeblocks/diffs.mako:465
8859 #: rhodecode/templates/codeblocks/diffs.mako:467
8860 #: rhodecode/templates/codeblocks/diffs.mako:470
8594 8861 msgid "Download diff"
8595 8862 msgstr ""
8596 8863
@@ -8614,102 +8881,99 b' msgstr ""'
8614 8881 msgid "No Parent Commits"
8615 8882 msgstr ""
8616 8883
8617 #: rhodecode/templates/changeset/changeset_file_comment.mako:33
8884 #: rhodecode/templates/changeset/changeset_file_comment.mako:34
8618 8885 msgid "Resolved by comment #{}"
8619 8886 msgstr ""
8620 8887
8621 #: rhodecode/templates/changeset/changeset_file_comment.mako:40
8888 #: rhodecode/templates/changeset/changeset_file_comment.mako:41
8622 8889 msgid "Click to resolve this comment"
8623 8890 msgstr ""
8624 8891
8625 #: rhodecode/templates/changeset/changeset_file_comment.mako:67
8626 #: rhodecode/templates/changeset/changeset_file_comment.mako:69
8892 #: rhodecode/templates/changeset/changeset_file_comment.mako:68
8893 #: rhodecode/templates/changeset/changeset_file_comment.mako:70
8627 8894 #, python-format
8628 8895 msgid "pull request #%s"
8629 8896 msgstr ""
8630 8897
8631 #: rhodecode/templates/changeset/changeset_file_comment.mako:74
8898 #: rhodecode/templates/changeset/changeset_file_comment.mako:75
8632 8899 msgid "Status change on commit"
8633 8900 msgstr ""
8634 8901
8635 #: rhodecode/templates/changeset/changeset_file_comment.mako:89
8902 #: rhodecode/templates/changeset/changeset_file_comment.mako:90
8636 8903 msgid "resolves comment #{}"
8637 8904 msgstr ""
8638 8905
8639 #: rhodecode/templates/changeset/changeset_file_comment.mako:97
8640 msgid "Pull request author"
8641 msgstr ""
8642
8643 8906 #: rhodecode/templates/changeset/changeset_file_comment.mako:98
8907 msgid "Pull request author"
8908 msgstr ""
8909
8910 #: rhodecode/templates/changeset/changeset_file_comment.mako:99
8644 8911 msgid "author"
8645 8912 msgstr ""
8646 8913
8647 #: rhodecode/templates/changeset/changeset_file_comment.mako:106
8648 msgid "Outdated comment from pull request version {0}"
8649 msgstr ""
8650
8651 #: rhodecode/templates/changeset/changeset_file_comment.mako:110
8652 #: rhodecode/templates/changeset/changeset_file_comment.mako:125
8653 msgid "Comment from pull request version {0}"
8654 msgstr ""
8655
8656 #: rhodecode/templates/changeset/changeset_file_comment.mako:122
8657 msgid "Outdated comment from pull request version {}"
8658 msgstr ""
8659
8660 #: rhodecode/templates/changeset/changeset_file_comment.mako:152
8661 #: rhodecode/templates/changeset/changeset_file_comment.mako:155
8662 msgid "Prev"
8914 #: rhodecode/templates/changeset/changeset_file_comment.mako:107
8915 #: rhodecode/templates/changeset/changeset_file_comment.mako:123
8916 msgid "Outdated comment from pull request version v{0}, latest v{1}"
8917 msgstr ""
8918
8919 #: rhodecode/templates/changeset/changeset_file_comment.mako:111
8920 #: rhodecode/templates/changeset/changeset_file_comment.mako:126
8921 msgid "Comment from pull request version v{0}, latest v{1}"
8663 8922 msgstr ""
8664 8923
8665 8924 #: rhodecode/templates/changeset/changeset_file_comment.mako:153
8666 8925 #: rhodecode/templates/changeset/changeset_file_comment.mako:156
8926 msgid "Prev"
8927 msgstr ""
8928
8929 #: rhodecode/templates/changeset/changeset_file_comment.mako:154
8930 #: rhodecode/templates/changeset/changeset_file_comment.mako:157
8667 8931 msgid "Next"
8668 8932 msgstr ""
8669 8933
8670 #: rhodecode/templates/changeset/changeset_file_comment.mako:191
8934 #: rhodecode/templates/changeset/changeset_file_comment.mako:192
8671 8935 msgid "Leave a comment on this Pull Request."
8672 8936 msgstr ""
8673 8937
8674 #: rhodecode/templates/changeset/changeset_file_comment.mako:193
8938 #: rhodecode/templates/changeset/changeset_file_comment.mako:194
8675 8939 msgid "Leave a comment on {} commits in this range."
8676 8940 msgstr ""
8677 8941
8678 #: rhodecode/templates/changeset/changeset_file_comment.mako:195
8942 #: rhodecode/templates/changeset/changeset_file_comment.mako:196
8679 8943 msgid "Leave a comment on this Commit."
8680 8944 msgstr ""
8681 8945
8682 #: rhodecode/templates/changeset/changeset_file_comment.mako:283
8683 #: rhodecode/templates/codeblocks/diffs.mako:67
8684 msgid "You need to be logged in to leave comments."
8685 msgstr ""
8686
8687 8946 #: rhodecode/templates/changeset/changeset_file_comment.mako:284
8688 8947 #: rhodecode/templates/codeblocks/diffs.mako:67
8948 msgid "You need to be logged in to leave comments."
8949 msgstr ""
8950
8951 #: rhodecode/templates/changeset/changeset_file_comment.mako:285
8952 #: rhodecode/templates/codeblocks/diffs.mako:67
8689 8953 msgid "Login now"
8690 8954 msgstr ""
8691 8955
8692 #: rhodecode/templates/changeset/changeset_file_comment.mako:349
8956 #: rhodecode/templates/changeset/changeset_file_comment.mako:350
8693 8957 #, python-format
8694 8958 msgid "Comments parsed using %s syntax with %s, and %s actions support."
8695 8959 msgstr ""
8696 8960
8697 #: rhodecode/templates/changeset/changeset_file_comment.mako:351
8698 msgid "Use @username inside this text to send notification to this RhodeCode user"
8699 msgstr ""
8700
8701 8961 #: rhodecode/templates/changeset/changeset_file_comment.mako:352
8962 msgid "Use @username inside this text to send notification to this RhodeCode user"
8963 msgstr ""
8964
8965 #: rhodecode/templates/changeset/changeset_file_comment.mako:353
8702 8966 msgid "Start typing with / for certain actions to be triggered via text box."
8703 8967 msgstr ""
8704 8968
8705 #: rhodecode/templates/changeset/changeset_file_comment.mako:369
8706 #: rhodecode/templates/pullrequests/pullrequest_show.mako:15
8707 #: rhodecode/templates/pullrequests/pullrequest_show.mako:159
8969 #: rhodecode/templates/changeset/changeset_file_comment.mako:370
8970 #: rhodecode/templates/pullrequests/pullrequest_show.mako:16
8971 #: rhodecode/templates/pullrequests/pullrequest_show.mako:160
8708 8972 #: rhodecode/templates/pullrequests/pullrequests.mako:52
8709 8973 msgid "Closed"
8710 8974 msgstr ""
8711 8975
8712 #: rhodecode/templates/changeset/changeset_file_comment.mako:399
8976 #: rhodecode/templates/changeset/changeset_file_comment.mako:400
8713 8977 #: rhodecode/templates/compare/compare_diff.mako:104
8714 8978 #: rhodecode/templates/compare/compare_diff.mako:112
8715 8979 #: rhodecode/templates/compare/compare_diff.mako:120
@@ -8809,82 +9073,82 b' msgstr ""'
8809 9073 msgid "Hide them"
8810 9074 msgstr ""
8811 9075
8812 #: rhodecode/templates/codeblocks/diffs.mako:294
8813 msgid "File was deleted in this version, and outdated comments were made on it"
8814 msgstr ""
8815
8816 #: rhodecode/templates/codeblocks/diffs.mako:360
9076 #: rhodecode/templates/codeblocks/diffs.mako:299
9077 msgid "File was deleted in this version. There are still outdated/unresolved comments attached to it."
9078 msgstr ""
9079
9080 #: rhodecode/templates/codeblocks/diffs.mako:365
8817 9081 #: rhodecode/templates/files/files_source.mako:19
8818 9082 msgid "Copy the full path"
8819 9083 msgstr ""
8820 9084
8821 #: rhodecode/templates/codeblocks/diffs.mako:425
8822 #: rhodecode/templates/codeblocks/diffs.mako:441
9085 #: rhodecode/templates/codeblocks/diffs.mako:430
9086 #: rhodecode/templates/codeblocks/diffs.mako:446
8823 9087 #, python-format
8824 9088 msgid "Show file at commit: %(commit_id)s"
8825 9089 msgstr ""
8826 9090
8827 #: rhodecode/templates/codeblocks/diffs.mako:427
8828 #: rhodecode/templates/codeblocks/diffs.mako:434
8829 msgid "Show file before"
8830 msgstr ""
8831
8832 9091 #: rhodecode/templates/codeblocks/diffs.mako:432
8833 #: rhodecode/templates/codeblocks/diffs.mako:448
9092 #: rhodecode/templates/codeblocks/diffs.mako:439
9093 msgid "Show file before"
9094 msgstr ""
9095
9096 #: rhodecode/templates/codeblocks/diffs.mako:437
9097 #: rhodecode/templates/codeblocks/diffs.mako:453
8834 9098 #, python-format
8835 9099 msgid "File no longer present at commit: %(commit_id)s"
8836 9100 msgstr ""
8837 9101
8838 #: rhodecode/templates/codeblocks/diffs.mako:443
8839 #: rhodecode/templates/codeblocks/diffs.mako:450
9102 #: rhodecode/templates/codeblocks/diffs.mako:448
9103 #: rhodecode/templates/codeblocks/diffs.mako:455
8840 9104 msgid "Show file after"
8841 9105 msgstr ""
8842 9106
8843 #: rhodecode/templates/codeblocks/diffs.mako:481
9107 #: rhodecode/templates/codeblocks/diffs.mako:486
8844 9108 msgid "Show comments"
8845 9109 msgstr ""
8846 9110
8847 #: rhodecode/templates/codeblocks/diffs.mako:481
9111 #: rhodecode/templates/codeblocks/diffs.mako:486
8848 9112 msgid "Hide comments"
8849 9113 msgstr ""
8850 9114
8851 #: rhodecode/templates/codeblocks/diffs.mako:547
8852 #: rhodecode/templates/codeblocks/diffs.mako:590
8853 #: rhodecode/templates/codeblocks/diffs.mako:645
9115 #: rhodecode/templates/codeblocks/diffs.mako:552
9116 #: rhodecode/templates/codeblocks/diffs.mako:595
9117 #: rhodecode/templates/codeblocks/diffs.mako:650
8854 9118 msgid "comments including outdated"
8855 9119 msgstr ""
8856 9120
8857 #: rhodecode/templates/codeblocks/diffs.mako:549
8858 #: rhodecode/templates/codeblocks/diffs.mako:592
8859 #: rhodecode/templates/codeblocks/diffs.mako:647
9121 #: rhodecode/templates/codeblocks/diffs.mako:554
9122 #: rhodecode/templates/codeblocks/diffs.mako:597
9123 #: rhodecode/templates/codeblocks/diffs.mako:652
8860 9124 msgid "comments"
8861 9125 msgstr ""
8862 9126
8863 #: rhodecode/templates/codeblocks/diffs.mako:701
9127 #: rhodecode/templates/codeblocks/diffs.mako:706
8864 9128 msgid "View side by side"
8865 9129 msgstr ""
8866 9130
8867 #: rhodecode/templates/codeblocks/diffs.mako:703
8868 msgid "Side by Side"
8869 msgstr ""
8870
8871 #: rhodecode/templates/codeblocks/diffs.mako:707
8872 msgid "View unified"
8873 msgstr ""
8874
8875 9131 #: rhodecode/templates/codeblocks/diffs.mako:708
9132 msgid "Side by Side"
9133 msgstr ""
9134
9135 #: rhodecode/templates/codeblocks/diffs.mako:712
9136 msgid "View unified"
9137 msgstr ""
9138
9139 #: rhodecode/templates/codeblocks/diffs.mako:713
8876 9140 msgid "Unified"
8877 9141 msgstr ""
8878 9142
8879 #: rhodecode/templates/codeblocks/diffs.mako:718
9143 #: rhodecode/templates/codeblocks/diffs.mako:723
8880 9144 msgid "Expand All Files"
8881 9145 msgstr ""
8882 9146
8883 #: rhodecode/templates/codeblocks/diffs.mako:722
9147 #: rhodecode/templates/codeblocks/diffs.mako:727
8884 9148 msgid "Collapse All Files"
8885 9149 msgstr ""
8886 9150
8887 #: rhodecode/templates/codeblocks/diffs.mako:726
9151 #: rhodecode/templates/codeblocks/diffs.mako:731
8888 9152 msgid "Wide Mode Diff"
8889 9153 msgstr ""
8890 9154
@@ -8901,7 +9165,7 b' msgid "Compare was calculated based on t'
8901 9165 msgstr ""
8902 9166
8903 9167 #: rhodecode/templates/compare/compare_commits.mako:17
8904 #: rhodecode/templates/pullrequests/pullrequest_show.mako:477
9168 #: rhodecode/templates/pullrequests/pullrequest_show.mako:480
8905 9169 msgid "Time"
8906 9170 msgstr ""
8907 9171
@@ -8928,7 +9192,7 b' msgstr ""'
8928 9192
8929 9193 #: rhodecode/templates/compare/compare_diff.mako:60
8930 9194 #: rhodecode/templates/email_templates/pull_request_review.mako:74
8931 #: rhodecode/templates/pullrequests/pullrequest_show.mako:107
9195 #: rhodecode/templates/pullrequests/pullrequest_show.mako:108
8932 9196 msgid "Target"
8933 9197 msgstr ""
8934 9198
@@ -8936,7 +9200,7 b' msgstr ""'
8936 9200 #: rhodecode/templates/email_templates/pull_request_comment.mako:90
8937 9201 #: rhodecode/templates/email_templates/pull_request_review.mako:73
8938 9202 #: rhodecode/templates/files/files_source.mako:29
8939 #: rhodecode/templates/pullrequests/pullrequest_show.mako:71
9203 #: rhodecode/templates/pullrequests/pullrequest_show.mako:72
8940 9204 msgid "Source"
8941 9205 msgstr ""
8942 9206
@@ -9003,6 +9267,10 b' msgstr ""'
9003 9267 msgid "Creating"
9004 9268 msgstr ""
9005 9269
9270 #: rhodecode/templates/data_table/_dt_elements.mako:183
9271 msgid "Created"
9272 msgstr ""
9273
9006 9274 #: rhodecode/templates/data_table/_dt_elements.mako:225
9007 9275 msgid "personal"
9008 9276 msgstr ""
@@ -9019,15 +9287,20 b' msgid "User group"'
9019 9287 msgstr ""
9020 9288
9021 9289 #: rhodecode/templates/data_table/_dt_elements.mako:332
9022 #: rhodecode/templates/forks/fork.mako:88
9290 #: rhodecode/templates/forks/fork.mako:98
9023 9291 msgid "Private"
9024 9292 msgstr ""
9025 9293
9026 #: rhodecode/templates/data_table/_dt_elements.mako:366
9294 #: rhodecode/templates/data_table/_dt_elements.mako:365
9027 9295 #, python-format
9028 9296 msgid "Pull request #%(pr_number)s"
9029 9297 msgstr ""
9030 9298
9299 #: rhodecode/templates/data_table/_dt_elements.mako:406
9300 #, python-format
9301 msgid "Parsed using %s syntax"
9302 msgstr ""
9303
9031 9304 #: rhodecode/templates/debug_style/buttons.html:131
9032 9305 msgid "Confirm to remove this field: Field"
9033 9306 msgstr ""
@@ -9266,7 +9539,7 b' msgid "%(user)s left %(comment_type)s on'
9266 9539 msgstr ""
9267 9540
9268 9541 #: rhodecode/templates/email_templates/pull_request_comment.mako:49
9269 #: rhodecode/templates/pullrequests/pullrequest.mako:72
9542 #: rhodecode/templates/pullrequests/pullrequest.mako:73
9270 9543 msgid "Source repository"
9271 9544 msgstr ""
9272 9545
@@ -9349,6 +9622,10 b' msgstr ""'
9349 9622 msgid "You will be redirected to %s in %s seconds"
9350 9623 msgstr ""
9351 9624
9625 #: rhodecode/templates/errors/error_document.mako:63
9626 msgid "Support Page"
9627 msgstr ""
9628
9352 9629 #: rhodecode/templates/feed/atom_feed_entry.mako:3
9353 9630 #, python-format
9354 9631 msgid "%(user)s commited on %(date)s UTC"
@@ -9634,7 +9911,7 b' msgid "New Fork"'
9634 9911 msgstr ""
9635 9912
9636 9913 #: rhodecode/templates/forks/fork.mako:37
9637 #: rhodecode/templates/forks/forks.mako:70
9914 #: rhodecode/templates/forks/forks.mako:62
9638 9915 msgid "Fork name"
9639 9916 msgstr ""
9640 9917
@@ -9642,11 +9919,11 b' msgstr ""'
9642 9919 msgid "Default commit for files page, downloads, whoosh and readme"
9643 9920 msgstr ""
9644 9921
9645 #: rhodecode/templates/forks/fork.mako:98
9922 #: rhodecode/templates/forks/fork.mako:88
9646 9923 msgid "Copy permissions"
9647 9924 msgstr ""
9648 9925
9649 #: rhodecode/templates/forks/fork.mako:102
9926 #: rhodecode/templates/forks/fork.mako:92
9650 9927 msgid "Copy permissions from forked repository"
9651 9928 msgstr ""
9652 9929
@@ -9667,19 +9944,15 b' msgstr ""'
9667 9944 msgid "Create new fork"
9668 9945 msgstr ""
9669 9946
9670 #: rhodecode/templates/forks/forks.mako:74
9947 #: rhodecode/templates/forks/forks.mako:66
9671 9948 msgid "Forked"
9672 9949 msgstr ""
9673 9950
9674 #: rhodecode/templates/journal/journal.mako:14
9675 msgid "Filter"
9676 msgstr ""
9677
9678 #: rhodecode/templates/journal/journal.mako:24
9679 msgid "ATOM journal feed"
9680 msgstr ""
9681
9682 9951 #: rhodecode/templates/journal/journal.mako:25
9952 msgid "ATOM journal feed"
9953 msgstr ""
9954
9955 #: rhodecode/templates/journal/journal.mako:26
9683 9956 msgid "RSS journal feed"
9684 9957 msgstr ""
9685 9958
@@ -9700,74 +9973,70 b' msgstr ""'
9700 9973 msgid "RSS public journal feed"
9701 9974 msgstr ""
9702 9975
9703 #: rhodecode/templates/pullrequests/pullrequest.mako:4
9704 #: rhodecode/templates/pullrequests/pullrequest.mako:8
9976 #: rhodecode/templates/pullrequests/pullrequest.mako:5
9977 #: rhodecode/templates/pullrequests/pullrequest.mako:9
9705 9978 msgid "New pull request"
9706 9979 msgstr ""
9707 9980
9708 #: rhodecode/templates/pullrequests/pullrequest.mako:35
9981 #: rhodecode/templates/pullrequests/pullrequest.mako:36
9709 9982 msgid "Pull request summary"
9710 9983 msgstr ""
9711 9984
9712 #: rhodecode/templates/pullrequests/pullrequest.mako:58
9713 msgid "Write a short description on this pull request"
9714 msgstr ""
9715
9716 #: rhodecode/templates/pullrequests/pullrequest.mako:64
9985 #: rhodecode/templates/pullrequests/pullrequest.mako:65
9717 9986 msgid "Commit flow"
9718 9987 msgstr ""
9719 9988
9720 #: rhodecode/templates/pullrequests/pullrequest.mako:90
9989 #: rhodecode/templates/pullrequests/pullrequest.mako:91
9721 9990 msgid "Loading refs..."
9722 9991 msgstr ""
9723 9992
9724 #: rhodecode/templates/pullrequests/pullrequest.mako:101
9993 #: rhodecode/templates/pullrequests/pullrequest.mako:102
9725 9994 msgid "Submit Pull Request"
9726 9995 msgstr ""
9727 9996
9728 #: rhodecode/templates/pullrequests/pullrequest.mako:115
9729 #: rhodecode/templates/pullrequests/pullrequest_show.mako:315
9997 #: rhodecode/templates/pullrequests/pullrequest.mako:116
9998 #: rhodecode/templates/pullrequests/pullrequest_show.mako:317
9730 9999 msgid "Author of this pull request"
9731 10000 msgstr ""
9732 10001
9733 #: rhodecode/templates/pullrequests/pullrequest.mako:129
9734 #: rhodecode/templates/pullrequests/pullrequest_show.mako:329
10002 #: rhodecode/templates/pullrequests/pullrequest.mako:130
10003 #: rhodecode/templates/pullrequests/pullrequest_show.mako:331
9735 10004 msgid "Reviewer rules"
9736 10005 msgstr ""
9737 10006
9738 #: rhodecode/templates/pullrequests/pullrequest.mako:139
9739 #: rhodecode/templates/pullrequests/pullrequest_show.mako:343
10007 #: rhodecode/templates/pullrequests/pullrequest.mako:140
10008 #: rhodecode/templates/pullrequests/pullrequest_show.mako:345
9740 10009 msgid "Pull request reviewers"
9741 10010 msgstr ""
9742 10011
9743 #: rhodecode/templates/pullrequests/pullrequest.mako:150
9744 #: rhodecode/templates/pullrequests/pullrequest_show.mako:386
10012 #: rhodecode/templates/pullrequests/pullrequest.mako:151
10013 #: rhodecode/templates/pullrequests/pullrequest_show.mako:388
9745 10014 msgid "Add reviewer or reviewer group"
9746 10015 msgstr ""
9747 10016
9748 #: rhodecode/templates/pullrequests/pullrequest.mako:305
9749 #: rhodecode/templates/pullrequests/pullrequest.mako:513
10017 #: rhodecode/templates/pullrequests/pullrequest.mako:307
10018 #: rhodecode/templates/pullrequests/pullrequest.mako:524
9750 10019 msgid "Please select source and target"
9751 10020 msgstr ""
9752 10021
9753 #: rhodecode/templates/pullrequests/pullrequest.mako:311
10022 #: rhodecode/templates/pullrequests/pullrequest.mako:313
9754 10023 msgid "Loading compare ..."
9755 10024 msgstr ""
9756 10025
9757 #: rhodecode/templates/pullrequests/pullrequest.mako:367
10026 #: rhodecode/templates/pullrequests/pullrequest.mako:372
9758 10027 msgid "Show detailed compare."
9759 10028 msgstr ""
9760 10029
9761 #: rhodecode/templates/pullrequests/pullrequest.mako:374
10030 #: rhodecode/templates/pullrequests/pullrequest.mako:379
9762 10031 msgid "There are no commits to merge."
9763 10032 msgstr ""
9764 10033
9765 #: rhodecode/templates/pullrequests/pullrequest.mako:424
9766 #: rhodecode/templates/pullrequests/pullrequest.mako:450
10034 #: rhodecode/templates/pullrequests/pullrequest.mako:429
10035 #: rhodecode/templates/pullrequests/pullrequest.mako:455
9767 10036 msgid "Select commit reference"
9768 10037 msgstr ""
9769 10038
9770 #: rhodecode/templates/pullrequests/pullrequest.mako:440
10039 #: rhodecode/templates/pullrequests/pullrequest.mako:445
9771 10040 msgid "Target repository"
9772 10041 msgstr ""
9773 10042
@@ -9802,179 +10071,187 b' msgstr ""'
9802 10071 msgid "Close with status {}"
9803 10072 msgstr ""
9804 10073
9805 #: rhodecode/templates/pullrequests/pullrequest_show.mako:5
10074 #: rhodecode/templates/pullrequests/pullrequest_show.mako:6
9806 10075 #, python-format
9807 10076 msgid "%s Pull Request #%s"
9808 10077 msgstr ""
9809 10078
9810 #: rhodecode/templates/pullrequests/pullrequest_show.mako:51
10079 #: rhodecode/templates/pullrequests/pullrequest_show.mako:52
9811 10080 msgid "From"
9812 10081 msgstr ""
9813 10082
9814 #: rhodecode/templates/pullrequests/pullrequest_show.mako:57
10083 #: rhodecode/templates/pullrequests/pullrequest_show.mako:58
9815 10084 msgid "Confirm to delete this pull request"
9816 10085 msgstr ""
9817 10086
9818 #: rhodecode/templates/pullrequests/pullrequest_show.mako:88
10087 #: rhodecode/templates/pullrequests/pullrequest_show.mako:89
9819 10088 msgid "Common ancestor"
9820 10089 msgstr ""
9821 10090
9822 #: rhodecode/templates/pullrequests/pullrequest_show.mako:100
10091 #: rhodecode/templates/pullrequests/pullrequest_show.mako:101
9823 10092 msgid "Copy the pull url"
9824 10093 msgstr ""
9825 10094
9826 #: rhodecode/templates/pullrequests/pullrequest_show.mako:129
10095 #: rhodecode/templates/pullrequests/pullrequest_show.mako:130
9827 10096 msgid "Merge"
9828 10097 msgstr ""
9829 10098
9830 #: rhodecode/templates/pullrequests/pullrequest_show.mako:140
10099 #: rhodecode/templates/pullrequests/pullrequest_show.mako:141
9831 10100 #: rhodecode/templates/summary/components.mako:66
9832 10101 msgid "Copy the clone url"
9833 10102 msgstr ""
9834 10103
9835 #: rhodecode/templates/pullrequests/pullrequest_show.mako:144
10104 #: rhodecode/templates/pullrequests/pullrequest_show.mako:145
9836 10105 msgid "Shadow repository data not available"
9837 10106 msgstr ""
9838 10107
9839 #: rhodecode/templates/pullrequests/pullrequest_show.mako:152
10108 #: rhodecode/templates/pullrequests/pullrequest_show.mako:153
9840 10109 msgid "Review"
9841 10110 msgstr ""
9842 10111
9843 #: rhodecode/templates/pullrequests/pullrequest_show.mako:181
10112 #: rhodecode/templates/pullrequests/pullrequest_show.mako:169
10113 msgid "Rendered using {} renderer"
10114 msgstr ""
10115
10116 #: rhodecode/templates/pullrequests/pullrequest_show.mako:183
9844 10117 msgid "Versions"
9845 10118 msgstr ""
9846 10119
9847 #: rhodecode/templates/pullrequests/pullrequest_show.mako:193
10120 #: rhodecode/templates/pullrequests/pullrequest_show.mako:195
9848 10121 msgid "Hide all versions of this pull request"
9849 10122 msgstr ""
9850 10123
9851 #: rhodecode/templates/pullrequests/pullrequest_show.mako:218
10124 #: rhodecode/templates/pullrequests/pullrequest_show.mako:220
9852 10125 msgid "Your review status at this version"
9853 10126 msgstr ""
9854 10127
9855 #: rhodecode/templates/pullrequests/pullrequest_show.mako:224
9856 msgid "Comment from pull request version {0}, general:{1} inline:{2}"
9857 msgstr ""
9858
9859 #: rhodecode/templates/pullrequests/pullrequest_show.mako:241
9860 #: rhodecode/templates/pullrequests/pullrequest_show.mako:245
9861 msgid "select versions to show changes"
9862 msgstr ""
9863
9864 #: rhodecode/templates/pullrequests/pullrequest_show.mako:242
9865 msgid "show changes between versions"
10128 #: rhodecode/templates/pullrequests/pullrequest_show.mako:226
10129 msgid "Comment from pull request version v{0}, general:{1} inline:{2}"
9866 10130 msgstr ""
9867 10131
9868 10132 #: rhodecode/templates/pullrequests/pullrequest_show.mako:243
10133 #: rhodecode/templates/pullrequests/pullrequest_show.mako:247
10134 msgid "select versions to show changes"
10135 msgstr ""
10136
10137 #: rhodecode/templates/pullrequests/pullrequest_show.mako:244
10138 msgid "show changes between versions"
10139 msgstr ""
10140
10141 #: rhodecode/templates/pullrequests/pullrequest_show.mako:245
9869 10142 msgid "show pull request for this version"
9870 10143 msgstr ""
9871 10144
9872 #: rhodecode/templates/pullrequests/pullrequest_show.mako:258
10145 #: rhodecode/templates/pullrequests/pullrequest_show.mako:260
9873 10146 msgid "Comments at this version"
9874 10147 msgstr ""
9875 10148
9876 #: rhodecode/templates/pullrequests/pullrequest_show.mako:262
10149 #: rhodecode/templates/pullrequests/pullrequest_show.mako:264
9877 10150 msgid "Comments for this pull request"
9878 10151 msgstr ""
9879 10152
9880 #: rhodecode/templates/pullrequests/pullrequest_show.mako:267
9881 10153 #: rhodecode/templates/pullrequests/pullrequest_show.mako:269
10154 #: rhodecode/templates/pullrequests/pullrequest_show.mako:271
9882 10155 #, python-format
9883 10156 msgid "%d General "
9884 10157 msgstr ""
9885 10158
9886 #: rhodecode/templates/pullrequests/pullrequest_show.mako:273
9887 10159 #: rhodecode/templates/pullrequests/pullrequest_show.mako:275
10160 #: rhodecode/templates/pullrequests/pullrequest_show.mako:277
9888 10161 #, python-format
9889 10162 msgid "%d Inline"
9890 10163 msgstr ""
9891 10164
9892 #: rhodecode/templates/pullrequests/pullrequest_show.mako:279
9893 #: rhodecode/templates/pullrequests/pullrequest_show.mako:283
9894 #, python-format
9895 msgid "%d Outdated"
9896 msgstr ""
9897
9898 #: rhodecode/templates/pullrequests/pullrequest_show.mako:280
9899 msgid "show outdated comments"
9900 msgstr ""
9901
9902 10165 #: rhodecode/templates/pullrequests/pullrequest_show.mako:281
10166 #: rhodecode/templates/pullrequests/pullrequest_show.mako:285
10167 #, python-format
10168 msgid "%d Outdated"
10169 msgstr ""
10170
10171 #: rhodecode/templates/pullrequests/pullrequest_show.mako:282
10172 msgid "show outdated comments"
10173 msgstr ""
10174
10175 #: rhodecode/templates/pullrequests/pullrequest_show.mako:283
9903 10176 msgid "hide outdated comments"
9904 10177 msgstr ""
9905 10178
9906 #: rhodecode/templates/pullrequests/pullrequest_show.mako:292
10179 #: rhodecode/templates/pullrequests/pullrequest_show.mako:294
9907 10180 msgid "Pull request versions not available"
9908 10181 msgstr ""
9909 10182
9910 #: rhodecode/templates/pullrequests/pullrequest_show.mako:306
9911 #: rhodecode/templates/pullrequests/pullrequest_show.mako:391
10183 #: rhodecode/templates/pullrequests/pullrequest_show.mako:308
10184 #: rhodecode/templates/pullrequests/pullrequest_show.mako:393
9912 10185 msgid "Save Changes"
9913 10186 msgstr ""
9914 10187
9915 #: rhodecode/templates/pullrequests/pullrequest_show.mako:408
10188 #: rhodecode/templates/pullrequests/pullrequest_show.mako:410
9916 10189 msgid "Missing requirements:"
9917 10190 msgstr ""
9918 10191
9919 #: rhodecode/templates/pullrequests/pullrequest_show.mako:409
10192 #: rhodecode/templates/pullrequests/pullrequest_show.mako:411
9920 10193 msgid "These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled."
9921 10194 msgstr ""
9922 10195
9923 #: rhodecode/templates/pullrequests/pullrequest_show.mako:417
9924 msgid "Missing commits"
9925 msgstr ""
9926
9927 #: rhodecode/templates/pullrequests/pullrequest_show.mako:418
9928 msgid "This pull request cannot be displayed, because one or more commits no longer exist in the source repository."
9929 msgstr ""
9930
9931 10196 #: rhodecode/templates/pullrequests/pullrequest_show.mako:419
10197 msgid "Missing commits"
10198 msgstr ""
10199
10200 #: rhodecode/templates/pullrequests/pullrequest_show.mako:420
10201 msgid "This pull request cannot be displayed, because one or more commits no longer exist in the source repository."
10202 msgstr ""
10203
10204 #: rhodecode/templates/pullrequests/pullrequest_show.mako:421
9932 10205 msgid "Please update this pull request, push the commits back into the source repository, or consider closing this pull request."
9933 10206 msgstr ""
9934 10207
9935 #: rhodecode/templates/pullrequests/pullrequest_show.mako:430
10208 #: rhodecode/templates/pullrequests/pullrequest_show.mako:422
10209 msgid "Consider doing a {force_refresh_url} in case you think this is an error."
10210 msgstr ""
10211
10212 #: rhodecode/templates/pullrequests/pullrequest_show.mako:433
9936 10213 #, python-format
9937 10214 msgid "Showing changes at v%d, commenting is disabled."
9938 10215 msgstr ""
9939 10216
9940 #: rhodecode/templates/pullrequests/pullrequest_show.mako:453
9941 #: rhodecode/templates/pullrequests/pullrequest_show.mako:455
10217 #: rhodecode/templates/pullrequests/pullrequest_show.mako:456
10218 #: rhodecode/templates/pullrequests/pullrequest_show.mako:458
9942 10219 msgid "Update commits"
9943 10220 msgstr ""
9944 10221
9945 #: rhodecode/templates/pullrequests/pullrequest_show.mako:455
10222 #: rhodecode/templates/pullrequests/pullrequest_show.mako:458
9946 10223 msgid "Update is disabled for current view"
9947 10224 msgstr ""
9948 10225
9949 #: rhodecode/templates/pullrequests/pullrequest_show.mako:466
10226 #: rhodecode/templates/pullrequests/pullrequest_show.mako:469
9950 10227 msgid "Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled"
9951 10228 msgstr ""
9952 10229
9953 #: rhodecode/templates/pullrequests/pullrequest_show.mako:470
10230 #: rhodecode/templates/pullrequests/pullrequest_show.mako:473
9954 10231 msgid "commits added: {}, removed: {}"
9955 10232 msgstr ""
9956 10233
9957 #: rhodecode/templates/pullrequests/pullrequest_show.mako:488
10234 #: rhodecode/templates/pullrequests/pullrequest_show.mako:491
9958 10235 msgid "Commit added in displayed changes"
9959 10236 msgstr ""
9960 10237
9961 #: rhodecode/templates/pullrequests/pullrequest_show.mako:490
10238 #: rhodecode/templates/pullrequests/pullrequest_show.mako:493
9962 10239 msgid "Commit removed in displayed changes"
9963 10240 msgstr ""
9964 10241
9965 #: rhodecode/templates/pullrequests/pullrequest_show.mako:594
9966 msgid "there is {num} general comment from older versions"
9967 msgstr ""
9968
9969 #: rhodecode/templates/pullrequests/pullrequest_show.mako:595
9970 msgid "show it"
9971 msgstr ""
9972
9973 10242 #: rhodecode/templates/pullrequests/pullrequest_show.mako:597
9974 msgid "there are {num} general comments from older versions"
10243 msgid "there is {num} general comment from older versions"
9975 10244 msgstr ""
9976 10245
9977 10246 #: rhodecode/templates/pullrequests/pullrequest_show.mako:598
10247 msgid "show it"
10248 msgstr ""
10249
10250 #: rhodecode/templates/pullrequests/pullrequest_show.mako:600
10251 msgid "there are {num} general comments from older versions"
10252 msgstr ""
10253
10254 #: rhodecode/templates/pullrequests/pullrequest_show.mako:601
9978 10255 msgid "show them"
9979 10256 msgstr ""
9980 10257
@@ -243,9 +243,11 b' class HipchatIntegrationType(Integration'
243 243 @async_task(ignore_result=True, base=RequestContextTask)
244 244 def post_text_to_hipchat(settings, text):
245 245 log.debug('sending %s to hipchat %s' % (text, settings['server_url']))
246 resp = requests.post(settings['server_url'], json={
246 json_message = {
247 247 "message": text,
248 248 "color": settings.get('color', 'yellow'),
249 249 "notify": settings.get('notify', False),
250 })
250 }
251
252 resp = requests.post(settings['server_url'], json=json_message, timeout=60)
251 253 resp.raise_for_status() # raise exception on a failed request
@@ -346,5 +346,5 b' def post_text_to_slack(settings, title, '
346 346 "attachments": [message_data]
347 347 }
348 348
349 resp = requests.post(settings['service'], json=json_message)
349 resp = requests.post(settings['service'], json=json_message, timeout=60)
350 350 resp.raise_for_status() # raise exception on a failed request
@@ -264,7 +264,7 b' def post_to_webhook(url_calls, settings)'
264 264 resp = call_method(url, json={
265 265 'token': token,
266 266 'event': data
267 }, headers=call_headers, auth=auth)
267 }, headers=call_headers, auth=auth, timeout=60)
268 268 log.debug('Got Webhook response: %s', resp)
269 269
270 270 try:
@@ -241,20 +241,24 b' def store(action, user, action_data=None'
241 241 action_name = safe_unicode(action)
242 242 ip_address = safe_unicode(ip_addr)
243 243
244 user_log = _store_log(
245 action_name=action_name,
246 action_data=action_data or {},
247 user_id=user_id,
248 username=username,
249 user_data=user_data or {},
250 ip_address=ip_address,
251 repository_id=repository_id,
252 repository_name=repository_name
253 )
244 with sa_session.no_autoflush:
245 update_user_last_activity(sa_session, user_id)
254 246
255 sa_session.add(user_log)
256 if commit:
257 sa_session.commit()
247 user_log = _store_log(
248 action_name=action_name,
249 action_data=action_data or {},
250 user_id=user_id,
251 username=username,
252 user_data=user_data or {},
253 ip_address=ip_address,
254 repository_id=repository_id,
255 repository_name=repository_name
256 )
257
258 sa_session.add(user_log)
259
260 if commit:
261 sa_session.commit()
258 262
259 263 entry_id = user_log.entry_id or ''
260 264 log.info('AUDIT[%s]: Logging action: `%s` by user:id:%s[%s] ip:%s',
@@ -262,3 +266,14 b' def store(action, user, action_data=None'
262 266
263 267 except Exception:
264 268 log.exception('AUDIT: failed to store audit log')
269
270
271 def update_user_last_activity(sa_session, user_id):
272 _last_activity = datetime.datetime.now()
273 try:
274 sa_session.query(User).filter(User.user_id == user_id).update(
275 {"last_activity": _last_activity})
276 log.debug(
277 'updated user `%s` last activity to:%s', user_id, _last_activity)
278 except Exception:
279 log.exception("Failed last activity update")
@@ -23,6 +23,7 b' authentication and permission libraries'
23 23 """
24 24
25 25 import os
26 import time
26 27 import inspect
27 28 import collections
28 29 import fnmatch
@@ -47,8 +48,8 b' from rhodecode.model.user import UserMod'
47 48 from rhodecode.model.db import (
48 49 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
49 50 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
50 from rhodecode.lib import caches
51 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5
51 from rhodecode.lib import rc_cache
52 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int, sha1
52 53 from rhodecode.lib.utils import (
53 54 get_repo_slug, get_repo_group_slug, get_user_group_slug)
54 55 from rhodecode.lib.caching_query import FromCache
@@ -90,7 +91,7 b' class PasswordGenerator(object):'
90 91 def gen_password(self, length, type_=None):
91 92 if type_ is None:
92 93 type_ = self.ALPHABETS_FULL
93 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
94 self.passwd = ''.join([random.choice(type_) for _ in range(length)])
94 95 return self.passwd
95 96
96 97
@@ -209,12 +210,12 b' class _RhodeCodeCryptoSha256(_RhodeCodeC'
209 210 return hashlib.sha256(password).hexdigest() == hashed
210 211
211 212
212 class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase):
213 class _RhodeCodeCryptoTest(_RhodeCodeCryptoBase):
213 214 ENC_PREF = '_'
214 215
215 216 def hash_create(self, str_):
216 217 self._assert_bytes(str_)
217 return hashlib.md5(str_).hexdigest()
218 return sha1(str_)
218 219
219 220 def hash_check(self, password, hashed):
220 221 """
@@ -224,18 +225,18 b' class _RhodeCodeCryptoMd5(_RhodeCodeCryp'
224 225 :param hashed: password in hashed form
225 226 """
226 227 self._assert_bytes(password)
227 return hashlib.md5(password).hexdigest() == hashed
228 return sha1(password) == hashed
228 229
229 230
230 231 def crypto_backend():
231 232 """
232 233 Return the matching crypto backend.
233 234
234 Selection is based on if we run tests or not, we pick md5 backend to run
235 Selection is based on if we run tests or not, we pick sha1-test backend to run
235 236 tests faster since BCRYPT is expensive to calculate
236 237 """
237 238 if rhodecode.is_test:
238 RhodeCodeCrypto = _RhodeCodeCryptoMd5()
239 RhodeCodeCrypto = _RhodeCodeCryptoTest()
239 240 else:
240 241 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
241 242
@@ -366,23 +367,51 b' class PermOriginDict(dict):'
366 367 self.perm_origin_stack = collections.OrderedDict()
367 368
368 369 def __setitem__(self, key, (perm, origin)):
369 self.perm_origin_stack.setdefault(key, []).append((perm, origin))
370 self.perm_origin_stack.setdefault(key, []).append(
371 (perm, origin))
370 372 dict.__setitem__(self, key, perm)
371 373
372 374
375 class BranchPermOriginDict(PermOriginDict):
376 """
377 Dedicated branch permissions dict, with tracking of patterns and origins.
378
379 >>> perms = BranchPermOriginDict()
380 >>> perms['resource'] = '*pattern', 'read', 'default'
381 >>> perms['resource']
382 {'*pattern': 'read'}
383 >>> perms['resource'] = '*pattern', 'write', 'admin'
384 >>> perms['resource']
385 {'*pattern': 'write'}
386 >>> perms.perm_origin_stack
387 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
388 """
389 def __setitem__(self, key, (pattern, perm, origin)):
390
391 self.perm_origin_stack.setdefault(key, {}) \
392 .setdefault(pattern, []).append((perm, origin))
393
394 if key in self:
395 self[key].__setitem__(pattern, perm)
396 else:
397 patterns = collections.OrderedDict()
398 patterns[pattern] = perm
399 dict.__setitem__(self, key, patterns)
400
401
373 402 class PermissionCalculator(object):
374 403
375 404 def __init__(
376 405 self, user_id, scope, user_is_admin,
377 406 user_inherit_default_permissions, explicit, algo,
378 calculate_super_admin=False):
407 calculate_super_admin_as_user=False):
379 408
380 409 self.user_id = user_id
381 410 self.user_is_admin = user_is_admin
382 411 self.inherit_default_permissions = user_inherit_default_permissions
383 412 self.explicit = explicit
384 413 self.algo = algo
385 self.calculate_super_admin = calculate_super_admin
414 self.calculate_super_admin_as_user = calculate_super_admin_as_user
386 415
387 416 scope = scope or {}
388 417 self.scope_repo_id = scope.get('repo_id')
@@ -394,6 +423,7 b' class PermissionCalculator(object):'
394 423 self.permissions_repositories = PermOriginDict()
395 424 self.permissions_repository_groups = PermOriginDict()
396 425 self.permissions_user_groups = PermOriginDict()
426 self.permissions_repository_branches = BranchPermOriginDict()
397 427 self.permissions_global = set()
398 428
399 429 self.default_repo_perms = Permission.get_default_repo_perms(
@@ -404,19 +434,25 b' class PermissionCalculator(object):'
404 434 Permission.get_default_user_group_perms(
405 435 self.default_user_id, self.scope_user_group_id)
406 436
437 # default branch perms
438 self.default_branch_repo_perms = \
439 Permission.get_default_repo_branch_perms(
440 self.default_user_id, self.scope_repo_id)
441
407 442 def calculate(self):
408 if self.user_is_admin and not self.calculate_super_admin:
409 return self._admin_permissions()
443 if self.user_is_admin and not self.calculate_super_admin_as_user:
444 return self._calculate_admin_permissions()
410 445
411 446 self._calculate_global_default_permissions()
412 447 self._calculate_global_permissions()
413 448 self._calculate_default_permissions()
414 449 self._calculate_repository_permissions()
450 self._calculate_repository_branch_permissions()
415 451 self._calculate_repository_group_permissions()
416 452 self._calculate_user_group_permissions()
417 453 return self._permission_structure()
418 454
419 def _admin_permissions(self):
455 def _calculate_admin_permissions(self):
420 456 """
421 457 admin user have all default rights for repositories
422 458 and groups set to admin
@@ -442,6 +478,13 b' class PermissionCalculator(object):'
442 478 p = 'usergroup.admin'
443 479 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
444 480
481 # branch permissions
482 # since super-admin also can have custom rule permissions
483 # we *always* need to calculate those inherited from default, and also explicit
484 self._calculate_default_permissions_repository_branches(
485 user_inherit_object_permissions=False)
486 self._calculate_repository_branch_permissions()
487
445 488 return self._permission_structure()
446 489
447 490 def _calculate_global_default_permissions(self):
@@ -471,18 +514,14 b' class PermissionCalculator(object):'
471 514 # now we read the defined permissions and overwrite what we have set
472 515 # before those can be configured from groups or users explicitly.
473 516
474 # TODO: johbo: This seems to be out of sync, find out the reason
475 # for the comment below and update it.
476
477 # In case we want to extend this list we should be always in sync with
478 # User.DEFAULT_USER_PERMISSIONS definitions
517 # In case we want to extend this list we should make sure
518 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
479 519 _configurable = frozenset([
480 520 'hg.fork.none', 'hg.fork.repository',
481 521 'hg.create.none', 'hg.create.repository',
482 522 'hg.usergroup.create.false', 'hg.usergroup.create.true',
483 523 'hg.repogroup.create.false', 'hg.repogroup.create.true',
484 'hg.create.write_on_repogroup.false',
485 'hg.create.write_on_repogroup.true',
524 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
486 525 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
487 526 ])
488 527
@@ -505,7 +544,7 b' class PermissionCalculator(object):'
505 544 for gr, perms in _explicit_grouped_perms:
506 545 # since user can be in multiple groups iterate over them and
507 546 # select the lowest permissions first (more explicit)
508 # TODO: marcink: do this^^
547 # TODO(marcink): do this^^
509 548
510 549 # group doesn't inherit default permissions so we actually set them
511 550 if not gr.inherit_default_permissions:
@@ -530,28 +569,7 b' class PermissionCalculator(object):'
530 569 for perm in user_perms:
531 570 self.permissions_global.add(perm.permission.permission_name)
532 571
533 def _calculate_default_permissions(self):
534 """
535 Set default user permissions for repositories, repository groups
536 taken from the default user.
537
538 Calculate inheritance of object permissions based on what we have now
539 in GLOBAL permissions. We check if .false is in GLOBAL since this is
540 explicitly set. Inherit is the opposite of .false being there.
541
542 .. note::
543
544 the syntax is little bit odd but what we need to check here is
545 the opposite of .false permission being in the list so even for
546 inconsistent state when both .true/.false is there
547 .false is more important
548
549 """
550 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
551 in self.permissions_global)
552
553 # defaults for repositories, taken from `default` user permissions
554 # on given repo
572 def _calculate_default_permissions_repositories(self, user_inherit_object_permissions):
555 573 for perm in self.default_repo_perms:
556 574 r_k = perm.UserRepoToPerm.repository.repo_name
557 575 p = perm.Permission.permission_name
@@ -584,8 +602,24 b' class PermissionCalculator(object):'
584 602 o = PermOrigin.SUPER_ADMIN
585 603 self.permissions_repositories[r_k] = p, o
586 604
587 # defaults for repository groups taken from `default` user permission
588 # on given group
605 def _calculate_default_permissions_repository_branches(self, user_inherit_object_permissions):
606 for perm in self.default_branch_repo_perms:
607
608 r_k = perm.UserRepoToPerm.repository.repo_name
609 p = perm.Permission.permission_name
610 pattern = perm.UserToRepoBranchPermission.branch_pattern
611 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
612
613 if not self.explicit:
614 # TODO(marcink): fix this for multiple entries
615 cur_perm = self.permissions_repository_branches.get(r_k) or 'branch.none'
616 p = self._choose_permission(p, cur_perm)
617
618 # NOTE(marcink): register all pattern/perm instances in this
619 # special dict that aggregates entries
620 self.permissions_repository_branches[r_k] = pattern, p, o
621
622 def _calculate_default_permissions_repository_groups(self, user_inherit_object_permissions):
589 623 for perm in self.default_repo_groups_perms:
590 624 rg_k = perm.UserRepoGroupToPerm.group.group_name
591 625 p = perm.Permission.permission_name
@@ -610,8 +644,7 b' class PermissionCalculator(object):'
610 644 o = PermOrigin.SUPER_ADMIN
611 645 self.permissions_repository_groups[rg_k] = p, o
612 646
613 # defaults for user groups taken from `default` user permission
614 # on given user group
647 def _calculate_default_permissions_user_groups(self, user_inherit_object_permissions):
615 648 for perm in self.default_user_group_perms:
616 649 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
617 650 p = perm.Permission.permission_name
@@ -636,6 +669,39 b' class PermissionCalculator(object):'
636 669 o = PermOrigin.SUPER_ADMIN
637 670 self.permissions_user_groups[u_k] = p, o
638 671
672 def _calculate_default_permissions(self):
673 """
674 Set default user permissions for repositories, repository branches,
675 repository groups, user groups taken from the default user.
676
677 Calculate inheritance of object permissions based on what we have now
678 in GLOBAL permissions. We check if .false is in GLOBAL since this is
679 explicitly set. Inherit is the opposite of .false being there.
680
681 .. note::
682
683 the syntax is little bit odd but what we need to check here is
684 the opposite of .false permission being in the list so even for
685 inconsistent state when both .true/.false is there
686 .false is more important
687
688 """
689 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
690 in self.permissions_global)
691
692 # default permissions inherited from `default` user permissions
693 self._calculate_default_permissions_repositories(
694 user_inherit_object_permissions)
695
696 self._calculate_default_permissions_repository_branches(
697 user_inherit_object_permissions)
698
699 self._calculate_default_permissions_repository_groups(
700 user_inherit_object_permissions)
701
702 self._calculate_default_permissions_user_groups(
703 user_inherit_object_permissions)
704
639 705 def _calculate_repository_permissions(self):
640 706 """
641 707 Repository permissions for the current user.
@@ -702,6 +768,49 b' class PermissionCalculator(object):'
702 768 o = PermOrigin.SUPER_ADMIN
703 769 self.permissions_repositories[r_k] = p, o
704 770
771 def _calculate_repository_branch_permissions(self):
772 # user group for repositories permissions
773 user_repo_branch_perms_from_user_group = Permission\
774 .get_default_repo_branch_perms_from_user_group(
775 self.user_id, self.scope_repo_id)
776
777 multiple_counter = collections.defaultdict(int)
778 for perm in user_repo_branch_perms_from_user_group:
779 r_k = perm.UserGroupRepoToPerm.repository.repo_name
780 p = perm.Permission.permission_name
781 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
782 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
783 .users_group.users_group_name
784
785 multiple_counter[r_k] += 1
786 if multiple_counter[r_k] > 1:
787 # TODO(marcink): fix this for multi branch support, and multiple entries
788 cur_perm = self.permissions_repository_branches[r_k]
789 p = self._choose_permission(p, cur_perm)
790
791 self.permissions_repository_branches[r_k] = pattern, p, o
792
793 # user explicit branch permissions for repositories, overrides
794 # any specified by the group permission
795 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
796 self.user_id, self.scope_repo_id)
797
798 for perm in user_repo_branch_perms:
799
800 r_k = perm.UserRepoToPerm.repository.repo_name
801 p = perm.Permission.permission_name
802 pattern = perm.UserToRepoBranchPermission.branch_pattern
803 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
804
805 if not self.explicit:
806 # TODO(marcink): fix this for multiple entries
807 cur_perm = self.permissions_repository_branches.get(r_k) or 'branch.none'
808 p = self._choose_permission(p, cur_perm)
809
810 # NOTE(marcink): register all pattern/perm instances in this
811 # special dict that aggregates entries
812 self.permissions_repository_branches[r_k] = pattern, p, o
813
705 814 def _calculate_repository_group_permissions(self):
706 815 """
707 816 Repository group permissions for the current user.
@@ -844,6 +953,7 b' class PermissionCalculator(object):'
844 953 return {
845 954 'global': self.permissions_global,
846 955 'repositories': self.permissions_repositories,
956 'repository_branches': self.permissions_repository_branches,
847 957 'repositories_groups': self.permissions_repository_groups,
848 958 'user_groups': self.permissions_user_groups,
849 959 }
@@ -937,30 +1047,33 b' class AuthUser(object):'
937 1047
938 1048 @LazyProperty
939 1049 def permissions(self):
940 return self.get_perms(user=self, cache=False)
1050 return self.get_perms(user=self, cache=None)
941 1051
942 1052 @LazyProperty
943 1053 def permissions_safe(self):
944 1054 """
945 1055 Filtered permissions excluding not allowed repositories
946 1056 """
947 perms = self.get_perms(user=self, cache=False)
1057 perms = self.get_perms(user=self, cache=None)
948 1058
949 1059 perms['repositories'] = {
950 k: v for k, v in perms['repositories'].iteritems()
1060 k: v for k, v in perms['repositories'].items()
951 1061 if v != 'repository.none'}
952 1062 perms['repositories_groups'] = {
953 k: v for k, v in perms['repositories_groups'].iteritems()
1063 k: v for k, v in perms['repositories_groups'].items()
954 1064 if v != 'group.none'}
955 1065 perms['user_groups'] = {
956 k: v for k, v in perms['user_groups'].iteritems()
1066 k: v for k, v in perms['user_groups'].items()
957 1067 if v != 'usergroup.none'}
1068 perms['repository_branches'] = {
1069 k: v for k, v in perms['repository_branches'].iteritems()
1070 if v != 'branch.none'}
958 1071 return perms
959 1072
960 1073 @LazyProperty
961 1074 def permissions_full_details(self):
962 1075 return self.get_perms(
963 user=self, cache=False, calculate_super_admin=True)
1076 user=self, cache=None, calculate_super_admin=True)
964 1077
965 1078 def permissions_with_scope(self, scope):
966 1079 """
@@ -975,29 +1088,22 b' class AuthUser(object):'
975 1088 obj = Repository.get_by_repo_name(scope['repo_name'])
976 1089 if obj:
977 1090 scope['repo_id'] = obj.repo_id
978 _scope = {
979 'repo_id': -1,
980 'user_group_id': -1,
981 'repo_group_id': -1,
982 }
983 _scope.update(scope)
984 cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b,
985 _scope.items())))
986 if cache_key not in self._permissions_scoped_cache:
987 # store in cache to mimic how the @LazyProperty works,
988 # the difference here is that we use the unique key calculated
989 # from params and values
990 res = self.get_perms(user=self, cache=False, scope=_scope)
991 self._permissions_scoped_cache[cache_key] = res
992 return self._permissions_scoped_cache[cache_key]
1091 _scope = collections.OrderedDict()
1092 _scope['repo_id'] = -1
1093 _scope['user_group_id'] = -1
1094 _scope['repo_group_id'] = -1
1095
1096 for k in sorted(scope.keys()):
1097 _scope[k] = scope[k]
1098
1099 # store in cache to mimic how the @LazyProperty works,
1100 # the difference here is that we use the unique key calculated
1101 # from params and values
1102 return self.get_perms(user=self, cache=None, scope=_scope)
993 1103
994 1104 def get_instance(self):
995 1105 return User.get(self.user_id)
996 1106
997 def update_lastactivity(self):
998 if self.user_id:
999 User.get(self.user_id).update_lastactivity()
1000
1001 1107 def propagate_data(self):
1002 1108 """
1003 1109 Fills in user data and propagates values to this instance. Maps fetched
@@ -1048,7 +1154,7 b' class AuthUser(object):'
1048 1154 log.debug('AuthUser: propagated user is now %s', self)
1049 1155
1050 1156 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1051 calculate_super_admin=False, cache=False):
1157 calculate_super_admin=False, cache=None):
1052 1158 """
1053 1159 Fills user permission attribute with permissions taken from database
1054 1160 works for permissions given for repositories, and for permissions that
@@ -1063,6 +1169,9 b' class AuthUser(object):'
1063 1169 it's multiple defined, eg user in two different groups. It also
1064 1170 decides if explicit flag is turned off how to specify the permission
1065 1171 for case when user is in a group + have defined separate permission
1172 :param calculate_super_admin: calculate permissions for super-admin in the
1173 same way as for regular user without speedups
1174 :param cache: Use caching for calculation, None = let the cache backend decide
1066 1175 """
1067 1176 user_id = user.user_id
1068 1177 user_is_admin = user.is_admin
@@ -1070,19 +1179,44 b' class AuthUser(object):'
1070 1179 # inheritance of global permissions like create repo/fork repo etc
1071 1180 user_inherit_default_permissions = user.inherit_default_permissions
1072 1181
1073 log.debug('Computing PERMISSION tree for scope %s' % (scope, ))
1074 compute = caches.conditional_cache(
1075 'short_term', 'cache_desc',
1076 condition=cache, func=_cached_perms_data)
1077 result = compute(user_id, scope, user_is_admin,
1078 user_inherit_default_permissions, explicit, algo,
1079 calculate_super_admin)
1182 cache_seconds = safe_int(
1183 rhodecode.CONFIG.get('rc_cache.cache_perms.expiration_time'))
1184
1185 if cache is None:
1186 # let the backend cache decide
1187 cache_on = cache_seconds > 0
1188 else:
1189 cache_on = cache
1190
1191 log.debug(
1192 'Computing PERMISSION tree for user %s scope `%s` '
1193 'with caching: %s[TTL: %ss]' % (user, scope, cache_on, cache_seconds or 0))
1194
1195 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
1196 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1197
1198 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
1199 condition=cache_on)
1200 def compute_perm_tree(cache_name,
1201 user_id, scope, user_is_admin,user_inherit_default_permissions,
1202 explicit, algo, calculate_super_admin):
1203 return _cached_perms_data(
1204 user_id, scope, user_is_admin, user_inherit_default_permissions,
1205 explicit, algo, calculate_super_admin)
1206
1207 start = time.time()
1208 result = compute_perm_tree(
1209 'permissions', user_id, scope, user_is_admin,
1210 user_inherit_default_permissions, explicit, algo,
1211 calculate_super_admin)
1080 1212
1081 1213 result_repr = []
1082 1214 for k in result:
1083 1215 result_repr.append((k, len(result[k])))
1084
1085 log.debug('PERMISSION tree computed %s' % (result_repr,))
1216 total = time.time() - start
1217 log.debug('PERMISSION tree for user %s computed in %.3fs: %s' % (
1218 user, total, result_repr))
1219
1086 1220 return result
1087 1221
1088 1222 @property
@@ -1103,7 +1237,7 b' class AuthUser(object):'
1103 1237 Returns list of repositories you're an admin of
1104 1238 """
1105 1239 return [
1106 x[0] for x in self.permissions['repositories'].iteritems()
1240 x[0] for x in self.permissions['repositories'].items()
1107 1241 if x[1] == 'repository.admin']
1108 1242
1109 1243 @property
@@ -1112,7 +1246,7 b' class AuthUser(object):'
1112 1246 Returns list of repository groups you're an admin of
1113 1247 """
1114 1248 return [
1115 x[0] for x in self.permissions['repositories_groups'].iteritems()
1249 x[0] for x in self.permissions['repositories_groups'].items()
1116 1250 if x[1] == 'group.admin']
1117 1251
1118 1252 @property
@@ -1121,7 +1255,7 b' class AuthUser(object):'
1121 1255 Returns list of user groups you're an admin of
1122 1256 """
1123 1257 return [
1124 x[0] for x in self.permissions['user_groups'].iteritems()
1258 x[0] for x in self.permissions['user_groups'].items()
1125 1259 if x[1] == 'usergroup.admin']
1126 1260
1127 1261 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
@@ -1135,20 +1269,17 b' class AuthUser(object):'
1135 1269 perms = [
1136 1270 'repository.read', 'repository.write', 'repository.admin']
1137 1271
1138 def _cached_repo_acl(user_id, perm_def, name_filter):
1272 def _cached_repo_acl(user_id, perm_def, _name_filter):
1139 1273 qry = Repository.query()
1140 if name_filter:
1141 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1274 if _name_filter:
1275 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1142 1276 qry = qry.filter(
1143 1277 Repository.repo_name.ilike(ilike_expression))
1144 1278
1145 1279 return [x.repo_id for x in
1146 1280 RepoList(qry, perm_set=perm_def)]
1147 1281
1148 compute = caches.conditional_cache(
1149 'long_term', 'repo_acl_ids',
1150 condition=cache, func=_cached_repo_acl)
1151 return compute(self.user_id, perms, name_filter)
1282 return _cached_repo_acl(self.user_id, perms, name_filter)
1152 1283
1153 1284 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1154 1285 """
@@ -1161,20 +1292,17 b' class AuthUser(object):'
1161 1292 perms = [
1162 1293 'group.read', 'group.write', 'group.admin']
1163 1294
1164 def _cached_repo_group_acl(user_id, perm_def, name_filter):
1295 def _cached_repo_group_acl(user_id, perm_def, _name_filter):
1165 1296 qry = RepoGroup.query()
1166 if name_filter:
1167 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1297 if _name_filter:
1298 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1168 1299 qry = qry.filter(
1169 1300 RepoGroup.group_name.ilike(ilike_expression))
1170 1301
1171 1302 return [x.group_id for x in
1172 1303 RepoGroupList(qry, perm_set=perm_def)]
1173 1304
1174 compute = caches.conditional_cache(
1175 'long_term', 'repo_group_acl_ids',
1176 condition=cache, func=_cached_repo_group_acl)
1177 return compute(self.user_id, perms, name_filter)
1305 return _cached_repo_group_acl(self.user_id, perms, name_filter)
1178 1306
1179 1307 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1180 1308 """
@@ -1197,10 +1325,7 b' class AuthUser(object):'
1197 1325 return [x.users_group_id for x in
1198 1326 UserGroupList(qry, perm_set=perm_def)]
1199 1327
1200 compute = caches.conditional_cache(
1201 'long_term', 'user_group_acl_ids',
1202 condition=cache, func=_cached_user_group_acl)
1203 return compute(self.user_id, perms, name_filter)
1328 return _cached_user_group_acl(self.user_id, perms, name_filter)
1204 1329
1205 1330 @property
1206 1331 def ip_allowed(self):
@@ -1227,13 +1352,42 b' class AuthUser(object):'
1227 1352 allowed_ips = AuthUser.get_allowed_ips(
1228 1353 user_id, cache=True, inherit_from_default=inherit_from_default)
1229 1354 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1230 log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
1355 log.debug('IP:%s for user %s is in range of %s' % (
1356 ip_addr, user_id, allowed_ips))
1231 1357 return True
1232 1358 else:
1233 log.info('Access for IP:%s forbidden, '
1234 'not in %s' % (ip_addr, allowed_ips))
1359 log.info('Access for IP:%s forbidden for user %s, '
1360 'not in %s' % (ip_addr, user_id, allowed_ips))
1235 1361 return False
1236 1362
1363 def get_branch_permissions(self, repo_name, perms=None):
1364 perms = perms or self.permissions_with_scope({'repo_name': repo_name})
1365 branch_perms = perms.get('repository_branches', {})
1366 if not branch_perms:
1367 return {}
1368 repo_branch_perms = branch_perms.get(repo_name)
1369 return repo_branch_perms or {}
1370
1371 def get_rule_and_branch_permission(self, repo_name, branch_name):
1372 """
1373 Check if this AuthUser has defined any permissions for branches. If any of
1374 the rules match in order, we return the matching permissions
1375 """
1376
1377 rule = default_perm = ''
1378
1379 repo_branch_perms = self.get_branch_permissions(repo_name=repo_name)
1380 if not repo_branch_perms:
1381 return rule, default_perm
1382
1383 # now calculate the permissions
1384 for pattern, branch_perm in repo_branch_perms.items():
1385 if fnmatch.fnmatch(branch_name, pattern):
1386 rule = '`{}`=>{}'.format(pattern, branch_perm)
1387 return rule, branch_perm
1388
1389 return rule, default_perm
1390
1237 1391 def __repr__(self):
1238 1392 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1239 1393 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
@@ -1268,8 +1422,8 b' class AuthUser(object):'
1268 1422 _set = set()
1269 1423
1270 1424 if inherit_from_default:
1271 default_ips = UserIpMap.query().filter(
1272 UserIpMap.user == User.get_default_user(cache=True))
1425 def_user_id = User.get_default_user(cache=True).user_id
1426 default_ips = UserIpMap.query().filter(UserIpMap.user_id == def_user_id)
1273 1427 if cache:
1274 1428 default_ips = default_ips.options(
1275 1429 FromCache("sql_cache_short", "get_user_ips_default"))
@@ -1283,10 +1437,15 b' class AuthUser(object):'
1283 1437 # we get deleted objects here, we just skip them
1284 1438 pass
1285 1439
1286 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1287 if cache:
1288 user_ips = user_ips.options(
1289 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1440 # NOTE:(marcink) we don't want to load any rules for empty
1441 # user_id which is the case of access of non logged users when anonymous
1442 # access is disabled
1443 user_ips = []
1444 if user_id:
1445 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1446 if cache:
1447 user_ips = user_ips.options(
1448 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1290 1449
1291 1450 for ip in user_ips:
1292 1451 try:
@@ -1295,7 +1454,7 b' class AuthUser(object):'
1295 1454 # since we use heavy caching sometimes it happens that we get
1296 1455 # deleted objects here, we just skip them
1297 1456 pass
1298 return _set or set(['0.0.0.0/0', '::/0'])
1457 return _set or {ip for ip in ['0.0.0.0/0', '::/0']}
1299 1458
1300 1459
1301 1460 def set_available_permissions(settings):
@@ -1486,9 +1645,6 b' class LoginRequired(object):'
1486 1645 'user %s authenticating with:%s IS authenticated on func %s'
1487 1646 % (user, reason, loc))
1488 1647
1489 # update user data to check last activity
1490 user.update_lastactivity()
1491 Session().commit()
1492 1648 return func(*fargs, **fkwargs)
1493 1649 else:
1494 1650 log.warning(
@@ -1627,7 +1783,7 b' class HasRepoPermissionAllDecorator(Perm'
1627 1783 repo_name = self._get_repo_name()
1628 1784
1629 1785 try:
1630 user_perms = set([perms['repositories'][repo_name]])
1786 user_perms = {perms['repositories'][repo_name]}
1631 1787 except KeyError:
1632 1788 log.debug('cannot locate repo with name: `%s` in permissions defs',
1633 1789 repo_name)
@@ -1654,7 +1810,7 b' class HasRepoPermissionAnyDecorator(Perm'
1654 1810 repo_name = self._get_repo_name()
1655 1811
1656 1812 try:
1657 user_perms = set([perms['repositories'][repo_name]])
1813 user_perms = {perms['repositories'][repo_name]}
1658 1814 except KeyError:
1659 1815 log.debug(
1660 1816 'cannot locate repo with name: `%s` in permissions defs',
@@ -1682,7 +1838,7 b' class HasRepoGroupPermissionAllDecorator'
1682 1838 perms = user.permissions
1683 1839 group_name = self._get_repo_group_name()
1684 1840 try:
1685 user_perms = set([perms['repositories_groups'][group_name]])
1841 user_perms = {perms['repositories_groups'][group_name]}
1686 1842 except KeyError:
1687 1843 log.debug(
1688 1844 'cannot locate repo group with name: `%s` in permissions defs',
@@ -1711,7 +1867,7 b' class HasRepoGroupPermissionAnyDecorator'
1711 1867 group_name = self._get_repo_group_name()
1712 1868
1713 1869 try:
1714 user_perms = set([perms['repositories_groups'][group_name]])
1870 user_perms = {perms['repositories_groups'][group_name]}
1715 1871 except KeyError:
1716 1872 log.debug(
1717 1873 'cannot locate repo group with name: `%s` in permissions defs',
@@ -1738,7 +1894,7 b' class HasUserGroupPermissionAllDecorator'
1738 1894 perms = user.permissions
1739 1895 group_name = self._get_user_group_name()
1740 1896 try:
1741 user_perms = set([perms['user_groups'][group_name]])
1897 user_perms = {perms['user_groups'][group_name]}
1742 1898 except KeyError:
1743 1899 return False
1744 1900
@@ -1760,7 +1916,7 b' class HasUserGroupPermissionAnyDecorator'
1760 1916 perms = user.permissions
1761 1917 group_name = self._get_user_group_name()
1762 1918 try:
1763 user_perms = set([perms['user_groups'][group_name]])
1919 user_perms = {perms['user_groups'][group_name]}
1764 1920 except KeyError:
1765 1921 return False
1766 1922
@@ -1793,7 +1949,6 b' class PermsFunction(object):'
1793 1949 def __call__(self, check_location='', user=None):
1794 1950 if not user:
1795 1951 log.debug('Using user attribute from global request')
1796 # TODO: remove this someday,put as user as attribute here
1797 1952 request = self._get_request()
1798 1953 user = request.user
1799 1954
@@ -1873,7 +2028,7 b' class HasRepoPermissionAll(PermsFunction'
1873 2028 self.repo_name = self._get_repo_name()
1874 2029 perms = user.permissions
1875 2030 try:
1876 user_perms = set([perms['repositories'][self.repo_name]])
2031 user_perms = {perms['repositories'][self.repo_name]}
1877 2032 except KeyError:
1878 2033 return False
1879 2034 if self.required_perms.issubset(user_perms):
@@ -1896,7 +2051,7 b' class HasRepoPermissionAny(PermsFunction'
1896 2051 self.repo_name = self._get_repo_name()
1897 2052 perms = user.permissions
1898 2053 try:
1899 user_perms = set([perms['repositories'][self.repo_name]])
2054 user_perms = {perms['repositories'][self.repo_name]}
1900 2055 except KeyError:
1901 2056 return False
1902 2057 if self.required_perms.intersection(user_perms):
@@ -1913,8 +2068,7 b' class HasRepoGroupPermissionAny(PermsFun'
1913 2068 def check_permissions(self, user):
1914 2069 perms = user.permissions
1915 2070 try:
1916 user_perms = set(
1917 [perms['repositories_groups'][self.repo_group_name]])
2071 user_perms = {perms['repositories_groups'][self.repo_group_name]}
1918 2072 except KeyError:
1919 2073 return False
1920 2074 if self.required_perms.intersection(user_perms):
@@ -1931,8 +2085,7 b' class HasRepoGroupPermissionAll(PermsFun'
1931 2085 def check_permissions(self, user):
1932 2086 perms = user.permissions
1933 2087 try:
1934 user_perms = set(
1935 [perms['repositories_groups'][self.repo_group_name]])
2088 user_perms = {perms['repositories_groups'][self.repo_group_name]}
1936 2089 except KeyError:
1937 2090 return False
1938 2091 if self.required_perms.issubset(user_perms):
@@ -1949,7 +2102,7 b' class HasUserGroupPermissionAny(PermsFun'
1949 2102 def check_permissions(self, user):
1950 2103 perms = user.permissions
1951 2104 try:
1952 user_perms = set([perms['user_groups'][self.user_group_name]])
2105 user_perms = {perms['user_groups'][self.user_group_name]}
1953 2106 except KeyError:
1954 2107 return False
1955 2108 if self.required_perms.intersection(user_perms):
@@ -1966,7 +2119,7 b' class HasUserGroupPermissionAll(PermsFun'
1966 2119 def check_permissions(self, user):
1967 2120 perms = user.permissions
1968 2121 try:
1969 user_perms = set([perms['user_groups'][self.user_group_name]])
2122 user_perms = {perms['user_groups'][self.user_group_name]}
1970 2123 except KeyError:
1971 2124 return False
1972 2125 if self.required_perms.issubset(user_perms):
@@ -1979,30 +2132,29 b' class HasPermissionAnyMiddleware(object)'
1979 2132 def __init__(self, *perms):
1980 2133 self.required_perms = set(perms)
1981 2134
1982 def __call__(self, user, repo_name):
2135 def __call__(self, auth_user, repo_name):
1983 2136 # repo_name MUST be unicode, since we handle keys in permission
1984 2137 # dict by unicode
1985 2138 repo_name = safe_unicode(repo_name)
1986 user = AuthUser(user.user_id)
1987 2139 log.debug(
1988 2140 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1989 self.required_perms, user, repo_name)
1990
1991 if self.check_permissions(user, repo_name):
2141 self.required_perms, auth_user, repo_name)
2142
2143 if self.check_permissions(auth_user, repo_name):
1992 2144 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1993 repo_name, user, 'PermissionMiddleware')
2145 repo_name, auth_user, 'PermissionMiddleware')
1994 2146 return True
1995 2147
1996 2148 else:
1997 2149 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1998 repo_name, user, 'PermissionMiddleware')
2150 repo_name, auth_user, 'PermissionMiddleware')
1999 2151 return False
2000 2152
2001 2153 def check_permissions(self, user, repo_name):
2002 2154 perms = user.permissions_with_scope({'repo_name': repo_name})
2003 2155
2004 2156 try:
2005 user_perms = set([perms['repositories'][repo_name]])
2157 user_perms = {perms['repositories'][repo_name]}
2006 2158 except Exception:
2007 2159 log.exception('Error while accessing user permissions')
2008 2160 return False
@@ -2085,7 +2237,7 b' class HasRepoPermissionAllApi(_BaseApiPe'
2085 2237 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2086 2238 user_group_name=None):
2087 2239 try:
2088 _user_perms = set([perm_defs['repositories'][repo_name]])
2240 _user_perms = {perm_defs['repositories'][repo_name]}
2089 2241 except KeyError:
2090 2242 log.warning(traceback.format_exc())
2091 2243 return False
@@ -2098,7 +2250,7 b' class HasRepoPermissionAnyApi(_BaseApiPe'
2098 2250 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2099 2251 user_group_name=None):
2100 2252 try:
2101 _user_perms = set([perm_defs['repositories'][repo_name]])
2253 _user_perms = {perm_defs['repositories'][repo_name]}
2102 2254 except KeyError:
2103 2255 log.warning(traceback.format_exc())
2104 2256 return False
@@ -2111,7 +2263,7 b' class HasRepoGroupPermissionAnyApi(_Base'
2111 2263 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2112 2264 user_group_name=None):
2113 2265 try:
2114 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2266 _user_perms = {perm_defs['repositories_groups'][group_name]}
2115 2267 except KeyError:
2116 2268 log.warning(traceback.format_exc())
2117 2269 return False
@@ -2124,7 +2276,7 b' class HasRepoGroupPermissionAllApi(_Base'
2124 2276 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2125 2277 user_group_name=None):
2126 2278 try:
2127 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2279 _user_perms = {perm_defs['repositories_groups'][group_name]}
2128 2280 except KeyError:
2129 2281 log.warning(traceback.format_exc())
2130 2282 return False
@@ -2137,7 +2289,7 b' class HasUserGroupPermissionAnyApi(_Base'
2137 2289 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2138 2290 user_group_name=None):
2139 2291 try:
2140 _user_perms = set([perm_defs['user_groups'][user_group_name]])
2292 _user_perms = {perm_defs['user_groups'][user_group_name]}
2141 2293 except KeyError:
2142 2294 log.warning(traceback.format_exc())
2143 2295 return False
@@ -42,7 +42,7 b' from rhodecode.lib.auth import AuthUser,'
42 42 from rhodecode.lib.exceptions import UserCreationError
43 43 from rhodecode.lib.utils import (password_changed, get_enabled_hook_classes)
44 44 from rhodecode.lib.utils2 import (
45 str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist, safe_str)
45 str2bool, safe_unicode, AttributeDict, safe_int, sha1, aslist, safe_str)
46 46 from rhodecode.model.db import Repository, User, ChangesetComment
47 47 from rhodecode.model.notification import NotificationModel
48 48 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
@@ -153,7 +153,7 b' def get_user_agent(environ):'
153 153
154 154 def vcs_operation_context(
155 155 environ, repo_name, username, action, scm, check_locking=True,
156 is_shadow_repo=False):
156 is_shadow_repo=False, check_branch_perms=False, detect_force_push=False):
157 157 """
158 158 Generate the context for a vcs operation, e.g. push or pull.
159 159
@@ -179,7 +179,9 b' def vcs_operation_context('
179 179 settings_model = VcsSettingsModel(repo=repo_name)
180 180 ui_settings = settings_model.get_ui_settings()
181 181
182 extras = {
182 # NOTE(marcink): This should be also in sync with
183 # rhodecode/apps/ssh_support/lib/backends/base.py:update_enviroment scm_data
184 scm_data = {
183 185 'ip': get_ip_addr(environ),
184 186 'username': username,
185 187 'user_id': user_id,
@@ -193,8 +195,10 b' def vcs_operation_context('
193 195 'user_agent': get_user_agent(environ),
194 196 'hooks': get_enabled_hook_classes(ui_settings),
195 197 'is_shadow_repo': is_shadow_repo,
198 'detect_force_push': detect_force_push,
199 'check_branch_perms': check_branch_perms,
196 200 }
197 return extras
201 return scm_data
198 202
199 203
200 204 class BasicAuth(AuthBasicAuthenticator):
@@ -256,7 +260,7 b' class BasicAuth(AuthBasicAuthenticator):'
256 260
257 261
258 262 def calculate_version_hash(config):
259 return md5(
263 return sha1(
260 264 config.get('beaker.session.secret', '') +
261 265 rhodecode.__version__)[:8]
262 266
@@ -504,7 +508,7 b' def bootstrap_config(request):'
504 508 # allow pyramid lookup in testing
505 509 config.include('pyramid_mako')
506 510 config.include('pyramid_beaker')
507 config.include('rhodecode.lib.caches')
511 config.include('rhodecode.lib.rc_cache')
508 512
509 513 add_events_routes(config)
510 514
@@ -18,16 +18,16 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 """
22 caching_query.py
21 """caching_query.py
23 22
24 Represent persistence structures which allow the usage of
25 Beaker caching with SQLAlchemy.
23 Represent functions and classes
24 which allow the usage of Dogpile caching with SQLAlchemy.
25 Introduces a query option called FromCache.
26 26
27 27 The three new concepts introduced here are:
28 28
29 29 * CachingQuery - a Query subclass that caches and
30 retrieves results in/from Beaker.
30 retrieves results in/from dogpile.cache.
31 31 * FromCache - a query option that establishes caching
32 32 parameters on a Query
33 33 * RelationshipCache - a variant of FromCache which is specific
@@ -36,57 +36,44 b' The three new concepts introduced here a'
36 36 a Query.
37 37
38 38 The rest of what's here are standard SQLAlchemy and
39 Beaker constructs.
39 dogpile.cache constructs.
40 40
41 41 """
42 import beaker
43 from beaker.exceptions import BeakerException
44
45 42 from sqlalchemy.orm.interfaces import MapperOption
46 43 from sqlalchemy.orm.query import Query
47 44 from sqlalchemy.sql import visitors
45 from dogpile.cache.api import NO_VALUE
48 46
49 47 from rhodecode.lib.utils2 import safe_str
50 48
51 49
52 50 class CachingQuery(Query):
53 """A Query subclass which optionally loads full results from a Beaker
51 """A Query subclass which optionally loads full results from a dogpile
54 52 cache region.
55 53
56 The CachingQuery stores additional state that allows it to consult
57 a Beaker cache before accessing the database:
58
59 * A "region", which is a cache region argument passed to a
60 Beaker CacheManager, specifies a particular cache configuration
61 (including backend implementation, expiration times, etc.)
62 * A "namespace", which is a qualifying name that identifies a
63 group of keys within the cache. A query that filters on a name
64 might use the name "by_name", a query that filters on a date range
65 to a joined table might use the name "related_date_range".
66
67 When the above state is present, a Beaker cache is retrieved.
68
69 The "namespace" name is first concatenated with
70 a string composed of the individual entities and columns the Query
71 requests, i.e. such as ``Query(User.id, User.name)``.
72
73 The Beaker cache is then loaded from the cache manager based
74 on the region and composed namespace. The key within the cache
75 itself is then constructed against the bind parameters specified
76 by this query, which are usually literals defined in the
77 WHERE clause.
54 The CachingQuery optionally stores additional state that allows it to consult
55 a dogpile.cache cache before accessing the database, in the form
56 of a FromCache or RelationshipCache object. Each of these objects
57 refer to the name of a :class:`dogpile.cache.Region` that's been configured
58 and stored in a lookup dictionary. When such an object has associated
59 itself with the CachingQuery, the corresponding :class:`dogpile.cache.Region`
60 is used to locate a cached result. If none is present, then the
61 Query is invoked normally, the results being cached.
78 62
79 63 The FromCache and RelationshipCache mapper options below represent
80 64 the "public" method of configuring this state upon the CachingQuery.
81 65
82 66 """
67 def _get_region(self):
68 from rhodecode.lib.rc_cache import region_meta
69 return region_meta.dogpile_cache_regions
83 70
84 def __init__(self, manager, *args, **kw):
85 self.cache_manager = manager
71 def __init__(self, regions, *args, **kw):
72 self.cache_regions = regions or self._get_region()
86 73 Query.__init__(self, *args, **kw)
87 74
88 75 def __iter__(self):
89 """override __iter__ to pull results from Beaker
76 """override __iter__ to pull results from dogpile
90 77 if particular attributes have been configured.
91 78
92 79 Note that this approach does *not* detach the loaded objects from
@@ -98,109 +85,121 b' class CachingQuery(Query):'
98 85 in the cache are not the same ones in the current Session.
99 86
100 87 """
101 if hasattr(self, '_cache_parameters'):
88 super_ = super(CachingQuery, self)
89
90 if hasattr(self, '_cache_region'):
91 return self.get_value(createfunc=lambda: list(super_.__iter__()))
92 else:
93 return super_.__iter__()
94
95 def _execute_and_instances(self, context):
96 """override _execute_and_instances to pull results from dogpile
97 if the query is invoked directly from an external context.
98
99 This method is necessary in order to maintain compatibility
100 with the "baked query" system now used by default in some
101 relationship loader scenarios. Note also the
102 RelationshipCache._generate_cache_key method which enables
103 the baked query to be used within lazy loads.
102 104
103 def caching_query():
104 return list(Query.__iter__(self))
105 .. versionadded:: 1.2.7
106 """
107 super_ = super(CachingQuery, self)
105 108
106 return self.get_value(createfunc=caching_query)
109 if context.query is not self and hasattr(self, '_cache_region'):
110 # special logic called when the Query._execute_and_instances()
111 # method is called directly from the baked query
112 return self.get_value(
113 createfunc=lambda: list(
114 super_._execute_and_instances(context)
115 )
116 )
107 117 else:
108 return Query.__iter__(self)
118 return super_._execute_and_instances(context)
119
120 def _get_cache_plus_key(self):
121 """Return a cache region plus key."""
122 dogpile_region = self.cache_regions[self._cache_region.region]
123 if self._cache_region.cache_key:
124 key = self._cache_region.cache_key
125 else:
126 key = _key_from_query(self)
127 return dogpile_region, key
109 128
110 129 def invalidate(self):
111 """Invalidate the value represented by this Query."""
130 """Invalidate the cache value represented by this Query."""
112 131
113 cache, cache_key = _get_cache_parameters(self)
114 cache.remove(cache_key)
132 dogpile_region, cache_key = self._get_cache_plus_key()
133 dogpile_region.delete(cache_key)
115 134
116 def get_value(self, merge=True, createfunc=None):
135 def get_value(self, merge=True, createfunc=None,
136 expiration_time=None, ignore_expiration=False):
117 137 """Return the value from the cache for this query.
118 138
119 139 Raise KeyError if no value present and no
120 140 createfunc specified.
121 141
122 142 """
123 cache, cache_key = _get_cache_parameters(self)
124 ret = cache.get_value(cache_key, createfunc=createfunc)
143 dogpile_region, cache_key = self._get_cache_plus_key()
144
145 # ignore_expiration means, if the value is in the cache
146 # but is expired, return it anyway. This doesn't make sense
147 # with createfunc, which says, if the value is expired, generate
148 # a new value.
149 assert not ignore_expiration or not createfunc, \
150 "Can't ignore expiration and also provide createfunc"
151
152 if ignore_expiration or not createfunc:
153 cached_value = dogpile_region.get(cache_key,
154 expiration_time=expiration_time,
155 ignore_expiration=ignore_expiration)
156 else:
157 cached_value = dogpile_region.get_or_create(
158 cache_key,
159 createfunc,
160 expiration_time=expiration_time
161 )
162 if cached_value is NO_VALUE:
163 raise KeyError(cache_key)
125 164 if merge:
126 ret = self.merge_result(ret, load=False)
127 return ret
165 cached_value = self.merge_result(cached_value, load=False)
166 return cached_value
128 167
129 168 def set_value(self, value):
130 169 """Set the value in the cache for this query."""
131 170
132 cache, cache_key = _get_cache_parameters(self)
133 cache.put(cache_key, value)
171 dogpile_region, cache_key = self._get_cache_plus_key()
172 dogpile_region.set(cache_key, value)
134 173
135 174
136 def query_callable(manager, query_cls=CachingQuery):
175 def query_callable(regions=None, query_cls=CachingQuery):
137 176 def query(*arg, **kw):
138 return query_cls(manager, *arg, **kw)
177 return query_cls(regions, *arg, **kw)
139 178 return query
140 179
141 180
142 def get_cache_region(name, region):
143 if region not in beaker.cache.cache_regions:
144 raise BeakerException('Cache region `%s` not configured '
145 'Check if proper cache settings are in the .ini files' % region)
146 kw = beaker.cache.cache_regions[region]
147 return beaker.cache.Cache._get_cache(name, kw)
181 def _key_from_query(query, qualifier=None):
182 """Given a Query, create a cache key.
148 183
149
150 def _get_cache_parameters(query):
151 """For a query with cache_region and cache_namespace configured,
152 return the correspoinding Cache instance and cache key, based
153 on this query's current criterion and parameter values.
184 There are many approaches to this; here we use the simplest,
185 which is to create an md5 hash of the text of the SQL statement,
186 combined with stringified versions of all the bound parameters
187 within it. There's a bit of a performance hit with
188 compiling out "query.statement" here; other approaches include
189 setting up an explicit cache key with a particular Query,
190 then combining that with the bound parameter values.
154 191
155 192 """
156 if not hasattr(query, '_cache_parameters'):
157 raise ValueError("This Query does not have caching "
158 "parameters configured.")
159 193
160 region, namespace, cache_key = query._cache_parameters
161
162 namespace = _namespace_from_query(namespace, query)
163
164 if cache_key is None:
165 # cache key - the value arguments from this query's parameters.
166 args = [safe_str(x) for x in _params_from_query(query)]
167 args.extend(filter(lambda k: k not in ['None', None, u'None'],
168 [str(query._limit), str(query._offset)]))
169
170 cache_key = " ".join(args)
171
172 if cache_key is None:
173 raise Exception('Cache key cannot be None')
194 stmt = query.with_labels().statement
195 compiled = stmt.compile()
196 params = compiled.params
174 197
175 # get cache
176 #cache = query.cache_manager.get_cache_region(namespace, region)
177 cache = get_cache_region(namespace, region)
178 # optional - hash the cache_key too for consistent length
179 # import uuid
180 # cache_key= str(uuid.uuid5(uuid.NAMESPACE_DNS, cache_key))
181
182 return cache, cache_key
183
184
185 def _namespace_from_query(namespace, query):
186 # cache namespace - the token handed in by the
187 # option + class we're querying against
188 namespace = " ".join([namespace] + [str(x) for x in query._entities])
189
190 # memcached wants this
191 namespace = namespace.replace(' ', '_')
192
193 return namespace
194
195
196 def _set_cache_parameters(query, region, namespace, cache_key):
197
198 if hasattr(query, '_cache_parameters'):
199 region, namespace, cache_key = query._cache_parameters
200 raise ValueError("This query is already configured "
201 "for region %r namespace %r" %
202 (region, namespace))
203 query._cache_parameters = region, namespace, cache_key
198 # here we return the key as a long string. our "key mangler"
199 # set up with the region will boil it down to an md5.
200 return " ".join(
201 [safe_str(compiled)] +
202 [safe_str(params[k]) for k in sorted(params)])
204 203
205 204
206 205 class FromCache(MapperOption):
@@ -208,15 +207,12 b' class FromCache(MapperOption):'
208 207
209 208 propagate_to_loaders = False
210 209
211 def __init__(self, region, namespace, cache_key=None):
210 def __init__(self, region="sql_cache_short", cache_key=None):
212 211 """Construct a new FromCache.
213 212
214 213 :param region: the cache region. Should be a
215 region configured in the Beaker CacheManager.
216
217 :param namespace: the cache namespace. Should
218 be a name uniquely describing the target Query's
219 lexical structure.
214 region configured in the dictionary of dogpile
215 regions.
220 216
221 217 :param cache_key: optional. A string cache key
222 218 that will serve as the key to the query. Use this
@@ -226,14 +222,11 b' class FromCache(MapperOption):'
226 222
227 223 """
228 224 self.region = region
229 self.namespace = namespace
230 225 self.cache_key = cache_key
231 226
232 227 def process_query(self, query):
233 228 """Process a Query during normal loading operation."""
234
235 _set_cache_parameters(query, self.region, self.namespace,
236 self.cache_key)
229 query._cache_region = self
237 230
238 231
239 232 class RelationshipCache(MapperOption):
@@ -242,27 +235,39 b' class RelationshipCache(MapperOption):'
242 235
243 236 propagate_to_loaders = True
244 237
245 def __init__(self, region, namespace, attribute):
238 def __init__(self, attribute, region="sql_cache_short", cache_key=None):
246 239 """Construct a new RelationshipCache.
247 240
248 :param region: the cache region. Should be a
249 region configured in the Beaker CacheManager.
250
251 :param namespace: the cache namespace. Should
252 be a name uniquely describing the target Query's
253 lexical structure.
254
255 241 :param attribute: A Class.attribute which
256 242 indicates a particular class relationship() whose
257 243 lazy loader should be pulled from the cache.
258 244
245 :param region: name of the cache region.
246
247 :param cache_key: optional. A string cache key
248 that will serve as the key to the query, bypassing
249 the usual means of forming a key from the Query itself.
250
259 251 """
260 252 self.region = region
261 self.namespace = namespace
253 self.cache_key = cache_key
262 254 self._relationship_options = {
263 255 (attribute.property.parent.class_, attribute.property.key): self
264 256 }
265 257
258 def _generate_cache_key(self, path):
259 """Indicate to the lazy-loader strategy that a "baked" query
260 may be used by returning ``None``.
261
262 If this method is omitted, the default implementation of
263 :class:`.MapperOption._generate_cache_key` takes place, which
264 returns ``False`` to disable the "baked" query from being used.
265
266 .. versionadded:: 1.2.7
267
268 """
269 return None
270
266 271 def process_query_conditionally(self, query):
267 272 """Process a Query that is used within a lazy loader.
268 273
@@ -271,17 +276,14 b' class RelationshipCache(MapperOption):'
271 276
272 277 """
273 278 if query._current_path:
274 mapper, key = query._current_path[-2:]
279 mapper, prop = query._current_path[-2:]
280 key = prop.key
275 281
276 282 for cls in mapper.class_.__mro__:
277 283 if (cls, key) in self._relationship_options:
278 relationship_option = \
279 self._relationship_options[(cls, key)]
280 _set_cache_parameters(
281 query,
282 relationship_option.region,
283 relationship_option.namespace,
284 None)
284 relationship_option = self._relationship_options[(cls, key)]
285 query._cache_region = relationship_option
286 break
285 287
286 288 def and_(self, option):
287 289 """Chain another RelationshipCache option to this one.
@@ -294,32 +296,3 b' class RelationshipCache(MapperOption):'
294 296 self._relationship_options.update(option._relationship_options)
295 297 return self
296 298
297
298 def _params_from_query(query):
299 """Pull the bind parameter values from a query.
300
301 This takes into account any scalar attribute bindparam set up.
302
303 E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
304 would return [5, 7].
305
306 """
307 v = []
308 def visit_bindparam(bind):
309
310 if bind.key in query._params:
311 value = query._params[bind.key]
312 elif bind.callable:
313 # lazyloader may dig a callable in here, intended
314 # to late-evaluate params after autoflush is called.
315 # convert to a scalar value.
316 value = bind.callable()
317 else:
318 value = bind.value
319
320 v.append(value)
321 if query._criterion is not None:
322 visitors.traverse(query._criterion, {}, {'bindparam':visit_bindparam})
323 for f in query._from_obj:
324 visitors.traverse(f, {}, {'bindparam':visit_bindparam})
325 return v
@@ -32,7 +32,7 b' from rhodecode.lib.celerylib import get_'
32 32 from rhodecode.lib.hooks_base import log_create_repository
33 33 from rhodecode.lib.rcmail.smtp_mailer import SmtpMailer
34 34 from rhodecode.lib.utils2 import safe_int, str2bool
35 from rhodecode.model.db import Session, IntegrityError, Repository, User
35 from rhodecode.model.db import Session, IntegrityError, Repository, User, true
36 36
37 37
38 38 @async_task(ignore_result=True, base=RequestContextTask)
@@ -52,9 +52,15 b' def send_email(recipients, subject, body'
52 52 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
53 53 if not recipients:
54 54 # if recipients are not defined we send to email_config + all admins
55 admins = [
56 u.email for u in User.query().filter(User.admin == True).all()]
57 recipients = [email_config.get('email_to')] + admins
55 admins = []
56 for u in User.query().filter(User.admin == true()).all():
57 if u.email:
58 admins.append(u.email)
59 recipients = []
60 config_email = email_config.get('email_to')
61 if config_email:
62 recipients += [config_email]
63 recipients += admins
58 64
59 65 mail_server = email_config.get('smtp_server') or None
60 66 if mail_server is None:
@@ -573,17 +573,18 b' class DbManage(object):'
573 573
574 574 def create_user(self, username, password, email='', admin=False,
575 575 strict_creation_check=True, api_key=None):
576 log.info('creating user %s' % username)
576 log.info('creating user `%s`' % username)
577 577 user = UserModel().create_or_update(
578 578 username, password, email, firstname=u'RhodeCode', lastname=u'Admin',
579 579 active=True, admin=admin, extern_type="rhodecode",
580 580 strict_creation_check=strict_creation_check)
581 581
582 582 if api_key:
583 log.info('setting a provided api key for the user %s', username)
584 from rhodecode.model.auth_token import AuthTokenModel
585 AuthTokenModel().create(
586 user=user, description=u'BUILTIN TOKEN')
583 log.info('setting a new default auth token for user `%s`', username)
584 UserModel().add_auth_token(
585 user=user, lifetime_minutes=-1,
586 role=UserModel.auth_token_role.ROLE_ALL,
587 description=u'BUILTIN TOKEN')
587 588
588 589 def create_default_user(self):
589 590 log.info('creating default user')
@@ -594,7 +595,7 b' class DbManage(object):'
594 595 firstname=u'Anonymous',
595 596 lastname=u'User',
596 597 strict_creation_check=False)
597 # based on configuration options activate/deactive this user which
598 # based on configuration options activate/de-activate this user which
598 599 # controlls anonymous access
599 600 if self.cli_args.get('public_access') is False:
600 601 log.info('Public access disabled')
@@ -648,17 +648,7 b' class Repository(Base, BaseModel):'
648 648
649 649 @property
650 650 def scm_instance_cached(self):
651 @cache_region('long_term')
652 def _c(repo_name):
653 return self.__get_instance()
654 rn = self.repo_name
655
656 inv = self.invalidate
657 if inv is not None:
658 region_invalidate(_c, None, rn)
659 # update our cache
660 CacheInvalidation.set_valid(inv.cache_key)
661 return _c(rn)
651 return self.__get_instance()
662 652
663 653 def __get_instance(self):
664 654
@@ -670,17 +670,7 b' class Repository(Base, BaseModel):'
670 670
671 671 @property
672 672 def scm_instance_cached(self):
673 @cache_region('long_term')
674 def _c(repo_name):
675 return self.__get_instance()
676 rn = self.repo_name
677 log.debug('Getting cached instance of repo')
678 inv = self.invalidate
679 if inv is not None:
680 region_invalidate(_c, None, rn)
681 # update our cache
682 CacheInvalidation.set_valid(inv.cache_key)
683 return _c(rn)
673 return self.__get_instance()
684 674
685 675 def __get_instance(self):
686 676 repo_full_path = self.repo_full_path
@@ -2262,18 +2262,7 b' class Repository(Base, BaseModel):'
2262 2262 return self._get_instance(cache=bool(cache), config=config)
2263 2263
2264 2264 def _get_instance_cached(self):
2265 @cache_region('long_term')
2266 def _get_repo(cache_key):
2267 return self._get_instance()
2268
2269 invalidator_context = CacheKey.repo_context_cache(
2270 _get_repo, self.repo_name, None, thread_scoped=True)
2271
2272 with invalidator_context as context:
2273 context.invalidate()
2274 repo = context.compute()
2275
2276 return repo
2265 self._get_instance()
2277 2266
2278 2267 def _get_instance(self, cache=True, config=None):
2279 2268 config = config or self._config
@@ -3165,27 +3154,6 b' class CacheKey(Base, BaseModel):'
3165 3154 return inv_obj
3166 3155 return None
3167 3156
3168 @classmethod
3169 def repo_context_cache(cls, compute_func, repo_name, cache_type,
3170 thread_scoped=False):
3171 """
3172 @cache_region('long_term')
3173 def _heavy_calculation(cache_key):
3174 return 'result'
3175
3176 cache_context = CacheKey.repo_context_cache(
3177 _heavy_calculation, repo_name, cache_type)
3178
3179 with cache_context as context:
3180 context.invalidate()
3181 computed = context.compute()
3182
3183 assert computed == 'result'
3184 """
3185 from rhodecode.lib import caches
3186 return caches.InvalidationContext(
3187 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
3188
3189 3157
3190 3158 class ChangesetComment(Base, BaseModel):
3191 3159 __tablename__ = 'changeset_comments'
@@ -1963,18 +1963,7 b' class Repository(Base, BaseModel):'
1963 1963 return self._get_instance(cache=bool(cache), config=config)
1964 1964
1965 1965 def _get_instance_cached(self):
1966 @cache_region('long_term')
1967 def _get_repo(cache_key):
1968 return self._get_instance()
1969
1970 invalidator_context = CacheKey.repo_context_cache(
1971 _get_repo, self.repo_name, None)
1972
1973 with invalidator_context as context:
1974 context.invalidate()
1975 repo = context.compute()
1976
1977 return repo
1966 self._get_instance()
1978 1967
1979 1968 def _get_instance(self, cache=True, config=None):
1980 1969 repo_full_path = self.repo_full_path
@@ -2849,25 +2838,6 b' class CacheKey(Base, BaseModel):'
2849 2838 return inv_obj
2850 2839 return None
2851 2840
2852 @classmethod
2853 def repo_context_cache(cls, compute_func, repo_name, cache_type):
2854 """
2855 @cache_region('long_term')
2856 def _heavy_calculation(cache_key):
2857 return 'result'
2858
2859 cache_context = CacheKey.repo_context_cache(
2860 _heavy_calculation, repo_name, cache_type)
2861
2862 with cache_context as context:
2863 context.invalidate()
2864 computed = context.compute()
2865
2866 assert computed == 'result'
2867 """
2868 from rhodecode.lib import caches
2869 return caches.InvalidationContext(compute_func, repo_name, cache_type)
2870
2871 2841
2872 2842 class ChangesetComment(Base, BaseModel):
2873 2843 __tablename__ = 'changeset_comments'
@@ -1966,18 +1966,7 b' class Repository(Base, BaseModel):'
1966 1966 return self._get_instance(cache=bool(cache), config=config)
1967 1967
1968 1968 def _get_instance_cached(self):
1969 @cache_region('long_term')
1970 def _get_repo(cache_key):
1971 return self._get_instance()
1972
1973 invalidator_context = CacheKey.repo_context_cache(
1974 _get_repo, self.repo_name, None, thread_scoped=True)
1975
1976 with invalidator_context as context:
1977 context.invalidate()
1978 repo = context.compute()
1979
1980 return repo
1969 self._get_instance()
1981 1970
1982 1971 def _get_instance(self, cache=True, config=None):
1983 1972 config = config or self._config
@@ -2841,27 +2830,6 b' class CacheKey(Base, BaseModel):'
2841 2830 return inv_obj
2842 2831 return None
2843 2832
2844 @classmethod
2845 def repo_context_cache(cls, compute_func, repo_name, cache_type,
2846 thread_scoped=False):
2847 """
2848 @cache_region('long_term')
2849 def _heavy_calculation(cache_key):
2850 return 'result'
2851
2852 cache_context = CacheKey.repo_context_cache(
2853 _heavy_calculation, repo_name, cache_type)
2854
2855 with cache_context as context:
2856 context.invalidate()
2857 computed = context.compute()
2858
2859 assert computed == 'result'
2860 """
2861 from rhodecode.lib import caches
2862 return caches.InvalidationContext(
2863 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
2864
2865 2833
2866 2834 class ChangesetComment(Base, BaseModel):
2867 2835 __tablename__ = 'changeset_comments'
@@ -1966,18 +1966,7 b' class Repository(Base, BaseModel):'
1966 1966 return self._get_instance(cache=bool(cache), config=config)
1967 1967
1968 1968 def _get_instance_cached(self):
1969 @cache_region('long_term')
1970 def _get_repo(cache_key):
1971 return self._get_instance()
1972
1973 invalidator_context = CacheKey.repo_context_cache(
1974 _get_repo, self.repo_name, None, thread_scoped=True)
1975
1976 with invalidator_context as context:
1977 context.invalidate()
1978 repo = context.compute()
1979
1980 return repo
1969 self._get_instance()
1981 1970
1982 1971 def _get_instance(self, cache=True, config=None):
1983 1972 config = config or self._config
@@ -2841,26 +2830,6 b' class CacheKey(Base, BaseModel):'
2841 2830 return inv_obj
2842 2831 return None
2843 2832
2844 @classmethod
2845 def repo_context_cache(cls, compute_func, repo_name, cache_type,
2846 thread_scoped=False):
2847 """
2848 @cache_region('long_term')
2849 def _heavy_calculation(cache_key):
2850 return 'result'
2851
2852 cache_context = CacheKey.repo_context_cache(
2853 _heavy_calculation, repo_name, cache_type)
2854
2855 with cache_context as context:
2856 context.invalidate()
2857 computed = context.compute()
2858
2859 assert computed == 'result'
2860 """
2861 from rhodecode.lib import caches
2862 return caches.InvalidationContext(
2863 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
2864 2833
2865 2834
2866 2835 class ChangesetComment(Base, BaseModel):
@@ -1968,18 +1968,7 b' class Repository(Base, BaseModel):'
1968 1968 return self._get_instance(cache=bool(cache), config=config)
1969 1969
1970 1970 def _get_instance_cached(self):
1971 @cache_region('long_term')
1972 def _get_repo(cache_key):
1973 return self._get_instance()
1974
1975 invalidator_context = CacheKey.repo_context_cache(
1976 _get_repo, self.repo_name, None, thread_scoped=True)
1977
1978 with invalidator_context as context:
1979 context.invalidate()
1980 repo = context.compute()
1981
1982 return repo
1971 self._get_instance()
1983 1972
1984 1973 def _get_instance(self, cache=True, config=None):
1985 1974 config = config or self._config
@@ -2845,27 +2834,6 b' class CacheKey(Base, BaseModel):'
2845 2834 return inv_obj
2846 2835 return None
2847 2836
2848 @classmethod
2849 def repo_context_cache(cls, compute_func, repo_name, cache_type,
2850 thread_scoped=False):
2851 """
2852 @cache_region('long_term')
2853 def _heavy_calculation(cache_key):
2854 return 'result'
2855
2856 cache_context = CacheKey.repo_context_cache(
2857 _heavy_calculation, repo_name, cache_type)
2858
2859 with cache_context as context:
2860 context.invalidate()
2861 computed = context.compute()
2862
2863 assert computed == 'result'
2864 """
2865 from rhodecode.lib import caches
2866 return caches.InvalidationContext(
2867 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
2868
2869 2837
2870 2838 class ChangesetComment(Base, BaseModel):
2871 2839 __tablename__ = 'changeset_comments'
@@ -1968,18 +1968,7 b' class Repository(Base, BaseModel):'
1968 1968 return self._get_instance(cache=bool(cache), config=config)
1969 1969
1970 1970 def _get_instance_cached(self):
1971 @cache_region('long_term')
1972 def _get_repo(cache_key):
1973 return self._get_instance()
1974
1975 invalidator_context = CacheKey.repo_context_cache(
1976 _get_repo, self.repo_name, None, thread_scoped=True)
1977
1978 with invalidator_context as context:
1979 context.invalidate()
1980 repo = context.compute()
1981
1982 return repo
1971 self._get_instance()
1983 1972
1984 1973 def _get_instance(self, cache=True, config=None):
1985 1974 config = config or self._config
@@ -2845,27 +2834,6 b' class CacheKey(Base, BaseModel):'
2845 2834 return inv_obj
2846 2835 return None
2847 2836
2848 @classmethod
2849 def repo_context_cache(cls, compute_func, repo_name, cache_type,
2850 thread_scoped=False):
2851 """
2852 @cache_region('long_term')
2853 def _heavy_calculation(cache_key):
2854 return 'result'
2855
2856 cache_context = CacheKey.repo_context_cache(
2857 _heavy_calculation, repo_name, cache_type)
2858
2859 with cache_context as context:
2860 context.invalidate()
2861 computed = context.compute()
2862
2863 assert computed == 'result'
2864 """
2865 from rhodecode.lib import caches
2866 return caches.InvalidationContext(
2867 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
2868
2869 2837
2870 2838 class ChangesetComment(Base, BaseModel):
2871 2839 __tablename__ = 'changeset_comments'
@@ -2010,18 +2010,7 b' class Repository(Base, BaseModel):'
2010 2010 return self._get_instance(cache=bool(cache), config=config)
2011 2011
2012 2012 def _get_instance_cached(self):
2013 @cache_region('long_term')
2014 def _get_repo(cache_key):
2015 return self._get_instance()
2016
2017 invalidator_context = CacheKey.repo_context_cache(
2018 _get_repo, self.repo_name, None, thread_scoped=True)
2019
2020 with invalidator_context as context:
2021 context.invalidate()
2022 repo = context.compute()
2023
2024 return repo
2013 self._get_instance()
2025 2014
2026 2015 def _get_instance(self, cache=True, config=None):
2027 2016 config = config or self._config
@@ -2900,27 +2889,6 b' class CacheKey(Base, BaseModel):'
2900 2889 return inv_obj
2901 2890 return None
2902 2891
2903 @classmethod
2904 def repo_context_cache(cls, compute_func, repo_name, cache_type,
2905 thread_scoped=False):
2906 """
2907 @cache_region('long_term')
2908 def _heavy_calculation(cache_key):
2909 return 'result'
2910
2911 cache_context = CacheKey.repo_context_cache(
2912 _heavy_calculation, repo_name, cache_type)
2913
2914 with cache_context as context:
2915 context.invalidate()
2916 computed = context.compute()
2917
2918 assert computed == 'result'
2919 """
2920 from rhodecode.lib import caches
2921 return caches.InvalidationContext(
2922 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
2923
2924 2892
2925 2893 class ChangesetComment(Base, BaseModel):
2926 2894 __tablename__ = 'changeset_comments'
@@ -2011,18 +2011,7 b' class Repository(Base, BaseModel):'
2011 2011 return self._get_instance(cache=bool(cache), config=config)
2012 2012
2013 2013 def _get_instance_cached(self):
2014 @cache_region('long_term')
2015 def _get_repo(cache_key):
2016 return self._get_instance()
2017
2018 invalidator_context = CacheKey.repo_context_cache(
2019 _get_repo, self.repo_name, None, thread_scoped=True)
2020
2021 with invalidator_context as context:
2022 context.invalidate()
2023 repo = context.compute()
2024
2025 return repo
2014 self._get_instance()
2026 2015
2027 2016 def _get_instance(self, cache=True, config=None):
2028 2017 config = config or self._config
@@ -2901,27 +2890,6 b' class CacheKey(Base, BaseModel):'
2901 2890 return inv_obj
2902 2891 return None
2903 2892
2904 @classmethod
2905 def repo_context_cache(cls, compute_func, repo_name, cache_type,
2906 thread_scoped=False):
2907 """
2908 @cache_region('long_term')
2909 def _heavy_calculation(cache_key):
2910 return 'result'
2911
2912 cache_context = CacheKey.repo_context_cache(
2913 _heavy_calculation, repo_name, cache_type)
2914
2915 with cache_context as context:
2916 context.invalidate()
2917 computed = context.compute()
2918
2919 assert computed == 'result'
2920 """
2921 from rhodecode.lib import caches
2922 return caches.InvalidationContext(
2923 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
2924
2925 2893
2926 2894 class ChangesetComment(Base, BaseModel):
2927 2895 __tablename__ = 'changeset_comments'
@@ -2199,18 +2199,7 b' class Repository(Base, BaseModel):'
2199 2199 return self._get_instance(cache=bool(cache), config=config)
2200 2200
2201 2201 def _get_instance_cached(self):
2202 @cache_region('long_term')
2203 def _get_repo(cache_key):
2204 return self._get_instance()
2205
2206 invalidator_context = CacheKey.repo_context_cache(
2207 _get_repo, self.repo_name, None, thread_scoped=True)
2208
2209 with invalidator_context as context:
2210 context.invalidate()
2211 repo = context.compute()
2212
2213 return repo
2202 self._get_instance()
2214 2203
2215 2204 def _get_instance(self, cache=True, config=None):
2216 2205 config = config or self._config
@@ -3101,27 +3090,6 b' class CacheKey(Base, BaseModel):'
3101 3090 return inv_obj
3102 3091 return None
3103 3092
3104 @classmethod
3105 def repo_context_cache(cls, compute_func, repo_name, cache_type,
3106 thread_scoped=False):
3107 """
3108 @cache_region('long_term')
3109 def _heavy_calculation(cache_key):
3110 return 'result'
3111
3112 cache_context = CacheKey.repo_context_cache(
3113 _heavy_calculation, repo_name, cache_type)
3114
3115 with cache_context as context:
3116 context.invalidate()
3117 computed = context.compute()
3118
3119 assert computed == 'result'
3120 """
3121 from rhodecode.lib import caches
3122 return caches.InvalidationContext(
3123 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
3124
3125 3093
3126 3094 class ChangesetComment(Base, BaseModel):
3127 3095 __tablename__ = 'changeset_comments'
@@ -107,6 +107,21 b' class HTTPLockedRC(HTTPClientError):'
107 107 self.args = (message, )
108 108
109 109
110 class HTTPBranchProtected(HTTPClientError):
111 """
112 Special Exception For Indicating that branch is protected in RhodeCode, the
113 return code can be overwritten by _code keyword argument passed into constructors
114 """
115 code = 403
116 title = explanation = 'Branch Protected'
117 reason = None
118
119 def __init__(self, message, *args, **kwargs):
120 self.title = self.explanation = message
121 super(HTTPBranchProtected, self).__init__(*args, **kwargs)
122 self.args = (message, )
123
124
110 125 class IMCCommitError(Exception):
111 126 pass
112 127
@@ -29,6 +29,7 b' import os'
29 29 import random
30 30 import hashlib
31 31 import StringIO
32 import textwrap
32 33 import urllib
33 34 import math
34 35 import logging
@@ -42,6 +43,7 b' from collections import OrderedDict'
42 43 import pygments
43 44 import itertools
44 45 import fnmatch
46 import bleach
45 47
46 48 from datetime import datetime
47 49 from functools import partial
@@ -1777,16 +1779,19 b' def render_binary(repo_name, file_obj):'
1777 1779 """
1778 1780 Choose how to render a binary file
1779 1781 """
1782
1780 1783 filename = file_obj.name
1781 1784
1782 1785 # images
1783 1786 for ext in ['*.png', '*.jpg', '*.ico', '*.gif']:
1784 1787 if fnmatch.fnmatch(filename, pat=ext):
1785 alt = filename
1788 alt = escape(filename)
1786 1789 src = route_path(
1787 1790 'repo_file_raw', repo_name=repo_name,
1788 commit_id=file_obj.commit.raw_id, f_path=file_obj.path)
1789 return literal('<img class="rendered-binary" alt="{}" src="{}">'.format(alt, src))
1791 commit_id=file_obj.commit.raw_id,
1792 f_path=file_obj.path)
1793 return literal(
1794 '<img class="rendered-binary" alt="{}" src="{}">'.format(alt, src))
1790 1795
1791 1796
1792 1797 def renderer_from_filename(filename, exclude=None):
@@ -1813,7 +1818,11 b" def render(source, renderer='rst', menti"
1813 1818 return relative_links(html_source, relative_urls)
1814 1819 return html_source
1815 1820
1816 if renderer == 'rst':
1821 if renderer == 'plain':
1822 return literal(
1823 MarkupRenderer.plain(source, leading_newline=False))
1824
1825 elif renderer == 'rst':
1817 1826 if repo_name:
1818 1827 # process patterns on comments if we pass in repo name
1819 1828 source, issues = process_patterns(
@@ -1823,6 +1832,7 b" def render(source, renderer='rst', menti"
1823 1832 '<div class="rst-block">%s</div>' %
1824 1833 maybe_convert_relative_links(
1825 1834 MarkupRenderer.rst(source, mentions=mentions)))
1835
1826 1836 elif renderer == 'markdown':
1827 1837 if repo_name:
1828 1838 # process patterns on comments if we pass in repo name
@@ -1834,6 +1844,7 b" def render(source, renderer='rst', menti"
1834 1844 maybe_convert_relative_links(
1835 1845 MarkupRenderer.markdown(source, flavored=True,
1836 1846 mentions=mentions)))
1847
1837 1848 elif renderer == 'jupyter':
1838 1849 return literal(
1839 1850 '<div class="ipynb">%s</div>' %
@@ -1864,6 +1875,8 b' def get_permission_name(key):'
1864 1875
1865 1876 def journal_filter_help(request):
1866 1877 _ = request.translate
1878 from rhodecode.lib.audit_logger import ACTIONS
1879 actions = '\n'.join(textwrap.wrap(', '.join(sorted(ACTIONS.keys())), 80))
1867 1880
1868 1881 return _(
1869 1882 'Example filter terms:\n' +
@@ -1875,6 +1888,8 b' def journal_filter_help(request):'
1875 1888 ' date:20120101\n' +
1876 1889 ' date:[20120101100000 TO 20120102]\n' +
1877 1890 '\n' +
1891 'Actions: {actions}\n' +
1892 '\n' +
1878 1893 'Generate wildcards using \'*\' character:\n' +
1879 1894 ' "repository:vcs*" - search everything starting with \'vcs\'\n' +
1880 1895 ' "repository:*vcs*" - search for repository containing \'vcs\'\n' +
@@ -1882,7 +1897,7 b' def journal_filter_help(request):'
1882 1897 'Optional AND / OR operators in queries\n' +
1883 1898 ' "repository:vcs OR repository:test"\n' +
1884 1899 ' "username:test AND repository:test*"\n'
1885 )
1900 ).format(actions=actions)
1886 1901
1887 1902
1888 1903 def search_filter_help(searcher, request):
@@ -32,7 +32,8 b' from rhodecode import events'
32 32 from rhodecode.lib import helpers as h
33 33 from rhodecode.lib import audit_logger
34 34 from rhodecode.lib.utils2 import safe_str
35 from rhodecode.lib.exceptions import HTTPLockedRC, UserCreationError
35 from rhodecode.lib.exceptions import (
36 HTTPLockedRC, HTTPBranchProtected, UserCreationError)
36 37 from rhodecode.model.db import Repository, User
37 38
38 39 log = logging.getLogger(__name__)
@@ -94,9 +95,9 b' def pre_push(extras):'
94 95 It bans pushing when the repository is locked.
95 96 """
96 97
97 usr = User.get_by_username(extras.username)
98 user = User.get_by_username(extras.username)
98 99 output = ''
99 if extras.locked_by[0] and usr.user_id != int(extras.locked_by[0]):
100 if extras.locked_by[0] and user.user_id != int(extras.locked_by[0]):
100 101 locked_by = User.get(extras.locked_by[0]).username
101 102 reason = extras.locked_by[2]
102 103 # this exception is interpreted in git/hg middlewares and based
@@ -109,9 +110,48 b' def pre_push(extras):'
109 110 else:
110 111 raise _http_ret
111 112
112 # Propagate to external components. This is done after checking the
113 # lock, for consistent behavior.
114 113 if not is_shadow_repo(extras):
114 if extras.commit_ids and extras.check_branch_perms:
115
116 auth_user = user.AuthUser()
117 repo = Repository.get_by_repo_name(extras.repository)
118 affected_branches = []
119 if repo.repo_type == 'hg':
120 for entry in extras.commit_ids:
121 if entry['type'] == 'branch':
122 is_forced = bool(entry['multiple_heads'])
123 affected_branches.append([entry['name'], is_forced])
124 elif repo.repo_type == 'git':
125 for entry in extras.commit_ids:
126 if entry['type'] == 'heads':
127 is_forced = bool(entry['pruned_sha'])
128 affected_branches.append([entry['name'], is_forced])
129
130 for branch_name, is_forced in affected_branches:
131
132 rule, branch_perm = auth_user.get_rule_and_branch_permission(
133 extras.repository, branch_name)
134 if not branch_perm:
135 # no branch permission found for this branch, just keep checking
136 continue
137
138 if branch_perm == 'branch.push_force':
139 continue
140 elif branch_perm == 'branch.push' and is_forced is False:
141 continue
142 elif branch_perm == 'branch.push' and is_forced is True:
143 halt_message = 'Branch `{}` changes rejected by rule {}. ' \
144 'FORCE PUSH FORBIDDEN.'.format(branch_name, rule)
145 else:
146 halt_message = 'Branch `{}` changes rejected by rule {}.'.format(
147 branch_name, rule)
148
149 if halt_message:
150 _http_ret = HTTPBranchProtected(halt_message)
151 raise _http_ret
152
153 # Propagate to external components. This is done after checking the
154 # lock, for consistent behavior.
115 155 pre_push_extension(repo_store_path=Repository.base_path(), **extras)
116 156 events.trigger(events.RepoPrePushEvent(
117 157 repo_name=extras.repository, extras=extras))
@@ -29,12 +29,13 b' from BaseHTTPServer import BaseHTTPReque'
29 29 from SocketServer import TCPServer
30 30
31 31 import rhodecode
32 from rhodecode.lib.exceptions import HTTPLockedRC, HTTPBranchProtected
32 33 from rhodecode.model import meta
33 34 from rhodecode.lib.base import bootstrap_request, bootstrap_config
34 35 from rhodecode.lib import hooks_base
35 36 from rhodecode.lib.utils2 import AttributeDict
36 37 from rhodecode.lib.ext_json import json
37
38 from rhodecode.lib import rc_cache
38 39
39 40 log = logging.getLogger(__name__)
40 41
@@ -45,10 +46,9 b' class HooksHttpHandler(BaseHTTPRequestHa'
45 46 method, extras = self._read_request()
46 47 txn_id = getattr(self.server, 'txn_id', None)
47 48 if txn_id:
48 from rhodecode.lib.caches import compute_key_from_params
49 49 log.debug('Computing TXN_ID based on `%s`:`%s`',
50 50 extras['repository'], extras['txn_id'])
51 computed_txn_id = compute_key_from_params(
51 computed_txn_id = rc_cache.utils.compute_key_from_params(
52 52 extras['repository'], extras['txn_id'])
53 53 if txn_id != computed_txn_id:
54 54 raise Exception(
@@ -119,8 +119,8 b' class ThreadedHookCallbackDaemon(object)'
119 119 _daemon = None
120 120 _done = False
121 121
122 def __init__(self, txn_id=None, port=None):
123 self._prepare(txn_id=txn_id, port=port)
122 def __init__(self, txn_id=None, host=None, port=None):
123 self._prepare(txn_id=txn_id, host=None, port=port)
124 124
125 125 def __enter__(self):
126 126 self._run()
@@ -130,7 +130,7 b' class ThreadedHookCallbackDaemon(object)'
130 130 log.debug('Callback daemon exiting now...')
131 131 self._stop()
132 132
133 def _prepare(self, txn_id=None, port=None):
133 def _prepare(self, txn_id=None, host=None, port=None):
134 134 raise NotImplementedError()
135 135
136 136 def _run(self):
@@ -147,17 +147,16 b' class HttpHooksCallbackDaemon(ThreadedHo'
147 147
148 148 hooks_uri = None
149 149
150 IP_ADDRESS = '127.0.0.1'
151
152 150 # From Python docs: Polling reduces our responsiveness to a shutdown
153 151 # request and wastes cpu at all other times.
154 152 POLL_INTERVAL = 0.01
155 153
156 def _prepare(self, txn_id=None, port=None):
154 def _prepare(self, txn_id=None, host=None, port=None):
155 host = host or '127.0.0.1'
157 156 self._done = False
158 self._daemon = TCPServer((self.IP_ADDRESS, port or 0), HooksHttpHandler)
157 self._daemon = TCPServer((host, port or 0), HooksHttpHandler)
159 158 _, port = self._daemon.server_address
160 self.hooks_uri = '{}:{}'.format(self.IP_ADDRESS, port)
159 self.hooks_uri = '{}:{}'.format(host, port)
161 160 self.txn_id = txn_id
162 161 # inject transaction_id for later verification
163 162 self._daemon.txn_id = self.txn_id
@@ -220,7 +219,7 b' def get_txn_id_from_store(txn_id):'
220 219 return {}
221 220
222 221
223 def prepare_callback_daemon(extras, protocol, use_direct_calls, txn_id=None):
222 def prepare_callback_daemon(extras, protocol, host, use_direct_calls, txn_id=None):
224 223 txn_details = get_txn_id_from_store(txn_id)
225 224 port = txn_details.get('port', 0)
226 225 if use_direct_calls:
@@ -228,7 +227,8 b' def prepare_callback_daemon(extras, prot'
228 227 extras['hooks_module'] = callback_daemon.hooks_module
229 228 else:
230 229 if protocol == 'http':
231 callback_daemon = HttpHooksCallbackDaemon(txn_id=txn_id, port=port)
230 callback_daemon = HttpHooksCallbackDaemon(
231 txn_id=txn_id, host=host, port=port)
232 232 else:
233 233 log.error('Unsupported callback daemon protocol "%s"', protocol)
234 234 raise Exception('Unsupported callback daemon protocol.')
@@ -286,9 +286,20 b' class Hooks(object):'
286 286
287 287 try:
288 288 result = hook(extras)
289 except Exception as error:
290 exc_tb = traceback.format_exc()
291 log.exception('Exception when handling hook %s', hook)
289 except HTTPBranchProtected as handled_error:
290 # Those special cases doesn't need error reporting. It's a case of
291 # locked repo or protected branch
292 result = AttributeDict({
293 'status': handled_error.code,
294 'output': handled_error.explanation
295 })
296 except (HTTPLockedRC, Exception) as error:
297 # locked needs different handling since we need to also
298 # handle PULL operations
299 exc_tb = ''
300 if not isinstance(error, HTTPLockedRC):
301 exc_tb = traceback.format_exc()
302 log.exception('Exception when handling hook %s', hook)
292 303 error_args = error.args
293 304 return {
294 305 'status': 128,
@@ -123,6 +123,35 b' class ColorFormatter(ExceptionAwareForma'
123 123 return colored_record
124 124
125 125
126 def _inject_req_id(record):
127 from pyramid.threadlocal import get_current_request
128 req = get_current_request()
129 req_id = 'req_id:%-36s ' % (getattr(req, 'req_id', None))
130 record.req_id = req_id
131
132
133 class RequestTrackingFormatter(ExceptionAwareFormatter):
134 def format(self, record):
135 _inject_req_id(record)
136 def_record = logging.Formatter.format(self, record)
137 return def_record
138
139
140 class ColorRequestTrackingFormatter(ColorFormatter):
141 def format(self, record):
142 """
143 Changes record's levelname to use with COLORS enum
144 """
145 _inject_req_id(record)
146 levelname = record.levelname
147 start = COLOR_SEQ % (COLORS[levelname])
148 def_record = logging.Formatter.format(self, record)
149 end = RESET_SEQ
150
151 colored_record = ''.join([start, def_record, end])
152 return colored_record
153
154
126 155 class ColorFormatterSql(logging.Formatter):
127 156
128 157 def format(self, record):
@@ -240,7 +240,11 b' class MarkupRenderer(object):'
240 240 from .bleach_whitelist import markdown_attrs, markdown_tags
241 241 allowed_tags = markdown_tags
242 242 allowed_attrs = markdown_attrs
243 return bleach.clean(text, tags=allowed_tags, attributes=allowed_attrs)
243
244 try:
245 return bleach.clean(text, tags=allowed_tags, attributes=allowed_attrs)
246 except Exception:
247 return 'UNPARSEABLE TEXT'
244 248
245 249 @classmethod
246 250 def renderer_from_filename(cls, filename, exclude):
@@ -319,14 +323,18 b' class MarkupRenderer(object):'
319 323 return cls.URL_PAT.sub(url_func, text)
320 324
321 325 @classmethod
322 def plain(cls, source, universal_newline=True):
326 def plain(cls, source, universal_newline=True, leading_newline=True):
323 327 source = safe_unicode(source)
324 328 if universal_newline:
325 329 newline = '\n'
326 330 source = newline.join(source.splitlines())
327 331
328 source = cls.urlify_text(source)
329 return '<br />' + source.replace("\n", '<br />')
332 rendered_source = cls.urlify_text(source)
333 source = ''
334 if leading_newline:
335 source += '<br />'
336 source += rendered_source.replace("\n", '<br />')
337 return source
330 338
331 339 @classmethod
332 340 def markdown(cls, source, safe=True, flavored=True, mentions=False,
@@ -357,17 +365,18 b' class MarkupRenderer(object):'
357 365 if flavored:
358 366 source = cls._flavored_markdown(source)
359 367 rendered = markdown_renderer.convert(source)
360 if clean_html:
361 rendered = cls.bleach_clean(rendered)
362 return rendered
363 368 except Exception:
364 369 log.exception('Error when rendering Markdown')
365 370 if safe:
366 371 log.debug('Fallback to render in plain mode')
367 return cls.plain(source)
372 rendered = cls.plain(source)
368 373 else:
369 374 raise
370 375
376 if clean_html:
377 rendered = cls.bleach_clean(rendered)
378 return rendered
379
371 380 @classmethod
372 381 def rst(cls, source, safe=True, mentions=False, clean_html=False):
373 382 if mentions:
@@ -25,24 +25,38 b' and the state of LRU dict.'
25 25 inrae.cache is licensed under LRUDict is licensed under ZPL license
26 26 This software is Copyright (c) Zope Corporation (tm) and
27 27 Contributors. All rights reserved.
28
29 TODO: marcink, we might think of replacing the LRUDict with lru-dict library
30 written in C.
28 """
31 29
32 eg difference in speed:
33
34 LRUDictC Time : 0.00025 s, Memory : 110592 Kb
35 LRUDict Time : 0.00369 s, Memory : 147456 Kb
36 """
37 30 import logging
38 31
39 from infrae.cache.beakerext.lru import LRUDict
32 from repoze.lru import LRUCache
40 33 from beaker.container import MemoryNamespaceManager, AbstractDictionaryNSManager
41 34 from rhodecode.lib.utils2 import safe_str
42 35
43 36 log = logging.getLogger(__name__)
44 37
45 38
39 class LRUDict(LRUCache):
40 """
41 Wrapper to provide partial dict access
42 """
43
44 def __setitem__(self, key, value):
45 return self.put(key, value)
46
47 def __getitem__(self, key):
48 return self.get(key)
49
50 def __contains__(self, key):
51 return bool(self.get(key))
52
53 def __delitem__(self, key):
54 del self.data[key]
55
56 def keys(self):
57 return self.data.keys()
58
59
46 60 class LRUDictDebug(LRUDict):
47 61 """
48 62 Wrapper to provide some debug options
@@ -25,6 +25,7 b' SimpleHG middleware for handling mercuri'
25 25
26 26 import logging
27 27 import urlparse
28 import urllib
28 29
29 30 from rhodecode.lib import utils
30 31 from rhodecode.lib.ext_json import json
@@ -51,24 +52,94 b' class SimpleHg(simplevcs.SimpleVCS):'
51 52 'getbundle': 'pull',
52 53 'stream_out': 'pull',
53 54 'listkeys': 'pull',
55 'between': 'pull',
56 'branchmap': 'pull',
57 'branches': 'pull',
58 'clonebundles': 'pull',
59 'capabilities': 'pull',
60 'debugwireargs': 'pull',
61 'heads': 'pull',
62 'lookup': 'pull',
63 'hello': 'pull',
64 'known': 'pull',
65
66 # largefiles
67 'putlfile': 'push',
68 'getlfile': 'pull',
69 'statlfile': 'pull',
70 'lheads': 'pull',
71
54 72 'unbundle': 'push',
55 73 'pushkey': 'push',
56 74 }
57 75
76 @classmethod
77 def _get_xarg_headers(cls, environ):
78 i = 1
79 chunks = [] # gather chunks stored in multiple 'hgarg_N'
80 while True:
81 head = environ.get('HTTP_X_HGARG_{}'.format(i))
82 if not head:
83 break
84 i += 1
85 chunks.append(urllib.unquote_plus(head))
86 full_arg = ''.join(chunks)
87 pref = 'cmds='
88 if full_arg.startswith(pref):
89 # strip the cmds= header defining our batch commands
90 full_arg = full_arg[len(pref):]
91 cmds = full_arg.split(';')
92 return cmds
93
94 @classmethod
95 def _get_batch_cmd(cls, environ):
96 """
97 Handle batch command send commands. Those are ';' separated commands
98 sent by batch command that server needs to execute. We need to extract
99 those, and map them to our ACTION_MAPPING to get all push/pull commands
100 specified in the batch
101 """
102 default = 'push'
103 batch_cmds = []
104 try:
105 cmds = cls._get_xarg_headers(environ)
106 for pair in cmds:
107 parts = pair.split(' ', 1)
108 if len(parts) != 2:
109 continue
110 # entry should be in a format `key ARGS`
111 cmd, args = parts
112 action = cls._ACTION_MAPPING.get(cmd, default)
113 batch_cmds.append(action)
114 except Exception:
115 log.exception('Failed to extract batch commands operations')
116
117 # in case we failed, (e.g malformed data) assume it's PUSH sub-command
118 # for safety
119 return batch_cmds or [default]
120
58 121 def _get_action(self, environ):
59 122 """
60 123 Maps mercurial request commands into a pull or push command.
61 In case of unknown/unexpected data, it returns 'pull' to be safe.
124 In case of unknown/unexpected data, it returns 'push' to be safe.
62 125
63 126 :param environ:
64 127 """
128 default = 'push'
65 129 query = urlparse.parse_qs(environ['QUERY_STRING'],
66 130 keep_blank_values=True)
131
67 132 if 'cmd' in query:
68 133 cmd = query['cmd'][0]
69 return self._ACTION_MAPPING.get(cmd, 'pull')
134 if cmd == 'batch':
135 cmds = self._get_batch_cmd(environ)
136 if 'push' in cmds:
137 return 'push'
138 else:
139 return 'pull'
140 return self._ACTION_MAPPING.get(cmd, default)
70 141
71 return 'pull'
142 return default
72 143
73 144 def _create_wsgi_app(self, repo_path, repo_name, config):
74 145 return self.scm_app.create_hg_wsgi_app(
@@ -26,7 +26,7 b' from urlparse import urljoin'
26 26 import requests
27 27 from pyramid.httpexceptions import HTTPNotAcceptable
28 28
29 from rhodecode.lib import caches
29 from rhodecode.lib import rc_cache
30 30 from rhodecode.lib.middleware import simplevcs
31 31 from rhodecode.lib.utils import is_valid_repo
32 32 from rhodecode.lib.utils2 import str2bool, safe_int
@@ -86,7 +86,7 b' class SimpleSvnApp(object):'
86 86
87 87 if response.headers.get('SVN-Txn-name'):
88 88 svn_tx_id = response.headers.get('SVN-Txn-name')
89 txn_id = caches.compute_key_from_params(
89 txn_id = rc_cache.utils.compute_key_from_params(
90 90 self.config['repository'], svn_tx_id)
91 91 port = safe_int(self.rc_extras['hooks_uri'].split(':')[-1])
92 92 store_txn_id_data(txn_id, {'port': port})
@@ -39,9 +39,8 b' from pyramid.httpexceptions import ('
39 39 from zope.cachedescriptors.property import Lazy as LazyProperty
40 40
41 41 import rhodecode
42 from rhodecode.authentication.base import (
43 authenticate, get_perms_cache_manager, VCS_TYPE, loadplugin)
44 from rhodecode.lib import caches
42 from rhodecode.authentication.base import authenticate, VCS_TYPE, loadplugin
43 from rhodecode.lib import rc_cache
45 44 from rhodecode.lib.auth import AuthUser, HasPermissionAnyMiddleware
46 45 from rhodecode.lib.base import (
47 46 BasicAuth, get_ip_addr, get_user_agent, vcs_operation_context)
@@ -65,7 +64,7 b' log = logging.getLogger(__name__)'
65 64
66 65 def extract_svn_txn_id(acl_repo_name, data):
67 66 """
68 Helper method for extraction of svn txn_id from submited XML data during
67 Helper method for extraction of svn txn_id from submitted XML data during
69 68 POST operations
70 69 """
71 70 try:
@@ -78,7 +77,7 b' def extract_svn_txn_id(acl_repo_name, da'
78 77 match = pat.search(sub_el.text)
79 78 if match:
80 79 svn_tx_id = match.groupdict()['txn_id']
81 txn_id = caches.compute_key_from_params(
80 txn_id = rc_cache.utils.compute_key_from_params(
82 81 acl_repo_name, svn_tx_id)
83 82 return txn_id
84 83 except Exception:
@@ -204,13 +203,14 b' class SimpleVCS(object):'
204 203
205 204 # Only proceed if we got a pull request and if acl repo name from
206 205 # URL equals the target repo name of the pull request.
207 if pull_request and (acl_repo_name ==
208 pull_request.target_repo.repo_name):
206 if pull_request and \
207 (acl_repo_name == pull_request.target_repo.repo_name):
208 repo_id = pull_request.target_repo.repo_id
209 209 # Get file system path to shadow repository.
210 210 workspace_id = PullRequestModel()._workspace_id(pull_request)
211 211 target_vcs = pull_request.target_repo.scm_instance()
212 212 vcs_repo_name = target_vcs._get_shadow_repository_path(
213 workspace_id)
213 repo_id, workspace_id)
214 214
215 215 # Store names for later usage.
216 216 self.vcs_repo_name = vcs_repo_name
@@ -297,7 +297,7 b' class SimpleVCS(object):'
297 297 def is_shadow_repo_dir(self):
298 298 return os.path.isdir(self.vcs_repo_name)
299 299
300 def _check_permission(self, action, user, repo_name, ip_addr=None,
300 def _check_permission(self, action, user, auth_user, repo_name, ip_addr=None,
301 301 plugin_id='', plugin_cache_active=False, cache_ttl=0):
302 302 """
303 303 Checks permissions using action (push/pull) user and repository
@@ -310,36 +310,24 b' class SimpleVCS(object):'
310 310 :param repo_name: repository name
311 311 """
312 312
313 # get instance of cache manager configured for a namespace
314 cache_manager = get_perms_cache_manager(
315 custom_ttl=cache_ttl, suffix=user.user_id)
316 313 log.debug('AUTH_CACHE_TTL for permissions `%s` active: %s (TTL: %s)',
317 314 plugin_id, plugin_cache_active, cache_ttl)
318 315
319 # for environ based password can be empty, but then the validation is
320 # on the server that fills in the env data needed for authentication
321 _perm_calc_hash = caches.compute_key_from_params(
322 plugin_id, action, user.user_id, repo_name, ip_addr)
316 user_id = user.user_id
317 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
318 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
323 319
324 # _authenticate is a wrapper for .auth() method of plugin.
325 # it checks if .auth() sends proper data.
326 # For RhodeCodeExternalAuthPlugin it also maps users to
327 # Database and maps the attributes returned from .auth()
328 # to RhodeCode database. If this function returns data
329 # then auth is correct.
330 start = time.time()
331 log.debug('Running plugin `%s` permissions check', plugin_id)
320 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
321 expiration_time=cache_ttl,
322 condition=plugin_cache_active)
323 def compute_perm_vcs(
324 cache_name, plugin_id, action, user_id, repo_name, ip_addr):
332 325
333 def perm_func():
334 """
335 This function is used internally in Cache of Beaker to calculate
336 Results
337 """
338 326 log.debug('auth: calculating permission access now...')
339 327 # check IP
340 328 inherit = user.inherit_default_permissions
341 329 ip_allowed = AuthUser.check_ip_allowed(
342 user.user_id, ip_addr, inherit_from_default=inherit)
330 user_id, ip_addr, inherit_from_default=inherit)
343 331 if ip_allowed:
344 332 log.info('Access for IP:%s allowed', ip_addr)
345 333 else:
@@ -347,24 +335,25 b' class SimpleVCS(object):'
347 335
348 336 if action == 'push':
349 337 perms = ('repository.write', 'repository.admin')
350 if not HasPermissionAnyMiddleware(*perms)(user, repo_name):
338 if not HasPermissionAnyMiddleware(*perms)(auth_user, repo_name):
351 339 return False
352 340
353 341 else:
354 342 # any other action need at least read permission
355 343 perms = (
356 344 'repository.read', 'repository.write', 'repository.admin')
357 if not HasPermissionAnyMiddleware(*perms)(user, repo_name):
345 if not HasPermissionAnyMiddleware(*perms)(auth_user, repo_name):
358 346 return False
359 347
360 348 return True
361 349
362 if plugin_cache_active:
363 log.debug('Trying to fetch cached perms by %s', _perm_calc_hash[:6])
364 perm_result = cache_manager.get(
365 _perm_calc_hash, createfunc=perm_func)
366 else:
367 perm_result = perm_func()
350 start = time.time()
351 log.debug('Running plugin `%s` permissions check', plugin_id)
352
353 # for environ based auth, password can be empty, but then the validation is
354 # on the server that fills in the env data needed for authentication
355 perm_result = compute_perm_vcs(
356 'vcs_permissions', plugin_id, action, user.user_id, repo_name, ip_addr)
368 357
369 358 auth_time = time.time() - start
370 359 log.debug('Permissions for plugin `%s` completed in %.3fs, '
@@ -452,14 +441,17 b' class SimpleVCS(object):'
452 441 # ======================================================================
453 442 # CHECK ANONYMOUS PERMISSION
454 443 # ======================================================================
444 detect_force_push = False
445 check_branch_perms = False
455 446 if action in ['pull', 'push']:
456 anonymous_user = User.get_default_user()
447 user_obj = anonymous_user = User.get_default_user()
448 auth_user = user_obj.AuthUser()
457 449 username = anonymous_user.username
458 450 if anonymous_user.active:
459 451 plugin_cache_active, cache_ttl = self._get_default_cache_ttl()
460 452 # ONLY check permissions if the user is activated
461 453 anonymous_perm = self._check_permission(
462 action, anonymous_user, self.acl_repo_name, ip_addr,
454 action, anonymous_user, auth_user, self.acl_repo_name, ip_addr,
463 455 plugin_id='anonymous_access',
464 456 plugin_cache_active=plugin_cache_active,
465 457 cache_ttl=cache_ttl,
@@ -525,7 +517,6 b' class SimpleVCS(object):'
525 517 return auth_result.wsgi_application(
526 518 environ, start_response)
527 519
528
529 520 # ==============================================================
530 521 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
531 522 # ==============================================================
@@ -533,11 +524,11 b' class SimpleVCS(object):'
533 524 if not self.valid_and_active_user(user):
534 525 return HTTPForbidden()(environ, start_response)
535 526 username = user.username
536 user.update_lastactivity()
537 meta.Session().commit()
527 user_id = user.user_id
538 528
539 529 # check user attributes for password change flag
540 530 user_obj = user
531 auth_user = user_obj.AuthUser()
541 532 if user_obj and user_obj.username != User.DEFAULT_USER and \
542 533 user_obj.user_data.get('force_password_change'):
543 534 reason = 'password change required'
@@ -546,18 +537,27 b' class SimpleVCS(object):'
546 537
547 538 # check permissions for this repository
548 539 perm = self._check_permission(
549 action, user, self.acl_repo_name, ip_addr,
540 action, user, auth_user, self.acl_repo_name, ip_addr,
550 541 plugin, plugin_cache_active, cache_ttl)
551 542 if not perm:
552 543 return HTTPForbidden()(environ, start_response)
544 environ['rc_auth_user_id'] = user_id
545
546 if action == 'push':
547 perms = auth_user.get_branch_permissions(self.acl_repo_name)
548 if perms:
549 check_branch_perms = True
550 detect_force_push = True
553 551
554 552 # extras are injected into UI object and later available
555 553 # in hooks executed by RhodeCode
556 554 check_locking = _should_check_locking(environ.get('QUERY_STRING'))
555
557 556 extras = vcs_operation_context(
558 557 environ, repo_name=self.acl_repo_name, username=username,
559 558 action=action, scm=self.SCM, check_locking=check_locking,
560 is_shadow_repo=self.is_shadow_repo
559 is_shadow_repo=self.is_shadow_repo, check_branch_perms=check_branch_perms,
560 detect_force_push=detect_force_push
561 561 )
562 562
563 563 # ======================================================================
@@ -662,7 +662,7 b' class SimpleVCS(object):'
662 662
663 663 return prepare_callback_daemon(
664 664 extras, protocol=vcs_settings.HOOKS_PROTOCOL,
665 use_direct_calls=direct_calls, txn_id=txn_id)
665 host=vcs_settings.HOOKS_HOST, use_direct_calls=direct_calls, txn_id=txn_id)
666 666
667 667
668 668 def _should_check_locking(query_string):
@@ -158,7 +158,7 b' def detect_vcs_request(environ, backends'
158 158 log.debug('got handler:%s from environ', handler)
159 159
160 160 if not handler:
161 log.debug('checking if request is of VCS type in order: %s', backends)
161 log.debug('request start: checking if request is of VCS type in order: %s', backends)
162 162 for vcs_type in backends:
163 163 vcs_check, _handler = checks[vcs_type]
164 164 if vcs_check(environ):
@@ -21,9 +21,10 b''
21 21 import os
22 22 from pyramid.compat import configparser
23 23 from pyramid.paster import bootstrap as pyramid_bootstrap, setup_logging # noqa
24 from pyramid.request import Request
25 24 from pyramid.scripting import prepare
26 25
26 from rhodecode.lib.request import Request
27
27 28
28 29 def get_config(ini_path, **kwargs):
29 30 parser = configparser.ConfigParser(**kwargs)
@@ -24,8 +24,9 b' Simple smtp mailer used in RhodeCode'
24 24
25 25 import time
26 26 import logging
27 from socket import sslerror
27 import socket
28 28 from email.utils import formatdate
29
29 30 from rhodecode.lib.rcmail.message import Message
30 31 from rhodecode.lib.rcmail.utils import DNS_NAME
31 32
@@ -33,7 +34,8 b' log = logging.getLogger(__name__)'
33 34
34 35
35 36 class SmtpMailer(object):
36 """SMTP mailer class
37 """
38 SMTP mailer class
37 39
38 40 mailer = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth
39 41 mail_port, ssl, tls)
@@ -59,7 +61,7 b' class SmtpMailer(object):'
59 61 self.auth = smtp_auth
60 62
61 63 def _get_smptlib(self):
62 #patch the output
64 # patch the output
63 65 import smtplib
64 66
65 67 class StderrLogger(object):
@@ -83,7 +85,7 b' class SmtpMailer(object):'
83 85 recipients_separator=", ", extra_headers=headers)
84 86 raw_msg = msg.to_message()
85 87
86 #patched smtplib without stderr
88 # patched smtplib without stderr
87 89 smtplib = self._get_smptlib()
88 90 if self.ssl:
89 91 smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port,
@@ -109,10 +111,10 b' class SmtpMailer(object):'
109 111 smtp_serv.login(self.user, self.passwd)
110 112
111 113 smtp_serv.sendmail(msg.sender, msg.send_to, raw_msg.as_string())
112 logging.info('MAIL SEND TO: %s' % recipients)
114 log.info('email sent to: %s' % recipients)
113 115
114 116 try:
115 117 smtp_serv.quit()
116 except sslerror:
118 except socket.sslerror:
117 119 # sslerror is raised in tls connections on closing sometimes
118 120 smtp_serv.close()
@@ -142,6 +142,21 b' def platform_type():'
142 142 return SysInfoRes(value=value)
143 143
144 144
145 def locale_info():
146 import locale
147
148 value = dict(
149 locale_default=locale.getdefaultlocale(),
150 locale_lc_all=locale.getlocale(locale.LC_ALL),
151 lang_env=os.environ.get('LANG'),
152 lc_all_env=os.environ.get('LC_ALL'),
153 local_archive_env=os.environ.get('LOCALE_ARCHIVE'),
154 )
155 human_value = 'LANG: {}, locale LC_ALL: {}, Default locales: {}'.format(
156 value['lang_env'], value['locale_lc_all'], value['locale_default'])
157 return SysInfoRes(value=value, human_value=human_value)
158
159
145 160 def ulimit_info():
146 161 data = collections.OrderedDict([
147 162 ('cpu time (seconds)', resource.getrlimit(resource.RLIMIT_CPU)),
@@ -712,7 +727,6 b' def usage_info():'
712 727 return SysInfoRes(value=value)
713 728
714 729
715
716 730 def get_system_info(environ):
717 731 environ = environ or {}
718 732 return {
@@ -723,6 +737,7 b' def get_system_info(environ):'
723 737 'py_modules': SysInfo(py_modules)(),
724 738
725 739 'platform': SysInfo(platform_type)(),
740 'locale': SysInfo(locale_info)(),
726 741 'server': SysInfo(server_info, environ=environ)(),
727 742 'database': SysInfo(database_info)(),
728 743 'ulimit': SysInfo(ulimit_info)(),
@@ -41,14 +41,14 b' import pkg_resources'
41 41 from webhelpers.text import collapse, remove_formatting, strip_tags
42 42 from mako import exceptions
43 43 from pyramid.threadlocal import get_current_registry
44 from pyramid.request import Request
44 from rhodecode.lib.request import Request
45 45
46 46 from rhodecode.lib.fakemod import create_module
47 47 from rhodecode.lib.vcs.backends.base import Config
48 48 from rhodecode.lib.vcs.exceptions import VCSError
49 49 from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend
50 50 from rhodecode.lib.utils2 import (
51 safe_str, safe_unicode, get_current_rhodecode_user, md5)
51 safe_str, safe_unicode, get_current_rhodecode_user, md5, sha1)
52 52 from rhodecode.model import meta
53 53 from rhodecode.model.db import (
54 54 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
@@ -120,7 +120,6 b' def get_repo_group_slug(request):'
120 120 # pyramid
121 121 _group = request.matchdict.get('repo_group_name')
122 122
123
124 123 if _group:
125 124 _group = _group.rstrip('/')
126 125 return _group
@@ -56,6 +56,14 b' def md5_safe(s):'
56 56 return md5(safe_str(s))
57 57
58 58
59 def sha1(s):
60 return hashlib.sha1(s).hexdigest()
61
62
63 def sha1_safe(s):
64 return sha1(safe_str(s))
65
66
59 67 def __get_lem(extra_mapping=None):
60 68 """
61 69 Get language extension map based on what's inside pygments lexers
@@ -353,6 +361,8 b' def ping_connection(connection, branch):'
353 361 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
354 362 """Custom engine_from_config functions."""
355 363 log = logging.getLogger('sqlalchemy.engine')
364 _ping_connection = configuration.pop('sqlalchemy.db1.ping_connection', None)
365
356 366 engine = sqlalchemy.engine_from_config(configuration, prefix, **kwargs)
357 367
358 368 def color_sql(sql):
@@ -360,6 +370,9 b' def engine_from_config(configuration, pr'
360 370 normal = '\x1b[0m'
361 371 return ''.join([color_seq, sql, normal])
362 372
373 if configuration['debug'] or _ping_connection:
374 sqlalchemy.event.listen(engine, "engine_connect", ping_connection)
375
363 376 if configuration['debug']:
364 377 # attach events only for debug configuration
365 378
@@ -381,8 +394,6 b' def engine_from_config(configuration, pr'
381 394 parameters, context, executemany):
382 395 delattr(conn, 'query_start_time')
383 396
384 sqlalchemy.event.listen(engine, "engine_connect",
385 ping_connection)
386 397 sqlalchemy.event.listen(engine, "before_cursor_execute",
387 398 before_cursor_execute)
388 399 sqlalchemy.event.listen(engine, "after_cursor_execute",
@@ -740,6 +751,13 b' class AttributeDict(AttributeDictBase):'
740 751
741 752
742 753
754 class OrderedDefaultDict(collections.OrderedDict, collections.defaultdict):
755 def __init__(self, default_factory=None, *args, **kwargs):
756 # in python3 you can omit the args to super
757 super(OrderedDefaultDict, self).__init__(*args, **kwargs)
758 self.default_factory = default_factory
759
760
743 761 def fix_PATH(os_=None):
744 762 """
745 763 Get current active python path, and append it to PATH variable to fix
@@ -22,7 +22,15 b''
22 22 Various version Control System version lib (vcs) management abstraction layer
23 23 for Python. Build with server client architecture.
24 24 """
25 import atexit
26 import logging
27 import urlparse
28 from cStringIO import StringIO
25 29
30 from rhodecode.lib.vcs.conf import settings
31 from rhodecode.lib.vcs.backends import get_vcs_instance, get_backend
32 from rhodecode.lib.vcs.exceptions import (
33 VCSError, RepositoryError, CommitError, VCSCommunicationError)
26 34
27 35 VERSION = (0, 5, 0, 'dev')
28 36
@@ -30,21 +38,8 b" VERSION = (0, 5, 0, 'dev')"
30 38
31 39 __all__ = [
32 40 'get_version', 'get_vcs_instance', 'get_backend',
33 'VCSError', 'RepositoryError', 'CommitError'
34 ]
35
36 import atexit
37 import logging
38 import subprocess32
39 import time
40 import urlparse
41 from cStringIO import StringIO
42
43
44 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.backends import get_vcs_instance, get_backend
46 from rhodecode.lib.vcs.exceptions import (
47 VCSError, RepositoryError, CommitError, VCSCommunicationError)
41 'VCSError', 'RepositoryError', 'CommitError', 'VCSCommunicationError'
42 ]
48 43
49 44 log = logging.getLogger(__name__)
50 45
@@ -176,7 +176,6 b' class BaseRepository(object):'
176 176 EMPTY_COMMIT_ID = '0' * 40
177 177
178 178 path = None
179 _remote = None
180 179
181 180 def __init__(self, repo_path, config=None, create=False, **kwargs):
182 181 """
@@ -222,6 +221,10 b' class BaseRepository(object):'
222 221 return config
223 222
224 223 @LazyProperty
224 def _remote(self):
225 raise NotImplementedError
226
227 @LazyProperty
225 228 def EMPTY_COMMIT(self):
226 229 return EmptyCommit(self.EMPTY_COMMIT_ID)
227 230
@@ -451,7 +454,7 b' class BaseRepository(object):'
451 454 """
452 455 raise NotImplementedError
453 456
454 def merge(self, target_ref, source_repo, source_ref, workspace_id,
457 def merge(self, repo_id, workspace_id, target_ref, source_repo, source_ref,
455 458 user_name='', user_email='', message='', dry_run=False,
456 459 use_rebase=False, close_branch=False):
457 460 """
@@ -465,13 +468,14 b' class BaseRepository(object):'
465 468 'possible', 'executed', 'source_commit', 'target_commit',
466 469 'merge_commit'.
467 470
471 :param repo_id: `repo_id` target repo id.
472 :param workspace_id: `workspace_id` unique identifier.
468 473 :param target_ref: `target_ref` points to the commit on top of which
469 474 the `source_ref` should be merged.
470 475 :param source_repo: The repository that contains the commits to be
471 476 merged.
472 477 :param source_ref: `source_ref` points to the topmost commit from
473 478 the `source_repo` which should be merged.
474 :param workspace_id: `workspace_id` unique identifier.
475 479 :param user_name: Merge commit `user_name`.
476 480 :param user_email: Merge commit `user_email`.
477 481 :param message: Merge commit `message`.
@@ -492,12 +496,9 b' class BaseRepository(object):'
492 496 if not message:
493 497 raise ValueError('message cannot be empty')
494 498
495 shadow_repository_path = self._maybe_prepare_merge_workspace(
496 workspace_id, target_ref, source_ref)
497
498 499 try:
499 500 return self._merge_repo(
500 shadow_repository_path, target_ref, source_repo,
501 repo_id, workspace_id, target_ref, source_repo,
501 502 source_ref, message, user_name, user_email, dry_run=dry_run,
502 503 use_rebase=use_rebase, close_branch=close_branch)
503 504 except RepositoryError:
@@ -507,14 +508,15 b' class BaseRepository(object):'
507 508 return MergeResponse(
508 509 False, False, None, MergeFailureReason.UNKNOWN)
509 510
510 def _merge_repo(self, shadow_repository_path, target_ref,
511 def _merge_repo(self, repo_id, workspace_id, target_ref,
511 512 source_repo, source_ref, merge_message,
512 513 merger_name, merger_email, dry_run=False,
513 514 use_rebase=False, close_branch=False):
514 515 """Internal implementation of merge."""
515 516 raise NotImplementedError
516 517
517 def _maybe_prepare_merge_workspace(self, workspace_id, target_ref, source_ref):
518 def _maybe_prepare_merge_workspace(
519 self, repo_id, workspace_id, target_ref, source_ref):
518 520 """
519 521 Create the merge workspace.
520 522
@@ -522,10 +524,27 b' class BaseRepository(object):'
522 524 """
523 525 raise NotImplementedError
524 526
525 def _get_shadow_repository_path(self, workspace_id):
526 raise NotImplementedError
527 def _get_legacy_shadow_repository_path(self, workspace_id):
528 """
529 Legacy version that was used before. We still need it for
530 backward compat
531 """
532 return os.path.join(
533 os.path.dirname(self.path),
534 '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
527 535
528 def cleanup_merge_workspace(self, workspace_id):
536 def _get_shadow_repository_path(self, repo_id, workspace_id):
537 # The name of the shadow repository must start with '.', so it is
538 # skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
539 legacy_repository_path = self._get_legacy_shadow_repository_path(workspace_id)
540 if os.path.exists(legacy_repository_path):
541 return legacy_repository_path
542 else:
543 return os.path.join(
544 os.path.dirname(self.path),
545 '.__shadow_repo_%s_%s' % (repo_id, workspace_id))
546
547 def cleanup_merge_workspace(self, repo_id, workspace_id):
529 548 """
530 549 Remove merge workspace.
531 550
@@ -534,7 +553,7 b' class BaseRepository(object):'
534 553
535 554 :param workspace_id: `workspace_id` unique identifier.
536 555 """
537 shadow_repository_path = self._get_shadow_repository_path(workspace_id)
556 shadow_repository_path = self._get_shadow_repository_path(repo_id, workspace_id)
538 557 shadow_repository_path_del = '{}.{}.delete'.format(
539 558 shadow_repository_path, time.time())
540 559
@@ -62,8 +62,7 b' class GitRepository(BaseRepository):'
62 62
63 63 self.path = safe_str(os.path.abspath(repo_path))
64 64 self.config = config if config else self.get_default_config()
65 self._remote = connection.Git(
66 self.path, self.config, with_wire=with_wire)
65 self.with_wire = with_wire
67 66
68 67 self._init_repo(create, src_url, update_after_clone, bare)
69 68
@@ -71,6 +70,10 b' class GitRepository(BaseRepository):'
71 70 self._commit_ids = {}
72 71
73 72 @LazyProperty
73 def _remote(self):
74 return connection.Git(self.path, self.config, with_wire=self.with_wire)
75
76 @LazyProperty
74 77 def bare(self):
75 78 return self._remote.bare()
76 79
@@ -103,8 +106,9 b' class GitRepository(BaseRepository):'
103 106 if not isinstance(cmd, list):
104 107 raise ValueError('cmd must be a list, got %s instead' % type(cmd))
105 108
109 skip_stderr_log = opts.pop('skip_stderr_log', False)
106 110 out, err = self._remote.run_git_command(cmd, **opts)
107 if err:
111 if err and not skip_stderr_log:
108 112 log.debug('Stderr output of git command "%s":\n%s', cmd, err)
109 113 return out, err
110 114
@@ -173,9 +177,9 b' class GitRepository(BaseRepository):'
173 177 # we must check if this repo is not empty, since later command
174 178 # fails if it is. And it's cheaper to ask than throw the subprocess
175 179 # errors
176 try:
177 self._remote.head()
178 except KeyError:
180
181 head = self._remote.head(show_exc=False)
182 if not head:
179 183 return []
180 184
181 185 rev_filter = ['--branches', '--tags']
@@ -756,7 +760,7 b' class GitRepository(BaseRepository):'
756 760 cmd = ['fetch', self.path, source_branch]
757 761 self.run_git_command(cmd, fail_on_stderr=False)
758 762
759 def _local_fetch(self, repository_path, branch_name):
763 def _local_fetch(self, repository_path, branch_name, use_origin=False):
760 764 """
761 765 Fetch a branch from a local repository.
762 766 """
@@ -764,7 +768,17 b' class GitRepository(BaseRepository):'
764 768 if repository_path == self.path:
765 769 raise ValueError('Cannot fetch from the same repository')
766 770
767 cmd = ['fetch', '--no-tags', repository_path, branch_name]
771 if use_origin:
772 branch_name = '+{branch}:refs/heads/{branch}'.format(
773 branch=branch_name)
774
775 cmd = ['fetch', '--no-tags', '--update-head-ok',
776 repository_path, branch_name]
777 self.run_git_command(cmd, fail_on_stderr=False)
778
779 def _local_reset(self, branch_name):
780 branch_name = '{}'.format(branch_name)
781 cmd = ['reset', '--hard', branch_name]
768 782 self.run_git_command(cmd, fail_on_stderr=False)
769 783
770 784 def _last_fetch_heads(self):
@@ -834,12 +848,12 b' class GitRepository(BaseRepository):'
834 848
835 849 # N.B.(skreft): the --no-ff option is used to enforce the creation of a
836 850 # commit message. We also specify the user who is doing the merge.
837 cmd = ['-c', 'user.name=%s' % safe_str(user_name),
851 cmd = ['-c', 'user.name="%s"' % safe_str(user_name),
838 852 '-c', 'user.email=%s' % safe_str(user_email),
839 853 'merge', '--no-ff', '-m', safe_str(merge_message)]
840 854 cmd.extend(heads)
841 855 try:
842 self.run_git_command(cmd, fail_on_stderr=False)
856 output = self.run_git_command(cmd, fail_on_stderr=False)
843 857 except RepositoryError:
844 858 # Cleanup any merge leftovers
845 859 self.run_git_command(['merge', '--abort'], fail_on_stderr=False)
@@ -891,35 +905,61 b' class GitRepository(BaseRepository):'
891 905
892 906 return '%s%d' % (prefix, branch_id)
893 907
894 def _merge_repo(self, shadow_repository_path, target_ref,
908 def _maybe_prepare_merge_workspace(
909 self, repo_id, workspace_id, target_ref, source_ref):
910 shadow_repository_path = self._get_shadow_repository_path(
911 repo_id, workspace_id)
912 if not os.path.exists(shadow_repository_path):
913 self._local_clone(
914 shadow_repository_path, target_ref.name, source_ref.name)
915 log.debug(
916 'Prepared shadow repository in %s', shadow_repository_path)
917
918 return shadow_repository_path
919
920 def _merge_repo(self, repo_id, workspace_id, target_ref,
895 921 source_repo, source_ref, merge_message,
896 922 merger_name, merger_email, dry_run=False,
897 923 use_rebase=False, close_branch=False):
898 924 if target_ref.commit_id != self.branches[target_ref.name]:
925 log.warning('Target ref %s commit mismatch %s vs %s', target_ref,
926 target_ref.commit_id, self.branches[target_ref.name])
899 927 return MergeResponse(
900 928 False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD)
901 929
902 shadow_repo = GitRepository(shadow_repository_path)
930 shadow_repository_path = self._maybe_prepare_merge_workspace(
931 repo_id, workspace_id, target_ref, source_ref)
932 shadow_repo = self._get_shadow_instance(shadow_repository_path)
933
903 934 # checkout source, if it's different. Otherwise we could not
904 935 # fetch proper commits for merge testing
905 936 if source_ref.name != target_ref.name:
906 937 if shadow_repo.get_remote_ref(source_ref.name):
907 938 shadow_repo._checkout(source_ref.name, force=True)
908 939
909 # checkout target
940 # checkout target, and fetch changes
910 941 shadow_repo._checkout(target_ref.name, force=True)
911 shadow_repo._local_pull(self.path, target_ref.name)
942
943 # fetch/reset pull the target, in case it is changed
944 # this handles even force changes
945 shadow_repo._local_fetch(self.path, target_ref.name, use_origin=True)
946 shadow_repo._local_reset(target_ref.name)
912 947
913 948 # Need to reload repo to invalidate the cache, or otherwise we cannot
914 949 # retrieve the last target commit.
915 shadow_repo = GitRepository(shadow_repository_path)
950 shadow_repo = self._get_shadow_instance(shadow_repository_path)
916 951 if target_ref.commit_id != shadow_repo.branches[target_ref.name]:
952 log.warning('Shadow Target ref %s commit mismatch %s vs %s',
953 target_ref, target_ref.commit_id,
954 shadow_repo.branches[target_ref.name])
917 955 return MergeResponse(
918 956 False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD)
919 957
958 # calculate new branch
920 959 pr_branch = shadow_repo._get_new_pr_branch(
921 960 source_ref.name, target_ref.name)
922 961 log.debug('using pull-request merge branch: `%s`', pr_branch)
962 # checkout to temp branch, and fetch changes
923 963 shadow_repo._checkout(pr_branch, create=True)
924 964 try:
925 965 shadow_repo._local_fetch(source_repo.path, source_ref.name)
@@ -967,18 +1007,3 b' class GitRepository(BaseRepository):'
967 1007 return MergeResponse(
968 1008 merge_possible, merge_succeeded, merge_ref,
969 1009 merge_failure_reason)
970
971 def _get_shadow_repository_path(self, workspace_id):
972 # The name of the shadow repository must start with '.', so it is
973 # skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
974 return os.path.join(
975 os.path.dirname(self.path),
976 '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
977
978 def _maybe_prepare_merge_workspace(self, workspace_id, target_ref, source_ref):
979 shadow_repository_path = self._get_shadow_repository_path(workspace_id)
980 if not os.path.exists(shadow_repository_path):
981 self._local_clone(
982 shadow_repository_path, target_ref.name, source_ref.name)
983
984 return shadow_repository_path
@@ -56,7 +56,7 b' class MercurialCommit(base.BaseCommit):'
56 56 self._remote = repository._remote
57 57
58 58 self.raw_id = raw_id
59 self.idx = repository._sanitize_commit_idx(idx)
59 self.idx = idx
60 60
61 61 self._set_bulk_properties(pre_load)
62 62
@@ -77,9 +77,7 b' class MercurialRepository(BaseRepository'
77 77 # special requirements
78 78 self.config = config if config else self.get_default_config(
79 79 default=[('extensions', 'largefiles', '1')])
80
81 self._remote = connection.Hg(
82 self.path, self.config, with_wire=with_wire)
80 self.with_wire = with_wire
83 81
84 82 self._init_repo(create, src_url, update_after_clone)
85 83
@@ -87,6 +85,10 b' class MercurialRepository(BaseRepository'
87 85 self._commit_ids = {}
88 86
89 87 @LazyProperty
88 def _remote(self):
89 return connection.Hg(self.path, self.config, with_wire=self.with_wire)
90
91 @LazyProperty
90 92 def commit_ids(self):
91 93 """
92 94 Returns list of commit ids, in ascending order. Being lazy
@@ -394,14 +396,6 b' class MercurialRepository(BaseRepository'
394 396 else:
395 397 return os.stat(st_path).st_mtime
396 398
397 def _sanitize_commit_idx(self, idx):
398 # Note: Mercurial has ``int(-1)`` reserved as not existing id_or_idx
399 # number. A `long` is treated in the correct way though. So we convert
400 # `int` to `long` here to make sure it is handled correctly.
401 if isinstance(idx, int):
402 return long(idx)
403 return idx
404
405 399 def _get_url(self, url):
406 400 """
407 401 Returns normalized url. If schema is not given, would fall
@@ -436,7 +430,6 b' class MercurialRepository(BaseRepository'
436 430 pass
437 431 elif commit_idx is not None:
438 432 self._validate_commit_idx(commit_idx)
439 commit_idx = self._sanitize_commit_idx(commit_idx)
440 433 try:
441 434 id_ = self.commit_ids[commit_idx]
442 435 if commit_idx < 0:
@@ -448,10 +441,6 b' class MercurialRepository(BaseRepository'
448 441 else:
449 442 commit_id = "tip"
450 443
451 # TODO Paris: Ugly hack to "serialize" long for msgpack
452 if isinstance(commit_id, long):
453 commit_id = float(commit_id)
454
455 444 if isinstance(commit_id, unicode):
456 445 commit_id = safe_str(commit_id)
457 446
@@ -694,15 +683,10 b' class MercurialRepository(BaseRepository'
694 683 return ref.name
695 684 return self._remote.ctx_branch(ref.commit_id)
696 685
697 def _get_shadow_repository_path(self, workspace_id):
698 # The name of the shadow repository must start with '.', so it is
699 # skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
700 return os.path.join(
701 os.path.dirname(self.path),
702 '.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
703
704 def _maybe_prepare_merge_workspace(self, workspace_id, unused_target_ref, unused_source_ref):
705 shadow_repository_path = self._get_shadow_repository_path(workspace_id)
686 def _maybe_prepare_merge_workspace(
687 self, repo_id, workspace_id, unused_target_ref, unused_source_ref):
688 shadow_repository_path = self._get_shadow_repository_path(
689 repo_id, workspace_id)
706 690 if not os.path.exists(shadow_repository_path):
707 691 self._local_clone(shadow_repository_path)
708 692 log.debug(
@@ -710,7 +694,7 b' class MercurialRepository(BaseRepository'
710 694
711 695 return shadow_repository_path
712 696
713 def _merge_repo(self, shadow_repository_path, target_ref,
697 def _merge_repo(self, repo_id, workspace_id, target_ref,
714 698 source_repo, source_ref, merge_message,
715 699 merger_name, merger_email, dry_run=False,
716 700 use_rebase=False, close_branch=False):
@@ -732,6 +716,8 b' class MercurialRepository(BaseRepository'
732 716 return MergeResponse(
733 717 False, False, None, MergeFailureReason.MISSING_TARGET_REF)
734 718
719 shadow_repository_path = self._maybe_prepare_merge_workspace(
720 repo_id, workspace_id, target_ref, source_ref)
735 721 shadow_repo = self._get_shadow_instance(shadow_repository_path)
736 722
737 723 log.debug('Pulling in target reference %s', target_ref)
@@ -72,11 +72,13 b' class SubversionRepository(base.BaseRepo'
72 72 **kwargs):
73 73 self.path = safe_str(os.path.abspath(repo_path))
74 74 self.config = config if config else self.get_default_config()
75 self._remote = connection.Svn(
76 self.path, self.config)
77 75
78 76 self._init_repo(create, src_url)
79 77
78 @LazyProperty
79 def _remote(self):
80 return connection.Svn(self.path, self.config)
81
80 82 def _init_repo(self, create, src_url):
81 83 if create and os.path.exists(self.path):
82 84 raise RepositoryError(
@@ -28,6 +28,7 b' import threading'
28 28 import urllib2
29 29 import urlparse
30 30 import uuid
31 import traceback
31 32
32 33 import pycurl
33 34 import msgpack
@@ -139,8 +140,9 b' class RemoteRepo(object):'
139 140 return _remote_call(self.url, payload, EXCEPTIONS_MAP, self._session)
140 141
141 142 def _call_with_logging(self, name, *args, **kwargs):
142
143 log.debug('Calling %s@%s with args:%r', self.url, name, args)
143 context_uid = self._wire.get('context')
144 log.debug('Calling %s@%s with args:%r. wire_context: %s',
145 self.url, name, args, context_uid)
144 146 return RemoteRepo._call(self, name, *args, **kwargs)
145 147
146 148 def __getitem__(self, key):
@@ -196,7 +198,8 b' def _remote_call(url, payload, exception'
196 198 try:
197 199 response = session.post(url, data=msgpack.packb(payload))
198 200 except pycurl.error as e:
199 raise exceptions.HttpVCSCommunicationError(e)
201 msg = '{}. \npycurl traceback: {}'.format(e, traceback.format_exc())
202 raise exceptions.HttpVCSCommunicationError(msg)
200 203 except Exception as e:
201 204 message = getattr(e, 'message', '')
202 205 if 'Failed to connect' in message:
@@ -51,6 +51,7 b' ARCHIVE_SPECS = {'
51 51
52 52 HOOKS_PROTOCOL = None
53 53 HOOKS_DIRECT_CALLS = False
54 HOOKS_HOST = '127.0.0.1'
54 55
55 56
56 57 def available_aliases():
@@ -205,7 +205,7 b' def map_vcs_exceptions(func):'
205 205 args = e.args
206 206 else:
207 207 args = [__traceback_info__ or 'unhandledException']
208 if __traceback_info__ and kind != 'unhandled':
208 if __traceback_info__ and kind not in ['unhandled', 'lookup']:
209 209 # for other than unhandled errors also log the traceback
210 210 # can be usefull for debugging
211 211 log.error(__traceback_info__)
@@ -27,6 +27,7 b' class in a way that is compatible with g'
27 27 import logging
28 28 import gevent
29 29 import pycurl
30 import greenlet
30 31
31 32 # Import everything from pycurl.
32 33 # This allows us to use this module as a drop in replacement of pycurl.
@@ -139,7 +140,7 b' class GeventCurlMulti(object):'
139 140 while True:
140 141 try:
141 142 ret, num_handles = self._curl_multi.socket_action(fd, action)
142 except pycurl.error, e:
143 except pycurl.error as e:
143 144 ret = e.args[0]
144 145 if ret != pycurl.E_CALL_MULTI_PERFORM:
145 146 break
@@ -156,7 +157,7 b' class GeventCurlMulti(object):'
156 157 try:
157 158 ret, num_handles = self._curl_multi.socket_action(
158 159 pycurl.SOCKET_TIMEOUT, 0)
159 except pycurl.error, e:
160 except pycurl.error as e:
160 161 ret = e.args[0]
161 162 if ret != pycurl.E_CALL_MULTI_PERFORM:
162 163 break
@@ -186,7 +187,7 b' class GeventCurlMulti(object):'
186 187 while True:
187 188 num_q, ok_list, err_list = self._curl_multi.info_read()
188 189 for curl in ok_list:
189 curl.waiter.switch()
190 curl.waiter.switch(None)
190 191 for curl, errnum, errmsg in err_list:
191 192 curl.waiter.throw(Exception('%s %s' % (errnum, errmsg)))
192 193 if num_q == 0:
@@ -230,15 +231,22 b' class GeventCurl(object):'
230 231 This perform method is compatible with gevent because it uses gevent
231 232 synchronization mechanisms to wait for the request to finish.
232 233 """
234 if getattr(self._curl, 'waiter', None) is not None:
235 current = greenlet.getcurrent()
236 msg = 'This curl object is already used by another greenlet, {}, \n' \
237 'this is {}'.format(self._curl.waiter, current)
238 raise Exception(msg)
239
233 240 waiter = self._curl.waiter = Waiter()
234 241 try:
235 242 self._multi.add_handle(self._curl)
236 response = waiter.get()
243 try:
244 return waiter.get()
245 finally:
246 self._multi.remove_handle(self._curl)
237 247 finally:
238 self._multi.remove_handle(self._curl)
239 248 del self._curl.waiter
240 249
241 return response
242 250
243 251 # Curl is originally imported from pycurl. At this point we override it with
244 252 # our custom implementation.
@@ -159,18 +159,18 b' class CommentsModel(BaseModel):'
159 159
160 160 return todos
161 161
162 def _log_audit_action(self, action, action_data, user, comment):
162 def _log_audit_action(self, action, action_data, auth_user, comment):
163 163 audit_logger.store(
164 164 action=action,
165 165 action_data=action_data,
166 user=user,
166 user=auth_user,
167 167 repo=comment.repo)
168 168
169 169 def create(self, text, repo, user, commit_id=None, pull_request=None,
170 170 f_path=None, line_no=None, status_change=None,
171 171 status_change_type=None, comment_type=None,
172 172 resolves_comment_id=None, closing_pr=False, send_email=True,
173 renderer=None):
173 renderer=None, auth_user=None):
174 174 """
175 175 Creates new comment for commit or pull request.
176 176 IF status_change is not none this comment is associated with a
@@ -190,6 +190,8 b' class CommentsModel(BaseModel):'
190 190 :param send_email:
191 191 :param renderer: pick renderer for this comment
192 192 """
193
194 auth_user = auth_user or user
193 195 if not text:
194 196 log.warning('Missing text for comment, skipping...')
195 197 return
@@ -355,7 +357,7 b' class CommentsModel(BaseModel):'
355 357
356 358 comment_data = comment.get_api_data()
357 359 self._log_audit_action(
358 action, {'data': comment_data}, user, comment)
360 action, {'data': comment_data}, auth_user, comment)
359 361
360 362 msg_url = ''
361 363 channel = None
@@ -388,7 +390,7 b' class CommentsModel(BaseModel):'
388 390
389 391 return comment
390 392
391 def delete(self, comment, user):
393 def delete(self, comment, auth_user):
392 394 """
393 395 Deletes given comment
394 396 """
@@ -402,7 +404,7 b' class CommentsModel(BaseModel):'
402 404 action = 'repo.commit.comment.delete'
403 405
404 406 self._log_audit_action(
405 action, {'old_data': old_data}, user, comment)
407 action, {'old_data': old_data}, auth_user, comment)
406 408
407 409 return comment
408 410
This diff has been collapsed as it changes many lines, (664 lines changed) Show them Hide them
@@ -47,7 +47,6 b' from sqlalchemy.ext.declarative import d'
47 47 from sqlalchemy.ext.hybrid import hybrid_property
48 48 from sqlalchemy.exc import IntegrityError # noqa
49 49 from sqlalchemy.dialects.mysql import LONGTEXT
50 from beaker.cache import cache_region
51 50 from zope.cachedescriptors.property import Lazy as LazyProperty
52 51
53 52 from pyramid.threadlocal import get_current_request
@@ -56,7 +55,7 b' from rhodecode.translation import _'
56 55 from rhodecode.lib.vcs import get_vcs_instance
57 56 from rhodecode.lib.vcs.backends.base import EmptyCommit, Reference
58 57 from rhodecode.lib.utils2 import (
59 str2bool, safe_str, get_commit_safe, safe_unicode, md5_safe,
58 str2bool, safe_str, get_commit_safe, safe_unicode, sha1_safe,
60 59 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict,
61 60 glob2re, StrictAttributeDict, cleaned_uri)
62 61 from rhodecode.lib.jsonalchemy import MutationObj, MutationList, JsonType, \
@@ -114,7 +113,7 b' def display_user_group_sort(obj):'
114 113
115 114
116 115 def _hash_key(k):
117 return md5_safe(k)
116 return sha1_safe(k)
118 117
119 118
120 119 def in_filter_generator(qry, items, limit=500):
@@ -140,6 +139,14 b' def in_filter_generator(qry, items, limi'
140 139 return parts
141 140
142 141
142 base_table_args = {
143 'extend_existing': True,
144 'mysql_engine': 'InnoDB',
145 'mysql_charset': 'utf8',
146 'sqlite_autoincrement': True
147 }
148
149
143 150 class EncryptedTextValue(TypeDecorator):
144 151 """
145 152 Special column for encrypted long text data, use like::
@@ -302,8 +309,7 b' class RhodeCodeSetting(Base, BaseModel):'
302 309 __tablename__ = 'rhodecode_settings'
303 310 __table_args__ = (
304 311 UniqueConstraint('app_settings_name'),
305 {'extend_existing': True, 'mysql_engine': 'InnoDB',
306 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
312 base_table_args
307 313 )
308 314
309 315 SETTINGS_TYPES = {
@@ -383,8 +389,7 b' class RhodeCodeUi(Base, BaseModel):'
383 389 __tablename__ = 'rhodecode_ui'
384 390 __table_args__ = (
385 391 UniqueConstraint('ui_key'),
386 {'extend_existing': True, 'mysql_engine': 'InnoDB',
387 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
392 base_table_args
388 393 )
389 394
390 395 HOOK_REPO_SIZE = 'changegroup.repo_size'
@@ -426,8 +431,7 b' class RepoRhodeCodeSetting(Base, BaseMod'
426 431 UniqueConstraint(
427 432 'app_settings_name', 'repository_id',
428 433 name='uq_repo_rhodecode_setting_name_repo_id'),
429 {'extend_existing': True, 'mysql_engine': 'InnoDB',
430 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
434 base_table_args
431 435 )
432 436
433 437 repository_id = Column(
@@ -502,8 +506,7 b' class RepoRhodeCodeUi(Base, BaseModel):'
502 506 UniqueConstraint(
503 507 'repository_id', 'ui_section', 'ui_key',
504 508 name='uq_repo_rhodecode_ui_repository_id_section_key'),
505 {'extend_existing': True, 'mysql_engine': 'InnoDB',
506 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
509 base_table_args
507 510 )
508 511
509 512 repository_id = Column(
@@ -535,9 +538,9 b' class User(Base, BaseModel):'
535 538 UniqueConstraint('username'), UniqueConstraint('email'),
536 539 Index('u_username_idx', 'username'),
537 540 Index('u_email_idx', 'email'),
538 {'extend_existing': True, 'mysql_engine': 'InnoDB',
539 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
541 base_table_args
540 542 )
543
541 544 DEFAULT_USER = 'default'
542 545 DEFAULT_USER_EMAIL = 'anonymous@rhodecode.org'
543 546 DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
@@ -686,7 +689,7 b' class User(Base, BaseModel):'
686 689 .filter(UserApiKeys.role == UserApiKeys.ROLE_FEED)
687 690 if cache:
688 691 feed_tokens = feed_tokens.options(
689 FromCache("long_term", "get_user_feed_token_%s" % self.user_id))
692 FromCache("sql_cache_short", "get_user_feed_token_%s" % self.user_id))
690 693
691 694 feed_tokens = feed_tokens.all()
692 695 if feed_tokens:
@@ -927,12 +930,6 b' class User(Base, BaseModel):'
927 930 Session().add(self)
928 931 log.debug('updated user %s lastlogin', self.username)
929 932
930 def update_lastactivity(self):
931 """Update user lastactivity"""
932 self.last_activity = datetime.datetime.now()
933 Session().add(self)
934 log.debug('updated user `%s` last activity', self.username)
935
936 933 def update_password(self, new_password):
937 934 from rhodecode.lib.auth import get_crypt_password
938 935
@@ -1034,8 +1031,7 b' class UserApiKeys(Base, BaseModel):'
1034 1031 __table_args__ = (
1035 1032 Index('uak_api_key_idx', 'api_key', unique=True),
1036 1033 Index('uak_api_key_expires_idx', 'api_key', 'expires'),
1037 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1038 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1034 base_table_args
1039 1035 )
1040 1036 __mapper_args__ = {}
1041 1037
@@ -1137,8 +1133,7 b' class UserEmailMap(Base, BaseModel):'
1137 1133 __table_args__ = (
1138 1134 Index('uem_email_idx', 'email'),
1139 1135 UniqueConstraint('email'),
1140 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1141 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1136 base_table_args
1142 1137 )
1143 1138 __mapper_args__ = {}
1144 1139
@@ -1168,8 +1163,7 b' class UserIpMap(Base, BaseModel):'
1168 1163 __tablename__ = 'user_ip_map'
1169 1164 __table_args__ = (
1170 1165 UniqueConstraint('user_id', 'ip_addr'),
1171 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1172 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1166 base_table_args
1173 1167 )
1174 1168 __mapper_args__ = {}
1175 1169
@@ -1208,8 +1202,7 b' class UserSshKeys(Base, BaseModel):'
1208 1202
1209 1203 UniqueConstraint('ssh_key_fingerprint'),
1210 1204
1211 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1212 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1205 base_table_args
1213 1206 )
1214 1207 __mapper_args__ = {}
1215 1208
@@ -1241,9 +1234,9 b' class UserSshKeys(Base, BaseModel):'
1241 1234 class UserLog(Base, BaseModel):
1242 1235 __tablename__ = 'user_logs'
1243 1236 __table_args__ = (
1244 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1245 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1237 base_table_args,
1246 1238 )
1239
1247 1240 VERSION_1 = 'v1'
1248 1241 VERSION_2 = 'v2'
1249 1242 VERSIONS = [VERSION_1, VERSION_2]
@@ -1291,8 +1284,7 b' class UserLog(Base, BaseModel):'
1291 1284 class UserGroup(Base, BaseModel):
1292 1285 __tablename__ = 'users_groups'
1293 1286 __table_args__ = (
1294 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1295 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1287 base_table_args,
1296 1288 )
1297 1289
1298 1290 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -1384,6 +1376,32 b' class UserGroup(Base, BaseModel):'
1384 1376 return user_group.get(user_group_id)
1385 1377
1386 1378 def permissions(self, with_admins=True, with_owner=True):
1379 """
1380 Permissions for user groups
1381 """
1382 _admin_perm = 'usergroup.admin'
1383
1384 owner_row = []
1385 if with_owner:
1386 usr = AttributeDict(self.user.get_dict())
1387 usr.owner_row = True
1388 usr.permission = _admin_perm
1389 owner_row.append(usr)
1390
1391 super_admin_ids = []
1392 super_admin_rows = []
1393 if with_admins:
1394 for usr in User.get_all_super_admins():
1395 super_admin_ids.append(usr.user_id)
1396 # if this admin is also owner, don't double the record
1397 if usr.user_id == owner_row[0].user_id:
1398 owner_row[0].admin_row = True
1399 else:
1400 usr = AttributeDict(usr.get_dict())
1401 usr.admin_row = True
1402 usr.permission = _admin_perm
1403 super_admin_rows.append(usr)
1404
1387 1405 q = UserUserGroupToPerm.query().filter(UserUserGroupToPerm.user_group == self)
1388 1406 q = q.options(joinedload(UserUserGroupToPerm.user_group),
1389 1407 joinedload(UserUserGroupToPerm.user),
@@ -1397,6 +1415,9 b' class UserGroup(Base, BaseModel):'
1397 1415 perm_rows = []
1398 1416 for _usr in q.all():
1399 1417 usr = AttributeDict(_usr.user.get_dict())
1418 # if this user is also owner/admin, mark as duplicate record
1419 if usr.user_id == owner_row[0].user_id or usr.user_id in super_admin_ids:
1420 usr.duplicate_perm = True
1400 1421 usr.permission = _usr.permission.permission_name
1401 1422 perm_rows.append(usr)
1402 1423
@@ -1405,26 +1426,6 b' class UserGroup(Base, BaseModel):'
1405 1426 # each group
1406 1427 perm_rows = sorted(perm_rows, key=display_user_sort)
1407 1428
1408 _admin_perm = 'usergroup.admin'
1409 owner_row = []
1410 if with_owner:
1411 usr = AttributeDict(self.user.get_dict())
1412 usr.owner_row = True
1413 usr.permission = _admin_perm
1414 owner_row.append(usr)
1415
1416 super_admin_rows = []
1417 if with_admins:
1418 for usr in User.get_all_super_admins():
1419 # if this admin is also owner, don't double the record
1420 if usr.user_id == owner_row[0].user_id:
1421 owner_row[0].admin_row = True
1422 else:
1423 usr = AttributeDict(usr.get_dict())
1424 usr.admin_row = True
1425 usr.permission = _admin_perm
1426 super_admin_rows.append(usr)
1427
1428 1429 return super_admin_rows + owner_row + perm_rows
1429 1430
1430 1431 def permission_user_groups(self):
@@ -1479,8 +1480,7 b' class UserGroup(Base, BaseModel):'
1479 1480 class UserGroupMember(Base, BaseModel):
1480 1481 __tablename__ = 'users_groups_members'
1481 1482 __table_args__ = (
1482 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1483 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1483 base_table_args,
1484 1484 )
1485 1485
1486 1486 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -1499,9 +1499,9 b' class RepositoryField(Base, BaseModel):'
1499 1499 __tablename__ = 'repositories_fields'
1500 1500 __table_args__ = (
1501 1501 UniqueConstraint('repository_id', 'field_key'), # no-multi field
1502 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1503 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1502 base_table_args,
1504 1503 )
1504
1505 1505 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
1506 1506
1507 1507 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -1537,8 +1537,7 b' class Repository(Base, BaseModel):'
1537 1537 __tablename__ = 'repositories'
1538 1538 __table_args__ = (
1539 1539 Index('r_repo_name_idx', 'repo_name', mysql_length=255),
1540 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1541 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1540 base_table_args,
1542 1541 )
1543 1542 DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
1544 1543 DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}'
@@ -1854,8 +1853,10 b' class Repository(Base, BaseModel):'
1854 1853 """
1855 1854 Returns associated cache keys for that repo
1856 1855 """
1856 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
1857 repo_id=self.repo_id)
1857 1858 return CacheKey.query()\
1858 .filter(CacheKey.cache_args == self.repo_name)\
1859 .filter(CacheKey.cache_args == invalidation_namespace)\
1859 1860 .order_by(CacheKey.cache_key)\
1860 1861 .all()
1861 1862
@@ -1883,6 +1884,12 b' class Repository(Base, BaseModel):'
1883 1884 return os.listdir(diff_cache_dir)
1884 1885 return []
1885 1886
1887 def shadow_repos(self):
1888 shadow_repos_pattern = '.__shadow_repo_{}'.format(self.repo_id)
1889 return [
1890 x for x in os.listdir(os.path.dirname(self.repo_full_path))
1891 if x.startswith(shadow_repos_pattern)]
1892
1886 1893 def get_new_name(self, repo_name):
1887 1894 """
1888 1895 returns new full repository name based on assigned group and new new
@@ -1901,6 +1908,34 b' class Repository(Base, BaseModel):'
1901 1908 return make_db_config(clear_session=False, repo=self)
1902 1909
1903 1910 def permissions(self, with_admins=True, with_owner=True):
1911 """
1912 Permissions for repositories
1913 """
1914 _admin_perm = 'repository.admin'
1915
1916 owner_row = []
1917 if with_owner:
1918 usr = AttributeDict(self.user.get_dict())
1919 usr.owner_row = True
1920 usr.permission = _admin_perm
1921 usr.permission_id = None
1922 owner_row.append(usr)
1923
1924 super_admin_ids = []
1925 super_admin_rows = []
1926 if with_admins:
1927 for usr in User.get_all_super_admins():
1928 super_admin_ids.append(usr.user_id)
1929 # if this admin is also owner, don't double the record
1930 if usr.user_id == owner_row[0].user_id:
1931 owner_row[0].admin_row = True
1932 else:
1933 usr = AttributeDict(usr.get_dict())
1934 usr.admin_row = True
1935 usr.permission = _admin_perm
1936 usr.permission_id = None
1937 super_admin_rows.append(usr)
1938
1904 1939 q = UserRepoToPerm.query().filter(UserRepoToPerm.repository == self)
1905 1940 q = q.options(joinedload(UserRepoToPerm.repository),
1906 1941 joinedload(UserRepoToPerm.user),
@@ -1914,7 +1949,15 b' class Repository(Base, BaseModel):'
1914 1949 perm_rows = []
1915 1950 for _usr in q.all():
1916 1951 usr = AttributeDict(_usr.user.get_dict())
1952 # if this user is also owner/admin, mark as duplicate record
1953 if usr.user_id == owner_row[0].user_id or usr.user_id in super_admin_ids:
1954 usr.duplicate_perm = True
1955 # also check if this permission is maybe used by branch_permissions
1956 if _usr.branch_perm_entry:
1957 usr.branch_rules = [x.branch_rule_id for x in _usr.branch_perm_entry]
1958
1917 1959 usr.permission = _usr.permission.permission_name
1960 usr.permission_id = _usr.repo_to_perm_id
1918 1961 perm_rows.append(usr)
1919 1962
1920 1963 # filter the perm rows by 'default' first and then sort them by
@@ -1922,26 +1965,6 b' class Repository(Base, BaseModel):'
1922 1965 # each group
1923 1966 perm_rows = sorted(perm_rows, key=display_user_sort)
1924 1967
1925 _admin_perm = 'repository.admin'
1926 owner_row = []
1927 if with_owner:
1928 usr = AttributeDict(self.user.get_dict())
1929 usr.owner_row = True
1930 usr.permission = _admin_perm
1931 owner_row.append(usr)
1932
1933 super_admin_rows = []
1934 if with_admins:
1935 for usr in User.get_all_super_admins():
1936 # if this admin is also owner, don't double the record
1937 if usr.user_id == owner_row[0].user_id:
1938 owner_row[0].admin_row = True
1939 else:
1940 usr = AttributeDict(usr.get_dict())
1941 usr.admin_row = True
1942 usr.permission = _admin_perm
1943 super_admin_rows.append(usr)
1944
1945 1968 return super_admin_rows + owner_row + perm_rows
1946 1969
1947 1970 def permission_user_groups(self):
@@ -2208,7 +2231,9 b' class Repository(Base, BaseModel):'
2208 2231 if cs_cache is None:
2209 2232 # use no-cache version here
2210 2233 scm_repo = self.scm_instance(cache=False, config=config)
2211 if scm_repo:
2234
2235 empty = scm_repo.is_empty()
2236 if not empty:
2212 2237 cs_cache = scm_repo.get_commit(
2213 2238 pre_load=["author", "date", "message", "parents"])
2214 2239 else:
@@ -2225,8 +2250,13 b' class Repository(Base, BaseModel):'
2225 2250
2226 2251 # check if we have maybe already latest cached revision
2227 2252 if is_outdated(cs_cache) or not self.changeset_cache:
2228 _default = datetime.datetime.fromtimestamp(0)
2253 _default = datetime.datetime.utcnow()
2229 2254 last_change = cs_cache.get('date') or _default
2255 if self.updated_on and self.updated_on > last_change:
2256 # we check if last update is newer than the new value
2257 # if yes, we use the current timestamp instead. Imagine you get
2258 # old commit pushed 1y ago, we'd set last update 1y to ago.
2259 last_change = _default
2230 2260 log.debug('updated repo %s with new cs cache %s',
2231 2261 self.repo_name, cs_cache)
2232 2262 self.updated_on = last_change
@@ -2325,18 +2355,34 b' class Repository(Base, BaseModel):'
2325 2355 return self._get_instance(cache=bool(cache), config=config)
2326 2356
2327 2357 def _get_instance_cached(self):
2328 @cache_region('long_term')
2329 def _get_repo(cache_key):
2358 from rhodecode.lib import rc_cache
2359
2360 cache_namespace_uid = 'cache_repo_instance.{}'.format(self.repo_id)
2361 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
2362 repo_id=self.repo_id)
2363 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
2364
2365 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
2366 def get_instance_cached(repo_id, context_id):
2330 2367 return self._get_instance()
2331 2368
2332 invalidator_context = CacheKey.repo_context_cache(
2333 _get_repo, self.repo_name, None, thread_scoped=True)
2334
2335 with invalidator_context as context:
2336 context.invalidate()
2337 repo = context.compute()
2338
2339 return repo
2369 # we must use thread scoped cache here,
2370 # because each thread of gevent needs it's own not shared connection and cache
2371 # we also alter `args` so the cache key is individual for every green thread.
2372 inv_context_manager = rc_cache.InvalidationContext(
2373 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace,
2374 thread_scoped=True)
2375 with inv_context_manager as invalidation_context:
2376 args = (self.repo_id, inv_context_manager.cache_key)
2377 # re-compute and store cache if we get invalidate signal
2378 if invalidation_context.should_invalidate():
2379 instance = get_instance_cached.refresh(*args)
2380 else:
2381 instance = get_instance_cached(*args)
2382
2383 log.debug(
2384 'Repo instance fetched in %.3fs', inv_context_manager.compute_time)
2385 return instance
2340 2386
2341 2387 def _get_instance(self, cache=True, config=None):
2342 2388 config = config or self._config
@@ -2370,8 +2416,7 b' class RepoGroup(Base, BaseModel):'
2370 2416 __table_args__ = (
2371 2417 UniqueConstraint('group_name', 'group_parent_id'),
2372 2418 CheckConstraint('group_id != group_parent_id'),
2373 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2374 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
2419 base_table_args,
2375 2420 )
2376 2421 __mapper_args__ = {'order_by': 'group_name'}
2377 2422
@@ -2574,6 +2619,32 b' class RepoGroup(Base, BaseModel):'
2574 2619 return RepoGroup.url_sep().join(path_prefix + [group_name])
2575 2620
2576 2621 def permissions(self, with_admins=True, with_owner=True):
2622 """
2623 Permissions for repository groups
2624 """
2625 _admin_perm = 'group.admin'
2626
2627 owner_row = []
2628 if with_owner:
2629 usr = AttributeDict(self.user.get_dict())
2630 usr.owner_row = True
2631 usr.permission = _admin_perm
2632 owner_row.append(usr)
2633
2634 super_admin_ids = []
2635 super_admin_rows = []
2636 if with_admins:
2637 for usr in User.get_all_super_admins():
2638 super_admin_ids.append(usr.user_id)
2639 # if this admin is also owner, don't double the record
2640 if usr.user_id == owner_row[0].user_id:
2641 owner_row[0].admin_row = True
2642 else:
2643 usr = AttributeDict(usr.get_dict())
2644 usr.admin_row = True
2645 usr.permission = _admin_perm
2646 super_admin_rows.append(usr)
2647
2577 2648 q = UserRepoGroupToPerm.query().filter(UserRepoGroupToPerm.group == self)
2578 2649 q = q.options(joinedload(UserRepoGroupToPerm.group),
2579 2650 joinedload(UserRepoGroupToPerm.user),
@@ -2587,6 +2658,9 b' class RepoGroup(Base, BaseModel):'
2587 2658 perm_rows = []
2588 2659 for _usr in q.all():
2589 2660 usr = AttributeDict(_usr.user.get_dict())
2661 # if this user is also owner/admin, mark as duplicate record
2662 if usr.user_id == owner_row[0].user_id or usr.user_id in super_admin_ids:
2663 usr.duplicate_perm = True
2590 2664 usr.permission = _usr.permission.permission_name
2591 2665 perm_rows.append(usr)
2592 2666
@@ -2595,30 +2669,11 b' class RepoGroup(Base, BaseModel):'
2595 2669 # each group
2596 2670 perm_rows = sorted(perm_rows, key=display_user_sort)
2597 2671
2598 _admin_perm = 'group.admin'
2599 owner_row = []
2600 if with_owner:
2601 usr = AttributeDict(self.user.get_dict())
2602 usr.owner_row = True
2603 usr.permission = _admin_perm
2604 owner_row.append(usr)
2605
2606 super_admin_rows = []
2607 if with_admins:
2608 for usr in User.get_all_super_admins():
2609 # if this admin is also owner, don't double the record
2610 if usr.user_id == owner_row[0].user_id:
2611 owner_row[0].admin_row = True
2612 else:
2613 usr = AttributeDict(usr.get_dict())
2614 usr.admin_row = True
2615 usr.permission = _admin_perm
2616 super_admin_rows.append(usr)
2617
2618 2672 return super_admin_rows + owner_row + perm_rows
2619 2673
2620 2674 def permission_user_groups(self):
2621 q = UserGroupRepoGroupToPerm.query().filter(UserGroupRepoGroupToPerm.group == self)
2675 q = UserGroupRepoGroupToPerm.query().filter(
2676 UserGroupRepoGroupToPerm.group == self)
2622 2677 q = q.options(joinedload(UserGroupRepoGroupToPerm.group),
2623 2678 joinedload(UserGroupRepoGroupToPerm.users_group),
2624 2679 joinedload(UserGroupRepoGroupToPerm.permission),)
@@ -2653,9 +2708,9 b' class Permission(Base, BaseModel):'
2653 2708 __tablename__ = 'permissions'
2654 2709 __table_args__ = (
2655 2710 Index('p_perm_name_idx', 'permission_name'),
2656 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2657 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
2711 base_table_args,
2658 2712 )
2713
2659 2714 PERMS = [
2660 2715 ('hg.admin', _('RhodeCode Super Administrator')),
2661 2716
@@ -2674,6 +2729,11 b' class Permission(Base, BaseModel):'
2674 2729 ('usergroup.write', _('User group write access')),
2675 2730 ('usergroup.admin', _('User group admin access')),
2676 2731
2732 ('branch.none', _('Branch no permissions')),
2733 ('branch.merge', _('Branch access by web merge')),
2734 ('branch.push', _('Branch access by push')),
2735 ('branch.push_force', _('Branch access by push with force')),
2736
2677 2737 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
2678 2738 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
2679 2739
@@ -2703,11 +2763,16 b' class Permission(Base, BaseModel):'
2703 2763 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
2704 2764 ]
2705 2765
2706 # definition of system default permissions for DEFAULT user
2766 # definition of system default permissions for DEFAULT user, created on
2767 # system setup
2707 2768 DEFAULT_USER_PERMISSIONS = [
2769 # object perms
2708 2770 'repository.read',
2709 2771 'group.read',
2710 2772 'usergroup.read',
2773 # branch, for backward compat we need same value as before so forced pushed
2774 'branch.push_force',
2775 # global
2711 2776 'hg.create.repository',
2712 2777 'hg.repogroup.create.false',
2713 2778 'hg.usergroup.create.false',
@@ -2738,6 +2803,11 b' class Permission(Base, BaseModel):'
2738 2803 'usergroup.write': 3,
2739 2804 'usergroup.admin': 4,
2740 2805
2806 'branch.none': 0,
2807 'branch.merge': 1,
2808 'branch.push': 3,
2809 'branch.push_force': 4,
2810
2741 2811 'hg.repogroup.create.false': 0,
2742 2812 'hg.repogroup.create.true': 1,
2743 2813
@@ -2774,6 +2844,21 b' class Permission(Base, BaseModel):'
2774 2844 return q.all()
2775 2845
2776 2846 @classmethod
2847 def get_default_repo_branch_perms(cls, user_id, repo_id=None):
2848 q = Session().query(UserToRepoBranchPermission, UserRepoToPerm, Permission) \
2849 .join(
2850 Permission,
2851 UserToRepoBranchPermission.permission_id == Permission.permission_id) \
2852 .join(
2853 UserRepoToPerm,
2854 UserToRepoBranchPermission.rule_to_perm_id == UserRepoToPerm.repo_to_perm_id) \
2855 .filter(UserRepoToPerm.user_id == user_id)
2856
2857 if repo_id:
2858 q = q.filter(UserToRepoBranchPermission.repository_id == repo_id)
2859 return q.order_by(UserToRepoBranchPermission.rule_order).all()
2860
2861 @classmethod
2777 2862 def get_default_repo_perms_from_user_group(cls, user_id, repo_id=None):
2778 2863 q = Session().query(UserGroupRepoToPerm, Repository, Permission)\
2779 2864 .join(
@@ -2798,10 +2883,37 b' class Permission(Base, BaseModel):'
2798 2883 return q.all()
2799 2884
2800 2885 @classmethod
2886 def get_default_repo_branch_perms_from_user_group(cls, user_id, repo_id=None):
2887 q = Session().query(UserGroupToRepoBranchPermission, UserGroupRepoToPerm, Permission) \
2888 .join(
2889 Permission,
2890 UserGroupToRepoBranchPermission.permission_id == Permission.permission_id) \
2891 .join(
2892 UserGroupRepoToPerm,
2893 UserGroupToRepoBranchPermission.rule_to_perm_id == UserGroupRepoToPerm.users_group_to_perm_id) \
2894 .join(
2895 UserGroup,
2896 UserGroupRepoToPerm.users_group_id == UserGroup.users_group_id) \
2897 .join(
2898 UserGroupMember,
2899 UserGroupRepoToPerm.users_group_id == UserGroupMember.users_group_id) \
2900 .filter(
2901 UserGroupMember.user_id == user_id,
2902 UserGroup.users_group_active == true())
2903
2904 if repo_id:
2905 q = q.filter(UserGroupToRepoBranchPermission.repository_id == repo_id)
2906 return q.order_by(UserGroupToRepoBranchPermission.rule_order).all()
2907
2908 @classmethod
2801 2909 def get_default_group_perms(cls, user_id, repo_group_id=None):
2802 2910 q = Session().query(UserRepoGroupToPerm, RepoGroup, Permission)\
2803 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
2804 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
2911 .join(
2912 Permission,
2913 UserRepoGroupToPerm.permission_id == Permission.permission_id)\
2914 .join(
2915 RepoGroup,
2916 UserRepoGroupToPerm.group_id == RepoGroup.group_id)\
2805 2917 .filter(UserRepoGroupToPerm.user_id == user_id)
2806 2918 if repo_group_id:
2807 2919 q = q.filter(UserRepoGroupToPerm.group_id == repo_group_id)
@@ -2878,9 +2990,9 b' class UserRepoToPerm(Base, BaseModel):'
2878 2990 __tablename__ = 'repo_to_perm'
2879 2991 __table_args__ = (
2880 2992 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
2881 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2882 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
2993 base_table_args
2883 2994 )
2995
2884 2996 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2885 2997 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
2886 2998 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
@@ -2890,6 +3002,8 b' class UserRepoToPerm(Base, BaseModel):'
2890 3002 repository = relationship('Repository')
2891 3003 permission = relationship('Permission')
2892 3004
3005 branch_perm_entry = relationship('UserToRepoBranchPermission', cascade="all, delete, delete-orphan", lazy='joined')
3006
2893 3007 @classmethod
2894 3008 def create(cls, user, repository, permission):
2895 3009 n = cls()
@@ -2907,9 +3021,9 b' class UserUserGroupToPerm(Base, BaseMode'
2907 3021 __tablename__ = 'user_user_group_to_perm'
2908 3022 __table_args__ = (
2909 3023 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
2910 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2911 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3024 base_table_args
2912 3025 )
3026
2913 3027 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2914 3028 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
2915 3029 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
@@ -2936,9 +3050,9 b' class UserToPerm(Base, BaseModel):'
2936 3050 __tablename__ = 'user_to_perm'
2937 3051 __table_args__ = (
2938 3052 UniqueConstraint('user_id', 'permission_id'),
2939 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2940 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3053 base_table_args
2941 3054 )
3055
2942 3056 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2943 3057 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
2944 3058 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
@@ -2954,9 +3068,9 b' class UserGroupRepoToPerm(Base, BaseMode'
2954 3068 __tablename__ = 'users_group_repo_to_perm'
2955 3069 __table_args__ = (
2956 3070 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
2957 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2958 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3071 base_table_args
2959 3072 )
3073
2960 3074 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2961 3075 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
2962 3076 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
@@ -2965,6 +3079,7 b' class UserGroupRepoToPerm(Base, BaseMode'
2965 3079 users_group = relationship('UserGroup')
2966 3080 permission = relationship('Permission')
2967 3081 repository = relationship('Repository')
3082 user_group_branch_perms = relationship('UserGroupToRepoBranchPermission', cascade='all')
2968 3083
2969 3084 @classmethod
2970 3085 def create(cls, users_group, repository, permission):
@@ -2984,9 +3099,9 b' class UserGroupUserGroupToPerm(Base, Bas'
2984 3099 __table_args__ = (
2985 3100 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
2986 3101 CheckConstraint('target_user_group_id != user_group_id'),
2987 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2988 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3102 base_table_args
2989 3103 )
3104
2990 3105 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2991 3106 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
2992 3107 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
@@ -3013,9 +3128,9 b' class UserGroupToPerm(Base, BaseModel):'
3013 3128 __tablename__ = 'users_group_to_perm'
3014 3129 __table_args__ = (
3015 3130 UniqueConstraint('users_group_id', 'permission_id',),
3016 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3017 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3131 base_table_args
3018 3132 )
3133
3019 3134 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3020 3135 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3021 3136 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
@@ -3028,8 +3143,7 b' class UserRepoGroupToPerm(Base, BaseMode'
3028 3143 __tablename__ = 'user_repo_group_to_perm'
3029 3144 __table_args__ = (
3030 3145 UniqueConstraint('user_id', 'group_id', 'permission_id'),
3031 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3032 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3146 base_table_args
3033 3147 )
3034 3148
3035 3149 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -3055,8 +3169,7 b' class UserGroupRepoGroupToPerm(Base, Bas'
3055 3169 __tablename__ = 'users_group_repo_group_to_perm'
3056 3170 __table_args__ = (
3057 3171 UniqueConstraint('users_group_id', 'group_id'),
3058 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3059 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3172 base_table_args
3060 3173 )
3061 3174
3062 3175 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -3084,9 +3197,9 b' class UserGroupRepoGroupToPerm(Base, Bas'
3084 3197 class Statistics(Base, BaseModel):
3085 3198 __tablename__ = 'statistics'
3086 3199 __table_args__ = (
3087 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3088 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3200 base_table_args
3089 3201 )
3202
3090 3203 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3091 3204 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
3092 3205 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
@@ -3102,8 +3215,7 b' class UserFollowing(Base, BaseModel):'
3102 3215 __table_args__ = (
3103 3216 UniqueConstraint('user_id', 'follows_repository_id'),
3104 3217 UniqueConstraint('user_id', 'follows_user_id'),
3105 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3106 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3218 base_table_args
3107 3219 )
3108 3220
3109 3221 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -3127,12 +3239,14 b' class CacheKey(Base, BaseModel):'
3127 3239 __table_args__ = (
3128 3240 UniqueConstraint('cache_key'),
3129 3241 Index('key_idx', 'cache_key'),
3130 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3131 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3242 base_table_args,
3132 3243 )
3133 CACHE_TYPE_ATOM = 'ATOM'
3134 CACHE_TYPE_RSS = 'RSS'
3244
3245 CACHE_TYPE_FEED = 'FEED'
3135 3246 CACHE_TYPE_README = 'README'
3247 # namespaces used to register process/thread aware caches
3248 REPO_INVALIDATION_NAMESPACE = 'repo_cache:{repo_id}'
3249 SETTINGS_INVALIDATION_NAMESPACE = 'system_settings'
3136 3250
3137 3251 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3138 3252 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
@@ -3181,44 +3295,27 b' class CacheKey(Base, BaseModel):'
3181 3295 Session().commit()
3182 3296
3183 3297 @classmethod
3184 def get_cache_key(cls, repo_name, cache_type):
3185 """
3186
3187 Generate a cache key for this process of RhodeCode instance.
3188 Prefix most likely will be process id or maybe explicitly set
3189 instance_id from .ini file.
3190 """
3191 import rhodecode
3192 prefix = safe_unicode(rhodecode.CONFIG.get('instance_id') or '')
3193
3194 repo_as_unicode = safe_unicode(repo_name)
3195 key = u'{}_{}'.format(repo_as_unicode, cache_type) \
3196 if cache_type else repo_as_unicode
3197
3198 return u'{}{}'.format(prefix, key)
3199
3200 @classmethod
3201 def set_invalidate(cls, repo_name, delete=False):
3298 def set_invalidate(cls, cache_uid, delete=False):
3202 3299 """
3203 3300 Mark all caches of a repo as invalid in the database.
3204 3301 """
3205 3302
3206 3303 try:
3207 qry = Session().query(cls).filter(cls.cache_args == repo_name)
3304 qry = Session().query(cls).filter(cls.cache_args == cache_uid)
3208 3305 if delete:
3209 log.debug('cache objects deleted for repo %s',
3210 safe_str(repo_name))
3211 3306 qry.delete()
3307 log.debug('cache objects deleted for cache args %s',
3308 safe_str(cache_uid))
3212 3309 else:
3213 log.debug('cache objects marked as invalid for repo %s',
3214 safe_str(repo_name))
3215 3310 qry.update({"cache_active": False})
3311 log.debug('cache objects marked as invalid for cache args %s',
3312 safe_str(cache_uid))
3216 3313
3217 3314 Session().commit()
3218 3315 except Exception:
3219 3316 log.exception(
3220 'Cache key invalidation failed for repository %s',
3221 safe_str(repo_name))
3317 'Cache key invalidation failed for cache args %s',
3318 safe_str(cache_uid))
3222 3319 Session().rollback()
3223 3320
3224 3321 @classmethod
@@ -3228,34 +3325,12 b' class CacheKey(Base, BaseModel):'
3228 3325 return inv_obj
3229 3326 return None
3230 3327
3231 @classmethod
3232 def repo_context_cache(cls, compute_func, repo_name, cache_type,
3233 thread_scoped=False):
3234 """
3235 @cache_region('long_term')
3236 def _heavy_calculation(cache_key):
3237 return 'result'
3238
3239 cache_context = CacheKey.repo_context_cache(
3240 _heavy_calculation, repo_name, cache_type)
3241
3242 with cache_context as context:
3243 context.invalidate()
3244 computed = context.compute()
3245
3246 assert computed == 'result'
3247 """
3248 from rhodecode.lib import caches
3249 return caches.InvalidationContext(
3250 compute_func, repo_name, cache_type, thread_scoped=thread_scoped)
3251
3252 3328
3253 3329 class ChangesetComment(Base, BaseModel):
3254 3330 __tablename__ = 'changeset_comments'
3255 3331 __table_args__ = (
3256 3332 Index('cc_revision_idx', 'revision'),
3257 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3258 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3333 base_table_args,
3259 3334 )
3260 3335
3261 3336 COMMENT_OUTDATED = u'comment_outdated'
@@ -3379,9 +3454,9 b' class ChangesetStatus(Base, BaseModel):'
3379 3454 Index('cs_revision_idx', 'revision'),
3380 3455 Index('cs_version_idx', 'version'),
3381 3456 UniqueConstraint('repo_id', 'revision', 'version'),
3382 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3383 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
3457 base_table_args
3384 3458 )
3459
3385 3460 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
3386 3461 STATUS_APPROVED = 'approved'
3387 3462 STATUS_REJECTED = 'rejected'
@@ -3451,6 +3526,8 b' class _PullRequestBase(BaseModel):'
3451 3526 description = Column(
3452 3527 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'),
3453 3528 nullable=True)
3529 description_renderer = Column('description_renderer', Unicode(64), nullable=True)
3530
3454 3531 # new/open/closed status of pull request (not approve/reject/etc)
3455 3532 status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW)
3456 3533 created_on = Column(
@@ -3651,8 +3728,7 b' class _PullRequestBase(BaseModel):'
3651 3728 class PullRequest(Base, _PullRequestBase):
3652 3729 __tablename__ = 'pull_requests'
3653 3730 __table_args__ = (
3654 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3655 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3731 base_table_args,
3656 3732 )
3657 3733
3658 3734 pull_request_id = Column(
@@ -3762,15 +3838,15 b' class PullRequest(Base, _PullRequestBase'
3762 3838 workspace_id = self.workspace_id
3763 3839 vcs_obj = self.target_repo.scm_instance()
3764 3840 shadow_repository_path = vcs_obj._get_shadow_repository_path(
3765 workspace_id)
3766 return vcs_obj._get_shadow_instance(shadow_repository_path)
3841 self.target_repo.repo_id, workspace_id)
3842 if os.path.isdir(shadow_repository_path):
3843 return vcs_obj._get_shadow_instance(shadow_repository_path)
3767 3844
3768 3845
3769 3846 class PullRequestVersion(Base, _PullRequestBase):
3770 3847 __tablename__ = 'pull_request_versions'
3771 3848 __table_args__ = (
3772 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3773 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3849 base_table_args,
3774 3850 )
3775 3851
3776 3852 pull_request_version_id = Column(
@@ -3808,8 +3884,7 b' class PullRequestVersion(Base, _PullRequ'
3808 3884 class PullRequestReviewers(Base, BaseModel):
3809 3885 __tablename__ = 'pull_request_reviewers'
3810 3886 __table_args__ = (
3811 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3812 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3887 base_table_args,
3813 3888 )
3814 3889
3815 3890 @hybrid_property
@@ -3869,8 +3944,7 b' class Notification(Base, BaseModel):'
3869 3944 __tablename__ = 'notifications'
3870 3945 __table_args__ = (
3871 3946 Index('notification_type_idx', 'type'),
3872 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3873 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
3947 base_table_args,
3874 3948 )
3875 3949
3876 3950 TYPE_CHANGESET_COMMENT = u'cs_comment'
@@ -3909,16 +3983,18 b' class Notification(Base, BaseModel):'
3909 3983 notification.type_ = type_
3910 3984 notification.created_on = datetime.datetime.now()
3911 3985
3986 # For each recipient link the created notification to his account
3912 3987 for u in recipients:
3913 3988 assoc = UserNotification()
3989 assoc.user_id = u.user_id
3914 3990 assoc.notification = notification
3915 3991
3916 3992 # if created_by is inside recipients mark his notification
3917 3993 # as read
3918 3994 if u.user_id == created_by.user_id:
3919 3995 assoc.read = True
3920
3921 u.notifications.append(assoc)
3996 Session().add(assoc)
3997
3922 3998 Session().add(notification)
3923 3999
3924 4000 return notification
@@ -3928,9 +4004,9 b' class UserNotification(Base, BaseModel):'
3928 4004 __tablename__ = 'user_to_notification'
3929 4005 __table_args__ = (
3930 4006 UniqueConstraint('user_id', 'notification_id'),
3931 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3932 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
4007 base_table_args
3933 4008 )
4009
3934 4010 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
3935 4011 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
3936 4012 read = Column('read', Boolean, default=False)
@@ -3950,9 +4026,9 b' class Gist(Base, BaseModel):'
3950 4026 __table_args__ = (
3951 4027 Index('g_gist_access_id_idx', 'gist_access_id'),
3952 4028 Index('g_created_on_idx', 'created_on'),
3953 {'extend_existing': True, 'mysql_engine': 'InnoDB',
3954 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
4029 base_table_args
3955 4030 )
4031
3956 4032 GIST_PUBLIC = u'public'
3957 4033 GIST_PRIVATE = u'private'
3958 4034 DEFAULT_FILENAME = u'gistfile1.txt'
@@ -4047,8 +4123,8 b' class ExternalIdentity(Base, BaseModel):'
4047 4123 __table_args__ = (
4048 4124 Index('local_user_id_idx', 'local_user_id'),
4049 4125 Index('external_id_idx', 'external_id'),
4050 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4051 'mysql_charset': 'utf8'})
4126 base_table_args
4127 )
4052 4128
4053 4129 external_id = Column('external_id', Unicode(255), default=u'',
4054 4130 primary_key=True)
@@ -4109,8 +4185,7 b' class ExternalIdentity(Base, BaseModel):'
4109 4185 class Integration(Base, BaseModel):
4110 4186 __tablename__ = 'integrations'
4111 4187 __table_args__ = (
4112 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4113 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
4188 base_table_args
4114 4189 )
4115 4190
4116 4191 integration_id = Column('integration_id', Integer(), primary_key=True)
@@ -4153,8 +4228,7 b' class Integration(Base, BaseModel):'
4153 4228 class RepoReviewRuleUser(Base, BaseModel):
4154 4229 __tablename__ = 'repo_review_rules_users'
4155 4230 __table_args__ = (
4156 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4157 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4231 base_table_args
4158 4232 )
4159 4233
4160 4234 repo_review_rule_user_id = Column('repo_review_rule_user_id', Integer(), primary_key=True)
@@ -4172,9 +4246,9 b' class RepoReviewRuleUser(Base, BaseModel'
4172 4246 class RepoReviewRuleUserGroup(Base, BaseModel):
4173 4247 __tablename__ = 'repo_review_rules_users_groups'
4174 4248 __table_args__ = (
4175 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4176 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4249 base_table_args
4177 4250 )
4251
4178 4252 VOTE_RULE_ALL = -1
4179 4253
4180 4254 repo_review_rule_users_group_id = Column('repo_review_rule_users_group_id', Integer(), primary_key=True)
@@ -4201,8 +4275,7 b' class RepoReviewRuleUserGroup(Base, Base'
4201 4275 class RepoReviewRule(Base, BaseModel):
4202 4276 __tablename__ = 'repo_review_rules'
4203 4277 __table_args__ = (
4204 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4205 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4278 base_table_args
4206 4279 )
4207 4280
4208 4281 repo_review_rule_id = Column(
@@ -4224,7 +4297,7 b' class RepoReviewRule(Base, BaseModel):'
4224 4297 rule_users = relationship('RepoReviewRuleUser')
4225 4298 rule_user_groups = relationship('RepoReviewRuleUserGroup')
4226 4299
4227 def _validate_glob(self, value):
4300 def _validate_pattern(self, value):
4228 4301 re.compile('^' + glob2re(value) + '$')
4229 4302
4230 4303 @hybrid_property
@@ -4233,7 +4306,7 b' class RepoReviewRule(Base, BaseModel):'
4233 4306
4234 4307 @source_branch_pattern.setter
4235 4308 def source_branch_pattern(self, value):
4236 self._validate_glob(value)
4309 self._validate_pattern(value)
4237 4310 self._branch_pattern = value or '*'
4238 4311
4239 4312 @hybrid_property
@@ -4242,7 +4315,7 b' class RepoReviewRule(Base, BaseModel):'
4242 4315
4243 4316 @target_branch_pattern.setter
4244 4317 def target_branch_pattern(self, value):
4245 self._validate_glob(value)
4318 self._validate_pattern(value)
4246 4319 self._target_branch_pattern = value or '*'
4247 4320
4248 4321 @hybrid_property
@@ -4251,7 +4324,7 b' class RepoReviewRule(Base, BaseModel):'
4251 4324
4252 4325 @file_pattern.setter
4253 4326 def file_pattern(self, value):
4254 self._validate_glob(value)
4327 self._validate_pattern(value)
4255 4328 self._file_pattern = value or '*'
4256 4329
4257 4330 def matches(self, source_branch, target_branch, files_changed):
@@ -4272,14 +4345,20 b' class RepoReviewRule(Base, BaseModel):'
4272 4345 if self.source_branch_pattern == '*':
4273 4346 source_branch_match = True
4274 4347 else:
4275 source_branch_regex = re.compile(
4276 '^' + glob2re(self.source_branch_pattern) + '$')
4348 if self.source_branch_pattern.startswith('re:'):
4349 source_pattern = self.source_branch_pattern[3:]
4350 else:
4351 source_pattern = '^' + glob2re(self.source_branch_pattern) + '$'
4352 source_branch_regex = re.compile(source_pattern)
4277 4353 source_branch_match = bool(source_branch_regex.search(source_branch))
4278 4354 if self.target_branch_pattern == '*':
4279 4355 target_branch_match = True
4280 4356 else:
4281 target_branch_regex = re.compile(
4282 '^' + glob2re(self.target_branch_pattern) + '$')
4357 if self.target_branch_pattern.startswith('re:'):
4358 target_pattern = self.target_branch_pattern[3:]
4359 else:
4360 target_pattern = '^' + glob2re(self.target_branch_pattern) + '$'
4361 target_branch_regex = re.compile(target_pattern)
4283 4362 target_branch_match = bool(target_branch_regex.search(target_branch))
4284 4363
4285 4364 branch_matches = source_branch_match and target_branch_match
@@ -4287,7 +4366,11 b' class RepoReviewRule(Base, BaseModel):'
4287 4366 files_matches = True
4288 4367 if self.file_pattern != '*':
4289 4368 files_matches = False
4290 file_regex = re.compile(glob2re(self.file_pattern))
4369 if self.file_pattern.startswith('re:'):
4370 file_pattern = self.file_pattern[3:]
4371 else:
4372 file_pattern = glob2re(self.file_pattern)
4373 file_regex = re.compile(file_pattern)
4291 4374 for filename in files_changed:
4292 4375 if file_regex.search(filename):
4293 4376 files_matches = True
@@ -4335,10 +4418,15 b' class RepoReviewRule(Base, BaseModel):'
4335 4418
4336 4419 return users
4337 4420
4338 def user_group_vote_rule(self):
4421 def user_group_vote_rule(self, user_id):
4422
4339 4423 rules = []
4340 if self.rule_user_groups:
4341 for user_group in self.rule_user_groups:
4424 if not self.rule_user_groups:
4425 return rules
4426
4427 for user_group in self.rule_user_groups:
4428 user_group_members = [x.user_id for x in user_group.users_group.members]
4429 if user_id in user_group_members:
4342 4430 rules.append(user_group)
4343 4431 return rules
4344 4432
@@ -4352,9 +4440,9 b' class ScheduleEntry(Base, BaseModel):'
4352 4440 __table_args__ = (
4353 4441 UniqueConstraint('schedule_name', name='s_schedule_name_idx'),
4354 4442 UniqueConstraint('task_uid', name='s_task_uid_idx'),
4355 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4356 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
4443 base_table_args,
4357 4444 )
4445
4358 4446 schedule_types = ['crontab', 'timedelta', 'integer']
4359 4447 schedule_entry_id = Column('schedule_entry_id', Integer(), primary_key=True)
4360 4448
@@ -4477,22 +4565,124 b' def set_task_uid(mapper, connection, tar'
4477 4565 target.task_uid = ScheduleEntry.get_uid(target)
4478 4566
4479 4567
4568 class _BaseBranchPerms(BaseModel):
4569 @classmethod
4570 def compute_hash(cls, value):
4571 return sha1_safe(value)
4572
4573 @hybrid_property
4574 def branch_pattern(self):
4575 return self._branch_pattern or '*'
4576
4577 @hybrid_property
4578 def branch_hash(self):
4579 return self._branch_hash
4580
4581 def _validate_glob(self, value):
4582 re.compile('^' + glob2re(value) + '$')
4583
4584 @branch_pattern.setter
4585 def branch_pattern(self, value):
4586 self._validate_glob(value)
4587 self._branch_pattern = value or '*'
4588 # set the Hash when setting the branch pattern
4589 self._branch_hash = self.compute_hash(self._branch_pattern)
4590
4591 def matches(self, branch):
4592 """
4593 Check if this the branch matches entry
4594
4595 :param branch: branch name for the commit
4596 """
4597
4598 branch = branch or ''
4599
4600 branch_matches = True
4601 if branch:
4602 branch_regex = re.compile('^' + glob2re(self.branch_pattern) + '$')
4603 branch_matches = bool(branch_regex.search(branch))
4604
4605 return branch_matches
4606
4607
4608 class UserToRepoBranchPermission(Base, _BaseBranchPerms):
4609 __tablename__ = 'user_to_repo_branch_permissions'
4610 __table_args__ = (
4611 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4612 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4613 )
4614
4615 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
4616
4617 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
4618 repo = relationship('Repository', backref='user_branch_perms')
4619
4620 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
4621 permission = relationship('Permission')
4622
4623 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('repo_to_perm.repo_to_perm_id'), nullable=False, unique=None, default=None)
4624 user_repo_to_perm = relationship('UserRepoToPerm')
4625
4626 rule_order = Column('rule_order', Integer(), nullable=False)
4627 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
4628 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
4629
4630 def __unicode__(self):
4631 return u'<UserBranchPermission(%s => %r)>' % (
4632 self.user_repo_to_perm, self.branch_pattern)
4633
4634
4635 class UserGroupToRepoBranchPermission(Base, _BaseBranchPerms):
4636 __tablename__ = 'user_group_to_repo_branch_permissions'
4637 __table_args__ = (
4638 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4639 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4640 )
4641
4642 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
4643
4644 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
4645 repo = relationship('Repository', backref='user_group_branch_perms')
4646
4647 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
4648 permission = relationship('Permission')
4649
4650 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('users_group_repo_to_perm.users_group_to_perm_id'), nullable=False, unique=None, default=None)
4651 user_group_repo_to_perm = relationship('UserGroupRepoToPerm')
4652
4653 rule_order = Column('rule_order', Integer(), nullable=False)
4654 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
4655 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
4656
4657 def __unicode__(self):
4658 return u'<UserBranchPermission(%s => %r)>' % (
4659 self.user_group_repo_to_perm, self.branch_pattern)
4660
4661
4480 4662 class DbMigrateVersion(Base, BaseModel):
4481 4663 __tablename__ = 'db_migrate_version'
4482 4664 __table_args__ = (
4483 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4484 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
4665 base_table_args,
4485 4666 )
4667
4486 4668 repository_id = Column('repository_id', String(250), primary_key=True)
4487 4669 repository_path = Column('repository_path', Text)
4488 4670 version = Column('version', Integer)
4489 4671
4672 @classmethod
4673 def set_version(cls, version):
4674 """
4675 Helper for forcing a different version, usually for debugging purposes via ishell.
4676 """
4677 ver = DbMigrateVersion.query().first()
4678 ver.version = version
4679 Session().commit()
4680
4490 4681
4491 4682 class DbSession(Base, BaseModel):
4492 4683 __tablename__ = 'db_session'
4493 4684 __table_args__ = (
4494 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4495 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
4685 base_table_args,
4496 4686 )
4497 4687
4498 4688 def __repr__(self):
@@ -504,12 +504,26 b' def ObjectPermissionsForm(localizer, rep'
504 504 overwrite_default_repo = v.StringBoolean(if_missing=False)
505 505 overwrite_default_group = v.StringBoolean(if_missing=False)
506 506 overwrite_default_user_group = v.StringBoolean(if_missing=False)
507
507 508 default_repo_perm = v.OneOf(repo_perms_choices)
508 509 default_group_perm = v.OneOf(group_perms_choices)
509 510 default_user_group_perm = v.OneOf(user_group_perms_choices)
511
510 512 return _ObjectPermissionsForm
511 513
512 514
515 def BranchPermissionsForm(localizer, branch_perms_choices):
516 _ = localizer
517
518 class _BranchPermissionsForm(formencode.Schema):
519 allow_extra_fields = True
520 filter_extra_fields = True
521 overwrite_default_branch = v.StringBoolean(if_missing=False)
522 default_branch_perm = v.OneOf(branch_perms_choices)
523
524 return _BranchPermissionsForm
525
526
513 527 def UserPermissionsForm(localizer, create_choices, create_on_write_choices,
514 528 repo_group_create_choices, user_group_create_choices,
515 529 fork_choices, inherit_default_permissions_choices):
@@ -606,6 +620,7 b' def PullRequestForm(localizer, repo_id):'
606 620 review_members = formencode.ForEach(ReviewerForm())
607 621 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3, max=255)
608 622 pullrequest_desc = v.UnicodeString(strip=True, required=False)
623 description_renderer = v.UnicodeString(strip=True, required=False)
609 624
610 625 return _PullRequestForm
611 626
@@ -33,6 +33,7 b' from pyramid.threadlocal import get_curr'
33 33 from rhodecode.lib.utils2 import (
34 34 safe_unicode, unique_id, safe_int, time_to_datetime, AttributeDict)
35 35 from rhodecode.lib.ext_json import json
36 from rhodecode.lib.vcs import VCSError
36 37 from rhodecode.model import BaseModel
37 38 from rhodecode.model.db import Gist
38 39 from rhodecode.model.repo import RepoModel
@@ -98,7 +99,11 b' class GistModel(BaseModel):'
98 99 :param gist_access_id:
99 100 """
100 101 repo = Gist.get_by_access_id(gist_access_id)
101 commit = repo.scm_instance().get_commit(commit_id=revision)
102 vcs_repo = repo.scm_instance()
103 if not vcs_repo:
104 raise VCSError('Failed to load gist repository for {}'.format(repo))
105
106 commit = vcs_repo.get_commit(commit_id=revision)
102 107 return commit, [n for n in commit.get_node('/')]
103 108
104 109 def create(self, description, owner, gist_mapping,
@@ -33,7 +33,7 b' from rhodecode import events'
33 33 from rhodecode.integrations.types.base import EEIntegration
34 34 from rhodecode.lib.caching_query import FromCache
35 35 from rhodecode.model import BaseModel
36 from rhodecode.model.db import Integration, Repository, RepoGroup
36 from rhodecode.model.db import Integration, Repository, RepoGroup, true, false
37 37 from rhodecode.integrations import integration_type_registry
38 38
39 39 log = logging.getLogger(__name__)
@@ -119,20 +119,20 b' class IntegrationModel(BaseModel):'
119 119
120 120 if isinstance(scope, Repository):
121 121 query = self.sa.query(Integration).filter(
122 Integration.repo==scope)
122 Integration.repo == scope)
123 123 elif isinstance(scope, RepoGroup):
124 124 query = self.sa.query(Integration).filter(
125 Integration.repo_group==scope)
125 Integration.repo_group == scope)
126 126 elif scope == 'global':
127 127 # global integrations
128 128 query = self.sa.query(Integration).filter(
129 and_(Integration.repo_id==None, Integration.repo_group_id==None)
129 and_(Integration.repo_id == None, Integration.repo_group_id == None)
130 130 )
131 131 elif scope == 'root-repos':
132 132 query = self.sa.query(Integration).filter(
133 and_(Integration.repo_id==None,
134 Integration.repo_group_id==None,
135 Integration.child_repos_only==True)
133 and_(Integration.repo_id == None,
134 Integration.repo_group_id == None,
135 Integration.child_repos_only == true())
136 136 )
137 137 elif scope == 'all':
138 138 query = self.sa.query(Integration)
@@ -158,20 +158,20 b' class IntegrationModel(BaseModel):'
158 158 query = self.sa.query(
159 159 Integration
160 160 ).filter(
161 Integration.enabled==True
161 Integration.enabled == true()
162 162 )
163 163
164 164 global_integrations_filter = and_(
165 Integration.repo_id==None,
166 Integration.repo_group_id==None,
167 Integration.child_repos_only==False,
165 Integration.repo_id == None,
166 Integration.repo_group_id == None,
167 Integration.child_repos_only == False,
168 168 )
169 169
170 170 if isinstance(event, events.RepoEvent):
171 171 root_repos_integrations_filter = and_(
172 Integration.repo_id==None,
173 Integration.repo_group_id==None,
174 Integration.child_repos_only==True,
172 Integration.repo_id == None,
173 Integration.repo_group_id == None,
174 Integration.child_repos_only == true(),
175 175 )
176 176
177 177 clauses = [
@@ -179,16 +179,16 b' class IntegrationModel(BaseModel):'
179 179 ]
180 180
181 181 # repo integrations
182 if event.repo.repo_id: # pre create events dont have a repo_id yet
182 if event.repo.repo_id: # pre create events dont have a repo_id yet
183 183 clauses.append(
184 Integration.repo_id==event.repo.repo_id
184 Integration.repo_id == event.repo.repo_id
185 185 )
186 186
187 187 if event.repo.group:
188 188 clauses.append(
189 189 and_(
190 Integration.repo_group_id==event.repo.group.group_id,
191 Integration.child_repos_only==True
190 Integration.repo_group_id == event.repo.group.group_id,
191 Integration.child_repos_only == true()
192 192 )
193 193 )
194 194 # repo group cascade to kids
@@ -196,14 +196,13 b' class IntegrationModel(BaseModel):'
196 196 and_(
197 197 Integration.repo_group_id.in_(
198 198 [group.group_id for group in
199 event.repo.groups_with_parents]
199 event.repo.groups_with_parents]
200 200 ),
201 Integration.child_repos_only==False
201 Integration.child_repos_only == false()
202 202 )
203 203 )
204 204
205
206 if not event.repo.group: # root repo
205 if not event.repo.group: # root repo
207 206 clauses.append(root_repos_integrations_filter)
208 207
209 208 query = query.filter(or_(*clauses))
@@ -212,11 +211,11 b' class IntegrationModel(BaseModel):'
212 211 cache_key = "get_enabled_repo_integrations_%i" % event.repo.repo_id
213 212 query = query.options(
214 213 FromCache("sql_cache_short", cache_key))
215 else: # only global integrations
214 else: # only global integrations
216 215 query = query.filter(global_integrations_filter)
217 216 if cache:
218 217 query = query.options(
219 218 FromCache("sql_cache_short", "get_enabled_global_integrations"))
220 219
221 220 result = query.all()
222 return result No newline at end of file
221 return result
@@ -24,27 +24,22 b' SQLAlchemy Metadata and Session object'
24 24
25 25 from sqlalchemy.ext.declarative import declarative_base
26 26 from sqlalchemy.orm import scoped_session, sessionmaker
27 from beaker import cache
28 27
29 28 from rhodecode.lib import caching_query
30 29
31
32 # Beaker CacheManager. A home base for cache configurations.
33 cache_manager = cache.CacheManager()
30 __all__ = ['Base', 'Session']
34 31
35 __all__ = ['Base', 'Session']
36 #
37 # SQLAlchemy session manager. Updated by model.init_model()
38 #
32 # scoped_session. Apply our custom CachingQuery class to it,
33 # using a callable that will associate the dictionary
34 # of regions with the Query.
35 # to use cache use this in query
36 # .options(FromCache("sqlalchemy_cache_type", "cachekey"))
39 37 Session = scoped_session(
40 38 sessionmaker(
41 query_cls=caching_query.query_callable(cache_manager),
39 query_cls=caching_query.query_callable(),
42 40 expire_on_commit=True,
43 41 )
44 42 )
45 43
46 44 # The declarative Base
47 45 Base = declarative_base()
48
49 #to use cache use this in query
50 #.options(FromCache("sqlalchemy_cache_type", "cachekey"))
@@ -31,7 +31,7 b' from sqlalchemy.exc import DatabaseError'
31 31 from rhodecode.model import BaseModel
32 32 from rhodecode.model.db import (
33 33 User, Permission, UserToPerm, UserRepoToPerm, UserRepoGroupToPerm,
34 UserUserGroupToPerm, UserGroup, UserGroupToPerm)
34 UserUserGroupToPerm, UserGroup, UserGroupToPerm, UserToRepoBranchPermission)
35 35 from rhodecode.lib.utils2 import str2bool, safe_int
36 36
37 37 log = logging.getLogger(__name__)
@@ -59,6 +59,9 b' class PermissionModel(BaseModel):'
59 59 'default_repo_perm': None,
60 60 'default_group_perm': None,
61 61 'default_user_group_perm': None,
62
63 # branch
64 'default_branch_perm': None,
62 65 }
63 66
64 67 def set_global_permission_choices(self, c_obj, gettext_translator):
@@ -82,6 +85,12 b' class PermissionModel(BaseModel):'
82 85 ('usergroup.write', _('Write'),),
83 86 ('usergroup.admin', _('Admin'),)]
84 87
88 c_obj.branch_perms_choices = [
89 ('branch.none', _('Protected/No Access'),),
90 ('branch.merge', _('Web merge'),),
91 ('branch.push', _('Push'),),
92 ('branch.push_force', _('Force Push'),)]
93
85 94 c_obj.register_choices = [
86 95 ('hg.register.none', _('Disabled')),
87 96 ('hg.register.manual_activate', _('Allowed with manual account activation')),
@@ -133,6 +142,10 b' class PermissionModel(BaseModel):'
133 142 if perm.permission.permission_name.startswith('usergroup.'):
134 143 defaults['default_user_group_perm' + suffix] = perm.permission.permission_name
135 144
145 # branch
146 if perm.permission.permission_name.startswith('branch.'):
147 defaults['default_branch_perm' + suffix] = perm.permission.permission_name
148
136 149 # creation of objects
137 150 if perm.permission.permission_name.startswith('hg.create.write_on_repogroup'):
138 151 defaults['default_repo_create_on_write' + suffix] = perm.permission.permission_name
@@ -199,6 +212,9 b' class PermissionModel(BaseModel):'
199 212 'default_repo_perm': 'repository.',
200 213 'default_group_perm': 'group.',
201 214 'default_user_group_perm': 'usergroup.',
215 # branch
216 'default_branch_perm': 'branch.',
217
202 218 }[field_name]
203 219 for field in keep_fields:
204 220 pat = get_pat(field)
@@ -236,8 +252,12 b' class PermissionModel(BaseModel):'
236 252 _global_perms = self.global_perms.copy()
237 253 if obj_type not in ['user', 'user_group']:
238 254 raise ValueError("obj_type must be on of 'user' or 'user_group'")
239 if len(_global_perms) != len(Permission.DEFAULT_USER_PERMISSIONS):
240 raise Exception('Inconsistent permissions definition')
255 global_perms = len(_global_perms)
256 default_user_perms = len(Permission.DEFAULT_USER_PERMISSIONS)
257 if global_perms != default_user_perms:
258 raise Exception(
259 'Inconsistent permissions definition. Got {} vs {}'.format(
260 global_perms, default_user_perms))
241 261
242 262 if obj_type == 'user':
243 263 self._clear_user_perms(object.user_id, preserve)
@@ -337,8 +357,8 b' class PermissionModel(BaseModel):'
337 357
338 358 def create_default_user_group_permissions(self, user_group, force=False):
339 359 """
340 Creates only missing default permissions for user group, if force is set it
341 resets the default permissions for that user group
360 Creates only missing default permissions for user group, if force is
361 set it resets the default permissions for that user group
342 362
343 363 :param user_group:
344 364 :param force:
@@ -366,6 +386,7 b' class PermissionModel(BaseModel):'
366 386 'default_repo_perm',
367 387 'default_group_perm',
368 388 'default_user_group_perm',
389 'default_branch_perm',
369 390
370 391 'default_repo_group_create',
371 392 'default_user_group_create',
@@ -392,6 +413,7 b' class PermissionModel(BaseModel):'
392 413 'default_repo_perm',
393 414 'default_group_perm',
394 415 'default_user_group_perm',
416 'default_branch_perm',
395 417
396 418 'default_register',
397 419 'default_password_reset',
@@ -414,6 +436,7 b' class PermissionModel(BaseModel):'
414 436 'default_repo_perm',
415 437 'default_group_perm',
416 438 'default_user_group_perm',
439 'default_branch_perm',
417 440
418 441 'default_register',
419 442 'default_password_reset',
@@ -440,6 +463,7 b' class PermissionModel(BaseModel):'
440 463 'default_repo_create',
441 464 'default_fork_create',
442 465 'default_inherit_default_permissions',
466 'default_branch_perm',
443 467
444 468 'default_register',
445 469 'default_password_reset',
@@ -477,8 +501,58 b' class PermissionModel(BaseModel):'
477 501 .all():
478 502 g2p.permission = _def
479 503 self.sa.add(g2p)
504
505 # COMMIT
480 506 self.sa.commit()
481 507 except (DatabaseError,):
482 508 log.exception('Failed to set default object permissions')
483 509 self.sa.rollback()
484 510 raise
511
512 def update_branch_permissions(self, form_result):
513 if 'perm_user_id' in form_result:
514 perm_user = User.get(safe_int(form_result['perm_user_id']))
515 else:
516 # used mostly to do lookup for default user
517 perm_user = User.get_by_username(form_result['perm_user_name'])
518 try:
519
520 # stage 2 reset defaults and set them from form data
521 self._set_new_user_perms(perm_user, form_result, preserve=[
522 'default_repo_perm',
523 'default_group_perm',
524 'default_user_group_perm',
525
526 'default_repo_group_create',
527 'default_user_group_create',
528 'default_repo_create_on_write',
529 'default_repo_create',
530 'default_fork_create',
531 'default_inherit_default_permissions',
532
533 'default_register',
534 'default_password_reset',
535 'default_extern_activate'])
536
537 # overwrite default branch permissions
538 if form_result['overwrite_default_branch']:
539 _def_name = \
540 form_result['default_branch_perm'].split('branch.')[-1]
541
542 _def = Permission.get_by_key('branch.' + _def_name)
543
544 user_perms = UserToRepoBranchPermission.query()\
545 .join(UserToRepoBranchPermission.user_repo_to_perm)\
546 .filter(UserRepoToPerm.user == perm_user).all()
547
548 for g2p in user_perms:
549 g2p.permission = _def
550 self.sa.add(g2p)
551
552 # COMMIT
553 self.sa.commit()
554 except (DatabaseError,):
555 log.exception('Failed to set default branch permissions')
556 self.sa.rollback()
557 raise
558
@@ -444,10 +444,12 b' class PullRequestModel(BaseModel):'
444 444
445 445 def create(self, created_by, source_repo, source_ref, target_repo,
446 446 target_ref, revisions, reviewers, title, description=None,
447 reviewer_data=None, translator=None):
447 description_renderer=None,
448 reviewer_data=None, translator=None, auth_user=None):
448 449 translator = translator or get_current_request().translate
449 450
450 451 created_by_user = self._get_user(created_by)
452 auth_user = auth_user or created_by_user.AuthUser()
451 453 source_repo = self._get_repo(source_repo)
452 454 target_repo = self._get_repo(target_repo)
453 455
@@ -459,6 +461,7 b' class PullRequestModel(BaseModel):'
459 461 pull_request.revisions = revisions
460 462 pull_request.title = title
461 463 pull_request.description = description
464 pull_request.description_renderer = description_renderer
462 465 pull_request.author = created_by_user
463 466 pull_request.reviewer_data = reviewer_data
464 467
@@ -487,11 +490,12 b' class PullRequestModel(BaseModel):'
487 490 rule_id = list(rules)[0] if rules else None
488 491 rule = RepoReviewRule.get(rule_id) if rule_id else None
489 492 if rule:
490 review_group = rule.user_group_vote_rule()
493 review_group = rule.user_group_vote_rule(user_id)
494 # we check if this particular reviewer is member of a voting group
491 495 if review_group:
492 496 # NOTE(marcink):
493 # again, can be that user is member of more,
494 # but we pick the first same, as default reviewers algo
497 # can be that user is member of more but we pick the first same,
498 # same as default reviewers algo
495 499 review_group = review_group[0]
496 500
497 501 rule_data = {
@@ -503,6 +507,8 b' class PullRequestModel(BaseModel):'
503 507 review_group.users_group.users_group_name,
504 508 'rule_user_group_members':
505 509 [x.user.username for x in review_group.users_group.members],
510 'rule_user_group_members_id':
511 [x.user.user_id for x in review_group.users_group.members],
506 512 }
507 513 # e.g {'vote_rule': -1, 'mandatory': True}
508 514 rule_data.update(review_group.rule_data())
@@ -528,7 +534,7 b' class PullRequestModel(BaseModel):'
528 534
529 535 # prepare workspace, and run initial merge simulation
530 536 MergeCheck.validate(
531 pull_request, user=created_by_user, translator=translator)
537 pull_request, auth_user=auth_user, translator=translator)
532 538
533 539 self.notify_reviewers(pull_request, reviewer_ids)
534 540 self._trigger_pull_request_hook(
@@ -537,7 +543,7 b' class PullRequestModel(BaseModel):'
537 543 creation_data = pull_request.get_api_data(with_merge_state=False)
538 544 self._log_audit_action(
539 545 'repo.pull_request.create', {'data': creation_data},
540 created_by_user, pull_request)
546 auth_user, pull_request)
541 547
542 548 return pull_request
543 549
@@ -582,7 +588,7 b' class PullRequestModel(BaseModel):'
582 588
583 589 return commit_ids
584 590
585 def merge(self, pull_request, user, extras):
591 def merge_repo(self, pull_request, user, extras):
586 592 log.debug("Merging pull request %s", pull_request.pull_request_id)
587 593 merge_state = self._merge_pull_request(pull_request, user, extras)
588 594 if merge_state.executed:
@@ -615,11 +621,13 b' class PullRequestModel(BaseModel):'
615 621 }
616 622
617 623 workspace_id = self._workspace_id(pull_request)
624 repo_id = pull_request.target_repo.repo_id
618 625 use_rebase = self._use_rebase_for_merging(pull_request)
619 626 close_branch = self._close_branch_before_merging(pull_request)
620 627
621 628 callback_daemon, extras = prepare_callback_daemon(
622 629 extras, protocol=vcs_settings.HOOKS_PROTOCOL,
630 host=vcs_settings.HOOKS_HOST,
623 631 use_direct_calls=vcs_settings.HOOKS_DIRECT_CALLS)
624 632
625 633 with callback_daemon:
@@ -628,9 +636,10 b' class PullRequestModel(BaseModel):'
628 636 target_vcs.config.set(
629 637 'rhodecode', 'RC_SCM_DATA', json.dumps(extras))
630 638 merge_state = target_vcs.merge(
631 target_ref, source_vcs, pull_request.source_ref_parts,
632 workspace_id, user_name=user.username,
633 user_email=user.email, message=message, use_rebase=use_rebase,
639 repo_id, workspace_id, target_ref, source_vcs,
640 pull_request.source_ref_parts,
641 user_name=user.username, user_email=user.email,
642 message=message, use_rebase=use_rebase,
634 643 close_branch=close_branch)
635 644 return merge_state
636 645
@@ -976,7 +985,7 b' class PullRequestModel(BaseModel):'
976 985 renderer = RstTemplateRenderer()
977 986 return renderer.render('pull_request_update.mako', **params)
978 987
979 def edit(self, pull_request, title, description, user):
988 def edit(self, pull_request, title, description, description_renderer, user):
980 989 pull_request = self.__get_pull_request(pull_request)
981 990 old_data = pull_request.get_api_data(with_merge_state=False)
982 991 if pull_request.is_closed():
@@ -985,6 +994,7 b' class PullRequestModel(BaseModel):'
985 994 pull_request.title = title
986 995 pull_request.description = description
987 996 pull_request.updated_on = datetime.datetime.now()
997 pull_request.description_renderer = description_renderer
988 998 Session().add(pull_request)
989 999 self._log_audit_action(
990 1000 'repo.pull_request.edit', {'old_data': old_data},
@@ -1218,7 +1228,8 b' class PullRequestModel(BaseModel):'
1218 1228
1219 1229 return comment, status
1220 1230
1221 def merge_status(self, pull_request, translator=None):
1231 def merge_status(self, pull_request, translator=None,
1232 force_shadow_repo_refresh=False):
1222 1233 _ = translator or get_current_request().translate
1223 1234
1224 1235 if not self._is_merge_enabled(pull_request):
@@ -1232,7 +1243,9 b' class PullRequestModel(BaseModel):'
1232 1243 return merge_possible, msg
1233 1244
1234 1245 try:
1235 resp = self._try_merge(pull_request)
1246 resp = self._try_merge(
1247 pull_request,
1248 force_shadow_repo_refresh=force_shadow_repo_refresh)
1236 1249 log.debug("Merge response: %s", resp)
1237 1250 status = resp.possible, self.merge_status_message(
1238 1251 resp.failure_reason)
@@ -1269,13 +1282,13 b' class PullRequestModel(BaseModel):'
1269 1282 'extensions', 'largefiles')
1270 1283 return largefiles_ui and largefiles_ui[0].active
1271 1284
1272 def _try_merge(self, pull_request):
1285 def _try_merge(self, pull_request, force_shadow_repo_refresh=False):
1273 1286 """
1274 1287 Try to merge the pull request and return the merge status.
1275 1288 """
1276 1289 log.debug(
1277 "Trying out if the pull request %s can be merged.",
1278 pull_request.pull_request_id)
1290 "Trying out if the pull request %s can be merged. Force_refresh=%s",
1291 pull_request.pull_request_id, force_shadow_repo_refresh)
1279 1292 target_vcs = pull_request.target_repo.scm_instance()
1280 1293
1281 1294 # Refresh the target reference.
@@ -1292,7 +1305,8 b' class PullRequestModel(BaseModel):'
1292 1305 log.debug("The target repository is locked.")
1293 1306 merge_state = MergeResponse(
1294 1307 False, False, None, MergeFailureReason.TARGET_IS_LOCKED)
1295 elif self._needs_merge_state_refresh(pull_request, target_ref):
1308 elif force_shadow_repo_refresh or self._needs_merge_state_refresh(
1309 pull_request, target_ref):
1296 1310 log.debug("Refreshing the merge status of the repository.")
1297 1311 merge_state = self._refresh_merge_state(
1298 1312 pull_request, target_vcs, target_ref)
@@ -1323,11 +1337,13 b' class PullRequestModel(BaseModel):'
1323 1337 def _refresh_merge_state(self, pull_request, target_vcs, target_reference):
1324 1338 workspace_id = self._workspace_id(pull_request)
1325 1339 source_vcs = pull_request.source_repo.scm_instance()
1340 repo_id = pull_request.target_repo.repo_id
1326 1341 use_rebase = self._use_rebase_for_merging(pull_request)
1327 1342 close_branch = self._close_branch_before_merging(pull_request)
1328 1343 merge_state = target_vcs.merge(
1344 repo_id, workspace_id,
1329 1345 target_reference, source_vcs, pull_request.source_ref_parts,
1330 workspace_id, dry_run=True, use_rebase=use_rebase,
1346 dry_run=True, use_rebase=use_rebase,
1331 1347 close_branch=close_branch)
1332 1348
1333 1349 # Do not store the response if there was an unknown error.
@@ -1393,11 +1409,12 b' class PullRequestModel(BaseModel):'
1393 1409
1394 1410 def _cleanup_merge_workspace(self, pull_request):
1395 1411 # Merging related cleanup
1412 repo_id = pull_request.target_repo.repo_id
1396 1413 target_scm = pull_request.target_repo.scm_instance()
1397 workspace_id = 'pr-%s' % pull_request.pull_request_id
1414 workspace_id = self._workspace_id(pull_request)
1398 1415
1399 1416 try:
1400 target_scm.cleanup_merge_workspace(workspace_id)
1417 target_scm.cleanup_merge_workspace(repo_id, workspace_id)
1401 1418 except NotImplementedError:
1402 1419 pass
1403 1420
@@ -1582,18 +1599,38 b' class MergeCheck(object):'
1582 1599 )
1583 1600
1584 1601 @classmethod
1585 def validate(cls, pull_request, user, translator, fail_early=False):
1602 def validate(cls, pull_request, auth_user, translator, fail_early=False,
1603 force_shadow_repo_refresh=False):
1586 1604 _ = translator
1587 1605 merge_check = cls()
1588 1606
1589 1607 # permissions to merge
1590 1608 user_allowed_to_merge = PullRequestModel().check_user_merge(
1591 pull_request, user)
1609 pull_request, auth_user)
1592 1610 if not user_allowed_to_merge:
1593 1611 log.debug("MergeCheck: cannot merge, approval is pending.")
1594 1612
1595 msg = _('User `{}` not allowed to perform merge.').format(user.username)
1596 merge_check.push_error('error', msg, cls.PERM_CHECK, user.username)
1613 msg = _('User `{}` not allowed to perform merge.').format(auth_user.username)
1614 merge_check.push_error('error', msg, cls.PERM_CHECK, auth_user.username)
1615 if fail_early:
1616 return merge_check
1617
1618 # permission to merge into the target branch
1619 target_commit_id = pull_request.target_ref_parts.commit_id
1620 if pull_request.target_ref_parts.type == 'branch':
1621 branch_name = pull_request.target_ref_parts.name
1622 else:
1623 # for mercurial we can always figure out the branch from the commit
1624 # in case of bookmark
1625 target_commit = pull_request.target_repo.get_commit(target_commit_id)
1626 branch_name = target_commit.branch
1627
1628 rule, branch_perm = auth_user.get_rule_and_branch_permission(
1629 pull_request.target_repo.repo_name, branch_name)
1630 if branch_perm and branch_perm == 'branch.none':
1631 msg = _('Target branch `{}` changes rejected by rule {}.').format(
1632 branch_name, rule)
1633 merge_check.push_error('error', msg, cls.PERM_CHECK, auth_user.username)
1597 1634 if fail_early:
1598 1635 return merge_check
1599 1636
@@ -1633,7 +1670,8 b' class MergeCheck(object):'
1633 1670
1634 1671 # merge possible, here is the filesystem simulation + shadow repo
1635 1672 merge_status, msg = PullRequestModel().merge_status(
1636 pull_request, translator=translator)
1673 pull_request, translator=translator,
1674 force_shadow_repo_refresh=force_shadow_repo_refresh)
1637 1675 merge_check.merge_possible = merge_status
1638 1676 merge_check.merge_msg = msg
1639 1677 if not merge_status:
@@ -92,13 +92,10 b' class RepoModel(BaseModel):'
92 92 settings_model = VcsSettingsModel(sa=self.sa)
93 93 return settings_model.get_repos_location()
94 94
95 def get(self, repo_id, cache=False):
95 def get(self, repo_id):
96 96 repo = self.sa.query(Repository) \
97 97 .filter(Repository.repo_id == repo_id)
98 98
99 if cache:
100 repo = repo.options(
101 FromCache("sql_cache_short", "get_repo_%s" % repo_id))
102 99 return repo.scalar()
103 100
104 101 def get_repo(self, repository):
@@ -547,14 +544,16 b' class RepoModel(BaseModel):'
547 544 # this updates also current one if found
548 545 self.grant_user_permission(
549 546 repo=repo, user=member_id, perm=perm)
550 else: # set for user group
547 elif member_type == 'user_group':
551 548 # check if we have permissions to alter this usergroup
552 549 member_name = UserGroup.get(member_id).users_group_name
553 550 if not check_perms or HasUserGroupPermissionAny(
554 551 *req_perms)(member_name, user=cur_user):
555 552 self.grant_user_group_permission(
556 553 repo=repo, group_name=member_id, perm=perm)
557
554 else:
555 raise ValueError("member_type must be 'user' or 'user_group' "
556 "got {} instead".format(member_type))
558 557 changes['updated'].append({'type': member_type, 'id': member_id,
559 558 'name': member_name, 'new_perm': perm})
560 559
@@ -565,13 +564,17 b' class RepoModel(BaseModel):'
565 564 member_name = User.get(member_id).username
566 565 self.grant_user_permission(
567 566 repo=repo, user=member_id, perm=perm)
568 else: # set for user group
567 elif member_type == 'user_group':
569 568 # check if we have permissions to alter this usergroup
570 569 member_name = UserGroup.get(member_id).users_group_name
571 570 if not check_perms or HasUserGroupPermissionAny(
572 571 *req_perms)(member_name, user=cur_user):
573 572 self.grant_user_group_permission(
574 573 repo=repo, group_name=member_id, perm=perm)
574 else:
575 raise ValueError("member_type must be 'user' or 'user_group' "
576 "got {} instead".format(member_type))
577
575 578 changes['added'].append({'type': member_type, 'id': member_id,
576 579 'name': member_name, 'new_perm': perm})
577 580 # delete permissions
@@ -580,13 +583,16 b' class RepoModel(BaseModel):'
580 583 if member_type == 'user':
581 584 member_name = User.get(member_id).username
582 585 self.revoke_user_permission(repo=repo, user=member_id)
583 else: # set for user group
586 elif member_type == 'user_group':
584 587 # check if we have permissions to alter this usergroup
585 588 member_name = UserGroup.get(member_id).users_group_name
586 589 if not check_perms or HasUserGroupPermissionAny(
587 590 *req_perms)(member_name, user=cur_user):
588 591 self.revoke_user_group_permission(
589 592 repo=repo, group_name=member_id)
593 else:
594 raise ValueError("member_type must be 'user' or 'user_group' "
595 "got {} instead".format(member_type))
590 596
591 597 changes['deleted'].append({'type': member_type, 'id': member_id,
592 598 'name': member_name, 'new_perm': perm})
@@ -425,11 +425,14 b' class RepoGroupModel(BaseModel):'
425 425 member_name = User.get(member_id).username
426 426 # this updates also current one if found
427 427 _set_perm_user(obj, user=member_id, perm=perm)
428 else: # set for user group
428 elif member_type == 'user_group':
429 429 member_name = UserGroup.get(member_id).users_group_name
430 430 if not check_perms or has_group_perm(member_name,
431 431 user=cur_user):
432 432 _set_perm_group(obj, users_group=member_id, perm=perm)
433 else:
434 raise ValueError("member_type must be 'user' or 'user_group' "
435 "got {} instead".format(member_type))
433 436
434 437 changes['updated'].append(
435 438 {'change_obj': change_obj, 'type': member_type,
@@ -441,12 +444,15 b' class RepoGroupModel(BaseModel):'
441 444 if member_type == 'user':
442 445 member_name = User.get(member_id).username
443 446 _set_perm_user(obj, user=member_id, perm=perm)
444 else: # set for user group
447 elif member_type == 'user_group':
445 448 # check if we have permissions to alter this usergroup
446 449 member_name = UserGroup.get(member_id).users_group_name
447 450 if not check_perms or has_group_perm(member_name,
448 451 user=cur_user):
449 452 _set_perm_group(obj, users_group=member_id, perm=perm)
453 else:
454 raise ValueError("member_type must be 'user' or 'user_group' "
455 "got {} instead".format(member_type))
450 456
451 457 changes['added'].append(
452 458 {'change_obj': change_obj, 'type': member_type,
@@ -458,12 +464,15 b' class RepoGroupModel(BaseModel):'
458 464 if member_type == 'user':
459 465 member_name = User.get(member_id).username
460 466 _revoke_perm_user(obj, user=member_id)
461 else: # set for user group
467 elif member_type == 'user_group':
462 468 # check if we have permissions to alter this usergroup
463 469 member_name = UserGroup.get(member_id).users_group_name
464 470 if not check_perms or has_group_perm(member_name,
465 471 user=cur_user):
466 472 _revoke_perm_group(obj, user_group=member_id)
473 else:
474 raise ValueError("member_type must be 'user' or 'user_group' "
475 "got {} instead".format(member_type))
467 476
468 477 changes['deleted'].append(
469 478 {'change_obj': change_obj, 'type': member_type,
@@ -38,12 +38,12 b' from rhodecode.lib.vcs import get_backen'
38 38 from rhodecode.lib.vcs.exceptions import RepositoryError, NodeNotChangedError
39 39 from rhodecode.lib.vcs.nodes import FileNode
40 40 from rhodecode.lib.vcs.backends.base import EmptyCommit
41 from rhodecode.lib import helpers as h
41 from rhodecode.lib import helpers as h, rc_cache
42 42 from rhodecode.lib.auth import (
43 43 HasRepoPermissionAny, HasRepoGroupPermissionAny,
44 44 HasUserGroupPermissionAny)
45 45 from rhodecode.lib.exceptions import NonRelativePathError, IMCCommitError
46 from rhodecode.lib import hooks_utils, caches
46 from rhodecode.lib import hooks_utils
47 47 from rhodecode.lib.utils import (
48 48 get_filesystem_repos, make_db_config)
49 49 from rhodecode.lib.utils2 import (safe_str, safe_unicode)
@@ -267,16 +267,22 b' class ScmModel(BaseModel):'
267 267 :param repo_name: the repo_name for which caches should be marked
268 268 invalid, or deleted
269 269 :param delete: delete the entry keys instead of setting bool
270 flag on them
270 flag on them, and also purge caches used by the dogpile
271 271 """
272 CacheKey.set_invalidate(repo_name, delete=delete)
273 272 repo = Repository.get_by_repo_name(repo_name)
274 273
275 274 if repo:
275 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
276 repo_id=repo.repo_id)
277 CacheKey.set_invalidate(invalidation_namespace, delete=delete)
278
279 repo_id = repo.repo_id
276 280 config = repo._config
277 281 config.set('extensions', 'largefiles', '')
278 282 repo.update_commit_cache(config=config, cs_cache=None)
279 caches.clear_repo_caches(repo_name)
283 if delete:
284 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
285 rc_cache.clear_cache_namespace('cache_repo', cache_namespace_uid)
280 286
281 287 def toggle_following_repo(self, follow_repo_id, user_id):
282 288
@@ -25,13 +25,13 b' from collections import namedtuple'
25 25 from functools import wraps
26 26 import bleach
27 27
28 from rhodecode.lib import caches
28 from rhodecode.lib import rc_cache
29 29 from rhodecode.lib.utils2 import (
30 30 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
31 31 from rhodecode.lib.vcs.backends import base
32 32 from rhodecode.model import BaseModel
33 33 from rhodecode.model.db import (
34 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
34 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting, CacheKey)
35 35 from rhodecode.model.meta import Session
36 36
37 37
@@ -206,13 +206,15 b' class SettingsModel(BaseModel):'
206 206 return res
207 207
208 208 def invalidate_settings_cache(self):
209 namespace = 'rhodecode_settings'
210 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
211 caches.clear_cache_manager(cache_manager)
209 invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
210 CacheKey.set_invalidate(invalidation_namespace)
212 211
213 212 def get_all_settings(self, cache=False):
213 region = rc_cache.get_or_create_region('sql_cache_short')
214 invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
214 215
215 def _compute():
216 @region.conditional_cache_on_arguments(condition=cache)
217 def _get_all_settings(name, key):
216 218 q = self._get_settings_query()
217 219 if not q:
218 220 raise Exception('Could not get application settings !')
@@ -223,20 +225,27 b' class SettingsModel(BaseModel):'
223 225 }
224 226 return settings
225 227
226 if cache:
227 log.debug('Fetching app settings using cache')
228 repo = self._get_repo(self.repo) if self.repo else None
229 namespace = 'rhodecode_settings'
230 cache_manager = caches.get_cache_manager(
231 'sql_cache_short', namespace)
232 _cache_key = (
233 "get_repo_{}_settings".format(repo.repo_id)
234 if repo else "get_app_settings")
228 repo = self._get_repo(self.repo) if self.repo else None
229 key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app"
235 230
236 return cache_manager.get(_cache_key, createfunc=_compute)
231 inv_context_manager = rc_cache.InvalidationContext(
232 uid='cache_settings', invalidation_namespace=invalidation_namespace)
233 with inv_context_manager as invalidation_context:
234 # check for stored invalidation signal, and maybe purge the cache
235 # before computing it again
236 if invalidation_context.should_invalidate():
237 # NOTE:(marcink) we flush the whole sql_cache_short region, because it
238 # reads different settings etc. It's little too much but those caches
239 # are anyway very short lived and it's a safest way.
240 region = rc_cache.get_or_create_region('sql_cache_short')
241 region.invalidate()
237 242
238 else:
239 return _compute()
243 result = _get_all_settings('rhodecode_settings', key)
244 log.debug(
245 'Fetching app settings for key: %s took: %.3fs', key,
246 inv_context_manager.compute_time)
247
248 return result
240 249
241 250 def get_auth_settings(self):
242 251 q = self._get_settings_query()
@@ -377,9 +377,11 b' class UserModel(BaseModel):'
377 377
378 378 if not edit:
379 379 # add the RSS token
380 AuthTokenModel().create(username,
381 description=u'Generated feed token',
382 role=AuthTokenModel.cls.ROLE_FEED)
380 self.add_auth_token(
381 user=username, lifetime_minutes=-1,
382 role=self.auth_token_role.ROLE_FEED,
383 description=u'Generated feed token')
384
383 385 kwargs = new_user.get_dict()
384 386 # backward compat, require api_keys present
385 387 kwargs['api_keys'] = kwargs['auth_tokens']
@@ -830,6 +832,26 b' class UserModel(BaseModel):'
830 832 self.sa.add(obj)
831 833 return obj
832 834
835 auth_token_role = AuthTokenModel.cls
836
837 def add_auth_token(self, user, lifetime_minutes, role, description=u'',
838 scope_callback=None):
839 """
840 Add AuthToken for user.
841
842 :param user: username/user_id
843 :param lifetime_minutes: in minutes the lifetime for token, -1 equals no limit
844 :param role: one of AuthTokenModel.cls.ROLE_*
845 :param description: optional string description
846 """
847
848 token = AuthTokenModel().create(
849 user, description, lifetime_minutes, role)
850 if scope_callback and callable(scope_callback):
851 # call the callback if we provide, used to attach scope for EE edition
852 scope_callback(token)
853 return token
854
833 855 def delete_extra_ip(self, user, ip_id):
834 856 """
835 857 Removes ip address from UserIpMap
@@ -891,7 +913,7 b' class UserModel(BaseModel):'
891 913 This way we block only latest created accounts.
892 914
893 915 :param expected_users: list of users in special order, we deactivate
894 the end N ammoun of users from that list
916 the end N amount of users from that list
895 917 """
896 918
897 919 list_of_accounts = self.get_accounts_in_creation_order(
@@ -90,13 +90,16 b' class UserGroupModel(BaseModel):'
90 90 self.grant_user_permission(
91 91 user_group=user_group, user=member_id, perm=perm
92 92 )
93 else:
93 elif member_type == 'user_group':
94 94 # check if we have permissions to alter this usergroup
95 95 member_name = UserGroup.get(member_id).users_group_name
96 96 if not check_perms or HasUserGroupPermissionAny(
97 97 *req_perms)(member_name, user=cur_user):
98 98 self.grant_user_group_permission(
99 99 target_user_group=user_group, user_group=member_id, perm=perm)
100 else:
101 raise ValueError("member_type must be 'user' or 'user_group' "
102 "got {} instead".format(member_type))
100 103
101 104 changes['updated'].append({
102 105 'change_obj': change_obj,
@@ -110,13 +113,16 b' class UserGroupModel(BaseModel):'
110 113 member_name = User.get(member_id).username
111 114 self.grant_user_permission(
112 115 user_group=user_group, user=member_id, perm=perm)
113 else:
116 elif member_type == 'user_group':
114 117 # check if we have permissions to alter this usergroup
115 118 member_name = UserGroup.get(member_id).users_group_name
116 119 if not check_perms or HasUserGroupPermissionAny(
117 120 *req_perms)(member_name, user=cur_user):
118 121 self.grant_user_group_permission(
119 122 target_user_group=user_group, user_group=member_id, perm=perm)
123 else:
124 raise ValueError("member_type must be 'user' or 'user_group' "
125 "got {} instead".format(member_type))
120 126
121 127 changes['added'].append({
122 128 'change_obj': change_obj,
@@ -129,13 +135,16 b' class UserGroupModel(BaseModel):'
129 135 if member_type == 'user':
130 136 member_name = User.get(member_id).username
131 137 self.revoke_user_permission(user_group=user_group, user=member_id)
132 else:
138 elif member_type == 'user_group':
133 139 # check if we have permissions to alter this usergroup
134 140 member_name = UserGroup.get(member_id).users_group_name
135 141 if not check_perms or HasUserGroupPermissionAny(
136 142 *req_perms)(member_name, user=cur_user):
137 143 self.revoke_user_group_permission(
138 144 target_user_group=user_group, user_group=member_id)
145 else:
146 raise ValueError("member_type must be 'user' or 'user_group' "
147 "got {} instead".format(member_type))
139 148
140 149 changes['deleted'].append({
141 150 'change_obj': change_obj,
@@ -733,7 +742,7 b' class UserGroupModel(BaseModel):'
733 742
734 743 data = {
735 744 'users_group_id': user_group.users_group_id,
736 'group_name': user_group.users_group_name,
745 'group_name': h.link_to_group(user_group.users_group_name),
737 746 'group_description': user_group.user_group_description,
738 747 'active': user_group.users_group_active,
739 748 "owner": user_group.user.username,
@@ -123,8 +123,6 b' class IntegrationScopeType(colander.Sche'
123 123 else:
124 124 return 'global'
125 125
126 raise colander.Invalid(node, '%r is not a valid scope' % appstruct)
127
128 126 def deserialize(self, node, cstruct):
129 127 if cstruct is colander.null:
130 128 return colander.null
@@ -797,7 +797,7 b" def ValidPerms(localizer, type_='repo'):"
797 797 obj_type = k[0]
798 798 obj_id = k[7:]
799 799 update_type = {'u': 'user',
800 'g': 'users_group'}[obj_type]
800 'g': 'user_group'}[obj_type]
801 801
802 802 if obj_type == 'u' and safe_int(obj_id) == default_user_id:
803 803 if str2bool(value.get('repo_private')):
@@ -827,7 +827,7 b" def ValidPerms(localizer, type_='repo'):"
827 827 User.query()\
828 828 .filter(User.active == true())\
829 829 .filter(User.user_id == member_id).one()
830 if member_type == 'users_group':
830 if member_type == 'user_group':
831 831 UserGroup.query()\
832 832 .filter(UserGroup.users_group_active == true())\
833 833 .filter(UserGroup.users_group_id == member_id)\
@@ -77,6 +77,13 b''
77 77 min-width: 100%;
78 78 }
79 79
80 .main-content-auto-width {
81 .main-content;
82 width: auto;
83 min-width: 100%;
84 max-width: inherit;
85 }
86
80 87 .field {
81 88 clear: left;
82 89 margin-bottom: @padding;
@@ -109,6 +116,11 b''
109 116 .label;
110 117 padding-top: 5px;
111 118 }
119 .label-branch-perm {
120 .label;
121 width: 115px;
122 }
123
112 124 // Used to position content on the right side of a .label
113 125 .content,
114 126 .side-by-side-selector {
@@ -128,6 +140,15 b''
128 140 }
129 141 }
130 142
143 .input-branch-perm {
144 .input;
145 margin-left: 140px;
146 }
147
148 .input-branch-perm-order {
149 width: 40px;
150 }
151
131 152 .checkboxes,
132 153 .input,
133 154 .select {
@@ -162,6 +183,9 b''
162 183 }
163 184
164 185 .input {
186 .branch-perm {
187 width: 80px;
188 }
165 189 .medium {
166 190 width: @fields-input-m;
167 191 }
@@ -462,7 +462,7 b' ul.auth_plugins {'
462 462
463 463 .radios {
464 464 position: relative;
465 width: 405px;
465 width: 505px;
466 466 }
467 467 }
468 468
@@ -1418,9 +1418,6 b' table.integrations {'
1418 1418 margin-top: @textmargin;
1419 1419 margin-bottom: @textmargin;
1420 1420 }
1421 .pr-description {
1422 white-space:pre-wrap;
1423 }
1424 1421
1425 1422 .pr-reviewer-rules {
1426 1423 padding: 10px 0px 20px 0px;
@@ -2405,3 +2402,65 b' input[type=radio] {'
2405 2402 height: 16px;
2406 2403 width: 16px;
2407 2404 }
2405
2406
2407 .markup-form .clearfix {
2408 .border-radius(@border-radius);
2409 margin: 0px;
2410 }
2411
2412 .markup-form-area {
2413 padding: 8px 12px;
2414 border: 1px solid @grey4;
2415 .border-radius(@border-radius);
2416 }
2417
2418 .markup-form-area-header .nav-links {
2419 display: flex;
2420 flex-flow: row wrap;
2421 -webkit-flex-flow: row wrap;
2422 width: 100%;
2423 }
2424
2425 .markup-form-area-footer {
2426 display: flex;
2427 }
2428
2429 .markup-form-area-footer .toolbar {
2430
2431 }
2432
2433 // markup Form
2434 div.markup-form {
2435 margin-top: 20px;
2436 }
2437
2438 .markup-form strong {
2439 display: block;
2440 margin-bottom: 15px;
2441 }
2442
2443 .markup-form textarea {
2444 width: 100%;
2445 height: 100px;
2446 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
2447 }
2448
2449 form.markup-form {
2450 margin-top: 10px;
2451 margin-left: 10px;
2452 }
2453
2454 .markup-form .comment-block-ta,
2455 .markup-form .preview-box {
2456 .border-radius(@border-radius);
2457 .box-sizing(border-box);
2458 background-color: white;
2459 }
2460
2461 .markup-form .preview-box.unloaded {
2462 height: 50px;
2463 text-align: center;
2464 padding: 20px;
2465 background-color: white;
2466 }
@@ -281,11 +281,9 b''
281 281 }
282 282
283 283 .navigation li.open {
284
285 .submenu,
286 .repo_switcher {
287 display: block;
288 }
284 .submenu {
285 display: block;
286 }
289 287 }
290 288
291 289 .navigation li:last-child .submenu {
@@ -411,6 +409,7 b''
411 409 display: block;
412 410 height: 16px;
413 411 padding: 8px; //must add up to td height (28px)
412 width: 120px; // set width
414 413
415 414 &:hover {
416 415 background-color: @grey5;
@@ -642,3 +641,56 b' ul#context-pages {'
642 641
643 642 }
644 643 }
644
645 .main_filter_help_box {
646 padding: 7px 7px;
647 border-top: 1px solid @grey4;
648 border-right: 1px solid @grey4;
649 border-bottom: 1px solid @grey4;
650 display: inline-block;
651 vertical-align: top;
652 margin-left: -5px;
653 background: @grey3;
654 }
655
656 .main_filter_input_box {
657 display: inline-block;
658 }
659
660 .main_filter_box {
661 margin: 9px 0 0 0;
662 }
663
664 #main_filter_help {
665 background: @grey3;
666 border: 1px solid black;
667 position: absolute;
668 white-space: pre-wrap;
669 z-index: 9999;
670 color: @nav-grey;
671 margin: 1px 7px;
672 padding: 0 2px;
673 }
674
675 .main_filter_input {
676 padding: 6px;
677 min-width: 220px;
678 color: @nav-grey;
679 background: @grey3;
680 }
681
682 .main_filter_input::placeholder {
683 color: @nav-grey;
684 opacity: 1;
685 }
686
687 .notice-box {
688 display:block !important;
689 padding: 9px 0 !important;
690 }
691
692 .menulabel-notice {
693 border: 1px solid @color5;
694 padding:7px 10px;
695 color: @color5;
696 }
@@ -55,6 +55,10 b''
55 55 /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
56 56 }
57 57
58 .icon-no-margin::before {
59 margin: 0;
60
61 }
58 62 // -- ICON CLASSES -- //
59 63
60 64 .icon-bookmark:before { content: '\e803'; } /* '' */
@@ -155,3 +159,9 b''
155 159 &:extend(.icon-svn-transparent:before);
156 160 }
157 161 }
162
163 .icon-user-group:before {
164 &:extend(.icon-group:before);
165 margin: 0;
166 font-size: 16px;
167 }
@@ -154,8 +154,8 b' select.select2{height:28px;visibility:hi'
154 154 }
155 155
156 156 .select2-search input {
157 width: auto !important;
158 margin: .5em;
157 width: 100%;
158 margin: .5em 0;
159 159 padding: .5em;
160 160 }
161 161
@@ -109,13 +109,21 b''
109 109 &.read {
110 110 &:extend(.tag1);
111 111 }
112
113 112 &.write {
114 113 &:extend(.tag4);
115 114 }
116 115 &.admin {
117 116 &:extend(.tag5);
118 117 }
118 &.merge {
119 &:extend(.tag1);
120 }
121 &.push {
122 &:extend(.tag4);
123 }
124 &.push_force {
125 &:extend(.tag5);
126 }
119 127 }
120 128
121 129 .phase-draft {
@@ -228,7 +228,7 b' mark,'
228 228 clear: both;
229 229 float: left;
230 230 width: 100%;
231 margin: @pagepadding 0 @pagepadding;
231 margin: @pagepadding/2 0 @pagepadding;
232 232
233 233 .breadcrumbs{
234 234 float: left;
@@ -20,7 +20,7 b' function setRCMouseBindings(repoName, re'
20 20
21 21 // / open the quick filter
22 22 Mousetrap.bind(['/'], function(e) {
23 $('#repo_switcher').select2('open');
23 $('#main_filter').get(0).focus();
24 24
25 25 // return false to prevent default browser behavior
26 26 // and stop event from bubbling
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'Spécifier un commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} années',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': '省略された結果',
98 98 'truncated results': '省略された結果',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} 前',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} 件の結果があります。矢印キーの上下で選択できます。',
113 115 '{0} sec': '{0} 秒',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} 年',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -90,6 +90,8 b''
90 90 _gettext('specify commit');
91 91 _gettext('truncated result');
92 92 _gettext('truncated results');
93 _gettext('{0} ({1} inactive) of {2} user groups ({3} inactive)');
94 _gettext('{0} ({1} inactive) of {2} users ({3} inactive)');
93 95 _gettext('{0} active out of {1} users');
94 96 _gettext('{0} ago');
95 97 _gettext('{0} and {1}');
@@ -105,6 +107,8 b''
105 107 _gettext('{0} out of {1} users');
106 108 _gettext('{0} results are available, use up and down arrow keys to navigate.');
107 109 _gettext('{0} sec');
110 _gettext('{0} user groups ({1} inactive)');
111 _gettext('{0} users ({1} inactive)');
108 112 _gettext('{0} year');
109 113 _gettext('{0} years');
110 114 _gettext('{0}, {1} ago');
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} aktywnych z {1} użytkowników',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -96,6 +96,8 b' var _TM = {'
96 96 'specify commit': 'specify commit',
97 97 'truncated result': 'truncated result',
98 98 'truncated results': 'truncated results',
99 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
100 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
99 101 '{0} active out of {1} users': '{0} active out of {1} users',
100 102 '{0} ago': '{0} ago',
101 103 '{0} and {1}': '{0} and {1}',
@@ -111,6 +113,8 b' var _TM = {'
111 113 '{0} out of {1} users': '{0} out of {1} users',
112 114 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
113 115 '{0} sec': '{0} sec',
116 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
117 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
114 118 '{0} year': '{0} year',
115 119 '{0} years': '{0} years',
116 120 '{0}, {1} ago': '{0}, {1} ago'
@@ -45,6 +45,10 b' function registerRCRoutes() {'
45 45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
46 46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
47 47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
48 52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
49 53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
50 54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
@@ -76,12 +80,14 b' function registerRCRoutes() {'
76 80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
77 81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
78 82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
83 pyroutes.register('admin_settings_automation', '/_admin/_admin/settings/automation', []);
79 84 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
80 85 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
81 86 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
82 87 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
83 88 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
84 89 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
90 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
85 91 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
86 92 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
87 93 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
@@ -118,6 +124,8 b' function registerRCRoutes() {'
118 124 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
119 125 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
120 126 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
127 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
128 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
121 129 pyroutes.register('user_groups', '/_admin/user_groups', []);
122 130 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
123 131 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
@@ -141,6 +149,7 b' function registerRCRoutes() {'
141 149 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
142 150 pyroutes.register('repo_list_data', '/_repos', []);
143 151 pyroutes.register('goto_switcher_data', '/_goto_data', []);
152 pyroutes.register('markup_preview', '/_markup_preview', []);
144 153 pyroutes.register('journal', '/_admin/journal', []);
145 154 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
146 155 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
@@ -222,8 +231,11 b' function registerRCRoutes() {'
222 231 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
223 232 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
224 233 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
234 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
225 235 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
226 236 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
237 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
238 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
227 239 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
228 240 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
229 241 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
@@ -275,6 +287,7 b' function registerRCRoutes() {'
275 287 pyroutes.register('search', '/_admin/search', []);
276 288 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
277 289 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
290 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
278 291 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
279 292 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
280 293 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
@@ -16,9 +16,25 b' var rhodeCodeApp = Polymer({'
16 16 for (var i = 0; i < alertMessagePayloads.length; i++) {
17 17 $.Topic('/notifications').publish(alertMessagePayloads[i]);
18 18 }
19 this.kickoffChannelstreamPlugin();
19 this.initPlugins();
20 // after rest of application loads and topics get fired, launch connection
21 $(document).ready(function () {
22 this.kickoffChannelstreamPlugin();
23 }.bind(this));
20 24 },
21 25
26 initPlugins: function(){
27 for (var i = 0; i < window.APPLICATION_PLUGINS.length; i++) {
28 var pluginDef = window.APPLICATION_PLUGINS[i];
29 if (pluginDef.component){
30 var pluginElem = document.createElement(pluginDef.component);
31 this.shadowRoot.appendChild(pluginElem);
32 if (typeof pluginElem.init !== 'undefined'){
33 pluginElem.init();
34 }
35 }
36 }
37 },
22 38 /** proxy to channelstream connection */
23 39 getChannelStreamConnection: function () {
24 40 return this.$['channelstream-connection'];
@@ -33,7 +49,7 b' var rhodeCodeApp = Polymer({'
33 49 },
34 50
35 51 faviconUpdate: function (data) {
36 this.$$('rhodecode-favicon').counter = data.count;
52 this.shadowRoot.querySelector('rhodecode-favicon').counter = data.count;
37 53 },
38 54
39 55 /** opens connection to ws server */
@@ -1,5 +1,4 b''
1 1 <link rel="import" href="../../../../../../bower_components/paper-button/paper-button.html">
2 <link rel="import" href="../../../../../../bower_components/paper-toast/paper-toast.html">
3 2 <link rel="import" href="../../../../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
4 3 <link rel="import" href="../rhodecode-unsafe-html/rhodecode-unsafe-html.html">
5 4 <dom-module id="rhodecode-toast">
@@ -3,7 +3,7 b''
3 3 <dom-module id="rhodecode-unsafe-html">
4 4 <template>
5 5 <style include="shared-styles"></style>
6 <content></content>
6 <slot></slot>
7 7 </template>
8 8 <script src="rhodecode-unsafe-html.js"></script>
9 9 </dom-module>
@@ -216,7 +216,7 b' var clipboardActivate = function() {'
216 216 *
217 217 * <i class="tooltip icon-plus clipboard-action" data-clipboard-text="${commit.raw_id}" title="${_('Copy the full commit id')}"></i>
218 218 * */
219 var clipboard = new Clipboard('.clipboard-action');
219 var clipboard = new ClipboardJS('.clipboard-action');
220 220
221 221 clipboard.on('success', function(e) {
222 222 var callback = function () {
@@ -231,6 +231,68 b' var initCodeMirror = function(textAreadI'
231 231 return myCodeMirror;
232 232 };
233 233
234
235 var initMarkupCodeMirror = function(textAreadId, focus, options) {
236 var initialHeight = 100;
237
238 var ta = $(textAreadId).get(0);
239 if (focus === undefined) {
240 focus = true;
241 }
242
243 // default options
244 var codeMirrorOptions = {
245 lineNumbers: false,
246 indentUnit: 4,
247 viewportMargin: 30,
248 // this is a trick to trigger some logic behind codemirror placeholder
249 // it influences styling and behaviour.
250 placeholder: " ",
251 lineWrapping: true,
252 autofocus: focus
253 };
254
255 if (options !== undefined) {
256 // extend with custom options
257 codeMirrorOptions = $.extend(true, codeMirrorOptions, options);
258 }
259
260 var cm = CodeMirror.fromTextArea(ta, codeMirrorOptions);
261 cm.setSize(null, initialHeight);
262 cm.setOption("mode", DEFAULT_RENDERER);
263 CodeMirror.autoLoadMode(cm, DEFAULT_RENDERER); // load rst or markdown mode
264 cmLog.debug('Loading codemirror mode', DEFAULT_RENDERER);
265
266 // start listening on changes to make auto-expanded editor
267 cm.on("change", function(instance, changeObj) {
268 var height = initialHeight;
269 var lines = instance.lineCount();
270 if ( lines > 6 && lines < 20) {
271 height = "auto";
272 }
273 else if (lines >= 20){
274 zheight = 20*15;
275 }
276 instance.setSize(null, height);
277
278 // detect if the change was trigger by auto desc, or user input
279 var changeOrigin = changeObj.origin;
280
281 if (changeOrigin === "setValue") {
282 cmLog.debug('Change triggered by setValue');
283 }
284 else {
285 cmLog.debug('user triggered change !');
286 // set special marker to indicate user has created an input.
287 instance._userDefinedValue = true;
288 }
289
290 });
291
292 return cm;
293 };
294
295
234 296 var initCommentBoxCodeMirror = function(CommentForm, textAreaId, triggerActions){
235 297 var initialHeight = 100;
236 298
@@ -593,3 +655,196 b' var CodeMirrorPreviewEnable = function(e'
593 655 }
594 656 }
595 657 };
658
659
660 /* markup form */
661 (function(mod) {
662
663 if (typeof exports == "object" && typeof module == "object") {
664 // CommonJS
665 module.exports = mod();
666 }
667 else {
668 // Plain browser env
669 (this || window).MarkupForm = mod();
670 }
671
672 })(function() {
673 "use strict";
674
675 function MarkupForm(textareaId) {
676 if (!(this instanceof MarkupForm)) {
677 return new MarkupForm(textareaId);
678 }
679
680 // bind the element instance to our Form
681 $('#' + textareaId).get(0).MarkupForm = this;
682
683 this.withSelectorId = function(selector) {
684 var selectorId = textareaId;
685 return selector + '_' + selectorId;
686 };
687
688 this.previewButton = this.withSelectorId('#preview-btn');
689 this.previewContainer = this.withSelectorId('#preview-container');
690
691 this.previewBoxSelector = this.withSelectorId('#preview-box');
692
693 this.editButton = this.withSelectorId('#edit-btn');
694 this.editContainer = this.withSelectorId('#edit-container');
695
696 this.cmBox = textareaId;
697 this.cm = initMarkupCodeMirror('#' + textareaId);
698
699 this.previewUrl = pyroutes.url('markup_preview');
700
701 // FUNCTIONS and helpers
702 var self = this;
703
704 this.getCmInstance = function(){
705 return this.cm
706 };
707
708 this.setPlaceholder = function(placeholder) {
709 var cm = this.getCmInstance();
710 if (cm){
711 cm.setOption('placeholder', placeholder);
712 }
713 };
714
715 this.initStatusChangeSelector = function(){
716 var formatChangeStatus = function(state, escapeMarkup) {
717 var originalOption = state.element;
718 return '<div class="flag_status ' + $(originalOption).data('status') + ' pull-left"></div>' +
719 '<span>' + escapeMarkup(state.text) + '</span>';
720 };
721 var formatResult = function(result, container, query, escapeMarkup) {
722 return formatChangeStatus(result, escapeMarkup);
723 };
724
725 var formatSelection = function(data, container, escapeMarkup) {
726 return formatChangeStatus(data, escapeMarkup);
727 };
728
729 $(this.submitForm).find(this.statusChange).select2({
730 placeholder: _gettext('Status Review'),
731 formatResult: formatResult,
732 formatSelection: formatSelection,
733 containerCssClass: "drop-menu status_box_menu",
734 dropdownCssClass: "drop-menu-dropdown",
735 dropdownAutoWidth: true,
736 minimumResultsForSearch: -1
737 });
738 $(this.submitForm).find(this.statusChange).on('change', function() {
739 var status = self.getCommentStatus();
740
741 if (status && !self.isInline()) {
742 $(self.submitButton).prop('disabled', false);
743 }
744
745 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
746 self.setPlaceholder(placeholderText)
747 })
748 };
749
750 // reset the text area into it's original state
751 this.resetMarkupFormState = function(content) {
752 content = content || '';
753
754 $(this.editContainer).show();
755 $(this.editButton).parent().addClass('active');
756
757 $(this.previewContainer).hide();
758 $(this.previewButton).parent().removeClass('active');
759
760 this.setActionButtonsDisabled(true);
761 self.cm.setValue(content);
762 self.cm.setOption("readOnly", false);
763 };
764
765 this.previewSuccessCallback = function(o) {
766 $(self.previewBoxSelector).html(o);
767 $(self.previewBoxSelector).removeClass('unloaded');
768
769 // swap buttons, making preview active
770 $(self.previewButton).parent().addClass('active');
771 $(self.editButton).parent().removeClass('active');
772
773 // unlock buttons
774 self.setActionButtonsDisabled(false);
775 };
776
777 this.setActionButtonsDisabled = function(state) {
778 $(this.editButton).prop('disabled', state);
779 $(this.previewButton).prop('disabled', state);
780 };
781
782 // lock preview/edit/submit buttons on load, but exclude cancel button
783 var excludeCancelBtn = true;
784 this.setActionButtonsDisabled(true);
785
786 // anonymous users don't have access to initialized CM instance
787 if (this.cm !== undefined){
788 this.cm.on('change', function(cMirror) {
789 if (cMirror.getValue() === "") {
790 self.setActionButtonsDisabled(true)
791 } else {
792 self.setActionButtonsDisabled(false)
793 }
794 });
795 }
796
797 $(this.editButton).on('click', function(e) {
798 e.preventDefault();
799
800 $(self.previewButton).parent().removeClass('active');
801 $(self.previewContainer).hide();
802
803 $(self.editButton).parent().addClass('active');
804 $(self.editContainer).show();
805
806 });
807
808 $(this.previewButton).on('click', function(e) {
809 e.preventDefault();
810 var text = self.cm.getValue();
811
812 if (text === "") {
813 return;
814 }
815
816 var postData = {
817 'text': text,
818 'renderer': templateContext.visual.default_renderer,
819 'csrf_token': CSRF_TOKEN
820 };
821
822 // lock ALL buttons on preview
823 self.setActionButtonsDisabled(true);
824
825 $(self.previewBoxSelector).addClass('unloaded');
826 $(self.previewBoxSelector).html(_gettext('Loading ...'));
827
828 $(self.editContainer).hide();
829 $(self.previewContainer).show();
830
831 // by default we reset state of comment preserving the text
832 var previewFailCallback = function(data){
833 alert(
834 "Error while submitting preview.\n" +
835 "Error code {0} ({1}).".format(data.status, data.statusText)
836 );
837 self.resetMarkupFormState(text)
838 };
839 _submitAjaxPOST(
840 self.previewUrl, postData, self.previewSuccessCallback,
841 previewFailCallback);
842
843 $(self.previewButton).parent().addClass('active');
844 $(self.editButton).parent().removeClass('active');
845 });
846
847 }
848
849 return MarkupForm;
850 });
@@ -42,6 +42,29 b' var bindToggleButtons = function() {'
42 42 });
43 43 };
44 44
45
46
47 var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
48 failHandler = failHandler || function() {};
49 postData = toQueryString(postData);
50 var request = $.ajax({
51 url: url,
52 type: 'POST',
53 data: postData,
54 headers: {'X-PARTIAL-XHR': true}
55 })
56 .done(function (data) {
57 successHandler(data);
58 })
59 .fail(function (data, textStatus, errorThrown) {
60 failHandler(data, textStatus, errorThrown)
61 });
62 return request;
63 };
64
65
66
67
45 68 /* Comment form for main and inline comments */
46 69 (function(mod) {
47 70
@@ -259,24 +282,7 b' var bindToggleButtons = function() {'
259 282 };
260 283
261 284 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
262 failHandler = failHandler || function() {};
263 var postData = toQueryString(postData);
264 var request = $.ajax({
265 url: url,
266 type: 'POST',
267 data: postData,
268 headers: {'X-PARTIAL-XHR': true}
269 })
270 .done(function(data) {
271 successHandler(data);
272 })
273 .fail(function(data, textStatus, errorThrown){
274 alert(
275 "Error while submitting comment.\n" +
276 "Error code {0} ({1}).".format(data.status, data.statusText));
277 failHandler()
278 });
279 return request;
285 return _submitAjaxPOST(url, postData, successHandler, failHandler);
280 286 };
281 287
282 288 // overwrite a submitHandler, we need to do it for inline comments
@@ -340,7 +346,11 b' var bindToggleButtons = function() {'
340 346 self.globalSubmitSuccessCallback();
341 347
342 348 };
343 var submitFailCallback = function(){
349 var submitFailCallback = function(data) {
350 alert(
351 "Error while submitting comment.\n" +
352 "Error code {0} ({1}).".format(data.status, data.statusText)
353 );
344 354 self.resetCommentFormState(text);
345 355 };
346 356 self.submitAjaxPOST(
@@ -436,7 +446,11 b' var bindToggleButtons = function() {'
436 446 $(self.previewContainer).show();
437 447
438 448 // by default we reset state of comment preserving the text
439 var previewFailCallback = function(){
449 var previewFailCallback = function(data){
450 alert(
451 "Error while preview of comment.\n" +
452 "Error code {0} ({1}).".format(data.status, data.statusText)
453 );
440 454 self.resetCommentFormState(text)
441 455 };
442 456 self.submitAjaxPOST(
@@ -763,7 +777,11 b' var CommentsController = function() {'
763 777 commentForm.setActionButtonsDisabled(false);
764 778
765 779 };
766 var submitFailCallback = function(){
780 var submitFailCallback = function(data){
781 alert(
782 "Error while submitting comment.\n" +
783 "Error code {0} ({1}).".format(data.status, data.statusText)
784 );
767 785 commentForm.resetCommentFormState(text)
768 786 };
769 787 commentForm.submitAjaxPOST(
@@ -32,6 +32,7 b' var addNewPermInput = function(node, per'
32 32 ' </div>'+
33 33 '</td>'+
34 34 '<td></td>'+
35 '<td></td>'+
35 36 '</tr>';
36 37 var _next_id = 'new'+$('.new_members').length;
37 38 _html = _html.format(_next_id, permission_type);
@@ -41,10 +41,10 b' var prButtonLock = function(lockEnabled,'
41 41 }
42 42 var checksMeet = prButtonLockChecks.compare && prButtonLockChecks.reviewers;
43 43 if (lockEnabled) {
44 $('#save').attr('disabled', 'disabled');
44 $('#pr_submit').attr('disabled', 'disabled');
45 45 }
46 46 else if (checksMeet) {
47 $('#save').removeAttr('disabled');
47 $('#pr_submit').removeAttr('disabled');
48 48 }
49 49
50 50 if (msg) {
@@ -361,7 +361,7 b' var updateCommits = function(repo_name, '
361 361 /**
362 362 * PULL REQUEST edit info
363 363 */
364 var editPullRequest = function(repo_name, pull_request_id, title, description) {
364 var editPullRequest = function(repo_name, pull_request_id, title, description, renderer) {
365 365 var url = pyroutes.url(
366 366 'pullrequest_update',
367 367 {"repo_name": repo_name, "pull_request_id": pull_request_id});
@@ -369,6 +369,7 b' var editPullRequest = function(repo_name'
369 369 var postData = {
370 370 'title': title,
371 371 'description': description,
372 'description_renderer': renderer,
372 373 'edit_pull_request': true,
373 374 'csrf_token': CSRF_TOKEN
374 375 };
@@ -378,49 +379,6 b' var editPullRequest = function(repo_name'
378 379 ajaxPOST(url, postData, success);
379 380 };
380 381
381 var initPullRequestsCodeMirror = function (textAreaId) {
382 var ta = $(textAreaId).get(0);
383 var initialHeight = '100px';
384
385 // default options
386 var codeMirrorOptions = {
387 mode: "text",
388 lineNumbers: false,
389 indentUnit: 4,
390 theme: 'rc-input'
391 };
392
393 var codeMirrorInstance = CodeMirror.fromTextArea(ta, codeMirrorOptions);
394 // marker for manually set description
395 codeMirrorInstance._userDefinedDesc = false;
396 codeMirrorInstance.setSize(null, initialHeight);
397 codeMirrorInstance.on("change", function(instance, changeObj) {
398 var height = initialHeight;
399 var lines = instance.lineCount();
400 if (lines > 6 && lines < 20) {
401 height = "auto"
402 }
403 else if (lines >= 20) {
404 height = 20 * 15;
405 }
406 instance.setSize(null, height);
407
408 // detect if the change was trigger by auto desc, or user input
409 changeOrigin = changeObj.origin;
410
411 if (changeOrigin === "setValue") {
412 cmLog.debug('Change triggered by setValue');
413 }
414 else {
415 cmLog.debug('user triggered change !');
416 // set special marker to indicate user has created an input.
417 instance._userDefinedDesc = true;
418 }
419
420 });
421
422 return codeMirrorInstance
423 };
424 382
425 383 /**
426 384 * Reviewer autocomplete
This diff has been collapsed as it changes many lines, (2723 lines changed) Show them Hide them
@@ -1,2505 +1,230 b''
1 1 /**
2 * @license
3 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 * Code distributed by Google as part of the polymer project is also
8 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9 */
10 // @version 0.7.22
11 (function() {
12 window.WebComponents = window.WebComponents || {
13 flags: {}
14 };
15 var file = "webcomponents-lite.js";
16 var script = document.querySelector('script[src*="' + file + '"]');
17 var flags = {};
18 if (!flags.noOpts) {
19 location.search.slice(1).split("&").forEach(function(option) {
20 var parts = option.split("=");
21 var match;
22 if (parts[0] && (match = parts[0].match(/wc-(.+)/))) {
23 flags[match[1]] = parts[1] || true;
24 }
25 });
26 if (script) {
27 for (var i = 0, a; a = script.attributes[i]; i++) {
28 if (a.name !== "src") {
29 flags[a.name] = a.value || true;
30 }
31 }
32 }
33 if (flags.log && flags.log.split) {
34 var parts = flags.log.split(",");
35 flags.log = {};
36 parts.forEach(function(f) {
37 flags.log[f] = true;
38 });
39 } else {
40 flags.log = {};
41 }
42 }
43 if (flags.register) {
44 window.CustomElements = window.CustomElements || {
45 flags: {}
46 };
47 window.CustomElements.flags.register = flags.register;
48 }
49 WebComponents.flags = flags;
50 })();
51
52 (function(scope) {
53 "use strict";
54 var hasWorkingUrl = false;
55 if (!scope.forceJURL) {
56 try {
57 var u = new URL("b", "http://a");
58 u.pathname = "c%20d";
59 hasWorkingUrl = u.href === "http://a/c%20d";
60 } catch (e) {}
61 }
62 if (hasWorkingUrl) return;
63 var relative = Object.create(null);
64 relative["ftp"] = 21;
65 relative["file"] = 0;
66 relative["gopher"] = 70;
67 relative["http"] = 80;
68 relative["https"] = 443;
69 relative["ws"] = 80;
70 relative["wss"] = 443;
71 var relativePathDotMapping = Object.create(null);
72 relativePathDotMapping["%2e"] = ".";
73 relativePathDotMapping[".%2e"] = "..";
74 relativePathDotMapping["%2e."] = "..";
75 relativePathDotMapping["%2e%2e"] = "..";
76 function isRelativeScheme(scheme) {
77 return relative[scheme] !== undefined;
78 }
79 function invalid() {
80 clear.call(this);
81 this._isInvalid = true;
82 }
83 function IDNAToASCII(h) {
84 if ("" == h) {
85 invalid.call(this);
86 }
87 return h.toLowerCase();
88 }
89 function percentEscape(c) {
90 var unicode = c.charCodeAt(0);
91 if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 63, 96 ].indexOf(unicode) == -1) {
92 return c;
93 }
94 return encodeURIComponent(c);
95 }
96 function percentEscapeQuery(c) {
97 var unicode = c.charCodeAt(0);
98 if (unicode > 32 && unicode < 127 && [ 34, 35, 60, 62, 96 ].indexOf(unicode) == -1) {
99 return c;
100 }
101 return encodeURIComponent(c);
102 }
103 var EOF = undefined, ALPHA = /[a-zA-Z]/, ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
104 function parse(input, stateOverride, base) {
105 function err(message) {
106 errors.push(message);
107 }
108 var state = stateOverride || "scheme start", cursor = 0, buffer = "", seenAt = false, seenBracket = false, errors = [];
109 loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
110 var c = input[cursor];
111 switch (state) {
112 case "scheme start":
113 if (c && ALPHA.test(c)) {
114 buffer += c.toLowerCase();
115 state = "scheme";
116 } else if (!stateOverride) {
117 buffer = "";
118 state = "no scheme";
119 continue;
120 } else {
121 err("Invalid scheme.");
122 break loop;
123 }
124 break;
125
126 case "scheme":
127 if (c && ALPHANUMERIC.test(c)) {
128 buffer += c.toLowerCase();
129 } else if (":" == c) {
130 this._scheme = buffer;
131 buffer = "";
132 if (stateOverride) {
133 break loop;
134 }
135 if (isRelativeScheme(this._scheme)) {
136 this._isRelative = true;
137 }
138 if ("file" == this._scheme) {
139 state = "relative";
140 } else if (this._isRelative && base && base._scheme == this._scheme) {
141 state = "relative or authority";
142 } else if (this._isRelative) {
143 state = "authority first slash";
144 } else {
145 state = "scheme data";
146 }
147 } else if (!stateOverride) {
148 buffer = "";
149 cursor = 0;
150 state = "no scheme";
151 continue;
152 } else if (EOF == c) {
153 break loop;
154 } else {
155 err("Code point not allowed in scheme: " + c);
156 break loop;
157 }
158 break;
159
160 case "scheme data":
161 if ("?" == c) {
162 this._query = "?";
163 state = "query";
164 } else if ("#" == c) {
165 this._fragment = "#";
166 state = "fragment";
167 } else {
168 if (EOF != c && " " != c && "\n" != c && "\r" != c) {
169 this._schemeData += percentEscape(c);
170 }
171 }
172 break;
173
174 case "no scheme":
175 if (!base || !isRelativeScheme(base._scheme)) {
176 err("Missing scheme.");
177 invalid.call(this);
178 } else {
179 state = "relative";
180 continue;
181 }
182 break;
183
184 case "relative or authority":
185 if ("/" == c && "/" == input[cursor + 1]) {
186 state = "authority ignore slashes";
187 } else {
188 err("Expected /, got: " + c);
189 state = "relative";
190 continue;
191 }
192 break;
193
194 case "relative":
195 this._isRelative = true;
196 if ("file" != this._scheme) this._scheme = base._scheme;
197 if (EOF == c) {
198 this._host = base._host;
199 this._port = base._port;
200 this._path = base._path.slice();
201 this._query = base._query;
202 this._username = base._username;
203 this._password = base._password;
204 break loop;
205 } else if ("/" == c || "\\" == c) {
206 if ("\\" == c) err("\\ is an invalid code point.");
207 state = "relative slash";
208 } else if ("?" == c) {
209 this._host = base._host;
210 this._port = base._port;
211 this._path = base._path.slice();
212 this._query = "?";
213 this._username = base._username;
214 this._password = base._password;
215 state = "query";
216 } else if ("#" == c) {
217 this._host = base._host;
218 this._port = base._port;
219 this._path = base._path.slice();
220 this._query = base._query;
221 this._fragment = "#";
222 this._username = base._username;
223 this._password = base._password;
224 state = "fragment";
225 } else {
226 var nextC = input[cursor + 1];
227 var nextNextC = input[cursor + 2];
228 if ("file" != this._scheme || !ALPHA.test(c) || nextC != ":" && nextC != "|" || EOF != nextNextC && "/" != nextNextC && "\\" != nextNextC && "?" != nextNextC && "#" != nextNextC) {
229 this._host = base._host;
230 this._port = base._port;
231 this._username = base._username;
232 this._password = base._password;
233 this._path = base._path.slice();
234 this._path.pop();
235 }
236 state = "relative path";
237 continue;
238 }
239 break;
240
241 case "relative slash":
242 if ("/" == c || "\\" == c) {
243 if ("\\" == c) {
244 err("\\ is an invalid code point.");
245 }
246 if ("file" == this._scheme) {
247 state = "file host";
248 } else {
249 state = "authority ignore slashes";
250 }
251 } else {
252 if ("file" != this._scheme) {
253 this._host = base._host;
254 this._port = base._port;
255 this._username = base._username;
256 this._password = base._password;
257 }
258 state = "relative path";
259 continue;
260 }
261 break;
262
263 case "authority first slash":
264 if ("/" == c) {
265 state = "authority second slash";
266 } else {
267 err("Expected '/', got: " + c);
268 state = "authority ignore slashes";
269 continue;
270 }
271 break;
272
273 case "authority second slash":
274 state = "authority ignore slashes";
275 if ("/" != c) {
276 err("Expected '/', got: " + c);
277 continue;
278 }
279 break;
280
281 case "authority ignore slashes":
282 if ("/" != c && "\\" != c) {
283 state = "authority";
284 continue;
285 } else {
286 err("Expected authority, got: " + c);
287 }
288 break;
289
290 case "authority":
291 if ("@" == c) {
292 if (seenAt) {
293 err("@ already seen.");
294 buffer += "%40";
295 }
296 seenAt = true;
297 for (var i = 0; i < buffer.length; i++) {
298 var cp = buffer[i];
299 if (" " == cp || "\n" == cp || "\r" == cp) {
300 err("Invalid whitespace in authority.");
301 continue;
302 }
303 if (":" == cp && null === this._password) {
304 this._password = "";
305 continue;
306 }
307 var tempC = percentEscape(cp);
308 null !== this._password ? this._password += tempC : this._username += tempC;
309 }
310 buffer = "";
311 } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
312 cursor -= buffer.length;
313 buffer = "";
314 state = "host";
315 continue;
316 } else {
317 buffer += c;
318 }
319 break;
320
321 case "file host":
322 if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
323 if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ":" || buffer[1] == "|")) {
324 state = "relative path";
325 } else if (buffer.length == 0) {
326 state = "relative path start";
327 } else {
328 this._host = IDNAToASCII.call(this, buffer);
329 buffer = "";
330 state = "relative path start";
331 }
332 continue;
333 } else if (" " == c || "\n" == c || "\r" == c) {
334 err("Invalid whitespace in file host.");
335 } else {
336 buffer += c;
337 }
338 break;
339
340 case "host":
341 case "hostname":
342 if (":" == c && !seenBracket) {
343 this._host = IDNAToASCII.call(this, buffer);
344 buffer = "";
345 state = "port";
346 if ("hostname" == stateOverride) {
347 break loop;
348 }
349 } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c) {
350 this._host = IDNAToASCII.call(this, buffer);
351 buffer = "";
352 state = "relative path start";
353 if (stateOverride) {
354 break loop;
355 }
356 continue;
357 } else if (" " != c && "\n" != c && "\r" != c) {
358 if ("[" == c) {
359 seenBracket = true;
360 } else if ("]" == c) {
361 seenBracket = false;
362 }
363 buffer += c;
364 } else {
365 err("Invalid code point in host/hostname: " + c);
366 }
367 break;
368
369 case "port":
370 if (/[0-9]/.test(c)) {
371 buffer += c;
372 } else if (EOF == c || "/" == c || "\\" == c || "?" == c || "#" == c || stateOverride) {
373 if ("" != buffer) {
374 var temp = parseInt(buffer, 10);
375 if (temp != relative[this._scheme]) {
376 this._port = temp + "";
377 }
378 buffer = "";
379 }
380 if (stateOverride) {
381 break loop;
382 }
383 state = "relative path start";
384 continue;
385 } else if (" " == c || "\n" == c || "\r" == c) {
386 err("Invalid code point in port: " + c);
387 } else {
388 invalid.call(this);
389 }
390 break;
391
392 case "relative path start":
393 if ("\\" == c) err("'\\' not allowed in path.");
394 state = "relative path";
395 if ("/" != c && "\\" != c) {
396 continue;
397 }
398 break;
399
400 case "relative path":
401 if (EOF == c || "/" == c || "\\" == c || !stateOverride && ("?" == c || "#" == c)) {
402 if ("\\" == c) {
403 err("\\ not allowed in relative path.");
404 }
405 var tmp;
406 if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
407 buffer = tmp;
408 }
409 if (".." == buffer) {
410 this._path.pop();
411 if ("/" != c && "\\" != c) {
412 this._path.push("");
413 }
414 } else if ("." == buffer && "/" != c && "\\" != c) {
415 this._path.push("");
416 } else if ("." != buffer) {
417 if ("file" == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == "|") {
418 buffer = buffer[0] + ":";
419 }
420 this._path.push(buffer);
421 }
422 buffer = "";
423 if ("?" == c) {
424 this._query = "?";
425 state = "query";
426 } else if ("#" == c) {
427 this._fragment = "#";
428 state = "fragment";
429 }
430 } else if (" " != c && "\n" != c && "\r" != c) {
431 buffer += percentEscape(c);
432 }
433 break;
434
435 case "query":
436 if (!stateOverride && "#" == c) {
437 this._fragment = "#";
438 state = "fragment";
439 } else if (EOF != c && " " != c && "\n" != c && "\r" != c) {
440 this._query += percentEscapeQuery(c);
441 }
442 break;
443
444 case "fragment":
445 if (EOF != c && " " != c && "\n" != c && "\r" != c) {
446 this._fragment += c;
447 }
448 break;
449 }
450 cursor++;
451 }
452 }
453 function clear() {
454 this._scheme = "";
455 this._schemeData = "";
456 this._username = "";
457 this._password = null;
458 this._host = "";
459 this._port = "";
460 this._path = [];
461 this._query = "";
462 this._fragment = "";
463 this._isInvalid = false;
464 this._isRelative = false;
465 }
466 function jURL(url, base) {
467 if (base !== undefined && !(base instanceof jURL)) base = new jURL(String(base));
468 this._url = url;
469 clear.call(this);
470 var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, "");
471 parse.call(this, input, null, base);
472 }
473 jURL.prototype = {
474 toString: function() {
475 return this.href;
476 },
477 get href() {
478 if (this._isInvalid) return this._url;
479 var authority = "";
480 if ("" != this._username || null != this._password) {
481 authority = this._username + (null != this._password ? ":" + this._password : "") + "@";
482 }
483 return this.protocol + (this._isRelative ? "//" + authority + this.host : "") + this.pathname + this._query + this._fragment;
484 },
485 set href(href) {
486 clear.call(this);
487 parse.call(this, href);
488 },
489 get protocol() {
490 return this._scheme + ":";
491 },
492 set protocol(protocol) {
493 if (this._isInvalid) return;
494 parse.call(this, protocol + ":", "scheme start");
495 },
496 get host() {
497 return this._isInvalid ? "" : this._port ? this._host + ":" + this._port : this._host;
498 },
499 set host(host) {
500 if (this._isInvalid || !this._isRelative) return;
501 parse.call(this, host, "host");
502 },
503 get hostname() {
504 return this._host;
505 },
506 set hostname(hostname) {
507 if (this._isInvalid || !this._isRelative) return;
508 parse.call(this, hostname, "hostname");
509 },
510 get port() {
511 return this._port;
512 },
513 set port(port) {
514 if (this._isInvalid || !this._isRelative) return;
515 parse.call(this, port, "port");
516 },
517 get pathname() {
518 return this._isInvalid ? "" : this._isRelative ? "/" + this._path.join("/") : this._schemeData;
519 },
520 set pathname(pathname) {
521 if (this._isInvalid || !this._isRelative) return;
522 this._path = [];
523 parse.call(this, pathname, "relative path start");
524 },
525 get search() {
526 return this._isInvalid || !this._query || "?" == this._query ? "" : this._query;
527 },
528 set search(search) {
529 if (this._isInvalid || !this._isRelative) return;
530 this._query = "?";
531 if ("?" == search[0]) search = search.slice(1);
532 parse.call(this, search, "query");
533 },
534 get hash() {
535 return this._isInvalid || !this._fragment || "#" == this._fragment ? "" : this._fragment;
536 },
537 set hash(hash) {
538 if (this._isInvalid) return;
539 this._fragment = "#";
540 if ("#" == hash[0]) hash = hash.slice(1);
541 parse.call(this, hash, "fragment");
542 },
543 get origin() {
544 var host;
545 if (this._isInvalid || !this._scheme) {
546 return "";
547 }
548 switch (this._scheme) {
549 case "data":
550 case "file":
551 case "javascript":
552 case "mailto":
553 return "null";
554 }
555 host = this.host;
556 if (!host) {
557 return "";
558 }
559 return this._scheme + "://" + host;
560 }
561 };
562 var OriginalURL = scope.URL;
563 if (OriginalURL) {
564 jURL.createObjectURL = function(blob) {
565 return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
566 };
567 jURL.revokeObjectURL = function(url) {
568 OriginalURL.revokeObjectURL(url);
569 };
570 }
571 scope.URL = jURL;
572 })(self);
2 @license @nocompile
3 Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9 */
10 (function(){/*
573 11
574 if (typeof WeakMap === "undefined") {
575 (function() {
576 var defineProperty = Object.defineProperty;
577 var counter = Date.now() % 1e9;
578 var WeakMap = function() {
579 this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__");
580 };
581 WeakMap.prototype = {
582 set: function(key, value) {
583 var entry = key[this.name];
584 if (entry && entry[0] === key) entry[1] = value; else defineProperty(key, this.name, {
585 value: [ key, value ],
586 writable: true
587 });
588 return this;
589 },
590 get: function(key) {
591 var entry;
592 return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;
593 },
594 "delete": function(key) {
595 var entry = key[this.name];
596 if (!entry || entry[0] !== key) return false;
597 entry[0] = entry[1] = undefined;
598 return true;
599 },
600 has: function(key) {
601 var entry = key[this.name];
602 if (!entry) return false;
603 return entry[0] === key;
604 }
605 };
606 window.WeakMap = WeakMap;
607 })();
608 }
12 Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
13 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
14 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
15 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
16 Code distributed by Google as part of the polymer project is also
17 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
18 */
19 'use strict';var p,aa="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)},ea="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this;function ha(){ha=function(){};ea.Symbol||(ea.Symbol=ia)}var ia=function(){var a=0;return function(b){return"jscomp_symbol_"+(b||"")+a++}}();
20 function ja(){ha();var a=ea.Symbol.iterator;a||(a=ea.Symbol.iterator=ea.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&aa(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return ka(this)}});ja=function(){}}function ka(a){var b=0;return la(function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}})}function la(a){ja();a={next:a};a[ea.Symbol.iterator]=function(){return this};return a}function ma(a){ja();var b=a[Symbol.iterator];return b?b.call(a):ka(a)}
21 function na(a){for(var b,c=[];!(b=a.next()).done;)c.push(b.value);return c}
22 (function(){if(!function(){var a=document.createEvent("Event");a.initEvent("foo",!0,!0);a.preventDefault();return a.defaultPrevented}()){var a=Event.prototype.preventDefault;Event.prototype.preventDefault=function(){this.cancelable&&(a.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0},configurable:!0}))}}var b=/Trident/.test(navigator.userAgent);if(!window.CustomEvent||b&&"function"!==typeof window.CustomEvent)window.CustomEvent=function(a,b){b=b||{};var c=document.createEvent("CustomEvent");
23 c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c},window.CustomEvent.prototype=window.Event.prototype;if(!window.Event||b&&"function"!==typeof window.Event){var c=window.Event;window.Event=function(a,b){b=b||{};var c=document.createEvent("Event");c.initEvent(a,!!b.bubbles,!!b.cancelable);return c};if(c)for(var d in c)window.Event[d]=c[d];window.Event.prototype=c.prototype}if(!window.MouseEvent||b&&"function"!==typeof window.MouseEvent){b=window.MouseEvent;window.MouseEvent=function(a,
24 b){b=b||{};var c=document.createEvent("MouseEvent");c.initMouseEvent(a,!!b.bubbles,!!b.cancelable,b.view||window,b.detail,b.screenX,b.screenY,b.clientX,b.clientY,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,b.button,b.relatedTarget);return c};if(b)for(d in b)window.MouseEvent[d]=b[d];window.MouseEvent.prototype=b.prototype}Array.from||(Array.from=function(a){return[].slice.call(a)});Object.assign||(Object.assign=function(a,b){for(var c=[].slice.call(arguments,1),d=0,e;d<c.length;d++)if(e=c[d])for(var f=
25 a,m=e,n=Object.getOwnPropertyNames(m),t=0;t<n.length;t++)e=n[t],f[e]=m[e];return a})})(window.WebComponents);(function(){function a(){}function b(a,b){if(!a.childNodes.length)return[];switch(a.nodeType){case Node.DOCUMENT_NODE:return ya.call(a,b);case Node.DOCUMENT_FRAGMENT_NODE:return qb.call(a,b);default:return ba.call(a,b)}}var c="undefined"===typeof HTMLTemplateElement,d=!(document.createDocumentFragment().cloneNode()instanceof DocumentFragment),e=!1;/Trident/.test(navigator.userAgent)&&function(){function a(a,b){if(a instanceof DocumentFragment)for(var d;d=a.firstChild;)c.call(this,d,b);else c.call(this,
26 a,b);return a}e=!0;var b=Node.prototype.cloneNode;Node.prototype.cloneNode=function(a){a=b.call(this,a);this instanceof DocumentFragment&&(a.__proto__=DocumentFragment.prototype);return a};DocumentFragment.prototype.querySelectorAll=HTMLElement.prototype.querySelectorAll;DocumentFragment.prototype.querySelector=HTMLElement.prototype.querySelector;Object.defineProperties(DocumentFragment.prototype,{nodeType:{get:function(){return Node.DOCUMENT_FRAGMENT_NODE},configurable:!0},localName:{get:function(){},
27 configurable:!0},nodeName:{get:function(){return"#document-fragment"},configurable:!0}});var c=Node.prototype.insertBefore;Node.prototype.insertBefore=a;var d=Node.prototype.appendChild;Node.prototype.appendChild=function(b){b instanceof DocumentFragment?a.call(this,b,null):d.call(this,b);return b};var f=Node.prototype.removeChild,h=Node.prototype.replaceChild;Node.prototype.replaceChild=function(b,c){b instanceof DocumentFragment?(a.call(this,b,c),f.call(this,c)):h.call(this,b,c);return c};Document.prototype.createDocumentFragment=
28 function(){var a=this.createElement("df");a.__proto__=DocumentFragment.prototype;return a};var g=Document.prototype.importNode;Document.prototype.importNode=function(a,b){b=g.call(this,a,b||!1);a instanceof DocumentFragment&&(b.__proto__=DocumentFragment.prototype);return b}}();var f=Node.prototype.cloneNode,h=Document.prototype.createElement,g=Document.prototype.importNode,k=Node.prototype.removeChild,l=Node.prototype.appendChild,m=Node.prototype.replaceChild,n=DOMParser.prototype.parseFromString,
29 t=Object.getOwnPropertyDescriptor(window.HTMLElement.prototype,"innerHTML"),C=Object.getOwnPropertyDescriptor(window.Node.prototype,"childNodes"),ba=Element.prototype.querySelectorAll,ya=Document.prototype.querySelectorAll,qb=DocumentFragment.prototype.querySelectorAll,rb=function(){if(!c){var a=document.createElement("template"),b=document.createElement("template");b.content.appendChild(document.createElement("div"));a.content.appendChild(b);a=a.cloneNode(!0);return 0===a.content.childNodes.length||
30 0===a.content.firstChild.content.childNodes.length||d}}();if(c){var V=document.implementation.createHTMLDocument("template"),D=!0,ca=document.createElement("style");ca.textContent="template{display:none;}";var oa=document.head;oa.insertBefore(ca,oa.firstElementChild);a.prototype=Object.create(HTMLElement.prototype);var za=!document.createElement("div").hasOwnProperty("innerHTML");a.I=function(b){if(!b.content&&b.namespaceURI===document.documentElement.namespaceURI){b.content=V.createDocumentFragment();
31 for(var c;c=b.firstChild;)l.call(b.content,c);if(za)b.__proto__=a.prototype;else if(b.cloneNode=function(b){return a.a(this,b)},D)try{T(b),da(b)}catch(Gh){D=!1}a.C(b.content)}};var fa={option:["select"],thead:["table"],col:["colgroup","table"],tr:["tbody","table"],th:["tr","tbody","table"],td:["tr","tbody","table"]},T=function(b){Object.defineProperty(b,"innerHTML",{get:function(){return sb(this)},set:function(b){var c=fa[(/<([a-z][^/\0>\x20\t\r\n\f]+)/i.exec(b)||["",""])[1].toLowerCase()];if(c)for(var d=
32 0;d<c.length;d++)b="<"+c[d]+">"+b+"</"+c[d]+">";V.body.innerHTML=b;for(a.C(V);this.content.firstChild;)k.call(this.content,this.content.firstChild);b=V.body;if(c)for(d=0;d<c.length;d++)b=b.lastChild;for(;b.firstChild;)l.call(this.content,b.firstChild)},configurable:!0})},da=function(a){Object.defineProperty(a,"outerHTML",{get:function(){return"<template>"+this.innerHTML+"</template>"},set:function(a){if(this.parentNode){V.body.innerHTML=a;for(a=this.ownerDocument.createDocumentFragment();V.body.firstChild;)l.call(a,
33 V.body.firstChild);m.call(this.parentNode,a,this)}else throw Error("Failed to set the 'outerHTML' property on 'Element': This element has no parent node.");},configurable:!0})};T(a.prototype);da(a.prototype);a.C=function(c){c=b(c,"template");for(var d=0,e=c.length,f;d<e&&(f=c[d]);d++)a.I(f)};document.addEventListener("DOMContentLoaded",function(){a.C(document)});Document.prototype.createElement=function(){var b=h.apply(this,arguments);"template"===b.localName&&a.I(b);return b};DOMParser.prototype.parseFromString=
34 function(){var b=n.apply(this,arguments);a.C(b);return b};Object.defineProperty(HTMLElement.prototype,"innerHTML",{get:function(){return sb(this)},set:function(b){t.set.call(this,b);a.C(this)},configurable:!0,enumerable:!0});var sf=/[&\u00A0"]/g,Kc=/[&\u00A0<>]/g,Lc=function(a){switch(a){case "&":return"&amp;";case "<":return"&lt;";case ">":return"&gt;";case '"':return"&quot;";case "\u00a0":return"&nbsp;"}};ca=function(a){for(var b={},c=0;c<a.length;c++)b[a[c]]=!0;return b};var tf=ca("area base br col command embed hr img input keygen link meta param source track wbr".split(" ")),
35 uf=ca("style script xmp iframe noembed noframes plaintext noscript".split(" ")),sb=function(a,b){"template"===a.localName&&(a=a.content);for(var c="",d=b?b(a):C.get.call(a),e=0,f=d.length,h;e<f&&(h=d[e]);e++){a:{var g=h;var k=a;var l=b;switch(g.nodeType){case Node.ELEMENT_NODE:for(var T=g.localName,m="<"+T,da=g.attributes,n=0;k=da[n];n++)m+=" "+k.name+'="'+k.value.replace(sf,Lc)+'"';m+=">";g=tf[T]?m:m+sb(g,l)+"</"+T+">";break a;case Node.TEXT_NODE:g=g.data;g=k&&uf[k.localName]?g:g.replace(Kc,Lc);
36 break a;case Node.COMMENT_NODE:g="\x3c!--"+g.data+"--\x3e";break a;default:throw window.console.error(g),Error("not implemented");}}c+=g}return c}}if(c||rb){a.a=function(a,b){var c=f.call(a,!1);this.I&&this.I(c);b&&(l.call(c.content,f.call(a.content,!0)),tb(c.content,a.content));return c};var tb=function(c,d){if(d.querySelectorAll&&(d=b(d,"template"),0!==d.length)){c=b(c,"template");for(var e=0,f=c.length,h,g;e<f;e++)g=d[e],h=c[e],a&&a.I&&a.I(g),m.call(h.parentNode,vf.call(g,!0),h)}},vf=Node.prototype.cloneNode=
37 function(b){if(!e&&d&&this instanceof DocumentFragment)if(b)var c=wf.call(this.ownerDocument,this,!0);else return this.ownerDocument.createDocumentFragment();else this.nodeType===Node.ELEMENT_NODE&&"template"===this.localName&&this.namespaceURI==document.documentElement.namespaceURI?c=a.a(this,b):c=f.call(this,b);b&&tb(c,this);return c},wf=Document.prototype.importNode=function(c,d){d=d||!1;if("template"===c.localName)return a.a(c,d);var e=g.call(this,c,d);if(d){tb(e,c);c=b(e,'script:not([type]),script[type="application/javascript"],script[type="text/javascript"]');
38 for(var f,k=0;k<c.length;k++){f=c[k];d=h.call(document,"script");d.textContent=f.textContent;for(var l=f.attributes,T=0,da;T<l.length;T++)da=l[T],d.setAttribute(da.name,da.value);m.call(f.parentNode,d,f)}}return e}}c&&(window.HTMLTemplateElement=a)})();var pa;Array.isArray?pa=Array.isArray:pa=function(a){return"[object Array]"===Object.prototype.toString.call(a)};var qa=pa;var ra=0,sa,ta="undefined"!==typeof window?window:void 0,ua=ta||{},va=ua.MutationObserver||ua.WebKitMutationObserver,wa="undefined"!==typeof Uint8ClampedArray&&"undefined"!==typeof importScripts&&"undefined"!==typeof MessageChannel;function xa(){return"undefined"!==typeof sa?function(){sa(Aa)}:Ba()}function Ca(){var a=0,b=new va(Aa),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}
39 function Da(){var a=new MessageChannel;a.port1.onmessage=Aa;return function(){return a.port2.postMessage(0)}}function Ba(){var a=setTimeout;return function(){return a(Aa,1)}}var Ea=Array(1E3);function Aa(){for(var a=0;a<ra;a+=2)(0,Ea[a])(Ea[a+1]),Ea[a]=void 0,Ea[a+1]=void 0;ra=0}var Fa,Ga;
40 if("undefined"===typeof self&&"undefined"!==typeof process&&"[object process]"==={}.toString.call(process))Ga=function(){return process.vb(Aa)};else{var Ha;if(va)Ha=Ca();else{var Ia;if(wa)Ia=Da();else{var Ja;if(void 0===ta&&"function"===typeof require)try{var Ka=require("vertx");sa=Ka.xb||Ka.wb;Ja=xa()}catch(a){Ja=Ba()}else Ja=Ba();Ia=Ja}Ha=Ia}Ga=Ha}Fa=Ga;function La(a,b){Ea[ra]=a;Ea[ra+1]=b;ra+=2;2===ra&&Fa()};function Ma(a,b){var c=this,d=new this.constructor(Na);void 0===d[Oa]&&Pa(d);var e=c.h;if(e){var f=arguments[e-1];La(function(){return Qa(e,d,f,c.f)})}else Ra(c,d,a,b);return d};function Sa(a){if(a&&"object"===typeof a&&a.constructor===this)return a;var b=new this(Na);Ta(b,a);return b};var Oa=Math.random().toString(36).substring(16);function Na(){}var Va=new Ua;function Wa(a){try{return a.then}catch(b){return Va.error=b,Va}}function Xa(a,b,c,d){try{a.call(b,c,d)}catch(e){return e}}function Ya(a,b,c){La(function(a){var d=!1,f=Xa(c,b,function(c){d||(d=!0,b!==c?Ta(a,c):q(a,c))},function(b){d||(d=!0,r(a,b))});!d&&f&&(d=!0,r(a,f))},a)}function Za(a,b){1===b.h?q(a,b.f):2===b.h?r(a,b.f):Ra(b,void 0,function(b){return Ta(a,b)},function(b){return r(a,b)})}
41 function $a(a,b,c){b.constructor===a.constructor&&c===Ma&&b.constructor.resolve===Sa?Za(a,b):c===Va?(r(a,Va.error),Va.error=null):void 0===c?q(a,b):"function"===typeof c?Ya(a,b,c):q(a,b)}function Ta(a,b){if(a===b)r(a,new TypeError("You cannot resolve a promise with itself"));else{var c=typeof b;null===b||"object"!==c&&"function"!==c?q(a,b):$a(a,b,Wa(b))}}function ab(a){a.va&&a.va(a.f);bb(a)}function q(a,b){void 0===a.h&&(a.f=b,a.h=1,0!==a.M.length&&La(bb,a))}
42 function r(a,b){void 0===a.h&&(a.h=2,a.f=b,La(ab,a))}function Ra(a,b,c,d){var e=a.M,f=e.length;a.va=null;e[f]=b;e[f+1]=c;e[f+2]=d;0===f&&a.h&&La(bb,a)}function bb(a){var b=a.M,c=a.h;if(0!==b.length){for(var d,e,f=a.f,h=0;h<b.length;h+=3)d=b[h],e=b[h+c],d?Qa(c,d,e,f):e(f);a.M.length=0}}function Ua(){this.error=null}var cb=new Ua;
43 function Qa(a,b,c,d){var e="function"===typeof c;if(e){try{var f=c(d)}catch(l){cb.error=l,f=cb}if(f===cb){var h=!0;var g=f.error;f.error=null}else var k=!0;if(b===f){r(b,new TypeError("A promises callback cannot return that same promise."));return}}else f=d,k=!0;void 0===b.h&&(e&&k?Ta(b,f):h?r(b,g):1===a?q(b,f):2===a&&r(b,f))}function db(a,b){try{b(function(b){Ta(a,b)},function(b){r(a,b)})}catch(c){r(a,c)}}var eb=0;function Pa(a){a[Oa]=eb++;a.h=void 0;a.f=void 0;a.M=[]};function fb(a,b){this.Ka=a;this.F=new a(Na);this.F[Oa]||Pa(this.F);if(qa(b))if(this.V=this.length=b.length,this.f=Array(this.length),0===this.length)q(this.F,this.f);else{this.length=this.length||0;for(a=0;void 0===this.h&&a<b.length;a++)gb(this,b[a],a);0===this.V&&q(this.F,this.f)}else r(this.F,Error("Array Methods must be provided an Array"))}
44 function gb(a,b,c){var d=a.Ka,e=d.resolve;e===Sa?(e=Wa(b),e===Ma&&void 0!==b.h?hb(a,b.h,c,b.f):"function"!==typeof e?(a.V--,a.f[c]=b):d===u?(d=new d(Na),$a(d,b,e),ib(a,d,c)):ib(a,new d(function(a){return a(b)}),c)):ib(a,e(b),c)}function hb(a,b,c,d){var e=a.F;void 0===e.h&&(a.V--,2===b?r(e,d):a.f[c]=d);0===a.V&&q(e,a.f)}function ib(a,b,c){Ra(b,void 0,function(b){return hb(a,1,c,b)},function(b){return hb(a,2,c,b)})};function jb(a){return(new fb(this,a)).F};function kb(a){var b=this;return qa(a)?new b(function(c,d){for(var e=a.length,f=0;f<e;f++)b.resolve(a[f]).then(c,d)}):new b(function(a,b){return b(new TypeError("You must pass an array to race."))})};function lb(a){var b=new this(Na);r(b,a);return b};function u(a){this[Oa]=eb++;this.f=this.h=void 0;this.M=[];if(Na!==a){if("function"!==typeof a)throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(this instanceof u)db(this,a);else throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");}}u.prototype={constructor:u,then:Ma,a:function(a){return this.then(null,a)}};/*
609 45
610 (function(global) {
611 if (global.JsMutationObserver) {
612 return;
613 }
614 var registrationsTable = new WeakMap();
615 var setImmediate;
616 if (/Trident|Edge/.test(navigator.userAgent)) {
617 setImmediate = setTimeout;
618 } else if (window.setImmediate) {
619 setImmediate = window.setImmediate;
620 } else {
621 var setImmediateQueue = [];
622 var sentinel = String(Math.random());
623 window.addEventListener("message", function(e) {
624 if (e.data === sentinel) {
625 var queue = setImmediateQueue;
626 setImmediateQueue = [];
627 queue.forEach(function(func) {
628 func();
629 });
630 }
631 });
632 setImmediate = function(func) {
633 setImmediateQueue.push(func);
634 window.postMessage(sentinel, "*");
635 };
636 }
637 var isScheduled = false;
638 var scheduledObservers = [];
639 function scheduleCallback(observer) {
640 scheduledObservers.push(observer);
641 if (!isScheduled) {
642 isScheduled = true;
643 setImmediate(dispatchCallbacks);
644 }
645 }
646 function wrapIfNeeded(node) {
647 return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;
648 }
649 function dispatchCallbacks() {
650 isScheduled = false;
651 var observers = scheduledObservers;
652 scheduledObservers = [];
653 observers.sort(function(o1, o2) {
654 return o1.uid_ - o2.uid_;
655 });
656 var anyNonEmpty = false;
657 observers.forEach(function(observer) {
658 var queue = observer.takeRecords();
659 removeTransientObserversFor(observer);
660 if (queue.length) {
661 observer.callback_(queue, observer);
662 anyNonEmpty = true;
663 }
664 });
665 if (anyNonEmpty) dispatchCallbacks();
666 }
667 function removeTransientObserversFor(observer) {
668 observer.nodes_.forEach(function(node) {
669 var registrations = registrationsTable.get(node);
670 if (!registrations) return;
671 registrations.forEach(function(registration) {
672 if (registration.observer === observer) registration.removeTransientObservers();
673 });
674 });
675 }
676 function forEachAncestorAndObserverEnqueueRecord(target, callback) {
677 for (var node = target; node; node = node.parentNode) {
678 var registrations = registrationsTable.get(node);
679 if (registrations) {
680 for (var j = 0; j < registrations.length; j++) {
681 var registration = registrations[j];
682 var options = registration.options;
683 if (node !== target && !options.subtree) continue;
684 var record = callback(options);
685 if (record) registration.enqueue(record);
686 }
687 }
688 }
689 }
690 var uidCounter = 0;
691 function JsMutationObserver(callback) {
692 this.callback_ = callback;
693 this.nodes_ = [];
694 this.records_ = [];
695 this.uid_ = ++uidCounter;
696 }
697 JsMutationObserver.prototype = {
698 observe: function(target, options) {
699 target = wrapIfNeeded(target);
700 if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) {
701 throw new SyntaxError();
702 }
703 var registrations = registrationsTable.get(target);
704 if (!registrations) registrationsTable.set(target, registrations = []);
705 var registration;
706 for (var i = 0; i < registrations.length; i++) {
707 if (registrations[i].observer === this) {
708 registration = registrations[i];
709 registration.removeListeners();
710 registration.options = options;
711 break;
712 }
713 }
714 if (!registration) {
715 registration = new Registration(this, target, options);
716 registrations.push(registration);
717 this.nodes_.push(target);
718 }
719 registration.addListeners();
720 },
721 disconnect: function() {
722 this.nodes_.forEach(function(node) {
723 var registrations = registrationsTable.get(node);
724 for (var i = 0; i < registrations.length; i++) {
725 var registration = registrations[i];
726 if (registration.observer === this) {
727 registration.removeListeners();
728 registrations.splice(i, 1);
729 break;
730 }
731 }
732 }, this);
733 this.records_ = [];
734 },
735 takeRecords: function() {
736 var copyOfRecords = this.records_;
737 this.records_ = [];
738 return copyOfRecords;
739 }
740 };
741 function MutationRecord(type, target) {
742 this.type = type;
743 this.target = target;
744 this.addedNodes = [];
745 this.removedNodes = [];
746 this.previousSibling = null;
747 this.nextSibling = null;
748 this.attributeName = null;
749 this.attributeNamespace = null;
750 this.oldValue = null;
751 }
752 function copyMutationRecord(original) {
753 var record = new MutationRecord(original.type, original.target);
754 record.addedNodes = original.addedNodes.slice();
755 record.removedNodes = original.removedNodes.slice();
756 record.previousSibling = original.previousSibling;
757 record.nextSibling = original.nextSibling;
758 record.attributeName = original.attributeName;
759 record.attributeNamespace = original.attributeNamespace;
760 record.oldValue = original.oldValue;
761 return record;
762 }
763 var currentRecord, recordWithOldValue;
764 function getRecord(type, target) {
765 return currentRecord = new MutationRecord(type, target);
766 }
767 function getRecordWithOldValue(oldValue) {
768 if (recordWithOldValue) return recordWithOldValue;
769 recordWithOldValue = copyMutationRecord(currentRecord);
770 recordWithOldValue.oldValue = oldValue;
771 return recordWithOldValue;
772 }
773 function clearRecords() {
774 currentRecord = recordWithOldValue = undefined;
775 }
776 function recordRepresentsCurrentMutation(record) {
777 return record === recordWithOldValue || record === currentRecord;
778 }
779 function selectRecord(lastRecord, newRecord) {
780 if (lastRecord === newRecord) return lastRecord;
781 if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
782 return null;
783 }
784 function Registration(observer, target, options) {
785 this.observer = observer;
786 this.target = target;
787 this.options = options;
788 this.transientObservedNodes = [];
789 }
790 Registration.prototype = {
791 enqueue: function(record) {
792 var records = this.observer.records_;
793 var length = records.length;
794 if (records.length > 0) {
795 var lastRecord = records[length - 1];
796 var recordToReplaceLast = selectRecord(lastRecord, record);
797 if (recordToReplaceLast) {
798 records[length - 1] = recordToReplaceLast;
799 return;
800 }
801 } else {
802 scheduleCallback(this.observer);
803 }
804 records[length] = record;
805 },
806 addListeners: function() {
807 this.addListeners_(this.target);
808 },
809 addListeners_: function(node) {
810 var options = this.options;
811 if (options.attributes) node.addEventListener("DOMAttrModified", this, true);
812 if (options.characterData) node.addEventListener("DOMCharacterDataModified", this, true);
813 if (options.childList) node.addEventListener("DOMNodeInserted", this, true);
814 if (options.childList || options.subtree) node.addEventListener("DOMNodeRemoved", this, true);
815 },
816 removeListeners: function() {
817 this.removeListeners_(this.target);
818 },
819 removeListeners_: function(node) {
820 var options = this.options;
821 if (options.attributes) node.removeEventListener("DOMAttrModified", this, true);
822 if (options.characterData) node.removeEventListener("DOMCharacterDataModified", this, true);
823 if (options.childList) node.removeEventListener("DOMNodeInserted", this, true);
824 if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", this, true);
825 },
826 addTransientObserver: function(node) {
827 if (node === this.target) return;
828 this.addListeners_(node);
829 this.transientObservedNodes.push(node);
830 var registrations = registrationsTable.get(node);
831 if (!registrations) registrationsTable.set(node, registrations = []);
832 registrations.push(this);
833 },
834 removeTransientObservers: function() {
835 var transientObservedNodes = this.transientObservedNodes;
836 this.transientObservedNodes = [];
837 transientObservedNodes.forEach(function(node) {
838 this.removeListeners_(node);
839 var registrations = registrationsTable.get(node);
840 for (var i = 0; i < registrations.length; i++) {
841 if (registrations[i] === this) {
842 registrations.splice(i, 1);
843 break;
844 }
845 }
846 }, this);
847 },
848 handleEvent: function(e) {
849 e.stopImmediatePropagation();
850 switch (e.type) {
851 case "DOMAttrModified":
852 var name = e.attrName;
853 var namespace = e.relatedNode.namespaceURI;
854 var target = e.target;
855 var record = new getRecord("attributes", target);
856 record.attributeName = name;
857 record.attributeNamespace = namespace;
858 var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
859 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
860 if (!options.attributes) return;
861 if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
862 return;
863 }
864 if (options.attributeOldValue) return getRecordWithOldValue(oldValue);
865 return record;
866 });
867 break;
868
869 case "DOMCharacterDataModified":
870 var target = e.target;
871 var record = getRecord("characterData", target);
872 var oldValue = e.prevValue;
873 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
874 if (!options.characterData) return;
875 if (options.characterDataOldValue) return getRecordWithOldValue(oldValue);
876 return record;
877 });
878 break;
879
880 case "DOMNodeRemoved":
881 this.addTransientObserver(e.target);
46 Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
47 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
48 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
49 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
50 Code distributed by Google as part of the polymer project is also
51 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
52 */
53 window.Promise||(window.Promise=u,u.prototype["catch"]=u.prototype.a,u.prototype.then=u.prototype.then,u.all=jb,u.race=kb,u.resolve=Sa,u.reject=lb);(function(a){function b(a,b){if("function"===typeof window.CustomEvent)return new CustomEvent(a,b);var c=document.createEvent("CustomEvent");c.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail);return c}function c(a){if(C)return a.ownerDocument!==document?a.ownerDocument:null;var b=a.__importDoc;if(!b&&a.parentNode){b=a.parentNode;if("function"===typeof b.closest)b=b.closest("link[rel=import]");else for(;!g(b)&&(b=b.parentNode););a.__importDoc=b}return b}function d(a){var b=m(document,"link[rel=import]:not([import-dependency])"),
54 c=b.length;c?n(b,function(b){return h(b,function(){0===--c&&a()})}):a()}function e(a){function b(){"loading"!==document.readyState&&document.body&&(document.removeEventListener("readystatechange",b),a())}document.addEventListener("readystatechange",b);b()}function f(a){e(function(){return d(function(){return a&&a()})})}function h(a,b){if(a.__loaded)b&&b();else if("script"===a.localName&&!a.src||"style"===a.localName&&!a.firstChild)a.__loaded=!0,b&&b();else{var c=function(d){a.removeEventListener(d.type,
55 c);a.__loaded=!0;b&&b()};a.addEventListener("load",c);oa&&"style"===a.localName||a.addEventListener("error",c)}}function g(a){return a.nodeType===Node.ELEMENT_NODE&&"link"===a.localName&&"import"===a.rel}function k(){var a=this;this.a={};this.b=0;this.c=new MutationObserver(function(b){return a.Va(b)});this.c.observe(document.head,{childList:!0,subtree:!0});this.loadImports(document)}function l(a){n(m(a,"template"),function(a){n(m(a.content,'script:not([type]),script[type="application/javascript"],script[type="text/javascript"],script[type="module"]'),
56 function(a){var b=document.createElement("script");n(a.attributes,function(a){return b.setAttribute(a.name,a.value)});b.textContent=a.textContent;a.parentNode.replaceChild(b,a)});l(a.content)})}function m(a,b){return a.childNodes.length?a.querySelectorAll(b):ba}function n(a,b,c){var d=a?a.length:0,e=c?-1:1;for(c=c?d-1:0;c<d&&0<=c;c+=e)b(a[c],c)}var t=document.createElement("link"),C="import"in t,ba=t.querySelectorAll("*"),ya=null;!1==="currentScript"in document&&Object.defineProperty(document,"currentScript",
57 {get:function(){return ya||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null)},configurable:!0});var qb=/(url\()([^)]*)(\))/g,rb=/(@import[\s]+(?!url\())([^;]*)(;)/g,V=/(<link[^>]*)(rel=['|"]?stylesheet['|"]?[^>]*>)/g,D={Pa:function(a,b){a.href&&a.setAttribute("href",D.ba(a.getAttribute("href"),b));a.src&&a.setAttribute("src",D.ba(a.getAttribute("src"),b));if("style"===a.localName){var c=D.za(a.textContent,b,qb);a.textContent=D.za(c,b,rb)}},za:function(a,b,c){return a.replace(c,
58 function(a,c,d,e){a=d.replace(/["']/g,"");b&&(a=D.ba(a,b));return c+"'"+a+"'"+e})},ba:function(a,b){if(void 0===D.ha){D.ha=!1;try{var c=new URL("b","http://a");c.pathname="c%20d";D.ha="http://a/c%20d"===c.href}catch(Kc){}}if(D.ha)return(new URL(a,b)).href;c=D.Ha;c||(c=document.implementation.createHTMLDocument("temp"),D.Ha=c,c.ra=c.createElement("base"),c.head.appendChild(c.ra),c.qa=c.createElement("a"));c.ra.href=b;c.qa.href=a;return c.qa.href||a}},ca={async:!0,load:function(a,b,c){if(a)if(a.match(/^data:/)){a=
59 a.split(",");var d=a[1];d=-1<a[0].indexOf(";base64")?atob(d):decodeURIComponent(d);b(d)}else{var e=new XMLHttpRequest;e.open("GET",a,ca.async);e.onload=function(){var a=e.responseURL||e.getResponseHeader("Location");a&&0===a.indexOf("/")&&(a=(location.origin||location.protocol+"//"+location.host)+a);var d=e.response||e.responseText;304===e.status||0===e.status||200<=e.status&&300>e.status?b(d,a):c(d)};e.send()}else c("error: href must be specified")}},oa=/Trident/.test(navigator.userAgent)||/Edge\/\d./i.test(navigator.userAgent);
60 k.prototype.loadImports=function(a){var b=this;a=m(a,"link[rel=import]");n(a,function(a){return b.o(a)})};k.prototype.o=function(a){var b=this,c=a.href;if(void 0!==this.a[c]){var d=this.a[c];d&&d.__loaded&&(a.__import=d,this.i(a))}else this.b++,this.a[c]="pending",ca.load(c,function(a,d){a=b.Wa(a,d||c);b.a[c]=a;b.b--;b.loadImports(a);b.J()},function(){b.a[c]=null;b.b--;b.J()})};k.prototype.Wa=function(a,b){if(!a)return document.createDocumentFragment();oa&&(a=a.replace(V,function(a,b,c){return-1===
61 a.indexOf("type=")?b+" type=import-disable "+c:a}));var c=document.createElement("template");c.innerHTML=a;if(c.content)a=c.content,l(a);else for(a=document.createDocumentFragment();c.firstChild;)a.appendChild(c.firstChild);if(c=a.querySelector("base"))b=D.ba(c.getAttribute("href"),b),c.removeAttribute("href");c=m(a,'link[rel=import],link[rel=stylesheet][href][type=import-disable],style:not([type]),link[rel=stylesheet][href]:not([type]),script:not([type]),script[type="application/javascript"],script[type="text/javascript"],script[type="module"]');
62 var d=0;n(c,function(a){h(a);D.Pa(a,b);a.setAttribute("import-dependency","");if("script"===a.localName&&!a.src&&a.textContent){if("module"===a.type)throw Error("Inline module scripts are not supported in HTML Imports.");a.setAttribute("src","data:text/javascript;charset=utf-8,"+encodeURIComponent(a.textContent+("\n//# sourceURL="+b+(d?"-"+d:"")+".js\n")));a.textContent="";d++}});return a};k.prototype.J=function(){var a=this;if(!this.b){this.c.disconnect();this.flatten(document);var b=!1,c=!1,d=function(){c&&
63 b&&(a.loadImports(document),a.b||(a.c.observe(document.head,{childList:!0,subtree:!0}),a.Ta()))};this.Ya(function(){c=!0;d()});this.Xa(function(){b=!0;d()})}};k.prototype.flatten=function(a){var b=this;a=m(a,"link[rel=import]");n(a,function(a){var c=b.a[a.href];(a.__import=c)&&c.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&(b.a[a.href]=a,a.readyState="loading",a.__import=a,b.flatten(c),a.appendChild(c))})};k.prototype.Xa=function(a){function b(e){if(e<d){var f=c[e],g=document.createElement("script");f.removeAttribute("import-dependency");
64 n(f.attributes,function(a){return g.setAttribute(a.name,a.value)});ya=g;f.parentNode.replaceChild(g,f);h(g,function(){ya=null;b(e+1)})}else a()}var c=m(document,"script[import-dependency]"),d=c.length;b(0)};k.prototype.Ya=function(a){var b=m(document,"style[import-dependency],link[rel=stylesheet][import-dependency]"),d=b.length;if(d){var e=oa&&!!document.querySelector("link[rel=stylesheet][href][type=import-disable]");n(b,function(b){h(b,function(){b.removeAttribute("import-dependency");0===--d&&
65 a()});if(e&&b.parentNode!==document.head){var f=document.createElement(b.localName);f.__appliedElement=b;f.setAttribute("type","import-placeholder");b.parentNode.insertBefore(f,b.nextSibling);for(f=c(b);f&&c(f);)f=c(f);f.parentNode!==document.head&&(f=null);document.head.insertBefore(b,f);b.removeAttribute("type")}})}else a()};k.prototype.Ta=function(){var a=this,b=m(document,"link[rel=import]");n(b,function(b){return a.i(b)},!0)};k.prototype.i=function(a){a.__loaded||(a.__loaded=!0,a.import&&(a.import.readyState=
66 "complete"),a.dispatchEvent(b(a.import?"load":"error",{bubbles:!1,cancelable:!1,detail:void 0})))};k.prototype.Va=function(a){var b=this;n(a,function(a){return n(a.addedNodes,function(a){a&&a.nodeType===Node.ELEMENT_NODE&&(g(a)?b.o(a):b.loadImports(a))})})};var za=null;if(C)t=m(document,"link[rel=import]"),n(t,function(a){a.import&&"loading"===a.import.readyState||(a.__loaded=!0)}),t=function(a){a=a.target;g(a)&&(a.__loaded=!0)},document.addEventListener("load",t,!0),document.addEventListener("error",
67 t,!0);else{var fa=Object.getOwnPropertyDescriptor(Node.prototype,"baseURI");Object.defineProperty((!fa||fa.configurable?Node:Element).prototype,"baseURI",{get:function(){var a=g(this)?this:c(this);return a?a.href:fa&&fa.get?fa.get.call(this):(document.querySelector("base")||window.location).href},configurable:!0,enumerable:!0});Object.defineProperty(HTMLLinkElement.prototype,"import",{get:function(){return this.__import||null},configurable:!0,enumerable:!0});e(function(){za=new k})}f(function(){return document.dispatchEvent(b("HTMLImportsLoaded",
68 {cancelable:!0,bubbles:!0,detail:void 0}))});a.useNative=C;a.whenReady=f;a.importForElement=c;a.loadImports=function(a){za&&za.loadImports(a)}})(window.HTMLImports=window.HTMLImports||{});/*
882 69
883 case "DOMNodeInserted":
884 var changedNode = e.target;
885 var addedNodes, removedNodes;
886 if (e.type === "DOMNodeInserted") {
887 addedNodes = [ changedNode ];
888 removedNodes = [];
889 } else {
890 addedNodes = [];
891 removedNodes = [ changedNode ];
892 }
893 var previousSibling = changedNode.previousSibling;
894 var nextSibling = changedNode.nextSibling;
895 var record = getRecord("childList", e.target.parentNode);
896 record.addedNodes = addedNodes;
897 record.removedNodes = removedNodes;
898 record.previousSibling = previousSibling;
899 record.nextSibling = nextSibling;
900 forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) {
901 if (!options.childList) return;
902 return record;
903 });
904 }
905 clearRecords();
906 }
907 };
908 global.JsMutationObserver = JsMutationObserver;
909 if (!global.MutationObserver) {
910 global.MutationObserver = JsMutationObserver;
911 JsMutationObserver._isPolyfilled = true;
912 }
913 })(self);
914
915 (function() {
916 var needsTemplate = typeof HTMLTemplateElement === "undefined";
917 if (/Trident/.test(navigator.userAgent)) {
918 (function() {
919 var importNode = document.importNode;
920 document.importNode = function() {
921 var n = importNode.apply(document, arguments);
922 if (n.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
923 var f = document.createDocumentFragment();
924 f.appendChild(n);
925 return f;
926 } else {
927 return n;
928 }
929 };
930 })();
931 }
932 var needsCloning = function() {
933 if (!needsTemplate) {
934 var t = document.createElement("template");
935 var t2 = document.createElement("template");
936 t2.content.appendChild(document.createElement("div"));
937 t.content.appendChild(t2);
938 var clone = t.cloneNode(true);
939 return clone.content.childNodes.length === 0 || clone.content.firstChild.content.childNodes.length === 0;
940 }
941 }();
942 var TEMPLATE_TAG = "template";
943 var TemplateImpl = function() {};
944 if (needsTemplate) {
945 var contentDoc = document.implementation.createHTMLDocument("template");
946 var canDecorate = true;
947 var templateStyle = document.createElement("style");
948 templateStyle.textContent = TEMPLATE_TAG + "{display:none;}";
949 var head = document.head;
950 head.insertBefore(templateStyle, head.firstElementChild);
951 TemplateImpl.prototype = Object.create(HTMLElement.prototype);
952 TemplateImpl.decorate = function(template) {
953 if (template.content) {
954 return;
955 }
956 template.content = contentDoc.createDocumentFragment();
957 var child;
958 while (child = template.firstChild) {
959 template.content.appendChild(child);
960 }
961 template.cloneNode = function(deep) {
962 return TemplateImpl.cloneNode(this, deep);
963 };
964 if (canDecorate) {
965 try {
966 Object.defineProperty(template, "innerHTML", {
967 get: function() {
968 var o = "";
969 for (var e = this.content.firstChild; e; e = e.nextSibling) {
970 o += e.outerHTML || escapeData(e.data);
971 }
972 return o;
973 },
974 set: function(text) {
975 contentDoc.body.innerHTML = text;
976 TemplateImpl.bootstrap(contentDoc);
977 while (this.content.firstChild) {
978 this.content.removeChild(this.content.firstChild);
979 }
980 while (contentDoc.body.firstChild) {
981 this.content.appendChild(contentDoc.body.firstChild);
982 }
983 },
984 configurable: true
985 });
986 } catch (err) {
987 canDecorate = false;
988 }
989 }
990 TemplateImpl.bootstrap(template.content);
991 };
992 TemplateImpl.bootstrap = function(doc) {
993 var templates = doc.querySelectorAll(TEMPLATE_TAG);
994 for (var i = 0, l = templates.length, t; i < l && (t = templates[i]); i++) {
995 TemplateImpl.decorate(t);
996 }
997 };
998 document.addEventListener("DOMContentLoaded", function() {
999 TemplateImpl.bootstrap(document);
1000 });
1001 var createElement = document.createElement;
1002 document.createElement = function() {
1003 "use strict";
1004 var el = createElement.apply(document, arguments);
1005 if (el.localName === "template") {
1006 TemplateImpl.decorate(el);
1007 }
1008 return el;
1009 };
1010 var escapeDataRegExp = /[&\u00A0<>]/g;
1011 function escapeReplace(c) {
1012 switch (c) {
1013 case "&":
1014 return "&amp;";
1015
1016 case "<":
1017 return "&lt;";
1018
1019 case ">":
1020 return "&gt;";
1021
1022 case " ":
1023 return "&nbsp;";
1024 }
1025 }
1026 function escapeData(s) {
1027 return s.replace(escapeDataRegExp, escapeReplace);
1028 }
1029 }
1030 if (needsTemplate || needsCloning) {
1031 var nativeCloneNode = Node.prototype.cloneNode;
1032 TemplateImpl.cloneNode = function(template, deep) {
1033 var clone = nativeCloneNode.call(template, false);
1034 if (this.decorate) {
1035 this.decorate(clone);
1036 }
1037 if (deep) {
1038 clone.content.appendChild(nativeCloneNode.call(template.content, true));
1039 this.fixClonedDom(clone.content, template.content);
1040 }
1041 return clone;
1042 };
1043 TemplateImpl.fixClonedDom = function(clone, source) {
1044 if (!source.querySelectorAll) return;
1045 var s$ = source.querySelectorAll(TEMPLATE_TAG);
1046 var t$ = clone.querySelectorAll(TEMPLATE_TAG);
1047 for (var i = 0, l = t$.length, t, s; i < l; i++) {
1048 s = s$[i];
1049 t = t$[i];
1050 if (this.decorate) {
1051 this.decorate(s);
1052 }
1053 t.parentNode.replaceChild(s.cloneNode(true), t);
1054 }
1055 };
1056 var originalImportNode = document.importNode;
1057 Node.prototype.cloneNode = function(deep) {
1058 var dom = nativeCloneNode.call(this, deep);
1059 if (deep) {
1060 TemplateImpl.fixClonedDom(dom, this);
1061 }
1062 return dom;
1063 };
1064 document.importNode = function(element, deep) {
1065 if (element.localName === TEMPLATE_TAG) {
1066 return TemplateImpl.cloneNode(element, deep);
1067 } else {
1068 var dom = originalImportNode.call(document, element, deep);
1069 if (deep) {
1070 TemplateImpl.fixClonedDom(dom, element);
1071 }
1072 return dom;
1073 }
1074 };
1075 if (needsCloning) {
1076 HTMLTemplateElement.prototype.cloneNode = function(deep) {
1077 return TemplateImpl.cloneNode(this, deep);
1078 };
1079 }
1080 }
1081 if (needsTemplate) {
1082 window.HTMLTemplateElement = TemplateImpl;
1083 }
1084 })();
1085
1086 (function(scope) {
1087 "use strict";
1088 if (!window.performance) {
1089 var start = Date.now();
1090 window.performance = {
1091 now: function() {
1092 return Date.now() - start;
1093 }
1094 };
1095 }
1096 if (!window.requestAnimationFrame) {
1097 window.requestAnimationFrame = function() {
1098 var nativeRaf = window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
1099 return nativeRaf ? function(callback) {
1100 return nativeRaf(function() {
1101 callback(performance.now());
1102 });
1103 } : function(callback) {
1104 return window.setTimeout(callback, 1e3 / 60);
1105 };
1106 }();
1107 }
1108 if (!window.cancelAnimationFrame) {
1109 window.cancelAnimationFrame = function() {
1110 return window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || function(id) {
1111 clearTimeout(id);
1112 };
1113 }();
1114 }
1115 var workingDefaultPrevented = function() {
1116 var e = document.createEvent("Event");
1117 e.initEvent("foo", true, true);
1118 e.preventDefault();
1119 return e.defaultPrevented;
1120 }();
1121 if (!workingDefaultPrevented) {
1122 var origPreventDefault = Event.prototype.preventDefault;
1123 Event.prototype.preventDefault = function() {
1124 if (!this.cancelable) {
1125 return;
1126 }
1127 origPreventDefault.call(this);
1128 Object.defineProperty(this, "defaultPrevented", {
1129 get: function() {
1130 return true;
1131 },
1132 configurable: true
1133 });
1134 };
1135 }
1136 var isIE = /Trident/.test(navigator.userAgent);
1137 if (!window.CustomEvent || isIE && typeof window.CustomEvent !== "function") {
1138 window.CustomEvent = function(inType, params) {
1139 params = params || {};
1140 var e = document.createEvent("CustomEvent");
1141 e.initCustomEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable), params.detail);
1142 return e;
1143 };
1144 window.CustomEvent.prototype = window.Event.prototype;
1145 }
1146 if (!window.Event || isIE && typeof window.Event !== "function") {
1147 var origEvent = window.Event;
1148 window.Event = function(inType, params) {
1149 params = params || {};
1150 var e = document.createEvent("Event");
1151 e.initEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable));
1152 return e;
1153 };
1154 window.Event.prototype = origEvent.prototype;
1155 }
1156 })(window.WebComponents);
1157
1158 window.HTMLImports = window.HTMLImports || {
1159 flags: {}
1160 };
70 Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
71 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
72 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
73 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
74 Code distributed by Google as part of the polymer project is also
75 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
76 */
77 window.WebComponents=window.WebComponents||{flags:{}};var mb=document.querySelector('script[src*="webcomponents-lite.js"]'),nb=/wc-(.+)/,v={};if(!v.noOpts){location.search.slice(1).split("&").forEach(function(a){a=a.split("=");var b;a[0]&&(b=a[0].match(nb))&&(v[b[1]]=a[1]||!0)});if(mb)for(var ob=0,pb;pb=mb.attributes[ob];ob++)"src"!==pb.name&&(v[pb.name]=pb.value||!0);if(v.log&&v.log.split){var ub=v.log.split(",");v.log={};ub.forEach(function(a){v.log[a]=!0})}else v.log={}}
78 window.WebComponents.flags=v;var vb=v.shadydom;vb&&(window.ShadyDOM=window.ShadyDOM||{},window.ShadyDOM.force=vb);var wb=v.register||v.ce;wb&&window.customElements&&(window.customElements.forcePolyfill=wb);/*
1161 79
1162 (function(scope) {
1163 var IMPORT_LINK_TYPE = "import";
1164 var useNative = Boolean(IMPORT_LINK_TYPE in document.createElement("link"));
1165 var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);
1166 var wrap = function(node) {
1167 return hasShadowDOMPolyfill ? window.ShadowDOMPolyfill.wrapIfNeeded(node) : node;
1168 };
1169 var rootDocument = wrap(document);
1170 var currentScriptDescriptor = {
1171 get: function() {
1172 var script = window.HTMLImports.currentScript || document.currentScript || (document.readyState !== "complete" ? document.scripts[document.scripts.length - 1] : null);
1173 return wrap(script);
1174 },
1175 configurable: true
1176 };
1177 Object.defineProperty(document, "_currentScript", currentScriptDescriptor);
1178 Object.defineProperty(rootDocument, "_currentScript", currentScriptDescriptor);
1179 var isIE = /Trident/.test(navigator.userAgent);
1180 function whenReady(callback, doc) {
1181 doc = doc || rootDocument;
1182 whenDocumentReady(function() {
1183 watchImportsLoad(callback, doc);
1184 }, doc);
1185 }
1186 var requiredReadyState = isIE ? "complete" : "interactive";
1187 var READY_EVENT = "readystatechange";
1188 function isDocumentReady(doc) {
1189 return doc.readyState === "complete" || doc.readyState === requiredReadyState;
1190 }
1191 function whenDocumentReady(callback, doc) {
1192 if (!isDocumentReady(doc)) {
1193 var checkReady = function() {
1194 if (doc.readyState === "complete" || doc.readyState === requiredReadyState) {
1195 doc.removeEventListener(READY_EVENT, checkReady);
1196 whenDocumentReady(callback, doc);
1197 }
1198 };
1199 doc.addEventListener(READY_EVENT, checkReady);
1200 } else if (callback) {
1201 callback();
1202 }
1203 }
1204 function markTargetLoaded(event) {
1205 event.target.__loaded = true;
1206 }
1207 function watchImportsLoad(callback, doc) {
1208 var imports = doc.querySelectorAll("link[rel=import]");
1209 var parsedCount = 0, importCount = imports.length, newImports = [], errorImports = [];
1210 function checkDone() {
1211 if (parsedCount == importCount && callback) {
1212 callback({
1213 allImports: imports,
1214 loadedImports: newImports,
1215 errorImports: errorImports
1216 });
1217 }
1218 }
1219 function loadedImport(e) {
1220 markTargetLoaded(e);
1221 newImports.push(this);
1222 parsedCount++;
1223 checkDone();
1224 }
1225 function errorLoadingImport(e) {
1226 errorImports.push(this);
1227 parsedCount++;
1228 checkDone();
1229 }
1230 if (importCount) {
1231 for (var i = 0, imp; i < importCount && (imp = imports[i]); i++) {
1232 if (isImportLoaded(imp)) {
1233 newImports.push(this);
1234 parsedCount++;
1235 checkDone();
1236 } else {
1237 imp.addEventListener("load", loadedImport);
1238 imp.addEventListener("error", errorLoadingImport);
1239 }
1240 }
1241 } else {
1242 checkDone();
1243 }
1244 }
1245 function isImportLoaded(link) {
1246 return useNative ? link.__loaded || link.import && link.import.readyState !== "loading" : link.__importParsed;
1247 }
1248 if (useNative) {
1249 new MutationObserver(function(mxns) {
1250 for (var i = 0, l = mxns.length, m; i < l && (m = mxns[i]); i++) {
1251 if (m.addedNodes) {
1252 handleImports(m.addedNodes);
1253 }
1254 }
1255 }).observe(document.head, {
1256 childList: true
1257 });
1258 function handleImports(nodes) {
1259 for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) {
1260 if (isImport(n)) {
1261 handleImport(n);
1262 }
1263 }
1264 }
1265 function isImport(element) {
1266 return element.localName === "link" && element.rel === "import";
1267 }
1268 function handleImport(element) {
1269 var loaded = element.import;
1270 if (loaded) {
1271 markTargetLoaded({
1272 target: element
1273 });
1274 } else {
1275 element.addEventListener("load", markTargetLoaded);
1276 element.addEventListener("error", markTargetLoaded);
1277 }
1278 }
1279 (function() {
1280 if (document.readyState === "loading") {
1281 var imports = document.querySelectorAll("link[rel=import]");
1282 for (var i = 0, l = imports.length, imp; i < l && (imp = imports[i]); i++) {
1283 handleImport(imp);
1284 }
1285 }
1286 })();
1287 }
1288 whenReady(function(detail) {
1289 window.HTMLImports.ready = true;
1290 window.HTMLImports.readyTime = new Date().getTime();
1291 var evt = rootDocument.createEvent("CustomEvent");
1292 evt.initCustomEvent("HTMLImportsLoaded", true, true, detail);
1293 rootDocument.dispatchEvent(evt);
1294 });
1295 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
1296 scope.useNative = useNative;
1297 scope.rootDocument = rootDocument;
1298 scope.whenReady = whenReady;
1299 scope.isIE = isIE;
1300 })(window.HTMLImports);
1301
1302 (function(scope) {
1303 var modules = [];
1304 var addModule = function(module) {
1305 modules.push(module);
1306 };
1307 var initializeModules = function() {
1308 modules.forEach(function(module) {
1309 module(scope);
1310 });
1311 };
1312 scope.addModule = addModule;
1313 scope.initializeModules = initializeModules;
1314 })(window.HTMLImports);
1315
1316 window.HTMLImports.addModule(function(scope) {
1317 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
1318 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
1319 var path = {
1320 resolveUrlsInStyle: function(style, linkUrl) {
1321 var doc = style.ownerDocument;
1322 var resolver = doc.createElement("a");
1323 style.textContent = this.resolveUrlsInCssText(style.textContent, linkUrl, resolver);
1324 return style;
1325 },
1326 resolveUrlsInCssText: function(cssText, linkUrl, urlObj) {
1327 var r = this.replaceUrls(cssText, urlObj, linkUrl, CSS_URL_REGEXP);
1328 r = this.replaceUrls(r, urlObj, linkUrl, CSS_IMPORT_REGEXP);
1329 return r;
1330 },
1331 replaceUrls: function(text, urlObj, linkUrl, regexp) {
1332 return text.replace(regexp, function(m, pre, url, post) {
1333 var urlPath = url.replace(/["']/g, "");
1334 if (linkUrl) {
1335 urlPath = new URL(urlPath, linkUrl).href;
1336 }
1337 urlObj.href = urlPath;
1338 urlPath = urlObj.href;
1339 return pre + "'" + urlPath + "'" + post;
1340 });
1341 }
1342 };
1343 scope.path = path;
1344 });
1345
1346 window.HTMLImports.addModule(function(scope) {
1347 var xhr = {
1348 async: true,
1349 ok: function(request) {
1350 return request.status >= 200 && request.status < 300 || request.status === 304 || request.status === 0;
1351 },
1352 load: function(url, next, nextContext) {
1353 var request = new XMLHttpRequest();
1354 if (scope.flags.debug || scope.flags.bust) {
1355 url += "?" + Math.random();
1356 }
1357 request.open("GET", url, xhr.async);
1358 request.addEventListener("readystatechange", function(e) {
1359 if (request.readyState === 4) {
1360 var redirectedUrl = null;
1361 try {
1362 var locationHeader = request.getResponseHeader("Location");
1363 if (locationHeader) {
1364 redirectedUrl = locationHeader.substr(0, 1) === "/" ? location.origin + locationHeader : locationHeader;
1365 }
1366 } catch (e) {
1367 console.error(e.message);
1368 }
1369 next.call(nextContext, !xhr.ok(request) && request, request.response || request.responseText, redirectedUrl);
1370 }
1371 });
1372 request.send();
1373 return request;
1374 },
1375 loadDocument: function(url, next, nextContext) {
1376 this.load(url, next, nextContext).responseType = "document";
1377 }
1378 };
1379 scope.xhr = xhr;
1380 });
1381
1382 window.HTMLImports.addModule(function(scope) {
1383 var xhr = scope.xhr;
1384 var flags = scope.flags;
1385 var Loader = function(onLoad, onComplete) {
1386 this.cache = {};
1387 this.onload = onLoad;
1388 this.oncomplete = onComplete;
1389 this.inflight = 0;
1390 this.pending = {};
1391 };
1392 Loader.prototype = {
1393 addNodes: function(nodes) {
1394 this.inflight += nodes.length;
1395 for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) {
1396 this.require(n);
1397 }
1398 this.checkDone();
1399 },
1400 addNode: function(node) {
1401 this.inflight++;
1402 this.require(node);
1403 this.checkDone();
1404 },
1405 require: function(elt) {
1406 var url = elt.src || elt.href;
1407 elt.__nodeUrl = url;
1408 if (!this.dedupe(url, elt)) {
1409 this.fetch(url, elt);
1410 }
1411 },
1412 dedupe: function(url, elt) {
1413 if (this.pending[url]) {
1414 this.pending[url].push(elt);
1415 return true;
1416 }
1417 var resource;
1418 if (this.cache[url]) {
1419 this.onload(url, elt, this.cache[url]);
1420 this.tail();
1421 return true;
1422 }
1423 this.pending[url] = [ elt ];
1424 return false;
1425 },
1426 fetch: function(url, elt) {
1427 flags.load && console.log("fetch", url, elt);
1428 if (!url) {
1429 setTimeout(function() {
1430 this.receive(url, elt, {
1431 error: "href must be specified"
1432 }, null);
1433 }.bind(this), 0);
1434 } else if (url.match(/^data:/)) {
1435 var pieces = url.split(",");
1436 var header = pieces[0];
1437 var body = pieces[1];
1438 if (header.indexOf(";base64") > -1) {
1439 body = atob(body);
1440 } else {
1441 body = decodeURIComponent(body);
1442 }
1443 setTimeout(function() {
1444 this.receive(url, elt, null, body);
1445 }.bind(this), 0);
1446 } else {
1447 var receiveXhr = function(err, resource, redirectedUrl) {
1448 this.receive(url, elt, err, resource, redirectedUrl);
1449 }.bind(this);
1450 xhr.load(url, receiveXhr);
1451 }
1452 },
1453 receive: function(url, elt, err, resource, redirectedUrl) {
1454 this.cache[url] = resource;
1455 var $p = this.pending[url];
1456 for (var i = 0, l = $p.length, p; i < l && (p = $p[i]); i++) {
1457 this.onload(url, p, resource, err, redirectedUrl);
1458 this.tail();
1459 }
1460 this.pending[url] = null;
1461 },
1462 tail: function() {
1463 --this.inflight;
1464 this.checkDone();
1465 },
1466 checkDone: function() {
1467 if (!this.inflight) {
1468 this.oncomplete();
1469 }
1470 }
1471 };
1472 scope.Loader = Loader;
1473 });
1474
1475 window.HTMLImports.addModule(function(scope) {
1476 var Observer = function(addCallback) {
1477 this.addCallback = addCallback;
1478 this.mo = new MutationObserver(this.handler.bind(this));
1479 };
1480 Observer.prototype = {
1481 handler: function(mutations) {
1482 for (var i = 0, l = mutations.length, m; i < l && (m = mutations[i]); i++) {
1483 if (m.type === "childList" && m.addedNodes.length) {
1484 this.addedNodes(m.addedNodes);
1485 }
1486 }
1487 },
1488 addedNodes: function(nodes) {
1489 if (this.addCallback) {
1490 this.addCallback(nodes);
1491 }
1492 for (var i = 0, l = nodes.length, n, loading; i < l && (n = nodes[i]); i++) {
1493 if (n.children && n.children.length) {
1494 this.addedNodes(n.children);
1495 }
1496 }
1497 },
1498 observe: function(root) {
1499 this.mo.observe(root, {
1500 childList: true,
1501 subtree: true
1502 });
1503 }
1504 };
1505 scope.Observer = Observer;
1506 });
1507
1508 window.HTMLImports.addModule(function(scope) {
1509 var path = scope.path;
1510 var rootDocument = scope.rootDocument;
1511 var flags = scope.flags;
1512 var isIE = scope.isIE;
1513 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
1514 var IMPORT_SELECTOR = "link[rel=" + IMPORT_LINK_TYPE + "]";
1515 var importParser = {
1516 documentSelectors: IMPORT_SELECTOR,
1517 importsSelectors: [ IMPORT_SELECTOR, "link[rel=stylesheet]:not([type])", "style:not([type])", "script:not([type])", 'script[type="application/javascript"]', 'script[type="text/javascript"]' ].join(","),
1518 map: {
1519 link: "parseLink",
1520 script: "parseScript",
1521 style: "parseStyle"
1522 },
1523 dynamicElements: [],
1524 parseNext: function() {
1525 var next = this.nextToParse();
1526 if (next) {
1527 this.parse(next);
1528 }
1529 },
1530 parse: function(elt) {
1531 if (this.isParsed(elt)) {
1532 flags.parse && console.log("[%s] is already parsed", elt.localName);
1533 return;
1534 }
1535 var fn = this[this.map[elt.localName]];
1536 if (fn) {
1537 this.markParsing(elt);
1538 fn.call(this, elt);
1539 }
1540 },
1541 parseDynamic: function(elt, quiet) {
1542 this.dynamicElements.push(elt);
1543 if (!quiet) {
1544 this.parseNext();
1545 }
1546 },
1547 markParsing: function(elt) {
1548 flags.parse && console.log("parsing", elt);
1549 this.parsingElement = elt;
1550 },
1551 markParsingComplete: function(elt) {
1552 elt.__importParsed = true;
1553 this.markDynamicParsingComplete(elt);
1554 if (elt.__importElement) {
1555 elt.__importElement.__importParsed = true;
1556 this.markDynamicParsingComplete(elt.__importElement);
1557 }
1558 this.parsingElement = null;
1559 flags.parse && console.log("completed", elt);
1560 },
1561 markDynamicParsingComplete: function(elt) {
1562 var i = this.dynamicElements.indexOf(elt);
1563 if (i >= 0) {
1564 this.dynamicElements.splice(i, 1);
1565 }
1566 },
1567 parseImport: function(elt) {
1568 elt.import = elt.__doc;
1569 if (window.HTMLImports.__importsParsingHook) {
1570 window.HTMLImports.__importsParsingHook(elt);
1571 }
1572 if (elt.import) {
1573 elt.import.__importParsed = true;
1574 }
1575 this.markParsingComplete(elt);
1576 if (elt.__resource && !elt.__error) {
1577 elt.dispatchEvent(new CustomEvent("load", {
1578 bubbles: false
1579 }));
1580 } else {
1581 elt.dispatchEvent(new CustomEvent("error", {
1582 bubbles: false
1583 }));
1584 }
1585 if (elt.__pending) {
1586 var fn;
1587 while (elt.__pending.length) {
1588 fn = elt.__pending.shift();
1589 if (fn) {
1590 fn({
1591 target: elt
1592 });
1593 }
1594 }
1595 }
1596 this.parseNext();
1597 },
1598 parseLink: function(linkElt) {
1599 if (nodeIsImport(linkElt)) {
1600 this.parseImport(linkElt);
1601 } else {
1602 linkElt.href = linkElt.href;
1603 this.parseGeneric(linkElt);
1604 }
1605 },
1606 parseStyle: function(elt) {
1607 var src = elt;
1608 elt = cloneStyle(elt);
1609 src.__appliedElement = elt;
1610 elt.__importElement = src;
1611 this.parseGeneric(elt);
1612 },
1613 parseGeneric: function(elt) {
1614 this.trackElement(elt);
1615 this.addElementToDocument(elt);
1616 },
1617 rootImportForElement: function(elt) {
1618 var n = elt;
1619 while (n.ownerDocument.__importLink) {
1620 n = n.ownerDocument.__importLink;
1621 }
1622 return n;
1623 },
1624 addElementToDocument: function(elt) {
1625 var port = this.rootImportForElement(elt.__importElement || elt);
1626 port.parentNode.insertBefore(elt, port);
1627 },
1628 trackElement: function(elt, callback) {
1629 var self = this;
1630 var done = function(e) {
1631 elt.removeEventListener("load", done);
1632 elt.removeEventListener("error", done);
1633 if (callback) {
1634 callback(e);
1635 }
1636 self.markParsingComplete(elt);
1637 self.parseNext();
1638 };
1639 elt.addEventListener("load", done);
1640 elt.addEventListener("error", done);
1641 if (isIE && elt.localName === "style") {
1642 var fakeLoad = false;
1643 if (elt.textContent.indexOf("@import") == -1) {
1644 fakeLoad = true;
1645 } else if (elt.sheet) {
1646 fakeLoad = true;
1647 var csr = elt.sheet.cssRules;
1648 var len = csr ? csr.length : 0;
1649 for (var i = 0, r; i < len && (r = csr[i]); i++) {
1650 if (r.type === CSSRule.IMPORT_RULE) {
1651 fakeLoad = fakeLoad && Boolean(r.styleSheet);
1652 }
1653 }
1654 }
1655 if (fakeLoad) {
1656 setTimeout(function() {
1657 elt.dispatchEvent(new CustomEvent("load", {
1658 bubbles: false
1659 }));
1660 });
1661 }
1662 }
1663 },
1664 parseScript: function(scriptElt) {
1665 var script = document.createElement("script");
1666 script.__importElement = scriptElt;
1667 script.src = scriptElt.src ? scriptElt.src : generateScriptDataUrl(scriptElt);
1668 scope.currentScript = scriptElt;
1669 this.trackElement(script, function(e) {
1670 if (script.parentNode) {
1671 script.parentNode.removeChild(script);
1672 }
1673 scope.currentScript = null;
1674 });
1675 this.addElementToDocument(script);
1676 },
1677 nextToParse: function() {
1678 this._mayParse = [];
1679 return !this.parsingElement && (this.nextToParseInDoc(rootDocument) || this.nextToParseDynamic());
1680 },
1681 nextToParseInDoc: function(doc, link) {
1682 if (doc && this._mayParse.indexOf(doc) < 0) {
1683 this._mayParse.push(doc);
1684 var nodes = doc.querySelectorAll(this.parseSelectorsForNode(doc));
1685 for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) {
1686 if (!this.isParsed(n)) {
1687 if (this.hasResource(n)) {
1688 return nodeIsImport(n) ? this.nextToParseInDoc(n.__doc, n) : n;
1689 } else {
1690 return;
1691 }
1692 }
1693 }
1694 }
1695 return link;
1696 },
1697 nextToParseDynamic: function() {
1698 return this.dynamicElements[0];
1699 },
1700 parseSelectorsForNode: function(node) {
1701 var doc = node.ownerDocument || node;
1702 return doc === rootDocument ? this.documentSelectors : this.importsSelectors;
1703 },
1704 isParsed: function(node) {
1705 return node.__importParsed;
1706 },
1707 needsDynamicParsing: function(elt) {
1708 return this.dynamicElements.indexOf(elt) >= 0;
1709 },
1710 hasResource: function(node) {
1711 if (nodeIsImport(node) && node.__doc === undefined) {
1712 return false;
1713 }
1714 return true;
1715 }
1716 };
1717 function nodeIsImport(elt) {
1718 return elt.localName === "link" && elt.rel === IMPORT_LINK_TYPE;
1719 }
1720 function generateScriptDataUrl(script) {
1721 var scriptContent = generateScriptContent(script);
1722 return "data:text/javascript;charset=utf-8," + encodeURIComponent(scriptContent);
1723 }
1724 function generateScriptContent(script) {
1725 return script.textContent + generateSourceMapHint(script);
1726 }
1727 function generateSourceMapHint(script) {
1728 var owner = script.ownerDocument;
1729 owner.__importedScripts = owner.__importedScripts || 0;
1730 var moniker = script.ownerDocument.baseURI;
1731 var num = owner.__importedScripts ? "-" + owner.__importedScripts : "";
1732 owner.__importedScripts++;
1733 return "\n//# sourceURL=" + moniker + num + ".js\n";
1734 }
1735 function cloneStyle(style) {
1736 var clone = style.ownerDocument.createElement("style");
1737 clone.textContent = style.textContent;
1738 path.resolveUrlsInStyle(clone);
1739 return clone;
1740 }
1741 scope.parser = importParser;
1742 scope.IMPORT_SELECTOR = IMPORT_SELECTOR;
1743 });
80 Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
81 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
82 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
83 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
84 Code distributed by Google as part of the polymer project is also
85 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
86 */
87 function xb(){this.ya=this.root=null;this.Z=!1;this.D=this.U=this.la=this.assignedSlot=this.assignedNodes=this.K=null;this.childNodes=this.nextSibling=this.previousSibling=this.lastChild=this.firstChild=this.parentNode=this.N=void 0;this.Da=this.ta=!1;this.S={}}xb.prototype.toJSON=function(){return{}};function w(a){a.fa||(a.fa=new xb);return a.fa}function x(a){return a&&a.fa};var y=window.ShadyDOM||{};y.Ra=!(!Element.prototype.attachShadow||!Node.prototype.getRootNode);var yb=Object.getOwnPropertyDescriptor(Node.prototype,"firstChild");y.w=!!(yb&&yb.configurable&&yb.get);y.na=y.force||!y.Ra;var zb=navigator.userAgent.match("Trident"),Ab=navigator.userAgent.match("Edge");void 0===y.Ba&&(y.Ba=y.w&&(zb||Ab));function Bb(a){return(a=x(a))&&void 0!==a.firstChild}function z(a){return"ShadyRoot"===a.La}function Cb(a){a=a.getRootNode();if(z(a))return a}
88 var Db=Element.prototype,Eb=Db.matches||Db.matchesSelector||Db.mozMatchesSelector||Db.msMatchesSelector||Db.oMatchesSelector||Db.webkitMatchesSelector;function Fb(a,b){if(a&&b)for(var c=Object.getOwnPropertyNames(b),d=0,e;d<c.length&&(e=c[d]);d++){var f=Object.getOwnPropertyDescriptor(b,e);f&&Object.defineProperty(a,e,f)}}function Gb(a,b){for(var c=[],d=1;d<arguments.length;++d)c[d-1]=arguments[d];for(d=0;d<c.length;d++)Fb(a,c[d]);return a}function Hb(a,b){for(var c in b)a[c]=b[c]}
89 var Ib=document.createTextNode(""),Jb=0,Kb=[];(new MutationObserver(function(){for(;Kb.length;)try{Kb.shift()()}catch(a){throw Ib.textContent=Jb++,a;}})).observe(Ib,{characterData:!0});function Lb(a){Kb.push(a);Ib.textContent=Jb++}var Mb=!!document.contains;function Nb(a,b){for(;b;){if(b==a)return!0;b=b.parentNode}return!1}
90 function Ob(a){for(var b=a.length-1;0<=b;b--){var c=a[b],d=c.getAttribute("id")||c.getAttribute("name");d&&"length"!==d&&isNaN(d)&&(a[d]=c)}a.item=function(b){return a[b]};a.namedItem=function(b){if("length"!==b&&isNaN(b)&&a[b])return a[b];for(var c=ma(a),d=c.next();!d.done;d=c.next())if(d=d.value,(d.getAttribute("id")||d.getAttribute("name"))==b)return d;return null};return a};var Pb=[],Qb;function Rb(a){Qb||(Qb=!0,Lb(Sb));Pb.push(a)}function Sb(){Qb=!1;for(var a=!!Pb.length;Pb.length;)Pb.shift()();return a}Sb.list=Pb;function Tb(){this.a=!1;this.addedNodes=[];this.removedNodes=[];this.Y=new Set}function Ub(a){a.a||(a.a=!0,Lb(function(){Vb(a)}))}function Vb(a){if(a.a){a.a=!1;var b=a.takeRecords();b.length&&a.Y.forEach(function(a){a(b)})}}Tb.prototype.takeRecords=function(){if(this.addedNodes.length||this.removedNodes.length){var a=[{addedNodes:this.addedNodes,removedNodes:this.removedNodes}];this.addedNodes=[];this.removedNodes=[];return a}return[]};
91 function Wb(a,b){var c=w(a);c.K||(c.K=new Tb);c.K.Y.add(b);var d=c.K;return{Ia:b,H:d,Ma:a,takeRecords:function(){return d.takeRecords()}}}function Xb(a){var b=a&&a.H;b&&(b.Y.delete(a.Ia),b.Y.size||(w(a.Ma).K=null))}
92 function Yb(a,b){var c=b.getRootNode();return a.map(function(a){var b=c===a.target.getRootNode();if(b&&a.addedNodes){if(b=Array.from(a.addedNodes).filter(function(a){return c===a.getRootNode()}),b.length)return a=Object.create(a),Object.defineProperty(a,"addedNodes",{value:b,configurable:!0}),a}else if(b)return a}).filter(function(a){return a})};var A={},Zb=Element.prototype.insertBefore,$b=Element.prototype.replaceChild,ac=Element.prototype.removeChild,bc=Element.prototype.setAttribute,cc=Element.prototype.removeAttribute,dc=Element.prototype.cloneNode,ec=Document.prototype.importNode,fc=Element.prototype.addEventListener,gc=Element.prototype.removeEventListener,hc=Window.prototype.addEventListener,ic=Window.prototype.removeEventListener,jc=Element.prototype.dispatchEvent,kc=Node.prototype.contains||HTMLElement.prototype.contains,lc=Document.prototype.getElementById,
93 mc=Element.prototype.querySelector,nc=DocumentFragment.prototype.querySelector,oc=Document.prototype.querySelector,pc=Element.prototype.querySelectorAll,qc=DocumentFragment.prototype.querySelectorAll,rc=Document.prototype.querySelectorAll;A.appendChild=Element.prototype.appendChild;A.insertBefore=Zb;A.replaceChild=$b;A.removeChild=ac;A.setAttribute=bc;A.removeAttribute=cc;A.cloneNode=dc;A.importNode=ec;A.addEventListener=fc;A.removeEventListener=gc;A.fb=hc;A.gb=ic;A.dispatchEvent=jc;A.contains=kc;
94 A.getElementById=lc;A.pb=mc;A.sb=nc;A.nb=oc;A.querySelector=function(a){switch(this.nodeType){case Node.ELEMENT_NODE:return mc.call(this,a);case Node.DOCUMENT_NODE:return oc.call(this,a);default:return nc.call(this,a)}};A.qb=pc;A.tb=qc;A.ob=rc;A.querySelectorAll=function(a){switch(this.nodeType){case Node.ELEMENT_NODE:return pc.call(this,a);case Node.DOCUMENT_NODE:return rc.call(this,a);default:return qc.call(this,a)}};var sc=/[&\u00A0"]/g,tc=/[&\u00A0<>]/g;function uc(a){switch(a){case "&":return"&amp;";case "<":return"&lt;";case ">":return"&gt;";case '"':return"&quot;";case "\u00a0":return"&nbsp;"}}function vc(a){for(var b={},c=0;c<a.length;c++)b[a[c]]=!0;return b}var wc=vc("area base br col command embed hr img input keygen link meta param source track wbr".split(" ")),xc=vc("style script xmp iframe noembed noframes plaintext noscript".split(" "));
95 function yc(a,b){"template"===a.localName&&(a=a.content);for(var c="",d=b?b(a):a.childNodes,e=0,f=d.length,h;e<f&&(h=d[e]);e++){a:{var g=h;var k=a;var l=b;switch(g.nodeType){case Node.ELEMENT_NODE:for(var m=g.localName,n="<"+m,t=g.attributes,C=0;k=t[C];C++)n+=" "+k.name+'="'+k.value.replace(sc,uc)+'"';n+=">";g=wc[m]?n:n+yc(g,l)+"</"+m+">";break a;case Node.TEXT_NODE:g=g.data;g=k&&xc[k.localName]?g:g.replace(tc,uc);break a;case Node.COMMENT_NODE:g="\x3c!--"+g.data+"--\x3e";break a;default:throw window.console.error(g),
96 Error("not implemented");}}c+=g}return c};var B={},E=document.createTreeWalker(document,NodeFilter.SHOW_ALL,null,!1),F=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT,null,!1);function zc(a){var b=[];E.currentNode=a;for(a=E.firstChild();a;)b.push(a),a=E.nextSibling();return b}B.parentNode=function(a){E.currentNode=a;return E.parentNode()};B.firstChild=function(a){E.currentNode=a;return E.firstChild()};B.lastChild=function(a){E.currentNode=a;return E.lastChild()};B.previousSibling=function(a){E.currentNode=a;return E.previousSibling()};
97 B.nextSibling=function(a){E.currentNode=a;return E.nextSibling()};B.childNodes=zc;B.parentElement=function(a){F.currentNode=a;return F.parentNode()};B.firstElementChild=function(a){F.currentNode=a;return F.firstChild()};B.lastElementChild=function(a){F.currentNode=a;return F.lastChild()};B.previousElementSibling=function(a){F.currentNode=a;return F.previousSibling()};B.nextElementSibling=function(a){F.currentNode=a;return F.nextSibling()};
98 B.children=function(a){var b=[];F.currentNode=a;for(a=F.firstChild();a;)b.push(a),a=F.nextSibling();return Ob(b)};B.innerHTML=function(a){return yc(a,function(a){return zc(a)})};B.textContent=function(a){switch(a.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:a=document.createTreeWalker(a,NodeFilter.SHOW_TEXT,null,!1);for(var b="",c;c=a.nextNode();)b+=c.nodeValue;return b;default:return a.nodeValue}};var G={},Ac=y.w,Bc=[Node.prototype,Element.prototype,HTMLElement.prototype];function H(a){var b;a:{for(b=0;b<Bc.length;b++){var c=Bc[b];if(c.hasOwnProperty(a)){b=c;break a}}b=void 0}if(!b)throw Error("Could not find descriptor for "+a);return Object.getOwnPropertyDescriptor(b,a)}
99 var I=Ac?{parentNode:H("parentNode"),firstChild:H("firstChild"),lastChild:H("lastChild"),previousSibling:H("previousSibling"),nextSibling:H("nextSibling"),childNodes:H("childNodes"),parentElement:H("parentElement"),previousElementSibling:H("previousElementSibling"),nextElementSibling:H("nextElementSibling"),innerHTML:H("innerHTML"),textContent:H("textContent"),firstElementChild:H("firstElementChild"),lastElementChild:H("lastElementChild"),children:H("children")}:{},Cc=Ac?{firstElementChild:Object.getOwnPropertyDescriptor(DocumentFragment.prototype,
100 "firstElementChild"),lastElementChild:Object.getOwnPropertyDescriptor(DocumentFragment.prototype,"lastElementChild"),children:Object.getOwnPropertyDescriptor(DocumentFragment.prototype,"children")}:{},Dc=Ac?{firstElementChild:Object.getOwnPropertyDescriptor(Document.prototype,"firstElementChild"),lastElementChild:Object.getOwnPropertyDescriptor(Document.prototype,"lastElementChild"),children:Object.getOwnPropertyDescriptor(Document.prototype,"children")}:{};G.xa=I;G.rb=Cc;G.mb=Dc;G.parentNode=function(a){return I.parentNode.get.call(a)};
101 G.firstChild=function(a){return I.firstChild.get.call(a)};G.lastChild=function(a){return I.lastChild.get.call(a)};G.previousSibling=function(a){return I.previousSibling.get.call(a)};G.nextSibling=function(a){return I.nextSibling.get.call(a)};G.childNodes=function(a){return Array.prototype.slice.call(I.childNodes.get.call(a))};G.parentElement=function(a){return I.parentElement.get.call(a)};G.previousElementSibling=function(a){return I.previousElementSibling.get.call(a)};G.nextElementSibling=function(a){return I.nextElementSibling.get.call(a)};
102 G.innerHTML=function(a){return I.innerHTML.get.call(a)};G.textContent=function(a){return I.textContent.get.call(a)};G.children=function(a){switch(a.nodeType){case Node.DOCUMENT_FRAGMENT_NODE:return Cc.children.get.call(a);case Node.DOCUMENT_NODE:return Dc.children.get.call(a);default:return I.children.get.call(a)}};
103 G.firstElementChild=function(a){switch(a.nodeType){case Node.DOCUMENT_FRAGMENT_NODE:return Cc.firstElementChild.get.call(a);case Node.DOCUMENT_NODE:return Dc.firstElementChild.get.call(a);default:return I.firstElementChild.get.call(a)}};G.lastElementChild=function(a){switch(a.nodeType){case Node.DOCUMENT_FRAGMENT_NODE:return Cc.lastElementChild.get.call(a);case Node.DOCUMENT_NODE:return Dc.lastElementChild.get.call(a);default:return I.lastElementChild.get.call(a)}};var J=y.Ba?G:B;function Ec(a){for(;a.firstChild;)a.removeChild(a.firstChild)}
104 var Fc=y.w,Gc=document.implementation.createHTMLDocument("inert"),Hc=Object.getOwnPropertyDescriptor(Node.prototype,"isConnected"),Ic=Hc&&Hc.get,Jc=Object.getOwnPropertyDescriptor(Document.prototype,"activeElement"),Mc={parentElement:{get:function(){var a=x(this);(a=a&&a.parentNode)&&a.nodeType!==Node.ELEMENT_NODE&&(a=null);return void 0!==a?a:J.parentElement(this)},configurable:!0},parentNode:{get:function(){var a=x(this);a=a&&a.parentNode;return void 0!==a?a:J.parentNode(this)},configurable:!0},
105 nextSibling:{get:function(){var a=x(this);a=a&&a.nextSibling;return void 0!==a?a:J.nextSibling(this)},configurable:!0},previousSibling:{get:function(){var a=x(this);a=a&&a.previousSibling;return void 0!==a?a:J.previousSibling(this)},configurable:!0},nextElementSibling:{get:function(){var a=x(this);if(a&&void 0!==a.nextSibling){for(a=this.nextSibling;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}return J.nextElementSibling(this)},configurable:!0},previousElementSibling:{get:function(){var a=
106 x(this);if(a&&void 0!==a.previousSibling){for(a=this.previousSibling;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return J.previousElementSibling(this)},configurable:!0}},Nc={className:{get:function(){return this.getAttribute("class")||""},set:function(a){this.setAttribute("class",a)},configurable:!0}},Oc={childNodes:{get:function(){if(Bb(this)){var a=x(this);if(!a.childNodes){a.childNodes=[];for(var b=this.firstChild;b;b=b.nextSibling)a.childNodes.push(b)}var c=a.childNodes}else c=
107 J.childNodes(this);c.item=function(a){return c[a]};return c},configurable:!0},childElementCount:{get:function(){return this.children.length},configurable:!0},firstChild:{get:function(){var a=x(this);a=a&&a.firstChild;return void 0!==a?a:J.firstChild(this)},configurable:!0},lastChild:{get:function(){var a=x(this);a=a&&a.lastChild;return void 0!==a?a:J.lastChild(this)},configurable:!0},textContent:{get:function(){if(Bb(this)){for(var a=[],b=0,c=this.childNodes,d;d=c[b];b++)d.nodeType!==Node.COMMENT_NODE&&
108 a.push(d.textContent);return a.join("")}return J.textContent(this)},set:function(a){if("undefined"===typeof a||null===a)a="";switch(this.nodeType){case Node.ELEMENT_NODE:case Node.DOCUMENT_FRAGMENT_NODE:if(!Bb(this)&&Fc){var b=this.firstChild;(b!=this.lastChild||b&&b.nodeType!=Node.TEXT_NODE)&&Ec(this);G.xa.textContent.set.call(this,a)}else Ec(this),(0<a.length||this.nodeType===Node.ELEMENT_NODE)&&this.appendChild(document.createTextNode(a));break;default:this.nodeValue=a}},configurable:!0},firstElementChild:{get:function(){var a=
109 x(this);if(a&&void 0!==a.firstChild){for(a=this.firstChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}return J.firstElementChild(this)},configurable:!0},lastElementChild:{get:function(){var a=x(this);if(a&&void 0!==a.lastChild){for(a=this.lastChild;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}return J.lastElementChild(this)},configurable:!0},children:{get:function(){return Bb(this)?Ob(Array.prototype.filter.call(this.childNodes,function(a){return a.nodeType===Node.ELEMENT_NODE})):
110 J.children(this)},configurable:!0},innerHTML:{get:function(){return Bb(this)?yc("template"===this.localName?this.content:this):J.innerHTML(this)},set:function(a){var b="template"===this.localName?this.content:this;Ec(b);var c=this.localName||"div";c=this.namespaceURI&&this.namespaceURI!==Gc.namespaceURI?Gc.createElementNS(this.namespaceURI,c):Gc.createElement(c);Fc?G.xa.innerHTML.set.call(c,a):c.innerHTML=a;for(a="template"===this.localName?c.content:c;a.firstChild;)b.appendChild(a.firstChild)},configurable:!0}},
111 Pc={shadowRoot:{get:function(){var a=x(this);return a&&a.ya||null},configurable:!0}},Qc={activeElement:{get:function(){var a=Jc&&Jc.get?Jc.get.call(document):y.w?void 0:document.activeElement;if(a&&a.nodeType){var b=!!z(this);if(this===document||b&&this.host!==a&&A.contains.call(this.host,a)){for(b=Cb(a);b&&b!==this;)a=b.host,b=Cb(a);a=this===document?b?null:a:b===this?a:null}else a=null}else a=null;return a},set:function(){},configurable:!0}};
112 function K(a,b,c){for(var d in b){var e=Object.getOwnPropertyDescriptor(a,d);e&&e.configurable||!e&&c?Object.defineProperty(a,d,b[d]):c&&console.warn("Could not define",d,"on",a)}}function Rc(a){K(a,Mc);K(a,Nc);K(a,Oc);K(a,Qc)}
113 function Sc(){var a=Tc.prototype;a.__proto__=DocumentFragment.prototype;K(a,Mc,!0);K(a,Oc,!0);K(a,Qc,!0);Object.defineProperties(a,{nodeType:{value:Node.DOCUMENT_FRAGMENT_NODE,configurable:!0},nodeName:{value:"#document-fragment",configurable:!0},nodeValue:{value:null,configurable:!0}});["localName","namespaceURI","prefix"].forEach(function(b){Object.defineProperty(a,b,{value:void 0,configurable:!0})});["ownerDocument","baseURI","isConnected"].forEach(function(b){Object.defineProperty(a,b,{get:function(){return this.host[b]},
114 configurable:!0})})}var Uc=y.w?function(){}:function(a){var b=w(a);b.ta||(b.ta=!0,K(a,Mc,!0),K(a,Nc,!0))},Vc=y.w?function(){}:function(a){w(a).Da||(K(a,Oc,!0),K(a,Pc,!0))};var Wc=J.childNodes;function Xc(a,b,c){Uc(a);c=c||null;var d=w(a),e=w(b),f=c?w(c):null;d.previousSibling=c?f.previousSibling:b.lastChild;if(f=x(d.previousSibling))f.nextSibling=a;if(f=x(d.nextSibling=c))f.previousSibling=a;d.parentNode=b;c?c===e.firstChild&&(e.firstChild=a):(e.lastChild=a,e.firstChild||(e.firstChild=a));e.childNodes=null}
115 function Yc(a){var b=w(a);if(void 0===b.firstChild){b.childNodes=null;var c=Wc(a);b.firstChild=c[0]||null;b.lastChild=c[c.length-1]||null;Vc(a);for(b=0;b<c.length;b++){var d=c[b],e=w(d);e.parentNode=a;e.nextSibling=c[b+1]||null;e.previousSibling=c[b-1]||null;Uc(d)}}};var Zc=J.parentNode;
116 function $c(a,b,c){if(b===a)throw Error("Failed to execute 'appendChild' on 'Node': The new child element contains the parent.");if(c){var d=x(c);d=d&&d.parentNode;if(void 0!==d&&d!==a||void 0===d&&Zc(c)!==a)throw Error("Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.");}if(c===b)return b;b.parentNode&&ad(b.parentNode,b);var e,f;if(!b.__noInsertionPoint){if(f=e=Cb(a)){var h;"slot"===b.localName?h=[b]:b.querySelectorAll&&
117 (h=b.querySelectorAll("slot"));f=h&&h.length?h:void 0}f&&(h=e,d=f,h.a=h.a||[],h.g=h.g||[],h.j=h.j||{},h.a.push.apply(h.a,[].concat(d instanceof Array?d:na(ma(d)))))}("slot"===a.localName||f)&&(e=e||Cb(a))&&bd(e);if(Bb(a)){e=c;Vc(a);f=w(a);void 0!==f.firstChild&&(f.childNodes=null);if(b.nodeType===Node.DOCUMENT_FRAGMENT_NODE){f=b.childNodes;for(h=0;h<f.length;h++)Xc(f[h],a,e);e=w(b);f=void 0!==e.firstChild?null:void 0;e.firstChild=e.lastChild=f;e.childNodes=f}else Xc(b,a,e);e=x(a);if(cd(a)){bd(e.root);
118 var g=!0}else e.root&&(g=!0)}g||(g=z(a)?a.host:a,c?(c=dd(c),A.insertBefore.call(g,b,c)):A.appendChild.call(g,b));ed(a,b);return b}
119 function ad(a,b){if(b.parentNode!==a)throw Error("The node to be removed is not a child of this node: "+b);var c=Cb(b),d=x(a);if(Bb(a)){var e=w(b),f=w(a);b===f.firstChild&&(f.firstChild=e.nextSibling);b===f.lastChild&&(f.lastChild=e.previousSibling);var h=e.previousSibling,g=e.nextSibling;h&&(w(h).nextSibling=g);g&&(w(g).previousSibling=h);e.parentNode=e.previousSibling=e.nextSibling=void 0;void 0!==f.childNodes&&(f.childNodes=null);if(cd(a)){bd(d.root);var k=!0}}fd(b);if(c){(e=a&&"slot"===a.localName)&&
120 (k=!0);if(c.g){gd(c);f=c.j;for(ba in f)for(h=f[ba],g=0;g<h.length;g++){var l=h[g];if(Nb(b,l)){h.splice(g,1);var m=c.g.indexOf(l);0<=m&&c.g.splice(m,1);g--;m=x(l);if(l=m.D)for(var n=0;n<l.length;n++){var t=l[n],C=hd(t);C&&A.removeChild.call(C,t)}m.D=[];m.assignedNodes=[];m=!0}}var ba=m}else ba=void 0;(ba||e)&&bd(c)}k||(k=z(a)?a.host:a,(!d.root&&"slot"!==b.localName||k===Zc(b))&&A.removeChild.call(k,b));ed(a,null,b);return b}
121 function fd(a){var b=x(a);if(b&&void 0!==b.N){b=a.childNodes;for(var c=0,d=b.length,e;c<d&&(e=b[c]);c++)fd(e)}if(a=x(a))a.N=void 0}function dd(a){var b=a;a&&"slot"===a.localName&&(b=(b=(b=x(a))&&b.D)&&b.length?b[0]:dd(a.nextSibling));return b}function cd(a){return(a=(a=x(a))&&a.root)&&id(a)}
122 function jd(a,b){if("slot"===b)a=a.parentNode,cd(a)&&bd(x(a).root);else if("slot"===a.localName&&"name"===b&&(b=Cb(a))){if(b.g){gd(b);var c=a.Ga,d=kd(a);if(d!==c){c=b.j[c];var e=c.indexOf(a);0<=e&&c.splice(e,1);c=b.j[d]||(b.j[d]=[]);c.push(a);1<c.length&&(b.j[d]=ld(c))}}bd(b)}}function ed(a,b,c){if(a=(a=x(a))&&a.K)b&&a.addedNodes.push(b),c&&a.removedNodes.push(c),Ub(a)}
123 function md(a){if(a&&a.nodeType){var b=w(a),c=b.N;void 0===c&&(z(a)?(c=a,b.N=c):(c=(c=a.parentNode)?md(c):a,A.contains.call(document.documentElement,a)&&(b.N=c)));return c}}function nd(a,b,c){var d=[];od(a.childNodes,b,c,d);return d}function od(a,b,c,d){for(var e=0,f=a.length,h;e<f&&(h=a[e]);e++){var g;if(g=h.nodeType===Node.ELEMENT_NODE){g=h;var k=b,l=c,m=d,n=k(g);n&&m.push(g);l&&l(n)?g=n:(od(g.childNodes,k,l,m),g=void 0)}if(g)break}}var pd=null;
124 function qd(a,b,c){pd||(pd=window.ShadyCSS&&window.ShadyCSS.ScopingShim);pd&&"class"===b?pd.setElementClass(a,c):(A.setAttribute.call(a,b,c),jd(a,b))}function rd(a,b){if(a.ownerDocument!==document||"template"===a.localName)return A.importNode.call(document,a,b);var c=A.importNode.call(document,a,!1);if(b){a=a.childNodes;b=0;for(var d;b<a.length;b++)d=rd(a[b],!0),c.appendChild(d)}return c};var sd="__eventWrappers"+Date.now(),td=function(){var a=Object.getOwnPropertyDescriptor(Event.prototype,"composed");return a?function(b){return a.get.call(b)}:null}(),ud={blur:!0,focus:!0,focusin:!0,focusout:!0,click:!0,dblclick:!0,mousedown:!0,mouseenter:!0,mouseleave:!0,mousemove:!0,mouseout:!0,mouseover:!0,mouseup:!0,wheel:!0,beforeinput:!0,input:!0,keydown:!0,keyup:!0,compositionstart:!0,compositionupdate:!0,compositionend:!0,touchstart:!0,touchend:!0,touchmove:!0,touchcancel:!0,pointerover:!0,
125 pointerenter:!0,pointerdown:!0,pointermove:!0,pointerup:!0,pointercancel:!0,pointerout:!0,pointerleave:!0,gotpointercapture:!0,lostpointercapture:!0,dragstart:!0,drag:!0,dragenter:!0,dragleave:!0,dragover:!0,drop:!0,dragend:!0,DOMActivate:!0,DOMFocusIn:!0,DOMFocusOut:!0,keypress:!0},vd={DOMAttrModified:!0,DOMAttributeNameChanged:!0,DOMCharacterDataModified:!0,DOMElementNameChanged:!0,DOMNodeInserted:!0,DOMNodeInsertedIntoDocument:!0,DOMNodeRemoved:!0,DOMNodeRemovedFromDocument:!0,DOMSubtreeModified:!0};
126 function wd(a,b){var c=[],d=a;for(a=a===window?window:a.getRootNode();d;)c.push(d),d=d.assignedSlot?d.assignedSlot:d.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&d.host&&(b||d!==a)?d.host:d.parentNode;c[c.length-1]===document&&c.push(window);return c}function xd(a,b){if(!z)return a;a=wd(a,!0);for(var c=0,d,e,f,h;c<b.length;c++)if(d=b[c],f=d===window?window:d.getRootNode(),f!==e&&(h=a.indexOf(f),e=f),!z(f)||-1<h)return d}
127 var yd={get composed(){void 0===this.R&&(td?this.R=td(this):!1!==this.isTrusted&&(this.R=ud[this.type]));return this.R||!1},composedPath:function(){this.sa||(this.sa=wd(this.__target,this.composed));return this.sa},get target(){return xd(this.currentTarget||this.__previousCurrentTarget,this.composedPath())},get relatedTarget(){if(!this.ea)return null;this.ua||(this.ua=wd(this.ea,!0));return xd(this.currentTarget,this.ua)},stopPropagation:function(){Event.prototype.stopPropagation.call(this);this.da=
128 !0},stopImmediatePropagation:function(){Event.prototype.stopImmediatePropagation.call(this);this.da=this.Ca=!0}};function zd(a){function b(b,d){b=new a(b,d);b.R=d&&!!d.composed;return b}Hb(b,a);b.prototype=a.prototype;return b}var Ad={focus:!0,blur:!0};function Bd(a){return a.__target!==a.target||a.ea!==a.relatedTarget}function Cd(a,b,c){if(c=b.__handlers&&b.__handlers[a.type]&&b.__handlers[a.type][c])for(var d=0,e;(e=c[d])&&(!Bd(a)||a.target!==a.relatedTarget)&&(e.call(b,a),!a.Ca);d++);}
129 function Dd(a){var b=a.composedPath();Object.defineProperty(a,"currentTarget",{get:function(){return d},configurable:!0});for(var c=b.length-1;0<=c;c--){var d=b[c];Cd(a,d,"capture");if(a.da)return}Object.defineProperty(a,"eventPhase",{get:function(){return Event.AT_TARGET}});var e;for(c=0;c<b.length;c++){d=b[c];var f=x(d);f=f&&f.root;if(0===c||f&&f===e)if(Cd(a,d,"bubble"),d!==window&&(e=d.getRootNode()),a.da)break}}
130 function Ed(a,b,c,d,e,f){for(var h=0;h<a.length;h++){var g=a[h],k=g.type,l=g.capture,m=g.once,n=g.passive;if(b===g.node&&c===k&&d===l&&e===m&&f===n)return h}return-1}
131 function Fd(a,b,c){if(b){var d=typeof b;if("function"===d||"object"===d)if("object"!==d||b.handleEvent&&"function"===typeof b.handleEvent){var e=this instanceof Window?A.fb:A.addEventListener;if(vd[a])return e.call(this,a,b,c);if(c&&"object"===typeof c){var f=!!c.capture;var h=!!c.once;var g=!!c.passive}else f=!!c,g=h=!1;var k=c&&c.ga||this,l=b[sd];if(l){if(-1<Ed(l,k,a,f,h,g))return}else b[sd]=[];l=function(e){h&&this.removeEventListener(a,b,c);e.__target||Gd(e);if(k!==this){var f=Object.getOwnPropertyDescriptor(e,
132 "currentTarget");Object.defineProperty(e,"currentTarget",{get:function(){return k},configurable:!0})}e.__previousCurrentTarget=e.currentTarget;if(!z(k)||-1!=e.composedPath().indexOf(k))if(e.composed||-1<e.composedPath().indexOf(k))if(Bd(e)&&e.target===e.relatedTarget)e.eventPhase===Event.BUBBLING_PHASE&&e.stopImmediatePropagation();else if(e.eventPhase===Event.CAPTURING_PHASE||e.bubbles||e.target===k||k instanceof Window){var g="function"===d?b.call(k,e):b.handleEvent&&b.handleEvent(e);k!==this&&
133 (f?(Object.defineProperty(e,"currentTarget",f),f=null):delete e.currentTarget);return g}};b[sd].push({node:k,type:a,capture:f,once:h,passive:g,hb:l});Ad[a]?(this.__handlers=this.__handlers||{},this.__handlers[a]=this.__handlers[a]||{capture:[],bubble:[]},this.__handlers[a][f?"capture":"bubble"].push(l)):e.call(this,a,l,c)}}}
134 function Hd(a,b,c){if(b){var d=this instanceof Window?A.gb:A.removeEventListener;if(vd[a])return d.call(this,a,b,c);if(c&&"object"===typeof c){var e=!!c.capture;var f=!!c.once;var h=!!c.passive}else e=!!c,h=f=!1;var g=c&&c.ga||this,k=void 0;var l=null;try{l=b[sd]}catch(m){}l&&(f=Ed(l,g,a,e,f,h),-1<f&&(k=l.splice(f,1)[0].hb,l.length||(b[sd]=void 0)));d.call(this,a,k||b,c);k&&Ad[a]&&this.__handlers&&this.__handlers[a]&&(a=this.__handlers[a][e?"capture":"bubble"],k=a.indexOf(k),-1<k&&a.splice(k,1))}}
135 function Id(){for(var a in Ad)window.addEventListener(a,function(a){a.__target||(Gd(a),Dd(a))},!0)}function Gd(a){a.__target=a.target;a.ea=a.relatedTarget;if(y.w){var b=Object.getPrototypeOf(a);if(!b.hasOwnProperty("__patchProto")){var c=Object.create(b);c.jb=b;Fb(c,yd);b.__patchProto=c}a.__proto__=b.__patchProto}else Fb(a,yd)}var Jd=zd(window.Event),Kd=zd(window.CustomEvent),Ld=zd(window.MouseEvent);
136 function Md(){window.Event=Jd;window.CustomEvent=Kd;window.MouseEvent=Ld;Id();if(!td&&Object.getOwnPropertyDescriptor(Event.prototype,"isTrusted")){var a=function(){var a=new MouseEvent("click",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(a)};Element.prototype.click?Element.prototype.click=a:HTMLElement.prototype.click&&(HTMLElement.prototype.click=a)}};function Nd(a,b){return{index:a,O:[],X:b}}
137 function Od(a,b,c,d){var e=0,f=0,h=0,g=0,k=Math.min(b-e,d-f);if(0==e&&0==f)a:{for(h=0;h<k;h++)if(a[h]!==c[h])break a;h=k}if(b==a.length&&d==c.length){g=a.length;for(var l=c.length,m=0;m<k-h&&Pd(a[--g],c[--l]);)m++;g=m}e+=h;f+=h;b-=g;d-=g;if(0==b-e&&0==d-f)return[];if(e==b){for(b=Nd(e,0);f<d;)b.O.push(c[f++]);return[b]}if(f==d)return[Nd(e,b-e)];k=e;h=f;d=d-h+1;g=b-k+1;b=Array(d);for(l=0;l<d;l++)b[l]=Array(g),b[l][0]=l;for(l=0;l<g;l++)b[0][l]=l;for(l=1;l<d;l++)for(m=1;m<g;m++)if(a[k+m-1]===c[h+l-1])b[l][m]=
138 b[l-1][m-1];else{var n=b[l-1][m]+1,t=b[l][m-1]+1;b[l][m]=n<t?n:t}k=b.length-1;h=b[0].length-1;d=b[k][h];for(a=[];0<k||0<h;)0==k?(a.push(2),h--):0==h?(a.push(3),k--):(g=b[k-1][h-1],l=b[k-1][h],m=b[k][h-1],n=l<m?l<g?l:g:m<g?m:g,n==g?(g==d?a.push(0):(a.push(1),d=g),k--,h--):n==l?(a.push(3),k--,d=l):(a.push(2),h--,d=m));a.reverse();b=void 0;k=[];for(h=0;h<a.length;h++)switch(a[h]){case 0:b&&(k.push(b),b=void 0);e++;f++;break;case 1:b||(b=Nd(e,0));b.X++;e++;b.O.push(c[f]);f++;break;case 2:b||(b=Nd(e,0));
139 b.X++;e++;break;case 3:b||(b=Nd(e,0)),b.O.push(c[f]),f++}b&&k.push(b);return k}function Pd(a,b){return a===b};var hd=J.parentNode,Qd=J.childNodes,Rd={},Sd=y.deferConnectionCallbacks&&"loading"===document.readyState,Td;function Ud(a){var b=[];do b.unshift(a);while(a=a.parentNode);return b}
140 function Tc(a,b,c){if(a!==Rd)throw new TypeError("Illegal constructor");this.La="ShadyRoot";this.host=b;this.c=c&&c.mode;Yc(b);a=w(b);a.root=this;a.ya="closed"!==this.c?this:null;a=w(this);a.firstChild=a.lastChild=a.parentNode=a.nextSibling=a.previousSibling=null;a.childNodes=[];this.b=this.W=!1;this.a=this.j=this.g=null;bd(this)}function bd(a){a.W||(a.W=!0,Rb(function(){return Vd(a)}))}
141 function Vd(a){for(var b;a;){a.W&&(b=a);a:{var c=a;a=c.host.getRootNode();if(z(a))for(var d=c.host.childNodes,e=0;e<d.length;e++)if(c=d[e],"slot"==c.localName)break a;a=void 0}}b&&b._renderRoot()}
142 Tc.prototype._renderRoot=function(){var a=Sd;Sd=!0;this.W=!1;if(this.g){gd(this);for(var b=0,c;b<this.g.length;b++){c=this.g[b];var d=x(c),e=d.assignedNodes;d.assignedNodes=[];d.D=[];if(d.la=e)for(d=0;d<e.length;d++){var f=x(e[d]);f.U=f.assignedSlot;f.assignedSlot===c&&(f.assignedSlot=null)}}for(c=this.host.firstChild;c;c=c.nextSibling)Wd(this,c);for(b=0;b<this.g.length;b++){c=this.g[b];e=x(c);if(!e.assignedNodes.length)for(d=c.firstChild;d;d=d.nextSibling)Wd(this,d,c);(d=(d=x(c.parentNode))&&d.root)&&
143 id(d)&&d._renderRoot();Xd(this,e.D,e.assignedNodes);if(d=e.la){for(f=0;f<d.length;f++)x(d[f]).U=null;e.la=null;d.length>e.assignedNodes.length&&(e.Z=!0)}e.Z&&(e.Z=!1,Yd(this,c))}b=this.g;c=[];for(e=0;e<b.length;e++)d=b[e].parentNode,(f=x(d))&&f.root||!(0>c.indexOf(d))||c.push(d);for(b=0;b<c.length;b++){e=c[b];d=e===this?this.host:e;f=[];e=e.childNodes;for(var h=0;h<e.length;h++){var g=e[h];if("slot"==g.localName){g=x(g).D;for(var k=0;k<g.length;k++)f.push(g[k])}else f.push(g)}e=void 0;h=Qd(d);g=Od(f,
144 f.length,h,h.length);for(var l=k=0;k<g.length&&(e=g[k]);k++){for(var m=0,n;m<e.O.length&&(n=e.O[m]);m++)hd(n)===d&&A.removeChild.call(d,n),h.splice(e.index+l,1);l-=e.X}for(l=0;l<g.length&&(e=g[l]);l++)for(k=h[e.index],m=e.index;m<e.index+e.X;m++)n=f[m],A.insertBefore.call(d,n,k),h.splice(m,0,n)}}if(!this.b)for(n=this.host.childNodes,c=0,b=n.length;c<b;c++)e=n[c],d=x(e),hd(e)!==this.host||"slot"!==e.localName&&d.assignedSlot||A.removeChild.call(this.host,e);this.b=!0;Sd=a;Td&&Td()};
145 function Wd(a,b,c){var d=w(b),e=d.U;d.U=null;c||(c=(a=a.j[b.slot||"__catchall"])&&a[0]);c?(w(c).assignedNodes.push(b),d.assignedSlot=c):d.assignedSlot=void 0;e!==d.assignedSlot&&d.assignedSlot&&(w(d.assignedSlot).Z=!0)}function Xd(a,b,c){for(var d=0,e;d<c.length&&(e=c[d]);d++)if("slot"==e.localName){var f=x(e).assignedNodes;f&&f.length&&Xd(a,b,f)}else b.push(c[d])}function Yd(a,b){A.dispatchEvent.call(b,new Event("slotchange"));b=x(b);b.assignedSlot&&Yd(a,b.assignedSlot)}
146 function gd(a){if(a.a&&a.a.length){for(var b=a.a,c,d=0;d<b.length;d++){var e=b[d];Yc(e);Yc(e.parentNode);var f=kd(e);a.j[f]?(c=c||{},c[f]=!0,a.j[f].push(e)):a.j[f]=[e];a.g.push(e)}if(c)for(var h in c)a.j[h]=ld(a.j[h]);a.a=[]}}function kd(a){var b=a.name||a.getAttribute("name")||"__catchall";return a.Ga=b}function ld(a){return a.sort(function(a,c){a=Ud(a);for(var b=Ud(c),e=0;e<a.length;e++){c=a[e];var f=b[e];if(c!==f)return a=Array.from(c.parentNode.childNodes),a.indexOf(c)-a.indexOf(f)}})}
147 function id(a){gd(a);return!(!a.g||!a.g.length)}
148 if(window.customElements&&y.na){var Zd=new Map;Td=function(){var a=Array.from(Zd);Zd.clear();a=ma(a);for(var b=a.next();!b.done;b=a.next()){b=ma(b.value);var c=b.next().value;b.next().value?c.Ea():c.Fa()}};Sd&&document.addEventListener("readystatechange",function(){Sd=!1;Td()},{once:!0});var $d=function(a,b,c){var d=0,e="__isConnected"+d++;if(b||c)a.prototype.connectedCallback=a.prototype.Ea=function(){Sd?Zd.set(this,!0):this[e]||(this[e]=!0,b&&b.call(this))},a.prototype.disconnectedCallback=a.prototype.Fa=
149 function(){Sd?this.isConnected||Zd.set(this,!1):this[e]&&(this[e]=!1,c&&c.call(this))};return a},define=window.customElements.define;Object.defineProperty(window.CustomElementRegistry.prototype,"define",{value:function(a,b){var c=b.prototype.connectedCallback,d=b.prototype.disconnectedCallback;define.call(window.customElements,a,$d(b,c,d));b.prototype.connectedCallback=c;b.prototype.disconnectedCallback=d}})};function ae(a){var b=a.getRootNode();z(b)&&Vd(b);return(a=x(a))&&a.assignedSlot||null}
150 var be={addEventListener:Fd.bind(window),removeEventListener:Hd.bind(window)},ce={addEventListener:Fd,removeEventListener:Hd,appendChild:function(a){return $c(this,a)},insertBefore:function(a,b){return $c(this,a,b)},removeChild:function(a){return ad(this,a)},replaceChild:function(a,b){$c(this,a,b);ad(this,b);return a},cloneNode:function(a){if("template"==this.localName)var b=A.cloneNode.call(this,a);else if(b=A.cloneNode.call(this,!1),a&&b.nodeType!==Node.ATTRIBUTE_NODE){a=this.childNodes;for(var c=
151 0,d;c<a.length;c++)d=a[c].cloneNode(!0),b.appendChild(d)}return b},getRootNode:function(){return md(this)},contains:function(a){return Nb(this,a)},dispatchEvent:function(a){Sb();return A.dispatchEvent.call(this,a)}};
152 Object.defineProperties(ce,{isConnected:{get:function(){if(Ic&&Ic.call(this))return!0;if(this.nodeType==Node.DOCUMENT_FRAGMENT_NODE)return!1;var a=this.ownerDocument;if(Mb){if(A.contains.call(a,this))return!0}else if(a.documentElement&&A.contains.call(a.documentElement,this))return!0;for(a=this;a&&!(a instanceof Document);)a=a.parentNode||(z(a)?a.host:void 0);return!!(a&&a instanceof Document)},configurable:!0}});
153 var de={get assignedSlot(){return ae(this)}},ee={querySelector:function(a){return nd(this,function(b){return Eb.call(b,a)},function(a){return!!a})[0]||null},querySelectorAll:function(a,b){if(b){b=Array.prototype.slice.call(A.querySelectorAll.call(this,a));var c=this.getRootNode();return b.filter(function(a){return a.getRootNode()==c})}return nd(this,function(b){return Eb.call(b,a)})}},fe={assignedNodes:function(a){if("slot"===this.localName){var b=this.getRootNode();z(b)&&Vd(b);return(b=x(this))?
154 (a&&a.flatten?b.D:b.assignedNodes)||[]:[]}}},ge=Gb({setAttribute:function(a,b){qd(this,a,b)},removeAttribute:function(a){A.removeAttribute.call(this,a);jd(this,a)},attachShadow:function(a){if(!this)throw"Must provide a host.";if(!a)throw"Not enough arguments.";return new Tc(Rd,this,a)},get slot(){return this.getAttribute("slot")},set slot(a){qd(this,"slot",a)},get assignedSlot(){return ae(this)}},ee,fe);Object.defineProperties(ge,Pc);
155 var he=Gb({importNode:function(a,b){return rd(a,b)},getElementById:function(a){return nd(this,function(b){return b.id==a},function(a){return!!a})[0]||null}},ee);Object.defineProperties(he,{_activeElement:Qc.activeElement});
156 for(var ie=HTMLElement.prototype.blur,je={blur:function(){var a=x(this);(a=(a=a&&a.root)&&a.activeElement)?a.blur():ie.call(this)}},ke={},le=ma(Object.getOwnPropertyNames(Document.prototype)),me=le.next();!me.done;ke={u:ke.u},me=le.next())ke.u=me.value,"on"===ke.u.substring(0,2)&&Object.defineProperty(je,ke.u,{set:function(a){return function(b){var c=w(this),d=a.u.substring(2);c.S[a.u]&&this.removeEventListener(d,c.S[a.u]);this.addEventListener(d,b,{});c.S[a.u]=b}}(ke),get:function(a){return function(){var b=
157 x(this);return b&&b.S[a.u]}}(ke),configurable:!0});var ne={addEventListener:function(a,b,c){"object"!==typeof c&&(c={capture:!!c});c.ga=this;this.host.addEventListener(a,b,c)},removeEventListener:function(a,b,c){"object"!==typeof c&&(c={capture:!!c});c.ga=this;this.host.removeEventListener(a,b,c)},getElementById:function(a){return nd(this,function(b){return b.id==a},function(a){return!!a})[0]||null}};
158 function L(a,b){for(var c=Object.getOwnPropertyNames(b),d=0;d<c.length;d++){var e=c[d],f=Object.getOwnPropertyDescriptor(b,e);f.value?a[e]=f.value:Object.defineProperty(a,e,f)}};if(y.na){var ShadyDOM={inUse:y.na,patch:function(a){Vc(a);Uc(a);return a},isShadyRoot:z,enqueue:Rb,flush:Sb,settings:y,filterMutations:Yb,observeChildren:Wb,unobserveChildren:Xb,nativeMethods:A,nativeTree:J,deferConnectionCallbacks:y.deferConnectionCallbacks};window.ShadyDOM=ShadyDOM;Md();var oe=window.customElements&&window.customElements.nativeHTMLElement||HTMLElement;L(Tc.prototype,ne);L(window.Node.prototype,ce);L(window.Window.prototype,be);L(window.Text.prototype,de);L(window.DocumentFragment.prototype,
159 ee);L(window.Element.prototype,ge);L(window.Document.prototype,he);window.HTMLSlotElement&&L(window.HTMLSlotElement.prototype,fe);L(oe.prototype,je);y.w&&(Rc(window.Node.prototype),Rc(window.Text.prototype),Rc(window.DocumentFragment.prototype),Rc(window.Element.prototype),Rc(oe.prototype),Rc(window.Document.prototype),window.HTMLSlotElement&&Rc(window.HTMLSlotElement.prototype));Sc();window.ShadowRoot=Tc};var pe=new Set("annotation-xml color-profile font-face font-face-src font-face-uri font-face-format font-face-name missing-glyph".split(" "));function qe(a){var b=pe.has(a);a=/^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/.test(a);return!b&&a}function M(a){var b=a.isConnected;if(void 0!==b)return b;for(;a&&!(a.__CE_isImportDocument||a instanceof Document);)a=a.parentNode||(window.ShadowRoot&&a instanceof ShadowRoot?a.host:void 0);return!(!a||!(a.__CE_isImportDocument||a instanceof Document))}
160 function re(a,b){for(;b&&b!==a&&!b.nextSibling;)b=b.parentNode;return b&&b!==a?b.nextSibling:null}
161 function se(a,b,c){c=void 0===c?new Set:c;for(var d=a;d;){if(d.nodeType===Node.ELEMENT_NODE){var e=d;b(e);var f=e.localName;if("link"===f&&"import"===e.getAttribute("rel")){d=e.import;if(d instanceof Node&&!c.has(d))for(c.add(d),d=d.firstChild;d;d=d.nextSibling)se(d,b,c);d=re(a,e);continue}else if("template"===f){d=re(a,e);continue}if(e=e.__CE_shadowRoot)for(e=e.firstChild;e;e=e.nextSibling)se(e,b,c)}d=d.firstChild?d.firstChild:re(a,d)}}function N(a,b,c){a[b]=c};function te(){this.a=new Map;this.o=new Map;this.i=[];this.c=!1}function ue(a,b,c){a.a.set(b,c);a.o.set(c.constructor,c)}function ve(a,b){a.c=!0;a.i.push(b)}function we(a,b){a.c&&se(b,function(b){return a.b(b)})}te.prototype.b=function(a){if(this.c&&!a.__CE_patched){a.__CE_patched=!0;for(var b=0;b<this.i.length;b++)this.i[b](a)}};function O(a,b){var c=[];se(b,function(a){return c.push(a)});for(b=0;b<c.length;b++){var d=c[b];1===d.__CE_state?a.connectedCallback(d):xe(a,d)}}
162 function P(a,b){var c=[];se(b,function(a){return c.push(a)});for(b=0;b<c.length;b++){var d=c[b];1===d.__CE_state&&a.disconnectedCallback(d)}}
163 function Q(a,b,c){c=void 0===c?{}:c;var d=c.eb||new Set,e=c.ca||function(b){return xe(a,b)},f=[];se(b,function(b){if("link"===b.localName&&"import"===b.getAttribute("rel")){var c=b.import;c instanceof Node&&(c.__CE_isImportDocument=!0,c.__CE_hasRegistry=!0);c&&"complete"===c.readyState?c.__CE_documentLoadHandled=!0:b.addEventListener("load",function(){var c=b.import;if(!c.__CE_documentLoadHandled){c.__CE_documentLoadHandled=!0;var f=new Set(d);f.delete(c);Q(a,c,{eb:f,ca:e})}})}else f.push(b)},d);
164 if(a.c)for(b=0;b<f.length;b++)a.b(f[b]);for(b=0;b<f.length;b++)e(f[b])}
165 function xe(a,b){if(void 0===b.__CE_state){var c=b.ownerDocument;if(c.defaultView||c.__CE_isImportDocument&&c.__CE_hasRegistry)if(c=a.a.get(b.localName)){c.constructionStack.push(b);var d=c.constructor;try{try{if(new d!==b)throw Error("The custom element constructor did not produce the element being upgraded.");}finally{c.constructionStack.pop()}}catch(h){throw b.__CE_state=2,h;}b.__CE_state=1;b.__CE_definition=c;if(c.attributeChangedCallback)for(c=c.observedAttributes,d=0;d<c.length;d++){var e=c[d],
166 f=b.getAttribute(e);null!==f&&a.attributeChangedCallback(b,e,null,f,null)}M(b)&&a.connectedCallback(b)}}}te.prototype.connectedCallback=function(a){var b=a.__CE_definition;b.connectedCallback&&b.connectedCallback.call(a)};te.prototype.disconnectedCallback=function(a){var b=a.__CE_definition;b.disconnectedCallback&&b.disconnectedCallback.call(a)};
167 te.prototype.attributeChangedCallback=function(a,b,c,d,e){var f=a.__CE_definition;f.attributeChangedCallback&&-1<f.observedAttributes.indexOf(b)&&f.attributeChangedCallback.call(a,b,c,d,e)};function ye(a){var b=document;this.l=a;this.a=b;this.H=void 0;Q(this.l,this.a);"loading"===this.a.readyState&&(this.H=new MutationObserver(this.b.bind(this)),this.H.observe(this.a,{childList:!0,subtree:!0}))}function ze(a){a.H&&a.H.disconnect()}ye.prototype.b=function(a){var b=this.a.readyState;"interactive"!==b&&"complete"!==b||ze(this);for(b=0;b<a.length;b++)for(var c=a[b].addedNodes,d=0;d<c.length;d++)Q(this.l,c[d])};function Ae(){var a=this;this.b=this.a=void 0;this.c=new Promise(function(b){a.b=b;a.a&&b(a.a)})}Ae.prototype.resolve=function(a){if(this.a)throw Error("Already resolved.");this.a=a;this.b&&this.b(a)};function R(a){this.ia=!1;this.l=a;this.ma=new Map;this.ja=function(a){return a()};this.T=!1;this.ka=[];this.Ja=new ye(a)}p=R.prototype;
168 p.define=function(a,b){var c=this;if(!(b instanceof Function))throw new TypeError("Custom element constructors must be functions.");if(!qe(a))throw new SyntaxError("The element name '"+a+"' is not valid.");if(this.l.a.get(a))throw Error("A custom element with name '"+a+"' has already been defined.");if(this.ia)throw Error("A custom element is already being defined.");this.ia=!0;try{var d=function(a){var b=e[a];if(void 0!==b&&!(b instanceof Function))throw Error("The '"+a+"' callback must be a function.");
169 return b},e=b.prototype;if(!(e instanceof Object))throw new TypeError("The custom element constructor's prototype is not an object.");var f=d("connectedCallback");var h=d("disconnectedCallback");var g=d("adoptedCallback");var k=d("attributeChangedCallback");var l=b.observedAttributes||[]}catch(m){return}finally{this.ia=!1}b={localName:a,constructor:b,connectedCallback:f,disconnectedCallback:h,adoptedCallback:g,attributeChangedCallback:k,observedAttributes:l,constructionStack:[]};ue(this.l,a,b);this.ka.push(b);
170 this.T||(this.T=!0,this.ja(function(){return Be(c)}))};p.ca=function(a){Q(this.l,a)};
171 function Be(a){if(!1!==a.T){a.T=!1;for(var b=a.ka,c=[],d=new Map,e=0;e<b.length;e++)d.set(b[e].localName,[]);Q(a.l,document,{ca:function(b){if(void 0===b.__CE_state){var e=b.localName,f=d.get(e);f?f.push(b):a.l.a.get(e)&&c.push(b)}}});for(e=0;e<c.length;e++)xe(a.l,c[e]);for(;0<b.length;){var f=b.shift();e=f.localName;f=d.get(f.localName);for(var h=0;h<f.length;h++)xe(a.l,f[h]);(e=a.ma.get(e))&&e.resolve(void 0)}}}p.get=function(a){if(a=this.l.a.get(a))return a.constructor};
172 p.whenDefined=function(a){if(!qe(a))return Promise.reject(new SyntaxError("'"+a+"' is not a valid custom element name."));var b=this.ma.get(a);if(b)return b.c;b=new Ae;this.ma.set(a,b);this.l.a.get(a)&&!this.ka.some(function(b){return b.localName===a})&&b.resolve(void 0);return b.c};p.Za=function(a){ze(this.Ja);var b=this.ja;this.ja=function(c){return a(function(){return b(c)})}};window.CustomElementRegistry=R;R.prototype.define=R.prototype.define;R.prototype.upgrade=R.prototype.ca;
173 R.prototype.get=R.prototype.get;R.prototype.whenDefined=R.prototype.whenDefined;R.prototype.polyfillWrapFlushCallback=R.prototype.Za;var Ce=window.Document.prototype.createElement,De=window.Document.prototype.createElementNS,Ee=window.Document.prototype.importNode,Fe=window.Document.prototype.prepend,Ge=window.Document.prototype.append,He=window.DocumentFragment.prototype.prepend,Ie=window.DocumentFragment.prototype.append,Je=window.Node.prototype.cloneNode,Ke=window.Node.prototype.appendChild,Le=window.Node.prototype.insertBefore,Me=window.Node.prototype.removeChild,Ne=window.Node.prototype.replaceChild,Oe=Object.getOwnPropertyDescriptor(window.Node.prototype,
174 "textContent"),Pe=window.Element.prototype.attachShadow,Qe=Object.getOwnPropertyDescriptor(window.Element.prototype,"innerHTML"),Re=window.Element.prototype.getAttribute,Se=window.Element.prototype.setAttribute,Te=window.Element.prototype.removeAttribute,Ue=window.Element.prototype.getAttributeNS,Ve=window.Element.prototype.setAttributeNS,We=window.Element.prototype.removeAttributeNS,Xe=window.Element.prototype.insertAdjacentElement,Ye=window.Element.prototype.insertAdjacentHTML,Ze=window.Element.prototype.prepend,
175 $e=window.Element.prototype.append,af=window.Element.prototype.before,bf=window.Element.prototype.after,cf=window.Element.prototype.replaceWith,df=window.Element.prototype.remove,ef=window.HTMLElement,ff=Object.getOwnPropertyDescriptor(window.HTMLElement.prototype,"innerHTML"),gf=window.HTMLElement.prototype.insertAdjacentElement,hf=window.HTMLElement.prototype.insertAdjacentHTML;var jf=new function(){};function kf(){var a=lf;window.HTMLElement=function(){function b(){var b=this.constructor,d=a.o.get(b);if(!d)throw Error("The custom element being constructed was not registered with `customElements`.");var e=d.constructionStack;if(0===e.length)return e=Ce.call(document,d.localName),Object.setPrototypeOf(e,b.prototype),e.__CE_state=1,e.__CE_definition=d,a.b(e),e;d=e.length-1;var f=e[d];if(f===jf)throw Error("The HTMLElement constructor was either called reentrantly for this constructor or called multiple times.");
176 e[d]=jf;Object.setPrototypeOf(f,b.prototype);a.b(f);return f}b.prototype=ef.prototype;Object.defineProperty(b.prototype,"constructor",{writable:!0,configurable:!0,enumerable:!1,value:b});return b}()};function mf(a,b,c){function d(b){return function(c){for(var d=[],e=0;e<arguments.length;++e)d[e-0]=arguments[e];e=[];for(var f=[],l=0;l<d.length;l++){var m=d[l];m instanceof Element&&M(m)&&f.push(m);if(m instanceof DocumentFragment)for(m=m.firstChild;m;m=m.nextSibling)e.push(m);else e.push(m)}b.apply(this,d);for(d=0;d<f.length;d++)P(a,f[d]);if(M(this))for(d=0;d<e.length;d++)f=e[d],f instanceof Element&&O(a,f)}}void 0!==c.aa&&(b.prepend=d(c.aa));void 0!==c.append&&(b.append=d(c.append))};function nf(){var a=lf;N(Document.prototype,"createElement",function(b){if(this.__CE_hasRegistry){var c=a.a.get(b);if(c)return new c.constructor}b=Ce.call(this,b);a.b(b);return b});N(Document.prototype,"importNode",function(b,c){b=Ee.call(this,b,c);this.__CE_hasRegistry?Q(a,b):we(a,b);return b});N(Document.prototype,"createElementNS",function(b,c){if(this.__CE_hasRegistry&&(null===b||"http://www.w3.org/1999/xhtml"===b)){var d=a.a.get(c);if(d)return new d.constructor}b=De.call(this,b,c);a.b(b);return b});
177 mf(a,Document.prototype,{aa:Fe,append:Ge})};function of(){var a=lf;function b(b,d){Object.defineProperty(b,"textContent",{enumerable:d.enumerable,configurable:!0,get:d.get,set:function(b){if(this.nodeType===Node.TEXT_NODE)d.set.call(this,b);else{var c=void 0;if(this.firstChild){var e=this.childNodes,g=e.length;if(0<g&&M(this)){c=Array(g);for(var k=0;k<g;k++)c[k]=e[k]}}d.set.call(this,b);if(c)for(b=0;b<c.length;b++)P(a,c[b])}}})}N(Node.prototype,"insertBefore",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);
178 b=Le.call(this,b,d);if(M(this))for(d=0;d<c.length;d++)O(a,c[d]);return b}c=M(b);d=Le.call(this,b,d);c&&P(a,b);M(this)&&O(a,b);return d});N(Node.prototype,"appendChild",function(b){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=Ke.call(this,b);if(M(this))for(var e=0;e<c.length;e++)O(a,c[e]);return b}c=M(b);e=Ke.call(this,b);c&&P(a,b);M(this)&&O(a,b);return e});N(Node.prototype,"cloneNode",function(b){b=Je.call(this,b);this.ownerDocument.__CE_hasRegistry?Q(a,b):
179 we(a,b);return b});N(Node.prototype,"removeChild",function(b){var c=M(b),e=Me.call(this,b);c&&P(a,b);return e});N(Node.prototype,"replaceChild",function(b,d){if(b instanceof DocumentFragment){var c=Array.prototype.slice.apply(b.childNodes);b=Ne.call(this,b,d);if(M(this))for(P(a,d),d=0;d<c.length;d++)O(a,c[d]);return b}c=M(b);var f=Ne.call(this,b,d),h=M(this);h&&P(a,d);c&&P(a,b);h&&O(a,b);return f});Oe&&Oe.get?b(Node.prototype,Oe):ve(a,function(a){b(a,{enumerable:!0,configurable:!0,get:function(){for(var a=
180 [],b=0;b<this.childNodes.length;b++)a.push(this.childNodes[b].textContent);return a.join("")},set:function(a){for(;this.firstChild;)Me.call(this,this.firstChild);Ke.call(this,document.createTextNode(a))}})})};function pf(a){var b=Element.prototype;function c(b){return function(c){for(var d=[],e=0;e<arguments.length;++e)d[e-0]=arguments[e];e=[];for(var g=[],k=0;k<d.length;k++){var l=d[k];l instanceof Element&&M(l)&&g.push(l);if(l instanceof DocumentFragment)for(l=l.firstChild;l;l=l.nextSibling)e.push(l);else e.push(l)}b.apply(this,d);for(d=0;d<g.length;d++)P(a,g[d]);if(M(this))for(d=0;d<e.length;d++)g=e[d],g instanceof Element&&O(a,g)}}void 0!==af&&(b.before=c(af));void 0!==af&&(b.after=c(bf));void 0!==
181 cf&&N(b,"replaceWith",function(b){for(var c=[],d=0;d<arguments.length;++d)c[d-0]=arguments[d];d=[];for(var h=[],g=0;g<c.length;g++){var k=c[g];k instanceof Element&&M(k)&&h.push(k);if(k instanceof DocumentFragment)for(k=k.firstChild;k;k=k.nextSibling)d.push(k);else d.push(k)}g=M(this);cf.apply(this,c);for(c=0;c<h.length;c++)P(a,h[c]);if(g)for(P(a,this),c=0;c<d.length;c++)h=d[c],h instanceof Element&&O(a,h)});void 0!==df&&N(b,"remove",function(){var b=M(this);df.call(this);b&&P(a,this)})};function qf(){var a=lf;function b(b,c){Object.defineProperty(b,"innerHTML",{enumerable:c.enumerable,configurable:!0,get:c.get,set:function(b){var d=this,e=void 0;M(this)&&(e=[],se(this,function(a){a!==d&&e.push(a)}));c.set.call(this,b);if(e)for(var f=0;f<e.length;f++){var h=e[f];1===h.__CE_state&&a.disconnectedCallback(h)}this.ownerDocument.__CE_hasRegistry?Q(a,this):we(a,this);return b}})}function c(b,c){N(b,"insertAdjacentElement",function(b,d){var e=M(d);b=c.call(this,b,d);e&&P(a,d);M(b)&&O(a,
182 d);return b})}function d(b,c){function d(b,c){for(var d=[];b!==c;b=b.nextSibling)d.push(b);for(c=0;c<d.length;c++)Q(a,d[c])}N(b,"insertAdjacentHTML",function(a,b){a=a.toLowerCase();if("beforebegin"===a){var e=this.previousSibling;c.call(this,a,b);d(e||this.parentNode.firstChild,this)}else if("afterbegin"===a)e=this.firstChild,c.call(this,a,b),d(this.firstChild,e);else if("beforeend"===a)e=this.lastChild,c.call(this,a,b),d(e||this.firstChild,null);else if("afterend"===a)e=this.nextSibling,c.call(this,
183 a,b),d(this.nextSibling,e);else throw new SyntaxError("The value provided ("+String(a)+") is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'.");})}Pe&&N(Element.prototype,"attachShadow",function(a){return this.__CE_shadowRoot=a=Pe.call(this,a)});Qe&&Qe.get?b(Element.prototype,Qe):ff&&ff.get?b(HTMLElement.prototype,ff):ve(a,function(a){b(a,{enumerable:!0,configurable:!0,get:function(){return Je.call(this,!0).innerHTML},set:function(a){var b="template"===this.localName,c=b?this.content:
184 this,d=De.call(document,this.namespaceURI,this.localName);for(d.innerHTML=a;0<c.childNodes.length;)Me.call(c,c.childNodes[0]);for(a=b?d.content:d;0<a.childNodes.length;)Ke.call(c,a.childNodes[0])}})});N(Element.prototype,"setAttribute",function(b,c){if(1!==this.__CE_state)return Se.call(this,b,c);var d=Re.call(this,b);Se.call(this,b,c);c=Re.call(this,b);a.attributeChangedCallback(this,b,d,c,null)});N(Element.prototype,"setAttributeNS",function(b,c,d){if(1!==this.__CE_state)return Ve.call(this,b,c,
185 d);var e=Ue.call(this,b,c);Ve.call(this,b,c,d);d=Ue.call(this,b,c);a.attributeChangedCallback(this,c,e,d,b)});N(Element.prototype,"removeAttribute",function(b){if(1!==this.__CE_state)return Te.call(this,b);var c=Re.call(this,b);Te.call(this,b);null!==c&&a.attributeChangedCallback(this,b,c,null,null)});N(Element.prototype,"removeAttributeNS",function(b,c){if(1!==this.__CE_state)return We.call(this,b,c);var d=Ue.call(this,b,c);We.call(this,b,c);var e=Ue.call(this,b,c);d!==e&&a.attributeChangedCallback(this,
186 c,d,e,b)});gf?c(HTMLElement.prototype,gf):Xe?c(Element.prototype,Xe):console.warn("Custom Elements: `Element#insertAdjacentElement` was not patched.");hf?d(HTMLElement.prototype,hf):Ye?d(Element.prototype,Ye):console.warn("Custom Elements: `Element#insertAdjacentHTML` was not patched.");mf(a,Element.prototype,{aa:Ze,append:$e});pf(a)};var rf=window.customElements;if(!rf||rf.forcePolyfill||"function"!=typeof rf.define||"function"!=typeof rf.get){var lf=new te;kf();nf();mf(lf,DocumentFragment.prototype,{aa:He,append:Ie});of();qf();document.__CE_hasRegistry=!0;var customElements=new R(lf);Object.defineProperty(window,"customElements",{configurable:!0,enumerable:!0,value:customElements})};function xf(){this.end=this.start=0;this.rules=this.parent=this.previous=null;this.cssText=this.parsedCssText="";this.atRule=!1;this.type=0;this.parsedSelector=this.selector=this.keyframesName=""}
187 function yf(a){a=a.replace(zf,"").replace(Af,"");var b=Bf,c=a,d=new xf;d.start=0;d.end=c.length;for(var e=d,f=0,h=c.length;f<h;f++)if("{"===c[f]){e.rules||(e.rules=[]);var g=e,k=g.rules[g.rules.length-1]||null;e=new xf;e.start=f+1;e.parent=g;e.previous=k;g.rules.push(e)}else"}"===c[f]&&(e.end=f+1,e=e.parent||d);return b(d,a)}
188 function Bf(a,b){var c=b.substring(a.start,a.end-1);a.parsedCssText=a.cssText=c.trim();a.parent&&(c=b.substring(a.previous?a.previous.end:a.parent.start,a.start-1),c=Cf(c),c=c.replace(Df," "),c=c.substring(c.lastIndexOf(";")+1),c=a.parsedSelector=a.selector=c.trim(),a.atRule=0===c.indexOf("@"),a.atRule?0===c.indexOf("@media")?a.type=Ef:c.match(Ff)&&(a.type=Gf,a.keyframesName=a.selector.split(Df).pop()):a.type=0===c.indexOf("--")?Hf:If);if(c=a.rules)for(var d=0,e=c.length,f;d<e&&(f=c[d]);d++)Bf(f,
189 b);return a}function Cf(a){return a.replace(/\\([0-9a-f]{1,6})\s/gi,function(a,c){a=c;for(c=6-a.length;c--;)a="0"+a;return"\\"+a})}
190 function Jf(a,b,c){c=void 0===c?"":c;var d="";if(a.cssText||a.rules){var e=a.rules,f;if(f=e)f=e[0],f=!(f&&f.selector&&0===f.selector.indexOf("--"));if(f){f=0;for(var h=e.length,g;f<h&&(g=e[f]);f++)d=Jf(g,b,d)}else b?b=a.cssText:(b=a.cssText,b=b.replace(Kf,"").replace(Lf,""),b=b.replace(Mf,"").replace(Nf,"")),(d=b.trim())&&(d=" "+d+"\n")}d&&(a.selector&&(c+=a.selector+" {\n"),c+=d,a.selector&&(c+="}\n\n"));return c}
191 var If=1,Gf=7,Ef=4,Hf=1E3,zf=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,Af=/@import[^;]*;/gim,Kf=/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,Lf=/(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,Mf=/@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,Nf=/[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,Ff=/^@[^\s]*keyframes/,Df=/\s+/g;var S=!(window.ShadyDOM&&window.ShadyDOM.inUse),Of;function Pf(a){Of=a&&a.shimcssproperties?!1:S||!(navigator.userAgent.match(/AppleWebKit\/601|Edge\/15/)||!window.CSS||!CSS.supports||!CSS.supports("box-shadow","0 0 0 var(--foo)"))}window.ShadyCSS&&void 0!==window.ShadyCSS.nativeCss?Of=window.ShadyCSS.nativeCss:window.ShadyCSS?(Pf(window.ShadyCSS),window.ShadyCSS=void 0):Pf(window.WebComponents&&window.WebComponents.flags);var U=Of;var Qf=/(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gi,Rf=/(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,Sf=/(--[\w-]+)\s*([:,;)]|$)/gi,Tf=/(animation\s*:)|(animation-name\s*:)/,Uf=/@media\s(.*)/,Vf=/\{[^}]*\}/g;var Wf=new Set;function Xf(a,b){if(!a)return"";"string"===typeof a&&(a=yf(a));b&&Yf(a,b);return Jf(a,U)}function Zf(a){!a.__cssRules&&a.textContent&&(a.__cssRules=yf(a.textContent));return a.__cssRules||null}function $f(a){return!!a.parent&&a.parent.type===Gf}function Yf(a,b,c,d){if(a){var e=!1,f=a.type;if(d&&f===Ef){var h=a.selector.match(Uf);h&&(window.matchMedia(h[1]).matches||(e=!0))}f===If?b(a):c&&f===Gf?c(a):f===Hf&&(e=!0);if((a=a.rules)&&!e){e=0;f=a.length;for(var g;e<f&&(g=a[e]);e++)Yf(g,b,c,d)}}}
192 function ag(a,b,c,d){var e=document.createElement("style");b&&e.setAttribute("scope",b);e.textContent=a;bg(e,c,d);return e}var cg=null;function bg(a,b,c){b=b||document.head;b.insertBefore(a,c&&c.nextSibling||b.firstChild);cg?a.compareDocumentPosition(cg)===Node.DOCUMENT_POSITION_PRECEDING&&(cg=a):cg=a}
193 function dg(a,b){var c=a.indexOf("var(");if(-1===c)return b(a,"","","");a:{var d=0;var e=c+3;for(var f=a.length;e<f;e++)if("("===a[e])d++;else if(")"===a[e]&&0===--d)break a;e=-1}d=a.substring(c+4,e);c=a.substring(0,c);a=dg(a.substring(e+1),b);e=d.indexOf(",");return-1===e?b(c,d.trim(),"",a):b(c,d.substring(0,e).trim(),d.substring(e+1).trim(),a)}function eg(a,b){S?a.setAttribute("class",b):window.ShadyDOM.nativeMethods.setAttribute.call(a,"class",b)}
194 function fg(a){var b=a.localName,c="";b?-1<b.indexOf("-")||(c=b,b=a.getAttribute&&a.getAttribute("is")||""):(b=a.is,c=a.extends);return{is:b,P:c}};function gg(){}function hg(a,b){var c=W;a.__styleScoped?a.__styleScoped=null:ig(c,a,function(a){jg(a,b||"")})}function ig(a,b,c){b.nodeType===Node.ELEMENT_NODE&&c(b);if(b="template"===b.localName?(b.content||b.kb||b).childNodes:b.children||b.childNodes)for(var d=0;d<b.length;d++)ig(a,b[d],c)}
195 function jg(a,b,c){if(b)if(a.classList)c?(a.classList.remove("style-scope"),a.classList.remove(b)):(a.classList.add("style-scope"),a.classList.add(b));else if(a.getAttribute){var d=a.getAttribute(kg);c?d&&(b=d.replace("style-scope","").replace(b,""),eg(a,b)):eg(a,(d?d+" ":"")+"style-scope "+b)}}function lg(a,b,c){var d=W;a.__styleScoped?a.__styleScoped=null:ig(d,a,function(a){jg(a,b,!0);jg(a,c)})}function mg(a,b){var c=W;a.__styleScoped?a.__styleScoped=null:ig(c,a,function(a){jg(a,b||"",!0)})}
196 function ng(a,b,c){var d=W,e=a.__cssBuild;S||"shady"===e?b=Xf(b,c):(a=fg(a),b=og(d,b,a.is,a.P,c)+"\n\n");return b.trim()}function og(a,b,c,d,e){var f=pg(c,d);c=c?qg+c:"";return Xf(b,function(b){b.c||(b.selector=b.s=rg(a,b,a.b,c,f),b.c=!0);e&&e(b,c,f)})}function pg(a,b){return b?"[is="+a+"]":a}function rg(a,b,c,d,e){var f=b.selector.split(sg);if(!$f(b)){b=0;for(var h=f.length,g;b<h&&(g=f[b]);b++)f[b]=c.call(a,g,d,e)}return f.join(sg)}
197 function tg(a){return a.replace(ug,function(a,c,d){-1<d.indexOf("+")?d=d.replace(/\+/g,"___"):-1<d.indexOf("___")&&(d=d.replace(/___/g,"+"));return":"+c+"("+d+")"})}gg.prototype.b=function(a,b,c){var d=!1;a=a.trim();var e=ug.test(a);e&&(a=a.replace(ug,function(a,b,c){return":"+b+"("+c.replace(/\s/g,"")+")"}),a=tg(a));a=a.replace(vg,wg+" $1");a=a.replace(xg,function(a,e,g){d||(a=yg(g,e,b,c),d=d||a.stop,e=a.Oa,g=a.value);return e+g});e&&(a=tg(a));return a};
198 function yg(a,b,c,d){var e=a.indexOf(zg);0<=a.indexOf(wg)?a=Ag(a,d):0!==e&&(a=c?Bg(a,c):a);c=!1;0<=e&&(b="",c=!0);if(c){var f=!0;c&&(a=a.replace(Cg,function(a,b){return" > "+b}))}a=a.replace(Dg,function(a,b,c){return'[dir="'+c+'"] '+b+", "+b+'[dir="'+c+'"]'});return{value:a,Oa:b,stop:f}}function Bg(a,b){a=a.split(Eg);a[0]+=b;return a.join(Eg)}
199 function Ag(a,b){var c=a.match(Fg);return(c=c&&c[2].trim()||"")?c[0].match(Gg)?a.replace(Fg,function(a,c,f){return b+f}):c.split(Gg)[0]===b?c:Hg:a.replace(wg,b)}function Ig(a){a.selector===Jg&&(a.selector="html")}gg.prototype.c=function(a){return a.match(zg)?this.b(a,Kg):Bg(a.trim(),Kg)};ea.Object.defineProperties(gg.prototype,{a:{configurable:!0,enumerable:!0,get:function(){return"style-scope"}}});
200 var ug=/:(nth[-\w]+)\(([^)]+)\)/,Kg=":not(.style-scope)",sg=",",xg=/(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=[])+)/g,Gg=/[[.:#*]/,wg=":host",Jg=":root",zg="::slotted",vg=new RegExp("^("+zg+")"),Fg=/(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,Cg=/(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,Dg=/(.*):dir\((?:(ltr|rtl))\)/,qg=".",Eg=":",kg="class",Hg="should_not_match",W=new gg;function Lg(a,b,c,d){this.B=a||null;this.b=b||null;this.oa=c||[];this.L=null;this.P=d||"";this.a=this.v=this.G=null}function X(a){return a?a.__styleInfo:null}function Mg(a,b){return a.__styleInfo=b}Lg.prototype.c=function(){return this.B};Lg.prototype._getStyleRules=Lg.prototype.c;function Ng(a){var b=this.matches||this.matchesSelector||this.mozMatchesSelector||this.msMatchesSelector||this.oMatchesSelector||this.webkitMatchesSelector;return b&&b.call(this,a)}var Og=navigator.userAgent.match("Trident");function Pg(){}function Qg(a){var b={},c=[],d=0;Yf(a,function(a){Rg(a);a.index=d++;a=a.m.cssText;for(var c;c=Sf.exec(a);){var e=c[1];":"!==c[2]&&(b[e]=!0)}},function(a){c.push(a)});a.b=c;a=[];for(var e in b)a.push(e);return a}
201 function Rg(a){if(!a.m){var b={},c={};Sg(a,c)&&(b.A=c,a.rules=null);b.cssText=a.parsedCssText.replace(Vf,"").replace(Qf,"");a.m=b}}function Sg(a,b){var c=a.m;if(c){if(c.A)return Object.assign(b,c.A),!0}else{c=a.parsedCssText;for(var d;a=Qf.exec(c);){d=(a[2]||a[3]).trim();if("inherit"!==d||"unset"!==d)b[a[1].trim()]=d;d=!0}return d}}
202 function Tg(a,b,c){b&&(b=0<=b.indexOf(";")?Ug(a,b,c):dg(b,function(b,e,f,h){if(!e)return b+h;(e=Tg(a,c[e],c))&&"initial"!==e?"apply-shim-inherit"===e&&(e="inherit"):e=Tg(a,c[f]||f,c)||f;return b+(e||"")+h}));return b&&b.trim()||""}
203 function Ug(a,b,c){b=b.split(";");for(var d=0,e,f;d<b.length;d++)if(e=b[d]){Rf.lastIndex=0;if(f=Rf.exec(e))e=Tg(a,c[f[1]],c);else if(f=e.indexOf(":"),-1!==f){var h=e.substring(f);h=h.trim();h=Tg(a,h,c)||h;e=e.substring(0,f)+h}b[d]=e&&e.lastIndexOf(";")===e.length-1?e.slice(0,-1):e||""}return b.join(";")}
204 function Vg(a,b){var c={},d=[];Yf(a,function(a){a.m||Rg(a);var e=a.s||a.parsedSelector;b&&a.m.A&&e&&Ng.call(b,e)&&(Sg(a,c),a=a.index,e=parseInt(a/32,10),d[e]=(d[e]||0)|1<<a%32)},null,!0);return{A:c,key:d}}
205 function Wg(a,b,c,d){b.m||Rg(b);if(b.m.A){var e=fg(a);a=e.is;e=e.P;e=a?pg(a,e):"html";var f=b.parsedSelector,h=":host > *"===f||"html"===f,g=0===f.indexOf(":host")&&!h;"shady"===c&&(h=f===e+" > *."+e||-1!==f.indexOf("html"),g=!h&&0===f.indexOf(e));"shadow"===c&&(h=":host > *"===f||"html"===f,g=g&&!h);if(h||g)c=e,g&&(b.s||(b.s=rg(W,b,W.b,a?qg+a:"",e)),c=b.s||e),d({ab:c,Ua:g,ub:h})}}
206 function Xg(a,b){var c={},d={},e=b&&b.__cssBuild;Yf(b,function(b){Wg(a,b,e,function(e){Ng.call(a.lb||a,e.ab)&&(e.Ua?Sg(b,c):Sg(b,d))})},null,!0);return{$a:d,Sa:c}}
207 function Yg(a,b,c,d){var e=fg(b),f=pg(e.is,e.P),h=new RegExp("(?:^|[^.#[:])"+(b.extends?"\\"+f.slice(0,-1)+"\\]":f)+"($|[.:[\\s>+~])");e=X(b).B;var g=Zg(e,d);return ng(b,e,function(b){var e="";b.m||Rg(b);b.m.cssText&&(e=Ug(a,b.m.cssText,c));b.cssText=e;if(!S&&!$f(b)&&b.cssText){var k=e=b.cssText;null==b.wa&&(b.wa=Tf.test(e));if(b.wa)if(null==b.$){b.$=[];for(var n in g)k=g[n],k=k(e),e!==k&&(e=k,b.$.push(n))}else{for(n=0;n<b.$.length;++n)k=g[b.$[n]],e=k(e);k=e}b.cssText=k;b.s=b.s||b.selector;e="."+
208 d;n=b.s.split(",");k=0;for(var t=n.length,C;k<t&&(C=n[k]);k++)n[k]=C.match(h)?C.replace(f,e):e+" "+C;b.selector=n.join(",")}})}function Zg(a,b){a=a.b;var c={};if(!S&&a)for(var d=0,e=a[d];d<a.length;e=a[++d]){var f=e,h=b;f.i=new RegExp("\\b"+f.keyframesName+"(?!\\B|-)","g");f.a=f.keyframesName+"-"+h;f.s=f.s||f.selector;f.selector=f.s.replace(f.keyframesName,f.a);c[e.keyframesName]=$g(e)}return c}function $g(a){return function(b){return b.replace(a.i,a.a)}}
209 function ah(a,b){var c=bh,d=Zf(a);a.textContent=Xf(d,function(a){var d=a.cssText=a.parsedCssText;a.m&&a.m.cssText&&(d=d.replace(Kf,"").replace(Lf,""),a.cssText=Ug(c,d,b))})}ea.Object.defineProperties(Pg.prototype,{a:{configurable:!0,enumerable:!0,get:function(){return"x-scope"}}});var bh=new Pg;var ch={},dh=window.customElements;if(dh&&!S){var eh=dh.define;dh.define=function(a,b,c){var d=document.createComment(" Shady DOM styles for "+a+" "),e=document.head;e.insertBefore(d,(cg?cg.nextSibling:null)||e.firstChild);cg=d;ch[a]=d;eh.call(dh,a,b,c)}};function fh(){this.cache={}}fh.prototype.store=function(a,b,c,d){var e=this.cache[a]||[];e.push({A:b,styleElement:c,v:d});100<e.length&&e.shift();this.cache[a]=e};fh.prototype.fetch=function(a,b,c){if(a=this.cache[a])for(var d=a.length-1;0<=d;d--){var e=a[d],f;a:{for(f=0;f<c.length;f++){var h=c[f];if(e.A[h]!==b[h]){f=!1;break a}}f=!0}if(f)return e}};function gh(){}
210 function hh(a){for(var b=0;b<a.length;b++){var c=a[b];if(c.target!==document.documentElement&&c.target!==document.head)for(var d=0;d<c.addedNodes.length;d++){var e=c.addedNodes[d];if(e.nodeType===Node.ELEMENT_NODE){var f=e.getRootNode();var h=e;var g=[];h.classList?g=Array.from(h.classList):h instanceof window.SVGElement&&h.hasAttribute("class")&&(g=h.getAttribute("class").split(/\s+/));h=g;g=h.indexOf(W.a);if((h=-1<g?h[g+1]:"")&&f===e.ownerDocument)mg(e,h);else if(f.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&(f=
211 f.host))for(f=fg(f).is,f!==h&&lg(e,h,f),e=window.ShadyDOM.nativeMethods.querySelectorAll.call(e,":not(."+W.a+")"),f=0;f<e.length;f++)if(h=e[f],g=h.getRootNode().host)g=fg(g).is,jg(h,g)}}}}
212 if(!S){var ih=new MutationObserver(hh),jh=function(a){ih.observe(a,{childList:!0,subtree:!0})};if(window.customElements&&!window.customElements.polyfillWrapFlushCallback)jh(document);else{var kh=function(){jh(document.body)};window.HTMLImports?window.HTMLImports.whenReady(kh):requestAnimationFrame(function(){if("loading"===document.readyState){var a=function(){kh();document.removeEventListener("readystatechange",a)};document.addEventListener("readystatechange",a)}else kh()})}gh=function(){hh(ih.takeRecords())}}
213 var lh=gh;var mh={};var nh=Promise.resolve();function oh(a){if(a=mh[a])a._applyShimCurrentVersion=a._applyShimCurrentVersion||0,a._applyShimValidatingVersion=a._applyShimValidatingVersion||0,a._applyShimNextVersion=(a._applyShimNextVersion||0)+1}function ph(a){return a._applyShimCurrentVersion===a._applyShimNextVersion}function qh(a){a._applyShimValidatingVersion=a._applyShimNextVersion;a.b||(a.b=!0,nh.then(function(){a._applyShimCurrentVersion=a._applyShimNextVersion;a.b=!1}))};var rh=new fh;function Y(){this.J={};this.c=document.documentElement;var a=new xf;a.rules=[];this.i=Mg(this.c,new Lg(a));this.o=!1;this.b=this.a=null}p=Y.prototype;p.pa=function(){lh()};p.Qa=function(a){return Zf(a)};p.cb=function(a){return Xf(a)};p.prepareTemplate=function(a,b,c){this.prepareTemplateDom(a,b);this.prepareTemplateStyles(a,b,c)};
214 p.prepareTemplateStyles=function(a,b,c){if(!a.o){a.o=!0;a.name=b;a.extends=c;mh[b]=a;var d=(d=a.content.querySelector("style"))?d.getAttribute("css-build")||"":"";var e=[];for(var f=a.content.querySelectorAll("style"),h=0;h<f.length;h++){var g=f[h];if(g.hasAttribute("shady-unscoped")){if(!S){var k=g.textContent;Wf.has(k)||(Wf.add(k),k=g.cloneNode(!0),document.head.appendChild(k));g.parentNode.removeChild(g)}}else e.push(g.textContent),g.parentNode.removeChild(g)}e=e.join("").trim();c={is:b,extends:c,
215 ib:d};sh(this);f=Rf.test(e)||Qf.test(e);Rf.lastIndex=0;Qf.lastIndex=0;e=yf(e);f&&U&&this.a&&this.a.transformRules(e,b);a._styleAst=e;a.J=d;d=[];U||(d=Qg(a._styleAst));if(!d.length||U)e=S?a.content:null,b=ch[b],f=ng(c,a._styleAst),b=f.length?ag(f,c.is,e,b):void 0,a.a=b;a.i=d}};p.prepareTemplateDom=function(a,b){S||a.c||(a.c=!0,hg(a.content,b))};
216 function th(a){!a.b&&window.ShadyCSS&&window.ShadyCSS.CustomStyleInterface&&(a.b=window.ShadyCSS.CustomStyleInterface,a.b.transformCallback=function(b){a.Aa(b)},a.b.validateCallback=function(){requestAnimationFrame(function(){(a.b.enqueued||a.o)&&a.flushCustomStyles()})})}function sh(a){!a.a&&window.ShadyCSS&&window.ShadyCSS.ApplyShim&&(a.a=window.ShadyCSS.ApplyShim,a.a.invalidCallback=oh);th(a)}
217 p.flushCustomStyles=function(){sh(this);if(this.b){var a=this.b.processStyles();if(this.b.enqueued){if(U)for(var b=0;b<a.length;b++){var c=this.b.getStyleForCustomStyle(a[b]);if(c&&U&&this.a){var d=Zf(c);sh(this);this.a.transformRules(d);c.textContent=Xf(d)}}else for(uh(this,this.c,this.i),b=0;b<a.length;b++)(c=this.b.getStyleForCustomStyle(a[b]))&&ah(c,this.i.G);this.b.enqueued=!1;this.o&&!U&&this.styleDocument()}}};
218 p.styleElement=function(a,b){var c=fg(a).is,d=X(a);if(!d){var e=fg(a);d=e.is;e=e.P;var f=ch[d];d=mh[d];if(d){var h=d._styleAst;var g=d.i}d=Mg(a,new Lg(h,f,g,e))}a!==this.c&&(this.o=!0);b&&(d.L=d.L||{},Object.assign(d.L,b));if(U){if(d.L){b=d.L;for(var k in b)null===k?a.style.removeProperty(k):a.style.setProperty(k,b[k])}if(((k=mh[c])||a===this.c)&&k&&k.a&&!ph(k)){if(ph(k)||k._applyShimValidatingVersion!==k._applyShimNextVersion)sh(this),this.a&&this.a.transformRules(k._styleAst,c),k.a.textContent=
219 ng(a,d.B),qh(k);S&&(c=a.shadowRoot)&&(c.querySelector("style").textContent=ng(a,d.B));d.B=k._styleAst}}else if(this.pa(),uh(this,a,d),d.oa&&d.oa.length){c=d;k=fg(a).is;d=(b=rh.fetch(k,c.G,c.oa))?b.styleElement:null;h=c.v;(g=b&&b.v)||(g=this.J[k]=(this.J[k]||0)+1,g=k+"-"+g);c.v=g;g=c.v;e=bh;e=d?d.textContent||"":Yg(e,a,c.G,g);f=X(a);var l=f.a;l&&!S&&l!==d&&(l._useCount--,0>=l._useCount&&l.parentNode&&l.parentNode.removeChild(l));S?f.a?(f.a.textContent=e,d=f.a):e&&(d=ag(e,g,a.shadowRoot,f.b)):d?d.parentNode||
220 (Og&&-1<e.indexOf("@media")&&(d.textContent=e),bg(d,null,f.b)):e&&(d=ag(e,g,null,f.b));d&&(d._useCount=d._useCount||0,f.a!=d&&d._useCount++,f.a=d);g=d;S||(d=c.v,f=e=a.getAttribute("class")||"",h&&(f=e.replace(new RegExp("\\s*x-scope\\s*"+h+"\\s*","g")," ")),f+=(f?" ":"")+"x-scope "+d,e!==f&&eg(a,f));b||rh.store(k,c.G,g,c.v)}};function vh(a,b){return(b=b.getRootNode().host)?X(b)?b:vh(a,b):a.c}
221 function uh(a,b,c){a=vh(a,b);var d=X(a);a=Object.create(d.G||null);var e=Xg(b,c.B);b=Vg(d.B,b).A;Object.assign(a,e.Sa,b,e.$a);b=c.L;for(var f in b)if((e=b[f])||0===e)a[f]=e;f=bh;b=Object.getOwnPropertyNames(a);for(e=0;e<b.length;e++)d=b[e],a[d]=Tg(f,a[d],a);c.G=a}p.styleDocument=function(a){this.styleSubtree(this.c,a)};
222 p.styleSubtree=function(a,b){var c=a.shadowRoot;(c||a===this.c)&&this.styleElement(a,b);if(b=c&&(c.children||c.childNodes))for(a=0;a<b.length;a++)this.styleSubtree(b[a]);else if(a=a.children||a.childNodes)for(b=0;b<a.length;b++)this.styleSubtree(a[b])};p.Aa=function(a){var b=this,c=Zf(a);Yf(c,function(a){if(S)Ig(a);else{var c=W;a.selector=a.parsedSelector;Ig(a);a.selector=a.s=rg(c,a,c.c,void 0,void 0)}U&&(sh(b),b.a&&b.a.transformRule(a))});U?a.textContent=Xf(c):this.i.B.rules.push(c)};
223 p.getComputedStyleValue=function(a,b){var c;U||(c=(X(a)||X(vh(this,a))).G[b]);return(c=c||window.getComputedStyle(a).getPropertyValue(b))?c.trim():""};p.bb=function(a,b){var c=a.getRootNode();b=b?b.split(/\s/):[];c=c.host&&c.host.localName;if(!c){var d=a.getAttribute("class");if(d){d=d.split(/\s/);for(var e=0;e<d.length;e++)if(d[e]===W.a){c=d[e+1];break}}}c&&b.push(W.a,c);U||(c=X(a))&&c.v&&b.push(bh.a,c.v);eg(a,b.join(" "))};p.Na=function(a){return X(a)};Y.prototype.flush=Y.prototype.pa;
224 Y.prototype.prepareTemplate=Y.prototype.prepareTemplate;Y.prototype.styleElement=Y.prototype.styleElement;Y.prototype.styleDocument=Y.prototype.styleDocument;Y.prototype.styleSubtree=Y.prototype.styleSubtree;Y.prototype.getComputedStyleValue=Y.prototype.getComputedStyleValue;Y.prototype.setElementClass=Y.prototype.bb;Y.prototype._styleInfoForNode=Y.prototype.Na;Y.prototype.transformCustomStyleForDocument=Y.prototype.Aa;Y.prototype.getStyleAst=Y.prototype.Qa;Y.prototype.styleAstToString=Y.prototype.cb;
225 Y.prototype.flushCustomStyles=Y.prototype.flushCustomStyles;Object.defineProperties(Y.prototype,{nativeShadow:{get:function(){return S}},nativeCss:{get:function(){return U}}});var Z=new Y,wh,xh;window.ShadyCSS&&(wh=window.ShadyCSS.ApplyShim,xh=window.ShadyCSS.CustomStyleInterface);
226 window.ShadyCSS={ScopingShim:Z,prepareTemplate:function(a,b,c){Z.flushCustomStyles();Z.prepareTemplate(a,b,c)},prepareTemplateDom:function(a,b){Z.prepareTemplateDom(a,b)},prepareTemplateStyles:function(a,b,c){Z.flushCustomStyles();Z.prepareTemplateStyles(a,b,c)},styleSubtree:function(a,b){Z.flushCustomStyles();Z.styleSubtree(a,b)},styleElement:function(a){Z.flushCustomStyles();Z.styleElement(a)},styleDocument:function(a){Z.flushCustomStyles();Z.styleDocument(a)},flushCustomStyles:function(){Z.flushCustomStyles()},
227 getComputedStyleValue:function(a,b){return Z.getComputedStyleValue(a,b)},nativeCss:U,nativeShadow:S};wh&&(window.ShadyCSS.ApplyShim=wh);xh&&(window.ShadyCSS.CustomStyleInterface=xh);var yh=window.customElements,zh=window.HTMLImports,Ah=window.HTMLTemplateElement;window.WebComponents=window.WebComponents||{};if(yh&&yh.polyfillWrapFlushCallback){var Bh,Ch=function(){if(Bh){Ah.C&&Ah.C(window.document);var a=Bh;Bh=null;a();return!0}},Dh=zh.whenReady;yh.polyfillWrapFlushCallback(function(a){Bh=a;Dh(Ch)});zh.whenReady=function(a){Dh(function(){Ch()?zh.whenReady(a):a()})}}
228 zh.whenReady(function(){requestAnimationFrame(function(){window.WebComponents.ready=!0;document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})});var Eh=document.createElement("style");Eh.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var Fh=document.querySelector("head");Fh.insertBefore(Eh,Fh.firstChild);}).call(this);
1744 229
1745 window.HTMLImports.addModule(function(scope) {
1746 var flags = scope.flags;
1747 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
1748 var IMPORT_SELECTOR = scope.IMPORT_SELECTOR;
1749 var rootDocument = scope.rootDocument;
1750 var Loader = scope.Loader;
1751 var Observer = scope.Observer;
1752 var parser = scope.parser;
1753 var importer = {
1754 documents: {},
1755 documentPreloadSelectors: IMPORT_SELECTOR,
1756 importsPreloadSelectors: [ IMPORT_SELECTOR ].join(","),
1757 loadNode: function(node) {
1758 importLoader.addNode(node);
1759 },
1760 loadSubtree: function(parent) {
1761 var nodes = this.marshalNodes(parent);
1762 importLoader.addNodes(nodes);
1763 },
1764 marshalNodes: function(parent) {
1765 return parent.querySelectorAll(this.loadSelectorsForNode(parent));
1766 },
1767 loadSelectorsForNode: function(node) {
1768 var doc = node.ownerDocument || node;
1769 return doc === rootDocument ? this.documentPreloadSelectors : this.importsPreloadSelectors;
1770 },
1771 loaded: function(url, elt, resource, err, redirectedUrl) {
1772 flags.load && console.log("loaded", url, elt);
1773 elt.__resource = resource;
1774 elt.__error = err;
1775 if (isImportLink(elt)) {
1776 var doc = this.documents[url];
1777 if (doc === undefined) {
1778 doc = err ? null : makeDocument(resource, redirectedUrl || url);
1779 if (doc) {
1780 doc.__importLink = elt;
1781 this.bootDocument(doc);
1782 }
1783 this.documents[url] = doc;
1784 }
1785 elt.__doc = doc;
1786 }
1787 parser.parseNext();
1788 },
1789 bootDocument: function(doc) {
1790 this.loadSubtree(doc);
1791 this.observer.observe(doc);
1792 parser.parseNext();
1793 },
1794 loadedAll: function() {
1795 parser.parseNext();
1796 }
1797 };
1798 var importLoader = new Loader(importer.loaded.bind(importer), importer.loadedAll.bind(importer));
1799 importer.observer = new Observer();
1800 function isImportLink(elt) {
1801 return isLinkRel(elt, IMPORT_LINK_TYPE);
1802 }
1803 function isLinkRel(elt, rel) {
1804 return elt.localName === "link" && elt.getAttribute("rel") === rel;
1805 }
1806 function hasBaseURIAccessor(doc) {
1807 return !!Object.getOwnPropertyDescriptor(doc, "baseURI");
1808 }
1809 function makeDocument(resource, url) {
1810 var doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE);
1811 doc._URL = url;
1812 var base = doc.createElement("base");
1813 base.setAttribute("href", url);
1814 if (!doc.baseURI && !hasBaseURIAccessor(doc)) {
1815 Object.defineProperty(doc, "baseURI", {
1816 value: url
1817 });
1818 }
1819 var meta = doc.createElement("meta");
1820 meta.setAttribute("charset", "utf-8");
1821 doc.head.appendChild(meta);
1822 doc.head.appendChild(base);
1823 doc.body.innerHTML = resource;
1824 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
1825 HTMLTemplateElement.bootstrap(doc);
1826 }
1827 return doc;
1828 }
1829 if (!document.baseURI) {
1830 var baseURIDescriptor = {
1831 get: function() {
1832 var base = document.querySelector("base");
1833 return base ? base.href : window.location.href;
1834 },
1835 configurable: true
1836 };
1837 Object.defineProperty(document, "baseURI", baseURIDescriptor);
1838 Object.defineProperty(rootDocument, "baseURI", baseURIDescriptor);
1839 }
1840 scope.importer = importer;
1841 scope.importLoader = importLoader;
1842 });
1843
1844 window.HTMLImports.addModule(function(scope) {
1845 var parser = scope.parser;
1846 var importer = scope.importer;
1847 var dynamic = {
1848 added: function(nodes) {
1849 var owner, parsed, loading;
1850 for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) {
1851 if (!owner) {
1852 owner = n.ownerDocument;
1853 parsed = parser.isParsed(owner);
1854 }
1855 loading = this.shouldLoadNode(n);
1856 if (loading) {
1857 importer.loadNode(n);
1858 }
1859 if (this.shouldParseNode(n) && parsed) {
1860 parser.parseDynamic(n, loading);
1861 }
1862 }
1863 },
1864 shouldLoadNode: function(node) {
1865 return node.nodeType === 1 && matches.call(node, importer.loadSelectorsForNode(node));
1866 },
1867 shouldParseNode: function(node) {
1868 return node.nodeType === 1 && matches.call(node, parser.parseSelectorsForNode(node));
1869 }
1870 };
1871 importer.observer.addCallback = dynamic.added.bind(dynamic);
1872 var matches = HTMLElement.prototype.matches || HTMLElement.prototype.matchesSelector || HTMLElement.prototype.webkitMatchesSelector || HTMLElement.prototype.mozMatchesSelector || HTMLElement.prototype.msMatchesSelector;
1873 });
1874
1875 (function(scope) {
1876 var initializeModules = scope.initializeModules;
1877 var isIE = scope.isIE;
1878 if (scope.useNative) {
1879 return;
1880 }
1881 initializeModules();
1882 var rootDocument = scope.rootDocument;
1883 function bootstrap() {
1884 window.HTMLImports.importer.bootDocument(rootDocument);
1885 }
1886 if (document.readyState === "complete" || document.readyState === "interactive" && !window.attachEvent) {
1887 bootstrap();
1888 } else {
1889 document.addEventListener("DOMContentLoaded", bootstrap);
1890 }
1891 })(window.HTMLImports);
1892
1893 window.CustomElements = window.CustomElements || {
1894 flags: {}
1895 };
1896
1897 (function(scope) {
1898 var flags = scope.flags;
1899 var modules = [];
1900 var addModule = function(module) {
1901 modules.push(module);
1902 };
1903 var initializeModules = function() {
1904 modules.forEach(function(module) {
1905 module(scope);
1906 });
1907 };
1908 scope.addModule = addModule;
1909 scope.initializeModules = initializeModules;
1910 scope.hasNative = Boolean(document.registerElement);
1911 scope.isIE = /Trident/.test(navigator.userAgent);
1912 scope.useNative = !flags.register && scope.hasNative && !window.ShadowDOMPolyfill && (!window.HTMLImports || window.HTMLImports.useNative);
1913 })(window.CustomElements);
1914
1915 window.CustomElements.addModule(function(scope) {
1916 var IMPORT_LINK_TYPE = window.HTMLImports ? window.HTMLImports.IMPORT_LINK_TYPE : "none";
1917 function forSubtree(node, cb) {
1918 findAllElements(node, function(e) {
1919 if (cb(e)) {
1920 return true;
1921 }
1922 forRoots(e, cb);
1923 });
1924 forRoots(node, cb);
1925 }
1926 function findAllElements(node, find, data) {
1927 var e = node.firstElementChild;
1928 if (!e) {
1929 e = node.firstChild;
1930 while (e && e.nodeType !== Node.ELEMENT_NODE) {
1931 e = e.nextSibling;
1932 }
1933 }
1934 while (e) {
1935 if (find(e, data) !== true) {
1936 findAllElements(e, find, data);
1937 }
1938 e = e.nextElementSibling;
1939 }
1940 return null;
1941 }
1942 function forRoots(node, cb) {
1943 var root = node.shadowRoot;
1944 while (root) {
1945 forSubtree(root, cb);
1946 root = root.olderShadowRoot;
1947 }
1948 }
1949 function forDocumentTree(doc, cb) {
1950 _forDocumentTree(doc, cb, []);
1951 }
1952 function _forDocumentTree(doc, cb, processingDocuments) {
1953 doc = window.wrap(doc);
1954 if (processingDocuments.indexOf(doc) >= 0) {
1955 return;
1956 }
1957 processingDocuments.push(doc);
1958 var imports = doc.querySelectorAll("link[rel=" + IMPORT_LINK_TYPE + "]");
1959 for (var i = 0, l = imports.length, n; i < l && (n = imports[i]); i++) {
1960 if (n.import) {
1961 _forDocumentTree(n.import, cb, processingDocuments);
1962 }
1963 }
1964 cb(doc);
1965 }
1966 scope.forDocumentTree = forDocumentTree;
1967 scope.forSubtree = forSubtree;
1968 });
1969
1970 window.CustomElements.addModule(function(scope) {
1971 var flags = scope.flags;
1972 var forSubtree = scope.forSubtree;
1973 var forDocumentTree = scope.forDocumentTree;
1974 function addedNode(node, isAttached) {
1975 return added(node, isAttached) || addedSubtree(node, isAttached);
1976 }
1977 function added(node, isAttached) {
1978 if (scope.upgrade(node, isAttached)) {
1979 return true;
1980 }
1981 if (isAttached) {
1982 attached(node);
1983 }
1984 }
1985 function addedSubtree(node, isAttached) {
1986 forSubtree(node, function(e) {
1987 if (added(e, isAttached)) {
1988 return true;
1989 }
1990 });
1991 }
1992 var hasThrottledAttached = window.MutationObserver._isPolyfilled && flags["throttle-attached"];
1993 scope.hasPolyfillMutations = hasThrottledAttached;
1994 scope.hasThrottledAttached = hasThrottledAttached;
1995 var isPendingMutations = false;
1996 var pendingMutations = [];
1997 function deferMutation(fn) {
1998 pendingMutations.push(fn);
1999 if (!isPendingMutations) {
2000 isPendingMutations = true;
2001 setTimeout(takeMutations);
2002 }
2003 }
2004 function takeMutations() {
2005 isPendingMutations = false;
2006 var $p = pendingMutations;
2007 for (var i = 0, l = $p.length, p; i < l && (p = $p[i]); i++) {
2008 p();
2009 }
2010 pendingMutations = [];
2011 }
2012 function attached(element) {
2013 if (hasThrottledAttached) {
2014 deferMutation(function() {
2015 _attached(element);
2016 });
2017 } else {
2018 _attached(element);
2019 }
2020 }
2021 function _attached(element) {
2022 if (element.__upgraded__ && !element.__attached) {
2023 element.__attached = true;
2024 if (element.attachedCallback) {
2025 element.attachedCallback();
2026 }
2027 }
2028 }
2029 function detachedNode(node) {
2030 detached(node);
2031 forSubtree(node, function(e) {
2032 detached(e);
2033 });
2034 }
2035 function detached(element) {
2036 if (hasThrottledAttached) {
2037 deferMutation(function() {
2038 _detached(element);
2039 });
2040 } else {
2041 _detached(element);
2042 }
2043 }
2044 function _detached(element) {
2045 if (element.__upgraded__ && element.__attached) {
2046 element.__attached = false;
2047 if (element.detachedCallback) {
2048 element.detachedCallback();
2049 }
2050 }
2051 }
2052 function inDocument(element) {
2053 var p = element;
2054 var doc = window.wrap(document);
2055 while (p) {
2056 if (p == doc) {
2057 return true;
2058 }
2059 p = p.parentNode || p.nodeType === Node.DOCUMENT_FRAGMENT_NODE && p.host;
2060 }
2061 }
2062 function watchShadow(node) {
2063 if (node.shadowRoot && !node.shadowRoot.__watched) {
2064 flags.dom && console.log("watching shadow-root for: ", node.localName);
2065 var root = node.shadowRoot;
2066 while (root) {
2067 observe(root);
2068 root = root.olderShadowRoot;
2069 }
2070 }
2071 }
2072 function handler(root, mutations) {
2073 if (flags.dom) {
2074 var mx = mutations[0];
2075 if (mx && mx.type === "childList" && mx.addedNodes) {
2076 if (mx.addedNodes) {
2077 var d = mx.addedNodes[0];
2078 while (d && d !== document && !d.host) {
2079 d = d.parentNode;
2080 }
2081 var u = d && (d.URL || d._URL || d.host && d.host.localName) || "";
2082 u = u.split("/?").shift().split("/").pop();
2083 }
2084 }
2085 console.group("mutations (%d) [%s]", mutations.length, u || "");
2086 }
2087 var isAttached = inDocument(root);
2088 mutations.forEach(function(mx) {
2089 if (mx.type === "childList") {
2090 forEach(mx.addedNodes, function(n) {
2091 if (!n.localName) {
2092 return;
2093 }
2094 addedNode(n, isAttached);
2095 });
2096 forEach(mx.removedNodes, function(n) {
2097 if (!n.localName) {
2098 return;
2099 }
2100 detachedNode(n);
2101 });
2102 }
2103 });
2104 flags.dom && console.groupEnd();
2105 }
2106 function takeRecords(node) {
2107 node = window.wrap(node);
2108 if (!node) {
2109 node = window.wrap(document);
2110 }
2111 while (node.parentNode) {
2112 node = node.parentNode;
2113 }
2114 var observer = node.__observer;
2115 if (observer) {
2116 handler(node, observer.takeRecords());
2117 takeMutations();
2118 }
2119 }
2120 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
2121 function observe(inRoot) {
2122 if (inRoot.__observer) {
2123 return;
2124 }
2125 var observer = new MutationObserver(handler.bind(this, inRoot));
2126 observer.observe(inRoot, {
2127 childList: true,
2128 subtree: true
2129 });
2130 inRoot.__observer = observer;
2131 }
2132 function upgradeDocument(doc) {
2133 doc = window.wrap(doc);
2134 flags.dom && console.group("upgradeDocument: ", doc.baseURI.split("/").pop());
2135 var isMainDocument = doc === window.wrap(document);
2136 addedNode(doc, isMainDocument);
2137 observe(doc);
2138 flags.dom && console.groupEnd();
2139 }
2140 function upgradeDocumentTree(doc) {
2141 forDocumentTree(doc, upgradeDocument);
2142 }
2143 var originalCreateShadowRoot = Element.prototype.createShadowRoot;
2144 if (originalCreateShadowRoot) {
2145 Element.prototype.createShadowRoot = function() {
2146 var root = originalCreateShadowRoot.call(this);
2147 window.CustomElements.watchShadow(this);
2148 return root;
2149 };
2150 }
2151 scope.watchShadow = watchShadow;
2152 scope.upgradeDocumentTree = upgradeDocumentTree;
2153 scope.upgradeDocument = upgradeDocument;
2154 scope.upgradeSubtree = addedSubtree;
2155 scope.upgradeAll = addedNode;
2156 scope.attached = attached;
2157 scope.takeRecords = takeRecords;
2158 });
2159
2160 window.CustomElements.addModule(function(scope) {
2161 var flags = scope.flags;
2162 function upgrade(node, isAttached) {
2163 if (node.localName === "template") {
2164 if (window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
2165 HTMLTemplateElement.decorate(node);
2166 }
2167 }
2168 if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
2169 var is = node.getAttribute("is");
2170 var definition = scope.getRegisteredDefinition(node.localName) || scope.getRegisteredDefinition(is);
2171 if (definition) {
2172 if (is && definition.tag == node.localName || !is && !definition.extends) {
2173 return upgradeWithDefinition(node, definition, isAttached);
2174 }
2175 }
2176 }
2177 }
2178 function upgradeWithDefinition(element, definition, isAttached) {
2179 flags.upgrade && console.group("upgrade:", element.localName);
2180 if (definition.is) {
2181 element.setAttribute("is", definition.is);
2182 }
2183 implementPrototype(element, definition);
2184 element.__upgraded__ = true;
2185 created(element);
2186 if (isAttached) {
2187 scope.attached(element);
2188 }
2189 scope.upgradeSubtree(element, isAttached);
2190 flags.upgrade && console.groupEnd();
2191 return element;
2192 }
2193 function implementPrototype(element, definition) {
2194 if (Object.__proto__) {
2195 element.__proto__ = definition.prototype;
2196 } else {
2197 customMixin(element, definition.prototype, definition.native);
2198 element.__proto__ = definition.prototype;
2199 }
2200 }
2201 function customMixin(inTarget, inSrc, inNative) {
2202 var used = {};
2203 var p = inSrc;
2204 while (p !== inNative && p !== HTMLElement.prototype) {
2205 var keys = Object.getOwnPropertyNames(p);
2206 for (var i = 0, k; k = keys[i]; i++) {
2207 if (!used[k]) {
2208 Object.defineProperty(inTarget, k, Object.getOwnPropertyDescriptor(p, k));
2209 used[k] = 1;
2210 }
2211 }
2212 p = Object.getPrototypeOf(p);
2213 }
2214 }
2215 function created(element) {
2216 if (element.createdCallback) {
2217 element.createdCallback();
2218 }
2219 }
2220 scope.upgrade = upgrade;
2221 scope.upgradeWithDefinition = upgradeWithDefinition;
2222 scope.implementPrototype = implementPrototype;
2223 });
2224
2225 window.CustomElements.addModule(function(scope) {
2226 var isIE = scope.isIE;
2227 var upgradeDocumentTree = scope.upgradeDocumentTree;
2228 var upgradeAll = scope.upgradeAll;
2229 var upgradeWithDefinition = scope.upgradeWithDefinition;
2230 var implementPrototype = scope.implementPrototype;
2231 var useNative = scope.useNative;
2232 function register(name, options) {
2233 var definition = options || {};
2234 if (!name) {
2235 throw new Error("document.registerElement: first argument `name` must not be empty");
2236 }
2237 if (name.indexOf("-") < 0) {
2238 throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '" + String(name) + "'.");
2239 }
2240 if (isReservedTag(name)) {
2241 throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '" + String(name) + "'. The type name is invalid.");
2242 }
2243 if (getRegisteredDefinition(name)) {
2244 throw new Error("DuplicateDefinitionError: a type with name '" + String(name) + "' is already registered");
2245 }
2246 if (!definition.prototype) {
2247 definition.prototype = Object.create(HTMLElement.prototype);
2248 }
2249 definition.__name = name.toLowerCase();
2250 if (definition.extends) {
2251 definition.extends = definition.extends.toLowerCase();
2252 }
2253 definition.lifecycle = definition.lifecycle || {};
2254 definition.ancestry = ancestry(definition.extends);
2255 resolveTagName(definition);
2256 resolvePrototypeChain(definition);
2257 overrideAttributeApi(definition.prototype);
2258 registerDefinition(definition.__name, definition);
2259 definition.ctor = generateConstructor(definition);
2260 definition.ctor.prototype = definition.prototype;
2261 definition.prototype.constructor = definition.ctor;
2262 if (scope.ready) {
2263 upgradeDocumentTree(document);
2264 }
2265 return definition.ctor;
2266 }
2267 function overrideAttributeApi(prototype) {
2268 if (prototype.setAttribute._polyfilled) {
2269 return;
2270 }
2271 var setAttribute = prototype.setAttribute;
2272 prototype.setAttribute = function(name, value) {
2273 changeAttribute.call(this, name, value, setAttribute);
2274 };
2275 var removeAttribute = prototype.removeAttribute;
2276 prototype.removeAttribute = function(name) {
2277 changeAttribute.call(this, name, null, removeAttribute);
2278 };
2279 prototype.setAttribute._polyfilled = true;
2280 }
2281 function changeAttribute(name, value, operation) {
2282 name = name.toLowerCase();
2283 var oldValue = this.getAttribute(name);
2284 operation.apply(this, arguments);
2285 var newValue = this.getAttribute(name);
2286 if (this.attributeChangedCallback && newValue !== oldValue) {
2287 this.attributeChangedCallback(name, oldValue, newValue);
2288 }
2289 }
2290 function isReservedTag(name) {
2291 for (var i = 0; i < reservedTagList.length; i++) {
2292 if (name === reservedTagList[i]) {
2293 return true;
2294 }
2295 }
2296 }
2297 var reservedTagList = [ "annotation-xml", "color-profile", "font-face", "font-face-src", "font-face-uri", "font-face-format", "font-face-name", "missing-glyph" ];
2298 function ancestry(extnds) {
2299 var extendee = getRegisteredDefinition(extnds);
2300 if (extendee) {
2301 return ancestry(extendee.extends).concat([ extendee ]);
2302 }
2303 return [];
2304 }
2305 function resolveTagName(definition) {
2306 var baseTag = definition.extends;
2307 for (var i = 0, a; a = definition.ancestry[i]; i++) {
2308 baseTag = a.is && a.tag;
2309 }
2310 definition.tag = baseTag || definition.__name;
2311 if (baseTag) {
2312 definition.is = definition.__name;
2313 }
2314 }
2315 function resolvePrototypeChain(definition) {
2316 if (!Object.__proto__) {
2317 var nativePrototype = HTMLElement.prototype;
2318 if (definition.is) {
2319 var inst = document.createElement(definition.tag);
2320 nativePrototype = Object.getPrototypeOf(inst);
2321 }
2322 var proto = definition.prototype, ancestor;
2323 var foundPrototype = false;
2324 while (proto) {
2325 if (proto == nativePrototype) {
2326 foundPrototype = true;
2327 }
2328 ancestor = Object.getPrototypeOf(proto);
2329 if (ancestor) {
2330 proto.__proto__ = ancestor;
2331 }
2332 proto = ancestor;
2333 }
2334 if (!foundPrototype) {
2335 console.warn(definition.tag + " prototype not found in prototype chain for " + definition.is);
2336 }
2337 definition.native = nativePrototype;
2338 }
2339 }
2340 function instantiate(definition) {
2341 return upgradeWithDefinition(domCreateElement(definition.tag), definition);
2342 }
2343 var registry = {};
2344 function getRegisteredDefinition(name) {
2345 if (name) {
2346 return registry[name.toLowerCase()];
2347 }
2348 }
2349 function registerDefinition(name, definition) {
2350 registry[name] = definition;
2351 }
2352 function generateConstructor(definition) {
2353 return function() {
2354 return instantiate(definition);
2355 };
2356 }
2357 var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
2358 function createElementNS(namespace, tag, typeExtension) {
2359 if (namespace === HTML_NAMESPACE) {
2360 return createElement(tag, typeExtension);
2361 } else {
2362 return domCreateElementNS(namespace, tag);
2363 }
2364 }
2365 function createElement(tag, typeExtension) {
2366 if (tag) {
2367 tag = tag.toLowerCase();
2368 }
2369 if (typeExtension) {
2370 typeExtension = typeExtension.toLowerCase();
2371 }
2372 var definition = getRegisteredDefinition(typeExtension || tag);
2373 if (definition) {
2374 if (tag == definition.tag && typeExtension == definition.is) {
2375 return new definition.ctor();
2376 }
2377 if (!typeExtension && !definition.is) {
2378 return new definition.ctor();
2379 }
2380 }
2381 var element;
2382 if (typeExtension) {
2383 element = createElement(tag);
2384 element.setAttribute("is", typeExtension);
2385 return element;
2386 }
2387 element = domCreateElement(tag);
2388 if (tag.indexOf("-") >= 0) {
2389 implementPrototype(element, HTMLElement);
2390 }
2391 return element;
2392 }
2393 var domCreateElement = document.createElement.bind(document);
2394 var domCreateElementNS = document.createElementNS.bind(document);
2395 var isInstance;
2396 if (!Object.__proto__ && !useNative) {
2397 isInstance = function(obj, ctor) {
2398 if (obj instanceof ctor) {
2399 return true;
2400 }
2401 var p = obj;
2402 while (p) {
2403 if (p === ctor.prototype) {
2404 return true;
2405 }
2406 p = p.__proto__;
2407 }
2408 return false;
2409 };
2410 } else {
2411 isInstance = function(obj, base) {
2412 return obj instanceof base;
2413 };
2414 }
2415 function wrapDomMethodToForceUpgrade(obj, methodName) {
2416 var orig = obj[methodName];
2417 obj[methodName] = function() {
2418 var n = orig.apply(this, arguments);
2419 upgradeAll(n);
2420 return n;
2421 };
2422 }
2423 wrapDomMethodToForceUpgrade(Node.prototype, "cloneNode");
2424 wrapDomMethodToForceUpgrade(document, "importNode");
2425 document.registerElement = register;
2426 document.createElement = createElement;
2427 document.createElementNS = createElementNS;
2428 scope.registry = registry;
2429 scope.instanceof = isInstance;
2430 scope.reservedTagList = reservedTagList;
2431 scope.getRegisteredDefinition = getRegisteredDefinition;
2432 document.register = document.registerElement;
2433 });
2434
2435 (function(scope) {
2436 var useNative = scope.useNative;
2437 var initializeModules = scope.initializeModules;
2438 var isIE = scope.isIE;
2439 if (useNative) {
2440 var nop = function() {};
2441 scope.watchShadow = nop;
2442 scope.upgrade = nop;
2443 scope.upgradeAll = nop;
2444 scope.upgradeDocumentTree = nop;
2445 scope.upgradeSubtree = nop;
2446 scope.takeRecords = nop;
2447 scope.instanceof = function(obj, base) {
2448 return obj instanceof base;
2449 };
2450 } else {
2451 initializeModules();
2452 }
2453 var upgradeDocumentTree = scope.upgradeDocumentTree;
2454 var upgradeDocument = scope.upgradeDocument;
2455 if (!window.wrap) {
2456 if (window.ShadowDOMPolyfill) {
2457 window.wrap = window.ShadowDOMPolyfill.wrapIfNeeded;
2458 window.unwrap = window.ShadowDOMPolyfill.unwrapIfNeeded;
2459 } else {
2460 window.wrap = window.unwrap = function(node) {
2461 return node;
2462 };
2463 }
2464 }
2465 if (window.HTMLImports) {
2466 window.HTMLImports.__importsParsingHook = function(elt) {
2467 if (elt.import) {
2468 upgradeDocument(wrap(elt.import));
2469 }
2470 };
2471 }
2472 function bootstrap() {
2473 upgradeDocumentTree(window.wrap(document));
2474 window.CustomElements.ready = true;
2475 var requestAnimationFrame = window.requestAnimationFrame || function(f) {
2476 setTimeout(f, 16);
2477 };
2478 requestAnimationFrame(function() {
2479 setTimeout(function() {
2480 window.CustomElements.readyTime = Date.now();
2481 if (window.HTMLImports) {
2482 window.CustomElements.elapsed = window.CustomElements.readyTime - window.HTMLImports.readyTime;
2483 }
2484 document.dispatchEvent(new CustomEvent("WebComponentsReady", {
2485 bubbles: true
2486 }));
2487 });
2488 });
2489 }
2490 if (document.readyState === "complete" || scope.flags.eager) {
2491 bootstrap();
2492 } else if (document.readyState === "interactive" && !window.attachEvent && (!window.HTMLImports || window.HTMLImports.ready)) {
2493 bootstrap();
2494 } else {
2495 var loadEvent = window.HTMLImports && !window.HTMLImports.ready ? "HTMLImportsLoaded" : "DOMContentLoaded";
2496 window.addEventListener(loadEvent, bootstrap);
2497 }
2498 })(window.CustomElements);
2499
2500 (function(scope) {
2501 var style = document.createElement("style");
2502 style.textContent = "" + "body {" + "transition: opacity ease-in 0.2s;" + " } \n" + "body[unresolved] {" + "opacity: 0; display: block; overflow: hidden; position: relative;" + " } \n";
2503 var head = document.querySelector("head");
2504 head.insertBefore(style, head.firstChild);
2505 })(window.WebComponents); No newline at end of file
230 //# sourceMappingURL=webcomponents-lite.js.map
@@ -1,8 +1,9 b''
1 1 # See http://www.robotstxt.org/robotstxt.html for documentation on
2 2 # how to use the robots.txt file
3 #
4 # To forbid all spiders from indexing, uncomment the next two lines:
5 # User-Agent: *
6 # Disallow: /
3
4 User-agent: *
7 5
8 User-Agent: *
6 # To forbid all spiders from indexing, uncomment the next line:
7 #Disallow: /
8
9
@@ -86,6 +86,8 b' def add_request_user_context(event):'
86 86 Adds auth user into request context
87 87 """
88 88 request = event.request
89 # access req_id as soon as possible
90 req_id = request.req_id
89 91
90 92 if hasattr(request, 'vcs_call'):
91 93 # skip vcs calls
@@ -98,6 +100,8 b' def add_request_user_context(event):'
98 100 auth_user = get_auth_user(request)
99 101 request.user = auth_user
100 102 request.environ['rc_auth_user'] = auth_user
103 request.environ['rc_auth_user_id'] = auth_user.user_id
104 request.environ['rc_req_id'] = req_id
101 105
102 106
103 107 def inject_app_settings(event):
@@ -239,8 +243,11 b' def write_js_routes_if_enabled(event):'
239 243 jsroutes_file_path = os.path.join(
240 244 static_path, 'js', 'rhodecode', 'routes.js')
241 245
242 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
243 f.write(jsroutes_file_content)
246 try:
247 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
248 f.write(jsroutes_file_content)
249 except Exception:
250 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
244 251
245 252
246 253 class Subscriber(object):
@@ -14,12 +14,14 b''
14 14 <input type='submit' value="${_('filter')}" class="btn" />
15 15 ${_('Audit logs')} - ${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)}
16 16 ${h.end_form()}
17 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
17 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Example Queries')}</p>
18 <pre id="search-help" style="display: none">${h.tooltip(h.journal_filter_help(request))}</pre>
18 19 </%def>
19 20
20 21 <%def name="menu_bar_nav()">
21 22 ${self.menu_items(active='admin')}
22 23 </%def>
24
23 25 <%def name="main()">
24 26 <div class="box">
25 27 <!-- box / title -->
@@ -131,7 +131,7 b' var repoFilter = function(data) {'
131 131
132 132 $.each(data.results[0].children, function() {
133 133 // replace name to ID for submision
134 this.id = this.obj.repo_id;
134 this.id = this.repo_id;
135 135 results.push(this);
136 136 });
137 137
@@ -154,7 +154,7 b' var selectVcsScope = function() {'
154 154 dropdownAutoWidth: true,
155 155 containerCssClass: "drop-menu",
156 156 dropdownCssClass: "drop-menu-dropdown",
157 formatResult: formatResult,
157 formatResult: formatRepoResult,
158 158 query: $.debounce(250, function(query){
159 159 self = this;
160 160 var cacheKey = query.term;
@@ -47,8 +47,14 b''
47 47 </table>
48 48 </div>
49 49
50 % if c.user.extern_type != 'rhodecode':
51 <p>${_('Your user account details are managed by an external source. Details cannot be managed here.')}
52 <br/>${_('Source type')}: <strong>${c.user.extern_type}</strong>
53 </p>
54 % else:
50 55 <div>
51 56 ${c.form.render() | n}
52 57 </div>
58 % endif
53 59 </div>
54 60 </div>
@@ -1,4 +1,5 b''
1 <template is="dom-bind" id="notificationsPage">
1 <dom-bind id="notificationsPage">
2 <template>
2 3 <iron-ajax id="toggleNotifications"
3 4 method="post"
4 5 url="${h.route_path('my_account_notifications_toggle_visibility')}"
@@ -60,6 +61,10 b''
60 61
61 62 </div>
62 63
64
65 </template>
66 </dom-bind>
67
63 68 <script type="text/javascript">
64 69 /** because im not creating a custom element for this page
65 70 * we need to push the function onto the dom-template
@@ -81,7 +86,7 b''
81 86 var levels = ['info', 'error', 'warning', 'success'];
82 87 var level = levels[Math.floor(Math.random()*levels.length)];
83 88 function getRandomArbitrary(min, max) {
84 return parseInt(Math.random() * (max - min) + min);
89 return parseInt(Math.random() * (max - min) + min);
85 90 }
86 91 function shuffle(a) {
87 92 var j, x, i;
@@ -126,5 +131,3 b''
126 131 };
127 132
128 133 </script>
129
130 </template>
@@ -8,7 +8,8 b''
8 8 <tr>
9 9 <th>${_('Fingerprint')}</th>
10 10 <th>${_('Description')}</th>
11 <th>${_('Created')}</th>
11 <th>${_('Created on')}</th>
12 <th>${_('Accessed on')}</th>
12 13 <th>${_('Action')}</th>
13 14 </tr>
14 15 % if not c.ssh_enabled:
@@ -22,6 +23,7 b''
22 23 </td>
23 24 <td class="td-wrap">${ssh_key.description}</td>
24 25 <td class="td-tags">${h.format_date(ssh_key.created_on)}</td>
26 <td class="td-tags">${h.format_date(ssh_key.accessed_on)}</td>
25 27
26 28 <td class="td-action">
27 29 ${h.secure_form(h.route_path('my_account_ssh_keys_delete'), request=request)}
@@ -38,7 +38,7 b' var api;'
38 38 { data: {"_": "group_name",
39 39 "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," ,
40 40 render: function (data,type,full,meta)
41 {return '<div><i class="icon-group" title="User group">'+data+'</i></div>'}},
41 {return '<div><i class="icon-user-group" title="User group">'+data+'</i></div>'}},
42 42
43 43 { data: {"_": "group_description",
44 44 "sort": "group_description"}, title: "${_('Description')}", className: "td-description" },
@@ -38,6 +38,9 b''
38 38 <li class="${'active' if c.active=='objects' else ''}">
39 39 <a href="${h.route_path('admin_permissions_object')}">${_('Object')}</a>
40 40 </li>
41 <li class="${'active' if c.active=='branch' else ''}">
42 <a href="${h.route_path('admin_permissions_branch')}">${_('Branch')}</a>
43 </li>
41 44 <li class="${'active' if c.active=='ips' else ''}">
42 45 <a href="${h.route_path('admin_permissions_ips')}">${_('IP Whitelist')}</a>
43 46 </li>
@@ -3,7 +3,10 b''
3 3 <h3 class="panel-title">${_('Default Permissions for Repositories, User Groups and Repository Groups.')}</h3>
4 4 </div>
5 5 <div class="panel-body">
6 <p>${_('Default system permissions. Each permissions management entity will be created with the following default settings. Check the overwrite checkbox to force any permission changes on already existing settings.')}
6 <p>
7 ${_('Default access permissions. This defines permissions for the `default` user from which other users inherit permissions.')}
8 <br/>
9 ${_('Check the overwrite checkbox to force change all previously defined permissions for `default` user to the new selected value.')}
7 10 </p>
8 11 ${h.secure_form(h.route_path('admin_permissions_object_update'), request=request)}
9 12 <div class="form">
@@ -45,7 +48,7 b''
45 48 ${h.select('default_user_group_perm','',c.user_group_perms_choices)}
46 49 ${h.checkbox('overwrite_default_user_group','true')}
47 50 <label for="overwrite_default_user_group">
48 <span class="tooltip" title="${h.tooltip(_('All default permissions on each user group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}">
51 <span class="tooltip" title="${h.tooltip(_('All default permissions on each user group will be reset to chosen permission, note that all custom default permission on user groups will be lost'))}">
49 52 ${_('Overwrite Existing Settings')}
50 53 </span>
51 54 </label>
@@ -22,21 +22,21 b''
22 22 $(document).ready(function() {
23 23 var $sshKeyListTable = $('#ssh_keys_table');
24 24
25 var getDatatableCount = function(){
26 var table = $sshKeyListTable.dataTable();
27 var page = table.api().page.info();
28 var active = page.recordsDisplay;
29 var total = page.recordsTotal;
30
31 var _text = _gettext("{0} out of {1} ssh keys").format(active, total);
32 $('#ssh_keys_count').text(_text);
33 };
34
35 25 // user list
36 26 $sshKeyListTable.DataTable({
37 27 processing: true,
38 28 serverSide: true,
39 ajax: "${h.route_path('admin_permissions_ssh_keys_data')}",
29 ajax: {
30 "url": "${h.route_path('admin_permissions_ssh_keys_data')}",
31 "dataSrc": function ( json ) {
32 var filteredCount = json.recordsFiltered;
33 var total = json.recordsTotal;
34
35 var _text = _gettext("{0} out of {1} ssh keys").format(filteredCount, total);
36 $('#ssh_keys_count').text(_text);
37 return json.data;
38 }
39 },
40 40 dom: 'rtp',
41 41 pageLength: ${c.visual.admin_grid_items},
42 42 order: [[ 0, "asc" ]],
@@ -75,11 +75,6 b''
75 75 $sshKeyListTable.css('opacity', 0.3);
76 76 });
77 77
78 // refresh counters on draw
79 $sshKeyListTable.on('draw.dt', function(){
80 getDatatableCount();
81 });
82
83 78 // filter
84 79 $('#q_filter').on('keyup',
85 80 $.debounce(250, function() {
@@ -13,10 +13,12 b''
13 13 <th class="td-radio">${_('Write')}</th>
14 14 <th class="td-radio">${_('Admin')}</th>
15 15 <th class="td-owner">${_('User/User Group')}</th>
16 <th></th>
16 <th class="td-action"></th>
17 <th class="td-action"></th>
17 18 </tr>
18 19 ## USERS
19 20 %for _user in c.repo_group.permissions():
21 ## super admin/owner row
20 22 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
21 23 <tr class="perm_admin_row">
22 24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
@@ -34,6 +36,18 b''
34 36 %endif
35 37 </td>
36 38 <td></td>
39 <td class="quick_repo_menu">
40 % if c.rhodecode_user.is_admin:
41 <i class="icon-more"></i>
42 <div class="menu_items_container" style="display: none;">
43 <ul class="menu_items">
44 <li>
45 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-groups-permissions'))}
46 </li>
47 </ul>
48 </div>
49 % endif
50 </td>
37 51 </tr>
38 52 %else:
39 53 <tr>
@@ -50,6 +64,9 b''
50 64 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
51 65 % else:
52 66 ${h.link_to_user(_user.username)}
67 %if getattr(_user, 'duplicate_perm', None):
68 (${_('inactive duplicate')})
69 %endif
53 70 % endif
54 71 </span>
55 72 </td>
@@ -57,12 +74,28 b''
57 74 %if _user.username != h.DEFAULT_USER:
58 75 <span class="btn btn-link btn-danger revoke_perm"
59 76 member="${_user.user_id}" member_type="user">
60 <i class="icon-remove"></i> ${_('Revoke')}
77 ${_('Remove')}
61 78 </span>
62 79 %endif
63 80 </td>
81 <td class="quick_repo_menu">
82 % if c.rhodecode_user.is_admin:
83 <i class="icon-more"></i>
84 <div class="menu_items_container" style="display: none;">
85 <ul class="menu_items">
86 <li>
87 % if _user.username == h.DEFAULT_USER:
88 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-groups-permissions'))}
89 % else:
90 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-groups-permissions'))}
91 % endif
92 </li>
93 </ul>
94 </div>
95 % endif
96 </td>
64 97 %else:
65 ## special case for current user permissions, we make sure he cannot take his own permissions
98 ## special case for currently logged-in user permissions, we make sure he cannot take his own permissions
66 99 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.none', disabled="disabled")}</td>
67 100 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.read', disabled="disabled")}</td>
68 101 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.write', disabled="disabled")}</td>
@@ -74,11 +107,26 b''
74 107 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
75 108 % else:
76 109 ${h.link_to_user(_user.username)}
110 %if getattr(_user, 'duplicate_perm', None):
111 (${_('inactive duplicate')})
112 %endif
77 113 % endif
78 114 <span class="user-perm-help-text">(${_('delegated admin')})</span>
79 115 </span>
80 116 </td>
81 117 <td></td>
118 <td class="quick_repo_menu">
119 % if c.rhodecode_user.is_admin:
120 <i class="icon-more"></i>
121 <div class="menu_items_container" style="display: none;">
122 <ul class="menu_items">
123 <li>
124 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-groups-permissions'))}
125 </li>
126 </ul>
127 </div>
128 % endif
129 </td>
82 130 %endif
83 131 </tr>
84 132 %endif
@@ -92,7 +140,7 b''
92 140 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.write', checked=_user_group.permission=='group.write')}</td>
93 141 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.admin', checked=_user_group.permission=='group.admin')}</td>
94 142 <td class="td-componentname">
95 <i class="icon-group" ></i>
143 <i class="icon-user-group"></i>
96 144 %if h.HasPermissionAny('hg.admin')():
97 145 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
98 146 ${_user_group.users_group_name}
@@ -104,17 +152,40 b''
104 152 <td class="td-action">
105 153 <span class="btn btn-link btn-danger revoke_perm"
106 154 member="${_user_group.users_group_id}" member_type="user_group">
107 <i class="icon-remove"></i> ${_('Revoke')}
155 ${_('Remove')}
108 156 </span>
109 157 </td>
158 <td class="quick_repo_menu">
159 % if c.rhodecode_user.is_admin:
160 <i class="icon-more"></i>
161 <div class="menu_items_container" style="display: none;">
162 <ul class="menu_items">
163 <li>
164 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='repositories-groups-permissions'))}
165 </li>
166 </ul>
167 </div>
168 % endif
169 </td>
110 170 </tr>
111 171 %endfor
112 172
113 173 <tr class="new_members" id="add_perm_input"></tr>
174 <tr>
175 <td></td>
176 <td></td>
177 <td></td>
178 <td></td>
179 <td></td>
180 <td>
181 <span id="add_perm" class="link">
182 ${_('Add user/user group')}
183 </span>
184 </td>
185 <td></td>
186 </tr>
114 187 </table>
115 <div id="add_perm" class="link">
116 ${_('Add new')}
117 </div>
188
118 189 <div class="fields">
119 190 <div class="field">
120 191 <div class="label label-radio">
@@ -142,5 +213,6 b''
142 213 });
143 214 $('.revoke_perm').on('click', function(e){
144 215 markRevokePermInput($(this), 'group');
145 })
216 });
217 quick_repo_menu();
146 218 </script>
@@ -40,6 +40,15 b''
40 40 </div>
41 41 <div class="field">
42 42 <div class="label">
43 <label for="repo_type">${_('Type')}:</label>
44 </div>
45 <div class="select">
46 ${h.select('repo_type','hg',c.backends)}
47 <span class="help-block">${_('Set the type of repository to create.')}</span>
48 </div>
49 </div>
50 <div class="field">
51 <div class="label">
43 52 <label for="repo_description">${_('Description')}:</label>
44 53 </div>
45 54 <div class="textarea editor">
@@ -66,6 +75,15 b''
66 75 <span class="help-block">${_('Optionally select a group to put this repository into.')}</span>
67 76 </div>
68 77 </div>
78 <div class="field">
79 <div class="label">
80 <label for="repo_landing_rev">${_('Landing commit')}:</label>
81 </div>
82 <div class="select">
83 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
84 <span class="help-block">${_('The default commit for file pages, downloads, full text search index, and README generation.')}</span>
85 </div>
86 </div>
69 87 <div id="copy_perms" class="field">
70 88 <div class="label label-checkbox">
71 89 <label for="repo_copy_permissions">${_('Copy Parent Group Permissions')}:</label>
@@ -76,24 +94,6 b''
76 94 </div>
77 95 </div>
78 96 <div class="field">
79 <div class="label">
80 <label for="repo_type">${_('Type')}:</label>
81 </div>
82 <div class="select">
83 ${h.select('repo_type','hg',c.backends)}
84 <span class="help-block">${_('Set the type of repository to create.')}</span>
85 </div>
86 </div>
87 <div class="field">
88 <div class="label">
89 <label for="repo_landing_rev">${_('Landing commit')}:</label>
90 </div>
91 <div class="select">
92 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
93 <span class="help-block">${_('The default commit for file pages, downloads, full text search index, and README generation.')}</span>
94 </div>
95 </div>
96 <div class="field">
97 97 <div class="label label-checkbox">
98 98 <label for="repo_private">${_('Private Repository')}:</label>
99 99 </div>
@@ -48,6 +48,9 b''
48 48 <li class="${'active' if c.active=='permissions' else ''}">
49 49 <a href="${h.route_path('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
50 50 </li>
51 <li class="${'active' if c.active=='permissions_branch' else ''}">
52 <a href="${h.route_path('edit_repo_perms_branch', repo_name=c.repo_name)}">${_('Branch Permissions')}</a>
53 </li>
51 54 <li class="${'active' if c.active=='advanced' else ''}">
52 55 <a href="${h.route_path('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
53 56 </li>
@@ -165,8 +165,8 b' var repoTypeFilter = function(data) {'
165 165
166 166 $.each(data.results[0].children, function() {
167 167 // filter out the SAME repo, it cannot be used as fork of itself
168 if (this.obj.repo_id != currentRepoId) {
169 this.id = this.obj.repo_id;
168 if (this.repo_id != currentRepoId) {
169 this.id = this.repo_id;
170 170 results.push(this)
171 171 }
172 172 });
@@ -181,7 +181,7 b' var repoTypeFilter = function(data) {'
181 181 dropdownAutoWidth: true,
182 182 containerCssClass: "drop-menu",
183 183 dropdownCssClass: "drop-menu-dropdown",
184 formatResult: formatResult,
184 formatResult: formatRepoResult,
185 185 query: $.debounce(250, function(query){
186 186 self = this;
187 187 var cacheKey = query.term;
@@ -14,7 +14,9 b''
14 14 <input class="q_filter_box ${'' if c.filter_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.filter_term or ''}" placeholder="${_('audit filter...')}"/>
15 15 <input type='submit' value="${_('filter')}" class="btn" />
16 16 ${h.end_form()}
17 <p class="tooltip filterexample" style="position: inherit" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
17
18 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Example Queries')}</p>
19 <pre id="search-help" style="display: none">${h.tooltip(h.journal_filter_help(request))}</pre>
18 20
19 21 <%include file="/admin/admin_log_base.mako" />
20 22
@@ -36,14 +36,14 b''
36 36 <div class="field" >
37 37 <table class="rctable edit_cache">
38 38 <tr>
39 <th>${_('Prefix')}</th>
40 39 <th>${_('Key')}</th>
40 <th>${_('Namespace')}</th>
41 41 <th>${_('Active')}</th>
42 42 </tr>
43 43 %for cache in c.rhodecode_db_repo.cache_keys:
44 44 <tr>
45 <td class="td-prefix">${cache.get_prefix() or '-'}</td>
46 <td class="td-cachekey">${cache.cache_key}</td>
45 <td class="td-prefix"><code>${cache.cache_key}</code></td>
46 <td class="td-cachekey"><code>${cache.cache_args}</code></td>
47 47 <td class="td-active">${h.bool2icon(cache.cache_active)}</td>
48 48 </tr>
49 49 %endfor
@@ -52,6 +52,63 b''
52 52 </div>
53 53 </div>
54 54
55 <div class="panel panel-default">
56 <div class="panel-heading">
57 <h3 class="panel-title">
58 ${_('Cache keys')}
59 </h3>
60 </div>
61 <div class="panel-body">
62 <p>
63 Cache keys used for storing cached values of repository stats,
64 file tree history and file tree search.
65 Invalidating the cache will remove those entries.
66 </p>
67 <pre>
68 region: ${c.region.name}
69 backend: ${c.region.actual_backend.__class__}
70 store: ${c.region.actual_backend.get_store()}
71
72
73 % if c.repo_keys:
74 ${len(c.repo_keys)} <a href="#showKeys" onclick="$('#show-keys').toggle()">${_('Show all')}</a>
75 <span id="show-keys" style="display: none">
76 % for k in c.repo_keys:
77 - ${k}
78 % endfor
79 </span>
80 % else:
81 NO KEYS FOUND
82 % endif
83
84 </pre>
85
86 </div>
87 </div>
88
89
90 <div class="panel panel-default">
91 <div class="panel-heading">
92 <h3 class="panel-title">${_('Shadow Repositories')}</h3>
93 </div>
94 <div class="panel-body">
95 <table class="rctable edit_cache">
96 % if c.shadow_repos:
97 % for shadow_repo in c.shadow_repos:
98 <tr>
99 <td>${shadow_repo}</td>
100 </tr>
101 % endfor
102 % else:
103 <tr>
104 <td>${_('No Shadow repositories exist for this repository.')}</td>
105 </tr>
106 % endif
107
108 </table>
109 </div>
110 </div>
111
55 112
56 113 <div class="panel panel-default">
57 114 <div class="panel-heading">
@@ -13,7 +13,8 b''
13 13 <th class="td-radio">${_('Write')}</th>
14 14 <th class="td-radio">${_('Admin')}</th>
15 15 <th class="td-owner">${_('User/User Group')}</th>
16 <th></th>
16 <th class="td-action"></th>
17 <th class="td-action"></th>
17 18 </tr>
18 19 ## USERS
19 20 %for _user in c.rhodecode_db_repo.permissions():
@@ -34,6 +35,18 b''
34 35 %endif
35 36 </td>
36 37 <td></td>
38 <td class="quick_repo_menu">
39 % if c.rhodecode_user.is_admin:
40 <i class="icon-more"></i>
41 <div class="menu_items_container" style="display: none;">
42 <ul class="menu_items">
43 <li>
44 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
45 </li>
46 </ul>
47 </div>
48 % endif
49 </td>
37 50 </tr>
38 51 %elif _user.username == h.DEFAULT_USER and c.rhodecode_db_repo.private:
39 52 <tr>
@@ -46,11 +59,24 b''
46 59 ${base.gravatar(h.DEFAULT_USER_EMAIL, 16)}
47 60 ${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td>
48 61 <td></td>
62 <td class="quick_repo_menu">
63 % if c.rhodecode_user.is_admin:
64 <i class="icon-more"></i>
65 <div class="menu_items_container" style="display: none;">
66 <ul class="menu_items">
67 <li>
68 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
69 </li>
70 </ul>
71 </div>
72 % endif
73 </td>
49 74 </tr>
50 75 %else:
76 <% used_by_n_rules = len(getattr(_user, 'branch_rules', None) or []) %>
51 77 <tr>
52 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none')}</td>
53 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read')}</td>
78 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
79 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
54 80 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write', checked=_user.permission=='repository.write')}</td>
55 81 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin', checked=_user.permission=='repository.admin')}</td>
56 82 <td class="td-user">
@@ -60,17 +86,43 b''
60 86 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
61 87 % else:
62 88 ${h.link_to_user(_user.username)}
89 %if getattr(_user, 'duplicate_perm', None):
90 (${_('inactive duplicate')})
91 %endif
92 %if getattr(_user, 'branch_rules', None):
93 % if used_by_n_rules == 1:
94 (${_('used by {} branch rule, requires write+ permissions').format(used_by_n_rules)})
95 % else:
96 (${_('used by {} branch rules, requires write+ permissions').format(used_by_n_rules)})
97 % endif
98 %endif
63 99 % endif
64 100 </span>
65 101 </td>
66 102 <td class="td-action">
67 %if _user.username != h.DEFAULT_USER:
103 %if _user.username != h.DEFAULT_USER and getattr(_user, 'branch_rules', None) is None:
68 104 <span class="btn btn-link btn-danger revoke_perm"
69 105 member="${_user.user_id}" member_type="user">
70 <i class="icon-remove"></i> ${_('Revoke')}
106 ${_('Remove')}
71 107 </span>
72 108 %endif
73 109 </td>
110 <td class="quick_repo_menu">
111 % if c.rhodecode_user.is_admin:
112 <i class="icon-more"></i>
113 <div class="menu_items_container" style="display: none;">
114 <ul class="menu_items">
115 <li>
116 % if _user.username == h.DEFAULT_USER:
117 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
118 % else:
119 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
120 % endif
121 </li>
122 </ul>
123 </div>
124 % endif
125 </td>
74 126 </tr>
75 127 %endif
76 128 %endfor
@@ -83,7 +135,7 b''
83 135 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')}</td>
84 136 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')}</td>
85 137 <td class="td-componentname">
86 <i class="icon-group" ></i>
138 <i class="icon-user-group"></i>
87 139 %if h.HasPermissionAny('hg.admin')():
88 140 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
89 141 ${_user_group.users_group_name}
@@ -95,16 +147,41 b''
95 147 <td class="td-action">
96 148 <span class="btn btn-link btn-danger revoke_perm"
97 149 member="${_user_group.users_group_id}" member_type="user_group">
98 <i class="icon-remove"></i> ${_('Revoke')}
150 ${_('Remove')}
99 151 </span>
100 152 </td>
153 <td class="quick_repo_menu">
154 % if c.rhodecode_user.is_admin:
155 <i class="icon-more"></i>
156 <div class="menu_items_container" style="display: none;">
157 <ul class="menu_items">
158 <li>
159 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='repositories-permissions'))}
160 </li>
161 </ul>
162 </div>
163 % endif
164 </td>
101 165 </tr>
102 166 %endfor
103 167 <tr class="new_members" id="add_perm_input"></tr>
168
169 <tr>
170 <td></td>
171 <td></td>
172 <td></td>
173 <td></td>
174 <td></td>
175 <td>
176 <span id="add_perm" class="link">
177 ${_('Add user/user group')}
178 </span>
179 </td>
180 <td></td>
181 </tr>
182
104 183 </table>
105 <div id="add_perm" class="link">
106 ${_('Add new')}
107 </div>
184
108 185 <div class="buttons">
109 186 ${h.submit('save',_('Save'),class_="btn btn-primary")}
110 187 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
@@ -120,4 +197,5 b''
120 197 $('.revoke_perm').on('click', function(e){
121 198 markRevokePermInput($(this), 'repository');
122 199 });
200 quick_repo_menu();
123 201 </script>
@@ -44,7 +44,7 b''
44 44 </ul>
45 45 </div>
46 46
47 <div class="main-content-full-width">
47 <div class="main-content-auto-width">
48 48 ${self.main_content()}
49 49 </div>
50 50 </div>
@@ -26,6 +26,10 b''
26 26 <dd title="${h.tooltip(tt)}">${dd}</dd>
27 27 %endfor
28 28 </dl>
29 <span class="help-block">
30 ${_('You can adjust those settings in [DEFAULT] section of .ini file located at')}: <br/>
31 ${c.rhodecode_ini.get('__file__')}
32 </span>
29 33 </div>
30 34 </div>
31 35
@@ -13,10 +13,12 b''
13 13 <th class="td-radio">${_('Write')}</th>
14 14 <th class="td-radio">${_('Admin')}</th>
15 15 <th>${_('User/User Group')}</th>
16 <th></th>
16 <th class="td-action"></th>
17 <th class="td-action"></th>
17 18 </tr>
18 19 ## USERS
19 20 %for _user in c.user_group.permissions():
21 ## super admin/owner row
20 22 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
21 23 <tr class="perm_admin_row">
22 24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
@@ -36,6 +38,18 b''
36 38 </span>
37 39 </td>
38 40 <td></td>
41 <td class="quick_repo_menu">
42 % if c.rhodecode_user.is_admin:
43 <i class="icon-more"></i>
44 <div class="menu_items_container" style="display: none;">
45 <ul class="menu_items">
46 <li>
47 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
48 </li>
49 </ul>
50 </div>
51 % endif
52 </td>
39 53 </tr>
40 54 %else:
41 55 ##forbid revoking permission from yourself, except if you're an super admin
@@ -52,6 +66,9 b''
52 66 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
53 67 % else:
54 68 ${h.link_to_user(_user.username)}
69 %if getattr(_user, 'duplicate_perm', None):
70 (${_('inactive duplicate')})
71 %endif
55 72 % endif
56 73 </span>
57 74 </td>
@@ -59,12 +76,28 b''
59 76 %if _user.username != h.DEFAULT_USER:
60 77 <span class="btn btn-link btn-danger revoke_perm"
61 78 member="${_user.user_id}" member_type="user">
62 <i class="icon-remove"></i> ${_('revoke')}
79 ${_('Remove')}
63 80 </span>
64 81 %endif
65 82 </td>
83 <td class="quick_repo_menu">
84 % if c.rhodecode_user.is_admin:
85 <i class="icon-more"></i>
86 <div class="menu_items_container" style="display: none;">
87 <ul class="menu_items">
88 <li>
89 % if _user.username == h.DEFAULT_USER:
90 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='user-groups-permissions'))}
91 % else:
92 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
93 % endif
94 </li>
95 </ul>
96 </div>
97 % endif
98 </td>
66 99 %else:
67 ## special case for current user permissions, we make sure he cannot take his own permissions
100 ## special case for currently logged-in user permissions, we make sure he cannot take his own permissions
68 101 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.none', disabled="disabled")}</td>
69 102 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.read', disabled="disabled")}</td>
70 103 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.write', disabled="disabled")}</td>
@@ -76,11 +109,26 b''
76 109 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
77 110 % else:
78 111 ${h.link_to_user(_user.username)}
112 %if getattr(_user, 'duplicate_perm', None):
113 (${_('inactive duplicate')})
114 %endif
79 115 % endif
80 116 <span class="user-perm-help-text">(${_('delegated admin')})</span>
81 117 </span>
82 118 </td>
83 119 <td></td>
120 <td class="quick_repo_menu">
121 % if c.rhodecode_user.is_admin:
122 <i class="icon-more"></i>
123 <div class="menu_items_container" style="display: none;">
124 <ul class="menu_items">
125 <li>
126 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
127 </li>
128 </ul>
129 </div>
130 % endif
131 </td>
84 132 %endif
85 133 </tr>
86 134 %endif
@@ -94,7 +142,7 b''
94 142 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.write')}</td>
95 143 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.admin')}</td>
96 144 <td class="td-user">
97 <i class="icon-group" ></i>
145 <i class="icon-user-group"></i>
98 146 %if h.HasPermissionAny('hg.admin')():
99 147 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
100 148 ${_user_group.users_group_name}
@@ -106,16 +154,39 b''
106 154 <td class="td-action">
107 155 <span class="btn btn-link btn-danger revoke_perm"
108 156 member="${_user_group.users_group_id}" member_type="user_group">
109 <i class="icon-remove"></i> ${_('revoke')}
157 ${_('Remove')}
110 158 </span>
111 159 </td>
160 <td class="quick_repo_menu">
161 % if c.rhodecode_user.is_admin:
162 <i class="icon-more"></i>
163 <div class="menu_items_container" style="display: none;">
164 <ul class="menu_items">
165 <li>
166 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='user-groups-permissions'))}
167 </li>
168 </ul>
169 </div>
170 % endif
171 </td>
112 172 </tr>
113 173 %endfor
114 174 <tr class="new_members" id="add_perm_input"></tr>
175 <tr>
176 <td></td>
177 <td></td>
178 <td></td>
179 <td></td>
180 <td></td>
181 <td>
182 <span id="add_perm" class="link">
183 ${_('Add user/user group')}
184 </span>
185 </td>
186 <td></td>
187 </tr>
115 188 </table>
116 <div id="add_perm" class="link">
117 ${_('Add new')}
118 </div>
189
119 190 <div class="buttons">
120 191 ${h.submit('save',_('Save'),class_="btn btn-primary")}
121 192 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
@@ -131,4 +202,5 b''
131 202 $('.revoke_perm').on('click', function(e){
132 203 markRevokePermInput($(this), 'usergroup');
133 204 });
205 quick_repo_menu()
134 206 </script>
@@ -10,7 +10,7 b''
10 10
11 11 <%def name="breadcrumbs_links()">
12 12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
13 ${h.link_to(_('Admin'),h.route_path('admin_home'))} &raquo; <span id="user_group_count">0</span> ${_('user groups')}
13 ${h.link_to(_('Admin'),h.route_path('admin_home'))} &raquo; <span id="user_group_count">0</span>
14 14 </%def>
15 15
16 16 <%def name="menu_bar_nav()">
@@ -38,21 +38,33 b''
38 38 </div>
39 39 <script>
40 40 $(document).ready(function() {
41 var getDatatableCount = function(){
42 var table = $('#user_group_list_table').dataTable();
43 var page = table.api().page.info();
44 var active = page.recordsDisplay;
45 var total = page.recordsTotal;
46
47 var _text = _gettext("{0} out of {1} users").format(active, total);
48 $('#user_group_count').text(_text);
49 };
41 var $userGroupsListTable = $('#user_group_list_table');
50 42
51 43 // user list
52 $('#user_group_list_table').DataTable({
44 $userGroupsListTable.DataTable({
53 45 processing: true,
54 46 serverSide: true,
55 ajax: "${h.route_path('user_groups_data')}",
47 ajax: {
48 "url": "${h.route_path('user_groups_data')}",
49 "dataSrc": function (json) {
50 var filteredCount = json.recordsFiltered;
51 var filteredInactiveCount = json.recordsFilteredInactive;
52 var totalInactive = json.recordsTotalInactive;
53 var total = json.recordsTotal;
54
55 var _text = _gettext(
56 "{0} ({1} inactive) of {2} user groups ({3} inactive)").format(
57 filteredCount, filteredInactiveCount, total, totalInactive);
58
59 if (total === filteredCount) {
60 _text = _gettext(
61 "{0} user groups ({1} inactive)").format(total, totalInactive);
62 }
63 $('#user_group_count').text(_text);
64 return json.data;
65 },
66 },
67
56 68 dom: 'rtp',
57 69 pageLength: ${c.visual.admin_grid_items},
58 70 order: [[ 0, "asc" ]],
@@ -79,17 +91,12 b''
79 91 }
80 92 });
81 93
82 $('#user_group_list_table').on('xhr.dt', function(e, settings, json, xhr){
83 $('#user_group_list_table').css('opacity', 1);
94 $userGroupsListTable.on('xhr.dt', function(e, settings, json, xhr){
95 $userGroupsListTable.css('opacity', 1);
84 96 });
85 97
86 $('#user_group_list_table').on('preXhr.dt', function(e, settings, data){
87 $('#user_group_list_table').css('opacity', 0.3);
88 });
89
90 // refresh counters on draw
91 $('#user_group_list_table').on('draw.dt', function(){
92 getDatatableCount();
98 $userGroupsListTable.on('preXhr.dt', function(e, settings, data){
99 $userGroupsListTable.css('opacity', 0.3);
93 100 });
94 101
95 102 // filter
@@ -45,6 +45,7 b''
45 45 <li class="${'active' if c.active=='ips' else ''}"><a href="${h.route_path('edit_user_ips', user_id=c.user.user_id)}">${_('Ip Whitelist')}</a></li>
46 46 <li class="${'active' if c.active=='groups' else ''}"><a href="${h.route_path('edit_user_groups_management', user_id=c.user.user_id)}">${_('User Groups Management')}</a></li>
47 47 <li class="${'active' if c.active=='audit' else ''}"><a href="${h.route_path('edit_user_audit_logs', user_id=c.user.user_id)}">${_('Audit logs')}</a></li>
48 <li class="${'active' if c.active=='caches' else ''}"><a href="${h.route_path('edit_user_caches', user_id=c.user.user_id)}">${_('Caches')}</a></li>
48 49 </ul>
49 50 </div>
50 51
@@ -14,7 +14,9 b''
14 14 <input class="q_filter_box ${'' if c.filter_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.filter_term or ''}" placeholder="${_('audit filter...')}"/>
15 15 <input type='submit' value="${_('filter')}" class="btn" />
16 16 ${h.end_form()}
17 <p class="tooltip filterexample" style="position: inherit" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
17
18 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Example Queries')}</p>
19 <pre id="search-help" style="display: none">${h.tooltip(h.journal_filter_help(request))}</pre>
18 20
19 21 <%include file="/admin/admin_log_base.mako" />
20 22
@@ -129,7 +129,7 b' var repoFilter = function(data) {'
129 129
130 130 $.each(data.results[0].children, function() {
131 131 // replace name to ID for submision
132 this.id = this.obj.repo_id;
132 this.id = this.repo_id;
133 133 results.push(this);
134 134 });
135 135
@@ -152,7 +152,7 b' var selectVcsScope = function() {'
152 152 dropdownAutoWidth: true,
153 153 containerCssClass: "drop-menu",
154 154 dropdownCssClass: "drop-menu-dropdown",
155 formatResult: formatResult,
155 formatResult: formatRepoResult,
156 156 query: $.debounce(250, function(query){
157 157 self = this;
158 158 var cacheKey = query.term;
@@ -53,7 +53,7 b' var api;'
53 53 { data: {"_": "group_name",
54 54 "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," ,
55 55 render: function (data,type,full,meta)
56 {return '<div><i class="icon-group" title="User group">'+data+'</i></div>'}},
56 {return '<div><i class="icon-user-group" title="User group">'+data+'</i></div>'}},
57 57
58 58 { data: {"_": "group_description",
59 59 "sort": "group_description"}, title: "${_('Description')}", className: "td-description" },
@@ -8,7 +8,8 b''
8 8 <tr>
9 9 <th>${_('Fingerprint')}</th>
10 10 <th>${_('Description')}</th>
11 <th>${_('Created')}</th>
11 <th>${_('Created on')}</th>
12 <th>${_('Accessed on')}</th>
12 13 <th>${_('Action')}</th>
13 14 </tr>
14 15 %if c.user_ssh_keys:
@@ -19,6 +20,7 b''
19 20 </td>
20 21 <td class="td-wrap">${ssh_key.description}</td>
21 22 <td class="td-tags">${h.format_date(ssh_key.created_on)}</td>
23 <td class="td-tags">${h.format_date(ssh_key.accessed_on)}</td>
22 24
23 25 <td class="td-action">
24 26 ${h.secure_form(h.route_path('edit_user_ssh_keys_delete', user_id=c.user.user_id), request=request)}
@@ -39,22 +39,30 b''
39 39
40 40 $(document).ready(function() {
41 41 var $userListTable = $('#user_list_table');
42
43 var getDatatableCount = function(){
44 var table = $userListTable.dataTable();
45 var page = table.api().page.info();
46 var active = page.recordsDisplay;
47 var total = page.recordsTotal;
48
49 var _text = _gettext("{0} out of {1} users").format(active, total);
50 $('#user_count').text(_text);
51 };
52
53 42 // user list
54 43 $userListTable.DataTable({
55 44 processing: true,
56 45 serverSide: true,
57 ajax: "${h.route_path('users_data')}",
46 ajax: {
47 "url": "${h.route_path('users_data')}",
48 "dataSrc": function ( json ) {
49 var filteredCount = json.recordsFiltered;
50 var filteredInactiveCount = json.recordsFilteredInactive;
51 var totalInactive = json.recordsTotalInactive;
52 var total = json.recordsTotal;
53
54 var _text = _gettext(
55 "{0} ({1} inactive) of {2} users ({3} inactive)").format(
56 filteredCount, filteredInactiveCount, total, totalInactive);
57
58 if(total === filteredCount){
59 _text = _gettext(
60 "{0} users ({1} inactive)").format(total, totalInactive);
61 }
62 $('#user_count').text(_text);
63 return json.data;
64 }
65 },
58 66 dom: 'rtp',
59 67 pageLength: ${c.visual.admin_grid_items},
60 68 order: [[ 0, "asc" ]],
@@ -100,11 +108,6 b''
100 108 $userListTable.css('opacity', 0.3);
101 109 });
102 110
103 // refresh counters on draw
104 $userListTable.on('draw.dt', function(){
105 getDatatableCount();
106 });
107
108 111 // filter
109 112 $('#q_filter').on('keyup',
110 113 $.debounce(250, function() {
@@ -226,7 +226,7 b''
226 226 <!--- CONTEXT BAR -->
227 227 <div id="context-bar">
228 228 <div class="wrapper">
229 <ul id="context-pages" class="horizontal-list navigation">
229 <ul id="context-pages" class="navigation horizontal-list">
230 230 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
231 231 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
232 232 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
@@ -385,11 +385,42 b''
385 385 return "active"
386 386 return ""
387 387 %>
388
388 389 <ul id="quick" class="main_nav navigation horizontal-list">
389 <!-- repo switcher -->
390 <li class="${is_active('repositories')} repo_switcher_li has_select2">
391 <input id="repo_switcher" name="repo_switcher" type="hidden">
392 </li>
390 ## notice box for important system messages
391 <li style="display: none">
392 <a class="notice-box" href="#openNotice" onclick="showNoticeBox(); return false">
393 <div class="menulabel-notice" >
394 0
395 </div>
396 </a>
397 </li>
398
399 ## Main filter
400 <li>
401 <div class="menulabel main_filter_box">
402 <div class="main_filter_input_box">
403 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
404 </div>
405 <div class="main_filter_help_box">
406 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
407 </div>
408 </div>
409
410 <div id="main_filter_help" style="display: none">
411 Use '/' key to quickly access this field.
412 Enter name of repository, or repository group for quick search.
413
414 Prefix query to allow special search:
415
416 user:admin, to search for usernames
417
418 user_group:devops, to search for user groups
419
420 commit:efced4, to search for commits
421
422 </div>
423 </li>
393 424
394 425 ## ROOT MENU
395 426 %if c.rhodecode_user.username != h.DEFAULT_USER:
@@ -432,109 +463,149 b''
432 463 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
433 464 </li>
434 465 % endif
466 ## render extra user menu
467 ${usermenu(active=(active=='my_account'))}
468
435 469 % if c.debug_style:
436 <li class="${is_active('debug_style')}">
470 <li>
437 471 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
438 <div class="menulabel">${_('Style')}</div>
472 <div class="menulabel">${_('[Style]')}</div>
439 473 </a>
440 474 </li>
441 475 % endif
442 ## render extra user menu
443 ${usermenu(active=(active=='my_account'))}
444 476 </ul>
445 477
446 478 <script type="text/javascript">
447 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
448
449 /*format the look of items in the list*/
450 var format = function(state, escapeMarkup){
451 if (!state.id){
452 return state.text; // optgroup
453 }
454 var obj_dict = state.obj;
455 var tmpl = '';
479 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
456 480
457 if(obj_dict && state.type == 'repo'){
458 if(obj_dict['repo_type'] === 'hg'){
459 tmpl += '<i class="icon-hg"></i> ';
460 }
461 else if(obj_dict['repo_type'] === 'git'){
462 tmpl += '<i class="icon-git"></i> ';
463 }
464 else if(obj_dict['repo_type'] === 'svn'){
465 tmpl += '<i class="icon-svn"></i> ';
481 var formatRepoResult = function(result, container, query, escapeMarkup) {
482 return function(data, escapeMarkup) {
483 if (!data.repo_id){
484 return data.text; // optgroup text Repositories
466 485 }
467 if(obj_dict['private']){
468 tmpl += '<i class="icon-lock" ></i> ';
469 }
470 else if(visual_show_public_icon){
471 tmpl += '<i class="icon-unlock-alt"></i> ';
486
487 var tmpl = '';
488 var repoType = data['repo_type'];
489 var repoName = data['text'];
490
491 if(data && data.type == 'repo'){
492 if(repoType === 'hg'){
493 tmpl += '<i class="icon-hg"></i> ';
494 }
495 else if(repoType === 'git'){
496 tmpl += '<i class="icon-git"></i> ';
497 }
498 else if(repoType === 'svn'){
499 tmpl += '<i class="icon-svn"></i> ';
500 }
501 if(data['private']){
502 tmpl += '<i class="icon-lock" ></i> ';
503 }
504 else if(visualShowPublicIcon){
505 tmpl += '<i class="icon-unlock-alt"></i> ';
506 }
472 507 }
473 }
474 if(obj_dict && state.type == 'commit') {
475 tmpl += '<i class="icon-tag"></i>';
476 }
477 if(obj_dict && state.type == 'group'){
478 tmpl += '<i class="icon-folder-close"></i> ';
479 }
480 tmpl += escapeMarkup(state.text);
481 return tmpl;
482 };
508 tmpl += escapeMarkup(repoName);
509 return tmpl;
483 510
484 var formatResult = function(result, container, query, escapeMarkup) {
485 return format(result, escapeMarkup);
486 };
487
488 var formatSelection = function(data, container, escapeMarkup) {
489 return format(data, escapeMarkup);
511 }(result, escapeMarkup);
490 512 };
491 513
492 $("#repo_switcher").select2({
493 cachedDataSource: {},
494 minimumInputLength: 2,
495 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
496 dropdownAutoWidth: true,
497 formatResult: formatResult,
498 formatSelection: formatSelection,
499 containerCssClass: "repo-switcher",
500 dropdownCssClass: "repo-switcher-dropdown",
501 escapeMarkup: function(m){
502 // don't escape our custom placeholder
503 if(m.substr(0,23) == '<div class="menulabel">'){
504 return m;
505 }
514
515 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
516
517 if (value.split(':').length === 2) {
518 value = value.split(':')[1]
519 }
520
521 var searchType = data['type'];
522 var valueDisplay = data['value_display'];
523
524 var escapeRegExChars = function (value) {
525 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
526 };
527 var pattern = '(' + escapeRegExChars(value) + ')';
528
529 // highlight match
530 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
531 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
532
533 var icon = '';
506 534
507 return Select2.util.escapeMarkup(m);
508 },
509 query: $.debounce(250, function(query){
510 self = this;
511 var cacheKey = query.term;
512 var cachedData = self.cachedDataSource[cacheKey];
535 if (searchType === 'hint') {
536 icon += '<i class="icon-folder-close"></i> ';
537 }
538 else if (searchType === 'search') {
539 icon += '<i class="icon-more"></i> ';
540 }
541 else if (searchType === 'repo') {
542 if (data['repo_type'] === 'hg') {
543 icon += '<i class="icon-hg"></i> ';
544 }
545 else if (data['repo_type'] === 'git') {
546 icon += '<i class="icon-git"></i> ';
547 }
548 else if (data['repo_type'] === 'svn') {
549 icon += '<i class="icon-svn"></i> ';
550 }
551 if (data['private']) {
552 icon += '<i class="icon-lock" ></i> ';
553 }
554 else if (visualShowPublicIcon) {
555 icon += '<i class="icon-unlock-alt"></i> ';
556 }
557 }
558 else if (searchType === 'repo_group') {
559 icon += '<i class="icon-folder-close"></i> ';
560 }
561 else if (searchType === 'user_group') {
562 icon += '<i class="icon-group"></i> ';
563 }
564 else if (searchType === 'user') {
565 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
566 }
567 else if (searchType === 'commit') {
568 icon += '<i class="icon-tag"></i>';
569 }
513 570
514 if (cachedData) {
515 query.callback({results: cachedData.results});
516 } else {
517 $.ajax({
518 url: pyroutes.url('goto_switcher_data'),
519 data: {'query': query.term},
520 dataType: 'json',
521 type: 'GET',
522 success: function(data) {
523 self.cachedDataSource[cacheKey] = data;
524 query.callback({results: data.results});
525 },
526 error: function(data, textStatus, errorThrown) {
527 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
528 }
529 })
530 }
531 })
571 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
572 return tmpl.format(icon, valueDisplay);
573 };
574
575 var handleSelect = function(element, suggestion) {
576 if (suggestion.type === "hint") {
577 // we skip action
578 $('#main_filter').focus();
579 } else {
580 window.location = suggestion['url'];
581 }
582 };
583 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
584 if (queryLowerCase.split(':').length === 2) {
585 queryLowerCase = queryLowerCase.split(':')[1]
586 }
587 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
588 };
589
590 $('#main_filter').autocomplete({
591 serviceUrl: pyroutes.url('goto_switcher_data'),
592 params: {"repo_group_id": templateContext.repo_group_id},
593 minChars:2,
594 maxHeight:400,
595 deferRequestBy: 300, //miliseconds
596 tabDisabled: true,
597 autoSelectFirst: true,
598 formatResult: autocompleteMainFilterFormatResult,
599 lookupFilter: autocompleteMainFilterResult,
600 onSelect: function(element, suggestion){
601 handleSelect(element, suggestion);
602 return false;
603 }
532 604 });
533 605
534 $("#repo_switcher").on('select2-selecting', function(e){
535 e.preventDefault();
536 window.location = e.choice.url;
537 });
606 showMainFilterBox = function () {
607 $('#main_filter_help').toggle();
608 }
538 609
539 610 </script>
540 611 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
@@ -557,7 +628,7 b''
557 628 </tr>
558 629 <%
559 630 elems = [
560 ('/', 'Open quick search box'),
631 ('/', 'Use quick search box'),
561 632 ('g h', 'Goto home page'),
562 633 ('g g', 'Goto my private gists page'),
563 634 ('g G', 'Goto my public gists page'),
@@ -611,3 +682,4 b''
611 682 </div><!-- /.modal-content -->
612 683 </div><!-- /.modal-dialog -->
613 684 </div><!-- /.modal -->
685
@@ -4,11 +4,23 b''
4 4 ## ${p.perms_summary(c.perm_user.permissions)}
5 5
6 6 <%def name="perms_summary(permissions, show_all=False, actions=True, side_link=None)">
7 <% section_to_label = {
8 'global': 'Global Permissions',
9 'repository_branches': 'Repository Branch Rules',
10 'repositories': 'Repository Permissions',
11 'user_groups': 'User Group Permissions',
12 'repositories_groups': 'Repository Group Permissions',
13 } %>
14
7 15 <div id="perms" class="table fields">
8 %for section in sorted(permissions.keys()):
16 %for section in sorted(permissions.keys(), key=lambda item: {'global': 0, 'repository_branches': 1}.get(item, 1000)):
17 <% total_counter = 0 %>
18
9 19 <div class="panel panel-default">
10 <div class="panel-heading">
11 <h3 class="panel-title">${section.replace("_"," ").capitalize()}</h3>
20 <div class="panel-heading" id="${section.replace("_","-")}-permissions">
21 <h3 class="panel-title">${section_to_label.get(section, section)} - <span id="total_count_${section}"></span>
22 <a class="permalink" href="#${section.replace("_","-")}-permissions"></a>
23 </h3>
12 24 % if side_link:
13 25 <div class="pull-right">
14 26 <a href="${side_link}">${_('in JSON format')}</a>
@@ -18,15 +30,24 b''
18 30 <div class="panel-body">
19 31 <div class="perms_section_head field">
20 32 <div class="radios">
21 %if section != 'global':
33 % if section == 'repository_branches':
22 34 <span class="permissions_boxes">
23 35 <span class="desc">${_('show')}: </span>
24 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_%s' % section}"><span class="perm_tag none">${_('none')}</span></label>
25 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_%s' % section}"><span class="perm_tag read">${_('read')}</span></label>
26 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_%s' % section}"> <span class="perm_tag write">${_('write')}</span></label>
27 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_%s' % section}"><span class="perm_tag admin">${_('admin')}</span></label>
36 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
37 ${h.checkbox('perms_filter_merge_%s' % section, 'merge', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='merge')} <label for="${'perms_filter_merge_{}'.format(section)}"><span class="perm_tag merge">${_('merge')}</span></label>
38 ${h.checkbox('perms_filter_push_%s' % section, 'push', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push')} <label for="${'perms_filter_push_{}'.format(section)}"> <span class="perm_tag push">${_('push')}</span></label>
39 ${h.checkbox('perms_filter_push_force_%s' % section, 'push_force', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push_force')} <label for="${'perms_filter_push_force_{}'.format(section)}"><span class="perm_tag push_force">${_('push force')}</span></label>
28 40 </span>
29 %endif
41 % elif section != 'global':
42 <span class="permissions_boxes">
43 <span class="desc">${_('show')}: </span>
44 ${h.checkbox('perms_filter_none_%s' % section, 'none', '', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
45 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_{}'.format(section)}"><span class="perm_tag read">${_('read')}</span></label>
46 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_{}'.format(section)}"> <span class="perm_tag write">${_('write')}</span></label>
47 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_{}'.format(section)}"><span class="perm_tag admin">${_('admin')}</span></label>
48 </span>
49 % endif
50
30 51 </div>
31 52 </div>
32 53 <div class="field">
@@ -72,12 +93,10 b''
72 93 %endif
73 94 %else:
74 95 %if not val_lbl:
75 ${
76 {'false': False,
96 ${{'false': False,
77 97 'true': True,
78 98 'none': False,
79 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false')
80 }
99 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false')}
81 100 %else:
82 101 <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span>
83 102 %endif
@@ -142,7 +161,81 b''
142 161 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
143 162
144 163 </tbody>
164 ## Branch perms
165 %elif section == 'repository_branches':
166 <thead>
167 <tr>
168 <th>${_('Name')}</th>
169 <th>${_('Pattern')}</th>
170 <th>${_('Permission')}</th>
171 %if actions:
172 <th>${_('Edit Branch Permission')}</th>
173 %endif
174 </thead>
175 <tbody class="section_${section}">
176 <%
177 def name_sorter(permissions):
178 def custom_sorter(item):
179 return item[0]
180 return sorted(permissions, key=custom_sorter)
181
182 def branch_sorter(permissions):
183 def custom_sorter(item):
184 ## none, merge, push, push_force
185 section = item[1].split('.')[-1]
186 section_importance = {'none': u'0',
187 'merge': u'1',
188 'push': u'2',
189 'push_force': u'3'}.get(section)
190 ## sort by importance + name
191 return section_importance + item[0]
192 return sorted(permissions, key=custom_sorter)
193 %>
194 %for k, section_perms in name_sorter(permissions[section].items()):
195 ## for display purposes, for non super-admins we need to check if shown
196 ## repository is actually accessible for user
197 <% repo_perm = permissions['repositories'][k] %>
198 % if repo_perm == 'repository.none' and not c.rhodecode_user.is_admin:
199 ## skip this entry
200 <% continue %>
201 % endif
202
203 <% total_counter +=1 %>
204 % for pattern, perm in branch_sorter(section_perms.items()):
205 <tr class="perm_row ${'{}_{}'.format(section, perm.split('.')[-1])}">
206 <td class="td-name">
207 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
208 </td>
209 <td>${pattern}</td>
210 <td class="td-tags">
211 ## TODO: calculate origin somehow
212 ## % for i, ((_pat, perm), origin) in enumerate((permissions[section].perm_origin_stack[k])):
213
214 <div>
215 <% i = 0 %>
216 <% origin = 'unknown' %>
217 <% _css_class = i > 0 and 'perm_overriden' or '' %>
218
219 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
220 ${perm}
221 ##(${origin})
222 </span>
223 </div>
224 ## % endfor
225 </td>
226 %if actions:
227 <td class="td-action">
228 <a href="${h.route_path('edit_repo_perms_branch',repo_name=k)}">${_('edit')}</a>
229 </td>
230 %endif
231 </tr>
232 % endfor
233 %endfor
234 </tbody>
235
236 ## Repos/Repo Groups/users groups perms
145 237 %else:
238
146 239 ## none/read/write/admin permissions on groups/repos etc
147 240 <thead>
148 241 <tr>
@@ -167,8 +260,11 b''
167 260 return sorted(permissions, key=custom_sorter)
168 261 %>
169 262 %for k, section_perm in sorter(permissions[section].items()):
170 %if section_perm.split('.')[-1] != 'none' or show_all:
171 <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}">
263 <% perm_value = section_perm.split('.')[-1] %>
264 <% _css_class = 'display:none' if perm_value in ['none'] else '' %>
265
266 %if perm_value != 'none' or show_all:
267 <tr class="perm_row ${'{}_{}'.format(section, section_perm.split('.')[-1])}" style="${_css_class}">
172 268 <td class="td-name">
173 269 %if section == 'repositories':
174 270 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
@@ -183,7 +279,7 b''
183 279 %if hasattr(permissions[section], 'perm_origin_stack'):
184 280 <div>
185 281 %for i, (perm, origin) in enumerate(reversed(permissions[section].perm_origin_stack[k])):
186
282 <% _css_class = i > 0 and 'perm_overriden' or '' %>
187 283 % if i > 0:
188 284 <div style="color: #979797">
189 285 <i class="icon-arrow_up"></i>
@@ -193,7 +289,7 b''
193 289 % endif
194 290
195 291 <div>
196 <span class="${i > 0 and 'perm_overriden' or ''} perm_tag ${perm.split('.')[-1]}">
292 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
197 293 ${perm} (${origin})
198 294 </span>
199 295 </div>
@@ -216,11 +312,13 b''
216 312 </td>
217 313 %endif
218 314 </tr>
315 <% total_counter +=1 %>
219 316 %endif
317
220 318 %endfor
221 319
222 320 <tr id="empty_${section}" class="noborder" style="display:none;">
223 <td colspan="6">${_('No permission defined')}</td>
321 <td colspan="6">${_('No matching permission defined')}</td>
224 322 </tr>
225 323
226 324 </tbody>
@@ -231,20 +329,26 b''
231 329 </div>
232 330 </div>
233 331 </div>
332
333 <script>
334 $('#total_count_${section}').html(${total_counter})
335 </script>
336
234 337 %endfor
235 338 </div>
236 339
237 340 <script>
238 341 $(document).ready(function(){
239 var show_empty = function(section){
342 var showEmpty = function(section){
240 343 var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length;
241 if(visible == 0){
344 if(visible === 0){
242 345 $('#empty_{0}'.format(section)).show();
243 346 }
244 347 else{
245 348 $('#empty_{0}'.format(section)).hide();
246 349 }
247 350 };
351
248 352 $('.perm_filter').on('change', function(e){
249 353 var self = this;
250 354 var section = $(this).attr('section');
@@ -261,7 +365,7 b''
261 365 $('.'+section+'_'+perm_type).hide();
262 366 }
263 367 });
264 show_empty(section);
368 showEmpty(section);
265 369 })
266 370 })
267 371 </script>
@@ -8,6 +8,9 b" if hasattr(c, 'rhodecode_db_repo'):"
8 8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
10 10
11 if getattr(c, 'repo_group', None):
12 c.template_context['repo_group_id'] = c.repo_group.group_id
13
11 14 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
12 15 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
13 16 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
@@ -24,7 +27,7 b" c.template_context['default_user'] = {"
24 27 %>
25 28 <html xmlns="http://www.w3.org/1999/xhtml">
26 29 <head>
27 <script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.min.js', ver=c.rhodecode_version_hash)}"></script>
30 <script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.js', ver=c.rhodecode_version_hash)}"></script>
28 31 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
29 32 <title>${self.title()}</title>
30 33 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
@@ -60,33 +63,6 b" c.template_context['default_user'] = {"
60 63
61 64 ## JAVASCRIPT
62 65 <%def name="js()">
63 <script>
64 // setup Polymer options
65 window.Polymer = {lazyRegister: true, dom: 'shadow'};
66
67 // Load webcomponentsjs polyfill if browser does not support native Web Components
68 (function() {
69 'use strict';
70 var onload = function() {
71 // For native Imports, manually fire WebComponentsReady so user code
72 // can use the same code path for native and polyfill'd imports.
73 if (!window.HTMLImports) {
74 document.dispatchEvent(
75 new CustomEvent('WebComponentsReady', {bubbles: true})
76 );
77 }
78 };
79 var webComponentsSupported = (
80 'registerElement' in document
81 && 'import' in document.createElement('link')
82 && 'content' in document.createElement('template')
83 );
84 if (!webComponentsSupported) {
85 } else {
86 onload();
87 }
88 })();
89 </script>
90 66
91 67 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
92 68 <script type="text/javascript">
@@ -94,6 +70,7 b" c.template_context['default_user'] = {"
94 70 var templateContext = ${h.json.dumps(c.template_context)|n};
95 71
96 72 var APPLICATION_URL = "${h.route_path('home').rstrip('/')}";
73 var APPLICATION_PLUGINS = [];
97 74 var ASSET_URL = "${h.asset('')}";
98 75 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
99 76 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
@@ -62,11 +62,11 b''
62 62 </div>
63 63 <div class="pull-right">
64 64 <span id="parent_link">
65 <a href="#parentCommit" title="${_('Parent Commit')}">${_('Parent')}</a>
65 <a href="#parentCommit" title="${_('Parent Commit')}"><i class="icon-left icon-no-margin"></i>${_('parent')}</a>
66 66 </span>
67 67 |
68 68 <span id="child_link">
69 <a href="#childCommit" title="${_('Child Commit')}">${_('Child')}</a>
69 <a href="#childCommit" title="${_('Child Commit')}">${_('child')}<i class="icon-right icon-no-margin"></i></a>
70 70 </span>
71 71 </div>
72 72 </div>
@@ -7,6 +7,7 b''
7 7
8 8 <%def name="comment_block(comment, inline=False)">
9 9 <% pr_index_ver = comment.get_index_version(getattr(c, 'versions', [])) %>
10 <% latest_ver = len(getattr(c, 'versions', [])) %>
10 11 % if inline:
11 12 <% outdated_at_ver = comment.outdated_at_version(getattr(c, 'at_version_num', None)) %>
12 13 % else:
@@ -103,11 +104,11 b''
103 104 <div class="pr-version-inline">
104 105 <a href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}">
105 106 % if outdated_at_ver:
106 <code class="pr-version-num" title="${_('Outdated comment from pull request version {0}').format(pr_index_ver)}">
107 <code class="pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format(pr_index_ver, latest_ver)}">
107 108 outdated ${'v{}'.format(pr_index_ver)} |
108 109 </code>
109 110 % elif pr_index_ver:
110 <code class="pr-version-num" title="${_('Comment from pull request version {0}').format(pr_index_ver)}">
111 <code class="pr-version-num" title="${_('Comment from pull request version v{0}, latest v{1}').format(pr_index_ver, latest_ver)}">
111 112 ${'v{}'.format(pr_index_ver)} |
112 113 </code>
113 114 % endif
@@ -119,10 +120,10 b''
119 120 <div class="pr-version">
120 121 % if comment.outdated:
121 122 <a href="?version=${comment.pull_request_version_id}#comment-${comment.comment_id}">
122 ${_('Outdated comment from pull request version {}').format(pr_index_ver)}
123 ${_('Outdated comment from pull request version v{0}, latest v{1}').format(pr_index_ver, latest_ver)}
123 124 </a>
124 125 % else:
125 <div title="${_('Comment from pull request version {0}').format(pr_index_ver)}">
126 <div title="${_('Comment from pull request version v{0}, latest v{1}').format(pr_index_ver, latest_ver)}">
126 127 <a href="${h.route_path('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id, version=comment.pull_request_version_id)}">
127 128 <code class="pr-version-num">
128 129 ${'v{}'.format(pr_index_ver)}
@@ -263,8 +263,13 b' collapse_all = len(diffset.files) > coll'
263 263
264 264 ## outdated comments that are made for a file that has been deleted
265 265 % for filename, comments_dict in (deleted_files_comments or {}).items():
266
267 <div class="filediffs filediff-outdated" style="display: none">
266 <%
267 display_state = 'display: none'
268 open_comments_in_file = [x for x in comments_dict['comments'] if x.outdated is False]
269 if open_comments_in_file:
270 display_state = ''
271 %>
272 <div class="filediffs filediff-outdated" style="${display_state}">
268 273 <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filename)}" type="checkbox">
269 274 <div class="filediff" data-f-path="${filename}" id="a_${h.FID('', filename)}">
270 275 <label for="filediff-collapse-${id(filename)}" class="filediff-heading">
@@ -291,7 +296,7 b' collapse_all = len(diffset.files) > coll'
291 296
292 297 <td></td>
293 298 <td class="cb-text cb-${op_class(BIN_FILENODE)}" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=5'}>
294 ${_('File was deleted in this version, and outdated comments were made on it')}
299 ${_('File was deleted in this version. There are still outdated/unresolved comments attached to it.')}
295 300 </td>
296 301 </tr>
297 302 %if c.diffmode == 'unified':
@@ -284,7 +284,7 b''
284 284
285 285 <%def name="user_group_name(user_group_name)">
286 286 <div>
287 <i class="icon-group" title="${_('User group')}"></i>
287 <i class="icon-user-group" title="${_('User group')}"></i>
288 288 ${h.link_to_group(user_group_name)}
289 289 </div>
290 290 </%def>
@@ -350,8 +350,7 b''
350 350 </%def>
351 351
352 352 <%def name="pullrequest_title(title, description)">
353 ${title} <br/>
354 ${h.shorter(description, 40)}
353 ${title}
355 354 </%def>
356 355
357 356 <%def name="pullrequest_comments(comments_nr)">
@@ -375,3 +374,52 b''
375 374 <%def name="pullrequest_author(full_contact)">
376 375 ${base.gravatar_with_user(full_contact, 16)}
377 376 </%def>
377
378
379 <%def name="markup_form(form_id, form_text='', help_text=None)">
380
381 <div class="markup-form">
382 <div class="markup-form-area">
383 <div class="markup-form-area-header">
384 <ul class="nav-links clearfix">
385 <li class="active">
386 <a href="#edit-text" tabindex="-1" id="edit-btn_${form_id}">${_('Write')}</a>
387 </li>
388 <li class="">
389 <a href="#preview-text" tabindex="-1" id="preview-btn_${form_id}">${_('Preview')}</a>
390 </li>
391 </ul>
392 </div>
393
394 <div class="markup-form-area-write" style="display: block;">
395 <div id="edit-container_${form_id}">
396 <textarea id="${form_id}" name="${form_id}" class="comment-block-ta ac-input">${form_text if form_text else ''}</textarea>
397 </div>
398 <div id="preview-container_${form_id}" class="clearfix" style="display: none;">
399 <div id="preview-box_${form_id}" class="preview-box"></div>
400 </div>
401 </div>
402
403 <div class="markup-form-area-footer">
404 <div class="toolbar">
405 <div class="toolbar-text">
406 ${(_('Parsed using %s syntax') % (
407 ('<a href="%s">%s</a>' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
408 )
409 )|n}
410 </div>
411 </div>
412 </div>
413 </div>
414
415 <div class="markup-form-footer">
416 % if help_text:
417 <span class="help-block">${help_text}</span>
418 % endif
419 </div>
420 </div>
421 <script type="text/javascript">
422 new MarkupForm('${form_id}');
423 </script>
424
425 </%def>
@@ -534,7 +534,7 b''
534 534 </tbody>
535 535 </table>
536 536 <div class="link" id="add_perm">
537 Add new
537 Add user/user group
538 538 </div>
539 539
540 540
@@ -60,15 +60,30 b''
60 60 </div>
61 61 <div class="inner-column">
62 62 <h4>Support</h4>
63 <p>For support, go to <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>.
63 <p>For help and support, go to the <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support Page')}</a>.
64 64 It may be useful to include your log file; see the log file locations <a href="${h.route_url('enterprise_log_file_locations')}">here</a>.
65 65 </p>
66
66 67 </div>
67 68 <div class="inner-column">
68 69 <h4>Documentation</h4>
69 70 <p>For more information, see <a href="${h.route_url('enterprise_docs')}">docs.rhodecode.com</a>.</p>
70 71 </div>
71 72 </div>
73
74 % if c.show_exception_id:
75 <div class="sidebar" style="width: 130px">
76
77 </div>
78 <div class="main-content">
79 <p>
80 <strong>Exception ID: <code><a href="${c.exception_id_url}">${c.exception_id}</a></code> </strong> <br/>
81
82 Super Admins can see detailed traceback information from this exception by checking the below Exception ID.<br/>
83 Please include the above link for further details of this exception.
84 </p>
85 </div>
86 % endif
72 87 </div>
73 88
74 89 </body>
@@ -12,7 +12,7 b''
12 12 </%def>
13 13
14 14 <%def name="breadcrumbs_links()">
15 ${_('Add new file')} @ ${h.show_id(c.commit)}
15 ${_('Add new file')} @ ${h.show_id(c.commit)} ${_('Branch')}: ${c.commit.branch}
16 16 </%def>
17 17
18 18 <%def name="menu_bar_subnav()">
@@ -85,6 +85,16 b''
85 85
86 86 <div class="field">
87 87 <div class="label label-checkbox">
88 <label for="private">${_('Copy permissions')}:</label>
89 </div>
90 <div class="checkboxes">
91 ${h.checkbox('copy_permissions',value="True", checked="checked")}
92 <span class="help-block">${_('Copy permissions from forked repository')}</span>
93 </div>
94 </div>
95
96 <div class="field">
97 <div class="label label-checkbox">
88 98 <label for="private">${_('Private')}:</label>
89 99 </div>
90 100 <div class="checkboxes">
@@ -93,16 +103,6 b''
93 103 </div>
94 104 </div>
95 105
96 <div class="field">
97 <div class="label label-checkbox">
98 <label for="private">${_('Copy permissions')}:</label>
99 </div>
100 <div class="checkboxes">
101 ${h.checkbox('copy_permissions',value="True", checked="checked")}
102 <span class="help-block">${_('Copy permissions from forked repository')}</span>
103 </div>
104 </div>
105
106 106 <div class="buttons">
107 107 ${h.submit('',_('Fork this Repository'),class_="btn")}
108 108 </div>
@@ -43,23 +43,15 b''
43 43 <script type="text/javascript">
44 44
45 45 $(document).ready(function() {
46 var $userListTable = $('#fork_list_table');
46 var $forksListTable = $('#fork_list_table');
47 47
48 var getDatatableCount = function(){
49 var table = $userListTable.dataTable();
50 var page = table.api().page.info();
51 var active = page.recordsDisplay;
52 var total = page.recordsTotal;
53
54 var _text = _gettext("{0} out of {1} users").format(active, total);
55 $('#user_count').text(_text);
56 };
57
58 // user list
59 $userListTable.DataTable({
48 // fork list
49 $forksListTable.DataTable({
60 50 processing: true,
61 51 serverSide: true,
62 ajax: "${h.route_path('repo_forks_data', repo_name=c.repo_name)}",
52 ajax: {
53 "url": "${h.route_path('repo_forks_data', repo_name=c.repo_name)}",
54 },
63 55 dom: 'rtp',
64 56 pageLength: ${c.visual.dashboard_items},
65 57 order: [[ 0, "asc" ]],
@@ -92,23 +84,18 b''
92 84 }
93 85 });
94 86
95 $userListTable.on('xhr.dt', function(e, settings, json, xhr){
96 $userListTable.css('opacity', 1);
87 $forksListTable.on('xhr.dt', function(e, settings, json, xhr){
88 $forksListTable.css('opacity', 1);
97 89 });
98 90
99 $userListTable.on('preXhr.dt', function(e, settings, data){
100 $userListTable.css('opacity', 0.3);
101 });
102
103 // refresh counters on draw
104 $userListTable.on('draw.dt', function(){
105 getDatatableCount();
91 $forksListTable.on('preXhr.dt', function(e, settings, data){
92 $forksListTable.css('opacity', 0.3);
106 93 });
107 94
108 95 // filter
109 96 $('#q_filter').on('keyup',
110 97 $.debounce(250, function() {
111 $userListTable.DataTable().search(
98 $forksListTable.DataTable().search(
112 99 $('#q_filter').val()
113 100 ).draw();
114 101 })
@@ -8,12 +8,11 b''
8 8 <div class="panel-heading">${title}</div>
9 9 <div class="panel-body">
10 10
11 <div tal:condition="errormsg"
12 class="clearfix alert alert-danger">
13 <p i18n:translate="">
11 <div tal:condition="errormsg" class="clearfix alert alert-error">
12 <span i18n:translate="">
14 13 There was a problem with this section
15 </p>
16 <p>${errormsg}</p>
14 </span>
15 <div>${errormsg}</div>
17 16 </div>
18 17
19 18 <div tal:condition="description">
@@ -5,9 +5,8 b''
5 5 <!-- box / title -->
6 6 <div class="title">
7 7 <div class="block-left breadcrumbs">
8 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
9 8 ${self.breadcrumbs()}
10 <span id="match_container" style="display:none">&raquo; <span id="match_count">0</span> ${_('matches')}</span>
9 <span id="match_container" style="display:none"><span id="match_count">0</span> ${_('matches')}</span>
11 10 </div>
12 11 %if c.rhodecode_user.username != h.DEFAULT_USER:
13 12 <div class="block-right">
@@ -137,65 +136,6 b''
137 136 });
138 137 % endif
139 138
140 var getDatatableCount = function() {
141 var reposCount = 0;
142 var reposCountTotal = 0;
143
144 % if c.repos_data != '[]':
145 var pageInfo = $('#repo_list_table').dataTable().api().page.info();
146 var reposCount = pageInfo.recordsDisplay;
147 var reposCountTotal = pageInfo.recordsTotal;
148 % endif
149
150 var repoGroupsCount = 0;
151 var repoGroupsCountTotal = 0;
152
153 % if c.repo_groups_data != '[]':
154 var pageInfo = $('#group_list_table').dataTable().api().page.info();
155 var repoGroupsCount = pageInfo.recordsDisplay;
156 var repoGroupsCountTotal = pageInfo.recordsTotal;
157 % endif
158
159 if (repoGroupsCount !== repoGroupsCountTotal) {
160 $('#match_count').text(reposCount + repoGroupsCount);
161 }
162 if (reposCount !== reposCountTotal) {
163 $('#match_container').show();
164 }
165 if ($('#q_filter').val() === '') {
166 $('#match_container').hide();
167 }
168 };
169
170 // update the counter when doing search
171 $('#repo_list_table, #group_list_table').on( 'search.dt', function (e,settings) {
172 getDatatableCount();
173 });
174
175 // filter, filter both grids
176 $('#q_filter').on( 'keyup', function () {
177
178 % if c.repo_groups_data != '[]':
179 var repo_group_api = $('#group_list_table').dataTable().api();
180 repo_group_api
181 .columns( 0 )
182 .search( this.value )
183 .draw();
184 % endif
185
186 % if c.repos_data != '[]':
187 var repo_api = $('#repo_list_table').dataTable().api();
188 repo_api
189 .columns( 0 )
190 .search( this.value )
191 .draw();
192 % endif
193
194 });
195
196 // refilter table if page load via back button
197 $("#q_filter").trigger('keyup');
198
199 139 });
200 140 </script>
201 141 </%def>
@@ -7,19 +7,20 b''
7 7 %endif
8 8 </%def>
9 9
10 <%def name="breadcrumbs()">
11 <h1 class="block-left">
10 <%def name="breadcrumbs_links()">
12 11 ${h.form(None, id_="filter_form", method="get")}
13 12 <input class="q_filter_box ${'' if c.search_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.search_term}" placeholder="${_('quick filter...')}"/>
14 <input type='submit' value="${_('Filter')}" class="btn" />
13 <input type='submit' value="${_('filter')}" class="btn" />
15 14 ${_('Journal')} - ${_ungettext('%s entry', '%s entries', c.journal_pager.item_count) % (c.journal_pager.item_count)}
16 15 ${h.end_form()}
17 </h1>
18 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
16 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Example Queries')}</p>
17 <pre id="search-help" style="display: none">${h.tooltip(h.journal_filter_help(request))}</pre>
19 18 </%def>
19
20 20 <%def name="menu_bar_nav()">
21 21 ${self.menu_items(active='journal')}
22 22 </%def>
23
23 24 <%def name="head_extra()">
24 25 <link href="${h.route_path('journal_atom', _query=dict(auth_token=c.rhodecode_user.feed_token))}" rel="alternate" title="${_('ATOM journal feed')}" type="application/atom+xml" />
25 26 <link href="${h.route_path('journal_rss', _query=dict(auth_token=c.rhodecode_user.feed_token))}" rel="alternate" title="${_('RSS journal feed')}" type="application/rss+xml" />
@@ -27,30 +28,31 b''
27 28
28 29 <%def name="main()">
29 30
30 <div class="box">
31 <!-- box / title -->
32 <div class="title journal">
33 ${self.breadcrumbs()}
34 <ul class="links icon-only-links block-right">
35 <li>
36 <span><a id="refresh" href="${h.route_path('journal')}"><i class="icon-refresh"></i></a></span>
37 </li>
38 <li>
39 <span><a href="${h.route_path('journal_atom', _query=dict(auth_token=c.rhodecode_user.feed_token))}"><i class="icon-rss-sign"></i></a></span>
40 </li>
41 </ul>
42 </div>
43 <div id="journal">${c.journal_data|n}</div>
31 <div class="box">
32 <!-- box / title -->
33 <div class="title journal">
34 ${self.breadcrumbs()}
35 <ul class="links icon-only-links block-right">
36 <li>
37 <span><a id="refresh" href="${h.route_path('journal')}"><i class="icon-refresh"></i></a></span>
38 </li>
39 <li>
40 <span><a href="${h.route_path('journal_atom', _query=dict(auth_token=c.rhodecode_user.feed_token))}"><i class="icon-rss-sign"></i></a></span>
41 </li>
42 </ul>
44 43 </div>
44 <div id="journal">${c.journal_data|n}</div>
45 </div>
45 46
46 <script type="text/javascript">
47 <script type="text/javascript">
47 48
48 $('#j_filter').autoGrowInput();
49 $(document).on('pjax:success',function(){
50 show_more_event();
51 });
52 $(document).pjax('#refresh', '#journal',
53 {url: "${request.current_route_path(_query=dict(filter=c.search_term))}", push: false});
49 $('#j_filter').autoGrowInput();
50 $(document).on('pjax:success',function(){
51 show_more_event();
52 });
53 $(document).pjax(
54 '#refresh', '#journal',
55 {url: "${request.current_route_path(_query=dict(filter=c.search_term))}", push: false});
54 56
55 </script>
57 </script>
56 58 </%def>
@@ -73,7 +73,9 b''
73 73 %endif
74 74
75 75 ${h.submit('sign_in', _('Sign In'), class_="btn sign-in")}
76
76 <p class="help-block pull-right">
77 RhodeCode ${c.rhodecode_edition}
78 </p>
77 79 ${h.end_form()}
78 80 <script type="text/javascript">
79 81 $(document).ready(function(){
@@ -55,6 +55,7 b''
55 55 <span class="error-message">${errors.get('email')}</span>
56 56 <br />
57 57 %endif
58 <p class="help-block">${_('Password reset link will be sent to matching email address')}</p>
58 59
59 60 %if captcha_active:
60 61 <div class="login-captcha">
@@ -70,7 +71,9 b''
70 71 %endif
71 72
72 73 ${h.submit('send', _('Send password reset email'), class_="btn sign-in")}
73 <div class="activation_msg">${_('Password reset link will be sent to matching email address')}</div>
74 <p class="help-block pull-right">
75 RhodeCode ${c.rhodecode_edition}
76 </p>
74 77
75 78 ${h.end_form()}
76 79 </div>
This diff has been collapsed as it changes many lines, (641 lines changed) Show them Hide them
@@ -1,4 +1,5 b''
1 1 <%inherit file="/base/base.mako"/>
2 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
2 3
3 4 <%def name="title()">
4 5 ${c.repo_name} ${_('New pull request')}
@@ -54,14 +55,14 b''
54 55 <label for="pullrequest_desc">${_('Description')}:</label>
55 56 </div>
56 57 <div class="textarea text-area editor">
57 ${h.textarea('pullrequest_desc',size=30, )}
58 <span class="help-block">${_('Write a short description on this pull request')}</span>
58 <input id="pr-renderer-input" type="hidden" name="description_renderer" value="${c.visual.default_renderer}">
59 ${dt.markup_form('pullrequest_desc')}
59 60 </div>
60 61 </div>
61 62
62 63 <div class="field">
63 64 <div class="label label-textarea">
64 <label for="pullrequest_desc">${_('Commit flow')}:</label>
65 <label for="commit_flow">${_('Commit flow')}:</label>
65 66 </div>
66 67
67 68 ## TODO: johbo: Abusing the "content" class here to get the
@@ -98,7 +99,7 b''
98 99 </div>
99 100 <div class="input">
100 101 <div class="pr-submit-button">
101 ${h.submit('save',_('Submit Pull Request'),class_="btn")}
102 <input id="pr_submit" class="btn" name="save" type="submit" value="${_('Submit Pull Request')}">
102 103 </div>
103 104 <div id="pr_open_message"></div>
104 105 </div>
@@ -164,374 +165,384 b''
164 165 </div>
165 166
166 167 <script type="text/javascript">
167 $(function(){
168 var defaultSourceRepo = '${c.default_repo_data['source_repo_name']}';
169 var defaultSourceRepoData = ${c.default_repo_data['source_refs_json']|n};
170 var defaultTargetRepo = '${c.default_repo_data['target_repo_name']}';
171 var defaultTargetRepoData = ${c.default_repo_data['target_refs_json']|n};
168 $(function(){
169 var defaultSourceRepo = '${c.default_repo_data['source_repo_name']}';
170 var defaultSourceRepoData = ${c.default_repo_data['source_refs_json']|n};
171 var defaultTargetRepo = '${c.default_repo_data['target_repo_name']}';
172 var defaultTargetRepoData = ${c.default_repo_data['target_refs_json']|n};
172 173
173 var $pullRequestForm = $('#pull_request_form');
174 var $sourceRepo = $('#source_repo', $pullRequestForm);
175 var $targetRepo = $('#target_repo', $pullRequestForm);
176 var $sourceRef = $('#source_ref', $pullRequestForm);
177 var $targetRef = $('#target_ref', $pullRequestForm);
174 var $pullRequestForm = $('#pull_request_form');
175 var $pullRequestSubmit = $('#pr_submit', $pullRequestForm);
176 var $sourceRepo = $('#source_repo', $pullRequestForm);
177 var $targetRepo = $('#target_repo', $pullRequestForm);
178 var $sourceRef = $('#source_ref', $pullRequestForm);
179 var $targetRef = $('#target_ref', $pullRequestForm);
178 180
179 var sourceRepo = function() { return $sourceRepo.eq(0).val() };
180 var sourceRef = function() { return $sourceRef.eq(0).val().split(':') };
181 var sourceRepo = function() { return $sourceRepo.eq(0).val() };
182 var sourceRef = function() { return $sourceRef.eq(0).val().split(':') };
181 183
182 var targetRepo = function() { return $targetRepo.eq(0).val() };
183 var targetRef = function() { return $targetRef.eq(0).val().split(':') };
184 var targetRepo = function() { return $targetRepo.eq(0).val() };
185 var targetRef = function() { return $targetRef.eq(0).val().split(':') };
184 186
185 var calculateContainerWidth = function() {
186 var maxWidth = 0;
187 var repoSelect2Containers = ['#source_repo', '#target_repo'];
188 $.each(repoSelect2Containers, function(idx, value) {
189 $(value).select2('container').width('auto');
190 var curWidth = $(value).select2('container').width();
191 if (maxWidth <= curWidth) {
192 maxWidth = curWidth;
193 }
194 $.each(repoSelect2Containers, function(idx, value) {
195 $(value).select2('container').width(maxWidth + 10);
196 });
197 });
198 };
187 var calculateContainerWidth = function() {
188 var maxWidth = 0;
189 var repoSelect2Containers = ['#source_repo', '#target_repo'];
190 $.each(repoSelect2Containers, function(idx, value) {
191 $(value).select2('container').width('auto');
192 var curWidth = $(value).select2('container').width();
193 if (maxWidth <= curWidth) {
194 maxWidth = curWidth;
195 }
196 $.each(repoSelect2Containers, function(idx, value) {
197 $(value).select2('container').width(maxWidth + 10);
198 });
199 });
200 };
199 201
200 var initRefSelection = function(selectedRef) {
201 return function(element, callback) {
202 // translate our select2 id into a text, it's a mapping to show
203 // simple label when selecting by internal ID.
204 var id, refData;
205 if (selectedRef === undefined || selectedRef === null) {
206 id = element.val();
207 refData = element.val().split(':');
202 var initRefSelection = function(selectedRef) {
203 return function(element, callback) {
204 // translate our select2 id into a text, it's a mapping to show
205 // simple label when selecting by internal ID.
206 var id, refData;
207 if (selectedRef === undefined || selectedRef === null) {
208 id = element.val();
209 refData = element.val().split(':');
208 210
209 if (refData.length !== 3){
210 refData = ["", "", ""]
211 }
212 } else {
213 id = selectedRef;
214 refData = selectedRef.split(':');
215 }
211 if (refData.length !== 3){
212 refData = ["", "", ""]
213 }
214 } else {
215 id = selectedRef;
216 refData = selectedRef.split(':');
217 }
216 218
217 var text = refData[1];
218 if (refData[0] === 'rev') {
219 text = text.substring(0, 12);
220 }
219 var text = refData[1];
220 if (refData[0] === 'rev') {
221 text = text.substring(0, 12);
222 }
221 223
222 var data = {id: id, text: text};
223 callback(data);
224 };
225 };
224 var data = {id: id, text: text};
225 callback(data);
226 };
227 };
226 228
227 var formatRefSelection = function(item) {
228 var prefix = '';
229 var refData = item.id.split(':');
230 if (refData[0] === 'branch') {
231 prefix = '<i class="icon-branch"></i>';
232 }
233 else if (refData[0] === 'book') {
234 prefix = '<i class="icon-bookmark"></i>';
235 }
236 else if (refData[0] === 'tag') {
237 prefix = '<i class="icon-tag"></i>';
238 }
229 var formatRefSelection = function(data, container, escapeMarkup) {
230 var prefix = '';
231 var refData = data.id.split(':');
232 if (refData[0] === 'branch') {
233 prefix = '<i class="icon-branch"></i>';
234 }
235 else if (refData[0] === 'book') {
236 prefix = '<i class="icon-bookmark"></i>';
237 }
238 else if (refData[0] === 'tag') {
239 prefix = '<i class="icon-tag"></i>';
240 }
239 241
240 var originalOption = item.element;
241 return prefix + item.text;
242 };
242 var originalOption = data.element;
243 return prefix + escapeMarkup(data.text);
244 };formatSelection:
243 245
244 // custom code mirror
245 var codeMirrorInstance = initPullRequestsCodeMirror('#pullrequest_desc');
246 // custom code mirror
247 var codeMirrorInstance = $('#pullrequest_desc').get(0).MarkupForm.cm;
246 248
247 reviewersController = new ReviewersController();
249 reviewersController = new ReviewersController();
248 250
249 var queryTargetRepo = function(self, query) {
250 // cache ALL results if query is empty
251 var cacheKey = query.term || '__';
252 var cachedData = self.cachedDataSource[cacheKey];
251 var queryTargetRepo = function(self, query) {
252 // cache ALL results if query is empty
253 var cacheKey = query.term || '__';
254 var cachedData = self.cachedDataSource[cacheKey];
253 255
254 if (cachedData) {
255 query.callback({results: cachedData.results});
256 } else {
257 $.ajax({
258 url: pyroutes.url('pullrequest_repo_destinations', {'repo_name': templateContext.repo_name}),
259 data: {query: query.term},
260 dataType: 'json',
261 type: 'GET',
262 success: function(data) {
263 self.cachedDataSource[cacheKey] = data;
264 query.callback({results: data.results});
265 },
266 error: function(data, textStatus, errorThrown) {
267 alert(
268 "Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
269 }
270 });
271 }
272 };
256 if (cachedData) {
257 query.callback({results: cachedData.results});
258 } else {
259 $.ajax({
260 url: pyroutes.url('pullrequest_repo_destinations', {'repo_name': templateContext.repo_name}),
261 data: {query: query.term},
262 dataType: 'json',
263 type: 'GET',
264 success: function(data) {
265 self.cachedDataSource[cacheKey] = data;
266 query.callback({results: data.results});
267 },
268 error: function(data, textStatus, errorThrown) {
269 alert(
270 "Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
271 }
272 });
273 }
274 };
273 275
274 var queryTargetRefs = function(initialData, query) {
275 var data = {results: []};
276 // filter initialData
277 $.each(initialData, function() {
278 var section = this.text;
279 var children = [];
280 $.each(this.children, function() {
281 if (query.term.length === 0 ||
282 this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ) {
283 children.push({'id': this.id, 'text': this.text})
284 }
285 });
286 data.results.push({'text': section, 'children': children})
287 });
288 query.callback({results: data.results});
289 };
276 var queryTargetRefs = function(initialData, query) {
277 var data = {results: []};
278 // filter initialData
279 $.each(initialData, function() {
280 var section = this.text;
281 var children = [];
282 $.each(this.children, function() {
283 if (query.term.length === 0 ||
284 this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ) {
285 children.push({'id': this.id, 'text': this.text})
286 }
287 });
288 data.results.push({'text': section, 'children': children})
289 });
290 query.callback({results: data.results});
291 };
290 292
291 var loadRepoRefDiffPreview = function() {
293 var loadRepoRefDiffPreview = function() {
292 294
293 var url_data = {
294 'repo_name': targetRepo(),
295 'target_repo': sourceRepo(),
296 'source_ref': targetRef()[2],
297 'source_ref_type': 'rev',
298 'target_ref': sourceRef()[2],
299 'target_ref_type': 'rev',
300 'merge': true,
301 '_': Date.now() // bypass browser caching
302 }; // gather the source/target ref and repo here
295 var url_data = {
296 'repo_name': targetRepo(),
297 'target_repo': sourceRepo(),
298 'source_ref': targetRef()[2],
299 'source_ref_type': 'rev',
300 'target_ref': sourceRef()[2],
301 'target_ref_type': 'rev',
302 'merge': true,
303 '_': Date.now() // bypass browser caching
304 }; // gather the source/target ref and repo here
303 305
304 if (sourceRef().length !== 3 || targetRef().length !== 3) {
305 prButtonLock(true, "${_('Please select source and target')}");
306 return;
307 }
308 var url = pyroutes.url('repo_compare', url_data);
306 if (sourceRef().length !== 3 || targetRef().length !== 3) {
307 prButtonLock(true, "${_('Please select source and target')}");
308 return;
309 }
310 var url = pyroutes.url('repo_compare', url_data);
309 311
310 // lock PR button, so we cannot send PR before it's calculated
311 prButtonLock(true, "${_('Loading compare ...')}", 'compare');
312 // lock PR button, so we cannot send PR before it's calculated
313 prButtonLock(true, "${_('Loading compare ...')}", 'compare');
314
315 if (loadRepoRefDiffPreview._currentRequest) {
316 loadRepoRefDiffPreview._currentRequest.abort();
317 }
312 318
313 if (loadRepoRefDiffPreview._currentRequest) {
314 loadRepoRefDiffPreview._currentRequest.abort();
315 }
319 loadRepoRefDiffPreview._currentRequest = $.get(url)
320 .error(function(data, textStatus, errorThrown) {
321 if (textStatus !== 'abort') {
322 alert(
323 "Error while processing request.\nError code {0} ({1}).".format(
324 data.status, data.statusText));
325 }
316 326
317 loadRepoRefDiffPreview._currentRequest = $.get(url)
318 .error(function(data, textStatus, errorThrown) {
319 if (textStatus !== 'abort') {
320 alert(
321 "Error while processing request.\nError code {0} ({1}).".format(
322 data.status, data.statusText));
323 }
327 })
328 .done(function(data) {
329 loadRepoRefDiffPreview._currentRequest = null;
330 $('#pull_request_overview').html(data);
331
332 var commitElements = $(data).find('tr[commit_id]');
324 333
325 })
326 .done(function(data) {
327 loadRepoRefDiffPreview._currentRequest = null;
328 $('#pull_request_overview').html(data);
334 var prTitleAndDesc = getTitleAndDescription(
335 sourceRef()[1], commitElements, 5);
329 336
330 var commitElements = $(data).find('tr[commit_id]');
337 var title = prTitleAndDesc[0];
338 var proposedDescription = prTitleAndDesc[1];
331 339
332 var prTitleAndDesc = getTitleAndDescription(
333 sourceRef()[1], commitElements, 5);
340 var useGeneratedTitle = (
341 $('#pullrequest_title').hasClass('autogenerated-title') ||
342 $('#pullrequest_title').val() === "");
334 343
335 var title = prTitleAndDesc[0];
336 var proposedDescription = prTitleAndDesc[1];
337
338 var useGeneratedTitle = (
339 $('#pullrequest_title').hasClass('autogenerated-title') ||
340 $('#pullrequest_title').val() === "");
344 if (title && useGeneratedTitle) {
345 // use generated title if we haven't specified our own
346 $('#pullrequest_title').val(title);
347 $('#pullrequest_title').addClass('autogenerated-title');
341 348
342 if (title && useGeneratedTitle) {
343 // use generated title if we haven't specified our own
344 $('#pullrequest_title').val(title);
345 $('#pullrequest_title').addClass('autogenerated-title');
349 }
350
351 var useGeneratedDescription = (
352 !codeMirrorInstance._userDefinedValue ||
353 codeMirrorInstance.getValue() === "");
346 354
347 }
355 if (proposedDescription && useGeneratedDescription) {
356 // set proposed content, if we haven't defined our own,
357 // or we don't have description written
358 codeMirrorInstance._userDefinedValue = false; // reset state
359 codeMirrorInstance.setValue(proposedDescription);
360 }
348 361
349 var useGeneratedDescription = (
350 !codeMirrorInstance._userDefinedDesc ||
351 codeMirrorInstance.getValue() === "");
362 // refresh our codeMirror so events kicks in and it's change aware
363 codeMirrorInstance.refresh();
352 364
353 if (proposedDescription && useGeneratedDescription) {
354 // set proposed content, if we haven't defined our own,
355 // or we don't have description written
356 codeMirrorInstance._userDefinedDesc = false; // reset state
357 codeMirrorInstance.setValue(proposedDescription);
358 }
365 var msg = '';
366 if (commitElements.length === 1) {
367 msg = "${_ungettext('This pull request will consist of __COMMITS__ commit.', 'This pull request will consist of __COMMITS__ commits.', 1)}";
368 } else {
369 msg = "${_ungettext('This pull request will consist of __COMMITS__ commit.', 'This pull request will consist of __COMMITS__ commits.', 2)}";
370 }
359 371
360 var msg = '';
361 if (commitElements.length === 1) {
362 msg = "${_ungettext('This pull request will consist of __COMMITS__ commit.', 'This pull request will consist of __COMMITS__ commits.', 1)}";
363 } else {
364 msg = "${_ungettext('This pull request will consist of __COMMITS__ commit.', 'This pull request will consist of __COMMITS__ commits.', 2)}";
365 }
372 msg += ' <a id="pull_request_overview_url" href="{0}" target="_blank">${_('Show detailed compare.')}</a>'.format(url);
366 373
367 msg += ' <a id="pull_request_overview_url" href="{0}" target="_blank">${_('Show detailed compare.')}</a>'.format(url);
368
369 if (commitElements.length) {
370 var commitsLink = '<a href="#pull_request_overview"><strong>{0}</strong></a>'.format(commitElements.length);
371 prButtonLock(false, msg.replace('__COMMITS__', commitsLink), 'compare');
372 }
373 else {
374 prButtonLock(true, "${_('There are no commits to merge.')}", 'compare');
375 }
374 if (commitElements.length) {
375 var commitsLink = '<a href="#pull_request_overview"><strong>{0}</strong></a>'.format(commitElements.length);
376 prButtonLock(false, msg.replace('__COMMITS__', commitsLink), 'compare');
377 }
378 else {
379 prButtonLock(true, "${_('There are no commits to merge.')}", 'compare');
380 }
376 381
377 382
378 });
379 };
383 });
384 };
380 385
381 var Select2Box = function(element, overrides) {
382 var globalDefaults = {
383 dropdownAutoWidth: true,
384 containerCssClass: "drop-menu",
385 dropdownCssClass: "drop-menu-dropdown"
386 };
386 var Select2Box = function(element, overrides) {
387 var globalDefaults = {
388 dropdownAutoWidth: true,
389 containerCssClass: "drop-menu",
390 dropdownCssClass: "drop-menu-dropdown"
391 };
387 392
388 var initSelect2 = function(defaultOptions) {
389 var options = jQuery.extend(globalDefaults, defaultOptions, overrides);
390 element.select2(options);
391 };
393 var initSelect2 = function(defaultOptions) {
394 var options = jQuery.extend(globalDefaults, defaultOptions, overrides);
395 element.select2(options);
396 };
392 397
393 return {
394 initRef: function() {
395 var defaultOptions = {
396 minimumResultsForSearch: 5,
397 formatSelection: formatRefSelection
398 };
398 return {
399 initRef: function() {
400 var defaultOptions = {
401 minimumResultsForSearch: 5,
402 formatSelection: formatRefSelection
403 };
399 404
400 initSelect2(defaultOptions);
401 },
405 initSelect2(defaultOptions);
406 },
402 407
403 initRepo: function(defaultValue, readOnly) {
404 var defaultOptions = {
405 initSelection : function (element, callback) {
406 var data = {id: defaultValue, text: defaultValue};
407 callback(data);
408 }
409 };
408 initRepo: function(defaultValue, readOnly) {
409 var defaultOptions = {
410 initSelection : function (element, callback) {
411 var data = {id: defaultValue, text: defaultValue};
412 callback(data);
413 }
414 };
410 415
411 initSelect2(defaultOptions);
416 initSelect2(defaultOptions);
412 417
413 element.select2('val', defaultSourceRepo);
414 if (readOnly === true) {
415 element.select2('readonly', true);
416 }
417 }
418 };
419 };
418 element.select2('val', defaultSourceRepo);
419 if (readOnly === true) {
420 element.select2('readonly', true);
421 }
422 }
423 };
424 };
425
426 var initTargetRefs = function(refsData, selectedRef) {
420 427
421 var initTargetRefs = function(refsData, selectedRef) {
428 Select2Box($targetRef, {
429 placeholder: "${_('Select commit reference')}",
430 query: function(query) {
431 queryTargetRefs(refsData, query);
432 },
433 initSelection : initRefSelection(selectedRef)
434 }).initRef();
422 435
423 Select2Box($targetRef, {
424 placeholder: "${_('Select commit reference')}",
425 query: function(query) {
426 queryTargetRefs(refsData, query);
427 },
428 initSelection : initRefSelection(selectedRef)
429 }).initRef();
436 if (!(selectedRef === undefined)) {
437 $targetRef.select2('val', selectedRef);
438 }
439 };
430 440
431 if (!(selectedRef === undefined)) {
432 $targetRef.select2('val', selectedRef);
433 }
434 };
441 var targetRepoChanged = function(repoData) {
442 // generate new DESC of target repo displayed next to select
443 var prLink = pyroutes.url('pullrequest_new', {'repo_name': repoData['name']});
444 $('#target_repo_desc').html(
445 "<strong>${_('Target repository')}</strong>: {0}. <a href=\"{1}\">Switch base, and use as source.</a>".format(repoData['description'], prLink)
446 );
447
448 // generate dynamic select2 for refs.
449 initTargetRefs(repoData['refs']['select2_refs'],
450 repoData['refs']['selected_ref']);
435 451
436 var targetRepoChanged = function(repoData) {
437 // generate new DESC of target repo displayed next to select
438 var prLink = pyroutes.url('pullrequest_new', {'repo_name': repoData['name']});
439 $('#target_repo_desc').html(
440 "<strong>${_('Target repository')}</strong>: {0}. <a href=\"{1}\">Switch base, and use as source.</a>".format(repoData['description'], prLink)
441 );
452 };
442 453
443 // generate dynamic select2 for refs.
444 initTargetRefs(repoData['refs']['select2_refs'],
445 repoData['refs']['selected_ref']);
446
447 };
454 var sourceRefSelect2 = Select2Box($sourceRef, {
455 placeholder: "${_('Select commit reference')}",
456 query: function(query) {
457 var initialData = defaultSourceRepoData['refs']['select2_refs'];
458 queryTargetRefs(initialData, query)
459 },
460 initSelection: initRefSelection()
461 }
462 );
448 463
449 var sourceRefSelect2 = Select2Box($sourceRef, {
450 placeholder: "${_('Select commit reference')}",
451 query: function(query) {
452 var initialData = defaultSourceRepoData['refs']['select2_refs'];
453 queryTargetRefs(initialData, query)
454 },
455 initSelection: initRefSelection()
456 }
457 );
464 var sourceRepoSelect2 = Select2Box($sourceRepo, {
465 query: function(query) {}
466 });
458 467
459 var sourceRepoSelect2 = Select2Box($sourceRepo, {
460 query: function(query) {}
461 });
468 var targetRepoSelect2 = Select2Box($targetRepo, {
469 cachedDataSource: {},
470 query: $.debounce(250, function(query) {
471 queryTargetRepo(this, query);
472 }),
473 formatResult: formatRepoResult
474 });
475
476 sourceRefSelect2.initRef();
477
478 sourceRepoSelect2.initRepo(defaultSourceRepo, true);
479
480 targetRepoSelect2.initRepo(defaultTargetRepo, false);
462 481
463 var targetRepoSelect2 = Select2Box($targetRepo, {
464 cachedDataSource: {},
465 query: $.debounce(250, function(query) {
466 queryTargetRepo(this, query);
467 }),
468 formatResult: formatResult
469 });
470
471 sourceRefSelect2.initRef();
472
473 sourceRepoSelect2.initRepo(defaultSourceRepo, true);
482 $sourceRef.on('change', function(e){
483 loadRepoRefDiffPreview();
484 reviewersController.loadDefaultReviewers(
485 sourceRepo(), sourceRef(), targetRepo(), targetRef());
486 });
474 487
475 targetRepoSelect2.initRepo(defaultTargetRepo, false);
488 $targetRef.on('change', function(e){
489 loadRepoRefDiffPreview();
490 reviewersController.loadDefaultReviewers(
491 sourceRepo(), sourceRef(), targetRepo(), targetRef());
492 });
476 493
477 $sourceRef.on('change', function(e){
478 loadRepoRefDiffPreview();
479 reviewersController.loadDefaultReviewers(
480 sourceRepo(), sourceRef(), targetRepo(), targetRef());
481 });
482
483 $targetRef.on('change', function(e){
484 loadRepoRefDiffPreview();
485 reviewersController.loadDefaultReviewers(
486 sourceRepo(), sourceRef(), targetRepo(), targetRef());
487 });
494 $targetRepo.on('change', function(e){
495 var repoName = $(this).val();
496 calculateContainerWidth();
497 $targetRef.select2('destroy');
498 $('#target_ref_loading').show();
488 499
489 $targetRepo.on('change', function(e){
490 var repoName = $(this).val();
491 calculateContainerWidth();
492 $targetRef.select2('destroy');
493 $('#target_ref_loading').show();
500 $.ajax({
501 url: pyroutes.url('pullrequest_repo_refs',
502 {'repo_name': templateContext.repo_name, 'target_repo_name':repoName}),
503 data: {},
504 dataType: 'json',
505 type: 'GET',
506 success: function(data) {
507 $('#target_ref_loading').hide();
508 targetRepoChanged(data);
509 loadRepoRefDiffPreview();
510 },
511 error: function(data, textStatus, errorThrown) {
512 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
513 }
514 })
494 515
495 $.ajax({
496 url: pyroutes.url('pullrequest_repo_refs',
497 {'repo_name': templateContext.repo_name, 'target_repo_name':repoName}),
498 data: {},
499 dataType: 'json',
500 type: 'GET',
501 success: function(data) {
502 $('#target_ref_loading').hide();
503 targetRepoChanged(data);
504 loadRepoRefDiffPreview();
505 },
506 error: function(data, textStatus, errorThrown) {
507 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
508 }
509 })
516 });
510 517
511 });
512
513 prButtonLock(true, "${_('Please select source and target')}", 'all');
518 $pullRequestForm.on('submit', function(e){
519 // Flush changes into textarea
520 codeMirrorInstance.save();
521 prButtonLock(true, null, 'all');
522 });
514 523
515 // auto-load on init, the target refs select2
516 calculateContainerWidth();
517 targetRepoChanged(defaultTargetRepoData);
524 prButtonLock(true, "${_('Please select source and target')}", 'all');
518 525
519 $('#pullrequest_title').on('keyup', function(e){
520 $(this).removeClass('autogenerated-title');
521 });
526 // auto-load on init, the target refs select2
527 calculateContainerWidth();
528 targetRepoChanged(defaultTargetRepoData);
522 529
523 % if c.default_source_ref:
524 // in case we have a pre-selected value, use it now
525 $sourceRef.select2('val', '${c.default_source_ref}');
526 // diff preview load
527 loadRepoRefDiffPreview();
528 // default reviewers
529 reviewersController.loadDefaultReviewers(
530 sourceRepo(), sourceRef(), targetRepo(), targetRef());
531 % endif
530 $('#pullrequest_title').on('keyup', function(e){
531 $(this).removeClass('autogenerated-title');
532 });
532 533
533 ReviewerAutoComplete('#user');
534 });
534 % if c.default_source_ref:
535 // in case we have a pre-selected value, use it now
536 $sourceRef.select2('val', '${c.default_source_ref}');
537 // diff preview load
538 loadRepoRefDiffPreview();
539 // default reviewers
540 reviewersController.loadDefaultReviewers(
541 sourceRepo(), sourceRef(), targetRepo(), targetRef());
542 % endif
543
544 ReviewerAutoComplete('#user');
545 });
535 546 </script>
536 547
537 548 </%def>
@@ -1,5 +1,6 b''
1 1 <%inherit file="/base/base.mako"/>
2 2 <%namespace name="base" file="/base/base.mako"/>
3 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
3 4
4 5 <%def name="title()">
5 6 ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)}
@@ -165,14 +166,15 b''
165 166 </div>
166 167 </div>
167 168 <div class="field">
168 <div class="pr-description-label label-summary">
169 <div class="pr-description-label label-summary" title="${_('Rendered using {} renderer').format(c.renderer)}">
169 170 <label>${_('Description')}:</label>
170 171 </div>
171 172 <div id="pr-desc" class="input">
172 <div class="pr-description">${h.urlify_commit_message(c.pull_request.description, c.repo_name)}</div>
173 <div class="pr-description">${h.render(c.pull_request.description, renderer=c.renderer)}</div>
173 174 </div>
174 175 <div id="pr-desc-edit" class="input textarea editor" style="display: none;">
175 <textarea id="pr-description-input" size="30">${c.pull_request.description}</textarea>
176 <input id="pr-renderer-input" type="hidden" name="description_renderer" value="${c.visual.default_renderer}">
177 ${dt.markup_form('pr-description-input', form_text=c.pull_request.description)}
176 178 </div>
177 179 </div>
178 180
@@ -221,7 +223,7 b''
221 223 <td>
222 224 % if c.at_version_num != ver_pr:
223 225 <i class="icon-comment"></i>
224 <code class="tooltip" title="${_('Comment from pull request version {0}, general:{1} inline:{2}').format(ver_pos, len(c.comment_versions[ver_pr]['at']), len(c.inline_versions[ver_pr]['at']))}">
226 <code class="tooltip" title="${_('Comment from pull request version v{0}, general:{1} inline:{2}').format(ver_pos, len(c.comment_versions[ver_pr]['at']), len(c.inline_versions[ver_pr]['at']))}">
225 227 G:${len(c.comment_versions[ver_pr]['at'])} / I:${len(c.inline_versions[ver_pr]['at'])}
226 228 </code>
227 229 % endif
@@ -417,6 +419,7 b''
417 419 <strong>${_('Missing commits')}:</strong>
418 420 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
419 421 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
422 ${_('Consider doing a {force_refresh_url} in case you think this is an error.').format(force_refresh_url=h.link_to('force refresh', h.current_route_path(request, force_refresh='1')))|n}
420 423 </div>
421 424 </div>
422 425 </div>
@@ -642,7 +645,7 b''
642 645 $(function(){
643 646
644 647 // custom code mirror
645 var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
648 var codeMirrorInstance = $('#pr-description-input').get(0).MarkupForm.cm;
646 649
647 650 var PRDetails = {
648 651 editButton: $('#open_edit_pullrequest'),
@@ -793,9 +796,10 b''
793 796 $('#edit_pull_request').on('click', function(e){
794 797 var title = $('#pr-title-input').val();
795 798 var description = codeMirrorInstance.getValue();
799 var renderer = $('#pr-renderer-input').val();
796 800 editPullRequest(
797 801 "${c.repo_name}", "${c.pull_request.pull_request_id}",
798 title, description);
802 title, description, renderer);
799 803 });
800 804
801 805 $('#update_pull_request').on('click', function(e){
@@ -32,7 +32,12 b''
32 32 <div id="register" class="right-column">
33 33 <!-- login -->
34 34 <div class="sign-in-title">
35 <h1>${_('Create an account')}</h1>
35 % if social_auth_provider:
36 <h1>${_('Create an account linked with {}').format(social_auth_provider)}</h1>
37 % else:
38 <h1>${_('Create an account')}</h1>
39 % endif
40
36 41 <h4>${h.link_to(_("Go to the login page to sign in with an existing account."), request.route_path('login'))}</h4>
37 42 </div>
38 43 <div class="inner form">
@@ -45,6 +50,11 b''
45 50 <br />
46 51 %endif
47 52
53 % if social_auth_provider:
54 ## hide password prompts for social auth
55 <div style="display: none">
56 % endif
57
48 58 <label for="password">${_('Password')}:</label>
49 59 ${h.password('password', defaults.get('password'))}
50 60 %if 'password' in errors:
@@ -59,6 +69,11 b''
59 69 <br />
60 70 %endif
61 71
72 % if social_auth_provider:
73 ## hide password prompts for social auth
74 </div>
75 % endif
76
62 77 <label for="firstname">${_('First Name')}:</label>
63 78 ${h.text('firstname', defaults.get('firstname'))}
64 79 %if 'firstname' in errors:
@@ -102,7 +117,9 b''
102 117 </p>
103 118
104 119 ${h.submit('sign_up',_('Create Account'),class_="btn sign-in")}
105
120 <p class="help-block pull-right">
121 RhodeCode ${c.rhodecode_edition}
122 </p>
106 123 ${h.end_form()}
107 124 </div>
108 125 <%block name="below_register_button" />
@@ -41,7 +41,7 b' log = logging.getLogger(__name__)'
41 41
42 42 __all__ = [
43 43 'get_new_dir', 'TestController',
44 'link_to', 'clear_all_caches',
44 'link_to', 'clear_cache_regions',
45 45 'assert_session_flash', 'login_user', 'no_newline_id_generator',
46 46 'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'SVN_REPO',
47 47 'NEW_HG_REPO', 'NEW_GIT_REPO',
@@ -95,10 +95,12 b" TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, '"
95 95 TEST_REPO_PREFIX = 'vcs-test'
96 96
97 97
98 def clear_all_caches():
99 from beaker.cache import cache_managers
100 for _cache in cache_managers.values():
101 _cache.clear()
98 def clear_cache_regions(regions=None):
99 # dogpile
100 from rhodecode.lib.rc_cache import region_meta
101 for region_name, region in region_meta.dogpile_cache_regions.items():
102 if not regions or region_name in regions:
103 region.invalidate()
102 104
103 105
104 106 def get_new_dir(title):
@@ -116,6 +118,13 b' def get_new_dir(title):'
116 118 return get_normalized_path(path)
117 119
118 120
121 def repo_id_generator(name):
122 numeric_hash = 0
123 for char in name:
124 numeric_hash += (ord(char))
125 return numeric_hash
126
127
119 128 @pytest.mark.usefixtures('app', 'index_location')
120 129 class TestController(object):
121 130
@@ -117,6 +117,7 b' class TestSanitizeVcsSettings(object):'
117 117 ('vcs.svn.compatible_version', ''),
118 118 ('git_rev_filter', '--all'),
119 119 ('vcs.hooks.protocol', 'http'),
120 ('vcs.hooks.host', '127.0.0.1'),
120 121 ('vcs.scm_app_implementation', 'http'),
121 122 ('vcs.server', ''),
122 123 ('vcs.server.log_level', 'debug'),
@@ -47,11 +47,14 b' def get_environ(url):'
47 47 ('/foo/bar?cmd=pushkey&key=tip', 'push'),
48 48 ('/foo/bar?cmd=listkeys&key=tip', 'pull'),
49 49 ('/foo/bar?cmd=changegroup&key=tip', 'pull'),
50 # Edge case: unknown argument: assume pull
51 ('/foo/bar?cmd=unknown&key=tip', 'pull'),
52 ('/foo/bar?cmd=&key=tip', 'pull'),
50 ('/foo/bar?cmd=hello', 'pull'),
51 ('/foo/bar?cmd=batch', 'push'),
52 ('/foo/bar?cmd=putlfile', 'push'),
53 # Edge case: unknown argument: assume push
54 ('/foo/bar?cmd=unknown&key=tip', 'push'),
55 ('/foo/bar?cmd=&key=tip', 'push'),
53 56 # Edge case: not cmd argument
54 ('/foo/bar?key=tip', 'pull'),
57 ('/foo/bar?key=tip', 'push'),
55 58 ])
56 59 def test_get_action(url, expected_action, request_stub):
57 60 app = simplehg.SimpleHg(config={'auth_ret_code': '', 'base_path': ''},
@@ -60,6 +63,34 b' def test_get_action(url, expected_action'
60 63
61 64
62 65 @pytest.mark.parametrize(
66 'environ, expected_xargs, expected_batch',
67 [
68 ({},
69 [''], ['push']),
70
71 ({'HTTP_X_HGARG_1': ''},
72 [''], ['push']),
73
74 ({'HTTP_X_HGARG_1': 'cmds=listkeys+namespace%3Dphases'},
75 ['listkeys namespace=phases'], ['pull']),
76
77 ({'HTTP_X_HGARG_1': 'cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'},
78 ['pushkey namespace=bookmarks,key=bm,old=,new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'], ['push']),
79
80 ({'HTTP_X_HGARG_1': 'namespace=phases'},
81 ['namespace=phases'], ['push']),
82
83 ])
84 def test_xarg_and_batch_commands(environ, expected_xargs, expected_batch):
85 app = simplehg.SimpleHg
86
87 result = app._get_xarg_headers(environ)
88 result_batch = app._get_batch_cmd(environ)
89 assert expected_xargs == result
90 assert expected_batch == result_batch
91
92
93 @pytest.mark.parametrize(
63 94 'url, expected_repo_name',
64 95 [
65 96 ('/foo?cmd=unbundle&key=tip', 'foo'),
@@ -333,7 +333,7 b' class TestShadowRepoExposure(object):'
333 333 workspace_id = PullRequestModel()._workspace_id(pull_request)
334 334 target_vcs = pull_request.target_repo.scm_instance()
335 335 vcs_repo_name = target_vcs._get_shadow_repository_path(
336 workspace_id)
336 pull_request.target_repo.repo_id, workspace_id)
337 337
338 338 assert controller.vcs_repo_name == vcs_repo_name
339 339 assert controller.url_repo_name == shadow_url
@@ -465,6 +465,7 b' class TestPrepareHooksDaemon(object):'
465 465 prepare_mock.assert_called_once_with(
466 466 expected_extras,
467 467 protocol=app_settings['vcs.hooks.protocol'],
468 host=app_settings['vcs.hooks.host'],
468 469 txn_id=None,
469 470 use_direct_calls=app_settings['vcs.hooks.direct_calls'])
470 471
@@ -419,7 +419,7 b' def test_permission_calculator_admin_per'
419 419
420 420 calculator = auth.PermissionCalculator(
421 421 user.user_id, {}, False, False, True, 'higherwin')
422 permissions = calculator._admin_permissions()
422 permissions = calculator._calculate_admin_permissions()
423 423
424 424 assert permissions['repositories_groups'][repo_group.group_name] == \
425 425 'group.admin'
@@ -75,7 +75,7 b' def test_hash_check_with_update_enforces'
75 75
76 76
77 77 @pytest.fixture(params=[
78 auth._RhodeCodeCryptoMd5,
78 auth._RhodeCodeCryptoTest,
79 79 auth._RhodeCodeCryptoBCrypt,
80 80 auth._RhodeCodeCryptoSha256,
81 81 ])
@@ -22,36 +22,24 b' import time'
22 22
23 23 import pytest
24 24
25 from rhodecode.lib import caches
26 from rhodecode.lib.memory_lru_debug import MemoryLRUNamespaceManagerBase
25 from rhodecode.lib import rc_cache
27 26
28 27
29 class TestCacheManager(object):
28 @pytest.mark.usefixtures('app')
29 class TestCaches(object):
30 30
31 @pytest.mark.parametrize('repo_name', [
32 ('',),
33 (u'',),
34 (u'ac',),
35 ('ac', ),
36 (u'ęćc',),
37 ('ąac',),
31 def test_cache_decorator_init_not_configured(self):
32 with pytest.raises(EnvironmentError):
33 rc_cache.get_or_create_region('dontexist')
34
35 @pytest.mark.parametrize('region_name', [
36 'cache_perms', u'cache_perms',
38 37 ])
39 def test_cache_manager_init(self, repo_name):
40 cache_manager_instance = caches.get_cache_manager(
41 repo_name, 'my_cache')
42 assert cache_manager_instance
43
44 def test_cache_manager_init_undefined_namespace(self):
45 cache_manager_instance = caches.get_cache_manager(
46 'repo_cache_long_undefined', 'my_cache')
47 assert cache_manager_instance
48
49 def_config = caches.DEFAULT_CACHE_MANAGER_CONFIG.copy()
50 def_config.pop('type')
51 assert cache_manager_instance.nsargs == def_config
52
53 assert isinstance(
54 cache_manager_instance.namespace, MemoryLRUNamespaceManagerBase)
38 def test_cache_decorator_init(self, region_name):
39 namespace = region_name
40 cache_region = rc_cache.get_or_create_region(
41 region_name, region_namespace=namespace)
42 assert cache_region
55 43
56 44 @pytest.mark.parametrize('example_input', [
57 45 ('',),
@@ -62,45 +50,59 b' class TestCacheManager(object):'
62 50 (u'/ac', ),
63 51 ])
64 52 def test_cache_manager_create_key(self, example_input):
65 key = caches.compute_key_from_params(*example_input)
53 key = rc_cache.utils.compute_key_from_params(*example_input)
66 54 assert key
67 55
68 def test_store_and_invalidate_value_from_manager(self):
69 cache_manger_instance = caches.get_cache_manager(
70 'repo_cache_long', 'my_cache_store')
56 @pytest.mark.parametrize('example_namespace', [
57 'namespace', None
58 ])
59 @pytest.mark.parametrize('example_input', [
60 ('',),
61 (u'/ac',),
62 (u'/ac', 1, 2, object()),
63 (u'/ęćc', 1, 2, object()),
64 ('/ąac',),
65 (u'/ac', ),
66 ])
67 def test_cache_keygen(self, example_input, example_namespace):
68 def func_wrapped():
69 return 1
70 func = rc_cache.utils.key_generator(example_namespace, func_wrapped)
71 key = func(*example_input)
72 assert key
71 73
72 def compute():
74 def test_store_value_in_cache(self):
75 cache_region = rc_cache.get_or_create_region('cache_perms')
76 # make sure we empty the cache now
77 cache_region.delete_multi(cache_region.backend.list_keys())
78
79 assert cache_region.backend.list_keys() == []
80
81 @cache_region.conditional_cache_on_arguments(expiration_time=5)
82 def compute(key):
73 83 return time.time()
74 84
75 added_keys = []
76 for i in xrange(3):
77 _cache_key = caches.compute_key_from_params('foo_bar', 'p%s' % i)
78 added_keys.append(_cache_key)
79 for x in xrange(10):
80 cache_manger_instance.get(_cache_key, createfunc=compute)
85 for x in range(10):
86 compute(x)
87
88 assert len(set(cache_region.backend.list_keys())) == 10
81 89
82 for key in added_keys:
83 assert cache_manger_instance[key]
84
85 caches.clear_cache_manager(cache_manger_instance)
86
87 for key in added_keys:
88 assert key not in cache_manger_instance
89 assert len(cache_manger_instance.namespace.keys()) == 0
90 def test_store_and_get_value_from_region(self):
91 cache_region = rc_cache.get_or_create_region('cache_perms')
92 # make sure we empty the cache now
93 for key in cache_region.backend.list_keys():
94 cache_region.delete(key)
95 assert cache_region.backend.list_keys() == []
90 96
91 def test_store_and_get_value_from_manager(self):
92 cache_manger_instance = caches.get_cache_manager(
93 'repo_cache_long', 'my_cache_store')
94
95 _cache_key = caches.compute_key_from_params('foo_bar', 'multicall')
97 @cache_region.conditional_cache_on_arguments(expiration_time=5)
98 def compute(key):
99 return time.time()
96 100
97 def compute():
98 return time.time()
101 result = set()
102 for x in range(10):
103 ret = compute('x')
104 result.add(ret)
99 105
100 result = set()
101 for x in xrange(10):
102 ret = cache_manger_instance.get(_cache_key, createfunc=compute)
103 result.add(ret)
104
105 # once computed we have only one value after executing it 10x
106 assert len(result) == 1
106 # once computed we have only one value (the same from cache)
107 # after executing it 10x
108 assert len(result) == 1
@@ -180,7 +180,7 b' class TestHttpHooksCallbackDaemon(object'
180 180 assert daemon._daemon == tcp_server
181 181
182 182 _, port = tcp_server.server_address
183 expected_uri = '{}:{}'.format(daemon.IP_ADDRESS, port)
183 expected_uri = '{}:{}'.format('127.0.0.1', port)
184 184 msg = 'Preparing HTTP callback daemon at `{}` and ' \
185 185 'registering hook object'.format(expected_uri)
186 186 assert_message_in_log(
@@ -192,7 +192,7 b' class TestHttpHooksCallbackDaemon(object'
192 192 daemon = hooks_daemon.HttpHooksCallbackDaemon()
193 193
194 194 _, port = tcp_server.server_address
195 expected_uri = '{}:{}'.format(daemon.IP_ADDRESS, port)
195 expected_uri = '{}:{}'.format('127.0.0.1', port)
196 196 assert daemon.hooks_uri == expected_uri
197 197
198 198 msg = 'Preparing HTTP callback daemon at `{}` and ' \
@@ -264,7 +264,8 b' class TestPrepareHooksDaemon(object):'
264 264 self, protocol):
265 265 expected_extras = {'extra1': 'value1'}
266 266 callback, extras = hooks_daemon.prepare_callback_daemon(
267 expected_extras.copy(), protocol=protocol, use_direct_calls=True)
267 expected_extras.copy(), protocol=protocol,
268 host='127.0.0.1', use_direct_calls=True)
268 269 assert isinstance(callback, hooks_daemon.DummyHooksCallbackDaemon)
269 270 expected_extras['hooks_module'] = 'rhodecode.lib.hooks_daemon'
270 271 expected_extras['time'] = extras['time']
@@ -281,7 +282,8 b' class TestPrepareHooksDaemon(object):'
281 282 'hooks_protocol': protocol.lower()
282 283 }
283 284 callback, extras = hooks_daemon.prepare_callback_daemon(
284 expected_extras.copy(), protocol=protocol, use_direct_calls=False,
285 expected_extras.copy(), protocol=protocol, host='127.0.0.1',
286 use_direct_calls=False,
285 287 txn_id='txnid2')
286 288 assert isinstance(callback, expected_class)
287 289 extras.pop('hooks_uri')
@@ -301,7 +303,7 b' class TestPrepareHooksDaemon(object):'
301 303 with pytest.raises(Exception):
302 304 callback, extras = hooks_daemon.prepare_callback_daemon(
303 305 expected_extras.copy(),
304 protocol=protocol,
306 protocol=protocol, host='127.0.0.1',
305 307 use_direct_calls=False)
306 308
307 309
@@ -30,10 +30,12 b' import pytest'
30 30
31 31 from rhodecode.tests import no_newline_id_generator
32 32 from rhodecode.tests.utils import run_test_concurrently
33 from rhodecode.lib.helpers import InitialsGravatar
34 33
34 from rhodecode.lib import rc_cache
35 from rhodecode.lib.helpers import InitialsGravatar
35 36 from rhodecode.lib.utils2 import AttributeDict
36 from rhodecode.model.db import Repository
37
38 from rhodecode.model.db import Repository, CacheKey
37 39
38 40
39 41 def _urls_for_proto(proto):
@@ -558,87 +560,128 b' def test_get_repo_by_id(test, expected):'
558 560 assert _test == expected
559 561
560 562
561 @pytest.mark.parametrize("test_repo_name, repo_type", [
562 ("test_repo_1", None),
563 ("repo_group/foobar", None),
564 ("test_non_asci_ąćę", None),
565 (u"test_non_asci_unicode_ąćę", None),
566 ])
567 def test_invalidation_context(baseapp, test_repo_name, repo_type):
568 from beaker.cache import cache_region
569 from rhodecode.lib import caches
570 from rhodecode.model.db import CacheKey
563 def test_invalidation_context(baseapp):
564 repo_id = 999
565
566 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
567 repo_id, CacheKey.CACHE_TYPE_README)
568 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
569 repo_id=repo_id)
570 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
571
572 calls = [1, 2]
571 573
572 @cache_region('long_term')
574 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
573 575 def _dummy_func(cache_key):
574 return 'result'
576 val = calls.pop(0)
577 return 'result:{}'.format(val)
578
579 inv_context_manager = rc_cache.InvalidationContext(
580 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
581
582 # 1st call, fresh caches
583 with inv_context_manager as invalidation_context:
584 should_invalidate = invalidation_context.should_invalidate()
585 if should_invalidate:
586 result = _dummy_func.refresh('some-key')
587 else:
588 result = _dummy_func('some-key')
589
590 assert isinstance(invalidation_context, rc_cache.FreshRegionCache)
591 assert should_invalidate is True
575 592
576 invalidator_context = CacheKey.repo_context_cache(
577 _dummy_func, test_repo_name, 'repo')
593 assert 'result:1' == result
594 # should be cached so calling it twice will give the same result !
595 result = _dummy_func('some-key')
596 assert 'result:1' == result
578 597
579 with invalidator_context as context:
580 invalidated = context.invalidate()
581 result = context.compute()
598 # 2nd call, we create a new context manager, this should be now key aware, and
599 # return an active cache region
600 with inv_context_manager as invalidation_context:
601 should_invalidate = invalidation_context.should_invalidate()
602 assert isinstance(invalidation_context, rc_cache.ActiveRegionCache)
603 assert should_invalidate is False
604
605 # Mark invalidation
606 CacheKey.set_invalidate(invalidation_namespace)
582 607
583 assert invalidated == True
584 assert 'result' == result
585 assert isinstance(context, caches.FreshRegionCache)
586
587 assert 'InvalidationContext' in repr(invalidator_context)
608 # 3nd call, fresh caches
609 with inv_context_manager as invalidation_context:
610 should_invalidate = invalidation_context.should_invalidate()
611 if should_invalidate:
612 result = _dummy_func.refresh('some-key')
613 else:
614 result = _dummy_func('some-key')
588 615
589 with invalidator_context as context:
590 context.invalidate()
591 result = context.compute()
616 assert isinstance(invalidation_context, rc_cache.FreshRegionCache)
617 assert should_invalidate is True
592 618
593 assert 'result' == result
594 assert isinstance(context, caches.ActiveRegionCache)
619 assert 'result:2' == result
620
621 # cached again, same result
622 result = _dummy_func('some-key')
623 assert 'result:2' == result
595 624
596 625
597 626 def test_invalidation_context_exception_in_compute(baseapp):
598 from rhodecode.model.db import CacheKey
599 from beaker.cache import cache_region
627 repo_id = 888
600 628
601 @cache_region('long_term')
629 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
630 repo_id, CacheKey.CACHE_TYPE_README)
631 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
632 repo_id=repo_id)
633 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
634
635 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
602 636 def _dummy_func(cache_key):
603 # this causes error since it doesn't get any params
604 raise Exception('ups')
605
606 invalidator_context = CacheKey.repo_context_cache(
607 _dummy_func, 'test_repo_2', 'repo')
637 raise Exception('Error in cache func')
608 638
609 639 with pytest.raises(Exception):
610 with invalidator_context as context:
611 context.invalidate()
612 context.compute()
640 inv_context_manager = rc_cache.InvalidationContext(
641 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
642
643 # 1st call, fresh caches
644 with inv_context_manager as invalidation_context:
645 should_invalidate = invalidation_context.should_invalidate()
646 if should_invalidate:
647 _dummy_func.refresh('some-key-2')
648 else:
649 _dummy_func('some-key-2')
613 650
614 651
615 652 @pytest.mark.parametrize('execution_number', range(5))
616 653 def test_cache_invalidation_race_condition(execution_number, baseapp):
617 654 import time
618 from beaker.cache import cache_region
619 from rhodecode.model.db import CacheKey
655
656 repo_id = 777
620 657
621 if CacheKey.metadata.bind.url.get_backend_name() == "mysql":
622 reason = (
623 'Fails on MariaDB due to some locking issues. Investigation'
624 ' needed')
625 pytest.xfail(reason=reason)
658 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
659 repo_id, CacheKey.CACHE_TYPE_README)
660 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
661 repo_id=repo_id)
662 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
626 663
627 664 @run_test_concurrently(25)
628 665 def test_create_and_delete_cache_keys():
629 666 time.sleep(0.2)
630 667
631 @cache_region('long_term')
668 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
632 669 def _dummy_func(cache_key):
633 return 'result'
670 val = 'async'
671 return 'result:{}'.format(val)
672
673 inv_context_manager = rc_cache.InvalidationContext(
674 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
634 675
635 invalidator_context = CacheKey.repo_context_cache(
636 _dummy_func, 'test_repo_1', 'repo')
676 # 1st call, fresh caches
677 with inv_context_manager as invalidation_context:
678 should_invalidate = invalidation_context.should_invalidate()
679 if should_invalidate:
680 _dummy_func.refresh('some-key-3')
681 else:
682 _dummy_func('some-key-3')
637 683
638 with invalidator_context as context:
639 context.invalidate()
640 context.compute()
641
642 CacheKey.set_invalidate('test_repo_1', delete=True)
684 # Mark invalidation
685 CacheKey.set_invalidate(invalidation_namespace)
643 686
644 687 test_create_and_delete_cache_keys()
@@ -70,8 +70,7 b' def disable_hooks(request, hooks):'
70 70 ui_settings.invalidate()
71 71
72 72 ui_settings = session.query(db.RhodeCodeUi).options(
73 caching_query.FromCache(
74 'sql_cache_short', 'get_hook_settings', 'get_hook_settings'))
73 caching_query.FromCache('sql_cache_short', 'get_hook_settings'))
75 74 ui_settings.invalidate()
76 75
77 76 @request.addfinalizer
@@ -140,6 +140,10 b' class TestPermissions(object):'
140 140 assert repo_perms(user)[repo.repo_name] == 'repository.admin'
141 141 repo.user = org_owner
142 142
143 def test_default_owner_branch_perms(self, user_util, test_user_group):
144 user = user_util.create_user()
145 assert branch_perms(user) == {}
146
143 147 def test_default_owner_repo_group_perms(self, user_util, test_repo_group):
144 148 user = user_util.create_user()
145 149 org_owner = test_repo_group.user
@@ -360,13 +364,15 b' class TestPermissions(object):'
360 364 user_model.revoke_perm(self.u1, 'hg.fork.repository')
361 365 user_model.grant_perm(self.u1, 'hg.fork.none')
362 366
367 # TODO(marcink): check branch permissions now ?
368
363 369 # make sure inherit flag is turned off
364 370 self.u1.inherit_default_permissions = False
365 371 Session().commit()
366 372
367 373 # this user will have non inherited permissions from he's
368 374 # explicitly set permissions
369 assert global_perms(self.u1) == set([
375 assert global_perms(self.u1) == {
370 376 'hg.create.none',
371 377 'hg.fork.none',
372 378 'hg.register.manual_activate',
@@ -375,7 +381,8 b' class TestPermissions(object):'
375 381 'repository.read',
376 382 'group.read',
377 383 'usergroup.read',
378 ])
384 'branch.push_force',
385 }
379 386
380 387 def test_non_inherited_permissions_from_default_on_user_disabled(self):
381 388 user_model = UserModel()
@@ -396,9 +403,11 b' class TestPermissions(object):'
396 403 self.u1.inherit_default_permissions = False
397 404 Session().commit()
398 405
406 # TODO(marcink): check branch perms
407
399 408 # this user will have non inherited permissions from he's
400 409 # explicitly set permissions
401 assert global_perms(self.u1) == set([
410 assert global_perms(self.u1) == {
402 411 'hg.create.repository',
403 412 'hg.fork.repository',
404 413 'hg.register.manual_activate',
@@ -407,7 +416,8 b' class TestPermissions(object):'
407 416 'repository.read',
408 417 'group.read',
409 418 'usergroup.read',
410 ])
419 'branch.push_force',
420 }
411 421
412 422 @pytest.mark.parametrize('perm, expected_perm', [
413 423 ('hg.inherit_default_perms.false', 'repository.none', ),
@@ -425,8 +435,10 b' class TestPermissions(object):'
425 435 self.u1.inherit_default_permissions = True
426 436 Session().commit()
427 437
438 # TODO(marcink): check branch perms
439
428 440 # this user will have inherited permissions from default user
429 assert global_perms(self.u1) == set([
441 assert global_perms(self.u1) == {
430 442 'hg.create.none',
431 443 'hg.fork.none',
432 444 'hg.register.manual_activate',
@@ -435,11 +447,12 b' class TestPermissions(object):'
435 447 'repository.read',
436 448 'group.read',
437 449 'usergroup.read',
450 'branch.push_force',
438 451 'hg.create.write_on_repogroup.true',
439 452 'hg.usergroup.create.false',
440 453 'hg.repogroup.create.false',
441 perm,
442 ])
454 perm
455 }
443 456
444 457 assert set(repo_perms(self.u1).values()) == set([expected_perm])
445 458
@@ -693,6 +706,11 b' def repo_perms(user):'
693 706 return auth_user.permissions['repositories']
694 707
695 708
709 def branch_perms(user):
710 auth_user = AuthUser(user_id=user.user_id)
711 return auth_user.permissions['repository_branches']
712
713
696 714 def group_perms(user):
697 715 auth_user = AuthUser(user_id=user.user_id)
698 716 return auth_user.permissions['repositories_groups']
@@ -81,6 +81,7 b' class TestPullRequestModel(object):'
81 81 self.source_commit = self.pull_request.source_ref_parts.commit_id
82 82 self.target_commit = self.pull_request.target_ref_parts.commit_id
83 83 self.workspace_id = 'pr-%s' % self.pull_request.pull_request_id
84 self.repo_id = self.pull_request.target_repo.repo_id
84 85
85 86 @request.addfinalizer
86 87 def cleanup_pull_request():
@@ -135,17 +136,19 b' class TestPullRequestModel(object):'
135 136 assert pr_count == 1
136 137
137 138 def test_delete_calls_cleanup_merge(self, pull_request):
139 repo_id = pull_request.target_repo.repo_id
138 140 PullRequestModel().delete(pull_request, pull_request.author)
139 141
140 142 self.workspace_remove_mock.assert_called_once_with(
141 self.workspace_id)
143 repo_id, self.workspace_id)
142 144
143 145 def test_close_calls_cleanup_and_hook(self, pull_request):
144 146 PullRequestModel().close_pull_request(
145 147 pull_request, pull_request.author)
148 repo_id = pull_request.target_repo.repo_id
146 149
147 150 self.workspace_remove_mock.assert_called_once_with(
148 self.workspace_id)
151 repo_id, self.workspace_id)
149 152 self.hook_mock.assert_called_with(
150 153 self.pull_request, self.pull_request.author, 'close')
151 154
@@ -161,9 +164,10 b' class TestPullRequestModel(object):'
161 164 assert status is True
162 165 assert msg.eval() == 'This pull request can be automatically merged.'
163 166 self.merge_mock.assert_called_with(
167 self.repo_id, self.workspace_id,
164 168 pull_request.target_ref_parts,
165 169 pull_request.source_repo.scm_instance(),
166 pull_request.source_ref_parts, self.workspace_id, dry_run=True,
170 pull_request.source_ref_parts, dry_run=True,
167 171 use_rebase=False, close_branch=False)
168 172
169 173 assert pull_request._last_merge_source_rev == self.source_commit
@@ -190,9 +194,10 b' class TestPullRequestModel(object):'
190 194 msg.eval() ==
191 195 'This pull request cannot be merged because of merge conflicts.')
192 196 self.merge_mock.assert_called_with(
197 self.repo_id, self.workspace_id,
193 198 pull_request.target_ref_parts,
194 199 pull_request.source_repo.scm_instance(),
195 pull_request.source_ref_parts, self.workspace_id, dry_run=True,
200 pull_request.source_ref_parts, dry_run=True,
196 201 use_rebase=False, close_branch=False)
197 202
198 203 assert pull_request._last_merge_source_rev == self.source_commit
@@ -222,9 +227,10 b' class TestPullRequestModel(object):'
222 227 'This pull request cannot be merged because of an unhandled'
223 228 ' exception.')
224 229 self.merge_mock.assert_called_with(
230 self.repo_id, self.workspace_id,
225 231 pull_request.target_ref_parts,
226 232 pull_request.source_repo.scm_instance(),
227 pull_request.source_ref_parts, self.workspace_id, dry_run=True,
233 pull_request.source_ref_parts, dry_run=True,
228 234 use_rebase=False, close_branch=False)
229 235
230 236 assert pull_request._last_merge_source_rev is None
@@ -281,7 +287,7 b' class TestPullRequestModel(object):'
281 287 True, True, merge_ref, MergeFailureReason.NONE)
282 288
283 289 merge_extras['repository'] = pull_request.target_repo.repo_name
284 PullRequestModel().merge(
290 PullRequestModel().merge_repo(
285 291 pull_request, pull_request.author, extras=merge_extras)
286 292
287 293 message = (
@@ -295,9 +301,10 b' class TestPullRequestModel(object):'
295 301 )
296 302 )
297 303 self.merge_mock.assert_called_with(
304 self.repo_id, self.workspace_id,
298 305 pull_request.target_ref_parts,
299 306 pull_request.source_repo.scm_instance(),
300 pull_request.source_ref_parts, self.workspace_id,
307 pull_request.source_ref_parts,
301 308 user_name=user.username, user_email=user.email, message=message,
302 309 use_rebase=False, close_branch=False
303 310 )
@@ -320,7 +327,7 b' class TestPullRequestModel(object):'
320 327 False, False, merge_ref, MergeFailureReason.MERGE_FAILED)
321 328
322 329 merge_extras['repository'] = pull_request.target_repo.repo_name
323 PullRequestModel().merge(
330 PullRequestModel().merge_repo(
324 331 pull_request, pull_request.author, extras=merge_extras)
325 332
326 333 message = (
@@ -334,9 +341,10 b' class TestPullRequestModel(object):'
334 341 )
335 342 )
336 343 self.merge_mock.assert_called_with(
344 self.repo_id, self.workspace_id,
337 345 pull_request.target_ref_parts,
338 346 pull_request.source_repo.scm_instance(),
339 pull_request.source_ref_parts, self.workspace_id,
347 pull_request.source_ref_parts,
340 348 user_name=user.username, user_email=user.email, message=message,
341 349 use_rebase=False, close_branch=False
342 350 )
@@ -392,7 +400,7 b' class TestIntegrationMerge(object):'
392 400 Session().commit()
393 401
394 402 with mock.patch.dict(rhodecode.CONFIG, extra_config, clear=False):
395 merge_state = PullRequestModel().merge(
403 merge_state = PullRequestModel().merge_repo(
396 404 pull_request, user_admin, extras=merge_extras)
397 405
398 406 assert merge_state.executed
@@ -409,7 +417,7 b' class TestIntegrationMerge(object):'
409 417
410 418 with mock.patch('rhodecode.EXTENSIONS.PRE_PUSH_HOOK') as pre_pull:
411 419 pre_pull.side_effect = RepositoryError("Disallow push!")
412 merge_status = PullRequestModel().merge(
420 merge_status = PullRequestModel().merge_repo(
413 421 pull_request, user_admin, extras=merge_extras)
414 422
415 423 assert not merge_status.executed
@@ -429,7 +437,7 b' class TestIntegrationMerge(object):'
429 437 merge_extras['repository'] = pull_request.target_repo.repo_name
430 438 # TODO: johbo: Needed for sqlite, try to find an automatic way for it
431 439 Session().commit()
432 merge_status = PullRequestModel().merge(
440 merge_status = PullRequestModel().merge_repo(
433 441 pull_request, user_regular, extras=merge_extras)
434 442 assert not merge_status.executed
435 443
@@ -48,7 +48,7 b' def permissions_setup_func_orig('
48 48 repo_group = RepoGroup.get_by_group_name(group_name=group_name)
49 49 if not repo_group:
50 50 raise Exception('Cannot get group %s' % group_name)
51 perm_updates = [[test_u2_gr_id, perm, 'users_group']]
51 perm_updates = [[test_u2_gr_id, perm, 'user_group']]
52 52 RepoGroupModel().update_permissions(repo_group,
53 53 perm_updates=perm_updates,
54 54 recursive=recursive, check_perms=False)
1 NO CONTENT: file renamed from rhodecode/tests/controllers/test_utils.py to rhodecode/tests/other/test_views_utils.py
@@ -125,11 +125,6 b' def vcsserver_factory(tmpdir_factory):'
125 125 overrides = list(overrides)
126 126 overrides.append({'server:main': {'port': vcsserver_port}})
127 127
128 if is_cygwin():
129 platform_override = {'DEFAULT': {
130 'beaker.cache.repo_object.type': 'nocache'}}
131 overrides.append(platform_override)
132
133 128 option_name = 'vcsserver_config_http'
134 129 override_option_name = 'vcsserver_config_override'
135 130 config_file = get_config(
@@ -177,6 +172,7 b' def ini_config(request, tmpdir_factory, '
177 172 'vcs.server.protocol': 'http',
178 173 'vcs.scm_app_implementation': 'http',
179 174 'vcs.hooks.protocol': 'http',
175 'vcs.hooks.host': '127.0.0.1',
180 176 }},
181 177
182 178 {'handler_console': {
@@ -292,44 +292,27 b' cache_dir = %(here)s/data'
292 292 beaker.cache.data_dir = %(here)s/rc/data/cache/beaker_data
293 293 beaker.cache.lock_dir = %(here)s/rc/data/cache/beaker_lock
294 294
295 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
296
297 beaker.cache.super_short_term.type = memory
298 beaker.cache.super_short_term.expire = 1
299 beaker.cache.super_short_term.key_length = 256
300
301 beaker.cache.short_term.type = memory
302 beaker.cache.short_term.expire = 60
303 beaker.cache.short_term.key_length = 256
295 beaker.cache.regions = long_term
304 296
305 297 beaker.cache.long_term.type = memory
306 298 beaker.cache.long_term.expire = 36000
307 299 beaker.cache.long_term.key_length = 256
308 300
309 beaker.cache.sql_cache_short.type = memory
310 beaker.cache.sql_cache_short.expire = 1
311 beaker.cache.sql_cache_short.key_length = 256
301
302 #####################################
303 ### DOGPILE CACHE ####
304 #####################################
312 305
313 ## default is memory cache, configure only if required
314 ## using multi-node or multi-worker setup
315 #beaker.cache.auth_plugins.type = memory
316 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
317 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
318 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
319 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
320 #beaker.cache.auth_plugins.sa.pool_size = 10
321 #beaker.cache.auth_plugins.sa.max_overflow = 0
306 ## permission tree cache settings
307 rc_cache.cache_perms.backend = dogpile.cache.rc.file_namespace
308 rc_cache.cache_perms.expiration_time = 0
309 rc_cache.cache_perms.arguments.filename = /tmp/rc_cache_1
322 310
323 beaker.cache.repo_cache_long.type = memorylru_base
324 beaker.cache.repo_cache_long.max_items = 4096
325 beaker.cache.repo_cache_long.expire = 2592000
326 311
327 ## default is memorylru_base cache, configure only if required
328 ## using multi-node or multi-worker setup
329 #beaker.cache.repo_cache_long.type = ext:memcached
330 #beaker.cache.repo_cache_long.url = localhost:11211
331 #beaker.cache.repo_cache_long.expire = 1209600
332 #beaker.cache.repo_cache_long.key_length = 256
312 ## cache settings for SQL queries
313 rc_cache.sql_cache_short.backend = dogpile.cache.rc.memory_lru
314 rc_cache.sql_cache_short.expiration_time = 0
315
333 316
334 317 ####################################
335 318 ### BEAKER SESSION ####
@@ -525,6 +508,7 b' vcs.scm_app_implementation = http'
525 508 ## Push/Pull operations hooks protocol, available options are:
526 509 ## `http` - use http-rpc backend (default)
527 510 vcs.hooks.protocol = http
511 vcs.hooks.host = 127.0.0.1
528 512
529 513 vcs.server.log_level = debug
530 514 ## Start VCSServer with this instance as a subprocess, usefull for development
@@ -427,3 +427,32 b' def commit_change('
427 427 f_path=filename
428 428 )
429 429 return commit
430
431
432 def permission_update_data_generator(csrf_token, default=None, grant=None, revoke=None):
433 if not default:
434 raise ValueError('Permission for default user must be given')
435 form_data = [(
436 'csrf_token', csrf_token
437 )]
438 # add default
439 form_data.extend([
440 ('u_perm_1', default)
441 ])
442
443 if grant:
444 for cnt, (obj_id, perm, obj_name, obj_type) in enumerate(grant, 1):
445 form_data.extend([
446 ('perm_new_member_perm_new{}'.format(cnt), perm),
447 ('perm_new_member_id_new{}'.format(cnt), obj_id),
448 ('perm_new_member_name_new{}'.format(cnt), obj_name),
449 ('perm_new_member_type_new{}'.format(cnt), obj_type),
450
451 ])
452 if revoke:
453 for obj_id, obj_type in revoke:
454 form_data.extend([
455 ('perm_del_member_id_{}'.format(obj_id), obj_id),
456 ('perm_del_member_type_{}'.format(obj_id), obj_type),
457 ])
458 return form_data
@@ -566,7 +566,7 b' TODO: To be written...'
566 566
567 567 def test_maybe_prepare_merge_workspace(self):
568 568 workspace = self.repo._maybe_prepare_merge_workspace(
569 'pr2', Reference('branch', 'master', 'unused'),
569 2, 'pr2', Reference('branch', 'master', 'unused'),
570 570 Reference('branch', 'master', 'unused'))
571 571
572 572 assert os.path.isdir(workspace)
@@ -575,13 +575,13 b' TODO: To be written...'
575 575
576 576 # Calling it a second time should also succeed
577 577 workspace = self.repo._maybe_prepare_merge_workspace(
578 'pr2', Reference('branch', 'master', 'unused'),
578 2, 'pr2', Reference('branch', 'master', 'unused'),
579 579 Reference('branch', 'master', 'unused'))
580 580 assert os.path.isdir(workspace)
581 581
582 582 def test_maybe_prepare_merge_workspace_different_refs(self):
583 583 workspace = self.repo._maybe_prepare_merge_workspace(
584 'pr2', Reference('branch', 'master', 'unused'),
584 2, 'pr2', Reference('branch', 'master', 'unused'),
585 585 Reference('branch', 'develop', 'unused'))
586 586
587 587 assert os.path.isdir(workspace)
@@ -590,22 +590,22 b' TODO: To be written...'
590 590
591 591 # Calling it a second time should also succeed
592 592 workspace = self.repo._maybe_prepare_merge_workspace(
593 'pr2', Reference('branch', 'master', 'unused'),
593 2, 'pr2', Reference('branch', 'master', 'unused'),
594 594 Reference('branch', 'develop', 'unused'))
595 595 assert os.path.isdir(workspace)
596 596
597 597 def test_cleanup_merge_workspace(self):
598 598 workspace = self.repo._maybe_prepare_merge_workspace(
599 'pr3', Reference('branch', 'master', 'unused'),
599 2, 'pr3', Reference('branch', 'master', 'unused'),
600 600 Reference('branch', 'master', 'unused'))
601 self.repo.cleanup_merge_workspace('pr3')
601 self.repo.cleanup_merge_workspace(2, 'pr3')
602 602
603 603 assert not os.path.exists(workspace)
604 604
605 605 def test_cleanup_merge_workspace_invalid_workspace_id(self):
606 606 # No assert: because in case of an inexistent workspace this function
607 607 # should still succeed.
608 self.repo.cleanup_merge_workspace('pr4')
608 self.repo.cleanup_merge_workspace(1, 'pr4')
609 609
610 610 def test_set_refs(self):
611 611 test_ref = 'refs/test-refs/abcde'
@@ -31,7 +31,7 b' from rhodecode.lib.vcs.backends.hg impor'
31 31 from rhodecode.lib.vcs.exceptions import (
32 32 RepositoryError, VCSError, NodeDoesNotExistError, CommitDoesNotExistError)
33 33 from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
34 from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE
34 from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE, repo_id_generator
35 35
36 36
37 37 pytestmark = pytest.mark.backends("hg")
@@ -46,7 +46,6 b' def repo_path_generator():'
46 46 i += 1
47 47 yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
48 48
49
50 49 REPO_PATH_GENERATOR = repo_path_generator()
51 50
52 51
@@ -553,7 +552,7 b' TODO: To be written...'
553 552
554 553 def test_maybe_prepare_merge_workspace(self):
555 554 workspace = self.repo._maybe_prepare_merge_workspace(
556 'pr2', 'unused', 'unused2')
555 1, 'pr2', 'unused', 'unused2')
557 556
558 557 assert os.path.isdir(workspace)
559 558 workspace_repo = MercurialRepository(workspace)
@@ -561,20 +560,22 b' TODO: To be written...'
561 560
562 561 # Calling it a second time should also succeed
563 562 workspace = self.repo._maybe_prepare_merge_workspace(
564 'pr2', 'unused', 'unused2')
563 1, 'pr2', 'unused', 'unused2')
565 564 assert os.path.isdir(workspace)
566 565
567 566 def test_cleanup_merge_workspace(self):
568 567 workspace = self.repo._maybe_prepare_merge_workspace(
569 'pr3', 'unused', 'unused2')
570 self.repo.cleanup_merge_workspace('pr3')
568 1, 'pr3', 'unused', 'unused2')
569
570 assert os.path.isdir(workspace)
571 self.repo.cleanup_merge_workspace(1, 'pr3')
571 572
572 573 assert not os.path.exists(workspace)
573 574
574 575 def test_cleanup_merge_workspace_invalid_workspace_id(self):
575 576 # No assert: because in case of an inexistent workspace this function
576 577 # should still succeed.
577 self.repo.cleanup_merge_workspace('pr4')
578 self.repo.cleanup_merge_workspace(1, 'pr4')
578 579
579 580 def test_merge_target_is_bookmark(self, vcsbackend_hg):
580 581 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
@@ -594,10 +595,10 b' TODO: To be written...'
594 595 target_repo.bookmark(bookmark_name)
595 596 target_ref = Reference('book', bookmark_name, target_commit.raw_id)
596 597 source_ref = Reference('branch', default_branch, source_commit.raw_id)
597 workspace = 'test-merge'
598
598 workspace_id = 'test-merge'
599 repo_id = repo_id_generator(target_repo.path)
599 600 merge_response = target_repo.merge(
600 target_ref, source_repo, source_ref, workspace,
601 repo_id, workspace_id, target_ref, source_repo, source_ref,
601 602 'test user', 'test@rhodecode.com', 'merge message 1',
602 603 dry_run=False)
603 604 expected_merge_response = MergeResponse(
@@ -638,10 +639,10 b' TODO: To be written...'
638 639 source_repo._update(default_branch)
639 640 source_repo.bookmark(bookmark_name)
640 641 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
641 workspace = 'test-merge'
642
642 workspace_id = 'test-merge'
643 repo_id = repo_id_generator(target_repo.path)
643 644 merge_response = target_repo.merge(
644 target_ref, source_repo, source_ref, workspace,
645 repo_id, workspace_id, target_ref, source_repo, source_ref,
645 646 'test user', 'test@rhodecode.com', 'merge message 1',
646 647 dry_run=False)
647 648 expected_merge_response = MergeResponse(
@@ -677,14 +678,15 b' TODO: To be written...'
677 678
678 679 target_ref = Reference('branch', default_branch, target_commit.raw_id)
679 680 source_ref = Reference('branch', default_branch, source_commit.raw_id)
680 workspace = 'test-merge'
681 workspace_id = 'test-merge'
681 682
682 683 assert len(target_repo._heads(branch='default')) == 2
683 684 expected_merge_response = MergeResponse(
684 685 False, False, None,
685 686 MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
687 repo_id = repo_id_generator(target_repo.path)
686 688 merge_response = target_repo.merge(
687 target_ref, source_repo, source_ref, workspace,
689 repo_id, workspace_id, target_ref, source_repo, source_ref,
688 690 'test user', 'test@rhodecode.com', 'merge message 1',
689 691 dry_run=False)
690 692 assert merge_response == expected_merge_response
@@ -711,10 +713,11 b' TODO: To be written...'
711 713
712 714 target_ref = Reference('branch', default_branch, target_commit.raw_id)
713 715 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
714 workspace = 'test-merge'
716 repo_id = repo_id_generator(target_repo.path)
717 workspace_id = 'test-merge'
715 718
716 719 merge_response = target_repo.merge(
717 target_ref, source_repo, source_ref, workspace,
720 repo_id, workspace_id, target_ref, source_repo, source_ref,
718 721 'test user', 'test@rhodecode.com', 'merge message 1',
719 722 dry_run=False, use_rebase=True)
720 723
@@ -95,7 +95,7 b' class TestMercurialRemoteRepoInvalidatio'
95 95 references.
96 96 """
97 97 from rhodecode.model.pull_request import PullRequestModel
98
98 repo_id = pull_request.target_repo.repo_id
99 99 target_vcs = pull_request.target_repo.scm_instance()
100 100 target_ref = pull_request.target_ref_parts
101 101 source_ref = pull_request.source_ref_parts
@@ -104,7 +104,7 b' class TestMercurialRemoteRepoInvalidatio'
104 104 pr = PullRequestModel()
105 105 workspace_id = pr._workspace_id(pull_request)
106 106 shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
107 workspace_id, target_ref, source_ref)
107 repo_id, workspace_id, target_ref, source_ref)
108 108 shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
109 109
110 110 # This will populate the cache of the mercurial repository object
@@ -30,6 +30,7 b' from rhodecode.lib.vcs.backends.base imp'
30 30 from rhodecode.lib.vcs.exceptions import VCSError, RepositoryError
31 31 from rhodecode.lib.vcs.nodes import FileNode
32 32 from rhodecode.tests.vcs.conftest import BackendTestMixin
33 from rhodecode.tests import repo_id_generator
33 34
34 35
35 36 @pytest.mark.usefixtures("vcs_repository_support")
@@ -268,7 +269,7 b' class TestRepositoryGetCommonAncestor:'
268 269
269 270
270 271 @pytest.mark.backends("git", "hg")
271 class TestRepositoryMerge:
272 class TestRepositoryMerge(object):
272 273 def prepare_for_success(self, vcsbackend):
273 274 self.target_repo = vcsbackend.create_repo(number_of_commits=1)
274 275 self.source_repo = vcsbackend.clone_repo(self.target_repo)
@@ -287,7 +288,8 b' class TestRepositoryMerge:'
287 288 'branch', default_branch, self.target_commit.raw_id)
288 289 self.source_ref = Reference(
289 290 'branch', default_branch, self.source_commit.raw_id)
290 self.workspace = 'test-merge'
291 self.workspace_id = 'test-merge'
292 self.repo_id = repo_id_generator(self.target_repo.path)
291 293
292 294 def prepare_for_conflict(self, vcsbackend):
293 295 self.target_repo = vcsbackend.create_repo(number_of_commits=1)
@@ -302,13 +304,15 b' class TestRepositoryMerge:'
302 304 'branch', default_branch, self.target_commit.raw_id)
303 305 self.source_ref = Reference(
304 306 'branch', default_branch, self.source_commit.raw_id)
305 self.workspace = 'test-merge'
307 self.workspace_id = 'test-merge'
308 self.repo_id = repo_id_generator(self.target_repo.path)
306 309
307 310 def test_merge_success(self, vcsbackend):
308 311 self.prepare_for_success(vcsbackend)
309 312
310 313 merge_response = self.target_repo.merge(
311 self.target_ref, self.source_repo, self.source_ref, self.workspace,
314 self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
315 self.source_ref,
312 316 'test user', 'test@rhodecode.com', 'merge message 1',
313 317 dry_run=False)
314 318 expected_merge_response = MergeResponse(
@@ -334,7 +338,7 b' class TestRepositoryMerge:'
334 338 merge_response.merge_ref.commit_id)
335 339
336 340 merge_response = target_repo.merge(
337 target_ref, self.source_repo, self.source_ref, self.workspace,
341 self.repo_id, self.workspace_id, target_ref, self.source_repo, self.source_ref,
338 342 'test user', 'test@rhodecode.com', 'merge message 2',
339 343 dry_run=False)
340 344 expected_merge_response = MergeResponse(
@@ -353,13 +357,13 b' class TestRepositoryMerge:'
353 357 self.prepare_for_success(vcsbackend)
354 358
355 359 merge_response = self.target_repo.merge(
356 self.target_ref, self.source_repo, self.source_ref, self.workspace,
357 dry_run=True)
360 self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
361 self.source_ref, dry_run=True)
358 362
359 363 # We call it twice so to make sure we can handle updates
360 364 merge_response_update = self.target_repo.merge(
361 self.target_ref, self.source_repo, self.source_ref, self.workspace,
362 dry_run=True)
365 self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
366 self.source_ref, dry_run=True)
363 367
364 368 # Multiple merges may differ in their commit id. Therefore we set the
365 369 # commit id to `None` before comparing the merge responses.
@@ -381,13 +385,15 b' class TestRepositoryMerge:'
381 385 False, False, None, MergeFailureReason.MERGE_FAILED)
382 386
383 387 merge_response = self.target_repo.merge(
384 self.target_ref, self.source_repo, self.source_ref, self.workspace,
388 self.repo_id, self.workspace_id, self.target_ref,
389 self.source_repo, self.source_ref,
385 390 'test_user', 'test@rhodecode.com', 'test message', dry_run=dry_run)
386 391 assert merge_response == expected_merge_response
387 392
388 393 # We call it twice so to make sure we can handle updates
389 394 merge_response = self.target_repo.merge(
390 self.target_ref, self.source_repo, self.source_ref, self.workspace,
395 self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
396 self.source_ref,
391 397 'test_user', 'test@rhodecode.com', 'test message', dry_run=dry_run)
392 398 assert merge_response == expected_merge_response
393 399
@@ -400,8 +406,8 b' class TestRepositoryMerge:'
400 406 self.target_ref.type, self.target_ref.name, '0' * 40)
401 407
402 408 merge_response = self.target_repo.merge(
403 target_ref, self.source_repo, self.source_ref, self.workspace,
404 dry_run=True)
409 self.repo_id, self.workspace_id, target_ref, self.source_repo,
410 self.source_ref, dry_run=True)
405 411
406 412 assert merge_response == expected_merge_response
407 413
@@ -414,7 +420,8 b' class TestRepositoryMerge:'
414 420 self.source_ref.type, 'not_existing', self.source_ref.commit_id)
415 421
416 422 merge_response = self.target_repo.merge(
417 self.target_ref, self.source_repo, source_ref, self.workspace,
423 self.repo_id, self.workspace_id, self.target_ref,
424 self.source_repo, source_ref,
418 425 dry_run=True)
419 426
420 427 assert merge_response == expected_merge_response
@@ -427,29 +434,38 b' class TestRepositoryMerge:'
427 434 with mock.patch.object(self.target_repo, '_merge_repo',
428 435 side_effect=RepositoryError()):
429 436 merge_response = self.target_repo.merge(
430 self.target_ref, self.source_repo, self.source_ref,
431 self.workspace, dry_run=True)
437 self.repo_id, self.workspace_id, self.target_ref,
438 self.source_repo, self.source_ref,
439 dry_run=True)
432 440
433 441 assert merge_response == expected_merge_response
434 442
435 443 def test_merge_invalid_user_name(self, vcsbackend):
436 444 repo = vcsbackend.create_repo(number_of_commits=1)
437 445 ref = Reference('branch', 'master', 'not_used')
446 workspace_id = 'test-errors-in-merge'
447 repo_id = repo_id_generator(workspace_id)
438 448 with pytest.raises(ValueError):
439 repo.merge(ref, self, ref, 'workspace_id')
449 repo.merge(repo_id, workspace_id, ref, self, ref)
440 450
441 451 def test_merge_invalid_user_email(self, vcsbackend):
442 452 repo = vcsbackend.create_repo(number_of_commits=1)
443 453 ref = Reference('branch', 'master', 'not_used')
454 workspace_id = 'test-errors-in-merge'
455 repo_id = repo_id_generator(workspace_id)
444 456 with pytest.raises(ValueError):
445 repo.merge(ref, self, ref, 'workspace_id', 'user name')
457 repo.merge(
458 repo_id, workspace_id, ref, self, ref, 'user name')
446 459
447 460 def test_merge_invalid_message(self, vcsbackend):
448 461 repo = vcsbackend.create_repo(number_of_commits=1)
449 462 ref = Reference('branch', 'master', 'not_used')
463 workspace_id = 'test-errors-in-merge'
464 repo_id = repo_id_generator(workspace_id)
450 465 with pytest.raises(ValueError):
451 466 repo.merge(
452 ref, self, ref, 'workspace_id', 'user name', 'user@email.com')
467 repo_id, workspace_id, ref, self, ref,
468 'user name', 'user@email.com')
453 469
454 470
455 471 @pytest.mark.usefixtures("vcs_repository_support")
@@ -505,7 +521,7 b' class TestRepositoryStrip(BackendTestMix'
505 521
506 522
507 523 @pytest.mark.backends('hg', 'git')
508 class TestRepositoryPull:
524 class TestRepositoryPull(object):
509 525
510 526 def test_pull(self, vcsbackend):
511 527 source_repo = vcsbackend.repo
@@ -66,5 +66,5 b' class TestTags(BackendTestMixin):'
66 66 def test_name_with_slash(self):
67 67 self.repo.tag('19/10/11', 'joe')
68 68 assert '19/10/11' in self.repo.tags
69 self.repo.tag('11', 'joe')
70 assert '11' in self.repo.tags
69 self.repo.tag('rel.11', 'joe')
70 assert 'rel.11' in self.repo.tags
@@ -77,22 +77,18 b' class Command(object):'
77 77 assert self.process.returncode == 0
78 78
79 79
80 def _add_files_and_push(vcs, dest, clone_url=None, tags=None, **kwargs):
81 """
82 Generate some files, add it to DEST repo and push back
83 vcs is git or hg and defines what VCS we want to make those files for
84 """
85 # commit some stuff into this repo
80 def _add_files(vcs, dest, clone_url=None, tags=None, target_branch=None,
81 new_branch=False, **kwargs):
82 git_ident = "git config user.name {} && git config user.email {}".format(
83 'Marcin Kuźminski', 'me@email.com')
84 cwd = path = jn(dest)
85
86 86 tags = tags or []
87 cwd = path = jn(dest)
88 87 added_file = jn(path, '%ssetup.py' % tempfile._RandomNameSequence().next())
89 88 Command(cwd).execute('touch %s' % added_file)
90 89 Command(cwd).execute('%s add %s' % (vcs, added_file))
91 90 author_str = 'Marcin Kuźminski <me@email.com>'
92 91
93 git_ident = "git config user.name {} && git config user.email {}".format(
94 'Marcin Kuźminski', 'me@email.com')
95
96 92 for i in range(kwargs.get('files_no', 3)):
97 93 cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
98 94 Command(cwd).execute(cmd)
@@ -107,30 +103,55 b' def _add_files_and_push(vcs, dest, clone'
107 103
108 104 for tag in tags:
109 105 if vcs == 'hg':
110 stdout, stderr = Command(cwd).execute(
106 Command(cwd).execute(
111 107 'hg tag', tag['name'])
112 108 elif vcs == 'git':
113 109 if tag['commit']:
114 110 # annotated tag
115 stdout, stderr = Command(cwd).execute(
111 _stdout, _stderr = Command(cwd).execute(
116 112 """%s && git tag -a %s -m "%s" """ % (
117 113 git_ident, tag['name'], tag['commit']))
118 114 else:
119 115 # lightweight tag
120 stdout, stderr = Command(cwd).execute(
116 _stdout, _stderr = Command(cwd).execute(
121 117 """%s && git tag %s""" % (
122 118 git_ident, tag['name']))
123 119
120
121 def _add_files_and_push(vcs, dest, clone_url=None, tags=None, target_branch=None,
122 new_branch=False, **kwargs):
123 """
124 Generate some files, add it to DEST repo and push back
125 vcs is git or hg and defines what VCS we want to make those files for
126 """
127 git_ident = "git config user.name {} && git config user.email {}".format(
128 'Marcin Kuźminski', 'me@email.com')
129 cwd = path = jn(dest)
130
131 # commit some stuff into this repo
132 _add_files(vcs, dest, clone_url, tags, target_branch, new_branch, **kwargs)
133
134 default_target_branch = {
135 'git': 'master',
136 'hg': 'default'
137 }.get(vcs)
138
139 target_branch = target_branch or default_target_branch
140
124 141 # PUSH it back
125 142 stdout = stderr = None
126 143 if vcs == 'hg':
144 maybe_new_branch = ''
145 if new_branch:
146 maybe_new_branch = '--new-branch'
127 147 stdout, stderr = Command(cwd).execute(
128 'hg push --verbose', clone_url)
148 'hg push --verbose {} -r {} {}'.format(maybe_new_branch, target_branch, clone_url)
149 )
129 150 elif vcs == 'git':
130 151 stdout, stderr = Command(cwd).execute(
131 """%s &&
132 git push --verbose --tags %s master""" % (
133 git_ident, clone_url))
152 """{} &&
153 git push --verbose --tags {} {}""".format(git_ident, clone_url, target_branch)
154 )
134 155
135 156 return stdout, stderr
136 157
@@ -33,7 +33,8 b' import textwrap'
33 33 import pytest
34 34
35 35 from rhodecode import events
36 from rhodecode.model.db import Integration
36 from rhodecode.model.db import Integration, UserRepoToPerm, Permission, \
37 UserToRepoBranchPermission, User
37 38 from rhodecode.model.integration import IntegrationModel
38 39 from rhodecode.model.db import Repository
39 40 from rhodecode.model.meta import Session
@@ -238,13 +239,13 b' def enable_webhook_push_integration(requ'
238 239 Session().add(integration)
239 240
240 241 settings = dict(
241 url='http://httpbin.org',
242 url='http://httpbin.org/post',
242 243 secret_token='secret',
243 244 username=None,
244 245 password=None,
245 246 custom_header_key=None,
246 247 custom_header_val=None,
247 method_type='get',
248 method_type='post',
248 249 events=[events.RepoPushEvent.name],
249 250 log_data=True
250 251 )
@@ -267,3 +268,74 b' def enable_webhook_push_integration(requ'
267 268 Session().delete(integration)
268 269 Session().commit()
269 270
271
272 @pytest.fixture
273 def branch_permission_setter(request):
274 """
275
276 def my_test(branch_permission_setter)
277 branch_permission_setter(repo_name, username, pattern='*', permission='branch.push')
278
279 """
280
281 rule_id = None
282 write_perm_id = None
283
284 def _branch_permissions_setter(
285 repo_name, username, pattern='*', permission='branch.push_force'):
286 global rule_id, write_perm_id
287
288 repo = Repository.get_by_repo_name(repo_name)
289 repo_id = repo.repo_id
290
291 user = User.get_by_username(username)
292 user_id = user.user_id
293
294 rule_perm_obj = Permission.get_by_key(permission)
295
296 write_perm = None
297
298 # add new entry, based on existing perm entry
299 perm = UserRepoToPerm.query() \
300 .filter(UserRepoToPerm.repository_id == repo_id) \
301 .filter(UserRepoToPerm.user_id == user_id) \
302 .first()
303
304 if not perm:
305 # such user isn't defined in Permissions for repository
306 # we now on-the-fly add new permission
307
308 write_perm = UserRepoToPerm()
309 write_perm.permission = Permission.get_by_key('repository.write')
310 write_perm.repository_id = repo_id
311 write_perm.user_id = user_id
312 Session().add(write_perm)
313 Session().flush()
314
315 perm = write_perm
316
317 rule = UserToRepoBranchPermission()
318 rule.rule_to_perm_id = perm.repo_to_perm_id
319 rule.branch_pattern = pattern
320 rule.rule_order = 10
321 rule.permission = rule_perm_obj
322 rule.repository_id = repo_id
323 Session().add(rule)
324 Session().commit()
325
326 global rule, write_perm
327
328 return rule
329
330 @request.addfinalizer
331 def cleanup():
332 if rule:
333 Session().delete(rule)
334 Session().commit()
335 if write_perm:
336 Session().delete(write_perm)
337 Session().commit()
338
339 return _branch_permissions_setter
340
341
@@ -32,6 +32,7 b' import time'
32 32
33 33 import pytest
34 34
35 from rhodecode.lib import rc_cache
35 36 from rhodecode.model.auth_token import AuthTokenModel
36 37 from rhodecode.model.db import Repository, UserIpMap, CacheKey
37 38 from rhodecode.model.meta import Session
@@ -217,46 +218,44 b' class TestVCSOperations(object):'
217 218
218 219 _check_proper_git_push(stdout, stderr)
219 220
220 def test_push_invalidates_cache_hg(self, rc_web_server, tmpdir):
221 key = CacheKey.query().filter(CacheKey.cache_key == HG_REPO).scalar()
222 if not key:
223 key = CacheKey(HG_REPO, HG_REPO)
221 def test_push_invalidates_cache(self, rc_web_server, tmpdir):
222 hg_repo = Repository.get_by_repo_name(HG_REPO)
223
224 # init cache objects
225 CacheKey.delete_all_cache()
226 cache_namespace_uid = 'cache_push_test.{}'.format(hg_repo.repo_id)
227 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
228 repo_id=hg_repo.repo_id)
224 229
225 key.cache_active = True
226 Session().add(key)
227 Session().commit()
230 inv_context_manager = rc_cache.InvalidationContext(
231 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
228 232
229 clone_url = rc_web_server.repo_clone_url(HG_REPO)
233 with inv_context_manager as invalidation_context:
234 # __enter__ will create and register cache objects
235 pass
236
237 # clone to init cache
238 clone_url = rc_web_server.repo_clone_url(hg_repo.repo_name)
230 239 stdout, stderr = Command('/tmp').execute(
231 240 'hg clone', clone_url, tmpdir.strpath)
232 241
242 cache_keys = hg_repo.cache_keys
243 assert cache_keys != []
244 for key in cache_keys:
245 assert key.cache_active is True
246
247 # PUSH that should trigger invalidation cache
233 248 stdout, stderr = _add_files_and_push(
234 249 'hg', tmpdir.strpath, clone_url=clone_url, files_no=1)
235 250
236 key = CacheKey.query().filter(CacheKey.cache_key == HG_REPO).one()
237 assert key.cache_active is False
238
239 def test_push_invalidates_cache_git(self, rc_web_server, tmpdir):
240 key = CacheKey.query().filter(CacheKey.cache_key == GIT_REPO).scalar()
241 if not key:
242 key = CacheKey(GIT_REPO, GIT_REPO)
243
244 key.cache_active = True
245 Session().add(key)
251 # flush...
246 252 Session().commit()
247
248 clone_url = rc_web_server.repo_clone_url(GIT_REPO)
249 stdout, stderr = Command('/tmp').execute(
250 'git clone', clone_url, tmpdir.strpath)
251
252 # commit some stuff into this repo
253 stdout, stderr = _add_files_and_push(
254 'git', tmpdir.strpath, clone_url=clone_url, files_no=1)
255 _check_proper_git_push(stdout, stderr)
256
257 key = CacheKey.query().filter(CacheKey.cache_key == GIT_REPO).one()
258
259 assert key.cache_active is False
253 hg_repo = Repository.get_by_repo_name(HG_REPO)
254 cache_keys = hg_repo.cache_keys
255 assert cache_keys != []
256 for key in cache_keys:
257 # keys should be marked as not active
258 assert key.cache_active is False
260 259
261 260 def test_push_wrong_credentials_hg(self, rc_web_server, tmpdir):
262 261 clone_url = rc_web_server.repo_clone_url(HG_REPO)
@@ -25,11 +25,17 b' import os'
25 25 import sys
26 26 import pkgutil
27 27 import platform
28 import codecs
28 29
29 from pip.download import PipSession
30 from pip.req import parse_requirements
30 try: # for pip >= 10
31 from pip._internal.req import parse_requirements
32 except ImportError: # for pip <= 9.0.3
33 from pip.req import parse_requirements
31 34
32 from codecs import open
35 try: # for pip >= 10
36 from pip._internal.download import PipSession
37 except ImportError: # for pip <= 9.0.3
38 from pip.download import PipSession
33 39
34 40
35 41 if sys.version_info < (2, 7):
@@ -96,8 +102,8 b" keywords = ' '.join(["
96 102 readme_file = 'README.rst'
97 103 changelog_file = 'CHANGES.rst'
98 104 try:
99 long_description = open(readme_file).read() + '\n\n' + \
100 open(changelog_file).read()
105 long_description = codecs.open(readme_file).read() + '\n\n' + \
106 codecs.open(changelog_file).read()
101 107 except IOError as err:
102 108 sys.stderr.write(
103 109 "[WARNING] Cannot find file specified as long_description (%s)\n "
@@ -113,7 +119,7 b' setup('
113 119 keywords=keywords,
114 120 license=__license__,
115 121 author=__author__,
116 author_email='marcin@rhodecode.com',
122 author_email='support@rhodecode.com',
117 123 url=__url__,
118 124 setup_requires=setup_requirements,
119 125 install_requires=install_requirements,
@@ -176,8 +182,8 b' setup('
176 182 'rc-ssh-wrapper=rhodecode.apps.ssh_support.lib.ssh_wrapper:main',
177 183 ],
178 184 'beaker.backends': [
179 'memorylru_base=rhodecode.lib.memory_lru_debug:MemoryLRUNamespaceManagerBase',
180 'memorylru_debug=rhodecode.lib.memory_lru_debug:MemoryLRUNamespaceManagerDebug'
185 'memorylru_base=rhodecode.lib.memory_lru_dict:MemoryLRUNamespaceManagerBase',
186 'memorylru_debug=rhodecode.lib.memory_lru_dict:MemoryLRUNamespaceManagerDebug'
181 187 ]
182 188 },
183 189 )
@@ -1,6 +1,9 b''
1 # This file contains the adjustments which are desired for a development
2 # environment.
3
1 4 { pkgs ? (import <nixpkgs> {})
2 5 , pythonPackages ? "python27Packages"
3 , doCheck ? true
6 , doCheck ? false
4 7 , sourcesOverrides ? {}
5 8 , doDevelopInstall ? true
6 9 }:
@@ -10,7 +13,10 b' let'
10 13 sources = (pkgs.config.rc.sources or {}) // sourcesOverrides;
11 14
12 15 enterprise-ce = import ./default.nix {
13 inherit pkgs pythonPackages doCheck;
16 inherit
17 pkgs
18 pythonPackages
19 doCheck;
14 20 };
15 21
16 22 ce-pythonPackages = enterprise-ce.pythonPackages;
@@ -22,14 +28,17 b' let'
22 28 let
23 29 path = pkgs.lib.attrByPath [attributeName] null sources;
24 30 doIt = doDevelopInstall && path != null;
31
25 32 in
26 pkgs.lib.optionalString doIt (
27 builtins.trace "Develop install of ${attributeName} from ${path}" ''
28 echo "Develop install of '${attributeName}' from '${path}' [BEGIN]"
33 # do develop installation with empty hosts to skip any package duplicates to
34 # be replaced. This only pushes the package to be locally available
35 pkgs.lib.optionalString doIt (''
36 echo "[BEGIN] Develop install of '${attributeName}' from '${path}'"
29 37 pushd ${path}
30 38 python setup.py develop --prefix $tmp_path --allow-hosts ""
31 39 popd
32 echo "Develop install of '${attributeName}' from '${path}' [DONE]"
40 echo "[DONE] Develop install of '${attributeName}' from '${path}'"
41 echo ""
33 42 '');
34 43
35 44 # This method looks up a path from `pkgs.config.rc.sources` and imports the
@@ -38,13 +47,16 b' let'
38 47 optionalDevelopInstallBuildInputs = attributeName:
39 48 let
40 49 path = pkgs.lib.attrByPath [attributeName] null sources;
50 doIt = doDevelopInstall && path != null && pkgs.lib.pathExists "${nixFile}";
41 51 nixFile = "${path}/default.nix";
42 doIt = doDevelopInstall && path != null && pkgs.lib.pathExists "${nixFile}";
52
43 53 derivate = import "${nixFile}" {
44 54 inherit doCheck pkgs pythonPackages;
45 55 };
46 56 in
47 pkgs.lib.lists.optionals doIt derivate.propagatedNativeBuildInputs;
57 pkgs.lib.lists.optionals doIt (
58 derivate.propagatedBuildInputs
59 );
48 60
49 61 developInstalls = [ "rhodecode-vcsserver" ];
50 62
@@ -53,31 +65,52 b' in enterprise-ce.override (attrs: {'
53 65 # make development a little bit more convenient.
54 66 src = null;
55 67
68 # Add dependencies which are useful for the development environment.
56 69 buildInputs =
57 70 attrs.buildInputs ++
58 pkgs.lib.lists.concatMap optionalDevelopInstallBuildInputs developInstalls ++
59 71 (with ce-pythonPackages; [
60 72 bumpversion
61 73 invoke
62 74 ipdb
63 75 ]);
64 76
65 # Somewhat snappier setup of the development environment
66 # TODO: think of supporting a stable path again, so that multiple shells
67 # can share it.
68 preShellHook = enterprise-ce.linkNodeAndBowerPackages + ''
77 # place to inject some required libs from develop installs
78 propagatedBuildInputs =
79 attrs.propagatedBuildInputs ++
80 pkgs.lib.lists.concatMap optionalDevelopInstallBuildInputs developInstalls;
81
82
83 # Make sure we execute both hooks
84 shellHook = ''
85 runHook preShellHook
86 runHook postShellHook
87 '';
88
89 preShellHook = ''
90 echo "Entering CE-Shell"
91
69 92 # Custom prompt to distinguish from other dev envs.
70 93 export PS1="\n\[\033[1;32m\][CE-shell:\w]$\[\033[0m\] "
71 94
95 echo "Building frontend assets"
96 ${enterprise-ce.linkNodeAndBowerPackages}
97
72 98 # Setup a temporary directory.
73 99 tmp_path=$(mktemp -d)
74 100 export PATH="$tmp_path/bin:$PATH"
75 101 export PYTHONPATH="$tmp_path/${ce-pythonPackages.python.sitePackages}:$PYTHONPATH"
76 102 mkdir -p $tmp_path/${ce-pythonPackages.python.sitePackages}
77 103
78 # Develop installations
104 # Develop installation
105 echo "[BEGIN]: develop install of rhodecode-enterprise-ce"
79 106 python setup.py develop --prefix $tmp_path --allow-hosts ""
80 echo "Additional develop installs"
81 '' + pkgs.lib.strings.concatMapStrings optionalDevelopInstall developInstalls;
107 '';
108
109 postShellHook = ''
110 echo "** Additional develop installs **"
111 '' +
112 pkgs.lib.strings.concatMapStrings optionalDevelopInstall developInstalls
113 + ''
114 '';
82 115
83 116 })
@@ -1,68 +0,0 b''
1 # Backported buildBowerComponents so that we can also use it with the version
2 # 16.03 which is the current stable at the time of this writing.
3 #
4 # This file can be removed once building with 16.03 is not needed anymore.
5
6 { pkgs }:
7
8 { buildInputs ? [], generated, ... } @ attrs:
9
10 let
11 bower2nix-src = pkgs.fetchzip {
12 url = "https://github.com/rvl/bower2nix/archive/v3.0.1.tar.gz";
13 sha256 = "1zbvz96k2j6g0r4lvm5cgh41a73k9dgayk7x63cmg538dzznxvyb";
14 };
15
16 bower2nix = import "${bower2nix-src}/default.nix" { inherit pkgs; };
17
18 fetchbower = import ./backport-16.03-fetchbower.nix {
19 inherit (pkgs) stdenv lib;
20 inherit bower2nix;
21 };
22
23 # Fetches the bower packages. `generated` should be the result of a
24 # `bower2nix` command.
25 bowerPackages = import generated {
26 inherit (pkgs) buildEnv;
27 inherit fetchbower;
28 };
29
30 in pkgs.stdenv.mkDerivation (
31 attrs
32 //
33 {
34 name = "bower_components-" + attrs.name;
35
36 inherit bowerPackages;
37
38 builder = builtins.toFile "builder.sh" ''
39 source $stdenv/setup
40
41 # The project's bower.json is required
42 cp $src/bower.json .
43
44 # Dereference symlinks -- bower doesn't like them
45 cp --recursive --reflink=auto \
46 --dereference --no-preserve=mode \
47 $bowerPackages bc
48
49 # Bower install in offline mode -- links together the fetched
50 # bower packages.
51 HOME=$PWD bower \
52 --config.registry=https://registry.bower.io \
53 --config.storage.packages=bc/packages \
54 --config.storage.registry=bc/registry \
55 install
56
57 # Sets up a single bower_components directory within
58 # the output derivation.
59 mkdir -p $out
60 mv bower_components $out
61 '';
62
63 buildInputs = buildInputs ++ [
64 pkgs.git
65 pkgs.nodePackages.bower
66 ];
67 }
68 )
@@ -1,26 +0,0 b''
1 { stdenv, lib, bower2nix }:
2 let
3 bowerVersion = version:
4 let
5 components = lib.splitString "#" version;
6 hash = lib.last components;
7 ver = if builtins.length components == 1 then version else hash;
8 in ver;
9
10 fetchbower = name: version: target: outputHash: stdenv.mkDerivation {
11 name = "${name}-${bowerVersion version}";
12 buildCommand = ''
13 fetch-bower --quiet --out=$PWD/out "${name}" "${target}" "${version}"
14 # In some cases, the result of fetchBower is different depending
15 # on the output directory (e.g. if the bower package contains
16 # symlinks). So use a local output directory before copying to
17 # $out.
18 cp -R out $out
19 '';
20 outputHashMode = "recursive";
21 outputHashAlgo = "sha256";
22 inherit outputHash;
23 buildInputs = [ bower2nix ];
24 };
25
26 in fetchbower
@@ -1,269 +0,0 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2015-2018 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 beaker
23 import logging
24 import threading
25
26 from beaker.cache import _cache_decorate, cache_regions, region_invalidate
27 from sqlalchemy.exc import IntegrityError
28
29 from rhodecode.lib.utils import safe_str, md5
30 from rhodecode.model.db import Session, CacheKey
31
32 log = logging.getLogger(__name__)
33
34 FILE_TREE = 'cache_file_tree'
35 FILE_TREE_META = 'cache_file_tree_metadata'
36 FILE_SEARCH_TREE_META = 'cache_file_search_metadata'
37 SUMMARY_STATS = 'cache_summary_stats'
38
39 # This list of caches gets purged when invalidation happens
40 USED_REPO_CACHES = (FILE_TREE, FILE_SEARCH_TREE_META)
41
42 DEFAULT_CACHE_MANAGER_CONFIG = {
43 'type': 'memorylru_base',
44 'max_items': 10240,
45 'key_length': 256,
46 'enabled': True
47 }
48
49
50 def get_default_cache_settings(settings):
51 cache_settings = {}
52 for key in settings.keys():
53 for prefix in ['beaker.cache.', 'cache.']:
54 if key.startswith(prefix):
55 name = key.split(prefix)[1].strip()
56 cache_settings[name] = settings[key].strip()
57 return cache_settings
58
59
60 # set cache regions for beaker so celery can utilise it
61 def configure_caches(settings, default_region_settings=None):
62 cache_settings = {'regions': None}
63 # main cache settings used as default ...
64 cache_settings.update(get_default_cache_settings(settings))
65 default_region_settings = default_region_settings or \
66 {'type': DEFAULT_CACHE_MANAGER_CONFIG['type']}
67 if cache_settings['regions']:
68 for region in cache_settings['regions'].split(','):
69 region = region.strip()
70 region_settings = default_region_settings.copy()
71 for key, value in cache_settings.items():
72 if key.startswith(region):
73 region_settings[key.split(region + '.')[-1]] = value
74 log.debug('Configuring cache region `%s` with settings %s',
75 region, region_settings)
76 configure_cache_region(
77 region, region_settings, cache_settings)
78
79
80 def configure_cache_region(
81 region_name, region_settings, default_cache_kw, default_expire=60):
82 default_type = default_cache_kw.get('type', 'memory')
83 default_lock_dir = default_cache_kw.get('lock_dir')
84 default_data_dir = default_cache_kw.get('data_dir')
85
86 region_settings['lock_dir'] = region_settings.get('lock_dir', default_lock_dir)
87 region_settings['data_dir'] = region_settings.get('data_dir', default_data_dir)
88 region_settings['type'] = region_settings.get('type', default_type)
89 region_settings['expire'] = int(region_settings.get('expire', default_expire))
90
91 beaker.cache.cache_regions[region_name] = region_settings
92
93
94 def get_cache_manager(region_name, cache_name, custom_ttl=None):
95 """
96 Creates a Beaker cache manager. Such instance can be used like that::
97
98 _namespace = caches.get_repo_namespace_key(caches.XXX, repo_name)
99 cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
100 _cache_key = caches.compute_key_from_params(repo_name, commit.raw_id)
101 def heavy_compute():
102 ...
103 result = cache_manager.get(_cache_key, createfunc=heavy_compute)
104
105 :param region_name: region from ini file
106 :param cache_name: custom cache name, usually prefix+repo_name. eg
107 file_switcher_repo1
108 :param custom_ttl: override .ini file timeout on this cache
109 :return: instance of cache manager
110 """
111
112 cache_config = cache_regions.get(region_name, DEFAULT_CACHE_MANAGER_CONFIG)
113 if custom_ttl:
114 log.debug('Updating region %s with custom ttl: %s',
115 region_name, custom_ttl)
116 cache_config.update({'expire': custom_ttl})
117
118 return beaker.cache.Cache._get_cache(cache_name, cache_config)
119
120
121 def clear_cache_manager(cache_manager):
122 """
123 namespace = 'foobar'
124 cache_manager = get_cache_manager('repo_cache_long', namespace)
125 clear_cache_manager(cache_manager)
126 """
127
128 log.debug('Clearing all values for cache manager %s', cache_manager)
129 cache_manager.clear()
130
131
132 def clear_repo_caches(repo_name):
133 # invalidate cache manager for this repo
134 for prefix in USED_REPO_CACHES:
135 namespace = get_repo_namespace_key(prefix, repo_name)
136 cache_manager = get_cache_manager('repo_cache_long', namespace)
137 clear_cache_manager(cache_manager)
138
139
140 def compute_key_from_params(*args):
141 """
142 Helper to compute key from given params to be used in cache manager
143 """
144 return md5("_".join(map(safe_str, args)))
145
146
147 def get_repo_namespace_key(prefix, repo_name):
148 return '{0}_{1}'.format(prefix, compute_key_from_params(repo_name))
149
150
151 def conditional_cache(region, prefix, condition, func):
152 """
153 Conditional caching function use like::
154 def _c(arg):
155 # heavy computation function
156 return data
157
158 # depending on the condition the compute is wrapped in cache or not
159 compute = conditional_cache('short_term', 'cache_desc',
160 condition=True, func=func)
161 return compute(arg)
162
163 :param region: name of cache region
164 :param prefix: cache region prefix
165 :param condition: condition for cache to be triggered, and
166 return data cached
167 :param func: wrapped heavy function to compute
168
169 """
170 wrapped = func
171 if condition:
172 log.debug('conditional_cache: True, wrapping call of '
173 'func: %s into %s region cache', region, func)
174 cached_region = _cache_decorate((prefix,), None, None, region)
175 wrapped = cached_region(func)
176 return wrapped
177
178
179 class ActiveRegionCache(object):
180 def __init__(self, context):
181 self.context = context
182
183 def invalidate(self, *args, **kwargs):
184 return False
185
186 def compute(self):
187 log.debug('Context cache: getting obj %s from cache', self.context)
188 return self.context.compute_func(self.context.cache_key)
189
190
191 class FreshRegionCache(ActiveRegionCache):
192 def invalidate(self):
193 log.debug('Context cache: invalidating cache for %s', self.context)
194 region_invalidate(
195 self.context.compute_func, None, self.context.cache_key)
196 return True
197
198
199 class InvalidationContext(object):
200 def __repr__(self):
201 return '<InvalidationContext:{}[{}]>'.format(
202 safe_str(self.repo_name), safe_str(self.cache_type))
203
204 def __init__(self, compute_func, repo_name, cache_type,
205 raise_exception=False, thread_scoped=False):
206 self.compute_func = compute_func
207 self.repo_name = repo_name
208 self.cache_type = cache_type
209 self.cache_key = compute_key_from_params(
210 repo_name, cache_type)
211 self.raise_exception = raise_exception
212
213 # Append the thread id to the cache key if this invalidation context
214 # should be scoped to the current thread.
215 if thread_scoped:
216 thread_id = threading.current_thread().ident
217 self.cache_key = '{cache_key}_{thread_id}'.format(
218 cache_key=self.cache_key, thread_id=thread_id)
219
220 def get_cache_obj(self):
221 cache_key = CacheKey.get_cache_key(
222 self.repo_name, self.cache_type)
223 cache_obj = CacheKey.get_active_cache(cache_key)
224 if not cache_obj:
225 cache_obj = CacheKey(cache_key, self.repo_name)
226 return cache_obj
227
228 def __enter__(self):
229 """
230 Test if current object is valid, and return CacheRegion function
231 that does invalidation and calculation
232 """
233
234 self.cache_obj = self.get_cache_obj()
235 if self.cache_obj.cache_active:
236 # means our cache obj is existing and marked as it's
237 # cache is not outdated, we return BaseInvalidator
238 self.skip_cache_active_change = True
239 return ActiveRegionCache(self)
240
241 # the key is either not existing or set to False, we return
242 # the real invalidator which re-computes value. We additionally set
243 # the flag to actually update the Database objects
244 self.skip_cache_active_change = False
245 return FreshRegionCache(self)
246
247 def __exit__(self, exc_type, exc_val, exc_tb):
248
249 if self.skip_cache_active_change:
250 return
251
252 try:
253 self.cache_obj.cache_active = True
254 Session().add(self.cache_obj)
255 Session().commit()
256 except IntegrityError:
257 # if we catch integrity error, it means we inserted this object
258 # assumption is that's really an edge race-condition case and
259 # it's safe is to skip it
260 Session().rollback()
261 except Exception:
262 log.exception('Failed to commit on cache key update')
263 Session().rollback()
264 if self.raise_exception:
265 raise
266
267
268 def includeme(config):
269 configure_caches(config.registry.settings)
General Comments 0
You need to be logged in to leave comments. Login now