release: Merge default into stable for release preparation

This commit is contained in:
Marcin Kuzminski 2019-07-03 14:38:34 +00:00
commit 89d54f218a
334 changed files with 21428 additions and 5130 deletions

View file

@ -1,5 +1,5 @@
[bumpversion]
current_version = 4.16.2
current_version = 4.17.0
message = release: Bump version {current_version} to {new_version}
[bumpversion:file:rhodecode/VERSION]

View file

@ -5,26 +5,21 @@ done = false
done = true
[task:rc_tools_pinned]
done = true
[task:fixes_on_stable]
done = true
[task:pip2nix_generated]
done = true
[task:changelog_updated]
done = true
[task:generate_api_docs]
done = true
[release]
state = prepared
version = 4.16.2
[task:updated_translation]
[release]
state = in_progress
version = 4.17.0
[task:generate_js_routes]
[task:updated_trial_license]

View file

@ -53,3 +53,12 @@ web-build:
generate-pkgs:
nix-shell pkgs/shell-generate.nix --command "pip2nix generate --licenses"
generate-js-pkgs:
rm -rf node_modules && \
nix-shell pkgs/shell-generate.nix --command "node2nix --input package.json -o pkgs/node-packages.nix -e pkgs/node-env.nix -c pkgs/node-default.nix -d --flatten --nodejs-8" && \
sed -i -e 's/http:\/\//https:\/\//g' pkgs/node-packages.nix
generate-license-meta:
nix-build pkgs/license-generate.nix -o result-license && \
cat result-license/licenses.json | python -m json.tool > rhodecode/config/licenses.json

View file

@ -133,6 +133,11 @@ rhodecode.api.url = /_admin/api
## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
#rhodecode.encrypted_values.strict = false
## Pick algorithm for encryption. Either fernet (more secure) or aes (default)
## fernet is safer, and we strongly recommend switching to it.
## Due to backward compatibility aes is used as default.
#rhodecode.encrypted_values.algorithm = fernet
## return gzipped responses from RhodeCode (static files/application)
gzip_responses = false
@ -374,6 +379,10 @@ rc_cache.cache_repo_longterm.max_size = 10000
beaker.session.type = file
beaker.session.data_dir = %(here)s/data/sessions
## redis sessions
#beaker.session.type = ext:redis
#beaker.session.url = redis://127.0.0.1:6379/2
## db based session, fast, and allows easy management over logged in users
#beaker.session.type = ext:database
#beaker.session.table_name = db_session

View file

@ -30,10 +30,12 @@ loglevel = 'debug'
# SECURITY
# The maximum size of HTTP request line in bytes.
limit_request_line = 4094
# 0 for unlimited
limit_request_line = 0
# Limit the number of HTTP headers fields in a request.
limit_request_fields = 1024
# By default this value is 100 and can’t be larger than 32768.
limit_request_fields = 10240
# Limit the allowed size of an HTTP request header field.
# Value is a positive number or 0.

View file

@ -108,6 +108,11 @@ use = egg:rhodecode-enterprise-ce
## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
#rhodecode.encrypted_values.strict = false
## Pick algorithm for encryption. Either fernet (more secure) or aes (default)
## fernet is safer, and we strongly recommend switching to it.
## Due to backward compatibility aes is used as default.
#rhodecode.encrypted_values.algorithm = fernet
## return gzipped responses from RhodeCode (static files/application)
gzip_responses = false
@ -349,6 +354,10 @@ rc_cache.cache_repo_longterm.max_size = 10000
beaker.session.type = file
beaker.session.data_dir = %(here)s/data/sessions
## redis sessions
#beaker.session.type = ext:redis
#beaker.session.url = redis://127.0.0.1:6379/2
## db based session, fast, and allows easy management over logged in users
#beaker.session.type = ext:database
#beaker.session.table_name = db_session

View file

@ -191,7 +191,7 @@ let
# check required files
STATIC_CHECK="/robots.txt /502.html
/js/scripts.js /js/rhodecode-components.js
/css/style.css /css/style-polymer.css"
/css/style.css /css/style-polymer.css /css/style-ipython.css"
for file in $STATIC_CHECK;
do

View file

@ -1,3 +1,4 @@
.. _repo-admin-set:
.. _permissions-info-add-group-ref:
Repository Administration
@ -18,9 +19,10 @@ settings for your needs:
.. toctree::
repo-perm-steps
repo-extra-fields
repo-hooks
repo-issue-tracker
repo-vcs
repo_admin/repo-perm-steps
repo_admin/repo-extra-fields
repo_admin/repo-hooks
repo_admin/repo-issue-tracker
repo_admin/repo-vcs
repo_admin/restore-deleted-repositories
repo_admin/repo-admin-tasks

View file

@ -0,0 +1,24 @@
.. _repo-admin-tasks:
Common Admin Tasks for Repositories
-----------------------------------
Manually Force Delete Repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In case of attached forks or pull-requests repositories should be archived.
Here is how to force delete a repository and remove all dependent objects
.. code-block:: bash
# starts the ishell interactive prompt
$ rccontrol ishell enterprise-1
.. code-block:: python
In [4]: from rhodecode.model.repo import RepoModel
In [3]: repo = Repository.get_by_repo_name('test_repos/repo_with_prs')
In [5]: RepoModel().delete(repo, forks='detach', pull_requests='delete')
In [6]: Session().commit()

View file

@ -29,7 +29,7 @@ To configure extra fields per repository, use the following steps:
beside the |repo| to which you wish to add extra fields.
2. On the |repo| settings page, select the :guilabel:`Extra fields` tab.
.. image:: ../images/extra-repo-fields.png
.. image:: ../../images/extra-repo-fields.png
The most important is the `New field key` variable which under the value will
be stored. It needs to be unique for each repository. The label and description

View file

@ -16,19 +16,17 @@ The following are the most common system administration tasks.
.. toctree::
config-files-overview
vcs-server
svn-http
svn-path-permissions
gunicorn-ssl-support
apache-config
nginx-config
backup-restore
tuning-rhodecode
indexing
reset-information
enable-debug
admin-tricks
cleanup-cmds
restore-deleted-repositories
system_admin/config-files-overview
system_admin/vcs-server
system_admin/svn-http
system_admin/svn-path-permissions
system_admin/gunicorn-ssl-support
system_admin/apache-config
system_admin/nginx-config
system_admin/backup-restore
system_admin/tuning-rhodecode
system_admin/indexing
system_admin/reset-information
system_admin/enable-debug
system_admin/admin-tricks
system_admin/cleanup-cmds

View file

@ -57,7 +57,7 @@ you can add a message to be displayed using the following steps:
3. Select :guilabel:`Save`, and you will see the message once your page
refreshes.
.. image:: ../images/server-wide-announcement.png
.. image:: ../../images/server-wide-announcement.png
:alt: Server Wide Announcement
.. _md-rst:
@ -207,7 +207,7 @@ do this, use the following steps.
Instance "enterprise-2" successfully stopped.
Instance "enterprise-2" successfully started.
.. image:: ../images/language.png
.. image:: ../../images/language.png
.. _set-repo-pub:
@ -239,3 +239,26 @@ following URL: ``{instance-URL}/_admin/ping``.
.. _Markdown: http://daringfireball.net/projects/markdown/
.. _reStructured Text: http://docutils.sourceforge.net/docs/index.html
Unarchiving a repository
^^^^^^^^^^^^^^^^^^^^^^^^^
Archive operation for the repository is similar as delete. Archive keeps the data for future references
but makes the repository read-only. After archiving the repository it shouldn't be modified in any way.
This is why repository settings are disabled for an archived repository.
If there's a need for unarchiving a repository for some reasons, the interactive
ishell interface should be used.
.. code-block:: bash
# Open iShell from the terminal
$ rccontrol ishell enterprise-1/community-1
.. code-block:: python
# Set repository as un-archived
In [1]: repo = Repository.get_by_repo_name('SOME_REPO_NAME')
In [2]: repo.archived = False
In [3]: Session().add(repo);Session().commit()

View file

@ -8,7 +8,7 @@ the information in the following sections.
.. toctree::
apache-conf-example
apache-diffie-hellman
apache-subdirectory
apache-wsgi-coding
apache/apache-conf-example
apache/apache-diffie-hellman
apache/apache-subdirectory
apache/apache-wsgi-coding

View file

@ -66,14 +66,18 @@ Below config if for an Apache Reverse Proxy configuration.
# Directive to properly generate url (clone url) for RhodeCode
ProxyPreserveHost On
# It allows request bodies to be sent to the backend using chunked transfer encoding.
SetEnv proxy-sendchunked 1
# Increase headers size for large Mercurial headers sent with many branches
LimitRequestLine 16380
# Url to running RhodeCode instance. This is shown as `- URL:` when
# running rccontrol status.
ProxyPass / http://127.0.0.1:10002/ timeout=7200 Keepalive=On
ProxyPassReverse / http://127.0.0.1:10002/
# Increase headers for large Mercurial headers
LimitRequestLine 16380
# strict http prevents from https -> http downgrade
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"

View file

@ -8,7 +8,7 @@ the information in the following sections.
.. toctree::
nginx-config-example
nginx-diffie-hellman
nginx-proxy-conf
nginx-url-prefix
nginx/nginx-config-example
nginx/nginx-diffie-hellman
nginx/nginx-proxy-conf
nginx/nginx-url-prefix

View file

@ -0,0 +1,21 @@
.. _rhodecode-tuning-ref:
Tuning |RCE|
============
To customize your |RCE| |version| installation for maximum performance you
may find some of the following methods useful.
.. toctree::
tuning/tuning-gunicorn
tuning/tuning-vcs-memory-cache
tuning/tuning-user-sessions-performance
tuning/tuning-increase-db-performance
tuning/tuning-scale-horizontally-cluster
tuning/tuning-mount-cache-memory
tuning/tuning-change-encoding
tuning/tuning-change-large-file-dir
tuning/tuning-change-lfs-dir
tuning/tuning-hg-auth-loop

View file

@ -42,7 +42,7 @@ To do this, use the following steps:
## restarted, could prevent memory leaks
max_requests = 1000
max_requests_jitter = 30
## amount of time a worker can spend with handling a request before it
## amount of time a worker can spend with handling a request tuning-change-lfs-dir.before it
## gets killed and restarted. Set to 6hrs
timeout = 21600

View file

@ -1,21 +0,0 @@
.. _rhodecode-tuning-ref:
Tuning |RCE|
============
To customize your |RCE| |version| installation for maximum performance you
may find some of the following methods useful.
.. toctree::
tuning-gunicorn
tuning-vcs-memory-cache
tuning-user-sessions-performance
tuning-increase-db-performance
tuning-scale-horizontally-cluster
tuning-mount-cache-memory
tuning-change-encoding
tuning-change-large-file-dir
tuning-change-lfs-dir
tuning-hg-auth-loop

View file

@ -13,11 +13,12 @@ permissions applied to it; |perm|.
.. toctree::
public-access
default-user-perms
adding-anonymous-user
adding-new-user
setting-default-permissions
setting-usergroup-permissions
user_admin/public-access
user_admin/default-user-perms
user_admin/adding-anonymous-user
user_admin/adding-new-user
user_admin/setting-default-permissions
user_admin/setting-usergroup-permissions
user_admin/user-admin-tasks
.. |perm| replace:: **None**, **Read**, **Write**, or **Admin**
.. |perm| replace:: **None**, **Read**, **Write**, or **Admin**

View file

@ -0,0 +1,24 @@
.. _user-admin-tasks:
Common Admin Tasks for Users
----------------------------
Manually Set Personal Repository Group
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is how to set a repository group as personal for a user using ishell.
.. code-block:: bash
# starts the ishell interactive prompt
$ rccontrol ishell enterprise-1
.. code-block:: python
In [1]: repo_group = RepoGroup.get_by_group_name('some_group_name')
In [2]: user = User.get_by_username('some_user')
In [3]: repo_group.user = user
In [4]: repo_group.personal = True
In [5]: Session().add(repo_group);Session().commit()

View file

@ -204,6 +204,7 @@ are not required in args.
methods/pull-request-methods
methods/repo-methods
methods/repo-group-methods
methods/search-methods
methods/server-methods
methods/user-methods
methods/user-group-methods

View file

@ -462,6 +462,7 @@ get_repo_file
:param cache: Use internal caches for fetching files. If disabled fetching
files is slower but more memory efficient
:type cache: Optional(bool)
Example output:
.. code-block:: bash
@ -499,53 +500,51 @@ get_repo_nodes
.. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
Returns a list of nodes and children in a flat list for a given
path at given revision.
path at given revision.
It's possible to specify ret_type to show only `files` or `dirs`.
It's possible to specify ret_type to show only `files` or `dirs`.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to |repos|.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to |repos|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
:param revision: The revision for which listing should be done.
:type revision: str
:param root_path: The path from which to start displaying.
:type root_path: str
:param ret_type: Set the return type. Valid options are
``all`` (default), ``files`` and ``dirs``.
:type ret_type: Optional(str)
:param details: Returns extended information about nodes, such as
md5, binary, and or content.
The valid options are ``basic`` and ``full``.
:type details: Optional(str)
:param max_file_bytes: Only return file content under this file size bytes
:type details: Optional(int)
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
:param revision: The revision for which listing should be done.
:type revision: str
:param root_path: The path from which to start displaying.
:type root_path: str
:param ret_type: Set the return type. Valid options are
``all`` (default), ``files`` and ``dirs``.
:type ret_type: Optional(str)
:param details: Returns extended information about nodes, such as
md5, binary, and or content.
The valid options are ``basic`` and ``full``.
:type details: Optional(str)
:param max_file_bytes: Only return file content under this file size bytes
:type details: Optional(int)
Example output:
Example output:
.. code-block:: bash
.. code-block:: bash
id : <id_given_in_input>
result: [
{
"binary": false,
"content": "File line
Line2
",
"extension": "md",
"lines": 2,
"md5": "059fa5d29b19c0657e384749480f6422",
"mimetype": "text/x-minidsrc",
"name": "file.md",
"size": 580,
"type": "file"
},
...
]
error: null
id : <id_given_in_input>
result: [
{
"binary": false,
"content": "File line",
"extension": "md",
"lines": 2,
"md5": "059fa5d29b19c0657e384749480f6422",
"mimetype": "text/x-minidsrc",
"name": "file.md",
"size": 580,
"type": "file"
},
...
]
error: null
get_repo_refs

View file

@ -0,0 +1,35 @@
.. _search-methods-ref:
search methods
==============
search
------
.. py:function:: search(apiuser, search_query, search_type, page_limit=<Optional:10>, page=<Optional:1>, search_sort=<Optional:'newfirst'>, repo_name=<Optional:None>, repo_group_name=<Optional:None>)
Fetch Full Text Search results using API.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param search_query: Search query.
:type search_query: str
:param search_type: Search type. The following are valid options:
* commit
* content
* path
:type search_type: str
:param page_limit: Page item limit, from 1 to 500. Default 10 items.
:type page_limit: Optional(int)
:param page: Page number. Default first page.
:type page: Optional(int)
:param search_sort: Search sort order. Default newfirst. The following are valid options:
* newfirst
* oldfirst
:type search_sort: Optional(str)
:param repo_name: Filter by one repo. Default is all.
:type repo_name: Optional(str)
:param repo_group_name: Filter by one repo group. Default is all.
:type repo_group_name: Optional(str)

View file

@ -32,9 +32,9 @@ The most important this id needs to be unique for each user.
In [1]: saml2user = {
...: # OneLogin, uses externalID available to read from in the UI
...: 123: {'id: '48253211'},
...: 123: {'id': '48253211'},
...: # for Google/DuoSecurity email is also an option for unique ID
...: 124: {'id: 'email@domain.com'},
...: 124: {'id': 'email@domain.com'},
...: }
@ -70,7 +70,7 @@ Enter in the ishell prompt
...: new_external_identity.external_id = external_id
...: new_external_identity.external_username = '{}-saml-{}'.format(user.username, user.user_id)
...: new_external_identity.provider_name = provider
...: new_external_identity.local_user_id = user_id
...: new_external_identity.local_user_id = user.user_id
...: new_external_identity.access_token = ''
...: new_external_identity.token_secret = ''
...: new_external_identity.alt_token = ''

View file

@ -46,7 +46,7 @@ and commit files and |repos| while managing their security permissions.
nix/default-env
admin/system-admin
admin/user-admin
admin/setting-repo-perms
admin/repo-admin
admin/security-tips
auth/auth
issue-trackers/issue-trackers
@ -62,6 +62,13 @@ and commit files and |repos| while managing their security permissions.
code-review/code-review
integrations/integrations
.. toctree::
:maxdepth: 1
:caption: User Documentation
usage/basic-usage
tutorials/tutorials
.. toctree::
:maxdepth: 1
:caption: Developer Documentation
@ -71,13 +78,6 @@ and commit files and |repos| while managing their security permissions.
extensions/extensions-hooks
contributing/contributing
.. toctree::
:maxdepth: 1
:caption: User Documentation
usage/basic-usage
tutorials/tutorials
.. toctree::
:maxdepth: 1
:caption: About

View file

@ -0,0 +1,85 @@
|RCE| 4.17.0 |RNS|
------------------
Release Date
^^^^^^^^^^^^
- 2019-07-04
New Features
^^^^^^^^^^^^
- New artifacts feature.
Ability to store binary artifacts for repository with ACL
- UI/UX refresh for most of the pages. This includes multiple fixes and improvements.
- Diffs: store wide-diff mode in user sessions to store user preference for diff display.
- Mercurial: added support for Mercurial 4.9
- API: Added search API methods
- Files: adding/editing allows previews for generated content.
- Files: allowed multi file upload using UI.
- Repository Groups: last change is now smartly calculated based on latest change
from all it's children repositories.
- Archives: it's now currently possible to download partial directories from files view.
- SVN: allowed executing pre-commit code with rcextensions, also added example to
validate SVN file size and paths on pre-commit level.
General
^^^^^^^
- Exception store: add filter for display and deletion.
- Files: loading history doesn't display hidden and obsolete commits anymore.
- Repositories: bring back missing watch action in summary view.
- Admin: user groups is now using pure DB filtering to speed up display
for large number of groups.
- Mercurial: enabled full evolve+topic extensions when evolve is enabled.
- Dependencies: bumped evolve to 8.5.1
- Dependencies: bumped pyramid to 1.10.4
- Dependencies: bumped psutil to 5.5.1
- Dependencies: bumped pygments to 2.4.2
- Dependencies: bumped pyramid to 1.10.4
- Dependencies: bumped psycopg2 to 2.8.3
- Dependencies [security]: updated colander to 1.7.0
Security
^^^^^^^^
- SSH: replaced pycrypto with cryptography to generate SSH keys as pycrypto isn't
considered safe anymore.
Performance
^^^^^^^^^^^
- Config: updated header limits on gunicorn to prevent errors on large Mercurial repositories.
- User sessions: added option to cleanup redis based sessions in user session interface.
- Authentication: reduced usage of raw auth calls inside templates to speed up rendering.
- Sessions: don't touch session for API calls. Before each API call created new session
object which wasn't required.
Fixes
^^^^^
- hHooks: fixed more unicode problems with new pull-request link generator.
- Mercurial: fix ssh-server support for mercurial custom options.
- Pull requests: updated metadata information for failed merges with multiple heads.
- Pull requests: calculate ancestor in the same way as creation mode.
Fixed problem with updates generating wrong diffs in case of merges.
- Pull requests: fixed a bug in removal of multiple reviewers at once.
- Summary: fix timeout issues loading summary page without styling.
- SSH: fix invocation of custom hgrc.
- SSH: call custom hooks via SSH backend
- Markup: fix styling for check-lists.
- Archives: allows downloading refs that have slashes and special refs. e.g f/feat1 branch names.
- Files: ensure we generate archives with consistent hashing (except for .tar.gz which uses temp files names in header)
- Files: fixed rendering of readme files under non-ascii paths.
Upgrade notes
^^^^^^^^^^^^^
- In this release we introduced new UI across the application.
In case of problems with the display on your systems please send us info to support@rhodecode.com.

View file

@ -9,6 +9,7 @@ Release Notes
.. toctree::
:maxdepth: 1
release-notes-4.17.0.rst
release-notes-4.16.2.rst
release-notes-4.16.1.rst
release-notes-4.16.0.rst

View file

@ -35,6 +35,7 @@
"<%= dirs.js.node_modules %>/moment/min/moment.min.js",
"<%= dirs.js.node_modules %>/clipboard/dist/clipboard.min.js",
"<%= dirs.js.node_modules %>/favico.js/favico-0.3.10.min.js",
"<%= dirs.js.node_modules %>/dropzone/dist/dropzone.js",
"<%= dirs.js.node_modules %>/sticky-sidebar/dist/sticky-sidebar.min.js",
"<%= dirs.js.node_modules %>/sticky-sidebar/dist/jquery.sticky-sidebar.min.js",
"<%= dirs.js.node_modules %>/waypoints/lib/noframework.waypoints.min.js",
@ -107,7 +108,8 @@
},
"files": {
"<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less",
"<%= dirs.css.dest %>/style-ipython.css": "<%= dirs.css.src %>/ipython.less"
}
},
"production": {
@ -118,7 +120,8 @@
},
"files": {
"<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less",
"<%= dirs.css.dest %>/style-ipython.css": "<%= dirs.css.src %>/ipython.less"
}
},
"components": {

View file

@ -13,6 +13,7 @@
"clipboard": "^2.0.1",
"exports-loader": "^0.6.4",
"favico.js": "^0.3.10",
"dropzone": "^5.5.0",
"grunt": "^0.4.5",
"grunt-cli": "^1.3.1",
"grunt-contrib-concat": "^0.5.1",

View file

@ -1,3 +1,3 @@
[pip2nix]
requirements = ., -r ./requirements.txt
requirements = ., -r ./requirements.txt, -r ./requirements_pinned.txt
output = ./pkgs/python-packages.nix

File diff suppressed because it is too large Load diff

View file

@ -35,6 +35,18 @@ self: super: {
];
});
"cffi" = super."cffi".override (attrs: {
buildInputs = [
pkgs.libffi
];
});
"cryptography" = super."cryptography".override (attrs: {
buildInputs = [
pkgs.openssl
];
});
"gevent" = super."gevent".override (attrs: {
propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
# NOTE: (marcink) odd requirements from gevent aren't set properly,
@ -152,12 +164,6 @@ self: super: {
};
});
"pytest-runner" = super."pytest-runner".override (attrs: {
propagatedBuildInputs = [
self."setuptools-scm"
];
});
"python-ldap" = super."python-ldap".override (attrs: {
propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
pkgs.openldap

View file

@ -5,7 +5,7 @@
self: super: {
"alembic" = super.buildPythonPackage {
name = "alembic-1.0.5";
name = "alembic-1.0.10";
doCheck = false;
propagatedBuildInputs = [
self."sqlalchemy"
@ -14,8 +14,8 @@ self: super: {
self."python-dateutil"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/1c/65/b8e4f5b2f345bb13b5e0a3fddd892b0b3f0e8ad4880e954fdc6a50d00d84/alembic-1.0.5.tar.gz";
sha256 = "0rpjqp2iq6p49x1nli18ivak1izz547nnjxi110mzrgc1v7dxzz9";
url = "https://files.pythonhosted.org/packages/6e/8b/fa3bd058cccd5e9177fea4efa26bfb769228fdd3178436ad5e05830ef6ef/alembic-1.0.10.tar.gz";
sha256 = "1dwl0264r6ri2jyrjr68am04x538ab26xwy4crqjnnhm4alwm3c2";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -51,6 +51,17 @@ self: super: {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"asn1crypto" = super.buildPythonPackage {
name = "asn1crypto-0.24.0";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/fc/f1/8db7daa71f414ddabfa056c4ef792e1461ff655c2ae2928a2b675bfed6b4/asn1crypto-0.24.0.tar.gz";
sha256 = "0jaf8rf9dx1lf23xfv2cdd5h52f1qr3w8k63985bc35g3d220p4x";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"atomicwrites" = super.buildPythonPackage {
name = "atomicwrites-1.2.1";
doCheck = false;
@ -77,8 +88,8 @@ self: super: {
name = "authomatic-0.1.0.post1";
doCheck = false;
src = fetchurl {
url = "https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801";
sha256 = "1cgk0a86sbsjbri06gf5z5l4npwkjdxw6fdnwl4vvfmxs2sx9yxw";
url = "https://code.rhodecode.com/upstream/authomatic/artifacts/download/0-4fe9c041-a567-4f84-be4c-7efa2a606d3c.tar.gz?md5=f6bdc3c769688212db68233e8d2b0383";
sha256 = "0pc716mva0ym6xd8jwzjbjp8dqxy9069wwwv2aqwb8lyhl4757ab";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -146,15 +157,15 @@ self: super: {
};
};
"bleach" = super.buildPythonPackage {
name = "bleach-3.0.2";
name = "bleach-3.1.0";
doCheck = false;
propagatedBuildInputs = [
self."six"
self."webencodings"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/ae/31/680afc7d44040004296a2d8f0584983c2f2386448cd9d0964197e6c1160e/bleach-3.0.2.tar.gz";
sha256 = "06474zg7f73hv8h1xw2wcsmvn2ygj73zxgxxqg8zcx8ap1srdls8";
url = "https://files.pythonhosted.org/packages/78/5a/0df03e8735cd9c75167528299c738702437589b9c71a849489d00ffa82e8/bleach-3.1.0.tar.gz";
sha256 = "1yhrgrhkln8bd6gn3imj69g1h4xqah9gaz9q26crqr6gmmvpzprz";
};
meta = {
license = [ pkgs.lib.licenses.asl20 ];
@ -187,6 +198,20 @@ self: super: {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"cffi" = super.buildPythonPackage {
name = "cffi-1.12.2";
doCheck = false;
propagatedBuildInputs = [
self."pycparser"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/64/7c/27367b38e6cc3e1f49f193deb761fe75cda9f95da37b67b422e62281fcac/cffi-1.12.2.tar.gz";
sha256 = "19qfks2djya8vix95bmg3xzipjb8w9b8mbj4j5k2hqkc8j58f4z1";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"chameleon" = super.buildPythonPackage {
name = "chameleon-2.24";
doCheck = false;
@ -230,7 +255,7 @@ self: super: {
};
};
"colander" = super.buildPythonPackage {
name = "colander-1.5.1";
name = "colander-1.7.0";
doCheck = false;
propagatedBuildInputs = [
self."translationstring"
@ -238,8 +263,8 @@ self: super: {
self."enum34"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/ec/d1/fcca811a0a692c69d27e36b4d11a73acb98b4bab48323442642b6fd4386d/colander-1.5.1.tar.gz";
sha256 = "18ah4cwwxnpm6qxi6x9ipy51dal4spd343h44s5wd01cnhgrwsyq";
url = "https://files.pythonhosted.org/packages/db/e4/74ab06f54211917b41865cafc987ce511e35503de48da9bfe9358a1bdc3e/colander-1.7.0.tar.gz";
sha256 = "1wl1bqab307lbbcjx81i28s3yl6dlm4rf15fxawkjb6j48x1cn6p";
};
meta = {
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
@ -252,19 +277,19 @@ self: super: {
self."six"
];
src = fetchurl {
url = "https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c";
sha256 = "1hhcxirwvg58grlfr177b3awhbq8hlx1l3lh69ifl1ki7lfd1s1x";
url = "https://code.rhodecode.com/upstream/configobj/artifacts/download/0-012de99a-b1e1-4f64-a5c0-07a98a41b324.tar.gz?md5=6a513f51fe04b2c18cf84c1395a7c626";
sha256 = "0kqfrdfr14mw8yd8qwq14dv2xghpkjmd3yjsy8dfcbvpcc17xnxp";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"configparser" = super.buildPythonPackage {
name = "configparser-3.7.1";
name = "configparser-3.7.4";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/b6/a6/eceea7c5a5dbcf56815bed411c38cabd8a879386be10717b160e7362b5a2/configparser-3.7.1.tar.gz";
sha256 = "0cnz213il9lhgda6x70fw7mfqr8da43s3wm343lwzhqx94mgmmav";
url = "https://files.pythonhosted.org/packages/e2/1c/83fd53748d8245cb9a3399f705c251d3fc0ce7df04450aac1cfc49dd6a0f/configparser-3.7.4.tar.gz";
sha256 = "0xac32886ihs2xg7w1gppcq2sgin5qsm8lqwijs5xifq9w0x0q6s";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -285,16 +310,34 @@ self: super: {
};
};
"coverage" = super.buildPythonPackage {
name = "coverage-4.5.1";
name = "coverage-4.5.3";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/35/fe/e7df7289d717426093c68d156e0fd9117c8f4872b6588e8a8928a0f68424/coverage-4.5.1.tar.gz";
sha256 = "1wbrzpxka3xd4nmmkc6q0ir343d91kymwsm8pbmwa0d2a7q4ir2n";
url = "https://files.pythonhosted.org/packages/82/70/2280b5b29a0352519bb95ab0ef1ea942d40466ca71c53a2085bdeff7b0eb/coverage-4.5.3.tar.gz";
sha256 = "02f6m073qdispn96rc616hg0rnmw1pgqzw3bgxwiwza4zf9hirlx";
};
meta = {
license = [ pkgs.lib.licenses.asl20 ];
};
};
"cryptography" = super.buildPythonPackage {
name = "cryptography-2.6.1";
doCheck = false;
propagatedBuildInputs = [
self."asn1crypto"
self."six"
self."cffi"
self."enum34"
self."ipaddress"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/07/ca/bc827c5e55918ad223d59d299fff92f3563476c3b00d0a9157d9c0217449/cryptography-2.6.1.tar.gz";
sha256 = "19iwz5avym5zl6jrrrkym1rdaa9h61j20ph4cswsqgv8xg5j3j16";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal { fullName = "BSD or Apache License, Version 2.0"; } pkgs.lib.licenses.asl20 ];
};
};
"cssselect" = super.buildPythonPackage {
name = "cssselect-1.0.3";
doCheck = false;
@ -337,11 +380,11 @@ self: super: {
};
};
"defusedxml" = super.buildPythonPackage {
name = "defusedxml-0.5.0";
name = "defusedxml-0.6.0";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/74/ba/4ba4e89e21b5a2e267d80736ea674609a0a33cc4435a6d748ef04f1f9374/defusedxml-0.5.0.tar.gz";
sha256 = "1x54n0h8hl92vvwyymx883fbqpqjwn2mc8fb383bcg3z9zwz5mr4";
url = "https://files.pythonhosted.org/packages/a4/5f/f8aa58ca0cf01cbcee728abc9d88bfeb74e95e6cb4334cfd5bed5673ea77/defusedxml-0.6.0.tar.gz";
sha256 = "1xbp8fivl3wlbyg2jrvs4lalaqv1xp9a9f29p75wdx2s2d6h717n";
};
meta = {
license = [ pkgs.lib.licenses.psfl ];
@ -399,11 +442,11 @@ self: super: {
};
};
"ecdsa" = super.buildPythonPackage {
name = "ecdsa-0.13";
name = "ecdsa-0.13.2";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz";
sha256 = "1yj31j0asmrx4an9xvsaj2icdmzy6pw0glfpqrrkrphwdpi1xkv4";
url = "https://files.pythonhosted.org/packages/51/76/139bf6e9b7b6684d5891212cdbd9e0739f2bfc03f380a1a6ffa700f392ac/ecdsa-0.13.2.tar.gz";
sha256 = "116qaq7bh4lcynzi613960jhsnn19v0kmsqwahiwjfj14gx4y0sw";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -491,8 +534,8 @@ self: super: {
self."configparser"
];
src = fetchurl {
url = "https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313";
sha256 = "0bihrdp8ahsys437kxdhk52gz6kib8rxjv71i93wkw7594fcaxll";
url = "https://code.rhodecode.com/upstream/entrypoints/artifacts/download/0-8e9ee9e4-c4db-409c-b07e-81568fd1832d.tar.gz?md5=3a027b8ff1d257b91fe257de6c43357d";
sha256 = "0qih72n2myclanplqipqxpgpj9d2yhff1pz5d02zq1cfqyd173w5";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -623,11 +666,11 @@ self: super: {
};
};
"hupper" = super.buildPythonPackage {
name = "hupper-1.4.2";
name = "hupper-1.6.1";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/f1/75/1915dc7650b4867fa3049256e24ca8eddb5989998fcec788cf52b9812dfc/hupper-1.4.2.tar.gz";
sha256 = "16vb9fkiaakdpcp6pn56h3w0dwvm67bxq2k2dv4i382qhqwphdzb";
url = "https://files.pythonhosted.org/packages/85/d9/e005d357b11249c5d70ddf5b7adab2e4c0da4e8b0531ff146917a04fe6c0/hupper-1.6.1.tar.gz";
sha256 = "0d3cvkc8ssgwk54wvhbifj56ry97qi10pfzwfk8vwzzcikbfp3zy";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -671,15 +714,15 @@ self: super: {
};
};
"ipdb" = super.buildPythonPackage {
name = "ipdb-0.11";
name = "ipdb-0.12";
doCheck = false;
propagatedBuildInputs = [
self."setuptools"
self."ipython"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/80/fe/4564de08f174f3846364b3add8426d14cebee228f741c27e702b2877e85b/ipdb-0.11.tar.gz";
sha256 = "02m0l8wrhhd3z7dg3czn5ys1g5pxib516hpshdzp7rxzsxgcd0bh";
url = "https://files.pythonhosted.org/packages/6d/43/c3c2e866a8803e196d6209595020a4a6db1a3c5d07c01455669497ae23d0/ipdb-0.12.tar.gz";
sha256 = "1khr2n7xfy8hg65kj1bsrjq9g7656pp0ybfa8abpbzpdawji3qnw";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
@ -802,14 +845,14 @@ self: super: {
};
};
"jupyter-core" = super.buildPythonPackage {
name = "jupyter-core-4.4.0";
name = "jupyter-core-4.5.0";
doCheck = false;
propagatedBuildInputs = [
self."traitlets"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
sha256 = "1dy083rarba8prn9f9srxq3c7n7vyql02ycrqq306c40lr57aw5s";
url = "https://files.pythonhosted.org/packages/4a/de/ff4ca734656d17ebe0450807b59d728f45277e2e7f4b82bc9aae6cb82961/jupyter_core-4.5.0.tar.gz";
sha256 = "1xr4pbghwk5hayn5wwnhb7z95380r45p79gf5if5pi1akwg7qvic";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
@ -1008,14 +1051,14 @@ self: super: {
};
};
"paste" = super.buildPythonPackage {
name = "paste-3.0.5";
name = "paste-3.0.8";
doCheck = false;
propagatedBuildInputs = [
self."six"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/d4/41/91bde422400786b1b06357c1e6e3a5379f54dc3002aeb337cb767233304e/Paste-3.0.5.tar.gz";
sha256 = "1a6i8fh1fg8r4x800fvy9r82m15clwjim6yf2g9r4dff0y40dchv";
url = "https://files.pythonhosted.org/packages/66/65/e3acf1663438483c1f6ced0b6c6f3b90da9f0faacb0a6e2aa0f3f9f4b235/Paste-3.0.8.tar.gz";
sha256 = "05w1sh6ky4d7pmdb8nv82n13w22jcn3qsagg5ih3hjmbws9kkwf4";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -1033,7 +1076,7 @@ self: super: {
};
};
"pastescript" = super.buildPythonPackage {
name = "pastescript-3.0.0";
name = "pastescript-3.1.0";
doCheck = false;
propagatedBuildInputs = [
self."paste"
@ -1041,23 +1084,23 @@ self: super: {
self."six"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/08/2a/3797377a884ab9a064ad4d564ed612e54d26d7997caa8229c9c9df4eac31/PasteScript-3.0.0.tar.gz";
sha256 = "1hvmyz1sbn7ws1syw567ph7km9fi0wi75r3vlyzx6sk0z26xkm6r";
url = "https://files.pythonhosted.org/packages/9e/1d/14db1c283eb21a5d36b6ba1114c13b709629711e64acab653d9994fe346f/PasteScript-3.1.0.tar.gz";
sha256 = "02qcxjjr32ks7a6d4f533wl34ysc7yhwlrfcyqwqbzr52250v4fs";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"pathlib2" = super.buildPythonPackage {
name = "pathlib2-2.3.3";
name = "pathlib2-2.3.4";
doCheck = false;
propagatedBuildInputs = [
self."six"
self."scandir"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/bf/d7/a2568f4596b75d2c6e2b4094a7e64f620decc7887f69a1f2811931ea15b9/pathlib2-2.3.3.tar.gz";
sha256 = "0hpp92vqqgcd8h92msm9slv161b1q160igjwnkf2ag6cx0c96695";
url = "https://files.pythonhosted.org/packages/b5/f4/9c7cc726ece2498b6c8b62d3262aa43f59039b953fe23c9964ac5e18d40b/pathlib2-2.3.4.tar.gz";
sha256 = "1y0f9rkm1924zrc5dn4bwxlhgdkbml82lkcc28l5rgmr7d918q24";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -1075,14 +1118,14 @@ self: super: {
};
};
"pexpect" = super.buildPythonPackage {
name = "pexpect-4.6.0";
name = "pexpect-4.7.0";
doCheck = false;
propagatedBuildInputs = [
self."ptyprocess"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/89/43/07d07654ee3e25235d8cea4164cdee0ec39d1fda8e9203156ebe403ffda4/pexpect-4.6.0.tar.gz";
sha256 = "1fla85g47iaxxpjhp9vkxdnv4pgc7rplfy6ja491smrrk0jqi3ia";
url = "https://files.pythonhosted.org/packages/1c/b1/362a0d4235496cb42c33d1d8732b5e2c607b0129ad5fdd76f5a583b9fcb3/pexpect-4.7.0.tar.gz";
sha256 = "1sv2rri15zwhds85a4kamwh9pj49qcxv7m4miyr4jfpfwv81yb4y";
};
meta = {
license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
@ -1117,63 +1160,63 @@ self: super: {
};
};
"plaster-pastedeploy" = super.buildPythonPackage {
name = "plaster-pastedeploy-0.6";
name = "plaster-pastedeploy-0.7";
doCheck = false;
propagatedBuildInputs = [
self."pastedeploy"
self."plaster"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/3f/e7/6a6833158d2038ec40085433308a1e164fd1dac595513f6dd556d5669bb8/plaster_pastedeploy-0.6.tar.gz";
sha256 = "1bkggk18f4z2bmsmxyxabvf62znvjwbivzh880419r3ap0616cf2";
url = "https://files.pythonhosted.org/packages/99/69/2d3bc33091249266a1bd3cf24499e40ab31d54dffb4a7d76fe647950b98c/plaster_pastedeploy-0.7.tar.gz";
sha256 = "1zg7gcsvc1kzay1ry5p699rg2qavfsxqwl17mqxzr0gzw6j9679r";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"pluggy" = super.buildPythonPackage {
name = "pluggy-0.8.1";
name = "pluggy-0.11.0";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/38/e1/83b10c17688af7b2998fa5342fec58ecbd2a5a7499f31e606ae6640b71ac/pluggy-0.8.1.tar.gz";
sha256 = "05l6g42p9ilmabw0hlbiyxy6gyzjri41m5l11a8dzgvi77q35p4d";
url = "https://files.pythonhosted.org/packages/0d/a1/862ab336e8128fde20981d2c1aa8506693412daf5083b1911d539412676b/pluggy-0.11.0.tar.gz";
sha256 = "10511a54dvafw1jrk75mrhml53c7b7w4yaw7241696lc2hfvr895";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"prompt-toolkit" = super.buildPythonPackage {
name = "prompt-toolkit-1.0.15";
name = "prompt-toolkit-1.0.16";
doCheck = false;
propagatedBuildInputs = [
self."six"
self."wcwidth"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/8a/ad/cf6b128866e78ad6d7f1dc5b7f99885fb813393d9860778b2984582e81b5/prompt_toolkit-1.0.15.tar.gz";
sha256 = "05v9h5nydljwpj5nm8n804ms0glajwfy1zagrzqrg91wk3qqi1c5";
url = "https://files.pythonhosted.org/packages/f1/03/bb36771dc9fa7553ac4bdc639a9ecdf6fda0ff4176faf940d97e3c16e41d/prompt_toolkit-1.0.16.tar.gz";
sha256 = "1d65hm6nf0cbq0q0121m60zzy4s1fpg9fn761s1yxf08dridvkn1";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"psutil" = super.buildPythonPackage {
name = "psutil-5.4.8";
name = "psutil-5.5.1";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/e3/58/0eae6e4466e5abf779d7e2b71fac7fba5f59e00ea36ddb3ed690419ccb0f/psutil-5.4.8.tar.gz";
sha256 = "1hyna338sml2cl1mfb2gs89np18z27mvyhmq4ifh22x07n7mq9kf";
url = "https://files.pythonhosted.org/packages/c7/01/7c30b247cdc5ba29623faa5c8cf1f1bbf7e041783c340414b0ed7e067c64/psutil-5.5.1.tar.gz";
sha256 = "045qaqvn6k90bj5bcy259yrwcd2afgznaav3sfhphy9b8ambzkkj";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"psycopg2" = super.buildPythonPackage {
name = "psycopg2-2.7.5";
name = "psycopg2-2.8.3";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/b2/c1/7bf6c464e903ffc4f3f5907c389e5a4199666bf57f6cd6bf46c17912a1f9/psycopg2-2.7.5.tar.gz";
sha256 = "17klx964gw8z0znl0raz3by8vdc7cq5gxj4pdcrfcina84nrdkzc";
url = "https://files.pythonhosted.org/packages/5c/1c/6997288da181277a0c29bc39a5f9143ff20b8c99f2a7d059cfb55163e165/psycopg2-2.8.3.tar.gz";
sha256 = "0ms4kx0p5n281l89awccix4d05ybmdngnjjpi9jbzd0rhf1nwyl9";
};
meta = {
license = [ pkgs.lib.licenses.zpl21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
@ -1239,14 +1282,25 @@ self: super: {
};
};
"pyasn1-modules" = super.buildPythonPackage {
name = "pyasn1-modules-0.2.4";
name = "pyasn1-modules-0.2.5";
doCheck = false;
propagatedBuildInputs = [
self."pyasn1"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/bd/a5/ef7bf693e8a8f015386c9167483199f54f8a8ec01d1c737e05524f16e792/pyasn1-modules-0.2.4.tar.gz";
sha256 = "0z3w5dqrrvdplg9ma45j8n23xvyrj9ki8mg4ibqbn7l4qpl90855";
url = "https://files.pythonhosted.org/packages/ec/0b/69620cb04a016e4a1e8e352e8a42717862129b574b3479adb2358a1f12f7/pyasn1-modules-0.2.5.tar.gz";
sha256 = "15nvfx0vnl8akdlv3k6s0n80vqvryj82bm040jdsn7wmyxl1ywpg";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"pycparser" = super.buildPythonPackage {
name = "pycparser-2.19";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/68/9e/49196946aee219aead1290e00d1e7fdeab8567783e83e1b9ab5585e6206a/pycparser-2.19.tar.gz";
sha256 = "1cr5dcj9628lkz1qlwq3fv97c25363qppkmcayqvd05dpy573259";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
@ -1274,23 +1328,12 @@ self: super: {
license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
};
};
"pyflakes" = super.buildPythonPackage {
name = "pyflakes-0.8.1";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
sha256 = "0sbpq6pqm1i9wqi41mlfrsc5rk92jv4mskvlyxmnhlbdnc80ma1z";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"pygments" = super.buildPythonPackage {
name = "pygments-2.3.1";
name = "pygments-2.4.2";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/64/69/413708eaf3a64a6abb8972644e0f20891a55e621c6759e2c3f3891e05d63/Pygments-2.3.1.tar.gz";
sha256 = "0ji87g09jph8jqcvclgb02qvxasdnr9pzvk90rl66d90yqcxmyjz";
url = "https://files.pythonhosted.org/packages/7e/ae/26808275fc76bf2832deb10d3a3ed3107bc4de01b85dcccbe525f2cd6d1e/Pygments-2.4.2.tar.gz";
sha256 = "15v2sqm5g12bqa0c7wikfh9ck2nl97ayizy1hpqhmws5gqalq748";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
@ -1330,7 +1373,7 @@ self: super: {
};
};
"pyramid" = super.buildPythonPackage {
name = "pyramid-1.10.1";
name = "pyramid-1.10.4";
doCheck = false;
propagatedBuildInputs = [
self."hupper"
@ -1345,28 +1388,13 @@ self: super: {
self."repoze.lru"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/0a/3e/22e3ac9be1b70a01139adba8906ee4b8f628bb469fea3c52f6c97b73063c/pyramid-1.10.1.tar.gz";
sha256 = "1h5105nfh6rsrfjiyw20aavyibj36la3hajy6vh1fa77xb4y3hrp";
url = "https://files.pythonhosted.org/packages/c2/43/1ae701c9c6bb3a434358e678a5e72c96e8aa55cf4cb1d2fa2041b5dd38b7/pyramid-1.10.4.tar.gz";
sha256 = "0rkxs1ajycg2zh1c94xlmls56mx5m161sn8112skj0amza6cn36q";
};
meta = {
license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
};
};
"pyramid-beaker" = super.buildPythonPackage {
name = "pyramid-beaker-0.8";
doCheck = false;
propagatedBuildInputs = [
self."pyramid"
self."beaker"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
sha256 = "0hflx3qkcdml1mwpq53sz46s7jickpfn0zy0ns2c7j445j66bp3p";
};
meta = {
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
};
};
"pyramid-debugtoolbar" = super.buildPythonPackage {
name = "pyramid-debugtoolbar-4.5";
doCheck = false;
@ -1538,14 +1566,14 @@ self: super: {
};
};
"python-dateutil" = super.buildPythonPackage {
name = "python-dateutil-2.7.5";
name = "python-dateutil-2.8.0";
doCheck = false;
propagatedBuildInputs = [
self."six"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/0e/01/68747933e8d12263d41ce08119620d9a7e5eb72c876a3442257f74490da0/python-dateutil-2.7.5.tar.gz";
sha256 = "00ngwcdw36w5b37b51mdwn3qxid9zdf3kpffv2q6n9kl05y2iyc8";
url = "https://files.pythonhosted.org/packages/ad/99/5b2e99737edeb28c71bcbec5b5dda19d0d9ef3ca3e92e3e925e7c0bb364c/python-dateutil-2.8.0.tar.gz";
sha256 = "17nsfhy4xdz1khrfxa61vd7pmvd5z0wa3zb6v4gb4kfnykv0b668";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.asl20 { fullName = "Dual License"; } ];
@ -1690,7 +1718,7 @@ self: super: {
};
};
"rhodecode-enterprise-ce" = super.buildPythonPackage {
name = "rhodecode-enterprise-ce-4.16.2";
name = "rhodecode-enterprise-ce-4.17.0";
buildInputs = [
self."pytest"
self."py"
@ -1709,36 +1737,29 @@ self: super: {
];
doCheck = true;
propagatedBuildInputs = [
self."setuptools-scm"
self."amqp"
self."authomatic"
self."atomicwrites"
self."attrs"
self."babel"
self."beaker"
self."bleach"
self."celery"
self."chameleon"
self."channelstream"
self."click"
self."colander"
self."configobj"
self."cssselect"
self."cryptography"
self."decorator"
self."deform"
self."docutils"
self."dogpile.cache"
self."dogpile.core"
self."ecdsa"
self."formencode"
self."future"
self."futures"
self."gnureadline"
self."infrae.cache"
self."iso8601"
self."itsdangerous"
self."jinja2"
self."billiard"
self."kombu"
self."lxml"
self."mako"
@ -1747,21 +1768,18 @@ self: super: {
self."msgpack-python"
self."pyotp"
self."packaging"
self."pathlib2"
self."paste"
self."pastedeploy"
self."pastescript"
self."pathlib2"
self."peppercorn"
self."psutil"
self."py-bcrypt"
self."pycrypto"
self."pycurl"
self."pyflakes"
self."pycrypto"
self."pygments"
self."pyparsing"
self."pyramid-beaker"
self."pyramid-debugtoolbar"
self."pyramid-jinja2"
self."pyramid-mako"
self."pyramid"
self."pyramid-mailer"
@ -1784,7 +1802,6 @@ self: super: {
self."sshpubkeys"
self."subprocess32"
self."supervisor"
self."tempita"
self."translationstring"
self."urllib3"
self."urlobject"
@ -1813,7 +1830,6 @@ self: super: {
self."greenlet"
self."gunicorn"
self."waitress"
self."setproctitle"
self."ipdb"
self."ipython"
self."rhodecode-tools"
@ -1855,8 +1871,8 @@ self: super: {
self."elasticsearch1-dsl"
];
src = fetchurl {
url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v1.2.1.tar.gz?md5=25bc2f7de1da318e547236d3fb463d28";
sha256 = "1k8l3s4mvshza1zay6dfxprq54fyb5dc85dqdva9wa3f466y0adk";
url = "https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-10ac93f4-bb7d-4b97-baea-68110743dd5a.tar.gz?md5=962dc77c06aceee62282b98d33149661";
sha256 = "1vfhgf46inbx7jvlfx4fdzh3vz7lh37r291gzb5hx447pfm3qllg";
};
meta = {
license = [ { fullName = "Apache 2.0 and Proprietary"; } ];
@ -1878,11 +1894,11 @@ self: super: {
};
};
"scandir" = super.buildPythonPackage {
name = "scandir-1.9.0";
name = "scandir-1.10.0";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/16/2a/557af1181e6b4e30254d5a6163b18f5053791ca66e251e77ab08887e8fe3/scandir-1.9.0.tar.gz";
sha256 = "0r3hvf1a9jm1rkqgx40gxkmccknkaiqjavs8lccgq9s8khh5x5s4";
url = "https://files.pythonhosted.org/packages/df/f5/9c052db7bd54d0cbf1bc0bb6554362bba1012d03e5888950a4f5c5dadc4e/scandir-1.10.0.tar.gz";
sha256 = "1bkqwmf056pkchf05ywbnf659wqlp6lljcdb0y88wr9f0vv32ijd";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
@ -1900,22 +1916,11 @@ self: super: {
};
};
"setuptools" = super.buildPythonPackage {
name = "setuptools-40.8.0";
name = "setuptools-41.0.1";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/c2/f7/c7b501b783e5a74cf1768bc174ee4fb0a8a6ee5af6afa92274ff964703e0/setuptools-40.8.0.zip";
sha256 = "0k9hifpgahnw2a26w3cr346iy733k6d3nwh3f7g9m13y6f8fqkkf";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"setuptools-scm" = super.buildPythonPackage {
name = "setuptools-scm-2.1.0";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/e5/62/f9e1ac314464eb5945c97542acb6bf6f3381dfa5d7a658de7730c36f31a1/setuptools_scm-2.1.0.tar.gz";
sha256 = "0yb364cgk15sfw3x8ln4ssh98z1dj6n8iiz4r2rw1cfsxhgi8rx7";
url = "https://files.pythonhosted.org/packages/1d/64/a18a487b4391a05b9c7f938b94a16d80305bf0369c6b0b9509e86165e1d3/setuptools-41.0.1.zip";
sha256 = "04sns22y2hhsrwfy1mha2lgslvpjsjsz8xws7h2rh5a7ylkd28m2";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -1966,40 +1971,40 @@ self: super: {
};
};
"sshpubkeys" = super.buildPythonPackage {
name = "sshpubkeys-2.2.0";
name = "sshpubkeys-3.1.0";
doCheck = false;
propagatedBuildInputs = [
self."pycrypto"
self."cryptography"
self."ecdsa"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/27/da/337fabeb3dca6b62039a93ceaa636f25065e0ae92b575b1235342076cf0a/sshpubkeys-2.2.0.tar.gz";
sha256 = "0r4kpwzmg96a2x56pllik7dmc3fnqk189v3sfgsi07q2ryrhr6xm";
url = "https://files.pythonhosted.org/packages/00/23/f7508a12007c96861c3da811992f14283d79c819d71a217b3e12d5196649/sshpubkeys-3.1.0.tar.gz";
sha256 = "105g2li04nm1hb15a2y6hm9m9k7fbrkd5l3gy12w3kgcmsf3k25k";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"subprocess32" = super.buildPythonPackage {
name = "subprocess32-3.5.3";
name = "subprocess32-3.5.4";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/be/2b/beeba583e9877e64db10b52a96915afc0feabf7144dcbf2a0d0ea68bf73d/subprocess32-3.5.3.tar.gz";
sha256 = "1hr5fan8i719hmlmz73hf8rhq74014w07d8ryg7krvvf6692kj3b";
url = "https://files.pythonhosted.org/packages/32/c8/564be4d12629b912ea431f1a50eb8b3b9d00f1a0b1ceff17f266be190007/subprocess32-3.5.4.tar.gz";
sha256 = "17f7mvwx2271s1wrl0qac3wjqqnrqag866zs3qc8v5wp0k43fagb";
};
meta = {
license = [ pkgs.lib.licenses.psfl ];
};
};
"supervisor" = super.buildPythonPackage {
name = "supervisor-3.3.5";
name = "supervisor-4.0.3";
doCheck = false;
propagatedBuildInputs = [
self."meld3"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/ba/65/92575a8757ed576beaee59251f64a3287bde82bdc03964b89df9e1d29e1b/supervisor-3.3.5.tar.gz";
sha256 = "1w3ahridzbc6rxfpbyx8lij6pjlcgf2ymzyg53llkjqxalp6sk8v";
url = "https://files.pythonhosted.org/packages/97/48/f38bf70bd9282d1a18d591616557cc1a77a1c627d57dff66ead65c891dc8/supervisor-4.0.3.tar.gz";
sha256 = "17hla7mx6w5m5jzkkjxgqa8wpswqmfhbhf49f692hw78fg0ans7p";
};
meta = {
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
@ -2128,22 +2133,22 @@ self: super: {
};
};
"vine" = super.buildPythonPackage {
name = "vine-1.2.0";
name = "vine-1.3.0";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/46/1a/c94317efa98040c5d50fe3cf9080cafb0372ff5afb0283dc018c751c6746/vine-1.2.0.tar.gz";
sha256 = "0xjz2sjbr5jrpjk411b7alkghdskhphgsqqrbi7abqfh2pli6j7f";
url = "https://files.pythonhosted.org/packages/1c/e1/79fb8046e607dd6c2ad05c9b8ebac9d0bd31d086a08f02699e96fc5b3046/vine-1.3.0.tar.gz";
sha256 = "11ydsbhl1vabndc2r979dv61s6j2b0giq6dgvryifvq1m7bycghk";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
"waitress" = super.buildPythonPackage {
name = "waitress-1.1.0";
name = "waitress-1.3.0";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz";
sha256 = "1a85gyji0kajc3p0s1pwwfm06w4wfxjkvvl4rnrz3h164kbd6g6k";
url = "https://files.pythonhosted.org/packages/43/50/9890471320d5ad22761ae46661cf745f487b1c8c4ec49352b99e1078b970/waitress-1.3.0.tar.gz";
sha256 = "09j5dzbbcxib7vdskhx39s1qsydlr4n2p2png71d7mjnr9pnwajf";
};
meta = {
license = [ pkgs.lib.licenses.zpl21 ];
@ -2218,18 +2223,18 @@ self: super: {
};
};
"webob" = super.buildPythonPackage {
name = "webob-1.8.4";
name = "webob-1.8.5";
doCheck = false;
src = fetchurl {
url = "https://files.pythonhosted.org/packages/e4/6c/99e322c3d4cc11d9060a67a9bf2f7c9c581f40988c11fffe89bb8c36bc5e/WebOb-1.8.4.tar.gz";
sha256 = "16cfg5y4n6sihz59vsmns2yqbfm0gfsn3l5xgz2g0pdhilaib0x4";
url = "https://files.pythonhosted.org/packages/9d/1a/0c89c070ee2829c934cb6c7082287c822e28236a4fcf90063e6be7c35532/WebOb-1.8.5.tar.gz";
sha256 = "11khpzaxc88q31v25ic330gsf56fwmbdc9b30br8mvp0fmwspah5";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
"webtest" = super.buildPythonPackage {
name = "webtest-2.0.32";
name = "webtest-2.0.33";
doCheck = false;
propagatedBuildInputs = [
self."six"
@ -2238,8 +2243,8 @@ self: super: {
self."beautifulsoup4"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/27/9f/9e74449d272ffbef4fb3012e6dbc53c0b24822d545e7a33a342f80131e59/WebTest-2.0.32.tar.gz";
sha256 = "0qp0nnbazzm4ibjiyqfcn6f230svk09i4g58zg2i9x1ga06h48a2";
url = "https://files.pythonhosted.org/packages/a8/b0/ffc9413b637dbe26e291429bb0f6ed731e518d0cd03da28524a8fe2e8a8f/WebTest-2.0.33.tar.gz";
sha256 = "1l3z0cwqslsf4rcrhi2gr8kdfh74wn2dw76376i4g9i38gz8wd21";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
@ -2293,42 +2298,42 @@ self: super: {
};
};
"zope.deprecation" = super.buildPythonPackage {
name = "zope.deprecation-4.3.0";
name = "zope.deprecation-4.4.0";
doCheck = false;
propagatedBuildInputs = [
self."setuptools"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/a1/18/2dc5e6bfe64fdc3b79411b67464c55bb0b43b127051a20f7f492ab767758/zope.deprecation-4.3.0.tar.gz";
sha256 = "095jas41wbxgmw95kwdxqhbc3bgihw2hzj9b3qpdg85apcsf2lkx";
url = "https://files.pythonhosted.org/packages/34/da/46e92d32d545dd067b9436279d84c339e8b16de2ca393d7b892bc1e1e9fd/zope.deprecation-4.4.0.tar.gz";
sha256 = "1pz2cv7gv9y1r3m0bdv7ks1alagmrn5msm5spwdzkb2by0w36i8d";
};
meta = {
license = [ pkgs.lib.licenses.zpl21 ];
};
};
"zope.event" = super.buildPythonPackage {
name = "zope.event-4.3.0";
name = "zope.event-4.4";
doCheck = false;
propagatedBuildInputs = [
self."setuptools"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/9e/d0/54ba59f19a0635f6591b74be259cf6fbf67e73f4edda27b5cd0cf4d26efa/zope.event-4.3.0.tar.gz";
sha256 = "1rrkyx42bcq8dkpj23c2v99kczlrg8d39c06q5qpr0vs4hjfmv70";
url = "https://files.pythonhosted.org/packages/4c/b2/51c0369adcf5be2334280eed230192ab3b03f81f8efda9ddea6f65cc7b32/zope.event-4.4.tar.gz";
sha256 = "1ksbc726av9xacml6jhcfyn828hlhb9xlddpx6fcvnlvmpmpvhk9";
};
meta = {
license = [ pkgs.lib.licenses.zpl21 ];
};
};
"zope.interface" = super.buildPythonPackage {
name = "zope.interface-4.5.0";
name = "zope.interface-4.6.0";
doCheck = false;
propagatedBuildInputs = [
self."setuptools"
];
src = fetchurl {
url = "https://files.pythonhosted.org/packages/ac/8a/657532df378c2cd2a1fe6b12be3b4097521570769d4852ec02c24bd3594e/zope.interface-4.5.0.tar.gz";
sha256 = "0k67m60ij06wkg82n15qgyn96waf4pmrkhv0njpkfzpmv5q89hsp";
url = "https://files.pythonhosted.org/packages/4e/d0/c9d16bd5b38de44a20c6dc5d5ed80a49626fafcb3db9f9efdc2a19026db6/zope.interface-4.6.0.tar.gz";
sha256 = "1rgh2x3rcl9r0v0499kf78xy86rnmanajf4ywmqb943wpk50sg8v";
};
meta = {
license = [ pkgs.lib.licenses.zpl21 ];

View file

@ -1,37 +1,31 @@
## dependencies
setuptools-scm==2.1.0
amqp==2.3.1
# not released authomatic that has updated some oauth providers
https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801#egg=authomatic==0.1.0.post1
atomicwrites==1.2.1
attrs==18.2.0
https://code.rhodecode.com/upstream/authomatic/artifacts/download/0-4fe9c041-a567-4f84-be4c-7efa2a606d3c.tar.gz?md5=f6bdc3c769688212db68233e8d2b0383#egg=authomatic==0.1.0.post1
babel==1.3
beaker==1.9.1
bleach==3.0.2
bleach==3.1.0
celery==4.1.1
chameleon==2.24
channelstream==0.5.2
click==7.0
colander==1.5.1
colander==1.7.0
# our custom configobj
https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c#egg=configobj==5.0.6
https://code.rhodecode.com/upstream/configobj/artifacts/download/0-012de99a-b1e1-4f64-a5c0-07a98a41b324.tar.gz?md5=6a513f51fe04b2c18cf84c1395a7c626#egg=configobj==5.0.6
cssselect==1.0.3
cryptography==2.6.1
decorator==4.1.2
deform==2.0.7
docutils==0.14.0
dogpile.cache==0.7.1
dogpile.core==0.4.1
ecdsa==0.13
formencode==1.2.4
future==0.14.3
futures==3.0.2
gnureadline==6.3.8
infrae.cache==1.0.1
iso8601==0.1.12
itsdangerous==0.24
jinja2==2.9.6
billiard==3.5.0.3
kombu==4.2.1
lxml==4.2.5
mako==1.0.7
@ -40,23 +34,20 @@ markupsafe==1.1.0
msgpack-python==0.5.6
pyotp==2.2.7
packaging==15.2
paste==3.0.5
pathlib2==2.3.4
paste==3.0.8
pastedeploy==2.0.1
pastescript==3.0.0
pathlib2==2.3.3
pastescript==3.1.0
peppercorn==0.6
psutil==5.4.8
psutil==5.5.1
py-bcrypt==0.4
pycrypto==2.6.1
pycurl==7.43.0.2
pyflakes==0.8.1
pygments==2.3.1
pycrypto==2.6.1
pygments==2.4.2
pyparsing==2.3.0
pyramid-beaker==0.8
pyramid-debugtoolbar==4.5.0
pyramid-jinja2==2.7
pyramid-mako==1.0.2
pyramid==1.10.1
pyramid==1.10.4
pyramid_mailer==0.15.1
python-dateutil
python-ldap==3.1.0
@ -74,10 +65,9 @@ routes==2.4.1
simplejson==3.16.0
six==1.11.0
sqlalchemy==1.1.18
sshpubkeys==2.2.0
subprocess32==3.5.3
supervisor==3.3.5
tempita==0.5.2
sshpubkeys==3.1.0
subprocess32==3.5.4
supervisor==4.0.3
translationstring==1.3
urllib3==1.24.1
urlobject==2.4.3
@ -85,29 +75,29 @@ venusian==1.2.0
weberror==0.10.3
webhelpers2==2.0
webhelpers==1.3
webob==1.8.4
webob==1.8.5
whoosh==2.7.4
wsgiref==0.1.2
zope.cachedescriptors==4.3.1
zope.deprecation==4.3.0
zope.event==4.3.0
zope.interface==4.5.0
zope.deprecation==4.4.0
zope.event==4.4.0
zope.interface==4.6.0
# DB drivers
mysql-python==1.2.5
pymysql==0.8.1
pysqlite==2.8.3
psycopg2==2.7.5
psycopg2==2.8.3
# IPYTHON RENDERING
# entrypoints backport, pypi version doesn't support egg installs
https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1
https://code.rhodecode.com/upstream/entrypoints/artifacts/download/0-8e9ee9e4-c4db-409c-b07e-81568fd1832d.tar.gz?md5=3a027b8ff1d257b91fe257de6c43357d#egg=entrypoints==0.2.2.rhodecode-upstream1
nbconvert==5.3.1
nbformat==4.4.0
jupyter_client==5.0.0
## cli tools
alembic==1.0.5
alembic==1.0.10
invoke==0.13.0
bumpversion==0.5.3
@ -115,15 +105,14 @@ bumpversion==0.5.3
gevent==1.4.0
greenlet==0.4.15
gunicorn==19.9.0
waitress==1.1.0
setproctitle==1.1.10
waitress==1.3.0
## debug
ipdb==0.11.0
ipdb==0.12.0
ipython==5.1.0
## rhodecode-tools, special case
https://code.rhodecode.com/rhodecode-tools-ce/archive/v1.2.1.tar.gz?md5=25bc2f7de1da318e547236d3fb463d28#egg=rhodecode-tools==1.2.1
https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-10ac93f4-bb7d-4b97-baea-68110743dd5a.tar.gz?md5=962dc77c06aceee62282b98d33149661#egg=rhodecode-tools==1.2.1
## appenlight
appenlight-client==0.6.26

19
requirements_pinned.txt Normal file
View file

@ -0,0 +1,19 @@
# contains not directly required libraries we want to pin the version.
atomicwrites==1.2.1
attrs==18.2.0
billiard==3.5.0.3
chameleon==2.24
cffi==1.12.2
ecdsa==0.13.2
hupper==1.6.1
gnureadline==6.3.8
jinja2==2.9.6
jsonschema==2.6.0
pyramid-jinja2==2.7
pluggy==0.11.0
setproctitle==1.1.10
scandir==1.10.0
tempita==0.5.2
vine==1.3.0
configparser==3.7.4

View file

@ -10,7 +10,7 @@ gprof2dot==2017.9.19
mock==1.0.1
cov-core==1.15.0
coverage==4.5.1
coverage==4.5.3
webtest==2.0.32
webtest==2.0.33
beautifulsoup4==4.6.3

View file

@ -1 +1 @@
4.16.2
4.17.0

View file

@ -45,7 +45,7 @@ PYRAMID_SETTINGS = {}
EXTENSIONS = {}
__version__ = ('.'.join((str(each) for each in VERSION[:3])))
__dbversion__ = 95 # defines current db version for migrations
__dbversion__ = 98 # defines current db version for migrations
__platform__ = platform.system()
__license__ = 'AGPLv3, and Commercial License'
__author__ = 'RhodeCode GmbH'

View file

@ -37,11 +37,11 @@ class TestCommentCommit(object):
assert_error(id_, expected, given=response.body)
@pytest.mark.parametrize("commit_id, expected_err", [
('abcabca', {'hg': 'Commit {commit} does not exist for {repo}',
'git': 'Commit {commit} does not exist for {repo}',
('abcabca', {'hg': 'Commit {commit} does not exist for `{repo}`',
'git': 'Commit {commit} does not exist for `{repo}`',
'svn': 'Commit id {commit} not understood.'}),
('idontexist', {'hg': 'Commit {commit} does not exist for {repo}',
'git': 'Commit {commit} does not exist for {repo}',
('idontexist', {'hg': 'Commit {commit} does not exist for `{repo}`',
'git': 'Commit {commit} does not exist for `{repo}`',
'svn': 'Commit id {commit} not understood.'}),
])
def test_api_comment_commit_wrong_hash(self, backend, commit_id, expected_err):
@ -53,7 +53,7 @@ class TestCommentCommit(object):
expected_err = expected_err[backend.alias]
expected_err = expected_err.format(
repo=backend.repo.scm_instance(), commit=commit_id)
repo=backend.repo.scm_instance().name, commit=commit_id)
assert_error(id_, expected_err, given=response.body)
@pytest.mark.parametrize("status_change, message, commit_id", [

View file

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2019 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import pytest
from rhodecode.tests import HG_REPO
from rhodecode.api.tests.utils import (
build_data, api_call, assert_error, assert_ok)
@pytest.mark.usefixtures("testuser_api", "app")
class TestApiSearch(object):
@pytest.mark.parametrize("query, expected_hits, expected_paths", [
('todo', 23, [
'vcs/backends/hg/inmemory.py',
'vcs/tests/test_git.py']),
('extension:rst installation', 6, [
'docs/index.rst',
'docs/installation.rst']),
('def repo', 87, [
'vcs/tests/test_git.py',
'vcs/tests/test_changesets.py']),
('repository:%s def test' % HG_REPO, 18, [
'vcs/tests/test_git.py',
'vcs/tests/test_changesets.py']),
('"def main"', 9, [
'vcs/__init__.py',
'vcs/tests/__init__.py',
'vcs/utils/progressbar.py']),
('owner:test_admin', 358, [
'vcs/tests/base.py',
'MANIFEST.in',
'vcs/utils/termcolors.py',
'docs/theme/ADC/static/documentation.png']),
('owner:test_admin def main', 72, [
'vcs/__init__.py',
'vcs/tests/test_utils_filesize.py',
'vcs/tests/test_cli.py']),
('owner:michał test', 0, []),
])
def test_search_content_results(self, query, expected_hits, expected_paths):
id_, params = build_data(
self.apikey_regular, 'search',
search_query=query,
search_type='content')
response = api_call(self.app, params)
json_response = response.json
assert json_response['result']['item_count'] == expected_hits
paths = [x['f_path'] for x in json_response['result']['results']]
for expected_path in expected_paths:
assert expected_path in paths
@pytest.mark.parametrize("query, expected_hits, expected_paths", [
('readme.rst', 3, []),
('test*', 75, []),
('*model*', 1, []),
('extension:rst', 48, []),
('extension:rst api', 24, []),
])
def test_search_file_paths(self, query, expected_hits, expected_paths):
id_, params = build_data(
self.apikey_regular, 'search',
search_query=query,
search_type='path')
response = api_call(self.app, params)
json_response = response.json
assert json_response['result']['item_count'] == expected_hits
paths = [x['f_path'] for x in json_response['result']['results']]
for expected_path in expected_paths:
assert expected_path in paths

View file

@ -44,6 +44,7 @@ class TestGetRepo(object):
self, apikey_attr, expect_secrets, cache_param, backend,
user_util):
repo = backend.create_repo()
repo_id = repo.repo_id
usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
group = user_util.create_user_group(members=[usr])
user_util.grant_user_group_permission_to_repo(
@ -64,6 +65,8 @@ class TestGetRepo(object):
permissions = expected_permissions(repo)
followers = []
repo = RepoModel().get(repo_id)
for user in repo.followers:
followers.append(user.user.get_api_data(
include_secrets=expect_secrets))
@ -84,6 +87,7 @@ class TestGetRepo(object):
# TODO: Depending on which tests are running before this one, we
# start with a different number of permissions in the database.
repo = RepoModel().get_by_repo_name(backend.repo_name)
repo_id = repo.repo_id
permission_count = len(repo.repo_to_perm)
RepoModel().grant_user_permission(repo=backend.repo_name,
@ -102,6 +106,8 @@ class TestGetRepo(object):
permissions = expected_permissions(repo)
followers = []
repo = RepoModel().get(repo_id)
for user in repo.followers:
followers.append(user.user.get_api_data())

View file

@ -444,7 +444,7 @@ def get_repo_nodes(request, apiuser, repoid, revision, root_path,
result: [
{
"binary": false,
"content": "File line\nLine2\n",
"content": "File line",
"extension": "md",
"lines": 2,
"md5": "059fa5d29b19c0657e384749480f6422",
@ -529,6 +529,7 @@ def get_repo_file(request, apiuser, repoid, commit_id, file_path,
:param cache: Use internal caches for fetching files. If disabled fetching
files is slower but more memory efficient
:type cache: Optional(bool)
Example output:
.. code-block:: bash

View file

@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2011-2019 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
from rhodecode.api import jsonrpc_method
from rhodecode.api.exc import JSONRPCValidationError
from rhodecode.api.utils import Optional
from rhodecode.lib.index import searcher_from_config
from rhodecode.model import validation_schema
from rhodecode.model.validation_schema.schemas import search_schema
log = logging.getLogger(__name__)
@jsonrpc_method()
def search(request, apiuser, search_query, search_type, page_limit=Optional(10),
page=Optional(1), search_sort=Optional('newfirst'),
repo_name=Optional(None), repo_group_name=Optional(None)):
"""
Fetch Full Text Search results using API.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param search_query: Search query.
:type search_query: str
:param search_type: Search type. The following are valid options:
* commit
* content
* path
:type search_type: str
:param page_limit: Page item limit, from 1 to 500. Default 10 items.
:type page_limit: Optional(int)
:param page: Page number. Default first page.
:type page: Optional(int)
:param search_sort: Search sort order. Default newfirst. The following are valid options:
* newfirst
* oldfirst
:type search_sort: Optional(str)
:param repo_name: Filter by one repo. Default is all.
:type repo_name: Optional(str)
:param repo_group_name: Filter by one repo group. Default is all.
:type repo_group_name: Optional(str)
"""
data = {'execution_time': ''}
repo_name = Optional.extract(repo_name)
repo_group_name = Optional.extract(repo_group_name)
schema = search_schema.SearchParamsSchema()
try:
search_params = schema.deserialize(
dict(search_query=search_query,
search_type=search_type,
search_sort=Optional.extract(search_sort),
page_limit=Optional.extract(page_limit),
requested_page=Optional.extract(page))
)
except validation_schema.Invalid as err:
raise JSONRPCValidationError(colander_exc=err)
search_query = search_params.get('search_query')
search_type = search_params.get('search_type')
search_sort = search_params.get('search_sort')
if search_params.get('search_query'):
page_limit = search_params['page_limit']
requested_page = search_params['requested_page']
searcher = searcher_from_config(request.registry.settings)
try:
search_result = searcher.search(
search_query, search_type, apiuser, repo_name, repo_group_name,
requested_page=requested_page, page_limit=page_limit, sort=search_sort)
data.update(dict(
results=list(search_result['results']), page=requested_page,
item_count=search_result['count'],
items_per_page=page_limit))
finally:
searcher.cleanup()
if not search_result['error']:
data['execution_time'] = '%s results (%.3f seconds)' % (
search_result['count'],
search_result['runtime'])
else:
node = schema['search_query']
raise JSONRPCValidationError(
colander_exc=validation_schema.Invalid(node, search_result['error']))
return data

View file

@ -168,6 +168,28 @@ class BaseAppView(object):
from rhodecode.lib.base import attach_context_attributes
attach_context_attributes(c, self.request, self.request.user.user_id)
c.is_super_admin = c.auth_user.is_admin
c.can_create_repo = c.is_super_admin
c.can_create_repo_group = c.is_super_admin
c.can_create_user_group = c.is_super_admin
c.is_delegated_admin = False
if not c.auth_user.is_default and not c.is_super_admin:
c.can_create_repo = h.HasPermissionAny('hg.create.repository')(
user=self.request.user)
repositories = c.auth_user.repositories_admin or c.can_create_repo
c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')(
user=self.request.user)
repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group
c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')(
user=self.request.user)
user_groups = c.auth_user.user_groups_admin or c.can_create_user_group
# delegated admin can create, or manage some objects
c.is_delegated_admin = repositories or repository_groups or user_groups
return c
def _get_template_context(self, tmpl_args, **kwargs):
@ -215,12 +237,17 @@ class RepoAppView(BaseAppView):
c.rhodecode_db_repo = self.db_repo
c.repo_name = self.db_repo_name
c.repository_pull_requests = self.db_repo_pull_requests
c.repository_is_user_following = ScmModel().is_following_repo(
self.db_repo_name, self._rhodecode_user.user_id)
self.path_filter = PathFilter(None)
c.repository_requirements_missing = {}
try:
self.rhodecode_vcs_repo = self.db_repo.scm_instance()
if self.rhodecode_vcs_repo:
# NOTE(marcink):
# comparison to None since if it's an object __bool__ is expensive to
# calculate
if self.rhodecode_vcs_repo is not None:
path_perms = self.rhodecode_vcs_repo.get_path_permissions(
c.auth_user.username)
self.path_filter = PathFilter(path_perms)

View file

@ -85,8 +85,6 @@ class NavigationRegistry(object):
'admin_settings_hooks'),
NavEntry('search', _('Full Text Search'),
'admin_settings_search'),
NavEntry('integrations', _('Integrations'),
'global_integrations_home'),
NavEntry('system', _('System Info'),
'admin_settings_system'),
NavEntry('exceptions', _('Exceptions Tracker'),

View file

@ -423,6 +423,10 @@ def admin_routes(config):
name='repo_groups',
pattern='/repo_groups')
config.add_route(
name='repo_groups_data',
pattern='/repo_groups_data')
config.add_route(
name='repo_group_new',
pattern='/repo_group/new')

View file

@ -46,10 +46,10 @@ def route_path(name, params=None, **kwargs):
class TestAdminMainView(TestController):
def test_redirect_admin_home(self):
def test_access_admin_home(self):
self.log_user()
response = self.app.get(route_path('admin_home'), status=302)
assert response.location.endswith('/audit_logs')
response = self.app.get(route_path('admin_home'), status=200)
response.mustcontain("Administration area")
def test_redirect_pull_request_view(self, view):
self.log_user()

View file

@ -23,11 +23,11 @@ import pytest
from rhodecode.apps._base import ADMIN_PREFIX
from rhodecode.lib import helpers as h
from rhodecode.model.db import Repository, UserRepoToPerm, User
from rhodecode.model.db import Repository, UserRepoToPerm, User, RepoGroup
from rhodecode.model.meta import Session
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.tests import (
assert_session_flash, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, TestController)
assert_session_flash, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH)
from rhodecode.tests.fixture import Fixture
fixture = Fixture()
@ -38,6 +38,7 @@ def route_path(name, params=None, **kwargs):
base_url = {
'repo_groups': ADMIN_PREFIX + '/repo_groups',
'repo_groups_data': ADMIN_PREFIX + '/repo_groups_data',
'repo_group_new': ADMIN_PREFIX + '/repo_group/new',
'repo_group_create': ADMIN_PREFIX + '/repo_group/create',
@ -59,13 +60,30 @@ def _get_permission_for_user(user, repo):
@pytest.mark.usefixtures("app")
class TestAdminRepositoryGroups(object):
def test_show_repo_groups(self, autologin_user):
response = self.app.get(route_path('repo_groups'))
response.mustcontain('data: []')
def test_show_repo_groups_after_creating_group(self, autologin_user):
def test_show_repo_groups(self, autologin_user):
self.app.get(route_path('repo_groups'))
def test_show_repo_groups_data(self, autologin_user, xhr_header):
response = self.app.get(route_path(
'repo_groups_data'), extra_environ=xhr_header)
all_repo_groups = RepoGroup.query().count()
assert response.json['recordsTotal'] == all_repo_groups
def test_show_repo_groups_data_filtered(self, autologin_user, xhr_header):
response = self.app.get(route_path(
'repo_groups_data', params={'search[value]': 'empty_search'}),
extra_environ=xhr_header)
all_repo_groups = RepoGroup.query().count()
assert response.json['recordsTotal'] == all_repo_groups
assert response.json['recordsFiltered'] == 0
def test_show_repo_groups_after_creating_group(self, autologin_user, xhr_header):
fixture.create_repo_group('test_repo_group')
response = self.app.get(route_path('repo_groups'))
response = self.app.get(route_path(
'repo_groups_data'), extra_environ=xhr_header)
response.mustcontain('"name_raw": "test_repo_group"')
fixture.destroy_repo_group('test_repo_group')

View file

@ -214,8 +214,7 @@ class TestAdminSettingsGlobal(object):
})
response = response.follow()
response.mustcontain(
"""<div class="branding">- %s</div>""" % new_title)
response.mustcontain(new_title)
def post_and_verify_settings(self, settings):
old_title = 'RhodeCode'

View file

@ -173,4 +173,4 @@ class TestAdminUsersSshKeysView(TestController):
response.mustcontain('Private key')
response.mustcontain('Public key')
response.mustcontain('-----BEGIN RSA PRIVATE KEY-----')
response.mustcontain('-----BEGIN PRIVATE KEY-----')

View file

@ -50,7 +50,7 @@ class ExceptionsTrackerView(BaseAppView):
count +=1
return count
def get_all_exceptions(self, read_metadata=False, limit=None):
def get_all_exceptions(self, read_metadata=False, limit=None, type_filter=None):
exc_store_path = exc_tracking.get_exc_store()
exception_list = []
@ -59,7 +59,7 @@ class ExceptionsTrackerView(BaseAppView):
return val.split('_')[-1]
except Exception:
return 0
count = 0
for fname in reversed(sorted(os.listdir(exc_store_path), key=key_sorter)):
parts = fname.split('_', 2)
@ -83,13 +83,17 @@ class ExceptionsTrackerView(BaseAppView):
except Exception:
log.exception('Failed to read exc data from:{}'.format(full_path))
pass
# convert our timestamp to a date obj, for nicer representation
exc['exc_utc_date'] = time_to_utcdatetime(exc['exc_timestamp'])
exception_list.append(exc)
count += 1
if limit and count >= limit:
type_present = exc.get('exc_type')
if type_filter:
if type_present and type_present == type_filter:
exception_list.append(exc)
else:
exception_list.append(exc)
if limit and len(exception_list) >= limit:
break
return exception_list
@ -103,8 +107,10 @@ class ExceptionsTrackerView(BaseAppView):
c = self.load_default_context()
c.active = 'exceptions_browse'
c.limit = safe_int(self.request.GET.get('limit')) or 50
c.type_filter = self.request.GET.get('type_filter')
c.next_limit = c.limit + 50
c.exception_list = self.get_all_exceptions(read_metadata=True, limit=c.limit)
c.exception_list = self.get_all_exceptions(
read_metadata=True, limit=c.limit, type_filter=c.type_filter)
c.exception_list_count = self.count_all_exceptions()
c.exception_store_dir = exc_tracking.get_exc_store()
return self._get_template_context(c)
@ -132,12 +138,20 @@ class ExceptionsTrackerView(BaseAppView):
def exception_delete_all(self):
_ = self.request.translate
c = self.load_default_context()
type_filter = self.request.POST.get('type_filter')
c.active = 'exceptions'
all_exc = self.get_all_exceptions()
exc_count = len(all_exc)
all_exc = self.get_all_exceptions(read_metadata=bool(type_filter), type_filter=type_filter)
exc_count = 0
for exc in all_exc:
exc_tracking.delete_exception(exc['exc_id'], prefix=None)
if type_filter:
if exc.get('exc_type') == type_filter:
exc_tracking.delete_exception(exc['exc_id'], prefix=None)
exc_count += 1
else:
exc_tracking.delete_exception(exc['exc_id'], prefix=None)
exc_count += 1
h.flash(_('Removed {} Exceptions').format(exc_count), category='success')
raise HTTPFound(h.route_path('admin_settings_exception_tracker'))

View file

@ -20,12 +20,12 @@
import logging
from pyramid.httpexceptions import HTTPFound
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from pyramid.view import view_config
from rhodecode.apps._base import BaseAppView
from rhodecode.lib import helpers as h
from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
from rhodecode.lib.auth import (LoginRequired, NotAnonymous)
from rhodecode.model.db import PullRequest
@ -33,14 +33,23 @@ log = logging.getLogger(__name__)
class AdminMainView(BaseAppView):
def load_default_context(self):
c = self._get_local_tmpl_context()
return c
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@NotAnonymous()
@view_config(
route_name='admin_home', request_method='GET')
route_name='admin_home', request_method='GET',
renderer='rhodecode:templates/admin/main.mako')
def admin_main(self):
# redirect _admin to audit logs...
raise HTTPFound(h.route_path('admin_audit_logs'))
c = self.load_default_context()
c.active = 'admin'
if not (c.is_super_admin or c.is_delegated_admin):
raise HTTPNotFound()
return self._get_template_context(c)
@LoginRequired()
@view_config(route_name='pull_requests_global_0', request_method='GET')
@ -49,8 +58,7 @@ class AdminMainView(BaseAppView):
def pull_requests(self):
"""
Global redirect for Pull Requests
:param pull_request_id: id of pull requests in the system
pull_request_id: id of pull requests in the system
"""
pull_request = PullRequest.get_or_404(

View file

@ -17,7 +17,7 @@
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import datetime
import logging
import formencode
import formencode.htmlfill
@ -30,16 +30,16 @@ from pyramid.response import Response
from rhodecode import events
from rhodecode.apps._base import BaseAppView, DataGridAppView
from rhodecode.lib.ext_json import json
from rhodecode.lib.auth import (
LoginRequired, CSRFRequired, NotAnonymous,
HasPermissionAny, HasRepoGroupPermissionAny)
from rhodecode.lib import helpers as h, audit_logger
from rhodecode.lib.utils2 import safe_int, safe_unicode
from rhodecode.lib.utils2 import safe_int, safe_unicode, datetime_to_time
from rhodecode.model.forms import RepoGroupForm
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.scm import RepoGroupList
from rhodecode.model.db import Session, RepoGroup
from rhodecode.model.db import (
or_, count, func, in_filter_generator, Session, RepoGroup, User, Repository)
log = logging.getLogger(__name__)
@ -88,23 +88,169 @@ class AdminRepoGroupsView(BaseAppView, DataGridAppView):
return False
return False
# permission check in data loading of
# `repo_group_list_data` via RepoGroupList
@LoginRequired()
@NotAnonymous()
# perms check inside
@view_config(
route_name='repo_groups', request_method='GET',
renderer='rhodecode:templates/admin/repo_groups/repo_groups.mako')
def repo_group_list(self):
c = self.load_default_context()
repo_group_list = RepoGroup.get_all_repo_groups()
repo_group_list_acl = RepoGroupList(
repo_group_list, perm_set=['group.admin'])
repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
repo_group_list=repo_group_list_acl, admin=True)
c.data = json.dumps(repo_group_data)
return self._get_template_context(c)
# permission check inside
@LoginRequired()
@NotAnonymous()
@view_config(
route_name='repo_groups_data', request_method='GET',
renderer='json_ext', xhr=True)
def repo_group_list_data(self):
self.load_default_context()
column_map = {
'name_raw': 'group_name_hash',
'desc': 'group_description',
'last_change_raw': 'updated_on',
'top_level_repos': 'repos_total',
'owner': 'user_username',
}
draw, start, limit = self._extract_chunk(self.request)
search_q, order_by, order_dir = self._extract_ordering(
self.request, column_map=column_map)
_render = self.request.get_partial_renderer(
'rhodecode:templates/data_table/_dt_elements.mako')
c = _render.get_call_context()
def quick_menu(repo_group_name):
return _render('quick_repo_group_menu', repo_group_name)
def repo_group_lnk(repo_group_name):
return _render('repo_group_name', repo_group_name)
def last_change(last_change):
if isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
delta = datetime.timedelta(
seconds=(datetime.datetime.now() - datetime.datetime.utcnow()).seconds)
last_change = last_change + delta
return _render("last_change", last_change)
def desc(desc, personal):
return _render(
'repo_group_desc', desc, personal, c.visual.stylify_metatags)
def repo_group_actions(repo_group_id, repo_group_name, gr_count):
return _render(
'repo_group_actions', repo_group_id, repo_group_name, gr_count)
def user_profile(username):
return _render('user_profile', username)
auth_repo_group_list = RepoGroupList(
RepoGroup.query().all(), perm_set=['group.admin'])
allowed_ids = [-1]
for repo_group in auth_repo_group_list:
allowed_ids.append(repo_group.group_id)
repo_groups_data_total_count = RepoGroup.query()\
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(RepoGroup.group_id, allowed_ids)
)) \
.count()
repo_groups_data_total_inactive_count = RepoGroup.query()\
.filter(RepoGroup.group_id.in_(allowed_ids))\
.count()
repo_count = count(Repository.repo_id)
base_q = Session.query(
RepoGroup.group_name,
RepoGroup.group_name_hash,
RepoGroup.group_description,
RepoGroup.group_id,
RepoGroup.personal,
RepoGroup.updated_on,
User,
repo_count.label('repos_count')
) \
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(RepoGroup.group_id, allowed_ids)
)) \
.outerjoin(Repository) \
.join(User, User.user_id == RepoGroup.user_id) \
.group_by(RepoGroup, User)
if search_q:
like_expression = u'%{}%'.format(safe_unicode(search_q))
base_q = base_q.filter(or_(
RepoGroup.group_name.ilike(like_expression),
))
repo_groups_data_total_filtered_count = base_q.count()
# the inactive isn't really used, but we still make it same as other data grids
# which use inactive (users,user groups)
repo_groups_data_total_filtered_inactive_count = repo_groups_data_total_filtered_count
sort_defined = False
if order_by == 'group_name':
sort_col = func.lower(RepoGroup.group_name)
sort_defined = True
elif order_by == 'repos_total':
sort_col = repo_count
sort_defined = True
elif order_by == 'user_username':
sort_col = User.username
else:
sort_col = getattr(RepoGroup, order_by, None)
if sort_defined or sort_col:
if order_dir == 'asc':
sort_col = sort_col.asc()
else:
sort_col = sort_col.desc()
base_q = base_q.order_by(sort_col)
base_q = base_q.offset(start).limit(limit)
# authenticated access to user groups
auth_repo_group_list = base_q.all()
repo_groups_data = []
for repo_gr in auth_repo_group_list:
row = {
"menu": quick_menu(repo_gr.group_name),
"name": repo_group_lnk(repo_gr.group_name),
"name_raw": repo_gr.group_name,
"last_change": last_change(repo_gr.updated_on),
"last_change_raw": datetime_to_time(repo_gr.updated_on),
"last_changeset": "",
"last_changeset_raw": "",
"desc": desc(repo_gr.group_description, repo_gr.personal),
"owner": user_profile(repo_gr.User.username),
"top_level_repos": repo_gr.repos_count,
"action": repo_group_actions(
repo_gr.group_id, repo_gr.group_name, repo_gr.repos_count),
}
repo_groups_data.append(row)
data = ({
'draw': draw,
'data': repo_groups_data,
'recordsTotal': repo_groups_data_total_count,
'recordsTotalInactive': repo_groups_data_total_inactive_count,
'recordsFiltered': repo_groups_data_total_filtered_count,
'recordsFilteredInactive': repo_groups_data_total_filtered_inactive_count,
})
return data
@LoginRequired()
@NotAnonymous()
# perm checks inside

View file

@ -39,7 +39,7 @@ from rhodecode.model.forms import UserGroupForm
from rhodecode.model.permission import PermissionModel
from rhodecode.model.scm import UserGroupList
from rhodecode.model.db import (
or_, count, User, UserGroup, UserGroupMember)
or_, count, User, UserGroup, UserGroupMember, in_filter_generator)
from rhodecode.model.meta import Session
from rhodecode.model.user_group import UserGroupModel
from rhodecode.model.db import true
@ -107,11 +107,17 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
allowed_ids.append(user_group.users_group_id)
user_groups_data_total_count = UserGroup.query()\
.filter(UserGroup.users_group_id.in_(allowed_ids))\
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(UserGroup.users_group_id, allowed_ids)
))\
.count()
user_groups_data_total_inactive_count = UserGroup.query()\
.filter(UserGroup.users_group_id.in_(allowed_ids))\
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(UserGroup.users_group_id, allowed_ids)
))\
.filter(UserGroup.users_group_active != true()).count()
member_count = count(UserGroupMember.user_id)
@ -123,11 +129,14 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
UserGroup.group_data,
User,
member_count.label('member_count')
) \
.filter(UserGroup.users_group_id.in_(allowed_ids)) \
.outerjoin(UserGroupMember) \
.join(User, User.user_id == UserGroup.user_id) \
.group_by(UserGroup, User)
) \
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(UserGroup.users_group_id, allowed_ids)
)) \
.outerjoin(UserGroupMember) \
.join(User, User.user_id == UserGroup.user_id) \
.group_by(UserGroup, User)
base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
@ -141,14 +150,16 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
user_groups_data_total_filtered_count = base_q.count()
user_groups_data_total_filtered_inactive_count = base_q_inactive.count()
sort_defined = False
if order_by == 'members_total':
sort_col = member_count
sort_defined = True
elif order_by == 'user_username':
sort_col = User.username
else:
sort_col = getattr(UserGroup, order_by, None)
if isinstance(sort_col, count) or sort_col:
if sort_defined or sort_col:
if order_dir == 'asc':
sort_col = sort_col.asc()
else:
@ -162,7 +173,7 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
user_groups_data = []
for user_gr in auth_user_group_list:
user_groups_data.append({
row = {
"users_group_name": user_group_name(user_gr.users_group_name),
"name_raw": h.escape(user_gr.users_group_name),
"description": h.escape(user_gr.user_group_description),
@ -175,7 +186,8 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
"owner": user_profile(user_gr.User.username),
"action": user_group_actions(
user_gr.users_group_id, user_gr.users_group_name)
})
}
user_groups_data.append(row)
data = ({
'draw': draw,

View file

@ -682,8 +682,7 @@ class UsersView(UserAppView):
if personal_repo_group:
raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
personal_repo_group_name = RepoGroupModel().get_personal_group_name(
c.user)
personal_repo_group_name = RepoGroupModel().get_personal_group_name(c.user)
named_personal_group = RepoGroup.get_by_group_name(
personal_repo_group_name)
try:

View file

@ -38,19 +38,18 @@ class LocalFileStorage(object):
"""
Resolves a unique name and the correct path. If a filename
for that path already exists then a numeric prefix with values > 0 will be
added, for example test.jpg -> test-1.jpg etc. initially file would have 0 prefix.
added, for example test.jpg -> 1-test.jpg etc. initially file would have 0 prefix.
:param name: base name of file
:param directory: absolute directory path
"""
basename, ext = os.path.splitext(name)
counter = 0
while True:
name = '%s-%d%s' % (basename, counter, ext)
name = '%d-%s' % (counter, name)
# sub_store prefix to optimize disk usage, e.g some_path/ab/final_file
sub_store = cls._sub_store_from_filename(basename)
sub_store = cls._sub_store_from_filename(name)
sub_store_path = os.path.join(directory, sub_store)
if not os.path.exists(sub_store_path):
os.makedirs(sub_store_path)
@ -209,3 +208,16 @@ class LocalFileStorage(object):
filename = os.path.join(directory, filename)
return filename, metadata
def get_metadata(self, filename):
"""
Reads JSON stored metadata for a file
:param filename:
:return:
"""
filename = self.store_path(filename)
filename_meta = filename + '.meta'
with open(filename_meta, "rb") as source_meta:
return json.loads(source_meta.read())

View file

@ -21,6 +21,7 @@ import os
import pytest
from rhodecode.lib.ext_json import json
from rhodecode.model.db import Session, FileStore
from rhodecode.tests import TestController
from rhodecode.apps.file_store import utils, config_keys
@ -46,9 +47,12 @@ class TestFileStoreViews(TestController):
('abcde-0.exe', "1234567", True),
('abcde-0.jpg', "xxxxx", False),
])
def test_get_files_from_store(self, fid, content, exists, tmpdir):
self.log_user()
def test_get_files_from_store(self, fid, content, exists, tmpdir, user_util):
user = self.log_user()
user_id = user['user_id']
repo_id = user_util.create_repo().repo_id
store_path = self.app._pyramid_settings[config_keys.store_path]
store_uid = fid
if exists:
status = 200
@ -58,17 +62,28 @@ class TestFileStoreViews(TestController):
f.write(content)
with open(filesystem_file, 'rb') as f:
fid, metadata = store.save_file(f, fid, extra_metadata={'filename': fid})
store_uid, metadata = store.save_file(f, fid, extra_metadata={'filename': fid})
entry = FileStore.create(
file_uid=store_uid, filename=metadata["filename"],
file_hash=metadata["sha256"], file_size=metadata["size"],
file_display_name='file_display_name',
file_description='repo artifact `{}`'.format(metadata["filename"]),
check_acl=True, user_id=user_id,
scope_repo_id=repo_id
)
Session().add(entry)
Session().commit()
else:
status = 404
response = self.app.get(route_path('download_file', fid=fid), status=status)
response = self.app.get(route_path('download_file', fid=store_uid), status=status)
if exists:
assert response.text == content
file_store_path = os.path.dirname(store.resolve_name(fid, store_path)[1])
metadata_file = os.path.join(file_store_path, fid + '.meta')
file_store_path = os.path.dirname(store.resolve_name(store_uid, store_path)[1])
metadata_file = os.path.join(file_store_path, store_uid + '.meta')
assert os.path.exists(metadata_file)
with open(metadata_file, 'rb') as f:
json_data = json.loads(f.read())

View file

@ -19,9 +19,10 @@
# and proprietary license terms, please see https://rhodecode.com/licenses/
import os
import uuid
import pathlib2
def get_file_storage(settings):
from rhodecode.apps.file_store.local_store import LocalFileStorage
@ -30,6 +31,11 @@ def get_file_storage(settings):
return LocalFileStorage(base_path=store_path)
def splitext(filename):
ext = ''.join(pathlib2.Path(filename).suffixes)
return filename, ext
def uid_filename(filename, randomized=True):
"""
Generates a randomized or stable (uuid) filename,
@ -38,7 +44,8 @@ def uid_filename(filename, randomized=True):
:param filename: the original filename
:param randomized: define if filename should be stable (sha1 based) or randomized
"""
_, ext = os.path.splitext(filename)
_, ext = splitext(filename)
if randomized:
uid = uuid.uuid4()
else:

View file

@ -30,7 +30,7 @@ from rhodecode.apps.file_store.exceptions import (
from rhodecode.lib import helpers as h
from rhodecode.lib import audit_logger
from rhodecode.lib.auth import (CSRFRequired, NotAnonymous)
from rhodecode.lib.auth import (CSRFRequired, NotAnonymous, HasRepoPermissionAny, HasRepoGroupPermissionAny)
from rhodecode.model.db import Session, FileStore
log = logging.getLogger(__name__)
@ -68,7 +68,7 @@ class FileStoreView(BaseAppView):
'user_id': self._rhodecode_user.user_id,
'ip': self._rhodecode_user.ip_addr}}
try:
store_fid, metadata = self.storage.save_file(
store_uid, metadata = self.storage.save_file(
file_obj.file, filename, extra_metadata=metadata)
except FileNotAllowedException:
return {'store_fid': None,
@ -82,7 +82,7 @@ class FileStoreView(BaseAppView):
try:
entry = FileStore.create(
file_uid=store_fid, filename=metadata["filename"],
file_uid=store_uid, filename=metadata["filename"],
file_hash=metadata["sha256"], file_size=metadata["size"],
file_description='upload attachment',
check_acl=False, user_id=self._rhodecode_user.user_id
@ -96,8 +96,8 @@ class FileStoreView(BaseAppView):
'access_path': None,
'error': 'File {} failed to store in DB.'.format(filename)}
return {'store_fid': store_fid,
'access_path': h.route_path('download_file', fid=store_fid)}
return {'store_fid': store_uid,
'access_path': h.route_path('download_file', fid=store_uid)}
@view_config(route_name='download_file')
def download_file(self):
@ -109,6 +109,35 @@ class FileStoreView(BaseAppView):
log.debug('File with FID:%s not found in the store', file_uid)
raise HTTPNotFound()
db_obj = FileStore().query().filter(FileStore.file_uid == file_uid).scalar()
if not db_obj:
raise HTTPNotFound()
# private upload for user
if db_obj.check_acl and db_obj.scope_user_id:
user = db_obj.user
if self._rhodecode_db_user.user_id != user.user_id:
log.warning('Access to file store object forbidden')
raise HTTPNotFound()
# scoped to repository permissions
if db_obj.check_acl and db_obj.scope_repo_id:
repo = db_obj.repo
perm_set = ['repository.read', 'repository.write', 'repository.admin']
has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'FileStore check')
if not has_perm:
log.warning('Access to file store object forbidden')
raise HTTPNotFound()
# scoped to repository group permissions
if db_obj.check_acl and db_obj.scope_repo_group_id:
repo_group = db_obj.repo_group
perm_set = ['group.read', 'group.write', 'group.admin']
has_perm = HasRepoGroupPermissionAny(*perm_set)(repo_group.group_name, 'FileStore check')
if not has_perm:
log.warning('Access to file store object forbidden')
raise HTTPNotFound()
FileStore.bump_access_counter(file_uid)
file_path = self.storage.store_path(file_uid)

View file

@ -25,7 +25,7 @@ import formencode
import formencode.htmlfill
import peppercorn
from pyramid.httpexceptions import HTTPNotFound, HTTPFound
from pyramid.httpexceptions import HTTPNotFound, HTTPFound, HTTPBadRequest
from pyramid.view import view_config
from pyramid.renderers import render
from pyramid.response import Response
@ -67,7 +67,6 @@ class GistView(BaseAppView):
(Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
]
return c
@LoginRequired()
@ -296,6 +295,8 @@ class GistView(BaseAppView):
response = Response(content)
response.content_type = 'text/plain'
return response
elif return_format:
raise HTTPBadRequest()
return self._get_template_context(c)

View file

@ -67,6 +67,10 @@ def includeme(config):
name='markup_preview',
pattern='/_markup_preview')
config.add_route(
name='file_preview',
pattern='/_file_preview')
config.add_route(
name='store_user_session_value',
pattern='/_store_session_attr')

View file

@ -27,13 +27,14 @@ from pyramid.view import view_config
from rhodecode.apps._base import BaseAppView
from rhodecode.lib import helpers as h
from rhodecode.lib.auth import (
LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator,
CSRFRequired)
LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
from rhodecode.lib.codeblocks import filenode_as_lines_tokens
from rhodecode.lib.index import searcher_from_config
from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
from rhodecode.lib.ext_json import json
from rhodecode.lib.vcs.nodes import FileNode
from rhodecode.model.db import (
func, true, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup)
from rhodecode.model.repo import RepoModel
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.scm import RepoGroupList, RepoList
@ -105,21 +106,27 @@ class HomeView(BaseAppView):
return {'suggestions': _user_groups}
def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
def _get_repo_list(self, name_contains=None, repo_type=None, repo_group_name='', limit=20):
org_query = name_contains
allowed_ids = self._rhodecode_user.repo_acl_ids(
['repository.read', 'repository.write', 'repository.admin'],
cache=False, name_filter=name_contains) or [-1]
query = Repository.query()\
.order_by(func.length(Repository.repo_name))\
.order_by(Repository.repo_name)\
.filter(Repository.archived.isnot(true()))\
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(Repository.repo_id, allowed_ids)
))
query = query.order_by(case(
[
(Repository.repo_name.startswith(repo_group_name), repo_group_name+'/'),
],
))
query = query.order_by(func.length(Repository.repo_name))
query = query.order_by(Repository.repo_name)
if repo_type:
query = query.filter(Repository.repo_type == repo_type)
@ -145,20 +152,26 @@ class HomeView(BaseAppView):
}
for obj in acl_iter]
def _get_repo_group_list(self, name_contains=None, limit=20):
def _get_repo_group_list(self, name_contains=None, repo_group_name='', limit=20):
org_query = name_contains
allowed_ids = self._rhodecode_user.repo_group_acl_ids(
['group.read', 'group.write', 'group.admin'],
cache=False, name_filter=name_contains) or [-1]
query = RepoGroup.query()\
.order_by(func.length(RepoGroup.group_name))\
.order_by(RepoGroup.group_name) \
.filter(or_(
# generate multiple IN to fix limitation problems
*in_filter_generator(RepoGroup.group_id, allowed_ids)
))
query = query.order_by(case(
[
(RepoGroup.group_name.startswith(repo_group_name), repo_group_name+'/'),
],
))
query = query.order_by(func.length(RepoGroup.group_name))
query = query.order_by(RepoGroup.group_name)
if name_contains:
ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
query = query.filter(
@ -183,11 +196,17 @@ class HomeView(BaseAppView):
def _get_user_list(self, name_contains=None, limit=20):
org_query = name_contains
if not name_contains:
return []
return [], False
name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
# TODO(marcink): should all logged in users be allowed to search others?
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
if not allowed_user_search:
return [], False
name_contains = re.compile('(?:user:[ ]?)(.+)').findall(name_contains)
if len(name_contains) != 1:
return []
return [], False
name_contains = name_contains[0]
query = User.query()\
@ -207,22 +226,28 @@ class HomeView(BaseAppView):
{
'id': obj.user_id,
'value': org_query,
'value_display': obj.username,
'value_display': 'user: `{}`'.format(obj.username),
'type': 'user',
'icon_link': h.gravatar_url(obj.email, 30),
'url': h.route_path(
'user_profile', username=obj.username)
}
for obj in acl_iter]
for obj in acl_iter], True
def _get_user_groups_list(self, name_contains=None, limit=20):
org_query = name_contains
if not name_contains:
return []
return [], False
name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
# TODO(marcink): should all logged in users be allowed to search others?
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
if not allowed_user_search:
return [], False
name_contains = re.compile('(?:user_group:[ ]?)(.+)').findall(name_contains)
if len(name_contains) != 1:
return []
return [], False
name_contains = name_contains[0]
query = UserGroup.query()\
@ -241,27 +266,34 @@ class HomeView(BaseAppView):
{
'id': obj.users_group_id,
'value': org_query,
'value_display': obj.users_group_name,
'value_display': 'user_group: `{}`'.format(obj.users_group_name),
'type': 'user_group',
'url': h.route_path(
'user_group_profile', user_group_name=obj.users_group_name)
}
for obj in acl_iter]
for obj in acl_iter], True
def _get_hash_commit_list(self, auth_user, searcher, query, repo=None, repo_group=None):
repo_name = repo_group_name = None
if repo:
repo_name = repo.repo_name
if repo_group:
repo_group_name = repo_group.group_name
def _get_hash_commit_list(self, auth_user, searcher, query):
org_query = query
if not query or len(query) < 3 or not searcher:
return []
return [], False
commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
commit_hashes = re.compile('(?:commit:[ ]?)([0-9a-f]{2,40})').findall(query)
if len(commit_hashes) != 1:
return []
return [], False
commit_hash = commit_hashes[0]
result = searcher.search(
'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
raise_on_exc=False)
repo_name, repo_group_name, raise_on_exc=False)
commits = []
for entry in result['results']:
@ -286,7 +318,55 @@ class HomeView(BaseAppView):
}
commits.append(commit_entry)
return commits
return commits, True
def _get_path_list(self, auth_user, searcher, query, repo=None, repo_group=None):
repo_name = repo_group_name = None
if repo:
repo_name = repo.repo_name
if repo_group:
repo_group_name = repo_group.group_name
org_query = query
if not query or len(query) < 3 or not searcher:
return [], False
paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query)
if len(paths_re) != 1:
return [], False
file_path = paths_re[0]
search_path = searcher.escape_specials(file_path)
result = searcher.search(
'file.raw:*{}*'.format(search_path), 'path', auth_user,
repo_name, repo_group_name, raise_on_exc=False)
files = []
for entry in result['results']:
repo_data = {
'repository_id': entry.get('repository_id'),
'repository_type': entry.get('repo_type'),
'repository_name': entry.get('repository'),
}
file_entry = {
'id': entry['commit_id'],
'value': org_query,
'value_display': '`{}` file: {}'.format(
entry['repository'], entry['file']),
'type': 'file',
'repo': entry['repository'],
'repo_data': repo_data,
'url': h.route_path(
'repo_files',
repo_name=entry['repository'], commit_id=entry['commit_id'],
f_path=entry['file'])
}
files.append(file_entry)
return files, True
@LoginRequired()
@view_config(
@ -363,36 +443,42 @@ class HomeView(BaseAppView):
def query_modifier():
qry = query
return {'q': qry, 'type': 'content'}
label = u'File search for `{}` in this repository.'.format(query)
queries.append(
{
'id': -10,
'value': query,
'value_display': label,
'type': 'search',
'url': h.route_path('search_repo',
repo_name=repo_name,
_query=query_modifier())
label = u'File search for `{}`'.format(h.escape(query))
file_qry = {
'id': -10,
'value': query,
'value_display': label,
'type': 'search',
'subtype': 'repo',
'url': h.route_path('search_repo',
repo_name=repo_name,
_query=query_modifier())
}
)
# commits
def query_modifier():
qry = query
return {'q': qry, 'type': 'commit'}
label = u'Commit search for `{}` in this repository.'.format(query)
queries.append(
{
'id': -20,
'value': query,
'value_display': label,
'type': 'search',
'url': h.route_path('search_repo',
repo_name=repo_name,
_query=query_modifier())
label = u'Commit search for `{}`'.format(h.escape(query))
commit_qry = {
'id': -20,
'value': query,
'value_display': label,
'type': 'search',
'subtype': 'repo',
'url': h.route_path('search_repo',
repo_name=repo_name,
_query=query_modifier())
}
)
if repo_context in ['commit', 'commits']:
queries.extend([commit_qry, file_qry])
elif repo_context in ['files', 'summary']:
queries.extend([file_qry, commit_qry])
else:
queries.extend([commit_qry, file_qry])
elif is_es_6 and repo_group_name:
# files
@ -400,37 +486,43 @@ class HomeView(BaseAppView):
qry = query
return {'q': qry, 'type': 'content'}
label = u'File search for `{}` in this repository group'.format(query)
queries.append(
{
'id': -30,
'value': query,
'value_display': label,
'type': 'search',
'url': h.route_path('search_repo_group',
repo_group_name=repo_group_name,
_query=query_modifier())
label = u'File search for `{}`'.format(query)
file_qry = {
'id': -30,
'value': query,
'value_display': label,
'type': 'search',
'subtype': 'repo_group',
'url': h.route_path('search_repo_group',
repo_group_name=repo_group_name,
_query=query_modifier())
}
)
# commits
def query_modifier():
qry = query
return {'q': qry, 'type': 'commit'}
label = u'Commit search for `{}` in this repository group'.format(query)
queries.append(
{
'id': -40,
'value': query,
'value_display': label,
'type': 'search',
'url': h.route_path('search_repo_group',
repo_group_name=repo_group_name,
_query=query_modifier())
label = u'Commit search for `{}`'.format(query)
commit_qry = {
'id': -40,
'value': query,
'value_display': label,
'type': 'search',
'subtype': 'repo_group',
'url': h.route_path('search_repo_group',
repo_group_name=repo_group_name,
_query=query_modifier())
}
)
if repo_context in ['commit', 'commits']:
queries.extend([commit_qry, file_qry])
elif repo_context in ['files', 'summary']:
queries.extend([file_qry, commit_qry])
else:
queries.extend([commit_qry, file_qry])
# Global, not scoped
if not queries:
queries.append(
{
@ -438,6 +530,7 @@ class HomeView(BaseAppView):
'value': query,
'value_display': u'File search for: `{}`'.format(query),
'type': 'search',
'subtype': 'global',
'url': h.route_path('search',
_query={'q': query, 'type': 'content'})
})
@ -447,6 +540,7 @@ class HomeView(BaseAppView):
'value': query,
'value_display': u'Commit search for: `{}`'.format(query),
'type': 'search',
'subtype': 'global',
'url': h.route_path('search',
_query={'q': query, 'type': 'commit'})
})
@ -469,54 +563,107 @@ class HomeView(BaseAppView):
if not query:
return {'suggestions': res}
def no_match(name):
return {
'id': -1,
'value': "",
'value_display': name,
'type': 'text',
'url': ""
}
searcher = searcher_from_config(self.request.registry.settings)
for _q in self._get_default_search_queries(self.request.GET, searcher, query):
res.append(_q)
has_specialized_search = False
# set repo context
repo = None
repo_id = safe_int(self.request.GET.get('search_context[repo_id]'))
if repo_id:
repo = Repository.get(repo_id)
# set group context
repo_group = None
repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
if repo_group_id:
repo_group = RepoGroup.get(repo_group_id)
composed_hint = '{}/{}'.format(repo_group.group_name, query)
show_hint = not query.startswith(repo_group.group_name)
if repo_group and show_hint:
hint = u'Repository search inside: `{}`'.format(composed_hint)
res.append({
'id': -1,
'value': composed_hint,
'value_display': hint,
'type': 'hint',
'url': ""
})
prefix_match = False
repo_groups = self._get_repo_group_list(query)
for serialized_repo_group in repo_groups:
res.append(serialized_repo_group)
# user: type search
if not prefix_match:
users, prefix_match = self._get_user_list(query)
if users:
has_specialized_search = True
for serialized_user in users:
res.append(serialized_user)
elif prefix_match:
has_specialized_search = True
res.append(no_match('No matching users found'))
repos = self._get_repo_list(query)
for serialized_repo in repos:
res.append(serialized_repo)
# user_group: type search
if not prefix_match:
user_groups, prefix_match = self._get_user_groups_list(query)
if user_groups:
has_specialized_search = True
for serialized_user_group in user_groups:
res.append(serialized_user_group)
elif prefix_match:
has_specialized_search = True
res.append(no_match('No matching user groups found'))
# TODO(marcink): should all logged in users be allowed to search others?
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
if allowed_user_search:
users = self._get_user_list(query)
for serialized_user in users:
res.append(serialized_user)
user_groups = self._get_user_groups_list(query)
for serialized_user_group in user_groups:
res.append(serialized_user_group)
commits = self._get_hash_commit_list(c.auth_user, searcher, query)
if commits:
unique_repos = collections.OrderedDict()
for commit in commits:
repo_name = commit['repo']
unique_repos.setdefault(repo_name, []).append(commit)
for repo, commits in unique_repos.items():
# FTS commit: type search
if not prefix_match:
commits, prefix_match = self._get_hash_commit_list(
c.auth_user, searcher, query, repo, repo_group)
if commits:
has_specialized_search = True
unique_repos = collections.OrderedDict()
for commit in commits:
res.append(commit)
repo_name = commit['repo']
unique_repos.setdefault(repo_name, []).append(commit)
for _repo, commits in unique_repos.items():
for commit in commits:
res.append(commit)
elif prefix_match:
has_specialized_search = True
res.append(no_match('No matching commits found'))
# FTS file: type search
if not prefix_match:
paths, prefix_match = self._get_path_list(
c.auth_user, searcher, query, repo, repo_group)
if paths:
has_specialized_search = True
unique_repos = collections.OrderedDict()
for path in paths:
repo_name = path['repo']
unique_repos.setdefault(repo_name, []).append(path)
for repo, paths in unique_repos.items():
for path in paths:
res.append(path)
elif prefix_match:
has_specialized_search = True
res.append(no_match('No matching files found'))
# main suggestions
if not has_specialized_search:
repo_group_name = ''
if repo_group:
repo_group_name = repo_group.group_name
for _q in self._get_default_search_queries(self.request.GET, searcher, query):
res.append(_q)
repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
for serialized_repo_group in repo_groups:
res.append(serialized_repo_group)
repos = self._get_repo_list(query, repo_group_name=repo_group_name)
for serialized_repo in repos:
res.append(serialized_repo)
if not repos and not repo_groups:
res.append(no_match('No matches found'))
return {'suggestions': res}
@ -564,8 +711,11 @@ class HomeView(BaseAppView):
def repo_group_main_page(self):
c = self.load_default_context()
c.repo_group = self.request.db_repo_group
repo_data, repo_group_data = self._get_groups_and_repos(
c.repo_group.group_id)
repo_data, repo_group_data = self._get_groups_and_repos(c.repo_group.group_id)
# update every 5 min
if self.request.db_repo_group.last_commit_cache_update_diff > 60 * 5:
self.request.db_repo_group.update_commit_cache()
# json used to render the grids
c.repos_data = json.dumps(repo_data)
@ -591,6 +741,34 @@ class HomeView(BaseAppView):
return h.render(text, renderer=renderer, mentions=True)
return ''
@LoginRequired()
@CSRFRequired()
@view_config(
route_name='file_preview', request_method='POST',
renderer='string', xhr=True)
def file_preview(self):
# Technically a CSRF token is not needed as no state changes with this
# call. However, as this is a POST is better to have it, so automated
# tools don't flag it as potential CSRF.
# Post is required because the payload could be bigger than the maximum
# allowed by GET.
text = self.request.POST.get('text')
file_path = self.request.POST.get('file_path')
renderer = h.renderer_from_filename(file_path)
if renderer:
return h.render(text, renderer=renderer, mentions=True)
else:
self.load_default_context()
_render = self.request.get_partial_renderer(
'rhodecode:templates/files/file_content.mako')
lines = filenode_as_lines_tokens(FileNode(file_path, text))
return _render('render_lines', lines)
@LoginRequired()
@CSRFRequired()
@view_config(
@ -604,4 +782,4 @@ class HomeView(BaseAppView):
if existing_value != val:
self.request.session[key] = val
return 'stored:{}'.format(key)
return 'stored:{}:{}'.format(key, val)

View file

@ -31,12 +31,12 @@ from pyramid.renderers import render
from rhodecode.apps._base import BaseAppView
from rhodecode.model.db import (
or_, joinedload, UserLog, UserFollowing, User, UserApiKeys)
or_, joinedload, Repository, UserLog, UserFollowing, User, UserApiKeys)
from rhodecode.model.meta import Session
import rhodecode.lib.helpers as h
from rhodecode.lib.helpers import Page
from rhodecode.lib.user_log_filter import user_log_filter
from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, HasRepoPermissionAny
from rhodecode.lib.utils2 import safe_int, AttributeDict, md5_safe
from rhodecode.model.scm import ScmModel
@ -153,7 +153,7 @@ class JournalView(BaseAppView):
desc = action_extra()
_url = h.route_url('home')
if entry.repository is not None:
_url = h.route_url('repo_changelog',
_url = h.route_url('repo_commits',
repo_name=entry.repository.repo_name)
feed.add_item(
@ -199,7 +199,7 @@ class JournalView(BaseAppView):
desc = action_extra()
_url = h.route_url('home')
if entry.repository is not None:
_url = h.route_url('repo_changelog',
_url = h.route_url('repo_commits',
repo_name=entry.repository.repo_name)
feed.add_item(
@ -297,18 +297,19 @@ class JournalView(BaseAppView):
user_id = self.request.POST.get('follows_user_id')
if user_id:
try:
ScmModel().toggle_following_user(
user_id, self._rhodecode_user.user_id)
ScmModel().toggle_following_user(user_id, self._rhodecode_user.user_id)
Session().commit()
return 'ok'
except Exception:
raise HTTPBadRequest()
repo_id = self.request.POST.get('follows_repo_id')
if repo_id:
repo = Repository.get_or_404(repo_id)
perm_set = ['repository.read', 'repository.write', 'repository.admin']
has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'RepoWatch check')
if repo and has_perm:
try:
ScmModel().toggle_following_repo(
repo_id, self._rhodecode_user.user_id)
ScmModel().toggle_following_repo(repo_id, self._rhodecode_user.user_id)
Session().commit()
return 'ok'
except Exception:

Some files were not shown because too many files have changed in this diff Show more