Changeset - 7f9040460576
[Not reviewed]
Merge default
1 58 5
Mads Kiilerich - 10 years ago 2015-10-02 22:46:15
madski@unity3d.com
Merge stable 0.3
63 files changed with 2096 insertions and 860 deletions:
0 comments (0 inline, 0 general)
.hgignore
Show inline comments
 
@@ -7,24 +7,25 @@ syntax: glob
 
*.egg
 
*.mo
 
.eggs/
 
tarballcache/
 

	
 
syntax: regexp
 
^rcextensions
 
^build
 
^dist/
 
^docs/build/
 
^docs/_build/
 
^data$
 
^kallithea/tests/data$
 
^sql_dumps/
 
^\.settings$
 
^\.project$
 
^\.pydevproject$
 
^\.coverage$
 
^kallithea\.db$
 
^test\.db$
 
^Kallithea\.egg-info$
 
^my\.ini$
 
^fabfile.py
 
^\.idea$
 
^\.cache$
.hgsigs
Show inline comments
 
new file 100644
 
9b3e9e242f5c97cc0c7657e5ac93dce7de61ca16 0 iQEcBAABAgAGBQJWDuAdAAoJEJ1bI/kYT6UUAlYH/ReCa7Im5tvy+ot5oAc7xey/O2rCVHp2h6i82tTWK/0i9EaS4DP+eTbAjV4WJA4qWF5DPenEJ3X9JhrTLNvGkR0f7lUqiFVMTJ472YlSsvIWg38gVFruzwk1cODRfq72o8ERYcRSfzrL4cDpIqjEd/vVVCV/gKVvPmzr4/FED/ZmS0X6T9gxWJo/eWSuLNAxHHtE/pCWDO3XEe+iOm+hHjkyz4Hn2r9/+ucrirnzycH6DnYO/kWvQzBnzgMjJm+1rLZ5cfU89V8zfhv6z0pd8CHZfpKGc2Z8EwVJq9LR+M4/76uDlYXx7IfZAxhRNqN6MC+yvPmDo3382dNr7Wkopi0=
.hgtags
Show inline comments
 
@@ -40,24 +40,25 @@ dbc82e3362a25d2aece42060089824c4342efd17
 
9ab21c5ddb84935bea5c743b4e147ed5a398b30c rhodecode-0.0.1.3.2
 
934906f028b582a254e0028ba25e5d20dd32b9cd rhodecode-0.0.1.3.3
 
af21362474e3ab5aa0e2fbb1c872356f2c16c4f3 rhodecode-0.0.1.3.4
 
0e2792e04bd316fe64335cbe6a476031ac60b29b rhodecode-0.0.1.3.5
 
edfff9f37916389144d3a3644d0a7d7adfd79b11 rhodecode-0.0.1.3.6
 
9ae95fdeca184f2404205645f06c6597b74ef2db rhodecode-0.0.1.4.0
 
909143a4dde53c46d4f24abb426ec870471c7de1 rhodecode-0.0.1.4.1
 
d998cc84cf726798486a438763053f0e1dc1b646 rhodecode-0.0.1.4.2
 
3f5d40b9dd99ccb009ea2211ee2d4b594c634946 rhodecode-0.0.1.4.3
 
3148c08cf86f1849917e2d50f7ab7766c1550b0a rhodecode-0.0.1.4.4
 
a5f0bc867edc88be23eb808693e5393a97d4c54a rhodecode-0.0.1.5.0
 
3259dc7caea48687eab018ee646ae6ad7e7ef377 rhodecode-0.0.1.5.1
 
efe23d6c178c11d575a0214181276a3452776e48 rhodecode-0.0.1.5.2
 
1a498b11f1540f5b94b6f6009298f5dc3eaad9e9 rhodecode-0.0.1.5.3
 
3447862ad8c9ceba85857774c526e39fde3a2281 rhodecode-0.0.1.5.4
 
c15d7b336af58df9f1bbc8f8957464e7ea618d4c rhodecode-0.0.1.6.0rc1
 
78b53ee0d247f90d51b028307ff5717851b6c265 rhodecode-0.0.1.6.0
 
351ad34d56321349ff5bd38f537bd768b8efef2e rhodecode-0.0.1.7.0
 
1f71ef689d2a3c9978cea6591a1f4e9107a5ca83 rhodecode-0.0.1.7.1
 
cc48c1541c7e2e84114bf92a0f9cd4b8b1341545 0.0
 
d17e88a1a88a29f6fac948c94498129e405a40d3 0.1
 
ad0ce803b40cb17fc3988373052943e041030b02 0.2
 
c6e32714336345403adf76abb6ebf9b8116fcdc7 0.2.1
 
14f488a5dc4ca6647bc6acf12534fd137e968aa8 0.2.2
 
9b3e9e242f5c97cc0c7657e5ac93dce7de61ca16 0.3
CONTRIBUTORS
Show inline comments
 
@@ -14,48 +14,49 @@ List of contributors to Kallithea projec
 
    Balázs Úr <urbalazs@gmail.com> 2015
 
    Ben Finney <ben@benfinney.id.au> 2015
 
    Branko Majic <branko@majic.rs> 2015
 
    Daniel Hobley <danielh@unity3d.com> 2015
 
    David Avigni <david.avigni@ankapi.com> 2015
 
    Denis Blanchette <dblanchette@coveo.com> 2015
 
    duanhongyi <duanhongyi@doopai.com> 2015
 
    EriCSN Chang <ericsning@gmail.com> 2015
 
    Étienne Gilli <etienne.gilli@gmail.com> 2015
 
    Grzegorz Krason <grzegorz.krason@gmail.com> 2015
 
    Jan Heylen <heyleke@gmail.com> 2015
 
    Kazunari Kobayashi <kobanari@nifty.com> 2015
 
    Kevin Bullock <kbullock@ringworld.org> 2015
 
    kobanari <kobanari@nifty.com> 2015
 
    Marc Abramowitz <marc@marc-abramowitz.com> 2015
 
    Marc Villetard <marc.villetard@gmail.com> 2015
 
    Matthias Zilk <matthias.zilk@gmail.com> 2015
 
    Michael Pohl <michael@mipapo.de> 2015
 
    Michael V. DePalatis <mike@depalatis.net> 2015
 
    Morten Skaaning <mortens@unity3d.com> 2015
 
    Nick High <nick@silverchip.org> 2015
 
    Niemand Jedermann <predatorix@web.de> 2015
 
    Peter Vitt <petervitt@web.de> 2015
 
    Robert Martinez <ntttq@inboxen.org> 2015
 
    Robert Rauch <mail@robertrauch.de> 2015
 
    Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> 2015
 
    Sam Jaques <sam.jaques@me.com> 2015
 
    Søren Løvborg <sorenl@unity3d.com> 2015
 
    Tuux <tuxa@galaxie.eu.org> 2015
 
    Viktar Palstsiuk <vipals@gmail.com> 2015
 
    Dominik Ruf <dominikruf@gmail.com> 2012 2014
 
    Bradley M. Kuhn <bkuhn@sfconservancy.org> 2014
 
    Calinou <calinou@opmbx.org> 2014
 
    Daniel Anderson <daniel@dattrix.com> 2014
 
    Henrik Stuart <hg@hstuart.dk> 2014
 
    Ingo von Borstel <kallithea@planetmaker.de> 2014
 
    Jelmer Vernooij <jelmer@samba.org> 2014
 
    Jim Hague <jim.hague@acm.org> 2014
 
    Matt Fellows <kallithea@matt-fellows.me.uk> 2014
 
    Max Roman <max@choloclos.se> 2014
 
    Michal Čihař <michal@cihar.com> 2014
 
    Na'Tosha Bard <natosha@unity3d.com> 2014
 
    Rasmus Selsmark <rasmuss@unity3d.com> 2014
 
    Tim Freund <tim@freunds.net> 2014
 
    Travis Burtrum <android@moparisthebest.com> 2014
 
    Zoltan Gyarmati <mr.zoltan.gyarmati@gmail.com> 2014
 
    Marcin Kuźmiński <marcin@python-works.com> 2010-2013
 
    xpol <xpolife@gmail.com> 2012-2013
 
    Aparkar <aparkar@icloud.com> 2013
README.rst
Show inline comments
 
@@ -16,48 +16,55 @@ Kallithea is similar in some respects to
 
Kallithea can be run as standalone hosted application on your own server. It is
 
open-source donationware and focuses more on providing a customised,
 
self-administered interface for Mercurial_ and Git_ repositories. Kallithea
 
works on Unix-like systems and Windows, and is powered by the vcs_ library
 
created by Łukasz Balcerzak and Marcin Kuźmiński to uniformly handle multiple
 
version control systems.
 

	
 
Kallithea was forked from RhodeCode in July 2014 and has been heavily modified.
 

	
 

	
 
Installation
 
------------
 

	
 
Kallithea requires Python_ 2.x and it is recommended to install it in a
 
virtualenv_. Official releases of Kallithea can be installed with::
 

	
 
    pip install kallithea
 

	
 
The development repository is kept very stable and used in production by the
 
developers -- you can do the same.
 

	
 
Please visit https://docs.kallithea-scm.org/en/latest/installation.html for
 
more details.
 

	
 
There is also an experimental `Puppet module`_ for installing and setting up
 
Kallithea. Currently, only basic functionality is provided, but it is still
 
enough to get up and running quickly, especially for people without Python
 
background. See
 
https://docs.kallithea-scm.org/en/latest/installation_puppet.html for further
 
information.
 

	
 

	
 
Source code
 
-----------
 

	
 
The latest sources can be obtained from
 
https://kallithea-scm.org/repos/kallithea.
 

	
 
The issue tracker and a repository mirror can be found at Bitbucket_ on
 
https://bitbucket.org/conservancy/kallithea.
 

	
 

	
 
Kallithea features
 
------------------
 

	
 
- Has its own middleware to handle Mercurial_ and Git_ protocol requests. Each
 
  request is authenticated and logged together with IP address.
 
- Built for speed and performance. You can make multiple pulls/pushes
 
  simultaneously. Proven to work with thousands of repositories and users.
 
- Supports http/https, LDAP, AD, proxy-pass authentication.
 
- Full permissions (private/read/write/admin) together with IP restrictions for
 
  each repository, additional explicit forking, repositories group and
 
  repository creation permissions.
 
- User groups for easier permission management.
 
- Repository groups let you group repos and manage them easier. They come with
 
@@ -157,84 +164,85 @@ You can also build the documentation loc
 

	
 
Converting from RhodeCode
 
-------------------------
 

	
 
Currently, you have two options for working with an existing RhodeCode
 
database:
 

	
 
- keep the database unconverted (intended for testing and evaluation)
 
- convert the database in a one-time step
 

	
 
Maintaining interoperability
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Interoperability with RhodeCode 2.2.X installations is provided so you don't
 
have to immediately commit to switching to Kallithea. This option will most
 
likely go away once the two projects have diverged significantly.
 

	
 
To run Kallithea on a RhodeCode database, run::
 

	
 
   echo "BRAND = 'rhodecode'" > kallithea/brand.py
 

	
 
This location will depend on where you installed Kallithea. If you installed
 
via::
 

	
 
   python setup.py install
 
   python2 setup.py install
 

	
 
then you will find this location at
 
``$VIRTUAL_ENV/lib/python2.7/site-packages/Kallithea-0.1-py2.7.egg/kallithea``.
 

	
 
One-time conversion
 
~~~~~~~~~~~~~~~~~~~
 

	
 
Alternatively, if you would like to convert the database for good, you can use
 
a helper script provided by Kallithea. This script will operate directly on the
 
database, using the database string you can find in your ``production.ini`` (or
 
``development.ini``) file. For example, if using SQLite::
 

	
 
   cd /path/to/kallithea
 
   cp /path/to/rhodecode/rhodecode.db kallithea.db
 
   pip install sqlalchemy-migrate
 
   python kallithea/bin/rebranddb.py sqlite:///kallithea.db
 
   python2 kallithea/bin/rebranddb.py sqlite:///kallithea.db
 

	
 
.. Note::
 

	
 
   If you started out using the branding interoperability approach mentioned
 
   above, watch out for stray brand.pyc after removing brand.py.
 

	
 
Git hooks
 
~~~~~~~~~
 

	
 
After switching to Kallithea, it will be necessary to update the Git_ hooks in
 
your repositories. If not, the Git_ hooks from RhodeCode will still be called,
 
which will cause ``git push`` to fail every time.
 

	
 
If you do not have any custom Git_ hooks deployed, perform the following steps
 
(this may take some time depending on the number and size of repositories you
 
have):
 

	
 
1. Log-in as an administrator.
 

	
 
2. Open page *Admin > Settings > Remap and Rescan*.
 

	
 
3. Turn on the option **Install Git Hooks**.
 

	
 
4. Turn on the option **Overwrite existing Git hooks**.
 

	
 
5. Click on the button **Rescan Repositories**.
 

	
 
If you do have custom hooks, you will need to merge those changes manually. In
 
order to get sample hooks from Kallithea, the easiest way is to create a new Git_
 
repository, and have a look at the hooks deployed there.
 

	
 

	
 
.. _virtualenv: http://pypi.python.org/pypi/virtualenv
 
.. _Python: http://www.python.org/
 
.. _Sphinx: http://sphinx.pocoo.org/
 
.. _Mercurial: http://mercurial.selenic.com/
 
.. _Bitbucket: http://bitbucket.org/
 
.. _GitHub: http://github.com/
 
.. _Subversion: http://subversion.tigris.org/
 
.. _Git: http://git-scm.com/
 
.. _Celery: http://celeryproject.org/
 
.. _vcs: http://pypi.python.org/pypi/vcs
 
.. _Software Freedom Conservancy: http://sfconservancy.org/
 
.. _Puppet module: https://forge.puppetlabs.com/rauch/kallithea
development.ini
Show inline comments
 
@@ -36,49 +36,49 @@ pdebug = false
 
## Default:
 
#email_prefix =
 
## Example:
 
#email_prefix = [Kallithea]
 

	
 
## Recipients for error emails and fallback recipients of application mails.
 
## Multiple addresses can be specified, space-separated.
 
## Only addresses are allowed, do not add any name part.
 
## Default:
 
#email_to =
 
## Examples:
 
#email_to = admin@example.com
 
#email_to = admin@example.com another_admin@example.com
 

	
 
## 'From' header for error emails. You can optionally add a name.
 
## Default:
 
#error_email_from = pylons@yourapp.com
 
## Examples:
 
#error_email_from = Kallithea Errors <kallithea-noreply@example.com>
 
#error_email_from = paste_error@example.com
 

	
 
## SMTP server settings
 
## Only smtp_server is mandatory. All other settings take the specified default
 
## values.
 
#smtp_server = mail.server.com
 
#smtp_server = smtp.example.com
 
#smtp_username =
 
#smtp_password =
 
#smtp_port = 25
 
#smtp_use_tls = false
 
#smtp_use_ssl = false
 
## SMTP authentication parameters to use (e.g. LOGIN PLAIN CRAM-MD5, etc.).
 
## If empty, use any of the authentication parameters supported by the server.
 
#smtp_auth =
 

	
 
[server:main]
 
## PASTE ##
 
#use = egg:Paste#http
 
## nr of worker threads to spawn
 
#threadpool_workers = 5
 
## max request before thread respawn
 
#threadpool_max_requests = 10
 
## option to use threads of process
 
#use_threadpool = true
 

	
 
## WAITRESS ##
 
use = egg:waitress#main
 
## number of worker threads
 
threads = 5
 
## MAX BODY SIZE 100GB
 
@@ -207,98 +207,98 @@ force_https = false
 
## use Strict-Transport-Security headers
 
use_htsts = false
 

	
 
## number of commits stats will parse on each iteration
 
commit_parse_limit = 25
 

	
 
## path to git executable
 
git_path = git
 

	
 
## git rev filter option, --all is the default filter, if you need to
 
## hide all refs in changelog switch this to --branches --tags
 
#git_rev_filter = --branches --tags
 

	
 
## RSS feed options
 
rss_cut_off_limit = 256000
 
rss_items_per_page = 10
 
rss_include_diff = false
 

	
 
## options for showing and identifying changesets
 
show_sha_length = 12
 
show_revision_number = false
 

	
 
## gist URL alias, used to create nicer urls for gist. This should be an
 
## url that does rewrites to _admin/gists/<gistid>.
 
## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
 
## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
 
## example: http://gist.example.com/{gistid}. Empty means use the internal
 
## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
 
gist_alias_url =
 

	
 
## white list of API enabled controllers. This allows to add list of
 
## controllers to which access will be enabled by api_key. eg: to enable
 
## api access to raw_files put `FilesController:raw`, to enable access to patches
 
## add `ChangesetController:changeset_patch`. This list should be "," separated
 
## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
 
## Recommended settings below are commented out:
 
api_access_controllers_whitelist =
 
#    ChangesetController:changeset_patch,
 
#    ChangesetController:changeset_raw,
 
#    FilesController:raw,
 
#    FilesController:archivefile
 

	
 
## default encoding used to convert from and to unicode
 
## can be also a comma seperated list of encoding in case of mixed encodings
 
default_encoding = utf8
 

	
 
## issue tracker for Kallithea (leave blank to disable, absent for default)
 
#bugtracker = https://bitbucket.org/conservancy/kallithea/issues
 

	
 
## issue tracking mapping for commits messages
 
## comment out issue_pat, issue_server, issue_prefix to enable
 

	
 
## pattern to get the issues from commit messages
 
## default one used here is #<numbers> with a regex passive group for `#`
 
## {id} will be all groups matched from this pattern
 

	
 
issue_pat = (?:\s*#)(\d+)
 

	
 
## server url to the issue, each {id} will be replaced with match
 
## fetched from the regex and {repo} is replaced with full repository name
 
## including groups {repo_name} is replaced with just name of repo
 

	
 
issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
issue_server_link = https://issues.example.com/{repo}/issue/{id}
 

	
 
## prefix to add to link to indicate it's an url
 
## #314 will be replaced by <issue_prefix><id>
 

	
 
issue_prefix = #
 

	
 
## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
 
## multiple patterns, to other issues server, wiki or others
 
## below an example how to create a wiki pattern
 
# wiki-some-id -> https://mywiki.com/some-id
 
# wiki-some-id -> https://wiki.example.com/some-id
 

	
 
#issue_pat_wiki = (?:wiki-)(.+)
 
#issue_server_link_wiki = https://mywiki.com/{id}
 
#issue_server_link_wiki = https://wiki.example.com/{id}
 
#issue_prefix_wiki = WIKI-
 

	
 
## instance-id prefix
 
## a prefix key for this instance used for cache invalidation when running
 
## multiple instances of kallithea, make sure it's globally unique for
 
## all running kallithea instances. Leave empty if you don't use it
 
instance_id =
 

	
 
## alternative return HTTP header for failed authentication. Default HTTP
 
## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 
## allows to change the repository location in settings page
 
allow_repo_location_change = True
 

	
 
## allows to setup custom hooks in settings page
 
allow_custom_hooks_settings = True
 

	
 
####################################
docs/api/api.rst
Show inline comments
 
@@ -28,106 +28,105 @@ For example, to enable API access to pat
 
        FilesController:raw,
 
        FilesController:archivefile
 

	
 
After this change, a Kallithea view can be accessed without login by adding a
 
GET parameter ``?api_key=<api_key>`` to the URL.
 

	
 
Exposing raw diffs is a good way to integrate with
 
third-party services like code review, or build farms that can download archives.
 

	
 

	
 
API access
 
++++++++++
 

	
 
Clients must send JSON encoded JSON-RPC requests::
 

	
 
    {
 
        "id: "<id>",
 
        "api_key": "<api_key>",
 
        "method": "<method_name>",
 
        "args": {"<arg_key>": "<arg_val>"}
 
    }
 

	
 
For example, to pull to a local "CPython" mirror using curl::
 

	
 
    curl https://example.com/_admin/api -X POST -H 'content-type:text/plain' \
 
    curl https://kallithea.example.com/_admin/api -X POST -H 'content-type:text/plain' \
 
        --data-binary '{"id":1,"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
 

	
 
In general, provide
 
 - *id*, a value of any type, can be used to match the response with the request that it is replying to.
 
 - *api_key*, for authentication and permission validation.
 
 - *method*, the name of the method to call -- a list of available methods can be found below.
 
 - *args*, the arguments to pass to the method.
 

	
 
.. note::
 

	
 
    api_key can be found or set on the user account page.
 

	
 
The response to the JSON-RPC API call will always be a JSON structure::
 

	
 
    {
 
        "id": <id>,  # the id that was used in the request
 
        "result": <result>|null,  # JSON formatted result (null on error)
 
        "error": null|<error_message>  # JSON formatted error (null on success)
 
    }
 

	
 
All responses from the API will be ``HTTP/1.0 200 OK``. If an error occurs,
 
the reponse will have a failure description in *error* and
 
*result* will be null.
 

	
 

	
 
API client
 
++++++++++
 

	
 
Kallithea comes with a ``kallithea-api`` command line tool, providing a convenient
 
way to call the JSON-RPC API.
 

	
 
For example, to call ``get_repo``::
 

	
 
 kallithea-api --apihost=<your.kallithea.server.url> --apikey=<yourapikey> get_repo
 
    kallithea-api --apihost=<Kallithea URL> --apikey=<API key> get_repo
 

	
 
 calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
 
 Kallithea said:
 
 {'error': 'Missing non optional `repoid` arg in JSON DATA',
 
  'id': 75,
 
  'result': None}
 
    Calling method get_repo => <Kallithea URL>
 
    Server response
 
    ERROR:"Missing non optional `repoid` arg in JSON DATA"
 

	
 
Oops, looks like we forgot to add an argument. Let's try again, now
 
providing the ``repoid`` as a parameter::
 

	
 
    kallithea-api get_repo repoid:myrepo
 
    kallithea-api --apihost=<Kallithea URL> --apikey=<API key> get_repo repoid:myrepo
 

	
 
    calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "myrepo"}, "method": "get_repo"} to http://127.0.0.1:5000
 
    Kallithea said:
 
    {'error': None,
 
     'id': 39,
 
     'result': <json data...>}
 
    Calling method get_repo => <Kallithea URL>
 
    Server response
 
    {
 
        "clone_uri": null,
 
        "created_on": "2015-08-31T14:55:19.042",
 
    ...
 

	
 
To avoid specifying ``apihost`` and ``apikey`` every time, run::
 

	
 
  kallithea-api --save-config --apihost=<your.kallithea.server.url> --apikey=<yourapikey>
 
    kallithea-api --save-config --apihost=<Kallithea URL> --apikey=<API key>
 

	
 
This will create a ``~/.config/kallithea`` with the specified hostname and API key
 
This will create a ``~/.config/kallithea`` with the specified URL and API key
 
so you don't have to specify them every time.
 

	
 

	
 
API methods
 
+++++++++++
 

	
 

	
 
pull
 
----
 

	
 
Pull the given repo from remote location. Can be used to automatically keep
 
remote repos up to date.
 
This command can only be executed using the api_key of a user with admin rights.
 

	
 
INPUT::
 

	
 
    id : <id_for_response>
 
    api_key : "<api_key>"
 
    method :  "pull"
 
    args :    {
 
                "repoid" : "<reponame or repo_id>"
 
              }
 

	
 
OUTPUT::
docs/contributing.rst
Show inline comments
 
@@ -13,49 +13,50 @@ Infrastructure
 

	
 
The main repository is hosted on Our Own Kallithea (aka OOK) at
 
https://kallithea-scm.org/repos/kallithea/, our self-hosted instance
 
of Kallithea.
 

	
 
For now, we use Bitbucket_ for `pull requests`_ and `issue tracking`_. The
 
issue tracker is for tracking bugs, not for support, discussion, or ideas --
 
please use the `mailing list`_ or :ref:`IRC <readme>` to reach the community.
 

	
 
We use Weblate_ to translate the user interface messages into languages other
 
than English. Join our project on `Hosted Weblate`_ to help us.
 
To register, you can use your Bitbucket or GitHub account. See :ref:`translations`
 
for more details.
 

	
 

	
 
Getting started
 
---------------
 

	
 
To get started with development::
 

	
 
        hg clone https://kallithea-scm.org/repos/kallithea
 
        cd kallithea
 
        virtualenv ../kallithea-venv
 
        source ../kallithea-venv/bin/activate
 
        python setup.py develop
 
        pip install --upgrade pip setuptools
 
        python2 setup.py develop
 
        paster make-config Kallithea my.ini
 
        paster setup-db my.ini --user=user --email=user@example.com --password=password --repos=/tmp
 
        paster serve my.ini --reload &
 
        firefox http://127.0.0.1:5000/
 

	
 
You can also start out by forking https://bitbucket.org/conservancy/kallithea
 
on Bitbucket_ and create a local clone of your own fork.
 

	
 

	
 
Running tests
 
-------------
 

	
 
After finishing your changes make sure all tests pass cleanly. You can run
 
the testsuite running ``nosetests`` from the project root, or if you use tox
 
run ``tox`` for Python 2.6--2.7 with multiple database test.
 

	
 
When running tests, Kallithea uses `kallithea/tests/test.ini` and populates the
 
SQLite database specified there.
 

	
 
It is possible to avoid recreating the full test database on each invocation of
 
the tests, thus eliminating the initial delay. To achieve this, run the tests as::
 

	
 
    paster serve kallithea/tests/test.ini --pid-file=test.pid --daemon
 
    KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 nosetests
docs/index.rst
Show inline comments
 
.. _index:
 

	
 
#######################
 
Kallithea Documentation
 
#######################
 

	
 
**Readme**
 

	
 
.. toctree::
 
   :maxdepth: 1
 

	
 
   readme
 

	
 
**Installation**
 

	
 
.. toctree::
 
   :maxdepth: 1
 

	
 
   overview
 
   installation
 
   installation_win
 
   installation_win_old
 
   installation_iis
 
   setup
 
   installation_puppet
 

	
 
**Usage**
 

	
 
.. toctree::
 
   :maxdepth: 1
 

	
 
   usage/general
 
   usage/vcs_support
 
   usage/locking
 
   usage/statistics
 

	
 
**Administrator's guide**
 

	
 
.. toctree::
 
   :maxdepth: 1
 

	
 
   usage/email
 
   usage/performance
 
   usage/backup
 
   usage/debugging
 
   usage/troubleshooting
 

	
 
**Development**
 

	
docs/installation.rst
Show inline comments
 
@@ -18,94 +18,106 @@ The following describes three different 
 
  contained inside the virtualenv (which also means you can have multiple
 
  installations side by side or remove it entirely by just removing the
 
  virtualenv directory) and does not require root privileges.
 

	
 
- :ref:`installation-without-virtualenv`: The alternative method of installing
 
  a Kallithea release is using standard pip. The package will be installed in
 
  the same location as all other Python packages you have ever installed. As a
 
  result, removing it is not as straightforward as with a virtualenv, as you'd
 
  have to remove its dependencies manually and make sure that they are not
 
  needed by other packages.
 

	
 
.. _installation-source:
 

	
 

	
 
Installation from repository source
 
-----------------------------------
 

	
 
To install Kallithea in a virtualenv_ using the stable branch of the development
 
repository, follow the instructions below::
 

	
 
        hg clone https://kallithea-scm.org/repos/kallithea -u stable
 
        cd kallithea
 
        virtualenv ../kallithea-venv
 
        source ../kallithea-venv/bin/activate
 
        python setup.py develop
 
        python setup.py compile_catalog   # for translation of the UI
 
        pip install --upgrade pip setuptools
 
        python2 setup.py develop
 
        python2 setup.py compile_catalog   # for translation of the UI
 

	
 
You can now proceed to :ref:`setup`.
 

	
 
To upgrade, simply update the repository with ``hg pull -u`` and restart the
 
server.
 

	
 
.. _installation-virtualenv:
 

	
 

	
 
Installing a released version in a virtualenv
 
---------------------------------------------
 

	
 
It is highly recommended to use a separate virtualenv_ for installing Kallithea.
 
This way, all libraries required by Kallithea will be installed separately from your
 
main Python installation and other applications and things will be less
 
problematic when upgrading the system or Kallithea.
 
An additional benefit of virtualenv_ is that it doesn't require root privileges.
 

	
 
- Assuming you have installed virtualenv_, create a new virtual environment
 
  for example, in `/srv/kallithea/venv`, using the virtualenv command::
 

	
 
    virtualenv /srv/kallithea/venv
 

	
 
- Activate the virtualenv_ in your current shell session by running::
 
- Activate the virtualenv_ in your current shell session and make sure the
 
  basic requirements are up-to-date by running::
 

	
 
    source /srv/kallithea/venv/bin/activate
 
    pip install --upgrade pip setuptools
 

	
 
.. note:: You can't use UNIX ``sudo`` to source the ``virtualenv`` script; it
 
   will "activate" a shell that terminates immediately. It is also perfectly
 
   acceptable (and desirable) to create a virtualenv as a normal user.
 

	
 
.. note:: Some dependencies are optional. If you need them, install them in
 
   the virtualenv too::
 

	
 
     pip install psycopg2
 
     pip install python-ldap
 

	
 
   This might require installation of development packages using your
 
   distribution's package manager.
 

	
 
- Make a folder for Kallithea data files, and configuration somewhere on the
 
  filesystem. For example::
 

	
 
    mkdir /srv/kallithea
 

	
 
- Go into the created directory and run this command to install Kallithea::
 

	
 
    pip install kallithea
 

	
 
  Alternatively, download a .tar.gz from http://pypi.python.org/pypi/Kallithea,
 
  extract it and run::
 

	
 
    python setup.py install
 
    python2 setup.py install
 

	
 
- This will install Kallithea together with pylons_ and all other required
 
  python libraries into the activated virtualenv.
 

	
 
You can now proceed to :ref:`setup`.
 

	
 
.. _installation-without-virtualenv:
 

	
 

	
 
Installing a released version without virtualenv
 
------------------------------------------------
 

	
 
For installation without virtualenv, 'just' use::
 

	
 
    pip install kallithea
 

	
 
Note that this method requires root privileges and will install packages
 
globally without using the system's package manager.
 

	
 
To install as a regular user in ``~/.local``, you can use::
 

	
 
    pip install --user kallithea
 

	
 
You can now proceed to :ref:`setup`.
docs/installation_iis.rst
Show inline comments
 
@@ -34,77 +34,77 @@ Make sure that there is a unique applica
 
with an identity that has read access to the Kallithea distribution.
 

	
 
The application pool does not need to be able to run any managed code. If you
 
are using a 32-bit Python installation, then you must enable 32-bit program in
 
the advanced settings for the application pool; otherwise Python will not be able
 
to run on the website and neither will Kallithea.
 

	
 
.. note::
 

	
 
    The application pool can be the same as an existing application pool,
 
    as long as the Kallithea requirements are met by the existing pool.
 

	
 
ISAPI handler
 
.............
 

	
 
The ISAPI handler can be generated using::
 

	
 
    paster install-iis my.ini --root=/
 

	
 
This will generate a ``dispatch.py`` file in the current directory that contains
 
the necessary components to finalize an installation into IIS. Once this file
 
has been generated, it is necessary to run the following command due to the way
 
that ISAPI-WSGI is made::
 

	
 
    python dispatch.py install
 
    python2 dispatch.py install
 

	
 
This accomplishes two things: generating an ISAPI compliant DLL file,
 
``_dispatch.dll``, and installing a script map handler into IIS for the
 
``--root`` specified above pointing to ``_dispatch.dll``.
 

	
 
The ISAPI handler is registered to all file extensions, so it will automatically
 
be the one handling all requests to the specified root. When the website starts
 
the ISAPI handler, it will start a thread pool managed wrapper around the paster
 
middleware WSGI handler that Kallithea runs within and each HTTP request to the
 
site will be processed through this logic henceforth.
 

	
 
Authentication with Kallithea using IIS authentication modules
 
..............................................................
 

	
 
The recommended way to handle authentication with Kallithea using IIS is to let
 
IIS handle all the authentication and just pass it to Kallithea.
 

	
 
To move responsibility into IIS from Kallithea, we need to configure Kallithea
 
to let external systems handle authentication and then let Kallithea create the
 
user automatically. To do this, access the administration's authentication page
 
and enable the ``kallithea.lib.auth_modules.auth_container`` plugin. Once it is
 
added, enable it with the ``REMOTE_USER`` header and check *Clean username*.
 
Finally, save the changes on this page.
 

	
 
Switch to the administration's permissions page and disable anonymous access,
 
otherwise Kallithea will not attempt to use the authenticated user name. By
 
default, Kallithea will populate the list of users lazily as they log in. Either
 
disable external auth account activation and ensure that you pre-populate the
 
user database with an external tool, or set it to *Automatic activation of
 
external account*. Finally, save the changes.
 

	
 
The last necessary step is to enable the relevant authentication in IIS, e.g.
 
Windows authentication.
 

	
 

	
 
Troubleshooting
 
---------------
 

	
 
Typically, any issues in this setup will either be entirely in IIS or entirely
 
in Kallithea (or Kallithea's WSGI/paster middleware). Consequently, two
 
different options for finding issues exist: IIS' failed request tracking which
 
is great at finding issues until they exist inside Kallithea, at which point the
 
ISAPI-WSGI wrapper above uses ``win32traceutil``, which is part of ``pywin32``.
 

	
 
In order to dump output from WSGI using ``win32traceutil`` it is sufficient to
 
type the following in a console window::
 

	
 
    python -m win32traceutil
 
    python2 -m win32traceutil
 

	
 
and any exceptions occurring in the WSGI layer and below (i.e. in the Kallithea
 
application itself) that are uncaught, will be printed here complete with stack
 
traces, making it a lot easier to identify issues.
docs/installation_puppet.rst
Show inline comments
 
new file 100644
 
.. _installation_puppet:
 

	
 
===================================
 
Installation and setup using Puppet
 
===================================
 

	
 
The whole installation and setup process of Kallithea can be simplified by
 
using Puppet and the `rauch/kallithea
 
<https://forge.puppetlabs.com/rauch/kallithea>`_ Puppet module. This is
 
especially useful for getting started quickly, without having to deal with all
 
the Python specialities.
 

	
 
.. note:: The following instructions assume you are not familiar with Puppet at
 
          all. If this is not the case, you should probably skip directly to the
 
          `Kallithea Puppet module documentation
 
          <https://forge.puppetlabs.com/rauch/kallithea#puppet-kallithea>`_.
 

	
 

	
 
Installing Puppet
 
-----------------
 

	
 
This installation variant requires a Unix/Linux type server with Puppet 3.0+
 
installed. Many major distributions have Puppet in their standard repositories.
 
Thus, you will probably be ready to go by running, e.g. ``apt-get install
 
puppet`` or ``yum install puppet``, depending on your distro's favoured package
 
manager. Afterwards, check the Puppet version by running ``puppet --version``
 
and ensure you have at least 3.0.
 

	
 
If your distribution does not provide Puppet packages or you need a
 
newer version, please see the `Puppet Reference Manual
 
<https://docs.puppetlabs.com/puppet/4.2/reference/install_linux.html>`_ for
 
instructions on how to install Puppet on your target platform.
 

	
 

	
 
Installing the Puppet module
 
----------------------------
 

	
 
To install the latest version of the Kallithea Puppet module from the Puppet
 
Forge, run the following as ``root``:
 

	
 
.. code-block:: bash
 

	
 
    puppet module install rauch/kallithea
 

	
 
This will install both the Kallithea Puppet module and its dependency modules.
 

	
 
.. warning::  Be aware that Puppet can do all kinds of things to your systems.
 
              Third-party modules (like the ``kallithea`` module) may run
 
              arbitrary commands on your system (most of the time as the
 
              ``root`` user), so do not apply them on production machines if
 
              you don't know what you are doing. Instead, use a test system
 
              (e.g. a virtual machine) for evaluation purposes.
 

	
 

	
 
Applying the module
 
-------------------
 

	
 
To trigger the actual installation process, we have to *apply* the
 
``kallithea`` Puppet class, which is provided by the module we have just
 
installed, to our system. For this, create a file named e.g. ``kallithea.pp``,
 
a *Puppet manifest*, with the following content:
 

	
 
.. _simple_manifest:
 
.. code-block:: puppet
 

	
 
    class { 'kallithea':
 
      seed_db    => true,
 
      manage_git => true,
 
    }
 

	
 
To apply the manifest, simply run the following (preferably as root):
 

	
 
.. code-block:: bash
 

	
 
    puppet apply kallithea.pp
 

	
 
This will basically run through the usual Kallithea :ref:`installation` and
 
:ref:`setup` steps, as documented. Consult the module documentation for details
 
on `what the module affects
 
<https://forge.puppetlabs.com/rauch/kallithea#what-kallithea-affects>`_. You
 
can also do a *dry run* by adding the ``--noop`` option to the command.
 

	
 

	
 
Using parameters for customizing the setup process
 
--------------------------------------------------
 

	
 
The ``kallithea`` Puppet class provides a number of `parameters
 
<https://forge.puppetlabs.com/rauch/kallithea#class-kallithea>`_ for
 
customizing the setup process. You have seen the usage of the ``seed_db``
 
parameter in the :ref:`example above <simple_manifest>`, but there are more.
 
For example, you can specify the installation directory, the name of the user
 
under which Kallithea gets installed, the initial admin password, etc.
 
Notably, you can provide arbitrary modifications to Kallitheas configuration
 
file by means of the ``config_hash`` parameter.
 

	
 
Parameters, which have not been set explicitly, will be set to default values,
 
which are defined inside the ``kallithea`` Puppet module. For example, if you
 
just stick to the defaults as in the :ref:`example above <simple_manifest>`,
 
you will end up with a Kallithea instance, which
 

	
 
- is installed in ``/srv/kallithea``, owned by the user ``kallithea``
 
- uses the Kallithea default configuration
 
- uses the admin user ``admin`` with password ``adminpw``
 
- is started automatically and enabled on boot
 

	
 
As of Kallithea 0.3.0, this in particular means that Kallithea will use an
 
SQLite database and listen on ``http://localhost:5000``.
 

	
 
See also the `full parameters list
 
<https://forge.puppetlabs.com/rauch/kallithea#class-kallithea>`_ for more
 
information.
 

	
 

	
 
Making your Kallithea instance publicly available
 
-------------------------------------------------
 

	
 
If you followed the instructions above, the Kallithea instance will be
 
listening on ``http://localhost:5000`` and therefore not publicly available.
 
There are several ways to change this.
 

	
 
The direct way
 
^^^^^^^^^^^^^^
 

	
 
The simplest setup is to instruct Kallithea to listen on another IP address
 
and/or port by using the ``config_hash`` parameter of the Kallithea Puppet
 
class. For example, assume we want to listen on all interfaces on port 80:
 

	
 
.. code-block:: puppet
 

	
 
    class { 'kallithea':
 
      seed_db => true,
 
      config_hash => {
 
        "server:main" => {
 
          'host' => '0.0.0.0',
 
          'port' => '80',
 
        }
 
      }
 
    }
 

	
 
Using Apache as reverse proxy
 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

	
 
In a more advanced setup, you might instead want use a full-blown web server
 
like Apache HTTP Server as the public web server, configured such that requests
 
are internally forwarded to the local Kallithea instance (a so called *reverse
 
proxy setup*). This can be easily done with Puppet as well:
 

	
 
First, install the `puppetlabs/apache
 
<https://forge.puppetlabs.com/puppetlabs/apache>`_ Puppet module as above by running the following as root:
 

	
 
.. code-block:: bash
 

	
 
    puppet module install puppetlabs/apache
 

	
 
Then, append the following to your manifest:
 

	
 
.. code-block:: puppet
 

	
 
    include apache
 

	
 
    apache::vhost { 'kallithea.example.com':
 
      docroot             => '/var/www/html',
 
      manage_docroot      => false,
 
      port                => 80,
 
      proxy_preserve_host => true,
 
      proxy_pass          => [
 
        {
 
          path => '/',
 
          url  => 'http://localhost:5000/',
 
        },
 
      ],
 
    }
 

	
 
Applying the resulting manifest will install the Apache web server and setup a
 
virtual host acting as a reverse proxy for your local Kallithea instance.
docs/installation_win.rst
Show inline comments
 
@@ -50,49 +50,49 @@ Step 3 -- Install pywin32 extensions
 
Download pywin32 from:
 
http://sourceforge.net/projects/pywin32/files/
 

	
 
- Click on "pywin32" folder
 
- Click on the first folder (in this case, Build 219, maybe newer when you try)
 
- Choose the file ending with ".amd64-py2.x.exe" (".win32-py2.x.exe"
 
  for Win32) where x is the minor version of Python you installed.
 
  When writing this guide, the file was:
 
  http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win-amd64-py2.7.exe/download
 
  (x64)
 
  http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win32-py2.7.exe/download
 
  (Win32)
 

	
 
Step 4 -- Install pip
 
---------------------
 

	
 
pip is a package management system for Python. You will need it to install Kallithea and its dependencies.
 

	
 
If you installed Python 2.7.9+, you already have it (as long as you ran the installer with admin privileges or disabled UAC).
 

	
 
If it was not installed or if you are using Python>=2.6,<2.7.9:
 

	
 
- Go to https://bootstrap.pypa.io
 
- Right-click on get-pip.py and choose Saves as...
 
- Run "python get-pip.py" in the folder where you downloaded get-pip.py (may require admin access).
 
- Run "python2 get-pip.py" in the folder where you downloaded get-pip.py (may require admin access).
 

	
 
.. note::
 

	
 
   See http://stackoverflow.com/questions/4750806/how-to-install-pip-on-windows
 
   for details and alternative methods.
 

	
 
Note that pip.exe will be placed inside your Python installation's
 
Scripts folder, which is likely not on your path. To correct this,
 
open a CMD and type::
 

	
 
  SETX PATH "%PATH%;[your-python-path]\Scripts" /M
 

	
 
Step 5 -- Kallithea folder structure
 
------------------------------------
 

	
 
Create a Kallithea folder structure.
 

	
 
This is only an example to install Kallithea. Of course, you can
 
change it. However, this guide will follow the proposed structure, so
 
please later adapt the paths if you change them. Folders without
 
spaces are recommended.
 

	
 
Create the following folder structure::
 

	
 
@@ -113,48 +113,49 @@ In a command prompt type::
 
  pip install virtualenv
 

	
 
Virtualenv will now be inside your Python Scripts path (C:\\Python27\\Scripts or similar).
 

	
 
To create a virtual environment, run::
 

	
 
  virtualenv C:\Kallithea\Env
 

	
 
Step 7 -- Install Kallithea
 
---------------------------
 

	
 
In order to install Kallithea, you need to be able to run "pip install kallithea". It will use pip to install the Kallithea Python package and its dependencies.
 
Some Python packages use managed code and need to be compiled.
 
This can be done on Linux without any special steps. On Windows, you will need to install Microsoft Visual C++ compiler for Python 2.7.
 

	
 
Download and install "Microsoft Visual C++ Compiler for Python 2.7" from http://aka.ms/vcpython27
 

	
 
.. note::
 
  You can also install the dependencies using already compiled Windows binaries packages. A good source of compiled Python packages is http://www.lfd.uci.edu/~gohlke/pythonlibs/. However, not all of the necessary packages for Kallithea are on this site and some are hard to find, so we will stick with using the compiler.
 

	
 
In a command prompt type (adapting paths if necessary)::
 

	
 
  cd C:\Kallithea\Env\Scripts
 
  activate
 
  pip install --upgrade pip setuptools
 

	
 
The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
 
(depending of your folder structure). Then type::
 

	
 
  pip install kallithea
 

	
 
.. note:: This will take some time. Please wait patiently until it is fully
 
          complete. Some warnings will appear. Don't worry, they are
 
          normal.
 

	
 
Step 8 -- Install git (optional)
 
--------------------------------
 

	
 
Mercurial being a python package, it was installed automatically when doing "pip install kallithea".
 

	
 
You need to install git manually if you want Kallithea to be able to host git repositories.
 

	
 
See http://git-scm.com/book/en/v2/Getting-Started-Installing-Git#Installing-on-Windows for instructions.
 

	
 
Step 9 -- Configuring Kallithea
 
-------------------------------
 

	
 
Steps taken from `<setup.html>`_
 

	
docs/installation_win_old.rst
Show inline comments
 
@@ -130,80 +130,81 @@ later adapt the paths if you change them
 
folders with NO SPACES. But you can try if you are brave...
 

	
 
Create the following folder structure::
 

	
 
  C:\Kallithea
 
  C:\Kallithea\Bin
 
  C:\Kallithea\Env
 
  C:\Kallithea\Repos
 

	
 
Step 6 -- Install virtualenv
 
----------------------------
 

	
 
Install Virtual Env for Python
 

	
 
Navigate to: http://www.virtualenv.org/en/latest/index.html#installation
 
Right click on "virtualenv.py" file and choose "Save link as...".
 
Download to C:\\Kallithea (or whatever you want)
 
(the file is located at
 
https://raw.github.com/pypa/virtualenv/master/virtualenv.py)
 

	
 
Create a virtual Python environment in C:\\Kallithea\\Env (or similar). To
 
do so, open a CMD (Python Path should be included in Step3), navigate
 
where you downloaded "virtualenv.py", and write::
 

	
 
 python virtualenv.py C:\Kallithea\Env
 
  python2 virtualenv.py C:\Kallithea\Env
 

	
 
(--no-site-packages is now the default behaviour of virtualenv, no need
 
to include it)
 

	
 
Step 7 -- Install Kallithea
 
---------------------------
 

	
 
Finally, install Kallithea
 

	
 
Close previously opened command prompt/s, and open a Visual Studio 2008
 
Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open
 
"Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" ->
 
"Visual Studio 2008 Command Prompt"
 

	
 
.. note::
 

	
 
   64-bit: For 64-bit you need to modify the shortcut that is used to start the
 
   Visual Studio 2008 Command Prompt. Use right-mouse click to open properties.
 

	
 
Change commandline from::
 

	
 
%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86
 

	
 
to::
 

	
 
%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" amd64
 

	
 
In that CMD (loaded with VS2008 PATHs) type::
 

	
 
  cd C:\Kallithea\Env\Scripts (or similar)
 
  activate
 
  pip install --upgrade pip setuptools
 

	
 
The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
 
(depending of your folder structure). Then type::
 

	
 
 pip install kallithea
 

	
 
(long step, please wait until fully complete)
 

	
 
Some warnings will appear, don't worry as they are normal.
 

	
 
Step 8 -- Configuring Kallithea
 
-------------------------------
 

	
 
steps taken from http://packages.python.org/Kallithea/setup.html
 

	
 
You have to use the same Visual Studio 2008 command prompt as Step7, so
 
if you closed it reopen it following the same commands (including the
 
"activate" one). When ready, just type::
 

	
 
  cd C:\Kallithea\Bin
 
  paster make-config Kallithea production.ini
 

	
 
Then, you must edit production.ini to fit your needs (network address and
 
port, mail settings, database, whatever). I recommend using NotePad++
docs/setup.rst
Show inline comments
 
@@ -15,49 +15,49 @@ following command to do so::
 

	
 
This will create the file ``my.ini`` in the current directory. This
 
configuration file contains the various settings for Kallithea, e.g.
 
proxy port, email settings, usage of static files, cache, Celery
 
settings, and logging.
 

	
 
Next, you need to create the databases used by Kallithea. It is recommended to
 
use PostgreSQL or SQLite (default). If you choose a database other than the
 
default, ensure you properly adjust the database URL in your ``my.ini``
 
configuration file to use this other database. Kallithea currently supports
 
PostgreSQL, SQLite and MySQL databases. Create the database by running
 
the following command::
 

	
 
    paster setup-db my.ini
 

	
 
This will prompt you for a "root" path. This "root" path is the location where
 
Kallithea will store all of its repositories on the current machine. After
 
entering this "root" path ``setup-db`` will also prompt you for a username
 
and password for the initial admin account which ``setup-db`` sets
 
up for you.
 

	
 
The ``setup-db`` values can also be given on the command line.
 
Example::
 

	
 
    paster setup-db my.ini --user=nn --password=secret --email=nn@example.org --repos=/srv/repos
 
    paster setup-db my.ini --user=nn --password=secret --email=nn@example.com --repos=/srv/repos
 

	
 
The ``setup-db`` command will create all needed tables and an
 
admin account. When choosing a root path you can either use a new
 
empty location, or a location which already contains existing
 
repositories. If you choose a location which contains existing
 
repositories Kallithea will add all of the repositories at the chosen
 
location to its database.  (Note: make sure you specify the correct
 
path to the root).
 

	
 
.. note:: the given path for Mercurial_ repositories **must** be write
 
          accessible for the application. It's very important since
 
          the Kallithea web interface will work without write access,
 
          but when trying to do a push it will fail with permission
 
          denied errors unless it has write access.
 

	
 
You are now ready to use Kallithea. To run it simply execute::
 

	
 
    paster serve my.ini
 

	
 
- This command runs the Kallithea server. The web app should be available at
 
  http://127.0.0.1:5000. The IP address and port is configurable via the
 
  configuration file created in the previous step.
 
- Log in to Kallithea using the admin account created when running ``setup-db``.
 
- The default permissions on each repository is read, and the owner is admin.
 
@@ -87,49 +87,49 @@ for more details.
 

	
 
Using Kallithea with SSH
 
------------------------
 

	
 
Kallithea currently only hosts repositories using http and https. (The addition
 
of ssh hosting is a planned future feature.) However you can easily use ssh in
 
parallel with Kallithea. (Repository access via ssh is a standard "out of
 
the box" feature of Mercurial_ and you can use this to access any of the
 
repositories that Kallithea is hosting. See PublishingRepositories_)
 

	
 
Kallithea repository structures are kept in directories with the same name
 
as the project. When using repository groups, each group is a subdirectory.
 
This allows you to easily use ssh for accessing repositories.
 

	
 
In order to use ssh you need to make sure that your web server and the users'
 
login accounts have the correct permissions set on the appropriate directories.
 

	
 
.. note:: These permissions are independent of any permissions you
 
          have set up using the Kallithea web interface.
 

	
 
If your main directory (the same as set in Kallithea settings) is for
 
example set to ``/srv/repos`` and the repository you are using is
 
named ``kallithea``, then to clone via ssh you should run::
 

	
 
    hg clone ssh://user@server.com//srv/repos/kallithea
 
    hg clone ssh://user@kallithea.example.com/srv/repos/kallithea
 

	
 
Using other external tools such as mercurial-server_ or using ssh key-based
 
authentication is fully supported.
 

	
 
.. note:: In an advanced setup, in order for your ssh access to use
 
          the same permissions as set up via the Kallithea web
 
          interface, you can create an authentication hook to connect
 
          to the Kallithea db and run check functions for permissions
 
          against that.
 

	
 

	
 
Setting up Whoosh full text search
 
----------------------------------
 

	
 
Kallithea provides full text search of repositories using `Whoosh`__.
 

	
 
.. __: https://pythonhosted.org/Whoosh/
 

	
 
For an incremental index build, run::
 

	
 
    paster make-index my.ini
 

	
 
For a full index rebuild, run::
 

	
 
@@ -155,49 +155,49 @@ from index.
 
If you want to rebuild the index from scratch, you can use the ``-f`` flag as above,
 
or in the admin panel you can check the "build from scratch" checkbox.
 

	
 

	
 
Setting up LDAP support
 
-----------------------
 

	
 
Kallithea supports LDAP authentication. In order
 
to use LDAP, you have to install the python-ldap_ package. This package is
 
available via PyPI, so you can install it by running::
 

	
 
    pip install python-ldap
 

	
 
.. note:: ``python-ldap`` requires some libraries to be installed on
 
          your system, so before installing it check that you have at
 
          least the ``openldap`` and ``sasl`` libraries.
 

	
 
Choose *Admin > Authentication*, click the ``kallithea.lib.auth_modules.auth_ldap`` button
 
and then *Save*, to enable the LDAP plugin and configure its settings.
 

	
 
Here's a typical LDAP setup::
 

	
 
 Connection settings
 
 Enable LDAP          = checked
 
 Host                 = host.example.org
 
 Host                 = host.example.com
 
 Port                 = 389
 
 Account              = <account>
 
 Password             = <password>
 
 Connection Security  = LDAPS connection
 
 Certificate Checks   = DEMAND
 

	
 
 Search settings
 
 Base DN              = CN=users,DC=host,DC=example,DC=org
 
 LDAP Filter          = (&(objectClass=user)(!(objectClass=computer)))
 
 LDAP Search Scope    = SUBTREE
 

	
 
 Attribute mappings
 
 Login Attribute      = uid
 
 First Name Attribute = firstName
 
 Last Name Attribute  = lastName
 
 Email Attribute      = mail
 

	
 
If your user groups are placed in an Organisation Unit (OU) structure, the Search Settings configuration differs::
 

	
 
 Search settings
 
 Base DN              = DC=host,DC=example,DC=org
 
 LDAP Filter          = (&(memberOf=CN=your user group,OU=subunit,OU=unit,DC=host,DC=example,DC=org)(objectClass=user))
 
 LDAP Search Scope    = SUBTREE
 

	
 
@@ -422,81 +422,81 @@ reverse-proxy setup with basic auth:
 
      RequestHeader unset X-Forwarded-User
 

	
 
      RewriteEngine On
 
      RewriteCond %{LA-U:REMOTE_USER} (.+)
 
      RewriteRule .* - [E=RU:%1]
 
      RequestHeader set X-Forwarded-User %{RU}e
 
    </Location>
 

	
 
.. note::
 
   If you enable proxy pass-through authentication, make sure your server is
 
   only accessible through the proxy. Otherwise, any client would be able to
 
   forge the authentication header and could effectively become authenticated
 
   using any account of their liking.
 

	
 

	
 
Integration with issue trackers
 
-------------------------------
 

	
 
Kallithea provides a simple integration with issue trackers. It's possible
 
to define a regular expression that will match an issue ID in commit messages,
 
and have that replaced with a URL to the issue. To enable this simply
 
uncomment the following variables in the ini file::
 

	
 
    issue_pat = (?:^#|\s#)(\w+)
 
    issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
    issue_server_link = https://issues.example.com/{repo}/issue/{id}
 
    issue_prefix = #
 

	
 
``issue_pat`` is the regular expression describing which strings in
 
commit messages will be treated as issue references. A match group in
 
parentheses should be used to specify the actual issue id.
 

	
 
The default expression matches issues in the format ``#<number>``, e.g., ``#300``.
 

	
 
Matched issue references are replaced with the link specified in
 
``issue_server_link``. ``{id}`` is replaced with the issue ID, and
 
``{repo}`` with the repository name.  Since the # is stripped away,
 
``issue_prefix`` is prepended to the link text.  ``issue_prefix`` doesn't
 
necessarily need to be ``#``: if you set issue prefix to ``ISSUE-`` this will
 
generate a URL in the format:
 

	
 
.. code-block:: html
 

	
 
  <a href="https://myissueserver.com/example_repo/issue/300">ISSUE-300</a>
 
  <a href="https://issues.example.com/example_repo/issue/300">ISSUE-300</a>
 

	
 
If needed, more than one pattern can be specified by appending a unique suffix to
 
the variables. For example::
 

	
 
    issue_pat_wiki = (?:wiki-)(.+)
 
    issue_server_link_wiki = https://mywiki.com/{id}
 
    issue_server_link_wiki = https://wiki.example.com/{id}
 
    issue_prefix_wiki = WIKI-
 

	
 
With these settings, wiki pages can be referenced as wiki-some-id, and every
 
such reference will be transformed into:
 

	
 
.. code-block:: html
 

	
 
  <a href="https://mywiki.com/some-id">WIKI-some-id</a>
 
  <a href="https://wiki.example.com/some-id">WIKI-some-id</a>
 

	
 

	
 
Hook management
 
---------------
 

	
 
Hooks can be managed in similar way to that used in ``.hgrc`` files.
 
To manage hooks, choose *Admin > Settings > Hooks*.
 

	
 
The built-in hooks cannot be modified, though they can be enabled or disabled in the *VCS* section.
 

	
 
To add another custom hook simply fill in the first textbox with
 
``<name>.<hook_type>`` and the second with the hook path. Example hooks
 
can be found in ``kallithea.lib.hooks``.
 

	
 

	
 
Changing default encoding
 
-------------------------
 

	
 
By default, Kallithea uses UTF-8 encoding.
 
This is configurable as ``default_encoding`` in the .ini file.
 
This affects many parts in Kallithea including user names, filenames, and
 
encoding of commit messages. In addition Kallithea can detect if the ``chardet``
 
library is installed. If ``chardet`` is detected Kallithea will fallback to it
 
when there are encode/decode errors.
 
@@ -548,129 +548,128 @@ directly which scheme/protocol Kallithea
 
- With ``https_fixup = true``, the scheme will be taken from the
 
  ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
 
  (default ``http``).
 
- With ``force_https = true`` the default will be ``https``.
 
- With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
 

	
 

	
 
Nginx virtual host example
 
--------------------------
 

	
 
Sample config for Nginx using proxy:
 

	
 
.. code-block:: nginx
 

	
 
    upstream kallithea {
 
        server 127.0.0.1:5000;
 
        # add more instances for load balancing
 
        #server 127.0.0.1:5001;
 
        #server 127.0.0.1:5002;
 
    }
 

	
 
    ## gist alias
 
    server {
 
       listen          443;
 
       server_name     gist.myserver.com;
 
       server_name     gist.example.com;
 
       access_log      /var/log/nginx/gist.access.log;
 
       error_log       /var/log/nginx/gist.error.log;
 

	
 
       ssl on;
 
       ssl_certificate     gist.your.kallithea.server.crt;
 
       ssl_certificate_key gist.your.kallithea.server.key;
 

	
 
       ssl_session_timeout 5m;
 

	
 
       ssl_protocols SSLv3 TLSv1;
 
       ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
 
       ssl_prefer_server_ciphers on;
 

	
 
       rewrite ^/(.+)$ https://your.kallithea.server/_admin/gists/$1;
 
       rewrite (.*)    https://your.kallithea.server/_admin/gists;
 
       rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
 
       rewrite (.*)    https://kallithea.example.com/_admin/gists;
 
    }
 

	
 
    server {
 
       listen          443;
 
       server_name     your.kallithea.server;
 
       server_name     kallithea.example.com
 
       access_log      /var/log/nginx/kallithea.access.log;
 
       error_log       /var/log/nginx/kallithea.error.log;
 

	
 
       ssl on;
 
       ssl_certificate     your.kallithea.server.crt;
 
       ssl_certificate_key your.kallithea.server.key;
 

	
 
       ssl_session_timeout 5m;
 

	
 
       ssl_protocols SSLv3 TLSv1;
 
       ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
 
       ssl_prefer_server_ciphers on;
 

	
 
       ## uncomment root directive if you want to serve static files by nginx
 
       ## requires static_files = false in .ini file
 
       #root /path/to/installation/kallithea/public;
 
       include         /etc/nginx/proxy.conf;
 
       location / {
 
            try_files $uri @kallithea;
 
       }
 

	
 
       location @kallithea {
 
            proxy_pass      http://kallithea;
 
            proxy_pass      http://127.0.0.1:5000;
 
       }
 

	
 
    }
 

	
 
Here's the proxy.conf. It's tuned so it will not timeout on long
 
pushes or large pushes::
 

	
 
    proxy_redirect              off;
 
    proxy_set_header            Host $host;
 
    ## needed for container auth
 
    #proxy_set_header            REMOTE_USER $remote_user;
 
    #proxy_set_header            X-Forwarded-User $remote_user;
 
    proxy_set_header            X-Url-Scheme $scheme;
 
    proxy_set_header            X-Host $http_host;
 
    proxy_set_header            X-Real-IP $remote_addr;
 
    proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
 
    proxy_set_header            Proxy-host $proxy_host;
 
    proxy_buffering             off;
 
    proxy_connect_timeout       7200;
 
    proxy_send_timeout          7200;
 
    proxy_read_timeout          7200;
 
    proxy_buffers               8 32k;
 
    client_max_body_size        1024m;
 
    client_body_buffer_size     128k;
 
    large_client_header_buffers 8 64k;
 

	
 

	
 
Apache virtual host reverse proxy example
 
-----------------------------------------
 

	
 
Here is a sample configuration file for Apache using proxy:
 

	
 
.. code-block:: apache
 

	
 
    <VirtualHost *:80>
 
            ServerName hg.myserver.com
 
            ServerAlias hg.myserver.com
 
            ServerName kallithea.example.com
 

	
 
            <Proxy *>
 
              # For Apache 2.4 and later:
 
              Require all granted
 

	
 
              # For Apache 2.2 and earlier, instead use:
 
              # Order allow,deny
 
              # Allow from all
 
            </Proxy>
 

	
 
            #important !
 
            #Directive to properly generate url (clone url) for pylons
 
            ProxyPreserveHost On
 

	
 
            #kallithea instance
 
            ProxyPass / http://127.0.0.1:5000/
 
            ProxyPassReverse / http://127.0.0.1:5000/
 

	
 
            #to enable https use line below
 
            #SetEnvIf X-Url-Scheme https HTTPS=1
 
    </VirtualHost>
 

	
 
Additional tutorial
 
http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
docs/usage/general.rst
Show inline comments
 
@@ -57,108 +57,108 @@ Viewing a changeset
 
  ``Show selected changeset`` button at the top.
 

	
 
Viewing all changes between two changesets
 
  To get a list of all changesets between two selected changesets, along with
 
  the changes in each one of them, tick the checkboxes of the first and
 
  last changeset in the desired range and click the ``Show selected changesets``
 
  button at the top. You can only show the range between the first and last
 
  checkbox (no cherry-picking).
 

	
 
  From that page, you can proceed to viewing the overall delta between the
 
  selected changesets, by clicking the ``Compare revisions`` button.
 

	
 
Creating a pull request
 
  You can create a new pull request for the changes of a particular changeset
 
  (and its ancestors) by selecting it and clicking the ``Open new pull request
 
  for selected changesets`` button.
 

	
 

	
 
Permanent repository URLs
 
-------------------------
 

	
 
Due to the complicated nature of repository grouping, URLs of repositories
 
can often change. For example, a repository originally accessible from::
 

	
 
  http://example.com/repo_name
 
  http://kallithea.example.com/repo_name
 

	
 
would get a new URL after moving it to test_group::
 

	
 
  http://example.com/test_group/repo_name
 
  http://kallithea.example.com/test_group/repo_name
 

	
 
Such moving of a repository to a group can be an issue for build systems and
 
other scripts where the repository paths are hardcoded. To mitigate this,
 
Kallithea provides permanent URLs using the repository ID prefixed with an
 
underscore. In all Kallithea URLs, for example those for the changelog and the
 
file view, a repository name can be replaced by this ``_ID`` string. Since IDs
 
are always the same, moving the repository to a different group will not affect
 
such URLs.
 

	
 
In the example, the repository could also be accessible as::
 

	
 
  http://example.com/_<ID>
 
  http://kallithea.example.com/_<ID>
 

	
 
The ID of a given repository can be shown from the repository ``Summary`` page,
 
by selecting the ``Show by ID`` button next to ``Clone URL``.
 

	
 

	
 
Email notifications
 
-------------------
 

	
 
With email settings properly configured in the Kallithea
 
configuration file, Kallithea will send emails on user registration and when
 
errors occur.
 

	
 
Emails are also sent for comments on changesets. In this case, an email is sent
 
to the committer of the changeset (if known to Kallithea), to all reviewers of
 
the pull request (if applicable) and to all people mentioned in the comment
 
using @mention notation.
 

	
 

	
 
Trending source files
 
---------------------
 

	
 
Trending source files are calculated based on a predefined dictionary of known
 
types and extensions. If an extension is missing or you would like to scan
 
custom files, it is possible to extend the ``LANGUAGES_EXTENSIONS_MAP``
 
dictionary located in ``kallithea/config/conf.py`` with new types.
 

	
 

	
 
Cloning remote repositories
 
---------------------------
 

	
 
Kallithea has the ability to clone repositories from given remote locations.
 
Currently it supports the following options:
 

	
 
- hg  -> hg clone
 
- svn -> hg clone
 
- git -> git clone
 

	
 
.. note:: svn -> hg cloning requires the ``hgsubversion`` library to be
 
   installed.
 

	
 
If you need to clone repositories that are protected via basic authentication,
 
you can pass the credentials in the URL, e.g.
 
``http://user:passw@remote.server/repo``. Kallithea will then try to login and
 
``http://user:passw@remote.example.com/repo``. Kallithea will then try to login and
 
clone using the given credentials. Please note that the given credentials will
 
be stored as plaintext inside the database. However, the authentication
 
information will not be shown in the clone URL on the summary page.
 

	
 

	
 
Specific features configurable in the Admin settings
 
----------------------------------------------------
 

	
 
In general, the Admin settings should be self-explanatory and will not be
 
described in more detail in this documentation. However, there are a few
 
features that merit further explanation.
 

	
 
Repository extra fields
 
~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
In the *Visual* tab, there is an option "Use repository extra
 
fields", which allows to set custom fields for each repository in the system.
 

	
 
Once enabled site-wide, the custom fields can be edited per-repository under
 
*Options* | *Settings* | *Extra Fields*.
 

	
 
Example usage of such fields would be to define company-specific information
 
into repositories, e.g., defining a ``repo_manager`` key that would give info
 
about a manager of each repository.  There's no limit for adding custom fields.
kallithea/__init__.py
Show inline comments
 
@@ -8,49 +8,49 @@
 
# 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 General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea
 
~~~~~~~~~
 

	
 
Kallithea, a web based repository management based on pylons
 
versioning implementation: http://www.python.org/dev/peps/pep-0386/
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 9, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, (C) 2014 Bradley M. Kuhn, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import sys
 
import platform
 

	
 
VERSION = (0, 2, 2)
 
VERSION = (0, 3)
 
BACKENDS = {
 
    'hg': 'Mercurial repository',
 
    'git': 'Git repository',
 
}
 

	
 
CELERY_ON = False
 
CELERY_EAGER = False
 

	
 
# link to config for pylons
 
CONFIG = {}
 

	
 
# Linked module for extensions
 
EXTENSIONS = {}
 

	
 
# BRAND controls internal references in database and config to the products
 
# own name.
 
#
 
# NOTE: If you want compatibility with a database that was originally created
 
#  for use with the RhodeCode software product, change BRAND to "rhodecode",
 
#  either by editing here or by creating a new file:
 
#  echo "BRAND = 'rhodecode'" > kallithea/brand.py
 

	
 
BRAND = "kallithea"
 
try:
kallithea/bin/kallithea_api.py
Show inline comments
 
@@ -15,49 +15,49 @@
 
kallithea.bin.kallithea_api
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Api CLI client for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Jun 3, 2012
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import sys
 
import argparse
 

	
 
from kallithea.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
 

	
 

	
 
def argparser(argv):
 
    usage = (
 
      "kallithea-api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
 
      "[--config=CONFIG] [--save-config] "
 
      "METHOD <key:val> <key2:val> ...\n"
 
      "Create config file: kallithea-api --apikey=<key> --apihost=http://your.kallithea.server --save-config"
 
      "Create config file: kallithea-api --apikey=<key> --apihost=http://kallithea.example.com --save-config"
 
    )
 

	
 
    parser = argparse.ArgumentParser(description='Kallithea API cli',
 
                                     usage=usage)
 

	
 
    ## config
 
    group = parser.add_argument_group('config')
 
    group.add_argument('--apikey', help='api access key')
 
    group.add_argument('--apihost', help='api host')
 
    group.add_argument('--config', help='config file')
 
    group.add_argument('--save-config', action='store_true', help='save the given config into a file')
 

	
 
    group = parser.add_argument_group('API')
 
    group.add_argument('method', metavar='METHOD', nargs='?', type=str, default=None,
 
            help='API method name to call followed by key:value attributes',
 
    )
 
    group.add_argument('--format', dest='format', type=str,
 
            help='output format default: `%s` can '
 
                 'be also `%s`' % (FORMAT_PRETTY, FORMAT_JSON),
 
            default=FORMAT_PRETTY
 
    )
 
    args, other = parser.parse_known_args()
 
    return parser, args, other
 

	
kallithea/bin/kallithea_gist.py
Show inline comments
 
@@ -18,49 +18,49 @@ kallithea.bin.kallithea_gist
 
Gist CLI client for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: May 9, 2013
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import os
 
import sys
 
import stat
 
import argparse
 
import fileinput
 

	
 
from kallithea.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
 

	
 

	
 
def argparser(argv):
 
    usage = (
 
      "kallithea-gist [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
 
      "[--config=CONFIG] [--save-config] [GIST OPTIONS] "
 
      "[filename or stdin use - for terminal stdin ]\n"
 
      "Create config file: kallithea-gist --apikey=<key> --apihost=http://your.kallithea.server --save-config"
 
      "Create config file: kallithea-gist --apikey=<key> --apihost=http://kallithea.example.com --save-config"
 
    )
 

	
 
    parser = argparse.ArgumentParser(description='Kallithea Gist cli',
 
                                     usage=usage)
 

	
 
    ## config
 
    group = parser.add_argument_group('config')
 
    group.add_argument('--apikey', help='api access key')
 
    group.add_argument('--apihost', help='api host')
 
    group.add_argument('--config', help='config file path DEFAULT: ~/.config/kallithea')
 
    group.add_argument('--save-config', action='store_true',
 
                       help='save the given config into a file')
 

	
 
    group = parser.add_argument_group('GIST')
 
    group.add_argument('-p', '--private', action='store_true',
 
                       help='create private Gist')
 
    group.add_argument('-f', '--filename',
 
                       help='set uploaded gist filename, '
 
                            'also defines syntax highlighting')
 
    group.add_argument('-d', '--description', help='Gist description')
 
    group.add_argument('-l', '--lifetime', metavar='MINUTES',
 
                       help='gist lifetime in minutes, -1 (DEFAULT) is forever')
 
    group.add_argument('--format', dest='format', type=str,
 
                       help='output format DEFAULT: `%s` can '
kallithea/bin/ldap_sync.conf
Show inline comments
 
[default]
 
api_url = http://your.kallithea.server:5000/_admin/api
 
api_url = http://kallithea.example.com/_admin/api
 
api_user = admin
 
api_key = XXXXXXXXXXXX
 

	
 
ldap_uri = ldap://your.ldap.server:389
 
ldap_user = cn=kallithea,ou=binders,dc=linaro,dc=org
 
ldap_uri = ldap://ldap.example.com:389
 
ldap_user = cn=kallithea,dc=example,dc=com
 
ldap_key = XXXXXXXXX
 
base_dn = dc=linaro,dc=org
 
base_dn = dc=example,dc=com
 

	
 
sync_users = True
 
\ No newline at end of file
kallithea/bin/template.ini.mako
Show inline comments
 
@@ -30,49 +30,49 @@ pdebug = false
 
<%text>## Default:</%text>
 
#email_prefix =
 
<%text>## Example:</%text>
 
#email_prefix = [Kallithea]
 

	
 
<%text>## Recipients for error emails and fallback recipients of application mails.</%text>
 
<%text>## Multiple addresses can be specified, space-separated.</%text>
 
<%text>## Only addresses are allowed, do not add any name part.</%text>
 
<%text>## Default:</%text>
 
#email_to =
 
<%text>## Examples:</%text>
 
#email_to = admin@example.com
 
#email_to = admin@example.com another_admin@example.com
 

	
 
<%text>## 'From' header for error emails. You can optionally add a name.</%text>
 
<%text>## Default:</%text>
 
#error_email_from = pylons@yourapp.com
 
<%text>## Examples:</%text>
 
#error_email_from = Kallithea Errors <kallithea-noreply@example.com>
 
#error_email_from = paste_error@example.com
 

	
 
<%text>## SMTP server settings</%text>
 
<%text>## Only smtp_server is mandatory. All other settings take the specified default</%text>
 
<%text>## values.</%text>
 
#smtp_server = mail.server.com
 
#smtp_server = smtp.example.com
 
#smtp_username =
 
#smtp_password =
 
#smtp_port = 25
 
#smtp_use_tls = false
 
#smtp_use_ssl = false
 
<%text>## SMTP authentication parameters to use (e.g. LOGIN PLAIN CRAM-MD5, etc.).</%text>
 
<%text>## If empty, use any of the authentication parameters supported by the server.</%text>
 
#smtp_auth =
 

	
 
[server:main]
 
%if http_server == 'paste':
 
<%text>## PASTE ##</%text>
 
use = egg:Paste#http
 
<%text>## nr of worker threads to spawn</%text>
 
threadpool_workers = 5
 
<%text>## max request before thread respawn</%text>
 
threadpool_max_requests = 10
 
<%text>## option to use threads of process</%text>
 
use_threadpool = true
 

	
 
%elif http_server == 'waitress':
 
<%text>## WAITRESS ##</%text>
 
use = egg:waitress#main
 
<%text>## number of worker threads</%text>
 
@@ -205,98 +205,98 @@ force_https = false
 
<%text>## use Strict-Transport-Security headers</%text>
 
use_htsts = false
 

	
 
<%text>## number of commits stats will parse on each iteration</%text>
 
commit_parse_limit = 25
 

	
 
<%text>## path to git executable</%text>
 
git_path = git
 

	
 
<%text>## git rev filter option, --all is the default filter, if you need to</%text>
 
<%text>## hide all refs in changelog switch this to --branches --tags</%text>
 
#git_rev_filter = --branches --tags
 

	
 
<%text>## RSS feed options</%text>
 
rss_cut_off_limit = 256000
 
rss_items_per_page = 10
 
rss_include_diff = false
 

	
 
<%text>## options for showing and identifying changesets</%text>
 
show_sha_length = 12
 
show_revision_number = false
 

	
 
<%text>## gist URL alias, used to create nicer urls for gist. This should be an</%text>
 
<%text>## url that does rewrites to _admin/gists/<gistid>.</%text>
 
<%text>## example: http://gist.kallithea.server/{gistid}. Empty means use the internal</%text>
 
<%text>## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid></%text>
 
<%text>## example: http://gist.example.com/{gistid}. Empty means use the internal</%text>
 
<%text>## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid></%text>
 
gist_alias_url =
 

	
 
<%text>## white list of API enabled controllers. This allows to add list of</%text>
 
<%text>## controllers to which access will be enabled by api_key. eg: to enable</%text>
 
<%text>## api access to raw_files put `FilesController:raw`, to enable access to patches</%text>
 
<%text>## add `ChangesetController:changeset_patch`. This list should be "," separated</%text>
 
<%text>## Syntax is <ControllerClass>:<function>. Check debug logs for generated names</%text>
 
<%text>## Recommended settings below are commented out:</%text>
 
api_access_controllers_whitelist =
 
#    ChangesetController:changeset_patch,
 
#    ChangesetController:changeset_raw,
 
#    FilesController:raw,
 
#    FilesController:archivefile
 

	
 
<%text>## default encoding used to convert from and to unicode</%text>
 
<%text>## can be also a comma seperated list of encoding in case of mixed encodings</%text>
 
default_encoding = utf8
 

	
 
<%text>## issue tracker for Kallithea (leave blank to disable, absent for default)</%text>
 
#bugtracker = https://bitbucket.org/conservancy/kallithea/issues
 

	
 
<%text>## issue tracking mapping for commits messages</%text>
 
<%text>## comment out issue_pat, issue_server, issue_prefix to enable</%text>
 

	
 
<%text>## pattern to get the issues from commit messages</%text>
 
<%text>## default one used here is #<numbers> with a regex passive group for `#`</%text>
 
<%text>## {id} will be all groups matched from this pattern</%text>
 

	
 
issue_pat = (?:\s*#)(\d+)
 

	
 
<%text>## server url to the issue, each {id} will be replaced with match</%text>
 
<%text>## fetched from the regex and {repo} is replaced with full repository name</%text>
 
<%text>## including groups {repo_name} is replaced with just name of repo</%text>
 

	
 
issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
issue_server_link = https://issues.example.com/{repo}/issue/{id}
 

	
 
<%text>## prefix to add to link to indicate it's an url</%text>
 
<%text>## #314 will be replaced by <issue_prefix><id></%text>
 

	
 
issue_prefix = #
 

	
 
<%text>## issue_pat, issue_server_link, issue_prefix can have suffixes to specify</%text>
 
<%text>## multiple patterns, to other issues server, wiki or others</%text>
 
<%text>## below an example how to create a wiki pattern</%text>
 
# wiki-some-id -> https://mywiki.com/some-id
 
# wiki-some-id -> https://wiki.example.com/some-id
 

	
 
#issue_pat_wiki = (?:wiki-)(.+)
 
#issue_server_link_wiki = https://mywiki.com/{id}
 
#issue_server_link_wiki = https://wiki.example.com/{id}
 
#issue_prefix_wiki = WIKI-
 

	
 
<%text>## instance-id prefix</%text>
 
<%text>## a prefix key for this instance used for cache invalidation when running</%text>
 
<%text>## multiple instances of kallithea, make sure it's globally unique for</%text>
 
<%text>## all running kallithea instances. Leave empty if you don't use it</%text>
 
instance_id =
 

	
 
<%text>## alternative return HTTP header for failed authentication. Default HTTP</%text>
 
<%text>## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with</%text>
 
<%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
 
auth_ret_code =
 

	
 
<%text>## locking return code. When repository is locked return this HTTP code. 2XX</%text>
 
<%text>## codes don't break the transactions while 4XX codes do</%text>
 
lock_ret_code = 423
 

	
 
<%text>## allows to change the repository location in settings page</%text>
 
allow_repo_location_change = True
 

	
 
<%text>## allows to setup custom hooks in settings page</%text>
 
allow_custom_hooks_settings = True
 

	
 
<%text>####################################</%text>
kallithea/config/deployment.ini_tmpl
Show inline comments
 
@@ -31,49 +31,49 @@ pdebug = false
 
## Default:
 
#email_prefix =
 
## Example:
 
#email_prefix = [Kallithea]
 

	
 
## Recipients for error emails and fallback recipients of application mails.
 
## Multiple addresses can be specified, space-separated.
 
## Only addresses are allowed, do not add any name part.
 
## Default:
 
#email_to =
 
## Examples:
 
#email_to = admin@example.com
 
#email_to = admin@example.com another_admin@example.com
 

	
 
## 'From' header for error emails. You can optionally add a name.
 
## Default:
 
#error_email_from = pylons@yourapp.com
 
## Examples:
 
#error_email_from = Kallithea Errors <kallithea-noreply@example.com>
 
#error_email_from = paste_error@example.com
 

	
 
## SMTP server settings
 
## Only smtp_server is mandatory. All other settings take the specified default
 
## values.
 
#smtp_server = mail.server.com
 
#smtp_server = smtp.example.com
 
#smtp_username =
 
#smtp_password =
 
#smtp_port = 25
 
#smtp_use_tls = false
 
#smtp_use_ssl = false
 
## SMTP authentication parameters to use (e.g. LOGIN PLAIN CRAM-MD5, etc.).
 
## If empty, use any of the authentication parameters supported by the server.
 
#smtp_auth =
 

	
 
[server:main]
 
## PASTE ##
 
#use = egg:Paste#http
 
## nr of worker threads to spawn
 
#threadpool_workers = 5
 
## max request before thread respawn
 
#threadpool_max_requests = 10
 
## option to use threads of process
 
#use_threadpool = true
 

	
 
## WAITRESS ##
 
use = egg:waitress#main
 
## number of worker threads
 
threads = 5
 
## MAX BODY SIZE 100GB
 
@@ -201,98 +201,98 @@ force_https = false
 
## use Strict-Transport-Security headers
 
use_htsts = false
 

	
 
## number of commits stats will parse on each iteration
 
commit_parse_limit = 25
 

	
 
## path to git executable
 
git_path = git
 

	
 
## git rev filter option, --all is the default filter, if you need to
 
## hide all refs in changelog switch this to --branches --tags
 
#git_rev_filter = --branches --tags
 

	
 
## RSS feed options
 
rss_cut_off_limit = 256000
 
rss_items_per_page = 10
 
rss_include_diff = false
 

	
 
## options for showing and identifying changesets
 
show_sha_length = 12
 
show_revision_number = false
 

	
 
## gist URL alias, used to create nicer urls for gist. This should be an
 
## url that does rewrites to _admin/gists/<gistid>.
 
## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
 
## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
 
## example: http://gist.example.com/{gistid}. Empty means use the internal
 
## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
 
gist_alias_url =
 

	
 
## white list of API enabled controllers. This allows to add list of
 
## controllers to which access will be enabled by api_key. eg: to enable
 
## api access to raw_files put `FilesController:raw`, to enable access to patches
 
## add `ChangesetController:changeset_patch`. This list should be "," separated
 
## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
 
## Recommended settings below are commented out:
 
api_access_controllers_whitelist =
 
#    ChangesetController:changeset_patch,
 
#    ChangesetController:changeset_raw,
 
#    FilesController:raw,
 
#    FilesController:archivefile
 

	
 
## default encoding used to convert from and to unicode
 
## can be also a comma seperated list of encoding in case of mixed encodings
 
default_encoding = utf8
 

	
 
## issue tracker for Kallithea (leave blank to disable, absent for default)
 
#bugtracker = https://bitbucket.org/conservancy/kallithea/issues
 

	
 
## issue tracking mapping for commits messages
 
## comment out issue_pat, issue_server, issue_prefix to enable
 

	
 
## pattern to get the issues from commit messages
 
## default one used here is #<numbers> with a regex passive group for `#`
 
## {id} will be all groups matched from this pattern
 

	
 
issue_pat = (?:\s*#)(\d+)
 

	
 
## server url to the issue, each {id} will be replaced with match
 
## fetched from the regex and {repo} is replaced with full repository name
 
## including groups {repo_name} is replaced with just name of repo
 

	
 
issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
issue_server_link = https://issues.example.com/{repo}/issue/{id}
 

	
 
## prefix to add to link to indicate it's an url
 
## #314 will be replaced by <issue_prefix><id>
 

	
 
issue_prefix = #
 

	
 
## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
 
## multiple patterns, to other issues server, wiki or others
 
## below an example how to create a wiki pattern
 
# wiki-some-id -> https://mywiki.com/some-id
 
# wiki-some-id -> https://wiki.example.com/some-id
 

	
 
#issue_pat_wiki = (?:wiki-)(.+)
 
#issue_server_link_wiki = https://mywiki.com/{id}
 
#issue_server_link_wiki = https://wiki.example.com/{id}
 
#issue_prefix_wiki = WIKI-
 

	
 
## instance-id prefix
 
## a prefix key for this instance used for cache invalidation when running
 
## multiple instances of kallithea, make sure it's globally unique for
 
## all running kallithea instances. Leave empty if you don't use it
 
instance_id =
 

	
 
## alternative return HTTP header for failed authentication. Default HTTP
 
## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 
## allows to change the repository location in settings page
 
allow_repo_location_change = True
 

	
 
## allows to setup custom hooks in settings page
 
allow_custom_hooks_settings = True
 

	
 
####################################
kallithea/controllers/changelog.py
Show inline comments
 
@@ -77,49 +77,48 @@ class ChangelogController(BaseRepoContro
 
        Safe way to get changeset. If error occur fail with error message.
 

	
 
        :param rev: revision to fetch
 
        :param repo: repo instance
 
        """
 

	
 
        try:
 
            return c.db_repo_scm_instance.get_changeset(rev)
 
        except EmptyRepositoryError as e:
 
            h.flash(h.literal(_('There are no changesets yet')),
 
                    category='error')
 
        except RepositoryError as e:
 
            log.error(traceback.format_exc())
 
            h.flash(safe_str(e), category='error')
 
        raise HTTPBadRequest()
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def index(self, repo_name, revision=None, f_path=None):
 
        # Fix URL after page size form submission via GET
 
        # TODO: Somehow just don't send this extra junk in the GET URL
 
        if request.GET.get('set'):
 
            request.GET.pop('set', None)
 
            request.GET.pop('_authentication_token', None)
 
            if revision is None:
 
                return redirect(url('changelog_home', repo_name=repo_name, **request.GET))
 
            return redirect(url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET))
 

	
 
        limit = 2000
 
        default = 100
 
        if request.GET.get('size'):
 
            c.size = max(min(safe_int(request.GET.get('size')), limit), 1)
 
            session['changelog_size'] = c.size
 
            session.save()
 
        else:
 
            c.size = int(session.get('changelog_size', default))
 
        # min size must be 1
 
        c.size = max(c.size, 1)
 
        p = safe_int(request.GET.get('page', 1), 1)
 
        branch_name = request.GET.get('branch', None)
 
        if (branch_name and
 
            branch_name not in c.db_repo_scm_instance.branches and
 
            branch_name not in c.db_repo_scm_instance.closed_branches and
 
            not revision):
 
            return redirect(url('changelog_file_home', repo_name=c.repo_name,
 
                                    revision=branch_name, f_path=f_path or ''))
 

	
 
        if revision == 'tip':
kallithea/controllers/login.py
Show inline comments
 
@@ -6,141 +6,136 @@
 
#
 
# 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 General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.login
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Login controller for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 22, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 

	
 
import logging
 
import re
 
import formencode
 
import urlparse
 

	
 
from formencode import htmlfill
 
from webob.exc import HTTPFound, HTTPBadRequest
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 
from pylons import request, session, tmpl_context as c, url
 

	
 
import kallithea.lib.helpers as h
 
from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator
 
from kallithea.lib.base import BaseController, log_in_user, render
 
from kallithea.lib.exceptions import UserCreationError
 
from kallithea.lib.utils2 import safe_str
 
from kallithea.model.db import User, Setting
 
from kallithea.model.forms import \
 
    LoginForm, RegisterForm, PasswordResetRequestForm, PasswordResetConfirmationForm
 
from kallithea.model.user import UserModel
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class LoginController(BaseController):
 

	
 
    def __before__(self):
 
        super(LoginController, self).__before__()
 

	
 
    def _validate_came_from(self, came_from):
 
        """Return True if came_from is valid and can and should be used"""
 
        if not came_from:
 
            return False
 
    def _validate_came_from(self, came_from,
 
            _re=re.compile(r"/(?!/)[-!#$%&'()*+,./:;=?@_~0-9A-Za-z]*$")):
 
        """Return True if came_from is valid and can and should be used.
 

	
 
        Determines if a URI reference is valid and relative to the origin;
 
        or in RFC 3986 terms, whether it matches this production:
 

	
 
        parsed = urlparse.urlparse(came_from)
 
        server_parsed = urlparse.urlparse(url.current())
 
        allowed_schemes = ['http', 'https']
 
        if parsed.scheme and parsed.scheme not in allowed_schemes:
 
            log.error('Suspicious URL scheme detected %s for url %s',
 
                     parsed.scheme, parsed)
 
            return False
 
        if server_parsed.netloc != parsed.netloc:
 
            log.error('Suspicious NETLOC detected %s for url %s server url '
 
                      'is: %s' % (parsed.netloc, parsed, server_parsed))
 
            return False
 
        return True
 
          origin-relative-ref = path-absolute [ "?" query ] [ "#" fragment ]
 

	
 
    def _redirect_to_origin(self, origin):
 
        '''redirect to the original page, preserving any get arguments given'''
 
        request.GET.pop('came_from', None)
 
        raise HTTPFound(location=url(origin, **request.GET))
 
        with the exception that '%' escapes are not validated and '#' is
 
        allowed inside the fragment part.
 
        """
 
        return _re.match(came_from) is not None
 

	
 
    def index(self):
 
        c.came_from = safe_str(request.GET.get('came_from', ''))
 
        if not self._validate_came_from(c.came_from):
 
        if c.came_from:
 
            if not self._validate_came_from(c.came_from):
 
                log.error('Invalid came_from (not server-relative): %r', c.came_from)
 
                raise HTTPBadRequest()
 
        else:
 
            c.came_from = url('home')
 

	
 
        not_default = self.authuser.username != User.DEFAULT_USER
 
        ip_allowed = AuthUser.check_ip_allowed(self.authuser, self.ip_addr)
 

	
 
        # redirect if already logged in
 
        if self.authuser.is_authenticated and not_default and ip_allowed:
 
            return self._redirect_to_origin(c.came_from)
 
            raise HTTPFound(location=c.came_from)
 

	
 
        if request.POST:
 
            # import Login Form validator class
 
            login_form = LoginForm()
 
            try:
 
                c.form_result = login_form.to_python(dict(request.POST))
 
                # form checks for username/password, now we're authenticated
 
                username = c.form_result['username']
 
                user = User.get_by_username(username, case_insensitive=True)
 
            except formencode.Invalid as errors:
 
                defaults = errors.value
 
                # remove password from filling in form again
 
                del defaults['password']
 
                return htmlfill.render(
 
                    render('/login.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8",
 
                    force_defaults=False)
 
            except UserCreationError as e:
 
                # container auth or other auth functions that create users on
 
                # the fly can throw this exception signaling that there's issue
 
                # with user creation, explanation should be provided in
 
                # Exception itself
 
                h.flash(e, 'error')
 
            else:
 
                log_in_user(user, c.form_result['remember'],
 
                    is_external_auth=False)
 
                return self._redirect_to_origin(c.came_from)
 
                raise HTTPFound(location=c.came_from)
 

	
 
        return render('/login.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
 
                               'hg.register.manual_activate')
 
    def register(self):
 
        c.auto_active = 'hg.register.auto_activate' in User.get_default_user()\
 
            .AuthUser.permissions['global']
 

	
 
        settings = Setting.get_app_settings()
 
        captcha_private_key = settings.get('captcha_private_key')
 
        c.captcha_active = bool(captcha_private_key)
 
        c.captcha_public_key = settings.get('captcha_public_key')
 

	
 
        if request.POST:
 
            register_form = RegisterForm()()
 
            try:
 
                form_result = register_form.to_python(dict(request.POST))
 
                form_result['active'] = c.auto_active
 

	
 
                if c.captcha_active:
 
                    from kallithea.lib.recaptcha import submit
 
                    response = submit(request.POST.get('recaptcha_challenge_field'),
 
                                      request.POST.get('recaptcha_response_field'),
kallithea/controllers/pullrequests.py
Show inline comments
 
@@ -481,51 +481,52 @@ class PullrequestsController(BaseRepoCon
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        if pull_request.is_closed():
 
            raise HTTPForbidden()
 
        assert pull_request.other_repo.repo_name == repo_name
 
        #only owner or admin can update it
 
        owner = pull_request.owner.user_id == c.authuser.user_id
 
        repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name)
 
        if not (h.HasPermissionAny('hg.admin') or repo_admin or owner):
 
            raise HTTPForbidden()
 

	
 
        _form = PullRequestPostForm()().to_python(request.POST)
 
        reviewers_ids = [int(s) for s in _form['review_members']]
 

	
 
        if _form['updaterev']:
 
            return self.create_update(pull_request,
 
                                      _form['updaterev'],
 
                                      _form['pullrequest_title'],
 
                                      _form['pullrequest_desc'],
 
                                      reviewers_ids)
 

	
 
        old_description = pull_request.description
 
        pull_request.title = _form['pullrequest_title']
 
        pull_request.description = _form['pullrequest_desc'].strip() or _('No description')
 
        pull_request.owner = User.get_by_username(_form['owner'])
 
        user = User.get(c.authuser.user_id)
 
        try:
 
            PullRequestModel().mention_from_description(pull_request, old_description)
 
            PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
 
            PullRequestModel().mention_from_description(user, pull_request, old_description)
 
            PullRequestModel().update_reviewers(user, pull_request_id, reviewers_ids)
 
        except UserInvalidException as u:
 
            h.flash(_('Invalid reviewer "%s" specified') % u, category='error')
 
            raise HTTPBadRequest()
 

	
 
        Session().commit()
 
        h.flash(_('Pull request updated'), category='success')
 

	
 
        return redirect(pull_request.url())
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    @jsonify
 
    def delete(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        #only owner can delete it !
 
        if pull_request.owner.user_id == c.authuser.user_id:
 
            PullRequestModel().delete(pull_request)
 
            Session().commit()
 
            h.flash(_('Successfully deleted pull request'),
 
                    category='success')
 
            return redirect(url('my_pullrequests'))
 
        raise HTTPForbidden()
 
@@ -569,76 +570,77 @@ class PullrequestsController(BaseRepoCon
 
        if c.a_ref_type == 'rev': # this looks like a free range where target is ancestor
 
            cs_a = org_scm_instance.get_changeset(c.a_rev)
 
            root_parents = c.cs_ranges[0].parents
 
            c.is_range = cs_a in root_parents
 
            #c.merge_root = len(root_parents) > 1 # a range starting with a merge might deserve a warning
 

	
 
        avail_revs = set()
 
        avail_show = []
 
        c.cs_branch_name = c.cs_ref_name
 
        other_scm_instance = c.a_repo.scm_instance
 
        c.update_msg = ""
 
        c.update_msg_other = ""
 
        if org_scm_instance.alias == 'hg' and c.a_ref_name != 'ancestor':
 
            if c.cs_ref_type != 'branch':
 
                c.cs_branch_name = org_scm_instance.get_changeset(c.cs_ref_name).branch # use ref_type ?
 
            c.a_branch_name = c.a_ref_name
 
            if c.a_ref_type != 'branch':
 
                try:
 
                    c.a_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ?
 
                except EmptyRepositoryError:
 
                    c.a_branch_name = 'null' # not a branch name ... but close enough
 
            # candidates: descendants of old head that are on the right branch
 
            #             and not are the old head itself ...
 
            #             and nothing at all if old head is a descendant of target ref name
 
            if other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, c.a_branch_name):
 
            if not c.is_range and other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, c.a_branch_name):
 
                c.update_msg = _('This pull request has already been merged to %s.') % c.a_branch_name
 
            elif c.pull_request.is_closed():
 
                c.update_msg = _('This pull request has been closed and can not be updated.')
 
            else: # look for descendants of PR head on source branch in org repo
 
                avail_revs = org_scm_instance._repo.revs('%s:: & branch(%s)',
 
                                                         revs[0], c.cs_branch_name)
 
                if len(avail_revs) > 1: # more than just revs[0]
 
                    # also show changesets that not are descendants but would be merged in
 
                    targethead = other_scm_instance.get_changeset(c.a_branch_name).raw_id
 
                    if org_scm_instance.path != other_scm_instance.path:
 
                        # Note: org_scm_instance.path must come first so all
 
                        # valid revision numbers are 100% org_scm compatible
 
                        # - both for avail_revs and for revset results
 
                        hgrepo = unionrepo.unionrepository(org_scm_instance.baseui,
 
                                                           org_scm_instance.path,
 
                                                           other_scm_instance.path)
 
                    else:
 
                        hgrepo = org_scm_instance._repo
 
                    show = set(hgrepo.revs('::%ld & !::%s & !::%s',
 
                                           avail_revs, revs[0], targethead))
 
                    c.update_msg = _('This pull request can be updated with changes on %s:') % c.cs_branch_name
 
                else:
 
                    show = set()
 
                    avail_revs = set() # drop revs[0]
 
                    c.update_msg = _('No changesets found for updating this pull request.')
 

	
 
                # TODO: handle branch heads that not are tip-most
 
                brevs = org_scm_instance._repo.revs('%s - %ld', c.cs_branch_name, avail_revs)
 
                brevs = org_scm_instance._repo.revs('%s - %ld - %s', c.cs_branch_name, avail_revs, revs[0])
 
                if brevs:
 
                    # also show changesets that are on branch but neither ancestors nor descendants
 
                    show.update(org_scm_instance._repo.revs('::%ld - ::%ld - ::%s', brevs, avail_revs, c.a_branch_name))
 
                    show.add(revs[0]) # make sure graph shows this so we can see how they relate
 
                    c.update_msg_other = _('Note: Branch %s has another head: %s.') % (c.cs_branch_name,
 
                        h.short_id(org_scm_instance.get_changeset((max(brevs))).raw_id))
 

	
 
                avail_show = sorted(show, reverse=True)
 

	
 
        elif org_scm_instance.alias == 'git':
 
            c.update_msg = _("Git pull requests don't support updates yet.")
 

	
 
        c.avail_revs = avail_revs
 
        c.avail_cs = [org_scm_instance.get_changeset(r) for r in avail_show]
 
        c.avail_jsdata = json.dumps(graph_data(org_scm_instance, avail_show))
 

	
 
        raw_ids = [x.raw_id for x in c.cs_ranges]
 
        c.cs_comments = c.cs_repo.get_comments(raw_ids)
 
        c.statuses = c.cs_repo.statuses(raw_ids)
 

	
 
        ignore_whitespace = request.GET.get('ignorews') == '1'
 
        line_context = request.GET.get('context', 3)
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
kallithea/controllers/summary.py
Show inline comments
 
@@ -174,48 +174,49 @@ class SummaryController(BaseRepoControll
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def statistics(self, repo_name):
 
        if c.db_repo.enable_statistics:
 
            c.show_stats = True
 
            c.no_data_msg = _('No data ready yet')
 
        else:
 
            c.show_stats = False
 
            c.no_data_msg = _('Statistics are disabled for this repository')
 

	
 
        td = date.today() + timedelta(days=1)
 
        td_1m = td - timedelta(days=calendar.mdays[td.month])
 
        td_1y = td - timedelta(days=365)
 

	
 
        ts_min_m = mktime(td_1m.timetuple())
 
        ts_min_y = mktime(td_1y.timetuple())
 
        ts_max_y = mktime(td.timetuple())
 
        c.ts_min = ts_min_m
 
        c.ts_max = ts_max_y
 

	
 
        stats = self.sa.query(Statistics)\
 
            .filter(Statistics.repository == c.db_repo)\
 
            .scalar()
 
        c.stats_percentage = 0
 
        if stats and stats.languages:
 
            c.no_data = False is c.db_repo.enable_statistics
 
            lang_stats_d = json.loads(stats.languages)
 
            c.commit_data = stats.commit_activity
 
            c.overview_data = stats.commit_activity_combined
 

	
 
            lang_stats = ((x, {"count": y,
 
                               "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
 
                          for x, y in lang_stats_d.items())
 

	
 
            c.trending_languages = json.dumps(
 
                sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
 
            )
 
            last_rev = stats.stat_on_revision + 1
 
            c.repo_last_rev = c.db_repo_scm_instance.count()\
 
                if c.db_repo_scm_instance.revisions else 0
 
            if last_rev == 0 or c.repo_last_rev == 0:
 
                pass
 
            else:
 
                c.stats_percentage = '%.2f' % ((float((last_rev)) /
 
                                                c.repo_last_rev) * 100)
 
        else:
 
            c.commit_data = json.dumps({})
 
            c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
kallithea/i18n/fr/LC_MESSAGES/kallithea.po
Show inline comments
 
# French translations for Kallithea.
 
# Copyright (C) 2014 RhodeCode GmbH, and others.
 
# This file is distributed under the same license as the Kallithea project.
 
# Translators:
 
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011
 
msgid ""
 
msgstr ""
 
"Project-Id-Version: Kallithea 0.3\n"
 
"Report-Msgid-Bugs-To: translations@kallithea-scm.org\n"
 
"POT-Creation-Date: 2015-09-08 10:34+0200\n"
 
"PO-Revision-Date: 2015-09-07 16:35+0200\n"
 
"Last-Translator: Andrew Shadura <andrew@shadura.me>\n"
 
"PO-Revision-Date: 2015-09-10 15:13+0200\n"
 
"Last-Translator: Étienne Gilli <etienne.gilli@gmail.com>\n"
 
"Language-Team: French "
 
"<https://hosted.weblate.org/projects/kallithea/kallithea/fr/>\n"
 
"<https://hosted.weblate.org/projects/kallithea/stable/fr/>\n"
 
"Language: fr\n"
 
"MIME-Version: 1.0\n"
 
"Content-Type: text/plain; charset=UTF-8\n"
 
"Content-Transfer-Encoding: 8bit\n"
 
"Plural-Forms: nplurals=2; plural=n > 1;\n"
 
"X-Generator: Weblate 2.4-dev\n"
 

	
 
#: kallithea/controllers/changelog.py:86
 
#: kallithea/controllers/pullrequests.py:238 kallithea/lib/base.py:512
 
msgid "There are no changesets yet"
 
msgstr "Il n’y a aucun changement pour le moment"
 

	
 
#: kallithea/controllers/changelog.py:166
 
#: kallithea/controllers/admin/permissions.py:61
 
#: kallithea/controllers/admin/permissions.py:65
 
#: kallithea/controllers/admin/permissions.py:69
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:7
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:104
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:8
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:7
 
#: kallithea/templates/base/perms_summary.html:14
 
msgid "None"
 
msgstr "Aucun"
 

	
 
#: kallithea/controllers/changelog.py:169 kallithea/controllers/files.py:196
 
msgid "(closed)"
 
msgstr "(fermé)"
 

	
 
#: kallithea/controllers/changeset.py:89
 
msgid "Show whitespace"
 
msgstr "Afficher les espaces et tabulations"
 

	
 
#: kallithea/controllers/changeset.py:96 kallithea/controllers/changeset.py:103
 
#: kallithea/templates/files/diff_2way.html:55
 
msgid "Ignore whitespace"
 
msgstr "Ignorer les espaces et tabulations"
 

	
 
#: kallithea/controllers/changeset.py:169
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Increase diff context to %(num)s lines"
 
msgstr "augmenter le contexte du diff à %(num)s lignes"
 
msgstr "Augmenter le contexte du diff à %(num)s lignes"
 

	
 
#: kallithea/controllers/changeset.py:212 kallithea/controllers/files.py:96
 
#: kallithea/controllers/files.py:116 kallithea/controllers/files.py:742
 
msgid "Such revision does not exist for this repository"
 
msgstr "Une telle révision n'existe pas pour ce dépôt"
 

	
 
#: kallithea/controllers/changeset.py:383
 
msgid ""
 
"Changing status on a changeset associated with a closed pull request is "
 
"not allowed"
 
msgstr ""
 
"La modification de l'état sur un ensemble de modifications associé à une "
 
"demande de tirage fermé n'est pas autorisé"
 

	
 
#: kallithea/controllers/compare.py:161 kallithea/templates/base/root.html:41
 
msgid "Select changeset"
 
msgstr "Sélectionner le changeset"
 

	
 
#: kallithea/controllers/compare.py:261
 
msgid "Cannot compare repositories without using common ancestor"
 
msgstr "Impossible de comparer des dépôts sans utiliser un ancêtre commun"
 

	
 
#: kallithea/controllers/error.py:71
 
msgid "No response"
 
@@ -278,68 +278,66 @@ msgstr "Dépôts"
 
msgid "Branch"
 
msgstr "Branche"
 

	
 
#: kallithea/controllers/home.py:136
 
msgid "Tag"
 
msgstr "Étiquette"
 

	
 
#: kallithea/controllers/home.py:142
 
msgid "Bookmark"
 
msgstr "Signet"
 

	
 
#: kallithea/controllers/journal.py:111 kallithea/controllers/journal.py:153
 
#: kallithea/templates/journal/public_journal.html:4
 
#: kallithea/templates/journal/public_journal.html:21
 
msgid "Public Journal"
 
msgstr "Journal public"
 

	
 
#: kallithea/controllers/journal.py:115 kallithea/controllers/journal.py:157
 
#: kallithea/templates/base/base.html:222
 
#: kallithea/templates/journal/journal.html:4
 
#: kallithea/templates/journal/journal.html:12
 
msgid "Journal"
 
msgstr "Historique"
 

	
 
#: kallithea/controllers/login.py:150 kallithea/controllers/login.py:196
 
#| msgid "bad captcha"
 
#: kallithea/controllers/login.py:151 kallithea/controllers/login.py:197
 
msgid "Bad captcha"
 
msgstr "Mauvais captcha"
 

	
 
#: kallithea/controllers/login.py:157
 
msgid "You have successfully registered into Kallithea"
 
msgstr "Vous vous êtes inscrits avec succès à Kallithea"
 

	
 
#: kallithea/controllers/login.py:202
 
#, fuzzy
 
#| msgid "Your password reset link was sent"
 
msgid "A password reset confirmation code has been sent"
 
msgstr "Un lien de rénitialisation de votre mot de passe vous a été envoyé"
 
msgstr ""
 
"Un lien de confirmation de réinitialisation de mot de passe a été envoyé"
 

	
 
#: kallithea/controllers/login.py:251
 
#, fuzzy
 
#| msgid "Password reset link"
 
msgid "Invalid password reset token"
 
msgstr "Lien de remise à zéro du mot de passe"
 
msgstr "Clé de réinitialisation de mot de passe invalide"
 

	
 
#: kallithea/controllers/login.py:256
 
#: kallithea/controllers/admin/my_account.py:167
 
msgid "Successfully updated password"
 
msgstr "Mot de passe mis à jour avec succès"
 

	
 
#: kallithea/controllers/pullrequests.py:124
 
#, python-format
 
msgid "%s (closed)"
 
msgstr "%s (fermé)"
 

	
 
#: kallithea/controllers/pullrequests.py:152
 
#: kallithea/templates/changeset/changeset.html:12
 
#: kallithea/templates/email_templates/changeset_comment.html:17
 
msgid "Changeset"
 
msgstr "Changements"
 

	
 
#: kallithea/controllers/pullrequests.py:173
 
msgid "Special"
 
msgstr "Spécial"
 

	
 
#: kallithea/controllers/pullrequests.py:174
 
msgid "Peer branches"
 
msgstr "Branches appairées"
 
@@ -417,62 +415,62 @@ msgstr "Mise à jour de la pull request créée"
 
#: kallithea/controllers/pullrequests.py:513
 
msgid "Pull request updated"
 
msgstr "Pull request mise à jour"
 

	
 
#: kallithea/controllers/pullrequests.py:528
 
msgid "Successfully deleted pull request"
 
msgstr "La requête de pull a été supprimée avec succès"
 

	
 
#: kallithea/controllers/pullrequests.py:594
 
#, python-format
 
msgid "This pull request has already been merged to %s."
 
msgstr "Cette pull request a déjà été fusionnée à %s."
 

	
 
#: kallithea/controllers/pullrequests.py:596
 
msgid "This pull request has been closed and can not be updated."
 
msgstr "Cette pull request a été fermée et ne peut pas être mise à jour."
 

	
 
#: kallithea/controllers/pullrequests.py:614
 
#, python-format
 
msgid "This pull request can be updated with changes on %s:"
 
msgstr "Cette demande de pull peut être mise à jour avec les modifications de %s :"
 

	
 
#: kallithea/controllers/pullrequests.py:617
 
msgid "No changesets found for updating this pull request."
 
msgstr "Pas de changeset trouvé pour ce pull request"
 
msgstr "Pas de changeset trouvé pour ce pull request."
 

	
 
#: kallithea/controllers/pullrequests.py:625
 
#, python-format
 
msgid "Note: Branch %s has another head: %s."
 
msgstr "Note: La branche %s a une autre tête: %s."
 

	
 
#: kallithea/controllers/pullrequests.py:631
 
msgid "Git pull requests don't support updates yet."
 
msgstr "Le smises à jour des Git pull requests ne sont pas encore supportées."
 

	
 
#: kallithea/controllers/pullrequests.py:722
 
msgid "No permission to change pull request status"
 
msgstr ""
 
msgstr "Permission manquante pour changer le statut du pull request"
 

	
 
#: kallithea/controllers/pullrequests.py:727
 
msgid "Closing."
 
msgstr "Fermeture."
 

	
 
#: kallithea/controllers/search.py:135
 
msgid "Invalid search query. Try quoting it."
 
msgstr "Requête invalide. Essayer de la mettre entre guillemets."
 

	
 
#: kallithea/controllers/search.py:140
 
msgid "There is no index to search in. Please run whoosh indexer"
 
msgstr ""
 
"L’index de recherche n’est pas présent. Veuillez exécuter l’indexeur de "
 
"code Whoosh"
 

	
 
#: kallithea/controllers/search.py:144
 
msgid "An error occurred during search operation."
 
msgstr "Une erreur est survenue pendant la recherche."
 

	
 
#: kallithea/controllers/summary.py:180
 
#: kallithea/templates/summary/summary.html:384
 
msgid "No data ready yet"
 
msgstr "Aucune donnée actuellement disponible"
 

	
 
@@ -481,95 +479,93 @@ msgstr "Aucune donnée actuellement disponible"
 
msgid "Statistics are disabled for this repository"
 
msgstr "La mise à jour des statistiques est désactivée pour ce dépôt"
 

	
 
#: kallithea/controllers/admin/auth_settings.py:135
 
msgid "Auth settings updated successfully"
 
msgstr "Mise à jour des paramètres d'authentification effectuée avec succès"
 

	
 
#: kallithea/controllers/admin/auth_settings.py:146
 
msgid "error occurred during update of auth settings"
 
msgstr ""
 
"une erreur est survenue pendant la mise à jour des réglages "
 
"d'authentification"
 

	
 
#: kallithea/controllers/admin/defaults.py:97
 
msgid "Default settings updated successfully"
 
msgstr "Mise à jour des réglages par défaut effectuée avec succès"
 

	
 
#: kallithea/controllers/admin/defaults.py:112
 
msgid "Error occurred during update of defaults"
 
msgstr "Une erreur est survenue durant la mise à jour des réglages par défaut"
 

	
 
#: kallithea/controllers/admin/gists.py:59
 
#: kallithea/controllers/admin/my_account.py:243
 
#: kallithea/controllers/admin/users.py:285
 
#, fuzzy
 
msgid "Forever"
 
msgstr "pour toujours"
 
msgstr "Pour toujours"
 

	
 
#: kallithea/controllers/admin/gists.py:60
 
#: kallithea/controllers/admin/my_account.py:244
 
#: kallithea/controllers/admin/users.py:286
 
msgid "5 minutes"
 
msgstr "5 minute"
 

	
 
#: kallithea/controllers/admin/gists.py:61
 
#: kallithea/controllers/admin/my_account.py:245
 
#: kallithea/controllers/admin/users.py:287
 
msgid "1 hour"
 
msgstr "1 heure"
 

	
 
#: kallithea/controllers/admin/gists.py:62
 
#: kallithea/controllers/admin/my_account.py:246
 
#: kallithea/controllers/admin/users.py:288
 
msgid "1 day"
 
msgstr "1 jour"
 

	
 
#: kallithea/controllers/admin/gists.py:63
 
#: kallithea/controllers/admin/my_account.py:247
 
#: kallithea/controllers/admin/users.py:289
 
msgid "1 month"
 
msgstr "1 mois"
 

	
 
#: kallithea/controllers/admin/gists.py:67
 
#: kallithea/controllers/admin/my_account.py:249
 
#: kallithea/controllers/admin/users.py:291
 
msgid "Lifetime"
 
msgstr "Toujours"
 

	
 
#: kallithea/controllers/admin/gists.py:146
 
msgid "Error occurred during gist creation"
 
msgstr "Une erreur est survenue lors de la création du gist"
 

	
 
#: kallithea/controllers/admin/gists.py:184
 
#, python-format
 
msgid "Deleted gist %s"
 
msgstr "Gist %s supprimé"
 

	
 
#: kallithea/controllers/admin/gists.py:233
 
#, fuzzy
 
msgid "Unmodified"
 
msgstr "non modifié"
 
msgstr "Non modifié"
 

	
 
#: kallithea/controllers/admin/gists.py:262
 
msgid "Successfully updated gist content"
 
msgstr "Le contenu du gist a été mis à jour avec succès"
 

	
 
#: kallithea/controllers/admin/gists.py:267
 
msgid "Successfully updated gist data"
 
msgstr "Les données du gist on été mises à jour avec succès"
 

	
 
#: kallithea/controllers/admin/gists.py:270
 
#, python-format
 
msgid "Error occurred during update of gist %s"
 
msgstr "Une erreur est survenue durant la mise à jour du gist %s"
 

	
 
#: kallithea/controllers/admin/my_account.py:70 kallithea/model/user.py:215
 
#: kallithea/model/user.py:237
 
msgid "You can't edit this user since it's crucial for entire application"
 
msgstr ""
 
"Vous ne pouvez pas éditer cet utilisateur ; il est nécessaire pour le bon"
 
" fonctionnement de l’application"
 

	
 
#: kallithea/controllers/admin/my_account.py:129
 
msgid "Your account was updated successfully"
 
msgstr "Votre compte a été mis à jour avec succès"
 
@@ -811,107 +807,105 @@ msgstr "Dépôt %s créé"
 
msgid "Repository %s updated successfully"
 
msgstr "Dépôt %s mis à jour avec succès"
 

	
 
#: kallithea/controllers/admin/repos.py:283
 
#, python-format
 
msgid "Error occurred during update of repository %s"
 
msgstr "Une erreur est survenue durant la mise à jour du dépôt %s"
 

	
 
#: kallithea/controllers/admin/repos.py:310
 
#, python-format
 
msgid "Detached %s forks"
 
msgstr "%s forks détachés"
 

	
 
#: kallithea/controllers/admin/repos.py:313
 
#, python-format
 
msgid "Deleted %s forks"
 
msgstr "%s forks supprimés"
 

	
 
#: kallithea/controllers/admin/repos.py:318
 
#, python-format
 
msgid "Deleted repository %s"
 
msgstr "Dépôt %s supprimé"
 

	
 
#: kallithea/controllers/admin/repos.py:321
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Cannot delete repository %s which still has forks"
 
msgstr "Impossible de supprimer le dépôt %s : Des forks y sont attachés"
 
msgstr "Impossible de supprimer le dépôt %s : des forks y sont attachés"
 

	
 
#: kallithea/controllers/admin/repos.py:326
 
#, python-format
 
msgid "An error occurred during deletion of %s"
 
msgstr "Erreur pendant la suppression de %s"
 

	
 
#: kallithea/controllers/admin/repos.py:374
 
msgid "Repository permissions updated"
 
msgstr "Permissions du dépôt mises à jour"
 

	
 
#: kallithea/controllers/admin/repos.py:430
 
msgid "An error occurred during creation of field"
 
msgstr "Une erreur est survenue durant la création du champ"
 

	
 
#: kallithea/controllers/admin/repos.py:444
 
msgid "An error occurred during removal of field"
 
msgstr "Une erreur est survenue durant la suppression du champ"
 

	
 
#: kallithea/controllers/admin/repos.py:460
 
msgid "-- Not a fork --"
 
msgstr "-- Pas un fork --"
 

	
 
#: kallithea/controllers/admin/repos.py:491
 
msgid "Updated repository visibility in public journal"
 
msgstr "La visibilité du dépôt dans le journal public a été mise à jour"
 

	
 
#: kallithea/controllers/admin/repos.py:495
 
msgid "An error occurred during setting this repository in public journal"
 
msgstr ""
 
"Une erreur est survenue durant la configuration du journal public pour ce"
 
" dépôt"
 

	
 
#: kallithea/controllers/admin/repos.py:512
 
msgid "Nothing"
 
msgstr "[Aucun dépôt]"
 

	
 
#: kallithea/controllers/admin/repos.py:514
 
#, python-format
 
msgid "Marked repository %s as fork of %s"
 
msgstr "Le dépôt %s a été marké comme fork de %s"
 

	
 
#: kallithea/controllers/admin/repos.py:521
 
msgid "An error occurred during this operation"
 
msgstr "Une erreur est survenue durant cette opération"
 

	
 
#: kallithea/controllers/admin/repos.py:537
 
#: kallithea/controllers/admin/repos.py:564
 
#, fuzzy
 
msgid "Repository has been locked"
 
msgstr "Ce dépôt n’est pas verrouillé"
 
msgstr "Ce dépôt a été verrouillé"
 

	
 
#: kallithea/controllers/admin/repos.py:540
 
#: kallithea/controllers/admin/repos.py:561
 
#, fuzzy
 
msgid "Repository has been unlocked"
 
msgstr "Ce dépôt n’est pas verrouillé"
 
msgstr "Ce dépôt a été déverrouillé"
 

	
 
#: kallithea/controllers/admin/repos.py:543
 
#: kallithea/controllers/admin/repos.py:568
 
msgid "An error occurred during unlocking"
 
msgstr "Une erreur est survenue durant le déverrouillage"
 

	
 
#: kallithea/controllers/admin/repos.py:582
 
msgid "Cache invalidation successful"
 
msgstr "Invalidation du cache réalisée avec succès"
 

	
 
#: kallithea/controllers/admin/repos.py:586
 
msgid "An error occurred during cache invalidation"
 
msgstr "Une erreur est survenue durant l’invalidation du cache"
 

	
 
#: kallithea/controllers/admin/repos.py:601
 
msgid "Pulled from remote location"
 
msgstr "Les changements distants ont été récupérés"
 

	
 
#: kallithea/controllers/admin/repos.py:604
 
msgid "An error occurred during pull from remote location"
 
msgstr "Une erreur est survenue durant le pull depuis la source distante"
 

	
 
#: kallithea/controllers/admin/repos.py:637
 
msgid "An error occurred during deletion of repository stats"
 
@@ -1028,145 +1022,143 @@ msgstr "Une erreur est survenue durant l’enregistrement des permissions"
 
#: kallithea/controllers/admin/users.py:134
 
#, python-format
 
msgid "Created user %s"
 
msgstr "Utilisateur %s créé"
 

	
 
#: kallithea/controllers/admin/users.py:149
 
#, python-format
 
msgid "Error occurred during creation of user %s"
 
msgstr "Une erreur est survenue durant la création de l'utilisateur %s"
 

	
 
#: kallithea/controllers/admin/users.py:182
 
msgid "User updated successfully"
 
msgstr "L’utilisateur a été mis à jour avec succès"
 

	
 
#: kallithea/controllers/admin/users.py:218
 
msgid "Successfully deleted user"
 
msgstr "Utilisateur supprimé avec succès"
 

	
 
#: kallithea/controllers/admin/users.py:223
 
msgid "An error occurred during deletion of user"
 
msgstr "Une erreur est survenue durant la suppression de l’utilisateur"
 

	
 
#: kallithea/controllers/admin/users.py:236
 
msgid "The default user cannot be edited"
 
msgstr ""
 
msgstr "L'utilisateur par défaut ne peut pas être modifié"
 

	
 
#: kallithea/controllers/admin/users.py:463
 
#, python-format
 
msgid "Added IP address %s to user whitelist"
 
msgstr "L'adresse IP %s a été ajoutée à la liste blanche"
 

	
 
#: kallithea/controllers/admin/users.py:469
 
msgid "An error occurred while adding IP address"
 
msgstr "Une erreur est survenue durant la sauvegarde d'IP"
 

	
 
#: kallithea/controllers/admin/users.py:483
 
msgid "Removed IP address from user whitelist"
 
msgstr "L'adresse IP a été supprimée de la liste blanche"
 

	
 
#: kallithea/lib/auth.py:743
 
#, python-format
 
msgid "IP %s not allowed"
 
msgstr "IP %s non autorisée"
 

	
 
#: kallithea/lib/auth.py:756
 
#, fuzzy
 
msgid "Invalid API key"
 
msgstr "Nouvelle clé d'API"
 
msgstr "Clé d'API invalide"
 

	
 
#: kallithea/lib/auth.py:812
 
msgid "You need to be a registered user to perform this action"
 
msgstr "Vous devez être un utilisateur enregistré pour effectuer cette action"
 

	
 
#: kallithea/lib/auth.py:844
 
msgid "You need to be signed in to view this page"
 
msgstr "Vous devez être connecté pour visualiser cette page"
 

	
 
#: kallithea/lib/base.py:490
 
msgid "Repository not found in the filesystem"
 
msgstr ""
 
msgstr "Dépôt non trouvé sur le système de fichiers"
 

	
 
#: kallithea/lib/base.py:516 kallithea/lib/helpers.py:622
 
msgid "Changeset not found"
 
msgstr "Ensemble de changements non trouvé"
 

	
 
#: kallithea/lib/diffs.py:66
 
msgid "Binary file"
 
msgstr "Fichier binaire"
 

	
 
#: kallithea/lib/diffs.py:82
 
msgid "Changeset was too big and was cut off, use diff menu to display this diff"
 
msgstr ""
 
"Cet ensemble de changements était trop gros pour être affiché et a été "
 
"découpé, utilisez le menu « diff » pour afficher les différences"
 

	
 
#: kallithea/lib/diffs.py:92
 
msgid "No changes detected"
 
msgstr "Aucun changement détecté"
 

	
 
#: kallithea/lib/helpers.py:609
 
#, python-format
 
msgid "Deleted branch: %s"
 
msgstr "Branche supprimée : %s"
 

	
 
#: kallithea/lib/helpers.py:611
 
#, python-format
 
msgid "Created tag: %s"
 
msgstr "Étiquette créée : %s"
 

	
 
#: kallithea/lib/helpers.py:671
 
#, python-format
 
msgid "Show all combined changesets %s->%s"
 
msgstr "Afficher les changements combinés %s->%s"
 

	
 
#: kallithea/lib/helpers.py:677
 
#, fuzzy
 
msgid "Compare view"
 
msgstr "vue de comparaison"
 
msgstr "Vue de comparaison"
 

	
 
#: kallithea/lib/helpers.py:696
 
msgid "and"
 
msgstr "et"
 

	
 
#: kallithea/lib/helpers.py:697
 
#, python-format
 
msgid "%s more"
 
msgstr "%s de plus"
 

	
 
#: kallithea/lib/helpers.py:698 kallithea/templates/changelog/changelog.html:44
 
msgid "revisions"
 
msgstr "révisions"
 

	
 
#: kallithea/lib/helpers.py:722
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Fork name %s"
 
msgstr "nom du fork %s"
 
msgstr "Nom du fork %s"
 

	
 
#: kallithea/lib/helpers.py:742
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Pull request %s"
 
msgstr "Requête de pull #%s"
 
msgstr "Requête de pull %s"
 

	
 
#: kallithea/lib/helpers.py:752
 
msgid "[deleted] repository"
 
msgstr "[a supprimé] le dépôt"
 

	
 
#: kallithea/lib/helpers.py:754 kallithea/lib/helpers.py:766
 
msgid "[created] repository"
 
msgstr "[a créé] le dépôt"
 

	
 
#: kallithea/lib/helpers.py:756
 
msgid "[created] repository as fork"
 
msgstr "[a créé] le dépôt en tant que fork"
 

	
 
#: kallithea/lib/helpers.py:758 kallithea/lib/helpers.py:768
 
msgid "[forked] repository"
 
msgstr "[a forké] le dépôt"
 

	
 
#: kallithea/lib/helpers.py:760 kallithea/lib/helpers.py:770
 
msgid "[updated] repository"
 
msgstr "[a mis à jour] le dépôt"
 

	
 
#: kallithea/lib/helpers.py:762
 
msgid "[downloaded] archive from repository"
 
msgstr "[téléchargée] archive depuis le dépôt"
 
@@ -1215,49 +1207,49 @@ msgstr "[a commité via Kallithea] dans le dépôt"
 
msgid "[pulled from remote] into repository"
 
msgstr "[a pullé depuis un site distant] dans le dépôt"
 

	
 
#: kallithea/lib/helpers.py:792
 
msgid "[pulled] from"
 
msgstr "[a pullé] depuis"
 

	
 
#: kallithea/lib/helpers.py:794
 
msgid "[started following] repository"
 
msgstr "[suit maintenant] le dépôt"
 

	
 
#: kallithea/lib/helpers.py:796
 
msgid "[stopped following] repository"
 
msgstr "[ne suit plus] le dépôt"
 

	
 
#: kallithea/lib/helpers.py:1124
 
#, python-format
 
msgid " and %s more"
 
msgstr " et %s de plus"
 

	
 
#: kallithea/lib/helpers.py:1128
 
#: kallithea/templates/compare/compare_diff.html:65
 
#: kallithea/templates/pullrequests/pullrequest_show.html:326
 
msgid "No files"
 
msgstr ""
 
msgstr "Aucun fichier"
 

	
 
#: kallithea/lib/helpers.py:1194
 
msgid "new file"
 
msgstr "nouveau fichier"
 

	
 
#: kallithea/lib/helpers.py:1197
 
msgid "mod"
 
msgstr "mod"
 

	
 
#: kallithea/lib/helpers.py:1200
 
msgid "del"
 
msgstr "suppr."
 

	
 
#: kallithea/lib/helpers.py:1203
 
msgid "rename"
 
msgstr "renommer"
 

	
 
#: kallithea/lib/helpers.py:1208
 
msgid "chmod"
 
msgstr "chmod"
 

	
 
#: kallithea/lib/helpers.py:1444
 
#, python-format
 
msgid ""
 
@@ -1760,359 +1752,359 @@ msgstr "Enregistrement des utilisateurs 
 
#: kallithea/lib/dbmigrate/schema/db_2_2_3.py:1672 kallithea/model/db.py:1691
 
msgid "Repository creation enabled with write permission to a repository group"
 
msgstr ""
 
"Création de dépôts activée avec l'accès en écriture vers un groupe de "
 
"dépôts"
 

	
 
#: kallithea/lib/dbmigrate/schema/db_2_2_0.py:1646
 
#: kallithea/lib/dbmigrate/schema/db_2_2_3.py:1673 kallithea/model/db.py:1692
 
msgid "Repository creation disabled with write permission to a repository group"
 
msgstr ""
 
"Création de dépôts désactivée avec l'accès en écriture vers un groupe de "
 
"dépôts"
 

	
 
#: kallithea/model/comment.py:72
 
#, python-format
 
msgid "on line %s"
 
msgstr "à la ligne %s"
 

	
 
#: kallithea/model/comment.py:217 kallithea/model/pull_request.py:169
 
msgid "[Mention]"
 
msgstr "[Mention]"
 

	
 
#: kallithea/model/db.py:1667
 
msgid "Default user has no access to new repositories"
 
msgstr ""
 
msgstr "L'utilisateur par défaut n'a pas accès aux nouveaux dépôts"
 

	
 
#: kallithea/model/db.py:1668
 
#, fuzzy
 
msgid "Default user has read access to new repositories"
 
msgstr "Accès interdit à cette ressource"
 
msgstr "L'utilisateur par défaut a un accès en lecture aux nouveaux dépôts"
 

	
 
#: kallithea/model/db.py:1669
 
#, fuzzy
 
msgid "Default user has write access to new repositories"
 
msgstr "Accès interdit à cette ressource"
 
msgstr "L'utilisateur par défaut a un accès en écriture aux nouveaux dépôts"
 

	
 
#: kallithea/model/db.py:1670
 
msgid "Default user has admin access to new repositories"
 
msgstr ""
 
msgstr "L'utilisateur par défaut a un accès administrateur aux nouveaux dépôts"
 

	
 
#: kallithea/model/db.py:1672
 
msgid "Default user has no access to new repository groups"
 
msgstr ""
 
msgstr "L'utilisateur par défaut n'a pas accès aux nouveaux groupes de dépôts"
 

	
 
#: kallithea/model/db.py:1673
 
msgid "Default user has read access to new repository groups"
 
msgstr ""
 
"L'utilisateur par défaut a accès en lecture seule aux nouveaux groupes de "
 
"dépôts"
 

	
 
#: kallithea/model/db.py:1674
 
msgid "Default user has write access to new repository groups"
 
msgstr ""
 
"L'utilisateur par défaut a accès en écriture aux nouveaux groupes de dépôts"
 

	
 
#: kallithea/model/db.py:1675
 
msgid "Default user has admin access to new repository groups"
 
msgstr ""
 
"L'utilisateur par défaut a accès administrateur aux nouveaux groupes de "
 
"dépôts"
 

	
 
#: kallithea/model/db.py:1677
 
msgid "Default user has no access to new user groups"
 
msgstr ""
 
"L'utilisateur par défaut n'a pas accès aux nouveaux groupes d'utilisateurs"
 

	
 
#: kallithea/model/db.py:1678
 
msgid "Default user has read access to new user groups"
 
msgstr ""
 
"L'utilisateur par défaut a accès en lecture seule aux nouveaux groupes "
 
"d'utilisateurs"
 

	
 
#: kallithea/model/db.py:1679
 
msgid "Default user has write access to new user groups"
 
msgstr ""
 
"L'utilisateur par défaut a accès en écriture aux nouveaux groupes "
 
"d'utilisateurs"
 

	
 
#: kallithea/model/db.py:1680
 
msgid "Default user has admin access to new user groups"
 
msgstr ""
 
"L'utilisateur par défaut a un accès administrateur aux nouveaux groupes "
 
"d'utilisateurs"
 

	
 
#: kallithea/model/db.py:1682
 
#, fuzzy
 
msgid "Only admins can create repository groups"
 
msgstr "Groupe de dépôts %s créé"
 
msgstr "Seul un administrateur peut créer un groupe de dépôts"
 

	
 
#: kallithea/model/db.py:1683
 
#, fuzzy
 
msgid "Non-admins can create repository groups"
 
msgstr "Groupe de dépôts %s créé"
 
msgstr ""
 
"Les utilisateurs non-administrateurs peuvent créer des groupes de dépôts"
 

	
 
#: kallithea/model/db.py:1685
 
#, fuzzy
 
msgid "Only admins can create user groups"
 
msgstr "[créé] groupe d'utilisateurs"
 
msgstr "Seul un administrateur peut créer des groupes d'utilisateurs"
 

	
 
#: kallithea/model/db.py:1686
 
#, fuzzy
 
msgid "Non-admins can create user groups"
 
msgstr "[créé] groupe d'utilisateurs"
 
msgstr ""
 
"Les utilisateurs non-administrateurs peuvent créer des groupes d'utilisateurs"
 

	
 
#: kallithea/model/db.py:1688
 
#, fuzzy
 
msgid "Only admins can create top level repositories"
 
msgstr "Dépôts de niveau supérieur"
 
msgstr "Seul un administrateur peut créer des dépôts de niveau supérieur"
 

	
 
#: kallithea/model/db.py:1689
 
#, fuzzy
 
msgid "Non-admins can create top level repositories"
 
msgstr "Dépôts de niveau supérieur"
 
msgstr ""
 
"Les utilisateurs non-administrateurs peuvent créer des dépôts de niveau "
 
"supérieur"
 

	
 
#: kallithea/model/db.py:1694
 
#, fuzzy
 
msgid "Only admins can fork repositories"
 
msgstr "Dépôts totaux"
 
msgstr "Seul un administrateur peut faire un fork de dépôt"
 

	
 
#: kallithea/model/db.py:1695
 
#, fuzzy
 
msgid "Non-admins can can fork repositories"
 
msgstr "Invalider le cache pour tous les dépôts"
 
msgstr "Les utilisateurs non-administrateurs peuvent faire un fork de dépôt"
 

	
 
#: kallithea/model/db.py:1698
 
#, fuzzy
 
msgid "User registration with manual account activation"
 
msgstr "Enregistrement des utilisateurs avec activation de compte manuelle"
 

	
 
#: kallithea/model/db.py:1699
 
#, fuzzy
 
msgid "User registration with automatic account activation"
 
msgstr "Enregistrement des utilisateurs avec activation de compte automatique"
 

	
 
#: kallithea/model/db.py:2228
 
#, fuzzy
 
msgid "Not reviewed"
 
msgstr "Pas encore relue"
 

	
 
#: kallithea/model/db.py:2231
 
#, fuzzy
 
msgid "Under review"
 
msgstr "En cours de relecture"
 

	
 
#: kallithea/model/forms.py:57
 
msgid "Please enter a login"
 
msgstr "Veuillez entrer un identifiant"
 

	
 
#: kallithea/model/forms.py:58
 
#, python-format
 
msgid "Enter a value %(min)i characters long or more"
 
msgstr "Entrez une valeur d’au moins %(min)i caractères de long"
 

	
 
#: kallithea/model/forms.py:66
 
msgid "Please enter a password"
 
msgstr "Veuillez entrer un mot de passe"
 

	
 
#: kallithea/model/forms.py:67
 
#, python-format
 
msgid "Enter %(min)i characters or more"
 
msgstr "Entrez au moins %(min)i caractères"
 

	
 
#: kallithea/model/forms.py:160
 
msgid "Name must not contain only digits"
 
msgstr "Le nom ne doit pas contenir seulement des chiffres"
 

	
 
#: kallithea/model/notification.py:254
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s commented on changeset %(age)s"
 
msgstr "%(user)s a commenté sur le changeset à %(when)s"
 
msgstr "%(user)s a commenté sur le changeset %(age)s"
 

	
 
#: kallithea/model/notification.py:255
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s sent message %(age)s"
 
msgstr "%(user)s a envoyé un message à %(when)s"
 
msgstr "%(user)s a envoyé un message %(age)s"
 

	
 
#: kallithea/model/notification.py:256
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s mentioned you %(age)s"
 
msgstr "%(user)s vous a mentionné à %(when)s"
 
msgstr "%(user)s vous a mentionné %(age)s"
 

	
 
#: kallithea/model/notification.py:257
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s registered in Kallithea %(age)s"
 
msgstr "%(user)s s'est enregistré sur Kallithea à %(when)s"
 
msgstr "%(user)s s'est enregistré sur Kallithea %(age)s"
 

	
 
#: kallithea/model/notification.py:258
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s opened new pull request %(age)s"
 
msgstr "%(user)s a ouvert une nouvelle demande de pull à %(when)s"
 
msgstr "%(user)s a ouvert une nouvelle demande de pull %(age)s"
 

	
 
#: kallithea/model/notification.py:259
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s commented on pull request %(age)s"
 
msgstr "%(user)s a commenté la demande de pull à %(when)s"
 
msgstr "%(user)s a commenté la demande de pull %(age)s"
 

	
 
#: kallithea/model/notification.py:266
 
#, python-format
 
msgid "%(user)s commented on changeset at %(when)s"
 
msgstr "%(user)s a commenté sur le changeset à %(when)s"
 

	
 
#: kallithea/model/notification.py:267
 
#, python-format
 
msgid "%(user)s sent message at %(when)s"
 
msgstr "%(user)s a envoyé un message à %(when)s"
 

	
 
#: kallithea/model/notification.py:268
 
#, python-format
 
msgid "%(user)s mentioned you at %(when)s"
 
msgstr "%(user)s vous a mentionné à %(when)s"
 

	
 
#: kallithea/model/notification.py:269
 
#, python-format
 
msgid "%(user)s registered in Kallithea at %(when)s"
 
msgstr "%(user)s s'est enregistré sur Kallithea à %(when)s"
 

	
 
#: kallithea/model/notification.py:270
 
#, python-format
 
msgid "%(user)s opened new pull request at %(when)s"
 
msgstr "%(user)s a ouvert une nouvelle demande de pull à %(when)s"
 

	
 
#: kallithea/model/notification.py:271
 
#, python-format
 
msgid "%(user)s commented on pull request at %(when)s"
 
msgstr "%(user)s a commenté la demande de pull à %(when)s"
 

	
 
#: kallithea/model/notification.py:302
 
#, python-format
 
msgid "[Comment] %(repo_name)s changeset %(short_id)s on %(branch)s"
 
msgstr ""
 
msgstr "[Commentaire] Changeset %(short_id)s de %(repo_name)s dans %(branch)s"
 

	
 
#: kallithea/model/notification.py:305
 
#, python-format
 
msgid "New user %(new_username)s registered"
 
msgstr "Nouvel utilisateur %(new_username)s enregistré"
 

	
 
#: kallithea/model/notification.py:307
 
#, fuzzy, python-format
 
#| msgid "%(user)s wants you to review pull request %(pr_nice_id)s:
 
#| %(pr_title)s"
 
#, python-format
 
#| msgid "%(user)s wants you to review pull request %(pr_nice_id)s:"
 
msgid "[Added] %(repo_name)s pull request %(pr_nice_id)s from %(ref)s"
 
msgstr ""
 
"%(user)s veut que vous regardiez la demande de pull #%(pr_id)s : "
 
"%(pr_title)s"
 
"[Ajouté] Demande de pull %(pr_nice_id)s à partir de %(ref)s pour "
 
"%(repo_name)s"
 

	
 
#: kallithea/model/notification.py:308
 
#, fuzzy, python-format
 
#, python-format
 
#| msgid "[commented] on pull request for"
 
msgid "[Comment] %(repo_name)s pull request %(pr_nice_id)s from %(ref)s"
 
msgstr "[a commenté] la requête de pull pour"
 
msgstr ""
 
"[Commentaire] Demande de pull %(pr_nice_id)s à partir de %(ref)s pour "
 
"%(repo_name)s"
 

	
 
#: kallithea/model/notification.py:321
 
msgid "Closing"
 
msgstr "Fermeture"
 

	
 
#: kallithea/model/pull_request.py:137
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s"
 
msgstr ""
 
"%(user)s veut que vous regardiez la demande de pull #%(pr_id)s: "
 
"%(user)s veut que vous regardiez la demande de pull %(pr_nice_id)s : "
 
"%(pr_title)s"
 

	
 
#: kallithea/model/scm.py:812
 
msgid "latest tip"
 
msgstr "Dernier sommet"
 

	
 
#: kallithea/model/user.py:192
 
msgid "New user registration"
 
msgstr "Nouveau enregistrement d'utilisateur"
 

	
 
#: kallithea/model/user.py:256
 
#, fuzzy
 
msgid "You can't remove this user since it is crucial for the entire application"
 
msgstr ""
 
"Vous ne pouvez pas supprimer cet utilisateur ; il est nécessaire pour le "
 
"bon fonctionnement de l’application"
 
"Vous ne pouvez pas supprimer cet utilisateur ; il est nécessaire pour le bon "
 
"fonctionnement de l’application"
 

	
 
#: kallithea/model/user.py:261
 
#, python-format
 
msgid ""
 
"User \"%s\" still owns %s repositories and cannot be removed. Switch "
 
"owners or remove those repositories: %s"
 
msgstr ""
 
"L’utilisateur \"%s\" possède %s dépôts et ne peut être supprimé. Changez "
 
"les propriétaires ou supprimez ces dépôts : %s"
 

	
 
#: kallithea/model/user.py:266
 
#, python-format
 
msgid ""
 
"User \"%s\" still owns %s repository groups and cannot be removed. Switch"
 
" owners or remove those repository groups: %s"
 
msgstr ""
 
"L’utilisateur \"%s\" possède %s groupes de dépôt et ne peut être "
 
"supprimé. Changez les propriétaires ou supprimez ces dépôts : %s"
 

	
 
#: kallithea/model/user.py:273
 
#, fuzzy, python-format
 
#, python-format
 
msgid ""
 
"User \"%s\" still owns %s user groups and cannot be removed. Switch "
 
"owners or remove those user groups: %s"
 
msgstr ""
 
"L’utilisateur « %s » possède %s dépôts et ne peut être supprimé. Changez "
 
"les propriétaires de ces dépôts. %s"
 
"L’utilisateur « %s » possède %s groupes d'utilisateurs et ne peut pas être "
 
"supprimé. Changez les propriétaires de ces groupes d'utilisateurs ou "
 
"supprimez-les : %s"
 

	
 
#: kallithea/model/user.py:360
 
msgid "Password reset link"
 
msgstr "Lien de remise à zéro du mot de passe"
 

	
 
#: kallithea/model/user.py:408
 
#, fuzzy
 
#| msgid "Password reset link"
 
msgid "Password reset notification"
 
msgstr "Lien de remise à zéro du mot de passe"
 
msgstr "Notification de réinitialisation du mot de passe"
 

	
 
#: kallithea/model/user.py:409
 
#, python-format
 
msgid ""
 
"The password to your account %s has been changed using password reset "
 
"form."
 
msgstr ""
 
"Le mot de passe de votre compte %s a été changé via le formulaire de "
 
"réinitialisation du mot de passe."
 

	
 
#: kallithea/model/validators.py:77 kallithea/model/validators.py:78
 
msgid "Value cannot be an empty list"
 
msgstr "Cette valeur ne peut être une liste vide"
 

	
 
#: kallithea/model/validators.py:95
 
#, python-format
 
msgid "Username \"%(username)s\" already exists"
 
msgstr "Le nom d’utilisateur « %(username)s » existe déjà"
 

	
 
#: kallithea/model/validators.py:97
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Username \"%(username)s\" cannot be used"
 
msgstr "Le nom d’utilisateur « %(username)s » n’est pas valide"
 

	
 
#: kallithea/model/validators.py:99
 
#, fuzzy
 
#| msgid "" "Username may only contain alphanumeric characters underscores,
 
#| periods or" " dashes and must begin with alphanumeric character or
 
#| underscore"
 
msgid ""
 
"Username may only contain alphanumeric characters underscores, periods or"
 
" dashes and must begin with an alphanumeric character or underscore"
 
msgstr ""
 
"Le pseudonyme ne peut contenir que des caractères alphanumériques, des "
 
"tirets, points, traits d'union et doit commencer avec un caractère "
 
"alphanumérique ou un trait d'union"
 
"Le nom d'utilisateur ne peut contenir que des caractères alphanumériques, "
 
"des underscores (_), points, traits d'union et doit commencer avec un "
 
"caractère alphanumérique ou un underscore"
 

	
 
#: kallithea/model/validators.py:126
 
msgid "The input is not valid"
 
msgstr "L'entrée n'est pas valide"
 

	
 
#: kallithea/model/validators.py:133
 
#, python-format
 
msgid "Username %(username)s is not valid"
 
msgstr "Le nom d’utilisateur « %(username)s » n’est pas valide"
 

	
 
#: kallithea/model/validators.py:152
 
msgid "Invalid user group name"
 
msgstr "Nom de groupe d'utilisateurs invalide"
 

	
 
#: kallithea/model/validators.py:153
 
#, python-format
 
msgid "User group \"%(usergroup)s\" already exists"
 
msgstr "Le groupe d'utilisateurs « %(usergroup)s » existe déjà"
 

	
 
#: kallithea/model/validators.py:155
 
msgid ""
 
"user group name may only contain alphanumeric characters underscores, "
 
"periods or dashes and must begin with alphanumeric character"
 
msgstr ""
 
@@ -2126,120 +2118,119 @@ msgstr "Impossible d’assigner ce groupe en tant que parent"
 

	
 
#: kallithea/model/validators.py:194
 
#, python-format
 
msgid "Group \"%(group_name)s\" already exists"
 
msgstr "Le groupe « %(group_name)s » existe déjà"
 

	
 
#: kallithea/model/validators.py:196
 
#, python-format
 
msgid "Repository with name \"%(group_name)s\" already exists"
 
msgstr "Un dépôt portant le nom « %(group_name)s » existe déjà"
 

	
 
#: kallithea/model/validators.py:254
 
msgid "Invalid characters (non-ascii) in password"
 
msgstr "Caractères incorrects (non-ASCII) dans le mot de passe"
 

	
 
#: kallithea/model/validators.py:269
 
msgid "Invalid old password"
 
msgstr "Ancien mot de passe invalide"
 

	
 
#: kallithea/model/validators.py:285
 
msgid "Passwords do not match"
 
msgstr "Les mots de passe ne correspondent pas"
 

	
 
#: kallithea/model/validators.py:300
 
#, fuzzy
 
msgid "Invalid username or password"
 
msgstr "mot de passe invalide"
 
msgstr "Nom d'utilisateur ou mot de passe invalide"
 

	
 
#: kallithea/model/validators.py:331
 
msgid "Token mismatch"
 
msgstr "Jeton d’authentification incorrect"
 

	
 
#: kallithea/model/validators.py:345
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Repository name %(repo)s is not allowed"
 
msgstr "Le nom de dépôt « %(repo)s » n’est pas autorisé"
 

	
 
#: kallithea/model/validators.py:347
 
#, python-format
 
msgid "Repository named %(repo)s already exists"
 
msgstr "Un dépôt portant le nom « %(repo)s » existe déjà"
 

	
 
#: kallithea/model/validators.py:348
 
#, python-format
 
msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
 
msgstr "Le dépôt « %(repo)s » existe déjà dans le groupe « %(group)s »"
 

	
 
#: kallithea/model/validators.py:350
 
#, python-format
 
msgid "Repository group with name \"%(repo)s\" already exists"
 
msgstr "Un groupe de dépôts avec le nom « %(repo)s » existe déjà"
 

	
 
#: kallithea/model/validators.py:465
 
#, fuzzy
 
msgid "Invalid repository URL"
 
msgstr "Dépôt privé"
 
msgstr "URL de dépôt invalide"
 

	
 
#: kallithea/model/validators.py:466
 
msgid ""
 
"Invalid repository URL. It must be a valid http, https, ssh, svn+http or "
 
"svn+https URL"
 
msgstr ""
 
"URL de dépôt invalide. Ce doit être une URL valide de type http, https, ssh, "
 
"svn+http ou svn+https"
 

	
 
#: kallithea/model/validators.py:489
 
msgid "Fork has to be the same type as parent"
 
msgstr "Le fork doit être du même type que le parent"
 

	
 
#: kallithea/model/validators.py:504
 
msgid "You don't have permissions to create repository in this group"
 
msgstr "Vous n’avez pas la permission de créer un dépôt dans ce"
 

	
 
#: kallithea/model/validators.py:506
 
msgid "no permission to create repository in root location"
 
msgstr "pas de permission de créer un dépôt dans la racine"
 

	
 
#: kallithea/model/validators.py:556
 
msgid "You don't have permissions to create a group in this location"
 
msgstr "Vous n'avez pas les permissions pour créer un groupe dans cet endroit"
 

	
 
#: kallithea/model/validators.py:597
 
msgid "This username or user group name is not valid"
 
msgstr "Ce nom d'utilisateur ou nom de groupe d'utilisateurs n'est pas valide"
 

	
 
#: kallithea/model/validators.py:690
 
msgid "This is not a valid path"
 
msgstr "Ceci n’est pas un chemin valide"
 

	
 
#: kallithea/model/validators.py:705
 
#, fuzzy
 
msgid "This email address is already in use"
 
msgstr "Cette adresse e-mail est déjà enregistrée"
 

	
 
#: kallithea/model/validators.py:725
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Email address \"%(email)s\" not found"
 
msgstr "L’adresse e-mail « %(email)s » n’existe pas."
 
msgstr "L’adresse e-mail « %(email)s » n’existe pas"
 

	
 
#: kallithea/model/validators.py:762
 
msgid ""
 
"The LDAP Login attribute of the CN must be specified - this is the name "
 
"of the attribute that is equivalent to \"username\""
 
msgstr ""
 
"L’attribut Login du CN doit être spécifié. Cet attribut correspond au nom"
 
" d’utilisateur"
 

	
 
#: kallithea/model/validators.py:774
 
msgid "Please enter a valid IPv4 or IPv6 address"
 
msgstr "Veuillez entrer une adresse IPv4 ou IPv6 valide"
 

	
 
#: kallithea/model/validators.py:775
 
#, python-format
 
msgid "The network size (bits) must be within the range of 0-32 (not %(bits)r)"
 
msgstr "La taille du réseau (bits) doit être entre 0 et 32 (et non %(bits)r)"
 

	
 
#: kallithea/model/validators.py:808
 
msgid "Key name can only consist of letters, underscore, dash or numbers"
 
msgstr ""
 
"Le nom de la clé ne peut consister que de letters, de traits d'union, de "
 
"tirets ou de nombres"
 

	
 
@@ -2486,134 +2477,135 @@ msgstr "Remettre le mot de passe à zéro"
 
#, python-format
 
msgid "Reset Your Password to %s"
 
msgstr "Réinitialiser votre mot de passe à %s"
 

	
 
#: kallithea/templates/password_reset.html:14
 
#: kallithea/templates/password_reset_confirmation.html:5
 
#: kallithea/templates/password_reset_confirmation.html:14
 
msgid "Reset Your Password"
 
msgstr "Réinitialiser votre mot de passe"
 

	
 
#: kallithea/templates/password_reset.html:25
 
msgid "Email Address"
 
msgstr "Adresse e-mail"
 

	
 
#: kallithea/templates/password_reset.html:35
 
#: kallithea/templates/register.html:79
 
msgid "Captcha"
 
msgstr "Captcha"
 

	
 
#: kallithea/templates/password_reset.html:46
 
msgid "Send Password Reset Email"
 
msgstr "Envoyer l'E-mail de réinitialisation du mot de passe"
 

	
 
#: kallithea/templates/password_reset.html:47
 
#, fuzzy
 
#| msgid "" "Password reset link will be sent to the email address matching
 
#| your " "username."
 
#| msgid "" "
 
msgid ""
 
"A password reset link will be sent to the specified email address if it "
 
"is registered in the system."
 
msgstr ""
 
"Le lien de réinitialisation du mot de passe sera envoyé à l'adresse "
 
"e-mail correspondant à votre nom d'utilisateur."
 
"Un lien de réinitialisation du mot de passe sera envoyé à l'adresse e-mail "
 
"indiquée si elle est enregistrée dans le système."
 

	
 
#: kallithea/templates/password_reset_confirmation.html:19
 
#, python-format
 
msgid "You are about to set a new password for the email address %s."
 
msgstr ""
 
"Vous êtes sur le point de changer le mot de passe pour l'adresse e-mail %s."
 

	
 
#: kallithea/templates/password_reset_confirmation.html:20
 
msgid ""
 
"Note that you must use the same browser session for this as the one used "
 
"to request the password reset."
 
msgstr ""
 
"Vous devez utiliser la même session de navigateur pour cette opération que "
 
"celle utilisée pour la demande de réinitialisation de mot de passe."
 

	
 
#: kallithea/templates/password_reset_confirmation.html:30
 
msgid "Code you received in the email"
 
msgstr ""
 
msgstr "Le code que vous avez reçu dans l'e-mail"
 

	
 
#: kallithea/templates/password_reset_confirmation.html:39
 
#, fuzzy
 
#| msgid "New password"
 
msgid "New Password"
 
msgstr "Nouveau mot de passe"
 

	
 
#: kallithea/templates/password_reset_confirmation.html:48
 
#, fuzzy
 
#| msgid "Confirm new password"
 
msgid "Confirm New Password"
 
msgstr "Confirmer le nouveau mot de passe"
 

	
 
#: kallithea/templates/password_reset_confirmation.html:56
 
msgid "Confirm"
 
msgstr ""
 
msgstr "Confirmation"
 

	
 
#: kallithea/templates/register.html:5 kallithea/templates/register.html:14
 
#: kallithea/templates/register.html:90
 
msgid "Sign Up"
 
msgstr "Inscription"
 

	
 
#: kallithea/templates/register.html:12
 
#, python-format
 
msgid "Sign Up to %s"
 
msgstr "S'inscrire sur %s"
 

	
 
#: kallithea/templates/register.html:42
 
msgid "Re-enter password"
 
msgstr "Confirmation"
 

	
 
#: kallithea/templates/register.html:51
 
#: kallithea/templates/admin/my_account/my_account_profile.html:34
 
#: kallithea/templates/admin/users/user_add.html:59
 
#: kallithea/templates/admin/users/user_edit_profile.html:78
 
#: kallithea/templates/admin/users/users.html:51
 
msgid "First Name"
 
msgstr "Prénom"
 

	
 
#: kallithea/templates/register.html:60
 
#: kallithea/templates/admin/my_account/my_account_profile.html:43
 
#: kallithea/templates/admin/users/user_add.html:68
 
#: kallithea/templates/admin/users/user_edit_profile.html:87
 
#: kallithea/templates/admin/users/users.html:52
 
msgid "Last Name"
 
msgstr "Nom"
 

	
 
#: kallithea/templates/register.html:69
 
#: kallithea/templates/admin/my_account/my_account_profile.html:52
 
#: kallithea/templates/admin/settings/settings.html:31
 
#: kallithea/templates/admin/users/user_add.html:77
 
#: kallithea/templates/admin/users/user_edit_profile.html:33
 
msgid "Email"
 
msgstr "E-mail"
 

	
 
#: kallithea/templates/register.html:92
 
msgid "Registered accounts are ready to use and need no further action."
 
msgstr ""
 
"Les comptes enregistrés sont prêts à être utilisés, et ne nécessitent aucune "
 
"autre action."
 

	
 
#: kallithea/templates/register.html:94
 
msgid "Please wait for an administrator to activate your account."
 
msgstr ""
 
msgstr "Merci d'attendre qu'un administrateur active votre compte."
 

	
 
#: kallithea/templates/switch_to_list.html:10
 
#: kallithea/templates/branches/branches_data.html:69
 
msgid "There are no branches yet"
 
msgstr "Aucune branche n’a été créée pour le moment"
 

	
 
#: kallithea/templates/switch_to_list.html:16
 
msgid "Closed Branches"
 
msgstr "Branches fermées"
 

	
 
#: kallithea/templates/switch_to_list.html:32
 
#: kallithea/templates/tags/tags_data.html:44
 
msgid "There are no tags yet"
 
msgstr "Aucun tag n’a été créé pour le moment"
 

	
 
#: kallithea/templates/switch_to_list.html:45
 
#: kallithea/templates/bookmarks/bookmarks_data.html:43
 
msgid "There are no bookmarks yet"
 
msgstr "Aucun signet n’a été créé"
 

	
 
#: kallithea/templates/admin/admin.html:5
 
#: kallithea/templates/admin/admin.html:13
 
#: kallithea/templates/base/base.html:59
 
msgid "Admin Journal"
 
@@ -2669,58 +2661,54 @@ msgid "From IP"
 
msgstr "Depuis l’adresse IP"
 

	
 
#: kallithea/templates/admin/admin_log.html:63
 
msgid "No actions yet"
 
msgstr "Aucune action n’a été enregistrée pour le moment"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:5
 
msgid "Authentication Settings"
 
msgstr "Réglages d'authentification"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:11
 
#: kallithea/templates/base/base.html:65
 
msgid "Authentication"
 
msgstr "Authentification"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:28
 
msgid "Authentication Plugins"
 
msgstr "Greffons d'authentification"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:31
 
msgid "Enabled Plugins"
 
msgstr "Greffons activés"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:33
 
#, fuzzy
 
#| msgid "" "Comma separated list of plugins. Order of plugins is also order in
 
#| which " "Kallithea will try to authenticate user"
 
msgid ""
 
"Comma-separated list of plugins; Kallithea will try user authentication "
 
"in plugin order"
 
msgstr ""
 
"Une liste séparée avec des virgules des greffons. L'ordre des greffons "
 
"est aussi celui dans lequel Kallithea va essayer d'authentifier un "
 
"utilisateur"
 
"Une liste séparée avec des virgules des greffons. L'ordre des greffons est "
 
"aussi celui dans lequel Kallithea va essayer d'authentifier un utilisateur"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:34
 
msgid "Available built-in plugins"
 
msgstr "Greffons inclus disponibles"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:51
 
msgid "Plugin"
 
msgstr "Greffon"
 

	
 
#: kallithea/templates/admin/auth/auth_settings.html:101
 
#: kallithea/templates/admin/defaults/defaults.html:82
 
#: kallithea/templates/admin/my_account/my_account_password.html:36
 
#: kallithea/templates/admin/my_account/my_account_profile.html:60
 
#: kallithea/templates/admin/permissions/permissions_globals.html:112
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:69
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:114
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:42
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:101
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:127
 
#: kallithea/templates/admin/settings/settings_hooks.html:53
 
#: kallithea/templates/admin/user_groups/user_group_add.html:57
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:104
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:60
 
#: kallithea/templates/admin/users/user_add.html:96
 
@@ -2815,51 +2803,50 @@ msgid "Gist lifetime"
 
msgstr "Durée de vie du gist"
 

	
 
#: kallithea/templates/admin/gists/edit.html:61
 
#: kallithea/templates/admin/gists/edit.html:63
 
#: kallithea/templates/admin/gists/index.html:57
 
#: kallithea/templates/admin/gists/index.html:59
 
#: kallithea/templates/admin/gists/show.html:47
 
#: kallithea/templates/admin/gists/show.html:49
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:8
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:27
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:32
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:8
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:27
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:32
 
msgid "Expires"
 
msgstr "Expire le"
 

	
 
#: kallithea/templates/admin/gists/edit.html:61
 
#: kallithea/templates/admin/gists/index.html:57
 
#: kallithea/templates/admin/gists/show.html:47
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:8
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:27
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:8
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:27
 
#, fuzzy
 
msgid "Never"
 
msgstr "jamais"
 
msgstr "Jamais"
 

	
 
#: kallithea/templates/admin/gists/edit.html:145
 
msgid "Update Gist"
 
msgstr "Mettre à jour le gist"
 

	
 
#: kallithea/templates/admin/gists/edit.html:146
 
#: kallithea/templates/changeset/changeset_file_comment.html:81
 
msgid "Cancel"
 
msgstr "Annuler"
 

	
 
#: kallithea/templates/admin/gists/index.html:6
 
#: kallithea/templates/admin/gists/index.html:16
 
#, python-format
 
msgid "Private Gists for User %s"
 
msgstr "Gists privés de l'utilisateur %s"
 

	
 
#: kallithea/templates/admin/gists/index.html:8
 
#: kallithea/templates/admin/gists/index.html:18
 
#, python-format
 
msgid "Public Gists for User %s"
 
msgstr "Gists publiques de l'utilisateur %s"
 

	
 
#: kallithea/templates/admin/gists/index.html:10
 
#: kallithea/templates/admin/gists/index.html:20
 
@@ -2999,114 +2986,106 @@ msgstr "Modifier"
 
msgid "Show as Raw"
 
msgstr "Montrer en brut"
 

	
 
#: kallithea/templates/admin/gists/show.html:73
 
msgid "created"
 
msgstr "créé"
 

	
 
#: kallithea/templates/admin/gists/show.html:86
 
#: kallithea/templates/files/files_source.html:73
 
msgid "Show as raw"
 
msgstr "Montrer en brut"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:5
 
#: kallithea/templates/admin/my_account/my_account.html:9
 
#: kallithea/templates/base/base.html:343
 
msgid "My Account"
 
msgstr "Mon compte"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:35
 
#: kallithea/templates/admin/users/user_edit.html:29
 
msgid "Profile"
 
msgstr "Profil"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:36
 
#, fuzzy
 
msgid "Email Addresses"
 
msgstr "Nouvelle adrese"
 
msgstr "Adresses e-mail"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:38
 
#: kallithea/templates/admin/users/user_edit.html:31
 
msgid "API Keys"
 
msgstr "Clés de l'API"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:39
 
#, fuzzy
 
msgid "Owned Repositories"
 
msgstr "Dépôts"
 
msgstr "Dépôts possédés"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:40
 
#: kallithea/templates/journal/journal.html:53
 
#, fuzzy
 
msgid "Watched Repositories"
 
msgstr "Création de dépôts"
 
msgstr "Dépôts surveillés"
 

	
 
#: kallithea/templates/admin/my_account/my_account.html:41
 
#: kallithea/templates/admin/permissions/permissions.html:30
 
#: kallithea/templates/admin/user_groups/user_group_edit.html:32
 
#: kallithea/templates/admin/users/user_edit.html:34
 
#, fuzzy
 
msgid "Show Permissions"
 
msgstr "Copier les permissions"
 
msgstr "Afficher les permissions"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:6
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:6
 
msgid "Built-in"
 
msgstr "Inclus"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:14
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:14
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Confirm to reset this API key: %s"
 
msgstr "Confirmer la remise à zéro de cette clé d'API : %s"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:30
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:30
 
#, fuzzy
 
msgid "Expired"
 
msgstr "a expiré"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:40
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:40
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Confirm to remove this API key: %s"
 
msgstr "Confirmer la suppression de cette clé d'API : %s"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:42
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:42
 
#, fuzzy
 
msgid "Remove"
 
msgstr "supprimer"
 
msgstr "Supprimer"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:49
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:49
 
#, fuzzy
 
msgid "No additional API keys specified"
 
msgstr "Pas de clés d'API supplémentaires spécifiées"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:61
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:61
 
#, fuzzy
 
msgid "New API key"
 
msgstr "Nouvelle clé d'API"
 

	
 
#: kallithea/templates/admin/my_account/my_account_api_keys.html:69
 
#: kallithea/templates/admin/my_account/my_account_emails.html:45
 
#: kallithea/templates/admin/permissions/permissions_ips.html:38
 
#: kallithea/templates/admin/repos/repo_add_base.html:81
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:58
 
#: kallithea/templates/admin/users/user_edit_api_keys.html:69
 
#: kallithea/templates/admin/users/user_edit_emails.html:45
 
#: kallithea/templates/admin/users/user_edit_ips.html:49
 
msgid "Add"
 
msgstr "Ajouter"
 

	
 
#: kallithea/templates/admin/my_account/my_account_emails.html:7
 
#: kallithea/templates/admin/users/user_edit_emails.html:7
 
msgid "Primary"
 
msgstr "Primaire"
 

	
 
#: kallithea/templates/admin/my_account/my_account_emails.html:20
 
#: kallithea/templates/admin/users/user_edit_emails.html:20
 
#, python-format
 
msgid "Confirm to delete this email: %s"
 
msgstr "Veuillez confirmer la suppression de l’e-mail : %s"
 
@@ -3121,72 +3100,72 @@ msgstr "Pas d'adresse email supplémentaires spécifiées."
 
msgid "New email address"
 
msgstr "Nouvelle adrese"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:1
 
msgid "Change Your Account Password"
 
msgstr "Changer le mot de passe de votre compte"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:10
 
msgid "Current password"
 
msgstr "Mot de passe actuel"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:19
 
#: kallithea/templates/admin/users/user_edit_profile.html:60
 
msgid "New password"
 
msgstr "Nouveau mot de passe"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:28
 
msgid "Confirm new password"
 
msgstr "Confirmer le nouveau mot de passe"
 

	
 
#: kallithea/templates/admin/my_account/my_account_password.html:45
 
#, python-format
 
msgid "This account is managed with %s and the password cannot be changed here"
 
msgstr ""
 
"Ce compte est géré avec %s et le mot de passe ne peut pas être changé ici"
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:11
 
msgid "Change your avatar at"
 
msgstr "Vous pouvez changer votre avatar sur"
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:12
 
#: kallithea/templates/admin/users/user_edit_profile.html:9
 
msgid "Using"
 
msgstr "en utilisant l’adresse"
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:14
 
#: kallithea/templates/admin/users/user_edit_profile.html:11
 
msgid "Avatars are disabled"
 
msgstr "Les avatars sont désactivés"
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:15
 
msgid "Missing email, please update your user email address."
 
msgstr "Adresse courriel manquante, veuillez mettre à jour votre adresse courriel."
 

	
 
#: kallithea/templates/admin/my_account/my_account_profile.html:16
 
#: kallithea/templates/admin/users/user_edit_profile.html:15
 
#, fuzzy
 
msgid "Current IP"
 
msgstr "adresse IP actuelle"
 
msgstr "Adresse IP actuelle"
 

	
 
#: kallithea/templates/admin/my_account/my_account_repos.html:1
 
msgid "Repositories You Own"
 
msgstr "Dépôts dont vous êtes le propriétaire"
 

	
 
#: kallithea/templates/admin/my_account/my_account_repos.html:59
 
#: kallithea/templates/admin/my_account/my_account_watched.html:59
 
#: kallithea/templates/base/root.html:45
 
#: kallithea/templates/bookmarks/bookmarks.html:81
 
#: kallithea/templates/branches/branches.html:81
 
#: kallithea/templates/journal/journal.html:200
 
#: kallithea/templates/journal/journal.html:291
 
#: kallithea/templates/tags/tags.html:81
 
msgid "No records found."
 
msgstr "Aucun élément n’a été trouvé."
 

	
 
#: kallithea/templates/admin/my_account/my_account_watched.html:1
 
msgid "Repositories You are Watching"
 
msgstr "Dépôts que vous surveillez"
 

	
 
#: kallithea/templates/admin/notifications/notifications.html:5
 
#: kallithea/templates/admin/notifications/notifications.html:9
 
msgid "My Notifications"
 
msgstr "Mes notifications"
 
@@ -3204,236 +3183,254 @@ msgstr "Commentaires"
 
msgid "Pull Requests"
 
msgstr "Demandes de pull"
 

	
 
#: kallithea/templates/admin/notifications/notifications.html:30
 
msgid "Mark All Read"
 
msgstr "Tout marquer comme lu"
 

	
 
#: kallithea/templates/admin/notifications/notifications_data.html:40
 
msgid "No notifications here yet"
 
msgstr "Aucune notification pour le moment"
 

	
 
#: kallithea/templates/admin/notifications/show_notification.html:5
 
#: kallithea/templates/admin/notifications/show_notification.html:11
 
msgid "Show Notification"
 
msgstr "Montrer Notification"
 

	
 
#: kallithea/templates/admin/notifications/show_notification.html:9
 
#: kallithea/templates/base/base.html:342
 
msgid "Notifications"
 
msgstr "Notifications"
 

	
 
#: kallithea/templates/admin/permissions/permissions.html:5
 
#: kallithea/templates/admin/permissions/permissions.html:11
 
#: kallithea/templates/base/base.html:64
 
#, fuzzy
 
msgid "Default Permissions"
 
msgstr "Permissions par défaut"
 

	
 
#: kallithea/templates/admin/permissions/permissions.html:28
 
#: kallithea/templates/admin/settings/settings.html:29
 
msgid "Global"
 
msgstr "Global"
 

	
 
#: kallithea/templates/admin/permissions/permissions.html:29
 
#: kallithea/templates/admin/users/user_edit.html:32
 
msgid "IP Whitelist"
 
msgstr "Liste blanche d'adresses IP"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:7
 
msgid "Anonymous access"
 
msgstr "Accès anonyme"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:13
 
#, fuzzy, python-format
 
#, python-format
 
msgid ""
 
"Allow access to Kallithea without needing to log in. Anonymous users use "
 
"%s user permissions."
 
msgstr ""
 
"Autoriser l'accès à Kallithea sans le besoin de se connecter. Les "
 
"utilisateurs anonymes ont les permissions de %s"
 
"utilisateurs anonymes ont les permissions de l'utilisateur %s."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:25
 
msgid ""
 
"All default permissions on each repository will be reset to chosen "
 
"permission, note that all custom default permission on repositories will "
 
"be lost"
 
msgstr ""
 
"Toutes les permissions par défaut de chaque dépôt vont être réinitialisées "
 
"aux valeurs choisies. Notez que toutes les permissions par défaut "
 
"personnalisées sur les dépôts seront perdues"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:26
 
#, fuzzy
 
msgid "Apply to all existing repositories"
 
msgstr "Importer un dépôt existant?"
 
msgstr "Appliquer à tous les dépôts existants"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:27
 
msgid "Permissions for the Default user on new repositories."
 
msgstr ""
 
msgstr "Permissions pour l'utilisateur par défaut sur les nouveaux dépôts."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:32
 
#: kallithea/templates/admin/repos/repo_add_base.html:37
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:35
 
#: kallithea/templates/data_table/_dt_elements.html:202
 
#: kallithea/templates/forks/fork.html:48
 
msgid "Repository group"
 
msgstr "Groupe de dépôt"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:39
 
msgid ""
 
"All default permissions on each repository group will be reset to chosen "
 
"permission, note that all custom default permission on repository groups "
 
"will be lost"
 
msgstr ""
 
"Toutes les permissions par défaut de chaque groupe de dépôts vont être "
 
"réinitialisées aux valeurs choisies. Notez que toutes les permissions par "
 
"défaut personnalisées sur les groupes de dépôts seront perdues"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:40
 
#, fuzzy
 
msgid "Apply to all existing repository groups"
 
msgstr "Importer un dépôt existant?"
 
msgstr "Appliquer à tous les groupes de dépôts existants"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:41
 
msgid "Permissions for the Default user on new repository groups."
 
msgstr ""
 
"Permissions pour l'utilisateur par défaut sur les nouveaux groupes de dépôts."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:46
 
#: kallithea/templates/data_table/_dt_elements.html:209
 
msgid "User group"
 
msgstr "Groupe d'utilisateurs"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:53
 
msgid ""
 
"All default permissions on each user group will be reset to chosen "
 
"permission, note that all custom default permission on user groups will "
 
"be lost"
 
msgstr ""
 
"Toutes les permissions par défaut de chaque groupe d'utilisateurs vont être "
 
"réinitialisées aux valeurs choisies. Notez que toutes les permissions par "
 
"défaut personnalisées sur les groupes d'utilisateurs seront perdues"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:54
 
msgid "Apply to all existing user groups"
 
msgstr ""
 
msgstr "Appliquer à tous les groupes d'utilisateurs existants"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:55
 
msgid "Permissions for the Default user on new user groups."
 
msgstr ""
 
"Permissions pour l'utilisateur par défaut sur les nouveaux groupes "
 
"d'utilisateurs."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:60
 
#, fuzzy
 
msgid "Top level repository creation"
 
msgstr "Création de dépôt"
 
msgstr "Création de dépôt de niveau supérieur"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:64
 
msgid "Enable this to allow non-admins to create repositories at the top level."
 
msgstr ""
 
"Activer pour autoriser les non-administrateurs à créer des dépôts au niveau "
 
"supérieur."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:65
 
msgid ""
 
"Note: This will also give all users API access to create repositories "
 
"everywhere. That might change in future versions."
 
msgstr ""
 
"Note : Cela autorisera également tous les utilisateurs à utiliser l'API pour "
 
"créer des dépôts partout. Ce comportement peut changer dans des versions "
 
"futures."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:70
 
msgid "Repository creation with group write access"
 
msgstr "Création de dépôts avec l'accès en écriture du groupe"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:74
 
msgid ""
 
"With this, write permission to a repository group allows creating "
 
"repositories inside that group. Without this, group write permissions "
 
"mean nothing."
 
msgstr ""
 
"Avec ceci, le droit d'écriture dans un groupe de dépôt donne le droit de "
 
"créer des dépôts dans ce groupe. Sans ceci, le droit d'écriture pour les "
 
"groupes n'a pas d'impact."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:79
 
msgid "User group creation"
 
msgstr "Création de groupes d'utilisateurs"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:83
 
msgid "Enable this to allow non-admins to create user groups."
 
msgstr ""
 
"Activer pour autoriser les non-administrateurs à créer des groupes "
 
"d'utilisateurs."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:88
 
msgid "Repository forking"
 
msgstr "Fork de dépôt"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:92
 
msgid "Enable this to allow non-admins to fork repositories."
 
msgstr ""
 
"Activer pour autoriser les non-administrateurs à faire des fork de dépôt."
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:97
 
msgid "Registration"
 
msgstr "Enregistrement"
 

	
 
#: kallithea/templates/admin/permissions/permissions_globals.html:105
 
msgid "External auth account activation"
 
msgstr ""
 
msgstr "Activation de l'authentification externe"
 

	
 
#: kallithea/templates/admin/permissions/permissions_ips.html:13
 
#: kallithea/templates/admin/users/user_edit_ips.html:23
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Confirm to delete this IP address: %s"
 
msgstr "Confirmer la suppression de cette adresse IP : %s"
 

	
 
#: kallithea/templates/admin/permissions/permissions_ips.html:19
 
#: kallithea/templates/admin/users/user_edit_ips.html:30
 
#, fuzzy
 
msgid "All IP addresses are allowed."
 
msgstr "Toutes les adresses IP sont autorisées"
 
msgstr "Toutes les adresses IP sont autorisées."
 

	
 
#: kallithea/templates/admin/permissions/permissions_ips.html:30
 
#: kallithea/templates/admin/users/user_edit_ips.html:42
 
msgid "New IP address"
 
msgstr "Nouvelle adresse IP"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:11
 
#: kallithea/templates/admin/repo_groups/repo_group_edit.html:11
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:105
 
#: kallithea/templates/admin/repo_groups/repo_groups.html:10
 
#: kallithea/templates/base/base.html:61 kallithea/templates/base/base.html:80
 
msgid "Repository Groups"
 
msgstr "Groupes de dépôts"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:33
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:8
 
#: kallithea/templates/admin/user_groups/user_group_add.html:32
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:7
 
msgid "Group name"
 
msgstr "Nom de groupe"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:51
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:26
 
msgid "Group parent"
 
msgstr "Parent du groupe"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:60
 
#: kallithea/templates/admin/repos/repo_add_base.html:46
 
msgid "Copy parent group permissions"
 
msgstr "Copier les permissions du groupe parent"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_add.html:64
 
#: kallithea/templates/admin/repos/repo_add_base.html:50
 
msgid "Copy permission set from parent repository group."
 
msgstr ""
 
msgstr "Copier les permissions à partir du groupe de dépôts parent."
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit.html:5
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%s Repository Group Settings"
 
msgstr "Réglages du groupe de dépôts %s"
 
msgstr "Options du groupe de dépôts %s"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit.html:21
 
msgid "Add Child Group"
 
msgstr "Ajouter un groupe enfant"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit.html:40
 
#: kallithea/templates/admin/repos/repo_edit.html:12
 
#: kallithea/templates/admin/repos/repo_edit.html:40
 
#: kallithea/templates/admin/settings/settings.html:11
 
#: kallithea/templates/admin/user_groups/user_group_edit.html:29
 
#: kallithea/templates/base/base.html:67 kallithea/templates/base/base.html:151
 
#: kallithea/templates/data_table/_dt_elements.html:45
 
#: kallithea/templates/data_table/_dt_elements.html:49
 
msgid "Settings"
 
msgstr "Options"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit.html:41
 
#: kallithea/templates/admin/repos/repo_edit.html:46
 
#: kallithea/templates/admin/user_groups/user_group_edit.html:30
 
#: kallithea/templates/admin/users/user_edit.html:33
 
msgid "Advanced"
 
msgstr "Avancé"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit.html:42
 
@@ -3460,2741 +3457,2734 @@ msgid "Children groups"
 
msgstr "Groupes enfants"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_advanced.html:9
 
#: kallithea/templates/admin/user_groups/user_group_edit_advanced.html:7
 
#: kallithea/templates/admin/users/user_edit_advanced.html:8
 
#: kallithea/templates/pullrequests/pullrequest_show.html:148
 
msgid "Created on"
 
msgstr "Créé le"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_advanced.html:21
 
#: kallithea/templates/data_table/_dt_elements.html:190
 
#, python-format
 
msgid "Confirm to delete this group: %s with %s repository"
 
msgid_plural "Confirm to delete this group: %s with %s repositories"
 
msgstr[0] "Confirmer la suppression de ce groupe : %s avec %s dépôt"
 
msgstr[1] "Confirmer la suppression de ce groupe : %s avec %s dépôts"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_advanced.html:25
 
msgid "Delete this repository group"
 
msgstr "Supprimer ce groupe de dépôts"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:11
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:12
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:11
 
#, fuzzy
 
msgid "User/User Group"
 
msgstr "utilisateur/groupe d'utilisateurs"
 
msgstr "Utilisateur/groupe d'utilisateurs"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:28
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:45
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:24
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:37
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:28
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:45
 
#, fuzzy
 
msgid "Default"
 
msgstr "[Par défaut]"
 
msgstr "Par défaut"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:34
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:71
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:43
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:68
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:34
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:71
 
#, fuzzy
 
msgid "Revoke"
 
msgstr "Révoquer"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:97
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:94
 
#: kallithea/templates/admin/user_groups/user_group_edit_perms.html:97
 
msgid "Add new"
 
msgstr "Ajouter un nouveau"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:103
 
#, fuzzy
 
msgid "Apply to children"
 
msgstr "Appliquer aux enfants"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:107
 
msgid "Both"
 
msgstr "Les deux"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_perms.html:108
 
msgid ""
 
"Set or revoke permission to all children of that group, including non-"
 
"private repositories and other groups if selected."
 
msgstr ""
 
"Ajouter ou révoquer la permission pour tous les enfants de ce groupe, y "
 
"compris les dépôts non-privés et les autres groupes si sélectionné."
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:38
 
msgid ""
 
"Enable lock-by-pulling on group. This option will be applied to all other"
 
" groups and repositories inside"
 
msgstr ""
 
"Activer le verrou lors d’un pull sur le groupe. Cette option sera "
 
"appliquée à tous les sous-groupes et dépôts de ce groupe"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:53
 
msgid "Remove this group"
 
msgstr ""
 
msgstr "Supprimer ce groupe"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_edit_settings.html:53
 
#, fuzzy
 
msgid "Confirm to delete this group"
 
msgstr "Confirmer la suppression de cette adresse IP : %s"
 
msgstr "Confirmer la suppression de ce groupe"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_show.html:4
 
#, python-format
 
msgid "%s Repository group dashboard"
 
msgstr "Tableau de bord du groupe de dépôts %s"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_show.html:9
 
msgid "Home"
 
msgstr "Accueil"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_group_show.html:13
 
msgid "with"
 
msgstr "comprenant"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_groups.html:5
 
#, fuzzy
 
msgid "Repository Groups Administration"
 
msgstr "Administration des groupes de dépôts"
 

	
 
#: kallithea/templates/admin/repo_groups/repo_groups.html:48
 
#, fuzzy
 
msgid "Number of Top-level Repositories"
 
msgstr "Nombre de sous-dépôts"
 
msgstr "Nombre de dépôts de niveau supérieur"
 

	
 
#: kallithea/templates/admin/repos/repo_add_base.html:17
 
#, fuzzy
 
msgid "Clone remote repository"
 
msgstr "[a créé] le dépôt"
 
msgstr "Cloner le dépôt distant"
 

	
 
#: kallithea/templates/admin/repos/repo_add_base.html:22
 
msgid ""
 
"Optional: URL of a remote repository. If set, the repository will be "
 
"created as a clone from this URL."
 
msgstr ""
 
"Optionnel : URL d'un dépôt distant. Si renseigné, le dépôt sera créé comme "
 
"un clone à partir de cette URL."
 

	
 
#: kallithea/templates/admin/repos/repo_add_base.html:32
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:69
 
#: kallithea/templates/forks/fork.html:42
 
msgid "Keep it short and to the point. Use a README file for longer descriptions."
 
msgstr ""
 
"Gardez cette description précise et concise. Utilisez un fichier README "
 
"pour des descriptions plus détaillées."
 

	
 
#: kallithea/templates/admin/repos/repo_add_base.html:41
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:39
 
#: kallithea/templates/forks/fork.html:52
 
msgid "Optionally select a group to put this repository into."
 
msgstr "Sélectionnez un groupe (optionel) dans lequel sera placé le dépôt."
 

	
 
#: kallithea/templates/admin/repos/repo_add_base.html:59
 
msgid "Type of repository to create."
 
msgstr "Type de dépôt à créer."
 

	
 
#: kallithea/templates/admin/repos/repo_add_base.html:64
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:44
 
#: kallithea/templates/forks/fork.html:58
 
msgid "Landing revision"
 
msgstr "Révision d’arrivée"
 

	
 
#: kallithea/templates/admin/repos/repo_add_base.html:68
 
msgid ""
 
"Default revision for files page, downloads, full text search index and "
 
"readme generation"
 
msgstr ""
 
"Révision par défaut pour les pages de fichiers, de téléchargement, de "
 
"l'index de recherche dans le texte complet, et de génération de "
 
"documentation (readme)"
 

	
 
#: kallithea/templates/admin/repos/repo_creating.html:9
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%s Creating Repository"
 
msgstr "%s Création du dépôt"
 
msgstr "Création du dépôt %s"
 

	
 
#: kallithea/templates/admin/repos/repo_creating.html:13
 
msgid "Creating repository"
 
msgstr "Création du dépôt"
 

	
 
#: kallithea/templates/admin/repos/repo_creating.html:27
 
#, python-format
 
msgid ""
 
"Repository \"%(repo_name)s\" is being created, you will be redirected "
 
"when this process is finished.repo_name"
 
msgstr ""
 
"Le dépôt « %(repo_name)s » est en cours de création, vous allez être "
 
"redirigé quand cette opération sera terminée."
 

	
 
#: kallithea/templates/admin/repos/repo_creating.html:39
 
msgid ""
 
"We're sorry but error occurred during this operation. Please check your "
 
"Kallithea server logs, or contact administrator."
 
msgstr ""
 
"Désolé, une erreur est survenue pendant l'opération. Vérifiez les journaux "
 
"du serveur Kallithea, ou contactez votre administrateur."
 

	
 
#: kallithea/templates/admin/repos/repo_edit.html:8
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%s Repository Settings"
 
msgstr "Réglages du groupe de dépôts %s"
 
msgstr "Réglages du dépôt %s"
 

	
 
#: kallithea/templates/admin/repos/repo_edit.html:49
 
msgid "Extra Fields"
 
msgstr ""
 
msgstr "Champs supplémentaires"
 

	
 
#: kallithea/templates/admin/repos/repo_edit.html:52
 
msgid "Caches"
 
msgstr ""
 
msgstr "Caches"
 

	
 
#: kallithea/templates/admin/repos/repo_edit.html:55
 
msgid "Remote"
 
msgstr "Dépôt distant"
 

	
 
#: kallithea/templates/admin/repos/repo_edit.html:58
 
#: kallithea/templates/summary/statistics.html:8
 
#: kallithea/templates/summary/summary.html:171
 
#: kallithea/templates/summary/summary.html:172
 
msgid "Statistics"
 
msgstr "Statistiques"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:1
 
#, fuzzy
 
msgid "Parent"
 
msgstr "Parent du groupe"
 
msgstr "Parent"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:5
 
#: kallithea/templates/admin/repos/repo_edit_fork.html:5
 
msgid "Set"
 
msgstr ""
 
msgstr "Appliquer"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:8
 
#: kallithea/templates/admin/repos/repo_edit_fork.html:9
 
#, fuzzy
 
msgid "Manually set this repository as a fork of another from the list."
 
msgstr "Marquer ce dépôt comme fork d’un autre dépôt de la liste"
 
msgstr "Marquer manuellement ce dépôt comme fork d’un autre dépôt de la liste."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:22
 
#, fuzzy
 
msgid "Public Journal Visibility"
 
msgstr "Journal public"
 
msgstr "Visibilité du journal public"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:29
 
msgid "Remove from public journal"
 
msgstr "Supprimer du journal public"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:34
 
#, fuzzy
 
msgid "Add to Public Journal"
 
msgstr "Journal public"
 
msgstr "Ajouter au journal public"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:40
 
#, fuzzy
 
msgid ""
 
"All actions done in this repository will be visible to everyone in the "
 
"public journal."
 
msgstr ""
 
"Le descriptif des actions réalisées sur ce dépôt sera visible à tous "
 
"depuis le journal public"
 
"Les actions réalisées sur ce dépôt seront visibles à tous depuis le journal "
 
"public."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:46
 
#, fuzzy
 
msgid "Change Locking"
 
msgstr "Activer le verrouillage"
 
msgstr "Changer le verrouillage"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:52
 
#, fuzzy
 
msgid "Confirm to unlock repository."
 
msgstr "Veuillez confirmer le déverrouillage de ce dépôt"
 
msgstr "Veuillez confirmer le déverrouillage de ce dépôt."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:54
 
#, fuzzy
 
msgid "Unlock Repository"
 
msgstr "Dépôt non verrouillé"
 
msgstr "Déverrouiller le dépôt"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:60
 
#, fuzzy
 
msgid "Confirm to lock repository."
 
msgstr "Veuillez confirmer le verrouillage de ce dépôt"
 
msgstr "Veuillez confirmer le verrouillage de ce dépôt."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:62
 
#, fuzzy
 
msgid "Lock Repository"
 
msgstr "Dépôt non verrouillé"
 
msgstr "Verrouiller le dépôt"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:64
 
msgid "Repository is not locked"
 
msgstr "Ce dépôt n’est pas verrouillé"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:68
 
msgid ""
 
"Force locking on the repository. Works only when anonymous access is "
 
"disabled. Triggering a pull locks the repository.  The user who is "
 
"pulling locks the repository; only the user who pulled and locked it can "
 
"unlock it by doing a push."
 
msgstr ""
 
"Forcer le verrouillage du dépôt. Ne fonctionne que lorsque l'accès anonyme "
 
"est désactivé. Déclencher un pull verrouille le dépôt. L'utilisateur qui "
 
"fait le pull verrouille le dépôt ; seul l'utilisateur qui a fait le pull et "
 
"a verrouillé peut déverrouiller en faisant un push."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:79
 
#: kallithea/templates/data_table/_dt_elements.html:130
 
#, python-format
 
msgid "Confirm to delete this repository: %s"
 
msgstr "Voulez-vous vraiment supprimer le dépôt %s ?"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:81
 
#, fuzzy
 
msgid "Delete this Repository"
 
msgstr "Supprimer ce groupe de dépôts"
 
msgstr "Supprimer ce dépôt"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:84
 
#, fuzzy, python-format
 
#, python-format
 
msgid "This repository has %s fork"
 
msgid_plural "This repository has %s forks"
 
msgstr[0] ""
 
msgstr[1] ""
 
msgstr[0] "Ce dépôt a %s fork"
 
msgstr[1] "Ce dépôt a %s forks"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:85
 
msgid "Detach forks"
 
msgstr ""
 
msgstr "Détacher les forks"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:86
 
msgid "Delete forks"
 
msgstr ""
 
msgstr "Supprimer les forks"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_advanced.html:90
 
msgid ""
 
"The deleted repository will be moved away and hidden until the "
 
"administrator expires it. The administrator can both permanently delete "
 
"it or restore it."
 
msgstr ""
 
"Le dépôt supprimé sera mis de côté et caché jusqu'à ce que l'administrateur "
 
"le fasse expirer. L'administrateur peut soit le supprimer définitivement, "
 
"soit le restaurer."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_caches.html:4
 
#, fuzzy
 
msgid "Invalidate Repository Cache"
 
msgstr "Invalider le cache du dépôt"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_caches.html:4
 
#, fuzzy
 
msgid "Confirm to invalidate repository cache."
 
msgstr "Voulez-vous vraiment invalider le cache du dépôt ?"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_caches.html:7
 
#, fuzzy
 
msgid ""
 
"Manually invalidate cache for this repository. On first access, the "
 
"repository will be cached again."
 
msgstr ""
 
"Invalide manuellement le cache de ce dépôt. Au prochain accès sur ce "
 
"dépôt, il sera à nouveau mis en cache"
 
"Invalider manuellement le cache de ce dépôt. Au prochain accès sur ce dépôt, "
 
"il sera à nouveau mis en cache."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_caches.html:12
 
#, fuzzy
 
msgid "List of Cached Values"
 
msgstr "Liste des valeurs en cache"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_caches.html:15
 
msgid "Prefix"
 
msgstr ""
 
msgstr "Préfixe"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_caches.html:16
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:6
 
msgid "Key"
 
msgstr ""
 
msgstr "Clé"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_caches.html:17
 
#: kallithea/templates/admin/user_groups/user_group_add.html:49
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:24
 
#: kallithea/templates/admin/user_groups/user_groups.html:49
 
#: kallithea/templates/admin/users/user_add.html:86
 
#: kallithea/templates/admin/users/user_edit_profile.html:96
 
#: kallithea/templates/admin/users/users.html:54
 
msgid "Active"
 
msgstr "Actif"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:5
 
msgid "Label"
 
msgstr ""
 
msgstr "Libellé"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:19
 
#, python-format
 
msgid "Confirm to delete this field: %s"
 
msgstr ""
 
msgstr "Voulez-vous vraiment supprimer ce champ : %s ?"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:33
 
msgid "New field key"
 
msgstr ""
 
msgstr "Clé du nouveau champ"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:41
 
msgid "New field label"
 
msgstr ""
 
msgstr "Libellé du nouveau champ"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:44
 
msgid "Enter short label"
 
msgstr ""
 
msgstr "Saisir un libellé court"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:50
 
msgid "New field description"
 
msgstr ""
 
msgstr "Description du nouveau champ"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:53
 
msgid "Enter description of a field"
 
msgstr ""
 
msgstr "Saisir la description du champ"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_fields.html:66
 
#, fuzzy
 
msgid "Extra fields are disabled."
 
msgstr "Les avatars sont désactivés"
 
msgstr "Les champs supplémentaires sont désactivés."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_permissions.html:21
 
#, fuzzy
 
msgid "Private Repository"
 
msgstr "Dépôt privé"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_remote.html:3
 
#, fuzzy
 
msgid "Remote repository URL"
 
msgstr "Dépôt %s créé"
 
msgstr "URL du dépôt distant"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_remote.html:9
 
#, fuzzy
 
msgid "Pull Changes from Remote Repository"
 
msgstr "[a pullé depuis un site distant] dans le dépôt"
 
msgstr "Récupérer les modifications depuis le dépôt distant"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_remote.html:11
 
#, fuzzy
 
msgid "Confirm to pull changes from remote repository."
 
msgstr "Voulez-vous vraiment récupérer les changements depuis le site distant ?"
 
msgstr ""
 
"Voulez-vous vraiment récupérer les changements depuis le dépôt distant ?"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_remote.html:17
 
msgid "This repository does not have a remote repository URL."
 
msgstr ""
 
msgstr "Ce dépôt n'a pas d'URL de dépôt distant."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:11
 
#, fuzzy
 
msgid "Permanent Repository ID"
 
msgstr "Dépôt privé"
 
msgstr "ID permanent du dépôt"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:11
 
msgid "What is that?"
 
msgstr ""
 
msgstr "Qu'est-ce que c'est ?"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:13
 
msgid "URL by id"
 
msgstr ""
 
msgstr "URL par id"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:14
 
msgid ""
 
"In case this repository is renamed or moved into another group the "
 
"repository URL changes.\n"
 
"                               Using the above permanent URL guarantees "
 
"that this repository always will be accessible on that URL.\n"
 
"                               This is useful for CI systems, or any "
 
"other cases that you need to hardcode the URL into a 3rd party service."
 
msgstr ""
 
"Si ce dépôt est renommé ou déplacé dans un autre groupe, l'URL du dépôt "
 
"change.\n"
 
"                               L'utilisation de l'URL permanente ci-dessus "
 
"garantit que ce dépôt sera toujours accessible via cette URL.\n"
 
"                               Cela peut être utile pour les systèmes "
 
"d'intégration continue, ou dans tous les cas où vous devez saisir l'URL « en "
 
"dur » dans un service tiers."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:21
 
#, fuzzy
 
msgid "Remote repository"
 
msgstr "[a créé] le dépôt"
 
msgstr "Dépôt distant"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:25
 
#, fuzzy
 
msgid "Repository URL"
 
msgstr "Dépôt"
 
msgstr "URL du dépôt"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:29
 
msgid ""
 
"Optional: URL of a remote repository. If set, the repository can be "
 
"pulled from this URL."
 
msgstr ""
 
"Optionel : URL d'un dépôt distant. Si renseigné, le dépôt sera pullé à "
 
"partir de cette URL."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:48
 
msgid "Default revision for files page, downloads, whoosh and readme"
 
msgstr ""
 
"Révision par défaut pour les pages de fichiers, de téléchargements, de "
 
"recherche et de documentation"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_settings.html:58
 
msgid "Change owner of this repository."
 
msgstr "Changer le propriétaire de ce dépôt."
 

	
 
#: kallithea/templates/admin/repos/repo_edit_statistics.html:6
 
msgid "Processed commits"
 
msgstr ""
 
msgstr "Commits traités"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_statistics.html:7
 
msgid "Processed progress"
 
msgstr ""
 
msgstr "Avancement"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_statistics.html:10
 
#, fuzzy
 
msgid "Reset Statistics"
 
msgstr "Remettre les statistiques à zéro"
 

	
 
#: kallithea/templates/admin/repos/repo_edit_statistics.html:10
 
#, fuzzy
 
msgid "Confirm to remove current statistics."
 
msgstr "Souhaitez-vous vraiment réinitialiser les statistiques de ce dépôt ?"
 

	
 
#: kallithea/templates/admin/repos/repos.html:5
 
#, fuzzy
 
msgid "Repositories Administration"
 
msgstr "Administration des dépôts"
 

	
 
#: kallithea/templates/admin/repos/repos.html:51
 
msgid "State"
 
msgstr "État"
 

	
 
#: kallithea/templates/admin/settings/settings.html:5
 
#, fuzzy
 
msgid "Settings Administration"
 
msgstr "Administration générale"
 
msgstr "Administration des options"
 

	
 
#: kallithea/templates/admin/settings/settings.html:27
 
msgid "VCS"
 
msgstr "VCS"
 

	
 
#: kallithea/templates/admin/settings/settings.html:28
 
msgid "Remap and Rescan"
 
msgstr ""
 
msgstr "Mapper et scanner"
 

	
 
#: kallithea/templates/admin/settings/settings.html:30
 
msgid "Visual"
 
msgstr "Visuel"
 

	
 
#: kallithea/templates/admin/settings/settings.html:32
 
#: kallithea/templates/admin/settings/settings_vcs.html:19
 
msgid "Hooks"
 
msgstr "Hooks"
 

	
 
#: kallithea/templates/admin/settings/settings.html:33
 
#, fuzzy
 
msgid "Full Text Search"
 
msgstr "Recherche dans le texte complet"
 

	
 
#: kallithea/templates/admin/settings/settings.html:34
 
msgid "System Info"
 
msgstr "Informations sytème"
 

	
 
#: kallithea/templates/admin/settings/settings_email.html:7
 
msgid "Send test email to"
 
msgstr "Envoyer un courriel de test à"
 

	
 
#: kallithea/templates/admin/settings/settings_email.html:15
 
msgid "Send"
 
msgstr "Envoyer"
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:8
 
msgid "Site branding"
 
msgstr ""
 
msgstr "Nom du site"
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:12
 
msgid "Set a custom title for your Kallithea Service."
 
msgstr "Mettez un title personnalisé pour votre service Kallithea."
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:18
 
msgid "HTTP authentication realm"
 
msgstr ""
 
msgstr "Domaine d'authentification HTTP (realm)"
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:27
 
msgid "Analytics HTML block"
 
msgstr ""
 
msgstr "Bloc HTML pour l'analytique"
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:31
 
msgid ""
 
"HTML with JavaScript for web analytics systems like Google Analytics or "
 
"Piwik. This will be added at the bottom of every page."
 
msgstr ""
 
"HTML avec du JavaScript pour les systèmes d'analyse Web comme Google "
 
"Analytics ou Piwik. Ceci sera ajouté en bas de chaque page."
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:37
 
msgid "ReCaptcha public key"
 
msgstr "Clé publique ReCaptcha"
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:41
 
msgid "Public key for reCaptcha system."
 
msgstr "Clé publique pour le système reCaptcha."
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:47
 
msgid "ReCaptcha private key"
 
msgstr "Clé privée ReCaptcha"
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:51
 
#, fuzzy
 
msgid ""
 
"Private key for reCaptcha system. Setting this value will enable captcha "
 
"on registration."
 
msgstr ""
 
"Clé privée pour le système reCaptcha. Définir cette valeur activera le "
 
"captcha d'enregistrement"
 
"captcha à l'enregistrement."
 

	
 
#: kallithea/templates/admin/settings/settings_global.html:56
 
#: kallithea/templates/admin/settings/settings_vcs.html:80
 
#: kallithea/templates/admin/settings/settings_visual.html:116
 
#, fuzzy
 
msgid "Save Settings"
 
msgstr "Enregister les options"
 
msgstr "Enregistrer les options"
 

	
 
#: kallithea/templates/admin/settings/settings_hooks.html:1
 
msgid "Built-in Mercurial Hooks (Read-Only)"
 
msgstr ""
 
msgstr "Hooks Mercurial intégrés (lecture seule)"
 

	
 
#: kallithea/templates/admin/settings/settings_hooks.html:15
 
msgid ""
 
"Hooks can be used to trigger actions on certain events such as push / "
 
"pull. They can trigger Python functions or external applications."
 
msgstr ""
 
"Les hooks peuvent être utilisés pour déclencher des actions lors de certains "
 
"évènements comme le push et le pull. Ils peuvent déclencher des fonctions "
 
"Python ou des applications externes."
 

	
 
#: kallithea/templates/admin/settings/settings_hooks.html:19
 
#, fuzzy
 
msgid "Custom Hooks"
 
msgstr "Hooks personnalisés"
 

	
 
#: kallithea/templates/admin/settings/settings_hooks.html:67
 
msgid "Failed to remove hook"
 
msgstr "Erreur lors de la suppression du hook"
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:6
 
msgid "Rescan option"
 
msgstr ""
 
msgstr "Option de scan"
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:11
 
msgid "Delete records of missing repositories"
 
msgstr ""
 
msgstr "Supprimer les enregistrements de dépôts manquants"
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:13
 
msgid ""
 
"Check this option to remove all comments, pull requests and other records"
 
" related to repositories that no longer exist in the filesystem."
 
msgstr ""
 
"Cocher cette option pour supprimer tous les commentaires, les requêtes de "
 
"pull et d'autres informations liées aux dépôts qui n'existent plus sur le "
 
"système de fichiers."
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:17
 
msgid "Invalidate cache for all repositories"
 
msgstr "Invalider le cache pour tous les dépôts"
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:19
 
#, fuzzy
 
msgid "Check this to reload data and clear cache keys for all repositories."
 
msgstr "Invalider le cache pour tous les dépôts"
 
msgstr ""
 
"Cocher pour recharger les données et vider le cache pour tous les dépôts."
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:23
 
msgid "Install Git hooks"
 
msgstr ""
 
msgstr "Installer des hooks Git"
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:25
 
msgid ""
 
"Verify if Kallithea's Git hooks are installed for each repository. "
 
"Current hooks will be updated to the latest version."
 
msgstr ""
 
"Vérifier si les hooks Git de Kallithea sont installés pour chaque dépôt. Les "
 
"hooks actuels seront mis à jour vers la dernière version."
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:28
 
msgid "Overwrite existing Git hooks"
 
msgstr ""
 
msgstr "Écraser les hooks Git existants"
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:30
 
msgid ""
 
"If installing Git hooks, overwrite any existing hooks, even if they do "
 
"not seem to come from Kallithea. WARNING: This operation will destroy any"
 
" custom git hooks you may have deployed by hand!"
 
msgstr ""
 
"Lors de l'installation des hooks Git, écraser tous les hooks existants, même "
 
"s'ils ne semblent pas provenir de Kallithea. ATTENTION : cette opération "
 
"détruira tous les hooks Git que vous avez déployés à la main !"
 

	
 
#: kallithea/templates/admin/settings/settings_mapping.html:35
 
msgid "Rescan Repositories"
 
msgstr ""
 
msgstr "Relancer le scan des dépôts"
 

	
 
#: kallithea/templates/admin/settings/settings_search.html:7
 
msgid "Index build option"
 
msgstr ""
 
msgstr "Option de construction de l'index"
 

	
 
#: kallithea/templates/admin/settings/settings_search.html:12
 
msgid "Build from scratch"
 
msgstr "Construire ex nihilo"
 

	
 
#: kallithea/templates/admin/settings/settings_search.html:15
 
msgid ""
 
"This option completely reindexeses all of the repositories for proper "
 
"fulltext search capabilities."
 
msgstr ""
 
"Cette option ré-indexe complètement tous les dépôts pour pouvoir faire des "
 
"recherches dans le texte complet."
 

	
 
#: kallithea/templates/admin/settings/settings_search.html:21
 
msgid "Reindex"
 
msgstr "Mettre à jour l’index"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:4
 
msgid "Kallithea version"
 
msgstr "Version de Kallithea"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:4
 
#, fuzzy
 
msgid "Check for updates"
 
msgstr "vérifier les mises à jour"
 
msgstr "Vérifier les mises à jour"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:5
 
msgid "Kallithea configuration file"
 
msgstr ""
 
msgstr "Fichier de configuration de Kallithea"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:6
 
msgid "Python version"
 
msgstr "Version de Python"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:7
 
msgid "Platform"
 
msgstr "Plateforme"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:8
 
#, fuzzy
 
msgid "Git version"
 
msgstr "Version de Git"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:9
 
#, fuzzy
 
msgid "Git path"
 
msgstr "Chemin de Git"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:10
 
msgid "Upgrade info endpoint"
 
msgstr ""
 
msgstr "Point d'accès aux informations de mise à jour"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:10
 
#, fuzzy
 
msgid "Note: please make sure this server can access this URL"
 
msgstr "Note : vérifiez que le serveur peut accéder cette URL"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:15
 
msgid "Checking for updates..."
 
msgstr "Vérification des mises à jour…"
 

	
 
#: kallithea/templates/admin/settings/settings_system.html:23
 
#, fuzzy
 
msgid "Python Packages"
 
msgstr "Paquets Python"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:6
 
msgid "Web"
 
msgstr "Web"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:11
 
msgid "Require SSL for vcs operations"
 
msgstr "Nécessiter SSL pour les opérations de VCS"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:13
 
#, fuzzy
 
msgid ""
 
"Activate to require SSL both pushing and pulling. If SSL certificate is "
 
"missing, it will return an HTTP Error 406: Not Acceptable."
 
msgstr ""
 
"Activez pour faire en sorte que Kallithea force l'utilisation de SSL pour"
 
" pousser ou tirer. Si le certificate SSL est manquant, une erreur HTTP "
 
"406 Not Acceptable sera retournée."
 
"Activez pour faire en sorte que Kallithea force l'utilisation de SSL pour "
 
"pousser ou tirer. Si le certificat SSL est manquant, une erreur « HTTP 406: "
 
"Not Acceptable » sera renvoyée."
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:24
 
msgid "Show repository size after push"
 
msgstr "Afficher la taille du dépôt après un push"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:28
 
msgid "Log user push commands"
 
msgstr "Journaliser les commandes de push"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:32
 
msgid "Log user pull commands"
 
msgstr "Journaliser les commandes de pull"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:36
 
msgid "Update repository after push (hg update)"
 
msgstr "Mettre à jour les dépôts après un push (hg update)"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:42
 
#, fuzzy
 
msgid "Mercurial extensions"
 
msgstr "Extensions Mercurial"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:47
 
msgid "Enable largefiles extension"
 
msgstr ""
 
msgstr "Activer l'extension largefiles"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:51
 
msgid "Enable hgsubversion extension"
 
msgstr "Activer l'extension hgsubversion"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:53
 
#, fuzzy
 
msgid ""
 
"Requires hgsubversion library to be installed. Enables cloning of remote "
 
"Subversion repositories while converting them to Mercurial."
 
msgstr ""
 
"La bibliothèque hgsubversion doit être installée. Elle permet de cloner "
 
"des dépôts SVN distants et de les migrer vers Mercurial."
 
"La bibliothèque hgsubversion doit être installée. Elle permet de cloner des "
 
"dépôts SVN distants et de les migrer vers Mercurial."
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:64
 
#, fuzzy
 
msgid "Location of repositories"
 
msgstr "Dépôts totaux"
 
msgstr "Emplacement des dépôts"
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:69
 
msgid ""
 
"Click to unlock. You must restart Kallithea in order to make this setting"
 
" take effect."
 
msgstr ""
 
"Cliquez pour déverrouiller. Vous devez redémarrer Kallithea pour ce que "
 
"réglage prenne effet."
 

	
 
#: kallithea/templates/admin/settings/settings_vcs.html:72
 
msgid ""
 
"Filesystem location where repositories are stored. After changing this "
 
"value, a restart and rescan of the repository folder are both required."
 
msgstr ""
 
"Emplacement où les dépôts sont stockés sur le système de fichiers. La "
 
"modification de cette valeur nécessite un re-démarrage et un nouveau scan."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:8
 
msgid "General"
 
msgstr ""
 
msgstr "Général"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:13
 
msgid "Use repository extra fields"
 
msgstr ""
 
msgstr "Activer les champs supplémentaires sur les dépôts"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:15
 
msgid "Allows storing additional customized fields per repository."
 
msgstr ""
 
"Permet d'enregistrer des champs personnalisés additionnels pour chaque dépôt."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:18
 
msgid "Show Kallithea version"
 
msgstr ""
 
msgstr "Afficher la version de Kallithea"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:20
 
msgid "Shows or hides a version number of Kallithea displayed in the footer."
 
msgstr ""
 
"Afficher ou cacher le numéro de version de Kallithea dans le pied de page."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:24
 
msgid "Use Gravatars in Kallithea"
 
msgstr ""
 
msgstr "Utiliser Gravatar sur Kallithea"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:30
 
msgid ""
 
"Gravatar URL allows you to use another avatar server application.\n"
 
"                                                        The following "
 
"variables of the URL will be replaced accordingly.\n"
 
"                                                        {scheme}    "
 
"'http' or 'https' sent from running Kallithea server,\n"
 
"                                                        {email}     user "
 
"email,\n"
 
"                                                        {md5email}  md5 "
 
"hash of the user email (like at gravatar.com),\n"
 
"                                                        {size}      size "
 
"of the image that is expected from the server application,\n"
 
"                                                        {netloc}    "
 
"network location/server host of running Kallithea server"
 
msgstr ""
 
"L'URL de Gravatar vous permet d'utiliser un autre serveur d'avatars.\n"
 
"                                                        Les variables "
 
"suivantes dans l'URL seront remplacées comme suit :\n"
 
"                                                        {scheme}    'http' "
 
"ou 'https' envoyé à partir du serveur Kallithea en cours d'utilisation,\n"
 
"                                                        {email}     adresse "
 
"e-mail de l'utilisateur,\n"
 
"                                                        {md5email}  "
 
"empreinte md5 (hash) de l'adresse e-mail de l'utilisateur (comme sur "
 
"gravatar.com),\n"
 
"                                                        {size}      taille "
 
"de l'image demandée au serveur,\n"
 
"                                                        {netloc}    "
 
"emplacement réseau/hôte du serveur Kallithea en cours d'utilisation."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:42
 
msgid ""
 
"Schema of clone URL construction eg. '{scheme}://{user}@{netloc}/{repo}'."
 
"\n"
 
"                                                        The following "
 
"variables are available:\n"
 
"                                                        {scheme} 'http' "
 
"or 'https' sent from running Kallithea server,\n"
 
"                                                        {user}   current "
 
"user username,\n"
 
"                                                        {netloc} network "
 
"location/server host of running Kallithea server,\n"
 
"                                                        {repo}   full "
 
"repository name,\n"
 
"                                                        {repoid} ID of "
 
"repository, can be used to contruct clone-by-id"
 
msgstr ""
 
"Modèle de construction d'URL de clone. Par exemple : "
 
"'{scheme}://{user}@{netloc}/{repo}'.\n"
 
"                                                       Les variables "
 
"suivantes sont disponibles :\n"
 
"                                                        {scheme}    'http' "
 
"ou 'https' envoyé à partir du serveur Kallithea en cours d'utilisation,\n"
 
"                                                        {user}     nom de "
 
"l'utilisateur courant,\n"
 
"                                                        {netloc}    "
 
"emplacement réseau/hôte du serveur Kallithea en cours d'utilisation,\n"
 
"                                                        {repo}    nom "
 
"complet du dépôt,\n"
 
"                                                        {repoid}    ID du "
 
"dépôt, peut être utilisé pour cloner par ID."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:55
 
msgid "Dashboard items"
 
msgstr ""
 
msgstr "Élements du tableau de bord"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:59
 
msgid ""
 
"Number of items displayed in the main page dashboard before pagination is"
 
" shown."
 
msgstr ""
 
"Nombre d'éléments affichés dans la page principale du tableau de bord avant "
 
"d'afficher la pagination."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:65
 
msgid "Admin pages items"
 
msgstr ""
 
msgstr "Élements des pages admin"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:69
 
msgid ""
 
"Number of items displayed in the admin pages grids before pagination is "
 
"shown."
 
msgstr ""
 
"Nombre d'éléments affichés dans les grilles des pages admin avant d'afficher "
 
"la pagination."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:75
 
msgid "Icons"
 
msgstr "Icônes"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:80
 
msgid "Show public repository icon on repositories"
 
msgstr "Afficher l’icône de dépôt public sur les dépôts"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:84
 
msgid "Show private repository icon on repositories"
 
msgstr "Afficher l’icône de dépôt privé sur les dépôts"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:86
 
#, fuzzy
 
msgid "Show public/private icons next to repository names."
 
msgstr "Afficher l’icône de dépôt public sur les dépôts"
 
msgstr "Afficher l’icône « public/privé » à côté du nom des dépôts."
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:92
 
#, fuzzy
 
msgid "Meta Tagging"
 
msgstr "Meta-tagging"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:97
 
msgid "Stylify recognised meta tags:"
 
msgstr ""
 
msgstr "Styliser les méta-tags reconnus :"
 

	
 
#: kallithea/templates/admin/settings/settings_visual.html:111
 
msgid ""
 
"Parses meta tags from the repository description field and turns them "
 
"into colored tags."
 
msgstr ""
 
"Analyser les méta-tags dans le champ de description du dépôt et les "
 
"transformer en tags colorés."
 

	
 
#: kallithea/templates/admin/user_groups/user_group_add.html:5
 
msgid "Add user group"
 
msgstr ""
 
msgstr "Ajouter un groupe d'utilisateurs"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_add.html:10
 
#: kallithea/templates/admin/user_groups/user_group_edit.html:11
 
#: kallithea/templates/admin/user_groups/user_groups.html:10
 
#: kallithea/templates/base/base.html:63 kallithea/templates/base/base.html:83
 
msgid "User Groups"
 
msgstr ""
 
msgstr "Groupes d'utilisateurs"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_add.html:12
 
#: kallithea/templates/admin/user_groups/user_groups.html:25
 
msgid "Add User Group"
 
msgstr ""
 
msgstr "Ajouter un groupe d'utilisateurs"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_add.html:44
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:19
 
msgid "Short, optional description for this user group."
 
msgstr ""
 
msgstr "Description courte pour ce groupe d'utilisateur (optionnel)."
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit.html:5
 
#, python-format
 
msgid "%s user group settings"
 
msgstr ""
 
msgstr "Réglages du groupe d'utilisateurs %s"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit.html:33
 
#, fuzzy
 
msgid "Show Members"
 
msgstr "Membres"
 
msgstr "Afficher les membres"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit_advanced.html:1
 
#, python-format
 
msgid "User Group: %s"
 
msgstr ""
 
msgstr "Groupe d'utilisateurs : %s"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit_advanced.html:6
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:32
 
#: kallithea/templates/admin/user_groups/user_groups.html:48
 
msgid "Members"
 
msgstr "Membres"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit_advanced.html:19
 
#: kallithea/templates/data_table/_dt_elements.html:174
 
#, python-format
 
msgid "Confirm to delete this user group: %s"
 
msgstr ""
 
msgstr "Voulez-vous vraiment supprimer ce groupe utilisateur : %s ?"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit_advanced.html:21
 
msgid "Delete this user group"
 
msgstr ""
 
msgstr "Supprimer ce groupe d'utilisateurs"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit_members.html:17
 
msgid "No members yet"
 
msgstr ""
 
msgstr "Aucun membre pour l'instant"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:40
 
msgid "Chosen group members"
 
msgstr ""
 
msgstr "Membres de groupe sélectionnés"
 

	
 
#: kallithea/templates/admin/user_groups/user_group_edit_settings.html:49
 
msgid "Available members"
 
msgstr "Membres disponibles"
 

	
 
#: kallithea/templates/admin/user_groups/user_groups.html:5
 
#, fuzzy
 
msgid "User Groups Administration"
 
msgstr "Administration des groupes de dépôts"
 
msgstr "Administration des groupes d'utilisateurs"
 

	
 
#: kallithea/templates/admin/users/user_add.html:5
 
msgid "Add user"
 
msgstr "Ajouter un utilisateur"
 

	
 
#: kallithea/templates/admin/users/user_add.html:10
 
#: kallithea/templates/admin/users/user_edit.html:11
 
#: kallithea/templates/admin/users/users.html:10
 
#: kallithea/templates/base/base.html:62
 
msgid "Users"
 
msgstr "Utilisateurs"
 

	
 
#: kallithea/templates/admin/users/user_add.html:12
 
#: kallithea/templates/admin/users/users.html:24
 
msgid "Add User"
 
msgstr ""
 
msgstr "Ajouter un utilisateur"
 

	
 
#: kallithea/templates/admin/users/user_add.html:50
 
msgid "Password confirmation"
 
msgstr "Confirmation"
 

	
 
#: kallithea/templates/admin/users/user_edit.html:5
 
#, python-format
 
msgid "%s user settings"
 
msgstr ""
 
msgstr "Réglages de l'utilisateur %s"
 

	
 
#: kallithea/templates/admin/users/user_edit.html:30
 
msgid "Emails"
 
msgstr ""
 
msgstr "E-mails"
 

	
 
#: kallithea/templates/admin/users/user_edit_advanced.html:1
 
#, python-format
 
msgid "User: %s"
 
msgstr ""
 
msgstr "Utilisateur : %s"
 

	
 
#: kallithea/templates/admin/users/user_edit_advanced.html:7
 
#: kallithea/templates/admin/users/user_edit_profile.html:42
 
msgid "Source of Record"
 
msgstr ""
 
msgstr "Source de l'enregistrement"
 

	
 
#: kallithea/templates/admin/users/user_edit_advanced.html:9
 
#: kallithea/templates/admin/users/users.html:53
 
msgid "Last Login"
 
msgstr ""
 
msgstr "Dernière connexion"
 

	
 
#: kallithea/templates/admin/users/user_edit_advanced.html:10
 
msgid "Member of User Groups"
 
msgstr ""
 
msgstr "Membre des groupes d'utilisateurs"
 

	
 
#: kallithea/templates/admin/users/user_edit_advanced.html:21
 
#: kallithea/templates/data_table/_dt_elements.html:158
 
#, python-format
 
msgid "Confirm to delete this user: %s"
 
msgstr "Voulez-vous vraiment supprimer l’utilisateur « %s » ?"
 

	
 
#: kallithea/templates/admin/users/user_edit_advanced.html:23
 
msgid "Delete this user"
 
msgstr ""
 
msgstr "Supprimer cet utilisateur"
 

	
 
#: kallithea/templates/admin/users/user_edit_ips.html:8
 
#, python-format
 
msgid "Inherited from %s"
 
msgstr ""
 
msgstr "Hérité de %s"
 

	
 
#: kallithea/templates/admin/users/user_edit_profile.html:8
 
msgid "Change avatar at"
 
msgstr ""
 
msgstr "Changer l'avatar sur"
 

	
 
#: kallithea/templates/admin/users/user_edit_profile.html:12
 
msgid "Missing email, please update this user email address."
 
msgstr ""
 
"E-mail manquant, veuillez mettre à jour l'adresse e-mail de cet utilisateur."
 

	
 
#: kallithea/templates/admin/users/user_edit_profile.html:51
 
msgid "Name in Source of Record"
 
msgstr ""
 
msgstr "Nom dans la source de l'enregistrement"
 

	
 
#: kallithea/templates/admin/users/user_edit_profile.html:69
 
msgid "New password confirmation"
 
msgstr "Confirmation du nouveau mot de passe"
 

	
 
#: kallithea/templates/admin/users/users.html:5
 
#, fuzzy
 
msgid "Users Administration"
 
msgstr "Administration des utilisateurs"
 

	
 
#: kallithea/templates/admin/users/users.html:56
 
msgid "Auth Type"
 
msgstr ""
 
msgstr "Type d'authentification"
 

	
 
#: kallithea/templates/base/base.html:18
 
#, python-format
 
msgid "Server instance: %s"
 
msgstr ""
 
msgstr "Instance de serveur : %s"
 

	
 
#: kallithea/templates/base/base.html:30
 
msgid "Support"
 
msgstr ""
 
msgstr "Support"
 

	
 
#: kallithea/templates/base/base.html:90
 
msgid "Mercurial repository"
 
msgstr "Dépôt Mercurial"
 

	
 
#: kallithea/templates/base/base.html:93
 
msgid "Git repository"
 
msgstr "Dépôt Git"
 

	
 
#: kallithea/templates/base/base.html:119
 
#, fuzzy
 
msgid "Create Fork"
 
msgstr "créé"
 
msgstr "Créer un fork"
 

	
 
#: kallithea/templates/base/base.html:130
 
#: kallithea/templates/data_table/_dt_elements.html:13
 
#: kallithea/templates/data_table/_dt_elements.html:17
 
#: kallithea/templates/summary/summary.html:8
 
msgid "Summary"
 
msgstr "Résumé"
 

	
 
#: kallithea/templates/base/base.html:132
 
#: kallithea/templates/base/base.html:134
 
#: kallithea/templates/changelog/changelog.html:14
 
#: kallithea/templates/data_table/_dt_elements.html:21
 
#: kallithea/templates/data_table/_dt_elements.html:25
 
msgid "Changelog"
 
msgstr "Historique"
 

	
 
#: kallithea/templates/base/base.html:136
 
#: kallithea/templates/data_table/_dt_elements.html:29
 
#: kallithea/templates/data_table/_dt_elements.html:33
 
#: kallithea/templates/files/files.html:11
 
msgid "Files"
 
msgstr "Fichiers"
 

	
 
#: kallithea/templates/base/base.html:138
 
msgid "Switch To"
 
msgstr ""
 
msgstr "Basculer vers"
 

	
 
#: kallithea/templates/base/base.html:145
 
#: kallithea/templates/base/base.html:147
 
msgid "Options"
 
msgstr "Options"
 

	
 
#: kallithea/templates/base/base.html:155
 
#: kallithea/templates/forks/forks_data.html:21
 
#, fuzzy
 
msgid "Compare Fork"
 
msgstr "Comparer le fork"
 

	
 
#: kallithea/templates/base/base.html:157
 
#: kallithea/templates/bookmarks/bookmarks.html:56
 
#: kallithea/templates/bookmarks/bookmarks_data.html:13
 
#: kallithea/templates/branches/branches.html:56
 
#: kallithea/templates/branches/branches_data.html:13
 
#: kallithea/templates/tags/tags.html:56
 
#: kallithea/templates/tags/tags_data.html:13
 
msgid "Compare"
 
msgstr "Comparer"
 

	
 
#: kallithea/templates/base/base.html:159
 
#: kallithea/templates/base/base.html:247
 
#: kallithea/templates/search/search.html:14
 
#: kallithea/templates/search/search.html:54
 
msgid "Search"
 
msgstr "Rechercher"
 

	
 
#: kallithea/templates/base/base.html:163
 
msgid "Unlock"
 
msgstr ""
 
msgstr "Déverrouiller"
 

	
 
#: kallithea/templates/base/base.html:165
 
msgid "Lock"
 
msgstr ""
 
msgstr "Verrouiller"
 

	
 
#: kallithea/templates/base/base.html:173
 
msgid "Follow"
 
msgstr ""
 
msgstr "Suivre"
 

	
 
#: kallithea/templates/base/base.html:174
 
msgid "Unfollow"
 
msgstr ""
 
msgstr "Arrêter de suivre"
 

	
 
#: kallithea/templates/base/base.html:177
 
#: kallithea/templates/data_table/_dt_elements.html:37
 
#: kallithea/templates/data_table/_dt_elements.html:41
 
#: kallithea/templates/forks/fork.html:9
 
msgid "Fork"
 
msgstr "Fork"
 

	
 
#: kallithea/templates/base/base.html:178
 
#: kallithea/templates/pullrequests/pullrequest.html:88
 
msgid "Create Pull Request"
 
msgstr ""
 
msgstr "Créer une requête de pull"
 

	
 
#: kallithea/templates/base/base.html:183
 
#, python-format
 
msgid "Show Pull Requests for %s"
 
msgstr ""
 
msgstr "Afficher les requêtes de pull pour %s"
 

	
 
#: kallithea/templates/base/base.html:221
 
msgid "Show recent activity"
 
msgstr ""
 
msgstr "Afficher l'activité récente"
 

	
 
#: kallithea/templates/base/base.html:227
 
#: kallithea/templates/base/base.html:228
 
msgid "Public journal"
 
msgstr "Journal public"
 

	
 
#: kallithea/templates/base/base.html:233
 
msgid "Show public gists"
 
msgstr ""
 
msgstr "Afficher les gists publics"
 

	
 
#: kallithea/templates/base/base.html:234
 
msgid "Gists"
 
msgstr ""
 
msgstr "Gists"
 

	
 
#: kallithea/templates/base/base.html:238
 
#, fuzzy
 
msgid "All Public Gists"
 
msgstr "Gists publics"
 
msgstr "Tous les Gists publics"
 

	
 
#: kallithea/templates/base/base.html:240
 
#, fuzzy
 
msgid "My Public Gists"
 
msgstr "Gists publics"
 
msgstr "Mes Gists publics"
 

	
 
#: kallithea/templates/base/base.html:241
 
#, fuzzy
 
msgid "My Private Gists"
 
msgstr "Gist privé"
 
msgstr "Mes Gist privés"
 

	
 
#: kallithea/templates/base/base.html:246
 
msgid "Search in repositories"
 
msgstr ""
 
msgstr "Recherche dans les dépôts"
 

	
 
#: kallithea/templates/base/base.html:269
 
#: kallithea/templates/base/base.html:270
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:6
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:10
 
#, fuzzy
 
msgid "My Pull Requests"
 
msgstr "Requêtes de pull"
 
msgstr "Mes requêtes de pull"
 

	
 
#: kallithea/templates/base/base.html:289
 
msgid "Not Logged In"
 
msgstr ""
 
msgstr "Non connecté"
 

	
 
#: kallithea/templates/base/base.html:296
 
#, fuzzy
 
msgid "Login to Your Account"
 
msgstr "Connexion à votre compte"
 

	
 
#: kallithea/templates/base/base.html:319
 
msgid "Forgot password ?"
 
msgstr "Mot de passe oublié ?"
 

	
 
#: kallithea/templates/base/base.html:346
 
msgid "Log Out"
 
msgstr "Se déconnecter"
 

	
 
#: kallithea/templates/base/base.html:395
 
msgid "No matches found"
 
msgstr ""
 
msgstr "Aucune correspondance trouvée"
 

	
 
#: kallithea/templates/base/base.html:524
 
msgid "Keyboard shortcuts"
 
msgstr ""
 
msgstr "Raccourcis clavier"
 

	
 
#: kallithea/templates/base/base.html:533
 
msgid "Site-wide shortcuts"
 
msgstr ""
 
msgstr "Raccourcis globaux"
 

	
 
#: kallithea/templates/base/default_perms_box.html:14
 
#, fuzzy
 
msgid "Inherit defaults"
 
msgstr "Réglages par défaut du dépôt"
 
msgstr "Hériter des réglages par défaut"
 

	
 
#: kallithea/templates/base/default_perms_box.html:19
 
#, python-format
 
msgid ""
 
"Select to inherit global settings, IP whitelist and permissions from the "
 
"%s."
 
msgstr ""
 
"Sélectionner pour hériter des réglages généraux, de la liste blanche d'IP et "
 
"des permissions depuis les %s."
 

	
 
#: kallithea/templates/base/default_perms_box.html:28
 
msgid "Create repositories"
 
msgstr "Création de dépôts"
 

	
 
#: kallithea/templates/base/default_perms_box.html:33
 
msgid "Select this option to allow repository creation for this user"
 
msgstr ""
 
"Sélectionner cette option pour autoriser cet utilisateur à créer des dépôts"
 

	
 
#: kallithea/templates/base/default_perms_box.html:40
 
msgid "Create user groups"
 
msgstr ""
 
msgstr "Créer des groupes d'utilisateurs"
 

	
 
#: kallithea/templates/base/default_perms_box.html:45
 
msgid "Select this option to allow user group creation for this user"
 
msgstr ""
 
"Sélectionner cette option pour autoriser cet utilisateur à créer des groupes "
 
"d'utilisateurs"
 

	
 
#: kallithea/templates/base/default_perms_box.html:52
 
msgid "Fork repositories"
 
msgstr "Forker les dépôts"
 

	
 
#: kallithea/templates/base/default_perms_box.html:57
 
msgid "Select this option to allow repository forking for this user"
 
msgstr ""
 
"Sélectionner cette option pour autoriser cet utilisateur à forker des dépôts"
 

	
 
#: kallithea/templates/base/perms_summary.html:13
 
#: kallithea/templates/changelog/changelog.html:42
 
msgid "Show"
 
msgstr "Afficher"
 

	
 
#: kallithea/templates/base/perms_summary.html:22
 
msgid "No permissions defined yet"
 
msgstr ""
 
msgstr "Aucune permission définie pour l'instant"
 

	
 
#: kallithea/templates/base/perms_summary.html:30
 
#: kallithea/templates/base/perms_summary.html:54
 
msgid "Permission"
 
msgstr "Permission"
 

	
 
#: kallithea/templates/base/perms_summary.html:32
 
#: kallithea/templates/base/perms_summary.html:56
 
msgid "Edit Permission"
 
msgstr "Éditer"
 

	
 
#: kallithea/templates/base/perms_summary.html:90
 
msgid "No permission defined"
 
msgstr ""
 
msgstr "Aucune permission définie"
 

	
 
#: kallithea/templates/base/root.html:22
 
#, fuzzy
 
msgid "Add Another Comment"
 
msgstr "%d commentaire"
 
msgstr "Ajouter un autre commentaire"
 

	
 
#: kallithea/templates/base/root.html:23
 
#: kallithea/templates/data_table/_dt_elements.html:214
 
msgid "Stop following this repository"
 
msgstr "Arrêter de suivre ce dépôt"
 

	
 
#: kallithea/templates/base/root.html:24
 
msgid "Start following this repository"
 
msgstr "Suivre ce dépôt"
 

	
 
#: kallithea/templates/base/root.html:25
 
msgid "Group"
 
msgstr "Groupe"
 

	
 
#: kallithea/templates/base/root.html:26
 
msgid "members"
 
msgstr "Membres"
 

	
 
#: kallithea/templates/base/root.html:27
 
msgid "Loading ..."
 
msgstr ""
 
msgstr "Chargement..."
 

	
 
#: kallithea/templates/base/root.html:28
 
msgid "loading ..."
 
msgstr ""
 
msgstr "chargement..."
 

	
 
#: kallithea/templates/base/root.html:29
 
msgid "Search truncated"
 
msgstr ""
 
msgstr "Recherche tronquée"
 

	
 
#: kallithea/templates/base/root.html:30
 
msgid "No matching files"
 
msgstr ""
 
msgstr "Aucun fichier correspondant"
 

	
 
#: kallithea/templates/base/root.html:31
 
#, fuzzy
 
#| msgid "on pull request"
 
msgid "Open New Pull Request from {0}"
 
msgstr "[a commenté] la requête de pull pour"
 
msgstr "Ouvrir une nouvelle requête de pull à partir de {0}"
 

	
 
#: kallithea/templates/base/root.html:32
 
msgid "Open New Pull Request for {0} &rarr; {1}"
 
msgstr ""
 
msgstr "Ouvrir une nouvelle requête de pull pour {0} &rarr; {1}"
 

	
 
#: kallithea/templates/base/root.html:33
 
#, fuzzy
 
#| msgid "Show Selected Changeset __S"
 
msgid "Show Selected Changesets {0} &rarr; {1}"
 
msgstr "Sélectionner le changeset"
 
msgstr "Afficher les changesets sélectionnés {0} &rarr; {1}"
 

	
 
#: kallithea/templates/base/root.html:34
 
#, fuzzy
 
msgid "Selection Link"
 
msgstr "Lien vers la sélection"
 

	
 
#: kallithea/templates/base/root.html:35
 
#: kallithea/templates/changeset/diff_block.html:8
 
msgid "Collapse Diff"
 
msgstr "Replier le Diff"
 

	
 
#: kallithea/templates/base/root.html:36
 
msgid "Expand Diff"
 
msgstr "Déplier le Diff"
 

	
 
#: kallithea/templates/base/root.html:37
 
msgid "Failed to revoke permission"
 
msgstr ""
 
msgstr "Échec de la révocation de permission"
 

	
 
#: kallithea/templates/base/root.html:38
 
#, fuzzy
 
msgid "Confirm to revoke permission for {0}: {1} ?"
 
msgstr "Impossible de révoquer votre permission d'administrateur"
 
msgstr "Voulez-vous vraiment révoquer la permission pour {0} : {1} ?"
 

	
 
#: kallithea/templates/base/root.html:39
 
msgid "enabled"
 
msgstr "activé"
 

	
 
#: kallithea/templates/base/root.html:40
 
msgid "disabled"
 
msgstr "désactivé"
 

	
 
#: kallithea/templates/base/root.html:42
 
#, fuzzy
 
msgid "Specify changeset"
 
msgstr "Sélectionner le changeset"
 

	
 
#: kallithea/templates/bookmarks/bookmarks.html:5
 
#, python-format
 
msgid "%s Bookmarks"
 
msgstr "Signets de %s"
 

	
 
#: kallithea/templates/bookmarks/bookmarks.html:26
 
msgid "Compare Bookmarks"
 
msgstr ""
 
msgstr "Comparer les marque-pages"
 

	
 
#: kallithea/templates/bookmarks/bookmarks.html:53
 
#: kallithea/templates/bookmarks/bookmarks_data.html:10
 
#: kallithea/templates/branches/branches.html:53
 
#: kallithea/templates/branches/branches_data.html:10
 
#: kallithea/templates/changelog/changelog_summary_data.html:10
 
#: kallithea/templates/tags/tags.html:53
 
#: kallithea/templates/tags/tags_data.html:10
 
msgid "Author"
 
msgstr "Auteur"
 

	
 
#: kallithea/templates/bookmarks/bookmarks.html:54
 
#: kallithea/templates/bookmarks/bookmarks_data.html:12
 
#: kallithea/templates/branches/branches.html:54
 
#: kallithea/templates/branches/branches_data.html:12
 
#: kallithea/templates/changelog/changelog_summary_data.html:7
 
#: kallithea/templates/files/files_browser.html:32
 
#: kallithea/templates/pullrequests/pullrequest.html:62
 
#: kallithea/templates/pullrequests/pullrequest.html:78
 
#: kallithea/templates/tags/tags.html:54
 
#: kallithea/templates/tags/tags_data.html:12
 
msgid "Revision"
 
msgstr "Révision"
 

	
 
#: kallithea/templates/branches/branches.html:5
 
#, python-format
 
msgid "%s Branches"
 
msgstr "Branches de %s"
 

	
 
#: kallithea/templates/branches/branches.html:26
 
msgid "Compare Branches"
 
msgstr ""
 
msgstr "Comparer les branches"
 

	
 
#: kallithea/templates/changelog/changelog.html:6
 
#, python-format
 
msgid "%s Changelog"
 
msgstr "Historique de %s"
 

	
 
#: kallithea/templates/changelog/changelog.html:21
 
#, python-format
 
msgid "showing %d out of %d revision"
 
msgid_plural "showing %d out of %d revisions"
 
msgstr[0] "Affichage de %d révision sur %d"
 
msgstr[1] "Affichage de %d révisions sur %d"
 

	
 
#: kallithea/templates/changelog/changelog.html:49
 
msgid "Clear selection"
 
msgstr ""
 
msgstr "Vider la sélection"
 

	
 
#: kallithea/templates/changelog/changelog.html:55
 
#, fuzzy
 
msgid "Go to tip of repository"
 
msgstr "Veuillez confirmer le verrouillage de ce dépôt"
 
msgstr "Aller au sommet (tip) du dépôt"
 

	
 
#: kallithea/templates/changelog/changelog.html:60
 
#: kallithea/templates/forks/forks_data.html:19
 
#, python-format
 
msgid "Compare fork with %s"
 
msgstr ""
 
msgstr "Comparer le fork avec %s"
 

	
 
#: kallithea/templates/changelog/changelog.html:62
 
#, python-format
 
msgid "Compare fork with parent repository (%s)"
 
msgstr ""
 
msgstr "Comparer le fork avec le dépôt parent (%s)"
 

	
 
#: kallithea/templates/changelog/changelog.html:66
 
#: kallithea/templates/files/files.html:29
 
#, fuzzy
 
msgid "Branch filter:"
 
msgstr "filtre"
 
msgstr "Filtre de branche :"
 

	
 
#: kallithea/templates/changelog/changelog.html:92
 
#: kallithea/templates/changelog/changelog_summary_data.html:20
 
#, python-format
 
msgid ""
 
"Changeset status: %s\n"
 
"Click to open associated pull request %s"
 
msgstr ""
 
"Statut du changeset : %s\n"
 
"Cliquer pour ouvrir la requête de pull %s associée"
 

	
 
#: kallithea/templates/changelog/changelog.html:96
 
#: kallithea/templates/compare/compare_cs.html:24
 
#, python-format
 
msgid "Changeset status: %s"
 
msgstr ""
 
msgstr "Statut de changeset : %s"
 

	
 
#: kallithea/templates/changelog/changelog.html:115
 
#: kallithea/templates/compare/compare_cs.html:63
 
msgid "Expand commit message"
 
msgstr ""
 
msgstr "Développer le message de commit"
 

	
 
#: kallithea/templates/changelog/changelog.html:124
 
#: kallithea/templates/compare/compare_cs.html:30
 
msgid "Changeset has comments"
 
msgstr ""
 
msgstr "Le changeset a des commentaires"
 

	
 
#: kallithea/templates/changelog/changelog.html:134
 
#: kallithea/templates/changelog/changelog_summary_data.html:54
 
#: kallithea/templates/changeset/changeset.html:94
 
#: kallithea/templates/changeset/changeset_range.html:92
 
#, python-format
 
msgid "Bookmark %s"
 
msgstr ""
 
msgstr "Marque-page %s"
 

	
 
#: kallithea/templates/changelog/changelog.html:140
 
#: kallithea/templates/changelog/changelog_summary_data.html:60
 
#: kallithea/templates/changeset/changeset.html:101
 
#: kallithea/templates/changeset/changeset_range.html:98
 
#, python-format
 
msgid "Tag %s"
 
msgstr ""
 
msgstr "Tag %s"
 

	
 
#: kallithea/templates/changelog/changelog.html:145
 
#: kallithea/templates/changelog/changelog_summary_data.html:65
 
#: kallithea/templates/changeset/changeset.html:106
 
#: kallithea/templates/changeset/changeset_range.html:102
 
#, python-format
 
msgid "Branch %s"
 
msgstr ""
 
msgstr "Branche %s"
 

	
 
#: kallithea/templates/changelog/changelog.html:310
 
msgid "There are no changes yet"
 
msgstr "Il n’y a aucun changement pour le moment"
 

	
 
#: kallithea/templates/changelog/changelog_details.html:4
 
#: kallithea/templates/changeset/changeset.html:77
 
msgid "Removed"
 
msgstr ""
 
msgstr "Supprimé"
 

	
 
#: kallithea/templates/changelog/changelog_details.html:5
 
#: kallithea/templates/changeset/changeset.html:78
 
msgid "Changed"
 
msgstr ""
 
msgstr "Modifié"
 

	
 
#: kallithea/templates/changelog/changelog_details.html:6
 
#: kallithea/templates/changeset/changeset.html:79
 
#: kallithea/templates/changeset/diff_block.html:79
 
msgid "Added"
 
msgstr ""
 
msgstr "Ajouté"
 

	
 
#: kallithea/templates/changelog/changelog_details.html:8
 
#: kallithea/templates/changelog/changelog_details.html:9
 
#: kallithea/templates/changelog/changelog_details.html:10
 
#: kallithea/templates/changeset/changeset.html:81
 
#: kallithea/templates/changeset/changeset.html:82
 
#: kallithea/templates/changeset/changeset.html:83
 
#, python-format
 
msgid "Affected %s files"
 
msgstr ""
 
msgstr "%s fichiers affectés"
 

	
 
#: kallithea/templates/changelog/changelog_summary_data.html:8
 
#: kallithea/templates/files/files_add.html:60
 
#: kallithea/templates/files/files_delete.html:39
 
#: kallithea/templates/files/files_edit.html:63
 
msgid "Commit Message"
 
msgstr ""
 
msgstr "Message de commit"
 

	
 
#: kallithea/templates/changelog/changelog_summary_data.html:9
 
#: kallithea/templates/pullrequests/pullrequest_data.html:17
 
msgid "Age"
 
msgstr ""
 
msgstr "Âge"
 

	
 
#: kallithea/templates/changelog/changelog_summary_data.html:11
 
msgid "Refs"
 
msgstr ""
 
msgstr "Refs"
 

	
 
#: kallithea/templates/changelog/changelog_summary_data.html:81
 
msgid "Add or upload files directly via Kallithea"
 
msgstr "Ajouter ou téléverser des fichiers directement via Kallithea"
 

	
 
#: kallithea/templates/changelog/changelog_summary_data.html:84
 
#: kallithea/templates/files/files_add.html:21
 
#: kallithea/templates/files/files_ypjax.html:9
 
msgid "Add New File"
 
msgstr ""
 
msgstr "Ajouter un nouveau fichier"
 

	
 
#: kallithea/templates/changelog/changelog_summary_data.html:90
 
#, fuzzy
 
msgid "Push new repository"
 
msgstr "Pusher le nouveau dépôt"
 

	
 
#: kallithea/templates/changelog/changelog_summary_data.html:98
 
msgid "Existing repository?"
 
msgstr "Le dépôt existe déjà ?"
 

	
 
#: kallithea/templates/changeset/changeset.html:8
 
#, python-format
 
msgid "%s Changeset"
 
msgstr "Changeset de %s"
 

	
 
#: kallithea/templates/changeset/changeset.html:36
 
msgid "Parent rev."
 
msgstr ""
 
msgstr "Révision parente"
 

	
 
#: kallithea/templates/changeset/changeset.html:42
 
msgid "Child rev."
 
msgstr ""
 
msgstr "Révision fille"
 

	
 
#: kallithea/templates/changeset/changeset.html:50
 
#: kallithea/templates/changeset/changeset_file_comment.html:37
 
#: kallithea/templates/changeset/changeset_range.html:48
 
msgid "Changeset status"
 
msgstr "Statut du changeset"
 

	
 
#: kallithea/templates/changeset/changeset.html:54
 
#: kallithea/templates/changeset/diff_block.html:27
 
#: kallithea/templates/files/diff_2way.html:49
 
msgid "Raw diff"
 
msgstr ""
 
msgstr "Diff brut"
 

	
 
#: kallithea/templates/changeset/changeset.html:57
 
msgid "Patch diff"
 
msgstr ""
 
msgstr "Diff patch"
 

	
 
#: kallithea/templates/changeset/changeset.html:60
 
#: kallithea/templates/changeset/diff_block.html:30
 
#: kallithea/templates/files/diff_2way.html:52
 
msgid "Download diff"
 
msgstr ""
 
msgstr "Télécharger le diff"
 

	
 
#: kallithea/templates/changeset/changeset.html:89
 
#: kallithea/templates/changeset/changeset_range.html:88
 
#, fuzzy
 
msgid "Merge"
 
msgstr "Fusion"
 

	
 
#: kallithea/templates/changeset/changeset.html:123
 
#, fuzzy
 
msgid "Grafted from:"
 
msgstr "Créé le"
 
msgstr "Grafté depuis :"
 

	
 
#: kallithea/templates/changeset/changeset.html:129
 
msgid "Transplanted from:"
 
msgstr ""
 
msgstr "Transplanté depuis :"
 

	
 
#: kallithea/templates/changeset/changeset.html:135
 
#, fuzzy
 
msgid "Replaced by:"
 
msgstr "créé"
 
msgstr "Remplacé par :"
 

	
 
#: kallithea/templates/changeset/changeset.html:149
 
#, fuzzy
 
msgid "Preceded by:"
 
msgstr "créé"
 
msgstr "Précédé par :"
 

	
 
#: kallithea/templates/changeset/changeset.html:166
 
#: kallithea/templates/compare/compare_diff.html:54
 
#: kallithea/templates/pullrequests/pullrequest_show.html:318
 
#, python-format
 
msgid "%s file changed"
 
msgid_plural "%s files changed"
 
msgstr[0] ""
 
msgstr[1] ""
 
msgstr[0] "%s fichier changé"
 
msgstr[1] "%s fichiers changés"
 

	
 
#: kallithea/templates/changeset/changeset.html:168
 
#: kallithea/templates/compare/compare_diff.html:56
 
#: kallithea/templates/pullrequests/pullrequest_show.html:320
 
#, python-format
 
msgid "%s file changed with %s insertions and %s deletions"
 
msgid_plural "%s files changed with %s insertions and %s deletions"
 
msgstr[0] ""
 
msgstr[1] ""
 
msgstr[0] "%s fichier changé avec %s insertions et %s suppressions"
 
msgstr[1] "%s fichiers changés avec %s insertions et %s suppressions"
 

	
 
#: kallithea/templates/changeset/changeset.html:182
 
#: kallithea/templates/changeset/changeset.html:195
 
#: kallithea/templates/pullrequests/pullrequest_show.html:339
 
#: kallithea/templates/pullrequests/pullrequest_show.html:363
 
msgid "Show full diff anyway"
 
msgstr ""
 
msgstr "Afficher le diff complet quand même"
 

	
 
#: kallithea/templates/changeset/changeset.html:247
 
#: kallithea/templates/changeset/changeset.html:284
 
#, fuzzy
 
msgid "No revisions"
 
msgstr "révisions"
 
msgstr "Aucune révision"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:21
 
#, fuzzy
 
msgid "on pull request"
 
msgstr "[a commenté] la requête de pull pour"
 
msgstr "sur la requête de pull"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:22
 
#, fuzzy
 
msgid "No title"
 
msgstr "nouveau fichier"
 
msgstr "Aucun titre"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:24
 
#, fuzzy
 
msgid "on this changeset"
 
msgstr "Aucun changeset"
 
msgstr "sur ce changeset"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:30
 
#, fuzzy
 
msgid "Delete comment?"
 
msgstr "%d commentaire"
 
msgstr "Supprimer le commentaire ?"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:37
 
#, fuzzy
 
msgid "Status change"
 
msgstr "fichiers modifiés"
 
msgstr "Changement de statut"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:59
 
msgid "Commenting on line {1}."
 
msgstr "Commentaire sur la ligne {1}."
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:60
 
#: kallithea/templates/changeset/changeset_file_comment.html:148
 
#, python-format
 
msgid "Comments parsed using %s syntax with %s support."
 
msgstr ""
 
"Les commentaires sont analysés avec la syntaxe %s, avec le support de la "
 
"commande %s."
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:62
 
#, fuzzy
 
msgid "Use @username inside this text to notify another user"
 
msgstr ""
 
"Utilisez @nomutilisateur dans ce texte pour envoyer une notification à "
 
"l’utilisateur Kallithea en question"
 
"Utilisez @nomutilisateur dans ce texte pour envoyer une notification à un "
 
"autre utilisateur"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:72
 
#: kallithea/templates/changeset/changeset_file_comment.html:184
 
msgid "Comment preview"
 
msgstr ""
 
msgstr "Aperçu du commentaire"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:77
 
#, fuzzy
 
msgid "Submitting ..."
 
msgstr "Envoi…"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:80
 
#: kallithea/templates/changeset/changeset_file_comment.html:190
 
msgid "Comment"
 
msgstr "Commentaire"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:82
 
#: kallithea/templates/changeset/changeset_file_comment.html:191
 
msgid "Preview"
 
msgstr ""
 
msgstr "Aperçu"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:90
 
msgid "You need to be logged in to comment."
 
msgstr "Vous devez être connecté pour poster des commentaires."
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:90
 
msgid "Login now"
 
msgstr "Se connecter maintenant"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:94
 
msgid "Hide"
 
msgstr "Masquer"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:106
 
#, python-format
 
msgid "%d comment"
 
msgid_plural "%d comments"
 
msgstr[0] "%d commentaire"
 
msgstr[1] "%d commentaires"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:107
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%d inline"
 
msgid_plural "%d inline"
 
msgstr[0] "(et %d en ligne)"
 
msgstr[1] "(et %d en ligne)"
 
msgstr[0] "%d de ligne"
 
msgstr[1] "%d de ligne"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:108
 
#, python-format
 
msgid "%d general"
 
msgid_plural "%d general"
 
msgstr[0] ""
 
msgstr[1] ""
 
msgstr[0] "%d général"
 
msgstr[1] "%d généraux"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:150
 
#, fuzzy
 
msgid "Use @username inside this text to notify another user."
 
msgstr ""
 
"Utilisez @nomutilisateur dans ce texte pour envoyer une notification à "
 
"l’utilisateur Kallithea en question"
 
"Utilisez @nomutilisateur dans ce texte pour envoyer une notification à un "
 
"autre utilisateur."
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:157
 
msgid "Vote for pull request status"
 
msgstr ""
 
msgstr "Voter pour le statut de la requête de pull"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:159
 
#, fuzzy
 
msgid "Set changeset status"
 
msgstr "Statut du changeset"
 
msgstr "Modifier le statut du changeset"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:163
 
#, fuzzy
 
msgid "No change"
 
msgstr "Aucun changement"
 

	
 
#: kallithea/templates/changeset/changeset_file_comment.html:176
 
#, fuzzy
 
msgid "Close"
 
msgstr "(fermé)"
 
msgstr "Fermer"
 

	
 
#: kallithea/templates/changeset/changeset_range.html:5
 
#, python-format
 
msgid "%s Changesets"
 
msgstr "Changesets de %s"
 

	
 
#: kallithea/templates/changeset/changeset_range.html:56
 
msgid "Files affected"
 
msgstr "Fichiers affectés"
 

	
 
#: kallithea/templates/changeset/diff_block.html:21
 
#: kallithea/templates/files/diff_2way.html:43
 
msgid "Show full diff for this file"
 
msgstr ""
 
msgstr "Afficher le diff complet pour ce fichier"
 

	
 
#: kallithea/templates/changeset/diff_block.html:24
 
#: kallithea/templates/changeset/diff_block.html:98
 
#: kallithea/templates/files/diff_2way.html:46
 
msgid "Show full side-by-side diff for this file"
 
msgstr ""
 
msgstr "Afficher le diff complet côte-à-côte pour ce fichier"
 

	
 
#: kallithea/templates/changeset/diff_block.html:38
 
msgid "Show inline comments"
 
msgstr ""
 
msgstr "Afficher les commentaires de ligne"
 

	
 
#: kallithea/templates/changeset/diff_block.html:86
 
#, fuzzy
 
msgid "Deleted"
 
msgstr "Supprimer"
 
msgstr "Supprimé"
 

	
 
#: kallithea/templates/changeset/diff_block.html:89
 
#, fuzzy
 
msgid "Renamed"
 
msgstr "renommer"
 
msgstr "Renommé"
 

	
 
#: kallithea/templates/compare/compare_cs.html:4
 
msgid "No changesets"
 
msgstr "Aucun changeset"
 

	
 
#: kallithea/templates/compare/compare_cs.html:8
 
msgid "Ancestor"
 
msgstr "Ancêtre"
 

	
 
#: kallithea/templates/compare/compare_cs.html:44
 
msgid "First (oldest) changeset in this list"
 
msgstr ""
 
msgstr "Premier changeset dans cette liste (le plus vieux)"
 

	
 
#: kallithea/templates/compare/compare_cs.html:46
 
msgid "Last (most recent) changeset in this list"
 
msgstr ""
 
msgstr "Dernier changeset dans cette liste (le plus récent)"
 

	
 
#: kallithea/templates/compare/compare_cs.html:48
 
msgid "Position in this list of changesets"
 
msgstr ""
 
msgstr "Position dans cette liste de changesets"
 

	
 
#: kallithea/templates/compare/compare_cs.html:76
 
msgid "Show merge diff"
 
msgstr ""
 
msgstr "Afficher le diff de fusion"
 

	
 
#: kallithea/templates/compare/compare_cs.html:86
 
#: kallithea/templates/pullrequests/pullrequest_show.html:310
 
msgid "Common ancestor"
 
msgstr "Ancêtre commun"
 

	
 
#: kallithea/templates/compare/compare_cs.html:90
 
msgid "No common ancestor found - repositories are unrelated"
 
msgstr "Aucun ancêtre commun trouvé - les dépôts n'ont aucun lien entre eux"
 

	
 
#: kallithea/templates/compare/compare_cs.html:98
 
#, fuzzy
 
msgid "is"
 
msgstr "Gist"
 
msgstr "est"
 

	
 
#: kallithea/templates/compare/compare_cs.html:99
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%s changesets"
 
msgstr "Changesets de %s"
 

	
 
#: kallithea/templates/compare/compare_cs.html:100
 
#, fuzzy
 
msgid "behind"
 
msgstr "Mettre à jour l’index"
 
msgstr "derrière"
 

	
 
#: kallithea/templates/compare/compare_diff.html:6
 
#: kallithea/templates/compare/compare_diff.html:8
 
#, python-format
 
msgid "%s Compare"
 
msgstr ""
 
msgstr "Comparaison de %s"
 

	
 
#: kallithea/templates/compare/compare_diff.html:13
 
#: kallithea/templates/compare/compare_diff.html:35
 
msgid "Compare Revisions"
 
msgstr ""
 
msgstr "Comparer les révisions"
 

	
 
#: kallithea/templates/compare/compare_diff.html:33
 
msgid "Swap"
 
msgstr ""
 
msgstr "Échanger"
 

	
 
#: kallithea/templates/compare/compare_diff.html:42
 
msgid "Compare revisions, branches, bookmarks, or tags."
 
msgstr ""
 
msgstr "Comparer les révisions, les branches, les marque-pages ou les tags."
 

	
 
#: kallithea/templates/compare/compare_diff.html:47
 
#: kallithea/templates/pullrequests/pullrequest_show.html:305
 
#, python-format
 
msgid "Showing %s commit"
 
msgid_plural "Showing %s commits"
 
msgstr[0] ""
 
msgstr[1] ""
 
msgstr[0] "Affichage de %s commit"
 
msgstr[1] "Affichage de %s commits"
 

	
 
#: kallithea/templates/compare/compare_diff.html:78
 
#: kallithea/templates/compare/compare_diff.html:89
 
msgid "Show full diff"
 
msgstr ""
 
msgstr "Afficher le diff complet"
 

	
 
#: kallithea/templates/data_table/_dt_elements.html:74
 
msgid "Public repository"
 
msgstr "Dépôt public"
 

	
 
#: kallithea/templates/data_table/_dt_elements.html:84
 
msgid "Repository creation in progress..."
 
msgstr ""
 
msgstr "Création du dépôt en cours..."
 

	
 
#: kallithea/templates/data_table/_dt_elements.html:98
 
msgid "No changesets yet"
 
msgstr "Dépôt vide"
 

	
 
#: kallithea/templates/data_table/_dt_elements.html:105
 
#: kallithea/templates/data_table/_dt_elements.html:107
 
#, python-format
 
msgid "Subscribe to %s rss feed"
 
msgstr "S’abonner au flux RSS de %s"
 

	
 
#: kallithea/templates/data_table/_dt_elements.html:113
 
#: kallithea/templates/data_table/_dt_elements.html:115
 
#, python-format
 
msgid "Subscribe to %s atom feed"
 
msgstr "S’abonner au flux ATOM de %s"
 

	
 
#: kallithea/templates/data_table/_dt_elements.html:139
 
msgid "Creating"
 
msgstr ""
 
msgstr "En cours de création"
 

	
 
#: kallithea/templates/email_templates/changeset_comment.html:5
 
#, python-format
 
msgid "Comment from %s on %s changeset %s mentioned you"
 
msgstr ""
 
msgstr "Le commentaire de %s sur le changeset de %s (%s) mentionne votre nom"
 

	
 
#: kallithea/templates/email_templates/changeset_comment.html:7
 
#, python-format
 
msgid "Comment from %s on %s changeset %s"
 
msgstr ""
 
msgstr "Commentaire de %s sur le changeset de %s (%s)"
 

	
 
#: kallithea/templates/email_templates/changeset_comment.html:12
 
msgid "The changeset status was changed to"
 
msgstr ""
 
msgstr "Le statut du changeset a été changé en"
 

	
 
#: kallithea/templates/email_templates/main.html:6
 
msgid "This is an automatic notification. Don't reply to this mail."
 
msgstr ""
 
msgstr "Ceci est une notification automatique. Ne pas répondre à cet e-mail."
 

	
 
#: kallithea/templates/email_templates/password_reset.html:4
 
#, python-format
 
msgid "Hello %s"
 
msgstr ""
 
msgstr "Bonjour %s"
 

	
 
#: kallithea/templates/email_templates/password_reset.html:6
 
msgid "We have received a request to reset the password for your account."
 
msgstr ""
 
"Nous avons reçu une demande de réinitialisation du mot de passe de votre "
 
"compte."
 

	
 
#: kallithea/templates/email_templates/password_reset.html:7
 
msgid "To set a new password, click the following link"
 
msgstr ""
 
msgstr "Pour choisir un nouveau mot de passe, cliquez sur le lien suivant"
 

	
 
#: kallithea/templates/email_templates/password_reset.html:10
 
msgid ""
 
"Should you not be able to use the link above, please type the following "
 
"code into the password reset form"
 
msgstr ""
 
"Si vous ne pouvez pas utiliser le lien ci-dessus, merci de saisir le code "
 
"suivant dans le formulaire de réinitialisation de mot de passe"
 

	
 
#: kallithea/templates/email_templates/password_reset.html:12
 
msgid ""
 
"If it weren't you who requested the password reset, just disregard this "
 
"message."
 
msgstr ""
 
"Si vous n'avez pas demandé la réinitialisation de votre mot de passe, ne "
 
"tenez pas compte de ce message."
 

	
 
#: kallithea/templates/email_templates/pull_request.html:5
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%s mentioned you on %s pull request \"%s\""
 
msgstr ""
 
msgstr "%s a mentionné votre nom dans la requête de pull %s « %s »"
 

	
 
#: kallithea/templates/email_templates/pull_request.html:7
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%s requested your review of %s pull request \"%s\""
 
msgstr ""
 
msgstr "%s vous demande de vérifier la requête de pull %s « %s »"
 

	
 
#: kallithea/templates/email_templates/pull_request_comment.html:4
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Comment from %s on %s pull request \"%s\""
 
msgstr ""
 
msgstr "Commentaire de %s sur la requête de pull %s « %s »"
 

	
 
#: kallithea/templates/email_templates/pull_request_comment.html:9
 
#, fuzzy
 
msgid "The comment closed the pull request with status"
 
msgstr "Montrer les demandes de pull fermées"
 
msgstr "Le commentaire a fermé la requête de pull avec le statut"
 

	
 
#: kallithea/templates/email_templates/pull_request_comment.html:11
 
msgid "The comment was made with status"
 
msgstr ""
 
msgstr "Le commentaire a été fait avec le statut"
 

	
 
#: kallithea/templates/email_templates/registration.html:6
 
msgid "View this user here"
 
msgstr ""
 
msgstr "Visualiser cet utilisateur ici"
 

	
 
#: kallithea/templates/files/diff_2way.html:15
 
#, python-format
 
msgid "%s File side-by-side diff"
 
msgstr ""
 
msgstr "Diff côte-à-côte de fichier pour %s"
 

	
 
#: kallithea/templates/files/diff_2way.html:19
 
#: kallithea/templates/files/file_diff.html:8
 
msgid "File diff"
 
msgstr "Diff de fichier"
 

	
 
#: kallithea/templates/files/file_diff.html:4
 
#, python-format
 
msgid "%s File Diff"
 
msgstr ""
 
msgstr "Diff de fichier pour %s"
 

	
 
#: kallithea/templates/files/files.html:4
 
#: kallithea/templates/files/files.html:80
 
#, python-format
 
msgid "%s Files"
 
msgstr "Fichiers de %s"
 

	
 
#: kallithea/templates/files/files_add.html:4
 
#, python-format
 
msgid "%s Files Add"
 
msgstr ""
 
msgstr "Ajout de fichiers pour %s"
 

	
 
#: kallithea/templates/files/files_add.html:40
 
#: kallithea/templates/files/files_edit.html:38
 
#: kallithea/templates/files/files_ypjax.html:3
 
msgid "Location"
 
msgstr "Emplacement"
 

	
 
#: kallithea/templates/files/files_add.html:42
 
msgid "Enter filename..."
 
msgstr ""
 
msgstr "Saisir le nom du fichier..."
 

	
 
#: kallithea/templates/files/files_add.html:44
 
#: kallithea/templates/files/files_add.html:48
 
msgid "or"
 
msgstr "ou"
 

	
 
#: kallithea/templates/files/files_add.html:44
 
msgid "Upload File"
 
msgstr ""
 
msgstr "Uploader un fichier"
 

	
 
#: kallithea/templates/files/files_add.html:48
 
msgid "Create New File"
 
msgstr ""
 
msgstr "Créer un nouveau fichier"
 

	
 
#: kallithea/templates/files/files_add.html:53
 
msgid "New file mode"
 
msgstr ""
 
msgstr "Mode du nouveau fichier"
 

	
 
#: kallithea/templates/files/files_add.html:64
 
#: kallithea/templates/files/files_delete.html:43
 
#: kallithea/templates/files/files_edit.html:67
 
#, fuzzy
 
msgid "Commit Changes"
 
msgstr "Commiter les changements"
 

	
 
#: kallithea/templates/files/files_browser.html:33
 
msgid "Previous revision"
 
msgstr ""
 
msgstr "Révision précédente"
 

	
 
#: kallithea/templates/files/files_browser.html:35
 
msgid "Next revision"
 
msgstr ""
 
msgstr "Révision suivante"
 

	
 
#: kallithea/templates/files/files_browser.html:41
 
msgid "Follow current branch"
 
msgstr ""
 
msgstr "Suivre la branche courante"
 

	
 
#: kallithea/templates/files/files_browser.html:44
 
msgid "Search File List"
 
msgstr ""
 
msgstr "Rechercher dans la liste des fichiers"
 

	
 
#: kallithea/templates/files/files_browser.html:48
 
msgid "Loading file list..."
 
msgstr "Chargement de la liste des fichiers…"
 

	
 
#: kallithea/templates/files/files_browser.html:61
 
msgid "Size"
 
msgstr "Taille"
 

	
 
#: kallithea/templates/files/files_browser.html:62
 
msgid "Last Revision"
 
msgstr "Dernière révision"
 

	
 
#: kallithea/templates/files/files_browser.html:63
 
#, fuzzy
 
msgid "Last Modified"
 
msgstr "Dernière modification"
 

	
 
#: kallithea/templates/files/files_browser.html:64
 
#, fuzzy
 
msgid "Last Committer"
 
msgstr "Dernier commiteur"
 

	
 
#: kallithea/templates/files/files_delete.html:4
 
#, python-format
 
msgid "%s Files Delete"
 
msgstr ""
 
msgstr "Suppression de fichiers pour %s"
 

	
 
#: kallithea/templates/files/files_delete.html:12
 
#: kallithea/templates/files/files_delete.html:31
 
msgid "Delete file"
 
msgstr ""
 
msgstr "Supprimer le fichier"
 

	
 
#: kallithea/templates/files/files_edit.html:4
 
#, python-format
 
msgid "%s File Edit"
 
msgstr ""
 
msgstr "Édition de fichier pour %s"
 

	
 
#: kallithea/templates/files/files_edit.html:21
 
msgid "Edit file"
 
msgstr ""
 
msgstr "Éditer le fichier"
 

	
 
#: kallithea/templates/files/files_edit.html:48
 
#: kallithea/templates/files/files_source.html:32
 
msgid "Show Annotation"
 
msgstr ""
 
msgstr "Afficher l'annotation"
 

	
 
#: kallithea/templates/files/files_edit.html:50
 
#: kallithea/templates/files/files_source.html:35
 
msgid "Download as Raw"
 
msgstr ""
 
msgstr "Télécharger au format brut"
 

	
 
#: kallithea/templates/files/files_edit.html:53
 
msgid "Source"
 
msgstr ""
 
msgstr "Source"
 

	
 
#: kallithea/templates/files/files_edit.html:58
 
msgid "Editing file"
 
msgstr "Édition du fichier"
 

	
 
#: kallithea/templates/files/files_history_box.html:2
 
#, python-format
 
msgid "%s author"
 
msgid_plural "%s authors"
 
msgstr[0] "%s auteur"
 
msgstr[1] "%s auteurs"
 

	
 
#: kallithea/templates/files/files_source.html:7
 
msgid "Diff to Revision"
 
msgstr ""
 
msgstr "Diff par rapport à une révision"
 

	
 
#: kallithea/templates/files/files_source.html:8
 
msgid "Show at Revision"
 
msgstr ""
 
msgstr "Afficher à une révision"
 

	
 
#: kallithea/templates/files/files_source.html:10
 
msgid "Show Full History"
 
msgstr ""
 
msgstr "Afficher l'historique complet"
 

	
 
#: kallithea/templates/files/files_source.html:11
 
msgid "Show Authors"
 
msgstr ""
 
msgstr "Afficher les auteurs"
 

	
 
#: kallithea/templates/files/files_source.html:30
 
msgid "Show Source"
 
msgstr ""
 
msgstr "Afficher la source"
 

	
 
#: kallithea/templates/files/files_source.html:38
 
#, python-format
 
msgid "Edit on Branch:%s"
 
msgstr ""
 
msgstr "Éditer sur la branche : %s"
 

	
 
#: kallithea/templates/files/files_source.html:41
 
msgid "Editing binary files not allowed"
 
msgstr ""
 
msgstr "Édition de fichiers binaires interdite"
 

	
 
#: kallithea/templates/files/files_source.html:44
 
msgid "Editing files allowed only when on branch head revision"
 
msgstr ""
 
"Édition de fichiers autorisée uniquement sur la révision de tête (head) de "
 
"la branche"
 

	
 
#: kallithea/templates/files/files_source.html:45
 
msgid "Deleting files allowed only when on branch head revision"
 
msgstr ""
 
"Suppression de fichiers autorisée uniquement sur la révision de tête (head) "
 
"de la branche"
 

	
 
#: kallithea/templates/files/files_source.html:63
 
#, python-format
 
msgid "Binary file (%s)"
 
msgstr "Fichier binaire (%s)"
 

	
 
#: kallithea/templates/files/files_source.html:73
 
msgid "File is too big to display"
 
msgstr "Ce fichier est trop gros pour être affiché"
 

	
 
#: kallithea/templates/files/files_ypjax.html:5
 
msgid "annotation"
 
msgstr "annotation"
 

	
 
#: kallithea/templates/files/files_ypjax.html:23
 
msgid "Go Back"
 
msgstr ""
 
msgstr "Retour"
 

	
 
#: kallithea/templates/files/files_ypjax.html:24
 
msgid "No files at given path"
 
msgstr "Aucun fichier à cet endroit"
 

	
 
#: kallithea/templates/followers/followers.html:5
 
#, python-format
 
msgid "%s Followers"
 
msgstr "Followers de %s"
 

	
 
#: kallithea/templates/followers/followers.html:9
 
#: kallithea/templates/summary/summary.html:142
 
#: kallithea/templates/summary/summary.html:143
 
msgid "Followers"
 
msgstr "Followers"
 

	
 
#: kallithea/templates/followers/followers_data.html:12
 
msgid "Started following -"
 
msgstr "A commencé à suivre le dépôt :"
 

	
 
#: kallithea/templates/forks/fork.html:5
 
#, python-format
 
msgid "Fork repository %s"
 
msgstr ""
 
msgstr "Forker le dépôt %s"
 

	
 
#: kallithea/templates/forks/fork.html:27
 
msgid "Fork name"
 
msgstr "Nom du fork"
 

	
 
#: kallithea/templates/forks/fork.html:62
 
#, fuzzy
 
msgid "Default revision for files page, downloads, whoosh, and readme."
 
msgstr ""
 
"Révision par défaut pour les pages de fichiers, de téléchargements, de "
 
"recherche et de documentation"
 
"recherche et de documentation."
 

	
 
#: kallithea/templates/forks/fork.html:68
 
msgid "Private"
 
msgstr "Privé"
 

	
 
#: kallithea/templates/forks/fork.html:77
 
msgid "Copy permissions"
 
msgstr "Copier les permissions"
 

	
 
#: kallithea/templates/forks/fork.html:81
 
msgid "Copy permissions from forked repository"
 
msgstr "Copier les permissions depuis le dépôt forké"
 

	
 
#: kallithea/templates/forks/fork.html:87
 
msgid "Update after clone"
 
msgstr "MÀJ après le clonage"
 

	
 
#: kallithea/templates/forks/fork.html:91
 
msgid "Checkout source after making a clone"
 
msgstr "Mettre à jour depuis la source après clonage"
 

	
 
#: kallithea/templates/forks/fork.html:96
 
msgid "Fork this Repository"
 
msgstr ""
 
msgstr "Forker ce dépôt"
 

	
 
#: kallithea/templates/forks/forks.html:5
 
#, python-format
 
msgid "%s Forks"
 
msgstr "Forks de %s"
 

	
 
#: kallithea/templates/forks/forks.html:9
 
#: kallithea/templates/summary/summary.html:148
 
#: kallithea/templates/summary/summary.html:149
 
msgid "Forks"
 
msgstr "Forks"
 

	
 
#: kallithea/templates/forks/forks_data.html:17
 
msgid "Forked"
 
msgstr ""
 
msgstr "Forké"
 

	
 
#: kallithea/templates/forks/forks_data.html:30
 
msgid "There are no forks yet"
 
msgstr "Il n’y a pas encore de forks"
 

	
 
#: kallithea/templates/journal/journal.html:21
 
msgid "ATOM journal feed"
 
msgstr "Flux ATOM du journal"
 

	
 
#: kallithea/templates/journal/journal.html:22
 
msgid "RSS journal feed"
 
msgstr "Flux RSS du journal"
 

	
 
#: kallithea/templates/journal/journal.html:56
 
msgid "My Repositories"
 
msgstr "Mes dépôts"
 

	
 
#: kallithea/templates/journal/journal_data.html:43
 
msgid "No entries yet"
 
msgstr "Aucune entrée pour le moment"
 

	
 
#: kallithea/templates/journal/public_journal.html:13
 
msgid "ATOM public journal feed"
 
msgstr "Flux ATOM du journal public"
 

	
 
#: kallithea/templates/journal/public_journal.html:14
 
msgid "RSS public journal feed"
 
msgstr "Flux RSS du journal public"
 

	
 
#: kallithea/templates/pullrequests/pullrequest.html:4
 
#: kallithea/templates/pullrequests/pullrequest.html:8
 
#, fuzzy
 
msgid "New Pull Request"
 
msgstr "Nouvelle requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest.html:31
 
#: kallithea/templates/pullrequests/pullrequest_data.html:15
 
#: kallithea/templates/pullrequests/pullrequest_show.html:29
 
#: kallithea/templates/pullrequests/pullrequest_show.html:54
 
msgid "Title"
 
msgstr "Titre"
 

	
 
#: kallithea/templates/pullrequests/pullrequest.html:34
 
msgid "Summarize the changes - or leave empty"
 
msgstr ""
 
msgstr "Résumer les modifications - ou laisser vide"
 

	
 
#: kallithea/templates/pullrequests/pullrequest.html:43
 
#: kallithea/templates/pullrequests/pullrequest_show.html:66
 
msgid "Write a short description on this pull request"
 
msgstr ""
 
msgstr "Saisir une courte description de cette requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest.html:49
 
msgid "Changeset flow"
 
msgstr ""
 
msgstr "Flux des changesets"
 

	
 
#: kallithea/templates/pullrequests/pullrequest.html:56
 
msgid "Origin repository"
 
msgstr ""
 
msgstr "Dépôt d'origine"
 

	
 
#: kallithea/templates/pullrequests/pullrequest.html:72
 
msgid "Destination repository"
 
msgstr ""
 
msgstr "Dépôt de destination"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:6
 
#, fuzzy
 
msgid "No entries"
 
msgstr "Aucune entrée pour le moment"
 
msgstr "Aucune entrée"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:14
 
#, fuzzy
 
msgid "Vote"
 
msgstr "Révoquer"
 
msgstr "Voter"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:18
 
msgid "From"
 
msgstr ""
 
msgstr "Depuis"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:19
 
msgid "To"
 
msgstr ""
 
msgstr "Vers"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:28
 
#, python-format
 
msgid "You voted: %s"
 
msgstr ""
 
msgstr "Vous avez voté : %s"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:30
 
msgid "You didn't vote"
 
msgstr ""
 
msgstr "Vous n'avez pas voté"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:35
 
msgid "(no title)"
 
msgstr ""
 
msgstr "(sans titre)"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:37
 
#: kallithea/templates/pullrequests/pullrequest_show.html:31
 
#: kallithea/templates/pullrequests/pullrequest_show.html:83
 
msgid "Closed"
 
msgstr "Fermée"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:67
 
#, fuzzy
 
msgid "Delete Pull Request"
 
msgstr "Nouvelle requête de pull"
 
msgstr "Supprimer la requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:68
 
msgid "Confirm to delete this pull request"
 
msgstr "Veuillez confirmer la suppression de cette requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_data.html:70
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Confirm again to delete this pull request with %s comments"
 
msgstr "Veuillez confirmer la suppression de cette requête de pull"
 
msgstr ""
 
"Veuillez confirmer la suppression de cette requête de pull avec %s "
 
"commentaires"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:6
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%s Pull Request %s"
 
msgstr "Requête de pull #%s"
 
msgstr "%s Requête de pull %s"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:10
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Pull request %s from %s#%s"
 
msgstr "Requête de pull #%s"
 
msgstr "Requête de pull %s depuis %s#%s"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:57
 
#, fuzzy
 
msgid "Summarize the changes"
 
msgstr "Commiter les changements"
 
msgstr "Résumer les changements"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:74
 
msgid "Reviewer voting result"
 
msgstr ""
 
msgstr "Résultat du vote des relecteurs"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:80
 
#: kallithea/templates/pullrequests/pullrequest_show.html:81
 
msgid "Pull request status calculated from votes"
 
msgstr ""
 
msgstr "Statut de la requête de pull calculé à partir des votes"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:93
 
msgid "Still not reviewed by"
 
msgstr "Pas encore relue par"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:97
 
#, python-format
 
msgid "%d reviewer"
 
msgid_plural "%d reviewers"
 
msgstr[0] "%d relecteur"
 
msgstr[1] "%d relecteurs"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:99
 
msgid "Pull request was reviewed by all reviewers"
 
msgstr ""
 
msgstr "La requête de pull a été relue par tous les relecteurs"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:101
 
#, fuzzy
 
msgid "There are no reviewers"
 
msgstr "Aucune branche na été créée pour le moment"
 
msgstr "Il n'y a aucun relecteur"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:107
 
msgid "Origin"
 
msgstr ""
 
msgstr "Origine"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:113
 
#, fuzzy
 
msgid "on"
 
msgstr "Aucune"
 
msgstr "sur"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:120
 
msgid "Target"
 
msgstr ""
 
msgstr "Cible"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:124
 
msgid ""
 
"This is just a range of changesets and doesn't have a target or a real "
 
"merge ancestor."
 
msgstr ""
 
"Ceci est juste une série de changesets, et n'a pas de cible ou de véritable "
 
"ancêtre de fusion."
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:133
 
msgid "Pull changes"
 
msgstr ""
 
msgstr "Puller les modifications"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:173
 
#, fuzzy
 
msgid "Update"
 
msgstr "[a mis à jour] l’utilisateur"
 
msgstr "Mettre à jour"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:191
 
msgid "Current revision - no change"
 
msgstr ""
 
msgstr "Révision courante - aucun changement"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:213
 
#, fuzzy
 
msgid "Pull Request Reviewers"
 
msgstr "Relecteurs de la requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:238
 
#, fuzzy
 
msgid "Remove reviewer"
 
msgstr "%d relecteur"
 
msgstr "Supprimer le relecteur"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:250
 
msgid "Type name of reviewer to add"
 
msgstr ""
 
msgstr "Saisir le nom du relecteur à ajouter"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:258
 
#, fuzzy
 
msgid "Potential Reviewers"
 
msgstr "%d relecteur"
 
msgstr "Relecteurs potentiels"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:261
 
msgid "Click to add the repository owner as reviewer:"
 
msgstr ""
 
msgstr "Cliquer pour ajouter le propriétaire du dépôt comme relecteur :"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:284
 
msgid "Save Changes"
 
msgstr ""
 
msgstr "Enregistrer les changements"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:285
 
#, fuzzy
 
msgid "Save as New Pull Request"
 
msgstr "Nouvelle requête de pull"
 
msgstr "Sauvegarder en tant que nouvelle requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:286
 
#, fuzzy
 
msgid "Cancel Changes"
 
msgstr "Sélectionner le changeset"
 
msgstr "Annuler les modifications"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show.html:296
 
#, fuzzy
 
msgid "Pull Request Content"
 
msgstr "Requêtes de pull"
 
msgstr "Contenu de la requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:6
 
#, python-format
 
msgid "%s Pull Requests"
 
msgstr ""
 
msgstr "Requêtes de pull pour %s"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:11
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Pull Requests from %s'"
 
msgstr "Requête de pull #%s"
 
msgstr "Requête de pull depuis %s'"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:13
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Pull Requests to '%s'"
 
msgstr "Requête de pull #%s"
 
msgstr "Requête de pull vers '%s'"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:32
 
#, fuzzy
 
msgid "Open New Pull Request"
 
msgstr "Nouvelle requête de pull"
 
msgstr "Ouvrir une nouvelle requête de pull"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:37
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Show Pull Requests to %s"
 
msgstr "Requête de pull #%s"
 
msgstr "Afficher les requêtes de pull vers %s"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:39
 
#, fuzzy, python-format
 
#, python-format
 
msgid "Show Pull Requests from '%s'"
 
msgstr ""
 
msgstr "Afficher les requêtes de pull depuis '%s'"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:49
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:28
 
msgid "Hide closed pull requests (only show open pull requests)"
 
msgstr ""
 
"Cacher les requêtes de pull fermées (afficher uniquement les requêtes de "
 
"pull ouvertes)"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_all.html:51
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:30
 
msgid "Show closed pull requests (in addition to open pull requests)"
 
msgstr ""
 
"Afficher les requêtes de pull fermées (en plus des requêtes de pull ouvertes)"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:35
 
#, fuzzy
 
msgid "Pull Requests Created by Me"
 
msgstr "Relecteurs de la requête de pull"
 
msgstr "Requêtes de pull créées par moi"
 

	
 
#: kallithea/templates/pullrequests/pullrequest_show_my.html:38
 
#, fuzzy
 
msgid "Pull Requests I Participate In"
 
msgstr "Je participe à"
 
msgstr "Requêtes de pull auxquelles je participe"
 

	
 
#: kallithea/templates/search/search.html:6
 
#, python-format
 
msgid "%s Search"
 
msgstr ""
 
msgstr "Recherche pour %s"
 

	
 
#: kallithea/templates/search/search.html:8
 
#: kallithea/templates/search/search.html:16
 
#, fuzzy
 
msgid "Search in All Repositories"
 
msgstr "Rechercher dans tous les dépôts"
 

	
 
#: kallithea/templates/search/search.html:50
 
msgid "Search term"
 
msgstr "Termes de la recherches"
 

	
 
#: kallithea/templates/search/search.html:62
 
msgid "Search in"
 
msgstr "Rechercher dans"
 

	
 
#: kallithea/templates/search/search.html:65
 
msgid "File contents"
 
msgstr "Le contenu des fichiers"
 

	
 
#: kallithea/templates/search/search.html:66
 
msgid "Commit messages"
 
msgstr "Les messages de commit"
 

	
 
#: kallithea/templates/search/search.html:67
 
msgid "File names"
 
msgstr "Les noms de fichiers"
 

	
 
#: kallithea/templates/search/search_commit.html:35
 
#: kallithea/templates/search/search_content.html:21
 
#: kallithea/templates/search/search_path.html:15
 
msgid "Permission denied"
 
msgstr "Permission refusée"
 

	
 
#: kallithea/templates/summary/statistics.html:4
 
#, python-format
 
msgid "%s Statistics"
 
msgstr ""
 
msgstr "Statistiques pour %s"
 

	
 
#: kallithea/templates/summary/statistics.html:16
 
#: kallithea/templates/summary/summary.html:39
 
#, python-format
 
msgid "%s ATOM feed"
 
msgstr ""
 
msgstr "Flux ATOM pour %s"
 

	
 
#: kallithea/templates/summary/statistics.html:17
 
#: kallithea/templates/summary/summary.html:40
 
#, python-format
 
msgid "%s RSS feed"
 
msgstr ""
 
msgstr "Flux RSS pour %s"
 

	
 
#: kallithea/templates/summary/statistics.html:36
 
#: kallithea/templates/summary/summary.html:100
 
#: kallithea/templates/summary/summary.html:116
 
msgid "Enable"
 
msgstr ""
 
msgstr "Activer"
 

	
 
#: kallithea/templates/summary/statistics.html:39
 
msgid "Stats gathered: "
 
msgstr "Statistiques obtenues : "
 

	
 
#: kallithea/templates/summary/statistics.html:89
 
#: kallithea/templates/summary/summary.html:349
 
msgid "files"
 
msgstr "Fichiers"
 

	
 
#: kallithea/templates/summary/statistics.html:113
 
#: kallithea/templates/summary/summary.html:373
 
msgid "Show more"
 
msgstr ""
 
msgstr "Afficher plus"
 

	
 
#: kallithea/templates/summary/statistics.html:390
 
msgid "commits"
 
msgstr "commits"
 

	
 
#: kallithea/templates/summary/statistics.html:391
 
msgid "files added"
 
msgstr "fichiers ajoutés"
 

	
 
#: kallithea/templates/summary/statistics.html:392
 
msgid "files changed"
 
msgstr "fichiers modifiés"
 

	
 
#: kallithea/templates/summary/statistics.html:393
 
msgid "files removed"
 
msgstr "fichiers supprimés"
 

	
 
#: kallithea/templates/summary/statistics.html:395
 
msgid "commit"
 
msgstr "commit"
 

	
 
#: kallithea/templates/summary/statistics.html:396
 
msgid "file added"
 
msgstr "fichier ajouté"
 

	
 
#: kallithea/templates/summary/statistics.html:397
 
msgid "file changed"
 
msgstr "fichié modifié"
 

	
 
#: kallithea/templates/summary/statistics.html:398
 
msgid "file removed"
 
msgstr "fichier supprimé"
 

	
 
#: kallithea/templates/summary/summary.html:4
 
#, python-format
 
msgid "%s Summary"
 
msgstr "Résumé de %s"
 

	
 
#: kallithea/templates/summary/summary.html:13
 
#, python-format
 
msgid "Repository locked by %s"
 
msgstr ""
 
msgstr "Dépôt verrouillé par %s"
 

	
 
#: kallithea/templates/summary/summary.html:15
 
msgid "Repository unlocked"
 
msgstr ""
 
msgstr "Dépôt déverrouillé"
 

	
 
#: kallithea/templates/summary/summary.html:22
 
msgid "Fork of"
 
msgstr "Fork de"
 

	
 
#: kallithea/templates/summary/summary.html:29
 
msgid "Clone from"
 
msgstr "Cloner depuis"
 

	
 
#: kallithea/templates/summary/summary.html:72
 
msgid "Clone URL"
 
msgstr "URL de clone"
 

	
 
#: kallithea/templates/summary/summary.html:78
 
msgid "Show by Name"
 
msgstr "Afficher par nom"
 

	
 
#: kallithea/templates/summary/summary.html:79
 
msgid "Show by ID"
 
msgstr "Afficher par ID"
 

	
 
#: kallithea/templates/summary/summary.html:92
 
msgid "Trending files"
 
msgstr "Populaires"
 

	
 
#: kallithea/templates/summary/summary.html:108
 
msgid "Download"
 
msgstr "Téléchargements"
 

	
 
#: kallithea/templates/summary/summary.html:112
 
msgid "There are no downloads yet"
 
msgstr "Il n’y a pas encore de téléchargements proposés"
 

	
 
#: kallithea/templates/summary/summary.html:114
 
msgid "Downloads are disabled for this repository"
 
msgstr "Les téléchargements sont désactivés pour ce dépôt"
 

	
 
#: kallithea/templates/summary/summary.html:120
 
msgid "Download as zip"
 
msgstr "Télécharger en ZIP"
 

	
 
#: kallithea/templates/summary/summary.html:125
 
msgid "Check this to download archive with subrepos"
 
msgstr "Télécharger une archive contenant également les sous-dépôts éventuels"
 

	
 
#: kallithea/templates/summary/summary.html:125
 
#, fuzzy
 
msgid "With subrepos"
 
msgstr "avec les sous-dépôts"
 
msgstr "Avec les sous-dépôts"
 

	
 
#: kallithea/templates/summary/summary.html:156
 
msgid "Repository Size"
 
msgstr "Taille du dépôt"
 

	
 
#: kallithea/templates/summary/summary.html:163
 
#: kallithea/templates/summary/summary.html:165
 
msgid "Feed"
 
msgstr "Flux"
 

	
 
#: kallithea/templates/summary/summary.html:186
 
msgid "Latest Changes"
 
msgstr "Derniers changements"
 

	
 
#: kallithea/templates/summary/summary.html:188
 
msgid "Quick Start"
 
msgstr "Démarrage rapide"
 

	
 
#: kallithea/templates/summary/summary.html:202
 
#, python-format
 
msgid "Readme file from revision %s:%s"
 
msgstr "Fichier Lisez-moi de la revision %s:%s"
 

	
 
#: kallithea/templates/summary/summary.html:293
 
@@ -6221,48 +6211,50 @@ msgstr "Comparer les tags"
 
#~ msgstr "Journal"
 

	
 
#~ msgid "Locked repository"
 
#~ msgstr "Dépôt verrouillé"
 

	
 
#~ msgid "Unlocked repository"
 
#~ msgstr "Dépôt non verrouillé"
 

	
 
#~ msgid "Unlocked"
 
#~ msgstr "Non verrouillé"
 

	
 
#~ msgid "Locked"
 
#~ msgstr "Verrouillé"
 

	
 
#~ msgid "Repository has been %s"
 
#~ msgstr "Le dépôt a été %s"
 

	
 
#~ msgid "You can't edit this user"
 
#~ msgstr "Vous ne pouvez pas éditer cet utilisateur"
 

	
 
#~ msgid "No Files"
 
#~ msgstr "Aucun fichier"
 

	
 
#~ msgid ""
 
#~ "_: \n"
 
#~ ""
 
#~ msgstr ""
 

	
 
#~ msgid "Username \"%(username)s\" is forbidden"
 
#~ msgstr "Le nom d’utilisateur « %(username)s » n’est pas autorisé"
 

	
 
#~ msgid "invalid user name"
 
#~ msgstr "nom d’utilisateur invalide"
 

	
 
#~ msgid "Your account is disabled"
 
#~ msgstr "Votre compte est désactivé"
 

	
 
#~ msgid "invalid clone URL"
 
#~ msgstr "URL de clonage invalide"
 

	
 
#~ msgid "Invalid clone URL, provide a valid clone http(s)/svn+http(s)/ssh URL"
 
#~ msgstr ""
 

	
 
#~ msgid "Revisions %(revs)s are already part of pull request or have set status"
 
#~ msgstr ""
 

	
 
#~ msgid "Defaults"
 
#~ msgstr "Par défaut"
 

	
 
#~ msgid "My Emails"
kallithea/i18n/how_to
Show inline comments
 
@@ -29,69 +29,69 @@ necessary corrections when they're neede
 

	
 

	
 
Merging translations from Weblate
 
---------------------------------
 

	
 
Weblate rebases its changes every time it pulls from our repository. Pulls are triggered
 
by a web hook from Our Own Kallithea every time it receives new commits. Usually merging
 
the new translations is a straightforward process consisting of a pull from Weblate-hosted
 
repository which is available under Data Exports tab in Weblate interface.
 

	
 
Weblate tries to minimise the number of commits, but that's not always work, especially
 
when two translators work with different languages at more or less the same time.
 
It makes sense sometimes to re-order or fold commits by the same author when they touch
 
just the same language translation. That, however, may confuse Weblate sometimes, in
 
which case it should be manually convinced it has to discard the commits it created by
 
using its administrative interface.
 

	
 

	
 
Manual creation of a new language translation
 
---------------------------------------------
 

	
 
In the prepared development environment, run the following to ensure
 
all translation strings are extracted and up-to-date::
 

	
 
    python setup.py extract_messages
 
    python2 setup.py extract_messages
 

	
 
Create new language by executing following command::
 

	
 
    python setup.py init_catalog -l <new_language_code>
 
    python2 setup.py init_catalog -l <new_language_code>
 

	
 
This creates a new translation under directory `kallithea/i18n/<new_language_code>`
 
based on the translation template file, `kallithea/i18n/kallithea.pot`.
 

	
 
Edit the new PO file located in `LC_MESSAGES` directory with poedit or your
 
favorite PO files editor. After you finished with the translations, check the
 
translation file for errors by executing::
 

	
 
    msgfmt -f -c kallithea/i18n/<new_language_code>/LC_MESSAGES/<updated_file.po>
 

	
 
Finally, compile the translations::
 

	
 
    python setup.py compile_catalog -l <new_language_code>
 
    python2 setup.py compile_catalog -l <new_language_code>
 

	
 

	
 
Updating translations
 
---------------------
 

	
 
Extract the latest versions of strings for translation by running::
 

	
 
    python setup.py extract_messages
 
    python2 setup.py extract_messages
 

	
 
Update the PO file by doing::
 

	
 
    python setup.py update_catalog -l <new_language_code>
 
    python2 setup.py update_catalog -l <new_language_code>
 

	
 
Edit the new updated translation file. Repeat all steps after `init_catalog` step from
 
new translation instructions
 

	
 

	
 
Testing translations
 
--------------------
 

	
 
Edit kallithea/tests/test.ini file and set lang attribute to::
 

	
 
    lang=<new_language_code>
 

	
 
Run Kallithea tests by executing::
 

	
 
    nosetests
kallithea/i18n/ru/LC_MESSAGES/kallithea.po
Show inline comments
 
@@ -1883,76 +1883,76 @@ msgstr "На рассмотрении"
 

	
 
#: kallithea/model/forms.py:57
 
msgid "Please enter a login"
 
msgstr "Пожалуйста, введите логин"
 

	
 
#: kallithea/model/forms.py:58
 
#, python-format
 
msgid "Enter a value %(min)i characters long or more"
 
msgstr "Введите значение длиной не менее %(min)i символов"
 

	
 
#: kallithea/model/forms.py:66
 
msgid "Please enter a password"
 
msgstr "Пожалуйста, введите пароль"
 

	
 
#: kallithea/model/forms.py:67
 
#, python-format
 
msgid "Enter %(min)i characters or more"
 
msgstr "Введите не менее %(min)i символов"
 

	
 
#: kallithea/model/forms.py:160
 
msgid "Name must not contain only digits"
 
msgstr ""
 

	
 
#: kallithea/model/notification.py:254
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s commented on changeset %(age)s"
 
msgstr "%(user)s оставил комментарий к набору изменений %(when)s"
 
msgstr "%(user)s оставил комментарий к набору изменений %(age)s"
 

	
 
#: kallithea/model/notification.py:255
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s sent message %(age)s"
 
msgstr "%(user)s отправил сообщение %(when)s"
 
msgstr "%(user)s отправил сообщение %(age)s"
 

	
 
#: kallithea/model/notification.py:256
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s mentioned you %(age)s"
 
msgstr "%(user)s упомянул вас %(when)s"
 
msgstr "%(user)s упомянул вас %(age)s"
 

	
 
#: kallithea/model/notification.py:257
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s registered in Kallithea %(age)s"
 
msgstr "%(user)s зарегистрировался в Kallithea %(when)s"
 
msgstr "%(user)s зарегистрировался в Kallithea %(age)s"
 

	
 
#: kallithea/model/notification.py:258
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s opened new pull request %(age)s"
 
msgstr "%(user)s открыл новый pull-запрос %(when)s"
 
msgstr "%(user)s открыл новый pull-запрос %(age)s"
 

	
 
#: kallithea/model/notification.py:259
 
#, fuzzy, python-format
 
#, python-format
 
msgid "%(user)s commented on pull request %(age)s"
 
msgstr "%(user)s оставил комментарий к pull-запросу %(when)s"
 
msgstr "%(user)s оставил комментарий к pull-запросу %(age)s"
 

	
 
#: kallithea/model/notification.py:266
 
#, python-format
 
msgid "%(user)s commented on changeset at %(when)s"
 
msgstr "%(user)s оставил комментарий к набору изменений %(when)s"
 

	
 
#: kallithea/model/notification.py:267
 
#, python-format
 
msgid "%(user)s sent message at %(when)s"
 
msgstr "%(user)s отправил сообщение %(when)s"
 

	
 
#: kallithea/model/notification.py:268
 
#, python-format
 
msgid "%(user)s mentioned you at %(when)s"
 
msgstr "%(user)s упомянул вас %(when)s"
 

	
 
#: kallithea/model/notification.py:269
 
#, python-format
 
msgid "%(user)s registered in Kallithea at %(when)s"
 
msgstr "%(user)s зарегистрировался в Kallithea %(when)s"
 

	
 
#: kallithea/model/notification.py:270
 
#, python-format
 
msgid "%(user)s opened new pull request at %(when)s"
kallithea/lib/auth.py
Show inline comments
 
@@ -13,49 +13,49 @@
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.lib.auth
 
~~~~~~~~~~~~~~~~~~
 

	
 
authentication and permission libraries
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 4, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 
import time
 
import os
 
import logging
 
import traceback
 
import hashlib
 
import itertools
 
import collections
 

	
 
from decorator import decorator
 

	
 
from pylons import url, request
 
from pylons import url, request, session
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 
from webhelpers.pylonslib import secure_form
 
from sqlalchemy import or_
 
from sqlalchemy.orm.exc import ObjectDeletedError
 
from sqlalchemy.orm import joinedload
 

	
 
from kallithea import __platform__, is_windows, is_unix
 
from kallithea.lib.vcs.utils.lazy import LazyProperty
 
from kallithea.model import meta
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 
from kallithea.model.db import User, Repository, Permission, \
 
    UserToPerm, UserGroupRepoToPerm, UserGroupToPerm, UserGroupMember, \
 
    RepoGroup, UserGroupRepoGroupToPerm, UserIpMap, UserGroupUserGroupToPerm, \
 
    UserGroup, UserApiKeys
 

	
 
from kallithea.lib.utils2 import safe_unicode, aslist
 
from kallithea.lib.utils import get_repo_slug, get_repo_group_slug, \
 
    get_user_group_slug, conditional_cache
 
from kallithea.lib.caching_query import FromCache
 

	
 

	
 
log = logging.getLogger(__name__)
 
@@ -691,101 +691,111 @@ def set_available_permissions(config):
 
    """
 
    This function will propagate pylons globals with all available defined
 
    permission given in db. We don't want to check each time from db for new
 
    permissions since adding a new permission also requires application restart
 
    ie. to decorate new views with the newly created permission
 

	
 
    :param config: current pylons config instance
 

	
 
    """
 
    log.info('getting information about all available permissions')
 
    try:
 
        sa = meta.Session
 
        all_perms = sa.query(Permission).all()
 
        config['available_permissions'] = [x.permission_name for x in all_perms]
 
    finally:
 
        meta.Session.remove()
 

	
 

	
 
#==============================================================================
 
# CHECK DECORATORS
 
#==============================================================================
 

	
 
def redirect_to_login(message=None):
 
    from kallithea.lib import helpers as h
 
    p = url.current()
 
    p = request.path_qs
 
    if message:
 
        h.flash(h.literal(message), category='warning')
 
    log.debug('Redirecting to login page, origin: %s', p)
 
    return redirect(url('login_home', came_from=p, **request.GET))
 
    return redirect(url('login_home', came_from=p))
 

	
 

	
 
class LoginRequired(object):
 
    """
 
    Must be logged in to execute this function else
 
    redirect to login page
 

	
 
    :param api_access: if enabled this checks only for valid auth token
 
        and grants access based on valid token
 
    """
 

	
 
    def __init__(self, api_access=False):
 
        self.api_access = api_access
 

	
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 

	
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        controller = fargs[0]
 
        user = controller.authuser
 
        loc = "%s:%s" % (controller.__class__.__name__, func.__name__)
 
        log.debug('Checking access for user %s @ %s', user, loc)
 

	
 
        if not AuthUser.check_ip_allowed(user, controller.ip_addr):
 
            return redirect_to_login(_('IP %s not allowed') % controller.ip_addr)
 

	
 
        # check if we used an API key and it's a valid one
 
        api_key = request.GET.get('api_key')
 
        if api_key is not None:
 
            # explicit controller is enabled or API is in our whitelist
 
            if self.api_access or allowed_api_access(loc, api_key=api_key):
 
                if api_key in user.api_keys:
 
                    log.info('user %s authenticated with API key ****%s @ %s',
 
                             user, api_key[-4:], loc)
 
                    return func(*fargs, **fkwargs)
 
                else:
 
                    log.warning('API key ****%s is NOT valid', api_key[-4:])
 
                    return redirect_to_login(_('Invalid API key'))
 
            else:
 
                # controller does not allow API access
 
                log.warning('API access to %s is not allowed', loc)
 
                return abort(403)
 

	
 
        # Only allow the following HTTP request methods. (We sometimes use POST
 
        # requests with a '_method' set to 'PUT' or 'DELETE'; but that is only
 
        # used for the route lookup, and does not affect request.method.)
 
        if request.method not in ['GET', 'HEAD', 'POST', 'PUT']:
 
            return abort(405)
 

	
 
        # Make sure CSRF token never appears in the URL. If so, invalidate it.
 
        if secure_form.token_key in request.GET:
 
            log.error('CSRF key leak detected')
 
            session.pop(secure_form.token_key, None)
 
            session.save()
 
            from kallithea.lib import helpers as h
 
            h.flash(_("CSRF token leak has been detected - all form tokens have been expired"),
 
                    category='error')
 

	
 
        # CSRF protection: Whenever a request has ambient authority (whether
 
        # through a session cookie or its origin IP address), it must include
 
        # the correct token, unless the HTTP method is GET or HEAD (and thus
 
        # guaranteed to be side effect free. In practice, the only situation
 
        # where we allow side effects without ambient authority is when the
 
        # authority comes from an API key; and that is handled above.
 
        if request.method not in ['GET', 'HEAD']:
 
            token = request.POST.get(secure_form.token_key)
 
            if not token or token != secure_form.authentication_token():
 
                log.error('CSRF check failed')
 
                return abort(403)
 

	
 
        # WebOb already ignores request payload parameters for anything other
 
        # than POST/PUT, but double-check since other Kallithea code relies on
 
        # this assumption.
 
        if request.method not in ['POST', 'PUT'] and request.POST:
 
            log.error('%r request with payload parameters; WebOb should have stopped this', request.method)
 
            return abort(400)
 

	
 
        # regular user authentication
 
        if user.is_authenticated:
 
            log.info('user %s authenticated with regular auth @ %s', user, loc)
 
            return func(*fargs, **fkwargs)
 
        else:
kallithea/lib/helpers.py
Show inline comments
 
@@ -15,54 +15,55 @@
 
Helper functions
 

	
 
Consists of functions to typically be used within templates, but also
 
available to Controllers. This module is available to both as 'h'.
 
"""
 
import hashlib
 
import StringIO
 
import math
 
import logging
 
import re
 
import urlparse
 
import textwrap
 

	
 
from pygments.formatters.html import HtmlFormatter
 
from pygments import highlight as code_highlight
 
from pylons import url
 
from pylons.i18n.translation import _, ungettext
 

	
 
from webhelpers.html import literal, HTML, escape
 
from webhelpers.html.tools import *
 
from webhelpers.html.builder import make_tag
 
from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
 
    end_form, file, hidden, image, javascript_link, link_to, \
 
    link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
 
    submit, text, password, textarea, title, ul, xml_declaration, radio
 
    submit, text, password, textarea, title, ul, xml_declaration, radio, \
 
    form as insecure_form
 
from webhelpers.html.tools import auto_link, button_to, highlight, \
 
    js_obfuscate, mail_to, strip_links, strip_tags, tag_re
 
from webhelpers.number import format_byte_size, format_bit_size
 
from webhelpers.pylonslib import Flash as _Flash
 
from webhelpers.pylonslib.secure_form import secure_form as form, authentication_token
 
from webhelpers.pylonslib.secure_form import secure_form, authentication_token
 
from webhelpers.text import chop_at, collapse, convert_accented_entities, \
 
    convert_misc_entities, lchop, plural, rchop, remove_formatting, \
 
    replace_whitespace, urlify, truncate, wrap_paragraphs
 
from webhelpers.date import time_ago_in_words
 
from webhelpers.paginate import Page as _Page
 
from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
 
    convert_boolean_attrs, NotGiven, _make_safe_id_component
 

	
 
from kallithea.lib.annotate import annotate_highlight
 
from kallithea.lib.utils import repo_name_slug, get_custom_lexer
 
from kallithea.lib.utils2 import str2bool, safe_unicode, safe_str, \
 
    get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict,\
 
    safe_int
 
from kallithea.lib.markup_renderer import MarkupRenderer, url_re
 
from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError
 
from kallithea.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
 
from kallithea.config.conf import DATE_FORMAT, DATETIME_FORMAT
 
from kallithea.model.changeset_status import ChangesetStatusModel
 
from kallithea.model.db import URL_SEP, Permission
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def canonical_url(*args, **kargs):
 
@@ -1430,24 +1431,34 @@ def journal_filter_help():
 
            date:20120101
 
            date:[20120101100000 TO 20120102]
 

	
 
        Generate wildcards using '*' character:
 
            "repository:vcs*" - search everything starting with 'vcs'
 
            "repository:*vcs*" - search for repository containing 'vcs'
 

	
 
        Optional AND / OR operators in queries
 
            "repository:vcs OR repository:test"
 
            "username:test AND repository:test*"
 
    '''))
 

	
 

	
 
def not_mapped_error(repo_name):
 
    flash(_('%s repository is not mapped to db perhaps'
 
            ' it was created or renamed from the filesystem'
 
            ' please run the application again'
 
            ' in order to rescan repositories') % repo_name, category='error')
 

	
 

	
 
def ip_range(ip_addr):
 
    from kallithea.model.db import UserIpMap
 
    s, e = UserIpMap._get_ip_range(ip_addr)
 
    return '%s - %s' % (s, e)
 

	
 

	
 
def form(url, method="post", **attrs):
 
    """Like webhelpers.html.tags.form but automatically using secure_form with
 
    authentication_token for POST. authentication_token is thus never leaked
 
    in the URL."""
 
    if method.lower() == 'get':
 
        return insecure_form(url, method=method, **attrs)
 
    # webhelpers will turn everything but GET into POST
 
    return secure_form(url, method=method, **attrs)
kallithea/lib/rcmail/response.py
Show inline comments
 
@@ -117,49 +117,49 @@ class MailBase(object):
 

	
 
        part = MailBase()
 
        part.body = data
 
        part.content_encoding['Content-Type'] = (ctype, {})
 
        self.parts.append(part)
 

	
 
    def walk(self):
 
        for p in self.parts:
 
            yield p
 
            for x in p.walk():
 
                yield x
 

	
 

	
 
class MailResponse(object):
 
    """
 
    You are given MailResponse objects from the lamson.view methods, and
 
    whenever you want to generate an email to send to someone.  It has the
 
    same basic functionality as MailRequest, but it is designed to be written
 
    to, rather than read from (although you can do both).
 

	
 
    You can easily set a Body or Html during creation or after by passing it
 
    as __init__ parameters, or by setting those attributes.
 

	
 
    You can initially set the From, To, and Subject, but they are headers so
 
    use the dict notation to change them: msg['From'] = 'joe@test.com'.
 
    use the dict notation to change them: msg['From'] = 'joe@example.com'.
 

	
 
    The message is not fully crafted until right when you convert it with
 
    MailResponse.to_message.  This lets you change it and work with it, then
 
    send it out when it's ready.
 
    """
 
    def __init__(self, To=None, From=None, Subject=None, Body=None, Html=None,
 
                 separator="; "):
 
        self.Body = Body
 
        self.Html = Html
 
        self.base = MailBase([('To', To), ('From', From), ('Subject', Subject)])
 
        self.multipart = self.Body and self.Html
 
        self.attachments = []
 
        self.separator = separator
 

	
 
    def __contains__(self, key):
 
        return self.base.__contains__(key)
 

	
 
    def __getitem__(self, key):
 
        return self.base.__getitem__(key)
 

	
 
    def __setitem__(self, key, val):
 
        return self.base.__setitem__(key, val)
 

	
 
    def __delitem__(self, name):
kallithea/lib/vcs/backends/git/repository.py
Show inline comments
 
@@ -654,52 +654,52 @@ class GitRepository(BaseRepository):
 
        cmd = ['pull', '--ff-only', url]
 
        # If error occurs run_git_command raises RepositoryError already
 
        self.run_git_command(cmd)
 

	
 
    def fetch(self, url):
 
        """
 
        Tries to pull changes from external location.
 
        """
 
        url = self._get_url(url)
 
        so, se = self.run_git_command(['ls-remote', '-h', url])
 
        cmd = ['fetch', url, '--']
 
        for line in (x for x in so.splitlines()):
 
            sha, ref = line.split('\t')
 
            cmd.append('+%s:%s' % (ref, ref))
 
        self.run_git_command(cmd)
 

	
 
    def _update_server_info(self):
 
        """
 
        runs gits update-server-info command in this repo instance
 
        """
 
        from dulwich.server import update_server_info
 
        try:
 
            update_server_info(self._repo)
 
        except OSError as e:
 
            if e.errno != errno.ENOENT:
 
            if e.errno not in [errno.ENOENT, errno.EROFS]:
 
                raise
 
            # Workaround for dulwich crashing on for example its own dulwich/tests/data/repos/simple_merge.git/info/refs.lock
 
            log.error('Ignoring error running update-server-info: %s', e)
 
            log.error('Ignoring %s running update-server-info: %s', type(e).__name__, e)
 

	
 
    @LazyProperty
 
    def workdir(self):
 
        """
 
        Returns ``Workdir`` instance for this repository.
 
        """
 
        return GitWorkdir(self)
 

	
 
    def get_config_value(self, section, name, config_file=None):
 
        """
 
        Returns configuration value for a given [``section``] and ``name``.
 

	
 
        :param section: Section we want to retrieve value from
 
        :param name: Name of configuration we want to retrieve
 
        :param config_file: A path to file which should be used to retrieve
 
          configuration from (might also be a list of file paths)
 
        """
 
        if config_file is None:
 
            config_file = []
 
        elif isinstance(config_file, basestring):
 
            config_file = [config_file]
 

	
 
        def gen_configs():
 
            for path in config_file + self._config_files:
kallithea/model/comment.py
Show inline comments
 
@@ -79,97 +79,97 @@ class ChangesetCommentsModel(BaseModel):
 

	
 
            threading = ['%s-rev-%s@%s' % (repo.repo_name, revision, h.canonical_hostname())]
 
            if line_no: # TODO: url to file _and_ line number
 
                threading.append('%s-rev-%s-line-%s@%s' % (repo.repo_name, revision, line_no,
 
                                                           h.canonical_hostname()))
 
            comment_url = h.canonical_url('changeset_home',
 
                repo_name=repo.repo_name,
 
                revision=revision,
 
                anchor='comment-%s' % comment.comment_id)
 
            subj = safe_unicode(
 
                h.link_to('Re changeset: %(desc)s %(line)s' % \
 
                          {'desc': desc, 'line': line},
 
                          comment_url)
 
            )
 
            # get the current participants of this changeset
 
            recipients = ChangesetComment.get_users(revision=revision)
 
            # add changeset author if it's known locally
 
            cs_author = User.get_from_cs_author(cs.author)
 
            if not cs_author:
 
                #use repo owner if we cannot extract the author correctly
 
                cs_author = repo.user
 
            recipients += [cs_author]
 
            email_kwargs = {
 
                'status_change': status_change,
 
                'cs_comment_user': h.person(user, 'full_name_and_username'),
 
                'cs_comment_user': user.full_name_and_username,
 
                'cs_target_repo': h.canonical_url('summary_home', repo_name=repo.repo_name),
 
                'cs_comment_url': comment_url,
 
                'raw_id': revision,
 
                'message': cs.message,
 
                'repo_name': repo.repo_name,
 
                'short_id': h.short_id(revision),
 
                'branch': cs.branch,
 
                'comment_username': user.username,
 
                'threading': threading,
 
            }
 
        #pull request
 
        elif pull_request:
 
            notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
 
            desc = comment.pull_request.title
 
            _org_ref_type, org_ref_name, _org_rev = comment.pull_request.org_ref.split(':')
 
            threading = ['%s-pr-%s@%s' % (pull_request.other_repo.repo_name,
 
                                          pull_request.pull_request_id,
 
                                          h.canonical_hostname())]
 
            if line_no: # TODO: url to file _and_ line number
 
                threading.append('%s-pr-%s-line-%s@%s' % (pull_request.other_repo.repo_name,
 
                                                          pull_request.pull_request_id, line_no,
 
                                                          h.canonical_hostname()))
 
            comment_url = pull_request.url(canonical=True,
 
                anchor='comment-%s' % comment.comment_id)
 
            subj = safe_unicode(
 
                h.link_to('Re pull request %(pr_nice_id)s: %(desc)s %(line)s' % \
 
                          {'desc': desc,
 
                           'pr_nice_id': comment.pull_request.nice_id(),
 
                           'line': line},
 
                          comment_url)
 
            )
 
            # get the current participants of this pull request
 
            recipients = ChangesetComment.get_users(pull_request_id=
 
                                                pull_request.pull_request_id)
 
            # add pull request author
 
            recipients += [pull_request.owner]
 

	
 
            # add the reviewers to notification
 
            recipients += [x.user for x in pull_request.reviewers]
 

	
 
            #set some variables for email notification
 
            email_kwargs = {
 
                'pr_title': pull_request.title,
 
                'pr_nice_id': pull_request.nice_id(),
 
                'status_change': status_change,
 
                'closing_pr': closing_pr,
 
                'pr_comment_url': comment_url,
 
                'pr_comment_user': h.person(user, 'full_name_and_username'),
 
                'pr_comment_user': user.full_name_and_username,
 
                'pr_target_repo': h.canonical_url('summary_home',
 
                                   repo_name=pull_request.other_repo.repo_name),
 
                'repo_name': pull_request.other_repo.repo_name,
 
                'ref': org_ref_name,
 
                'comment_username': user.username,
 
                'threading': threading,
 
            }
 

	
 
        return subj, body, recipients, notification_type, email_kwargs
 

	
 
    def create(self, text, repo, user, revision=None, pull_request=None,
 
               f_path=None, line_no=None, status_change=None, closing_pr=False,
 
               send_email=True):
 
        """
 
        Creates a new comment for either a changeset or a pull request.
 
        status_change and closing_pr is only for the optional email.
 

	
 
        Returns the created comment.
 
        """
 
        if not status_change and not text:
 
            log.warning('Missing text for comment, skipping...')
 
            return None
 

	
 
        repo = self._get_repo(repo)
kallithea/model/pull_request.py
Show inline comments
 
@@ -90,127 +90,127 @@ class PullRequestModel(BaseModel):
 
        new.owner = created_by_user
 
        Session().add(new)
 
        Session().flush()
 

	
 
        #reset state to under-review
 
        from kallithea.model.comment import ChangesetCommentsModel
 
        comment = ChangesetCommentsModel().create(
 
            text=u'',
 
            repo=org_repo,
 
            user=new.owner,
 
            pull_request=new,
 
            send_email=False,
 
            status_change=ChangesetStatus.STATUS_UNDER_REVIEW,
 
        )
 
        ChangesetStatusModel().set_status(
 
            org_repo,
 
            ChangesetStatus.STATUS_UNDER_REVIEW,
 
            new.owner,
 
            comment,
 
            pull_request=new
 
        )
 

	
 
        mention_recipients = set(User.get_by_username(username, case_insensitive=True)
 
                                 for username in extract_mentioned_users(new.description))
 
        self.__add_reviewers(new, reviewers, mention_recipients)
 
        self.__add_reviewers(created_by_user, new, reviewers, mention_recipients)
 

	
 
        return new
 

	
 
    def __add_reviewers(self, pr, reviewers, mention_recipients=None):
 
    def __add_reviewers(self, user, pr, reviewers, mention_recipients=None):
 
        #members
 
        for member in set(reviewers):
 
            _usr = self._get_user(member)
 
            if _usr is None:
 
                raise UserInvalidException(member)
 
            reviewer = PullRequestReviewers(_usr, pr)
 
            Session().add(reviewer)
 

	
 
        revision_data = [(x.raw_id, x.message)
 
                         for x in map(pr.org_repo.get_changeset, pr.revisions)]
 

	
 
        #notification to reviewers
 
        pr_url = pr.url(canonical=True)
 
        threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name,
 
                                      pr.pull_request_id,
 
                                      h.canonical_hostname())]
 
        subject = safe_unicode(
 
            h.link_to(
 
              _('%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s') % \
 
                {'user': pr.owner.username,
 
                {'user': user.username,
 
                 'pr_title': pr.title,
 
                 'pr_nice_id': pr.nice_id()},
 
                pr_url)
 
            )
 
        body = pr.description
 
        _org_ref_type, org_ref_name, _org_rev = pr.org_ref.split(':')
 
        email_kwargs = {
 
            'pr_title': pr.title,
 
            'pr_user_created': h.person(pr.owner),
 
            'pr_user_created': user.full_name_and_username,
 
            'pr_repo_url': h.canonical_url('summary_home', repo_name=pr.other_repo.repo_name),
 
            'pr_url': pr_url,
 
            'pr_revisions': revision_data,
 
            'repo_name': pr.other_repo.repo_name,
 
            'pr_nice_id': pr.nice_id(),
 
            'ref': org_ref_name,
 
            'pr_username': pr.owner.username,
 
            'pr_username': user.username,
 
            'threading': threading,
 
            'is_mention': False,
 
            }
 
        if reviewers:
 
            NotificationModel().create(created_by=pr.owner, subject=subject, body=body,
 
            NotificationModel().create(created_by=user, subject=subject, body=body,
 
                                       recipients=reviewers,
 
                                       type_=Notification.TYPE_PULL_REQUEST,
 
                                       email_kwargs=email_kwargs)
 

	
 
        if mention_recipients:
 
            mention_recipients.discard(None)
 
            mention_recipients.difference_update(reviewers)
 
        if mention_recipients:
 
            email_kwargs['is_mention'] = True
 
            subject = _('[Mention]') + ' ' + subject
 
            NotificationModel().create(created_by=pr.owner, subject=subject, body=body,
 
            NotificationModel().create(created_by=user, subject=subject, body=body,
 
                                       recipients=mention_recipients,
 
                                       type_=Notification.TYPE_PULL_REQUEST,
 
                                       email_kwargs=email_kwargs)
 

	
 
    def mention_from_description(self, pr, old_description=''):
 
    def mention_from_description(self, user, pr, old_description=''):
 
        mention_recipients = set(User.get_by_username(username, case_insensitive=True)
 
                                 for username in extract_mentioned_users(pr.description))
 
        mention_recipients.difference_update(User.get_by_username(username, case_insensitive=True)
 
                                             for username in extract_mentioned_users(old_description))
 

	
 
        log.debug("Mentioning %s", mention_recipients)
 
        self.__add_reviewers(pr, [], mention_recipients)
 
        self.__add_reviewers(user, pr, [], mention_recipients)
 

	
 
    def update_reviewers(self, pull_request, reviewers_ids):
 
    def update_reviewers(self, user, pull_request, reviewers_ids):
 
        reviewers_ids = set(reviewers_ids)
 
        pull_request = self.__get_pull_request(pull_request)
 
        current_reviewers = PullRequestReviewers.query()\
 
                            .filter(PullRequestReviewers.pull_request==
 
                                   pull_request)\
 
                            .all()
 
        current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
 

	
 
        to_add = reviewers_ids.difference(current_reviewers_ids)
 
        to_remove = current_reviewers_ids.difference(reviewers_ids)
 

	
 
        log.debug("Adding %s reviewers", to_add)
 
        self.__add_reviewers(pull_request, to_add)
 
        self.__add_reviewers(user, pull_request, to_add)
 

	
 
        log.debug("Removing %s reviewers", to_remove)
 
        for uid in to_remove:
 
            reviewer = PullRequestReviewers.query()\
 
                    .filter(PullRequestReviewers.user_id==uid,
 
                            PullRequestReviewers.pull_request==pull_request)\
 
                    .scalar()
 
            if reviewer:
 
                Session().delete(reviewer)
 

	
 
    def delete(self, pull_request):
 
        pull_request = self.__get_pull_request(pull_request)
 
        Session().delete(pull_request)
 

	
 
    def close_pull_request(self, pull_request):
 
        pull_request = self.__get_pull_request(pull_request)
 
        pull_request.status = PullRequest.STATUS_CLOSED
 
        pull_request.updated_on = datetime.datetime.now()
 
        Session().add(pull_request)
kallithea/public/css/style.css
Show inline comments
 
@@ -4288,49 +4288,49 @@ form.comment-inline-form {
 
.comment-inline-form .comment-button {
 
    padding-top: 5px;
 
}
 

	
 
/** comment inline **/
 
.inline-comments {
 
    padding: 0 20px;
 
}
 

	
 
.inline-comments div.rst-block {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0 20px 0px;
 
}
 

	
 
.inline-comments .comment .comment-wrapp {
 
    max-width: 978px;
 
    border: 1px solid #ddd;
 
    border-radius: 4px;
 
    margin: 3px 3px 5px 5px;
 
    background-color: #FAFAFA;
 
}
 

	
 
.inline-comments .add-comment {
 
.inline-comments .add-button-row {
 
    padding: 2px 4px 8px 5px;
 
}
 

	
 
.inline-comments .comment .meta {
 
    background: #f8f8f8;
 
    padding: 4px;
 
    border-bottom: 1px solid #ddd;
 
    min-height: 20px;
 
    overflow: auto;
 
}
 

	
 
.inline-comments .comment .meta img {
 
    vertical-align: middle;
 
}
 

	
 
.inline-comments .comment .meta .user {
 
    font-weight: bold;
 
    float: left;
 
    padding: 3px;
 
}
 

	
 
.inline-comments .comment .meta .date {
 
    float: left;
 
    padding: 3px;
 
@@ -4805,48 +4805,49 @@ table.code-difftable .unmod .code pre:be
 
}
 

	
 
.add-bubble div:before {
 
    font-size: 14px;
 
    color: #ffffff;
 
    font-family: "kallithea";
 
    content: '\1f5ea';
 
}
 

	
 
.add-bubble div:hover {
 
    transform: scale(1.2, 1.2);
 
}
 

	
 
/* show some context of link targets - but only works when the link target
 
   can be extended with any visual difference */
 
div.comment:target:before {
 
  display: block;
 
  height: 100px;
 
  margin: -100px 0 0;
 
  content: "";
 
}
 

	
 
div.comment:target>.comment-wrapp {
 
    border: solid 2px #ee0 !important;
 
    margin: 2px 2px 4px 4px;
 
}
 

	
 
.lineno:target a {
 
    border: solid 2px #ee0 !important;
 
    margin: -2px;
 
}
 

	
 
.btn-image-diff-show,
 
.btn-image-diff-swap {
 
    margin: 5px;
 
}
 

	
 
.img-diff {
 
    max-width: 45%;
 
    height: auto;
 
    margin: 5px;
 
    /* http://lea.verou.me/demos/css3-patterns.html */
 
    background-image:
 
        linear-gradient(45deg, #888 25%, transparent 25%, transparent),
 
        linear-gradient(-45deg, #888 25%, transparent 25%, transparent),
 
        linear-gradient(45deg, transparent 75%, #888 75%),
 
        linear-gradient(-45deg, transparent 75%, #888 75%);
 
    background-size: 10px 10px;
 
    background-color: #999;
kallithea/public/js/base.js
Show inline comments
 
@@ -634,69 +634,69 @@ function show_comment_form($bubble) {
 
    var children = $bubble.closest('tr.line').children('[id]');
 
    var line_td_id = children[children.length - 1].id;
 
    var $comment_div = _get_add_comment_div(line_td_id);
 
    var f_path = $bubble.closest('div.full_f_path').data('f_path');
 
    var parts = line_td_id.split('_');
 
    var line_no = parts[parts.length-1];
 
    comment_div_state($comment_div, f_path, line_no, true);
 
}
 

	
 
// return comment div for target_id - add it if it doesn't exist yet
 
function _get_add_comment_div(target_id) {
 
    var comments_box_id = 'comments-' + target_id;
 
    var $comments_box = $('#' + comments_box_id);
 
    if (!$comments_box.length) {
 
        var html = '<tr><td id="{0}" colspan="3" class="inline-comments"></td></tr>'.format(comments_box_id);
 
        $('#' + target_id).closest('tr').after(html);
 
        $comments_box = $('#' + comments_box_id);
 
    }
 
    return $comments_box;
 
}
 

	
 
// set $comment_div state - showing or not showing form and Add button
 
function comment_div_state($comment_div, f_path, line_no, show_form) {
 
    var $forms = $comment_div.children('.comment-inline-form');
 
    var $buttons = $comment_div.children('.add-comment');
 
    var $buttonrow = $comment_div.children('.add-button-row');
 
    var $comments = $comment_div.children('.comment');
 
    if (show_form) {
 
        if (!$forms.length) {
 
            _comment_div_append_form($comment_div, f_path, line_no);
 
        }
 
    } else {
 
        $forms.remove();
 
    }
 
    $buttons.remove();
 
    $buttonrow.remove();
 
    if ($comments.length && !show_form) {
 
        _comment_div_append_add($comment_div, f_path, line_no);
 
    }
 
}
 

	
 
// append an Add button to $comment_div and hook it up to show form
 
function _comment_div_append_add($comment_div, f_path, line_no) {
 
    var addlabel = TRANSLATION_MAP['Add Another Comment'];
 
    var $add = $('<div class="add-comment"><span class="btn btn-mini">{0}</span></div>'.format(addlabel));
 
    var $add = $('<div class="add-button-row"><span class="btn btn-mini add-button">{0}</span></div>'.format(addlabel));
 
    $comment_div.append($add);
 
    $add.click(function(e) {
 
    $add.children('.add-button').click(function(e) {
 
        comment_div_state($comment_div, f_path, line_no, true);
 
    });
 
}
 

	
 
// append a comment form to $comment_div
 
function _comment_div_append_form($comment_div, f_path, line_no) {
 
    var $form_div = $($('#comment-inline-form-template').html().format(f_path, line_no))
 
        .addClass('comment-inline-form');
 
    $comment_div.append($form_div);
 
    var $form = $comment_div.find("form");
 

	
 
    $form.submit(function(e) {
 
        e.preventDefault();
 

	
 
        var text = $('#text_'+line_no).val();
 
        if (!text){
 
            return;
 
        }
 

	
 
        $form.find('.submitting-overlay').show();
 

	
 
        var success = function(json_data) {
 
            $comment_div.append(json_data['rendered_text']);
 
            comment_div_state($comment_div, f_path, line_no, false);
 
@@ -875,104 +875,104 @@ var fileBrowserListeners = function(curr
 
            }
 
            else{
 
                $('#tbody').show();
 
                $('#tbody_filtered').hide();
 
            }
 
        }
 
    };
 

	
 
    $('#filter_activate').click(function(){
 
            initFilter();
 
        });
 
    $node_filter.click(function(){
 
            if($node_filter.hasClass('init')){
 
                $node_filter.val('');
 
                $node_filter.removeClass('init');
 
            }
 
        });
 
    $node_filter.keyup(function(e){
 
            clearTimeout(filterTimeout);
 
            filterTimeout = setTimeout(updateFilter(e),600);
 
        });
 
};
 

	
 

	
 
var initCodeMirror = function(textarea_id, resetUrl){
 
var initCodeMirror = function(textarea_id, baseUrl, resetUrl){
 
    var myCodeMirror = CodeMirror.fromTextArea($('#' + textarea_id)[0], {
 
            mode: "null",
 
            lineNumbers: true,
 
            indentUnit: 4,
 
            autofocus: true
 
        });
 
    CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
 
    CodeMirror.modeURL = baseUrl + "/codemirror/mode/%N/%N.js";
 

	
 
    $('#reset').click(function(e){
 
            window.location=resetUrl;
 
        });
 

	
 
    $('#file_enable').click(function(){
 
            $('#editor_container').show();
 
            $('#upload_file_container').hide();
 
            $('#filename_container').show();
 
            $('#set_mode_header').show();
 
        });
 

	
 
    $('#upload_file_enable').click(function(){
 
            $('#editor_container').hide();
 
            $('#upload_file_container').show();
 
            $('#filename_container').hide();
 
            $('#set_mode_header').hide();
 
        });
 

	
 
    return myCodeMirror
 
};
 

	
 
var setCodeMirrorMode = function(codeMirrorInstance, mode) {
 
    CodeMirror.autoLoadMode(codeMirrorInstance, mode);
 
}
 

	
 

	
 
var _getIdentNode = function(n){
 
    //iterate thrugh nodes until matching interesting node
 

	
 
    if (typeof n == 'undefined'){
 
        return -1
 
    }
 

	
 
    if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
 
        return n
 
    }
 
    else{
 
        return _getIdentNode(n.parentNode);
 
    }
 
};
 

	
 
/* generate links for multi line selects that can be shown by files.html page_highlights.
 
 * This is a mouseup handler for hlcode from CodeHtmlFormatter and pygmentize */
 
var getSelectionLink = function(e) {
 
    //get selection from start/to nodes
 
    if (typeof window.getSelection != "undefined") {
 
        s = window.getSelection();
 
        var s = window.getSelection();
 

	
 
        var from = _getIdentNode(s.anchorNode);
 
        var till = _getIdentNode(s.focusNode);
 

	
 
        var f_int = parseInt(from.id.replace('L',''));
 
        var t_int = parseInt(till.id.replace('L',''));
 

	
 
        var yoffset = 35;
 
        var ranges = [parseInt(from.id.replace('L','')), parseInt(till.id.replace('L',''))];
 
        if (ranges[0] > ranges[1]){
 
            //highlight from bottom
 
            yoffset = -yoffset;
 
            ranges = [ranges[1], ranges[0]];
 
        }
 
        var $hl_div = $('div#linktt');
 
        // if we select more than 2 lines
 
        if (ranges[0] != ranges[1]){
 
            if ($hl_div.length) {
 
                $hl_div.html('');
 
            } else {
 
                $hl_div = $('<div id="linktt" class="hl-tip-box">');
 
                $('body').prepend($hl_div);
 
            }
 

	
kallithea/public/js/codemirror_loadmode.js
Show inline comments
 
(function() {
 
  // FIXME: if this default value ever is used, it will probably be wrong
 
  if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
 

	
 
  var loading = {};
 
  function splitCallback(cont, n) {
 
    var countDown = n;
 
    return function() { if (--countDown == 0) cont(); };
 
  }
 
  function ensureDeps(mode, cont) {
 
    var deps = CodeMirror.modes[mode].dependencies;
 
    if (!deps) return cont();
 
    var missing = [];
 
    for (var i = 0; i < deps.length; ++i) {
 
      if (!CodeMirror.modes.hasOwnProperty(deps[i]))
 
        missing.push(deps[i]);
 
    }
 
    if (!missing.length) return cont();
 
    var split = splitCallback(cont, missing.length);
 
    for (var i = 0; i < missing.length; ++i)
 
      CodeMirror.requireMode(missing[i], split);
 
  }
 

	
 
  CodeMirror.requireMode = function(mode, cont) {
 
    if (typeof mode != "string") mode = mode.mode;
 
    if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
 
    if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
 

	
kallithea/templates/about.html
Show inline comments
 
@@ -41,48 +41,49 @@
 
  <li>Copyright &copy; 2015, Balázs Úr</li>
 
  <li>Copyright &copy; 2015, Ben Finney</li>
 
  <li>Copyright &copy; 2015, Branko Majic</li>
 
  <li>Copyright &copy; 2015, Daniel Hobley</li>
 
  <li>Copyright &copy; 2015, David Avigni</li>
 
  <li>Copyright &copy; 2015, Denis Blanchette</li>
 
  <li>Copyright &copy; 2015, duanhongyi</li>
 
  <li>Copyright &copy; 2015, EriCSN Chang</li>
 
  <li>Copyright &copy; 2015, Étienne Gilli</li>
 
  <li>Copyright &copy; 2015, Grzegorz Krason</li>
 
  <li>Copyright &copy; 2015, Jan Heylen</li>
 
  <li>Copyright &copy; 2015, Kazunari Kobayashi</li>
 
  <li>Copyright &copy; 2015, Kevin Bullock</li>
 
  <li>Copyright &copy; 2015, kobanari</li>
 
  <li>Copyright &copy; 2015, Marc Abramowitz</li>
 
  <li>Copyright &copy; 2015, Marc Villetard</li>
 
  <li>Copyright &copy; 2015, Matthias Zilk</li>
 
  <li>Copyright &copy; 2015, Michael Pohl</li>
 
  <li>Copyright &copy; 2015, Michael V. DePalatis</li>
 
  <li>Copyright &copy; 2015, Morten Skaaning</li>
 
  <li>Copyright &copy; 2015, Nick High</li>
 
  <li>Copyright &copy; 2015, Niemand Jedermann</li>
 
  <li>Copyright &copy; 2015, Peter Vitt</li>
 
  <li>Copyright &copy; 2015, Robert Martinez</li>
 
  <li>Copyright &copy; 2015, Robert Rauch</li>
 
  <li>Copyright &copy; 2015, Ronny Pfannschmidt</li>
 
  <li>Copyright &copy; 2015, Sam Jaques</li>
 
  <li>Copyright &copy; 2015, Søren Løvborg</li>
 
  <li>Copyright &copy; 2015, Tuux</li>
 
  <li>Copyright &copy; 2015, Viktar Palstsiuk</li>
 
  <li>Copyright &copy; 2012, 2014, Dominik Ruf</li>
 
  <li>Copyright &copy; 2014, Bradley M. Kuhn</li>
 
  <li>Copyright &copy; 2014, Calinou</li>
 
  <li>Copyright &copy; 2014, Daniel Anderson</li>
 
  <li>Copyright &copy; 2014, Henrik Stuart</li>
 
  <li>Copyright &copy; 2014, Ingo von Borstel</li>
 
  <li>Copyright &copy; 2014, Jelmer Vernooij</li>
 
  <li>Copyright &copy; 2014, Jim Hague</li>
 
  <li>Copyright &copy; 2014, Matt Fellows</li>
 
  <li>Copyright &copy; 2014, Max Roman</li>
 
  <li>Copyright &copy; 2014, Michal Čihař</li>
 
  <li>Copyright &copy; 2014, Na'Tosha Bard</li>
 
  <li>Copyright &copy; 2014, Rasmus Selsmark</li>
 
  <li>Copyright &copy; 2014, Tim Freund</li>
 
  <li>Copyright &copy; 2014, Travis Burtrum</li>
 
  <li>Copyright &copy; 2014, Zoltan Gyarmati</li>
 
  <li>Copyright &copy; 2010&ndash;2013, Marcin Kuźmiński</li>
 
  <li>Copyright &copy; 2010&ndash;2013, RhodeCode GmbH</li>
 
  <li>Copyright &copy; 2011, 2013, Aparkar</li>
kallithea/templates/admin/gists/edit.html
Show inline comments
 
@@ -60,49 +60,49 @@
 
                     %if c.gist.gist_expires == -1:
 
                      ${_('Expires')}: ${_('Never')}
 
                     %else:
 
                      ${_('Expires')}: ${h.age(h.time_to_datetime(c.gist.gist_expires))}
 
                     %endif
 
                   </span>
 
                </div>
 
            </div>
 

	
 
            % for cnt, file in enumerate(c.files):
 
                <div id="body" class="codeblock" style="margin-bottom: 4px">
 
                    <div style="padding: 10px 10px 10px 26px;color:#666666">
 
                        <input type="hidden" value="${file.path}" name="org_files">
 
                        <input id="filename_${h.FID('f',file.path)}" name="files" size="30" type="text" value="${file.path}">
 
                        <select id="mimetype_${h.FID('f',file.path)}" name="mimetypes"/>
 
                    </div>
 
                    <div class="editor_container">
 
                        <pre id="editor_pre"></pre>
 
                        <textarea id="editor_${h.FID('f',file.path)}" name="contents" style="display:none">${file.content}</textarea>
 
                    </div>
 
                </div>
 

	
 
                ## dynamic edit box.
 
                <script type="text/javascript">
 
                var myCodeMirror = initCodeMirror("editor_${h.FID('f',file.path)}", '');
 
                var myCodeMirror = initCodeMirror("editor_${h.FID('f',file.path)}", "${request.script_name}", '');
 

	
 
                //inject new modes
 
                var $modes_select = $('#mimetype_${h.FID('f',file.path)}');
 
                $modes_select.each(function(){
 
                    var modes_select = this;
 
                    var index = 1;
 
                    for(var i=0;i<CodeMirror.modeInfo.length;i++) {
 
                        var m = CodeMirror.modeInfo[i];
 
                        var opt = new Option(m.name, m.mime);
 
                        $(opt).attr('mode', m.mode);
 
                        if (m.mime == 'text/plain') {
 
                            // default plain text
 
                            $(opt).prop('selected', true);
 
                            modes_select.options[0] = opt;
 
                        } else {
 
                            modes_select.options[index++] = opt;
 
                        }
 
                    }
 
                });
 

	
 
                var $filename = $('#filename_${h.FID('f',file.path)}');
 
                // on select change set new mode
 
                $modes_select.change(function(e){
 
                    var selected = e.currentTarget;
kallithea/templates/admin/gists/new.html
Show inline comments
 
@@ -38,49 +38,49 @@
 
                </div>
 
                <textarea style="resize:vertical; width:400px;border: 1px solid #ccc;border-radius: 3px;" id="description" name="description" placeholder="${_('Gist description ...')}"></textarea>
 
                <div style="padding:0px 0px 0px 42px">
 
                <label for='lifetime'>${_('Gist lifetime')}</label>
 
                ${h.select('lifetime', '', c.lifetime_options)}
 
                </div>
 
            </div>
 
            <div id="body" class="codeblock">
 
                <div style="padding: 10px 10px 10px 26px;color:#666666">
 
                    ${h.text('filename', size=30, placeholder=_('name this file...'))}
 
                    <select id="mimetype" name="mimetype"/>
 
                </div>
 
                <div id="editor_container">
 
                    <pre id="editor_pre"></pre>
 
                    <textarea id="editor" name="content" style="display:none"></textarea>
 
                </div>
 
            </div>
 
            <div style="padding-top: 5px">
 
            ${h.submit('private',_('Create Private Gist'),class_="btn btn-mini btn-success")}
 
            ${h.submit('public',_('Create Public Gist'),class_="btn btn-mini")}
 
            ${h.reset('reset',_('Reset'),class_="btn btn-mini")}
 
            </div>
 
          ${h.end_form()}
 
          <script type="text/javascript">
 
            var myCodeMirror = initCodeMirror('editor', '');
 
            var myCodeMirror = initCodeMirror('editor', "${request.script_name}", '');
 

	
 
            //inject new modes
 
            var $modes_select = $('#mimetype');
 
            $modes_select.each(function(){
 
                var modes_select = this;
 
                var index = 1;
 
                for(var i=0;i<CodeMirror.modeInfo.length;i++) {
 
                    var m = CodeMirror.modeInfo[i];
 
                    var opt = new Option(m.name, m.mime);
 
                    $(opt).attr('mode', m.mode);
 
                    if (m.mime == 'text/plain') {
 
                        // default plain text
 
                        $(opt).prop('selected', true);
 
                        modes_select.options[0] = opt;
 
                    } else {
 
                        modes_select.options[index++] = opt;
 
                    }
 
                }
 
            });
 

	
 
            var $filename = $('#filename');
 
            // on select change set new mode
 
            $modes_select.change(function(e){
 
                var selected = e.currentTarget;
kallithea/templates/admin/notifications/notifications_data.html
Show inline comments
 
@@ -11,31 +11,31 @@ unread = lambda n:{False:'unread'}.get(n
 
    <div class="notification-header">
 
      <div class="gravatar">
 
        ${h.gravatar(notification.notification.created_by_user.email, size=24)}
 
      </div>
 
      <div class="desc ${unread(notification.read)}">
 
      <a href="${url('notification', notification_id=notification.notification.notification_id)}">${notification.notification.description}</a>
 

	
 
      </div>
 
      <div class="delete-notifications">
 
        <span id="${notification.notification.notification_id}" class="delete-notification"><i class="icon-minus-circled" id="yui-gen24" style="color: #b94a48; padding: 2px;"></i></span>
 
      </div>
 
      %if not notification.read:
 
      <div class="read-notifications">
 
        <span id="${notification.notification.notification_id}" class="read-notification"><i class="icon-ok" id="yui-gen24" style="color: #4CBB17; padding: 2px;"></i></span>
 
      </div>
 
      %endif
 
    </div>
 
        <div class="notification-subject"></div>
 
  </div>
 
%endfor
 
</div>
 

	
 
<div class="notification-paginator">
 
  <div class="pagination-wh pagination-left">
 
  ${c.notifications.pager('$link_previous ~2~ $link_next',**request.GET.mixed())}
 
  ${c.notifications.pager('$link_previous ~2~ $link_next',controller='admin/notifications',**request.GET.mixed())}
 
  </div>
 
</div>
 

	
 
%else:
 
    <div class="table">${_('No notifications here yet')}</div>
 
%endif
kallithea/templates/base/base.html
Show inline comments
 
@@ -273,49 +273,49 @@
 
        %endif
 
      </a>
 
    </li>
 

	
 
    ## USER MENU
 
    <li>
 
      <a class="menu_link childs" id="quick_login_link">
 
          <span class="icon">
 
            ${h.gravatar(c.authuser.email, size=20)}
 
          </span>
 
          %if c.authuser.username != 'default':
 
            <span class="menu_link_user">${c.authuser.username}</span>
 
            %if c.unread_notifications != 0:
 
              <span class="menu_link_notifications">${c.unread_notifications}</span>
 
            %endif
 
          %else:
 
              <span>${_('Not Logged In')}</span>
 
          %endif
 
      </a>
 

	
 
      <div class="user-menu">
 
        <div id="quick_login">
 
          %if c.authuser.username == 'default' or c.authuser.user_id is None:
 
            <h4>${_('Login to Your Account')}</h4>
 
            ${h.form(h.url('login_home',came_from=h.url.current()))}
 
            ${h.form(h.url('login_home', came_from=request.path_qs))}
 
            <div class="form">
 
                <div class="fields">
 
                    <div class="field">
 
                        <div class="label">
 
                            <label for="username">${_('Username')}:</label>
 
                        </div>
 
                        <div class="input">
 
                            ${h.text('username',class_='focus')}
 
                        </div>
 

	
 
                    </div>
 
                    <div class="field">
 
                        <div class="label">
 
                            <label for="password">${_('Password')}:</label>
 
                        </div>
 
                        <div class="input">
 
                            ${h.password('password',class_='focus')}
 
                        </div>
 

	
 
                    </div>
 
                    <div class="buttons">
 
                        <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
 
                        <div class="register">
 
                        %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
kallithea/templates/changelog/changelog.html
Show inline comments
 
@@ -89,49 +89,49 @@ ${self.repo_context_bar('changelog', c.f
 
                          %if c.statuses.get(cs.raw_id):
 
                            <div class="changeset-status-ico">
 
                            %if c.statuses.get(cs.raw_id)[2]:
 
                              <a class="tooltip" title="${_('Changeset status: %s\nClick to open associated pull request %s') % (c.statuses.get(cs.raw_id)[1], c.statuses.get(cs.raw_id)[4])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
 
                                <i class="icon-circle changeset-status-${c.statuses.get(cs.raw_id)[0]}"></i>
 
                              </a>
 
                            %else:
 
                              <a class="tooltip" title="${_('Changeset status: %s') % c.statuses.get(cs.raw_id)[1]}" href="${c.comments[cs.raw_id][0].url()}">
 
                                  <i class="icon-circle changeset-status-${c.statuses.get(cs.raw_id)[0]}"></i>
 
                              </a>
 
                            %endif
 
                            </div>
 
                          %endif
 
                        </td>
 
                        <td class="author">
 
                            ${h.gravatar(h.email_or_none(cs.author), size=16)}
 
                            <span title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</span>
 
                        </td>
 
                        <td class="hash" style="width:${len(h.show_id(cs))*6.5}px">
 
                            <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
 
                                <span class="changeset_hash">${h.show_id(cs)}</span>
 
                            </a>
 
                        </td>
 
                        <td class="date">
 
                            <div class="date">${h.age(cs.date,True)}</div>
 
                            <div class="date tooltip" title="${h.fmt_date(cs.date)}">${h.age(cs.date,True)}</div>
 
                        </td>
 
                        <td class="expand_commit" commit_id="${cs.raw_id}" title="${_('Expand commit message')}">
 
                            <i class="icon-align-left" style="color:#999"></i>
 
                        </td>
 
                        <td class="mid">
 
                            <div class="log-container">
 
                                <div class="message" id="C-${cs.raw_id}">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
 
                                <div class="extra-container">
 
                                    %if c.comments.get(cs.raw_id):
 
                                        <div class="comments-container">
 
                                            <div class="comments-cnt" title="${_('Changeset has comments')}">
 
                                                <a href="${c.comments[cs.raw_id][0].url()}">
 
                                                    ${len(c.comments[cs.raw_id])}
 
                                                    <i class="icon-comment-discussion"></i>
 
                                                </a>
 
                                            </div>
 
                                        </div>
 
                                    %endif
 
                                    %if h.is_hg(c.db_repo_scm_instance):
 
                                        %for book in cs.bookmarks:
 
                                            <div class="booktag" title="${_('Bookmark %s') % book}">
 
                                                ${h.link_to(book,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
 
                                            </div>
 
                                        %endfor
kallithea/templates/changeset/changeset_file_comment.html
Show inline comments
 
@@ -66,49 +66,49 @@
 
        </div>
 
        <div class="mentions-container" id="mentions_container_{1}"></div>
 
        <textarea id="text_{1}" name="text" class="comment-block-ta yui-ac-input"></textarea>
 
      </div>
 
      <div id="preview-container_{1}" class="clearfix" style="display:none">
 
        <div class="comment-help">
 
            ${_('Comment preview')}
 
        </div>
 
        <div id="preview-box_{1}" class="preview-box"></div>
 
      </div>
 
      <div class="comment-button">
 
        <div class="submitting-overlay">${_('Submitting ...')}</div>
 
        <input type="hidden" name="f_path" value="{0}">
 
        <input type="hidden" name="line" value="{1}">
 
        ${h.submit('save', _('Comment'), class_='btn btn-small save-inline-form')}
 
        ${h.reset('hide-inline-form', _('Cancel'), class_='btn btn-small hide-inline-form')}
 
        <div id="preview-btn_{1}" class="preview-btn btn btn-small">${_('Preview')}</div>
 
        <div id="edit-btn_{1}" class="edit-btn btn btn-small" style="display:none">${_('Edit')}</div>
 
      </div>
 
    ${h.end_form()}
 
  %else:
 
      ${h.form('')}
 
      <div class="clearfix">
 
          <div class="comment-help">
 
            ${_('You need to be logged in to comment.')} <a href="${h.url('login_home',came_from=h.url.current())}">${_('Login now')}</a>
 
            ${_('You need to be logged in to comment.')} <a href="${h.url('login_home', came_from=request.path_qs)}">${_('Login now')}</a>
 
          </div>
 
      </div>
 
      <div class="comment-button">
 
      ${h.reset('hide-inline-form', _('Hide'), class_='btn btn-small hide-inline-form')}
 
      </div>
 
      ${h.end_form()}
 
  %endif
 
  </div>
 
</div>
 
</%def>
 

	
 

	
 
## show comment count as "x comments (y inline, z general)"
 
<%def name="comment_count(inline_cnt, general_cnt)">
 
    ${'%s (%s, %s)' % (
 
        ungettext("%d comment", "%d comments", inline_cnt + general_cnt) % (inline_cnt + general_cnt),
 
        ungettext("%d inline", "%d inline", inline_cnt) % inline_cnt,
 
        ungettext("%d general", "%d general", general_cnt) % general_cnt
 
    )}
 
    <span class="firstlink"></span>
 
</%def>
 

	
 

	
 
## generate inline comments and the main ones
kallithea/templates/files/files_add.html
Show inline comments
 
@@ -46,49 +46,49 @@ ${self.repo_context_bar('files')}
 
              <span id="upload_file_container" class="reviewer_ac" style="display:none">
 
                  <input type="file"  size="20" name="upload_file" id="upload_file">
 
                  ${_('or')} <div class="btn btn-small" id="file_enable">${_('Create New File')}</div>
 
              </span>
 
          </h3>
 
            <div id="body" class="codeblock">
 
            <div class="code-header" id="set_mode_header">
 
                <label class="commit" for="set_mode">${_('New file mode')}</label>
 
                <select id="set_mode" name="set_mode"/>
 
            </div>
 
                <div id="editor_container">
 
                    <pre id="editor_pre"></pre>
 
                    <textarea id="editor" name="content" style="display:none"></textarea>
 
                </div>
 
                <div style="padding: 10px;color:#666666">${_('Commit Message')}</div>
 
                <textarea id="commit" name="message" style="height: 100px;width: 99%;margin-left:4px" placeholder="${c.default_message}"></textarea>
 
            </div>
 
            <div style="text-align: left;padding-top: 5px">
 
            ${h.submit('commit',_('Commit Changes'),class_="btn btn-small btn-success")}
 
            ${h.reset('reset',_('Reset'),class_="btn btn-small")}
 
            </div>
 
            ${h.end_form()}
 
            <script type="text/javascript">
 
            var reset_url = "${h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path)}";
 
            var myCodeMirror = initCodeMirror('editor',reset_url);
 
            var myCodeMirror = initCodeMirror('editor', "${request.script_name}", reset_url);
 

	
 
            //inject new modes, based on codeMirrors modeInfo object
 
            $('#set_mode').each(function(){
 
                var modes_select = this;
 
                var index = 1;
 
                for(var i=0;i<CodeMirror.modeInfo.length;i++){
 
                    var m = CodeMirror.modeInfo[i];
 
                    var opt = new Option(m.name, m.mime);
 
                    $(opt).attr('mode', m.mode);
 
                    if (m.mime == 'text/plain') {
 
                        // default plain text
 
                        $(opt).prop('selected', true);
 
                        modes_select.options[0] = opt;
 
                    } else {
 
                        modes_select.options[index++] = opt;
 
                    }
 
                }
 
            });
 
            $('#set_mode').change(function(e){
 
                var selected = e.currentTarget;
 
                var node = selected.options[selected.selectedIndex];
 
                var detected_mode = CodeMirror.findModeByMIME(node.value);
 
                setCodeMirrorMode(myCodeMirror, detected_mode);
 

	
kallithea/templates/files/files_edit.html
Show inline comments
 
@@ -54,49 +54,49 @@ ${self.repo_context_bar('files')}
 
                       % endif
 
                      % endif
 
                    </div>
 
                </div>
 
                <label class="commit" for="set_mode">${_('Editing file')}: ${c.file.unicode_path}</label>
 
                <select id="set_mode" name="set_mode"/>
 
            </div>
 
                <pre id="editor_pre"></pre>
 
                <textarea id="editor" name="content" style="display:none">${h.escape(c.file.content)|n}</textarea>
 
                <div style="padding: 10px;color:#666666">${_('Commit Message')}</div>
 
                <textarea id="commit" name="message" style="height: 60px;width: 99%;margin-left:4px" placeholder="${c.default_message}"></textarea>
 
            </div>
 
            <div style="text-align: left;padding-top: 5px">
 
            ${h.submit('commit',_('Commit Changes'),class_="btn btn-small btn-success")}
 
            ${h.reset('reset',_('Reset'),class_="btn btn-small")}
 
            </div>
 
            ${h.end_form()}
 
        </div>
 
    </div>
 
</div>
 

	
 
<script type="text/javascript">
 
$(document).ready(function(){
 
    var reset_url = "${h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.file.path)}";
 
    var myCodeMirror = initCodeMirror('editor',reset_url);
 
    var myCodeMirror = initCodeMirror('editor', "${request.script_name}", reset_url);
 

	
 
   //inject new modes, based on codeMirrors modeInfo object
 
    $('#set_mode').each(function(){
 
        var modes_select = this;
 
        var index = 1;
 
        for(var i=0;i<CodeMirror.modeInfo.length;i++){
 
            var m = CodeMirror.modeInfo[i];
 
            var opt = new Option(m.name, m.mime);
 
            $(opt).attr('mode', m.mode);
 
            if (m.mime == 'text/plain') {
 
                // default plain text
 
                $(opt).prop('selected', true);
 
                modes_select.options[0] = opt;
 
            } else {
 
                modes_select.options[index++] = opt;
 
            }
 
        }
 
    });
 
    // try to detect the mode based on the file we edit
 
    var detected_mode = CodeMirror.findModeByExtension("${c.file.extension}");
 
    if(detected_mode){
 
        setCodeMirrorMode(myCodeMirror, detected_mode);
 
        $($('#set_mode option[value="'+detected_mode.mime+'"]')[0]).prop('selected', true);
 
    }
kallithea/templates/login.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="base/root.html"/>
 

	
 
<%block name="title">
 
    ${_('Log In')}
 
</%block>
 

	
 
<div id="login" class="panel panel-default">
 
    <%include file="/base/flash_msg.html"/>
 
    <!-- login -->
 
    <div class="panel-heading title withlogo">
 
        %if c.site_name:
 
            <h5>${_('Log In to %s') % c.site_name}</h5>
 
        %else:
 
            <h5>${_('Log In')}</h5>
 
        %endif
 
    </div>
 
    <div class="panel-body inner">
 
        ${h.form(h.url.current(**request.GET))}
 
        ${h.form(url('login_home', came_from=c.came_from))}
 
        <div class="form">
 
            <i class="icon-lock"></i>
 
            <!-- fields -->
 

	
 
            <div class="form-horizontal">
 
                <div class="form-group">
 
                    <label class="control-label col-sm-5" for="username">${_('Username')}:</label>
 
                    <div class="input col-sm-7">
 
                        ${h.text('username',class_='form-control focus large')}
 
                    </div>
 

	
 
                </div>
 
                <div class="form-group">
 
                    <label class="control-label col-sm-5" for="password">${_('Password')}:</label>
 
                    <div class="input col-sm-7">
 
                        ${h.password('password',class_='form-control focus large')}
 
                    </div>
 

	
 
                </div>
 
                <div class="form-group">
 
                    <div class="col-sm-offset-5 col-sm-7">
 
                        <div class="checkbox">
 
                            <label for="remember">
 
                                <input type="checkbox" id="remember" name="remember"/>
kallithea/tests/__init__.py
Show inline comments
 
@@ -69,57 +69,57 @@ log = logging.getLogger(__name__)
 

	
 
__all__ = [
 
    'parameterized', 'environ', 'url', 'TestController',
 
    'SkipTest', 'ldap_lib_installed', 'pam_lib_installed', 'BaseTestCase', 'init_stack',
 
    'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO',
 
    'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
 
    'TEST_USER_ADMIN_EMAIL', 'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
 
    'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
 
    'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
 
    'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
 
    'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO',
 
    'GIT_REMOTE_REPO', 'SCM_TESTS',
 
]
 

	
 
# Invoke websetup with the current config file
 
# SetupCommand('setup-app').run([config_file])
 

	
 
environ = {}
 

	
 
#SOME GLOBALS FOR TESTS
 

	
 
TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
 
TEST_USER_ADMIN_LOGIN = 'test_admin'
 
TEST_USER_ADMIN_PASS = 'test12'
 
TEST_USER_ADMIN_EMAIL = 'test_admin@mail.com'
 
TEST_USER_ADMIN_EMAIL = 'test_admin@example.com'
 

	
 
TEST_USER_REGULAR_LOGIN = 'test_regular'
 
TEST_USER_REGULAR_PASS = 'test12'
 
TEST_USER_REGULAR_EMAIL = 'test_regular@mail.com'
 
TEST_USER_REGULAR_EMAIL = 'test_regular@example.com'
 

	
 
TEST_USER_REGULAR2_LOGIN = 'test_regular2'
 
TEST_USER_REGULAR2_PASS = 'test12'
 
TEST_USER_REGULAR2_EMAIL = 'test_regular2@mail.com'
 
TEST_USER_REGULAR2_EMAIL = 'test_regular2@example.com'
 

	
 
HG_REPO = 'vcs_test_hg'
 
GIT_REPO = 'vcs_test_git'
 

	
 
NEW_HG_REPO = 'vcs_test_hg_new'
 
NEW_GIT_REPO = 'vcs_test_git_new'
 

	
 
HG_FORK = 'vcs_test_hg_fork'
 
GIT_FORK = 'vcs_test_git_fork'
 

	
 
## VCS
 
SCM_TESTS = ['hg', 'git']
 
uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
 

	
 
GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
 

	
 
TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
 
TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix)
 
TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix)
 

	
 

	
 
HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
 

	
 
TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO)
kallithea/tests/api/api_base.py
Show inline comments
 
@@ -531,132 +531,132 @@ class _BaseTestApi(object):
 
    def test_api_get_locks_with_one_locked_repo_for_specific_user(self):
 
        repo_name = 'api_delete_me'
 
        repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
 
                                   cur_user=self.TEST_USER_LOGIN)
 
        Repository.lock(repo, User.get_by_username(self.TEST_USER_LOGIN).user_id)
 
        try:
 
            id_, params = _build_data(self.apikey, 'get_locks',
 
                                      userid=self.TEST_USER_LOGIN)
 
            response = api_call(self, params)
 
            expected = [repo.get_api_data()]
 
            self._compare_ok(id_, expected, given=response.body)
 
        finally:
 
            fixture.destroy_repo(repo_name)
 

	
 
    def test_api_get_locks_with_userid(self):
 
        id_, params = _build_data(self.apikey, 'get_locks',
 
                                  userid=TEST_USER_REGULAR_LOGIN)
 
        response = api_call(self, params)
 
        expected = []
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_create_existing_user(self):
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=TEST_USER_ADMIN_LOGIN,
 
                                  email='test@foo.com',
 
                                  email='test@example.com',
 
                                  password='trololo')
 
        response = api_call(self, params)
 

	
 
        expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_create_user_with_existing_email(self):
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=TEST_USER_ADMIN_LOGIN + 'new',
 
                                  email=TEST_USER_REGULAR_EMAIL,
 
                                  password='trololo')
 
        response = api_call(self, params)
 

	
 
        expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_create_user(self):
 
        username = 'test_new_api_user'
 
        email = username + "@foo.com"
 
        email = username + "@example.com"
 

	
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=username,
 
                                  email=email,
 
                                  password='trololo')
 
        response = api_call(self, params)
 

	
 
        usr = User.get_by_username(username)
 
        ret = dict(
 
            msg='created new user `%s`' % username,
 
            user=jsonify(usr.get_api_data())
 
        )
 

	
 
        try:
 
            expected = ret
 
            self._compare_ok(id_, expected, given=response.body)
 
        finally:
 
            fixture.destroy_user(usr.user_id)
 

	
 
    def test_api_create_user_without_password(self):
 
        username = 'test_new_api_user_passwordless'
 
        email = username + "@foo.com"
 
        email = username + "@example.com"
 

	
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=username,
 
                                  email=email)
 
        response = api_call(self, params)
 

	
 
        usr = User.get_by_username(username)
 
        ret = dict(
 
            msg='created new user `%s`' % username,
 
            user=jsonify(usr.get_api_data())
 
        )
 
        try:
 
            expected = ret
 
            self._compare_ok(id_, expected, given=response.body)
 
        finally:
 
            fixture.destroy_user(usr.user_id)
 

	
 
    def test_api_create_user_with_extern_name(self):
 
        username = 'test_new_api_user_passwordless'
 
        email = username + "@foo.com"
 
        email = username + "@example.com"
 

	
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=username,
 
                                  email=email, extern_name='internal')
 
        response = api_call(self, params)
 

	
 
        usr = User.get_by_username(username)
 
        ret = dict(
 
            msg='created new user `%s`' % username,
 
            user=jsonify(usr.get_api_data())
 
        )
 
        try:
 
            expected = ret
 
            self._compare_ok(id_, expected, given=response.body)
 
        finally:
 
            fixture.destroy_user(usr.user_id)
 

	
 
    @mock.patch.object(UserModel, 'create_or_update', crash)
 
    def test_api_create_user_when_exception_happened(self):
 

	
 
        username = 'test_new_api_user'
 
        email = username + "@foo.com"
 
        email = username + "@example.com"
 

	
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=username,
 
                                  email=email,
 
                                  password='trololo')
 
        response = api_call(self, params)
 
        expected = 'failed to create user `%s`' % username
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_delete_user(self):
 
        usr = UserModel().create_or_update(username=u'test_user',
 
                                           password=u'qweqwe',
 
                                           email=u'u232@example.com',
 
                                           firstname=u'u1', lastname=u'u1')
 
        Session().commit()
 
        username = usr.username
 
        email = usr.email
 
        usr_id = usr.user_id
 
        ## DELETE THIS USER NOW
 

	
 
        id_, params = _build_data(self.apikey, 'delete_user',
 
                                  userid=username, )
 
        response = api_call(self, params)
 

	
 
@@ -1117,49 +1117,49 @@ class _BaseTestApi(object):
 
        id_, params = _build_data(self.apikey, 'create_repo',
 
                                  repo_name=repo_name,
 
                                  owner=TEST_USER_ADMIN_LOGIN,
 
                                  repo_type=self.REPO_TYPE,)
 
        response = api_call(self, params)
 
        expected = "repo `%s` already exist" % repo_name
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(RepoModel, 'create', crash)
 
    def test_api_create_repo_exception_occurred(self):
 
        repo_name = 'api-repo'
 
        id_, params = _build_data(self.apikey, 'create_repo',
 
                                  repo_name=repo_name,
 
                                  owner=TEST_USER_ADMIN_LOGIN,
 
                                  repo_type=self.REPO_TYPE,)
 
        response = api_call(self, params)
 
        expected = 'failed to create repository `%s`' % repo_name
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    @parameterized.expand([
 
        ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
 
        ('description', {'description': 'new description'}),
 
        ('active', {'active': True}),
 
        ('active', {'active': False}),
 
        ('clone_uri', {'clone_uri': 'http://foo.com/repo'}),
 
        ('clone_uri', {'clone_uri': 'http://example.com/repo'}),
 
        ('clone_uri', {'clone_uri': None}),
 
        ('landing_rev', {'landing_rev': 'branch:master'}),
 
        ('enable_statistics', {'enable_statistics': True}),
 
        ('enable_locking', {'enable_locking': True}),
 
        ('enable_downloads', {'enable_downloads': True}),
 
        ('name', {'name': 'new_repo_name'}),
 
        ('repo_group', {'group': 'test_group_for_update'}),
 
    ])
 
    def test_api_update_repo(self, changing_attr, updates):
 
        repo_name = 'api_update_me'
 
        repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
 
        if changing_attr == 'repo_group':
 
            fixture.create_repo_group(updates['group'])
 

	
 
        id_, params = _build_data(self.apikey, 'update_repo',
 
                                  repoid=repo_name, **updates)
 
        response = api_call(self, params)
 
        if changing_attr == 'name':
 
            repo_name = updates['name']
 
        if changing_attr == 'repo_group':
 
            repo_name = '/'.join([updates['group'], repo_name])
 
        try:
 
            expected = {
 
                'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
kallithea/tests/functional/test_admin_users.py
Show inline comments
 
@@ -26,121 +26,121 @@ from kallithea.model.meta import Session
 
fixture = Fixture()
 

	
 

	
 
class TestAdminUsersController(TestController):
 
    test_user_1 = 'testme'
 

	
 
    @classmethod
 
    def teardown_class(cls):
 
        if User.get_by_username(cls.test_user_1):
 
            UserModel().delete(cls.test_user_1)
 
            Session().commit()
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(url('users'))
 
        # Test response...
 

	
 
    def test_create(self):
 
        self.log_user()
 
        username = 'newtestuser'
 
        password = 'test12'
 
        password_confirmation = password
 
        name = 'name'
 
        lastname = 'lastname'
 
        email = 'mail@mail.com'
 
        email = 'mail@example.com'
 

	
 
        response = self.app.post(url('users'),
 
            {'username': username,
 
             'password': password,
 
             'password_confirmation': password_confirmation,
 
             'firstname': name,
 
             'active': True,
 
             'lastname': lastname,
 
             'extern_name': 'internal',
 
             'extern_type': 'internal',
 
             'email': email,
 
             '_authentication_token': self.authentication_token()})
 

	
 
        self.checkSessionFlash(response, '''Created user <a href="/_admin/users/''')
 
        self.checkSessionFlash(response, '''/edit">%s</a>''' % (username))
 

	
 
        new_user = Session().query(User).\
 
            filter(User.username == username).one()
 

	
 
        self.assertEqual(new_user.username, username)
 
        self.assertEqual(check_password(password, new_user.password), True)
 
        self.assertEqual(new_user.name, name)
 
        self.assertEqual(new_user.lastname, lastname)
 
        self.assertEqual(new_user.email, email)
 

	
 
        response.follow()
 
        response = response.follow()
 
        response.mustcontain("""newtestuser""")
 

	
 
    def test_create_err(self):
 
        self.log_user()
 
        username = 'new_user'
 
        password = ''
 
        name = 'name'
 
        lastname = 'lastname'
 
        email = 'errmail.com'
 
        email = 'errmail.example.com'
 

	
 
        response = self.app.post(url('users'), {'username': username,
 
                                               'password': password,
 
                                               'name': name,
 
                                               'active': False,
 
                                               'lastname': lastname,
 
                                               'email': email,
 
                                               '_authentication_token': self.authentication_token()})
 

	
 
        msg = validators.ValidUsername(False, {})._messages['system_invalid_username']
 
        msg = h.html_escape(msg % {'username': 'new_user'})
 
        response.mustcontain("""<span class="error-message">%s</span>""" % msg)
 
        response.mustcontain("""<span class="error-message">Please enter a value</span>""")
 
        response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""")
 

	
 
        def get_user():
 
            Session().query(User).filter(User.username == username).one()
 

	
 
        self.assertRaises(NoResultFound, get_user), 'found user in database'
 

	
 
    def test_new(self):
 
        self.log_user()
 
        response = self.app.get(url('new_user'))
 

	
 
    @parameterized.expand(
 
        [('firstname', {'firstname': 'new_username'}),
 
         ('lastname', {'lastname': 'new_username'}),
 
         ('admin', {'admin': True}),
 
         ('admin', {'admin': False}),
 
         ('extern_type', {'extern_type': 'ldap'}),
 
         ('extern_type', {'extern_type': None}),
 
         ('extern_name', {'extern_name': 'test'}),
 
         ('extern_name', {'extern_name': None}),
 
         ('active', {'active': False}),
 
         ('active', {'active': True}),
 
         ('email', {'email': 'some@email.com'}),
 
         ('email', {'email': 'someemail@example.com'}),
 
        # ('new_password', {'new_password': 'foobar123',
 
        #                   'password_confirmation': 'foobar123'})
 
        ])
 
    def test_update(self, name, attrs):
 
        self.log_user()
 
        usr = fixture.create_user(self.test_user_1, password='qweqwe',
 
                                  email='testme@example.com',
 
                                  extern_type='internal',
 
                                  extern_name=self.test_user_1,
 
                                  skip_if_exists=True)
 
        Session().commit()
 
        params = usr.get_api_data(True)
 
        params.update({'password_confirmation': ''})
 
        params.update({'new_password': ''})
 
        params.update(attrs)
 
        if name == 'email':
 
            params['emails'] = [attrs['email']]
 
        if name == 'extern_type':
 
            #cannot update this via form, expected value is original one
 
            params['extern_type'] = "internal"
 
        if name == 'extern_name':
 
            #cannot update this via form, expected value is original one
 
            params['extern_name'] = self.test_user_1
 
            # special case since this user is not
kallithea/tests/functional/test_files.py
Show inline comments
 
@@ -76,49 +76,49 @@ class TestFilesController(TestController
 

	
 
    def test_index_paging(self):
 
        self.log_user()
 

	
 
        for r in [(73, 'a066b25d5df7016b45a41b7e2a78c33b57adc235'),
 
                  (92, 'cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e'),
 
                  (109, '75feb4c33e81186c87eac740cee2447330288412'),
 
                  (1, '3d8f361e72ab303da48d799ff1ac40d5ac37c67e'),
 
                  (0, 'b986218ba1c9b0d6a259fac9b050b1724ed8e545')]:
 

	
 
            response = self.app.get(url(controller='files', action='index',
 
                                    repo_name=HG_REPO,
 
                                    revision=r[1],
 
                                    f_path='/'))
 

	
 
            response.mustcontain("""@ r%s:%s""" % (r[0], r[1][:12]))
 

	
 
    def test_file_source(self):
 
        self.log_user()
 
        response = self.app.get(url(controller='files', action='index',
 
                                    repo_name=HG_REPO,
 
                                    revision='8911406ad776fdd3d0b9932a2e89677e57405a48',
 
                                    f_path='vcs/nodes.py'))
 

	
 
        response.mustcontain("""<div class="commit">Partially implemented <a class="issue-tracker-link" href="https://myissueserver.com/vcs_test_hg/issue/16">#16</a>. filecontent/commit message/author/node name are safe_unicode now.
 
        response.mustcontain("""<div class="commit">Partially implemented <a class="issue-tracker-link" href="https://issues.example.com/vcs_test_hg/issue/16">#16</a>. filecontent/commit message/author/node name are safe_unicode now.
 
In addition some other __str__ are unicode as well
 
Added test for unicode
 
Improved test to clone into uniq repository.
 
removed extra unicode conversion in diff.</div>
 
""")
 

	
 
        response.mustcontain("""<option selected="selected" value="8911406ad776fdd3d0b9932a2e89677e57405a48">default at 8911406ad776</option>""")
 

	
 
    def test_file_source_history(self):
 
        self.log_user()
 
        response = self.app.get(url(controller='files', action='history',
 
                                    repo_name=HG_REPO,
 
                                    revision='tip',
 
                                    f_path='vcs/nodes.py'),
 
                                extra_environ={'HTTP_X_PARTIAL_XHR': '1'},)
 
        self.assertEqual(response.body, HG_NODE_HISTORY)
 

	
 
    def test_file_source_history_git(self):
 
        self.log_user()
 
        response = self.app.get(url(controller='files', action='history',
 
                                    repo_name=GIT_REPO,
 
                                    revision='master',
 
                                    f_path='vcs/nodes.py'),
 
                                extra_environ={'HTTP_X_PARTIAL_XHR': '1'},)
kallithea/tests/functional/test_login.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
import re
 
import time
 
import urlparse
 

	
 
import mock
 

	
 
from kallithea.tests import *
 
from kallithea.tests.fixture import Fixture
 
from kallithea.lib.utils2 import generate_api_key
 
from kallithea.lib.auth import check_password
 
from kallithea.lib import helpers as h
 
from kallithea.model.api_key import ApiKeyModel
 
from kallithea.model import validators
 
from kallithea.model.db import User, Notification
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestLoginController(TestController):
 
    def setUp(self):
 
        self.remove_all_notifications()
 
        self.assertEqual(Notification.query().all(), [])
 

	
 
    def test_index(self):
 
        response = self.app.get(url(controller='login', action='index'))
 
@@ -82,151 +83,151 @@ class TestLoginController(TestController
 
        for cookie in response.headers.getall('Set-Cookie'):
 
            self.assertTrue(re.search(r';\s+(Max-Age|Expires)=', cookie, re.IGNORECASE),
 
                'Cookie %r should have expiration date, but is a session cookie' % cookie)
 

	
 
    def test_logout(self):
 
        response = self.app.post(url(controller='login', action='index'),
 
                                 {'username': TEST_USER_REGULAR_LOGIN,
 
                                  'password': TEST_USER_REGULAR_PASS})
 

	
 
        # Verify that a login session has been established.
 
        response = self.app.get(url(controller='login', action='index'))
 
        response = response.follow()
 
        self.assertIn('authuser', response.session)
 

	
 
        response.click('Log Out')
 

	
 
        # Verify that the login session has been terminated.
 
        response = self.app.get(url(controller='login', action='index'))
 
        self.assertNotIn('authuser', response.session)
 

	
 
    @parameterized.expand([
 
          ('data:text/html,<script>window.alert("xss")</script>',),
 
          ('mailto:test@example.com',),
 
          ('file:///etc/passwd',),
 
          ('ftp://some.ftp.server',),
 
          ('http://other.domain/bl%C3%A5b%C3%A6rgr%C3%B8d',),
 
          ('ftp://ftp.example.com',),
 
          ('http://other.example.com/bl%C3%A5b%C3%A6rgr%C3%B8d',),
 
          ('//evil.example.com/',),
 
          ('/\r\nX-Header-Injection: boo',),
 
          ('/invälid_url_bytes',),
 
          ('non-absolute-path',),
 
    ])
 
    def test_login_bad_came_froms(self, url_came_from):
 
        response = self.app.post(url(controller='login', action='index',
 
                                     came_from=url_came_from),
 
                                 {'username': TEST_USER_ADMIN_LOGIN,
 
                                  'password': TEST_USER_ADMIN_PASS})
 
        self.assertEqual(response.status, '302 Found')
 
        self.assertEqual(response._environ['paste.testing_variables']
 
                         ['tmpl_context'].came_from, '/')
 
        response = response.follow()
 

	
 
        self.assertEqual(response.status, '200 OK')
 
                                  'password': TEST_USER_ADMIN_PASS},
 
                                 status=400)
 

	
 
    def test_login_short_password(self):
 
        response = self.app.post(url(controller='login', action='index'),
 
                                 {'username': TEST_USER_ADMIN_LOGIN,
 
                                  'password': 'as'})
 
        self.assertEqual(response.status, '200 OK')
 

	
 
        response.mustcontain('Enter 3 characters or more')
 

	
 
    def test_login_wrong_username_password(self):
 
        response = self.app.post(url(controller='login', action='index'),
 
                                 {'username': 'error',
 
                                  'password': 'test12'})
 

	
 
        response.mustcontain('Invalid username or password')
 

	
 
    # verify that get arguments are correctly passed along login redirection
 

	
 
    @parameterized.expand([
 
        ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
 
        ({'foo':'one', 'bar':'two'}, (('foo', 'one'), ('bar', 'two'))),
 
        ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
 
             ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
 
             (('blue', u'blå'.encode('utf-8')), ('green', u'grøn'.encode('utf-8')))),
 
    ])
 
    def test_redirection_to_login_form_preserves_get_args(self, args, args_encoded):
 
        with fixture.anon_access(False):
 
            response = self.app.get(url(controller='summary', action='index',
 
                                        repo_name=HG_REPO,
 
                                        **args))
 
            self.assertEqual(response.status, '302 Found')
 
            came_from = urlparse.parse_qs(urlparse.urlparse(response.location).query)['came_from'][0]
 
            came_from_qs = urlparse.parse_qsl(urlparse.urlparse(came_from).query)
 
            for encoded in args_encoded:
 
                self.assertIn(encoded, response.location)
 
                self.assertIn(encoded, came_from_qs)
 

	
 
    @parameterized.expand([
 
        ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
 
        ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
 
        ({'blue': u'blå', 'green':u'grøn'},
 
             ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
 
    ])
 
    def test_login_form_preserves_get_args(self, args, args_encoded):
 
        response = self.app.get(url(controller='login', action='index',
 
                                    came_from = '/_admin/users',
 
                                    **args))
 
                                    came_from=url('/_admin/users', **args)))
 
        came_from = urlparse.parse_qs(urlparse.urlparse(response.form.action).query)['came_from'][0]
 
        for encoded in args_encoded:
 
            self.assertIn(encoded, response.form.action)
 
            self.assertIn(encoded, came_from)
 

	
 
    @parameterized.expand([
 
        ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
 
        ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
 
        ({'blue': u'blå', 'green':u'grøn'},
 
             ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
 
    ])
 
    def test_redirection_after_successful_login_preserves_get_args(self, args, args_encoded):
 
        response = self.app.post(url(controller='login', action='index',
 
                                     came_from = '/_admin/users',
 
                                     **args),
 
                                     came_from = url('/_admin/users', **args)),
 
                                 {'username': TEST_USER_ADMIN_LOGIN,
 
                                  'password': TEST_USER_ADMIN_PASS})
 
        self.assertEqual(response.status, '302 Found')
 
        for encoded in args_encoded:
 
            self.assertIn(encoded, response.location)
 

	
 
    @parameterized.expand([
 
        ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
 
        ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
 
        ({'blue': u'blå', 'green':u'grøn'},
 
             ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
 
    ])
 
    def test_login_form_after_incorrect_login_preserves_get_args(self, args, args_encoded):
 
        response = self.app.post(url(controller='login', action='index',
 
                                     came_from = '/_admin/users',
 
                                     **args),
 
                                     came_from=url('/_admin/users', **args)),
 
                                 {'username': 'error',
 
                                  'password': 'test12'})
 

	
 
        response.mustcontain('Invalid username or password')
 
        came_from = urlparse.parse_qs(urlparse.urlparse(response.form.action).query)['came_from'][0]
 
        for encoded in args_encoded:
 
            self.assertIn(encoded, response.form.action)
 
            self.assertIn(encoded, came_from)
 

	
 
    #==========================================================================
 
    # REGISTRATIONS
 
    #==========================================================================
 
    def test_register(self):
 
        response = self.app.get(url(controller='login', action='register'))
 
        response.mustcontain('Sign Up')
 

	
 
    def test_register_err_same_username(self):
 
        uname = TEST_USER_ADMIN_LOGIN
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username': uname,
 
                                             'password': 'test12',
 
                                             'password_confirmation': 'test12',
 
                                             'email': 'goodmail@domain.com',
 
                                             'email': 'goodmail@example.com',
 
                                             'firstname': 'test',
 
                                             'lastname': 'test'})
 

	
 
        msg = validators.ValidUsername()._messages['username_exists']
 
        msg = h.html_escape(msg % {'username': uname})
 
        response.mustcontain(msg)
 

	
 
    def test_register_err_same_email(self):
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username': 'test_admin_0',
 
                                             'password': 'test12',
 
                                             'password_confirmation': 'test12',
 
                                             'email': TEST_USER_ADMIN_EMAIL,
 
                                             'firstname': 'test',
 
                                             'lastname': 'test'})
 

	
 
        msg = validators.UniqSystemEmail()()._messages['email_taken']
 
        response.mustcontain(msg)
 

	
 
    def test_register_err_same_email_case_sensitive(self):
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username': 'test_admin_1',
 
                                             'password': 'test12',
 
                                             'password_confirmation': 'test12',
 
@@ -283,93 +284,93 @@ class TestLoginController(TestController
 
                                        {'username': 'xxxaxn',
 
                                         'password': 'ąćźżąśśśś',
 
                                         'password_confirmation': 'ąćźżąśśśś',
 
                                         'email': 'goodmailm@test.plx',
 
                                         'firstname': 'test',
 
                                         'lastname': 'test'})
 

	
 
        msg = validators.ValidPassword()._messages['invalid_password']
 
        response.mustcontain(msg)
 

	
 
    def test_register_password_mismatch(self):
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username': 'xs',
 
                                             'password': '123qwe',
 
                                             'password_confirmation': 'qwe123',
 
                                             'email': 'goodmailm@test.plxa',
 
                                             'firstname': 'test',
 
                                             'lastname': 'test'})
 
        msg = validators.ValidPasswordsMatch('password', 'password_confirmation')._messages['password_mismatch']
 
        response.mustcontain(msg)
 

	
 
    def test_register_ok(self):
 
        username = 'test_regular4'
 
        password = 'qweqwe'
 
        email = 'username@test.com'
 
        email = 'user4@example.com'
 
        name = 'testname'
 
        lastname = 'testlastname'
 

	
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username': username,
 
                                             'password': password,
 
                                             'password_confirmation': password,
 
                                             'email': email,
 
                                             'firstname': name,
 
                                             'lastname': lastname,
 
                                             'admin': True})  # This should be overriden
 
        self.assertEqual(response.status, '302 Found')
 
        self.checkSessionFlash(response, 'You have successfully registered into Kallithea')
 

	
 
        ret = Session().query(User).filter(User.username == 'test_regular4').one()
 
        self.assertEqual(ret.username, username)
 
        self.assertEqual(check_password(password, ret.password), True)
 
        self.assertEqual(ret.email, email)
 
        self.assertEqual(ret.name, name)
 
        self.assertEqual(ret.lastname, lastname)
 
        self.assertNotEqual(ret.api_key, None)
 
        self.assertEqual(ret.admin, False)
 

	
 
    #==========================================================================
 
    # PASSWORD RESET
 
    #==========================================================================
 

	
 
    def test_forgot_password_wrong_mail(self):
 
        bad_email = 'username%wrongmail.org'
 
        response = self.app.post(
 
                        url(controller='login', action='password_reset'),
 
                            {'email': bad_email, }
 
        )
 

	
 
        response.mustcontain('An email address must contain a single @')
 

	
 
    def test_forgot_password(self):
 
        response = self.app.get(url(controller='login',
 
                                    action='password_reset'))
 
        self.assertEqual(response.status, '200 OK')
 

	
 
        username = 'test_password_reset_1'
 
        password = 'qweqwe'
 
        email = 'username@python-works.com'
 
        email = 'username@example.com'
 
        name = 'passwd'
 
        lastname = 'reset'
 
        timestamp = int(time.time())
 

	
 
        new = User()
 
        new.username = username
 
        new.password = password
 
        new.email = email
 
        new.name = name
 
        new.lastname = lastname
 
        new.api_key = generate_api_key()
 
        Session().add(new)
 
        Session().commit()
 

	
 
        response = self.app.post(url(controller='login',
 
                                     action='password_reset'),
 
                                 {'email': email, })
 

	
 
        self.checkSessionFlash(response, 'A password reset confirmation code has been sent')
 

	
 
        response = response.follow()
 

	
 
        # BAD TOKEN
 

	
kallithea/tests/functional/test_my_account.py
Show inline comments
 
@@ -46,79 +46,79 @@ class TestMyAccountController(TestContro
 
        response.mustcontain('No additional emails specified')
 

	
 
    def test_my_account_my_emails_add_existing_email(self):
 
        self.log_user()
 
        response = self.app.get(url('my_account_emails'))
 
        response.mustcontain('No additional emails specified')
 
        response = self.app.post(url('my_account_emails'),
 
                                 {'new_email': TEST_USER_REGULAR_EMAIL, '_authentication_token': self.authentication_token()})
 
        self.checkSessionFlash(response, 'This email address is already in use')
 

	
 
    def test_my_account_my_emails_add_mising_email_in_form(self):
 
        self.log_user()
 
        response = self.app.get(url('my_account_emails'))
 
        response.mustcontain('No additional emails specified')
 
        response = self.app.post(url('my_account_emails'),
 
            {'_authentication_token': self.authentication_token()})
 
        self.checkSessionFlash(response, 'Please enter an email address')
 

	
 
    def test_my_account_my_emails_add_remove(self):
 
        self.log_user()
 
        response = self.app.get(url('my_account_emails'))
 
        response.mustcontain('No additional emails specified')
 

	
 
        response = self.app.post(url('my_account_emails'),
 
                                 {'new_email': 'foo@barz.com', '_authentication_token': self.authentication_token()})
 
                                 {'new_email': 'barz@example.com', '_authentication_token': self.authentication_token()})
 

	
 
        response = self.app.get(url('my_account_emails'))
 

	
 
        from kallithea.model.db import UserEmailMap
 
        email_id = UserEmailMap.query()\
 
            .filter(UserEmailMap.user == User.get_by_username(TEST_USER_ADMIN_LOGIN))\
 
            .filter(UserEmailMap.email == 'foo@barz.com').one().email_id
 
            .filter(UserEmailMap.email == 'barz@example.com').one().email_id
 

	
 
        response.mustcontain('foo@barz.com')
 
        response.mustcontain('barz@example.com')
 
        response.mustcontain('<input id="del_email_id" name="del_email_id" type="hidden" value="%s" />' % email_id)
 

	
 
        response = self.app.post(url('my_account_emails'),
 
                                 {'del_email_id': email_id, '_method': 'delete', '_authentication_token': self.authentication_token()})
 
        self.checkSessionFlash(response, 'Removed email from user')
 
        response = self.app.get(url('my_account_emails'))
 
        response.mustcontain('No additional emails specified')
 

	
 

	
 
    @parameterized.expand(
 
        [('firstname', {'firstname': 'new_username'}),
 
         ('lastname', {'lastname': 'new_username'}),
 
         ('admin', {'admin': True}),
 
         ('admin', {'admin': False}),
 
         ('extern_type', {'extern_type': 'ldap'}),
 
         ('extern_type', {'extern_type': None}),
 
         #('extern_name', {'extern_name': 'test'}),
 
         #('extern_name', {'extern_name': None}),
 
         ('active', {'active': False}),
 
         ('active', {'active': True}),
 
         ('email', {'email': 'some@email.com'}),
 
         ('email', {'email': 'someemail@example.com'}),
 
        # ('new_password', {'new_password': 'foobar123',
 
        #                   'password_confirmation': 'foobar123'})
 
        ])
 
    def test_my_account_update(self, name, attrs):
 
        usr = fixture.create_user(self.test_user_1, password='qweqwe',
 
                                  email='testme@example.com',
 
                                  extern_type='internal',
 
                                  extern_name=self.test_user_1,
 
                                  skip_if_exists=True)
 
        params = usr.get_api_data(True)  # current user data
 
        user_id = usr.user_id
 
        self.log_user(username=self.test_user_1, password='qweqwe')
 

	
 
        params.update({'password_confirmation': ''})
 
        params.update({'new_password': ''})
 
        params.update({'extern_type': 'internal'})
 
        params.update({'extern_name': self.test_user_1})
 
        params.update({'_authentication_token': self.authentication_token()})
 

	
 
        params.update(attrs)
 
        response = self.app.post(url('my_account'), params)
 

	
 
        self.checkSessionFlash(response,
 
                               'Your account was updated successfully')
kallithea/tests/other/manual_test_vcs_operations.py
Show inline comments
 
@@ -91,55 +91,55 @@ def _construct_url(repo, dest=None, **kw
 
        _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s %(dest)s' % params
 
    else:
 
        _url = 'http://(host)s/%(cloned_repo)s %(dest)s' % params
 
    return _url
 

	
 

	
 
def _add_files_and_push(vcs, DEST, **kwargs):
 
    """
 
    Generate some files, add it to DEST repo and push back
 
    vcs is git or hg and defines what VCS we want to make those files for
 

	
 
    :param vcs:
 
    :param DEST:
 
    """
 
    # commit some stuff into this repo
 
    cwd = path = jn(DEST)
 
    #added_file = jn(path, '%ssetupążźć.py' % _RandomNameSequence().next())
 
    added_file = jn(path, '%ssetup.py' % _RandomNameSequence().next())
 
    Command(cwd).execute('touch %s' % added_file)
 
    Command(cwd).execute('%s add %s' % (vcs, added_file))
 

	
 
    for i in xrange(kwargs.get('files_no', 3)):
 
        cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
 
        Command(cwd).execute(cmd)
 
        author_str = 'User ǝɯɐᴎ <me@email.com>'
 
        author_str = 'User ǝɯɐᴎ <me@example.com>'
 
        if vcs == 'hg':
 
            cmd = """hg commit -m 'commited new %s' -u '%s' %s """ % (
 
                i, author_str, added_file
 
            )
 
        elif vcs == 'git':
 
            cmd = """EMAIL="me@email.com" git commit -m 'commited new %s' --author '%s' %s """ % (
 
            cmd = """EMAIL="me@example.com" git commit -m 'commited new %s' --author '%s' %s """ % (
 
                i, author_str, added_file
 
            )
 
        Command(cwd).execute(cmd)
 

	
 
    # PUSH it back
 
    _REPO = None
 
    if vcs == 'hg':
 
        _REPO = HG_REPO
 
    elif vcs == 'git':
 
        _REPO = GIT_REPO
 

	
 
    kwargs['dest'] = ''
 
    clone_url = _construct_url(_REPO, **kwargs)
 
    if 'clone_url' in kwargs:
 
        clone_url = kwargs['clone_url']
 
    stdout = stderr = None
 
    if vcs == 'hg':
 
        stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
 
    elif vcs == 'git':
 
        stdout, stderr = Command(cwd).execute('git push --verbose', clone_url + " master")
 

	
 
    return stdout, stderr
 

	
 

	
kallithea/tests/other/test_libs.py
Show inline comments
 
@@ -21,115 +21,115 @@ This file was forked by the Kallithea pr
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Jun 9, 2011
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import datetime
 
import hashlib
 
import mock
 
from kallithea.tests import *
 
from kallithea.lib.utils2 import AttributeDict
 
from kallithea.model.db import Repository
 

	
 
proto = 'http'
 
TEST_URLS = [
 
    ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://username@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://username:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
 
     '%s://127.0.0.1:8080' % proto),
 
    ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
 
     '%s://domain.org' % proto),
 
    ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
 
    ('%s://example.com' % proto, ['%s://' % proto, 'example.com'],
 
     '%s://example.com' % proto),
 
    ('%s://user:pass@example.com:8080' % proto, ['%s://' % proto, 'example.com',
 
                                                '8080'],
 
     '%s://domain.org:8080' % proto),
 
     '%s://example.com:8080' % proto),
 
]
 

	
 
proto = 'https'
 
TEST_URLS += [
 
    ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://username@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://username:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
 
     '%s://127.0.0.1:8080' % proto),
 
    ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
 
     '%s://domain.org' % proto),
 
    ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
 
    ('%s://example.com' % proto, ['%s://' % proto, 'example.com'],
 
     '%s://example.com' % proto),
 
    ('%s://user:pass@example.com:8080' % proto, ['%s://' % proto, 'example.com',
 
                                                '8080'],
 
     '%s://domain.org:8080' % proto),
 
     '%s://example.com:8080' % proto),
 
]
 

	
 

	
 
class TestLibs(BaseTestCase):
 

	
 
    @parameterized.expand(TEST_URLS)
 
    def test_uri_filter(self, test_url, expected, expected_creds):
 
        from kallithea.lib.utils2 import uri_filter
 
        self.assertEqual(uri_filter(test_url), expected)
 

	
 
    @parameterized.expand(TEST_URLS)
 
    def test_credentials_filter(self, test_url, expected, expected_creds):
 
        from kallithea.lib.utils2 import credentials_filter
 
        self.assertEqual(credentials_filter(test_url), expected_creds)
 

	
 
    @parameterized.expand([('t', True),
 
                           ('true', True),
 
                           ('y', True),
 
                           ('yes', True),
 
                           ('on', True),
 
                           ('1', True),
 
                           ('Y', True),
 
                           ('yeS', True),
 
                           ('Y', True),
 
                           ('TRUE', True),
 
                           ('T', True),
 
                           ('False', False),
 
                           ('F', False),
 
                           ('FALSE', False),
 
                           ('0', False),
 
                           ('-1', False),
 
                           ('', False)
 
    ])
 
    def test_str2bool(self, str_bool, expected):
 
        from kallithea.lib.utils2 import str2bool
 
        self.assertEqual(str2bool(str_bool), expected)
 

	
 
    def test_mention_extractor(self):
 
        from kallithea.lib.utils2 import extract_mentioned_users
 
        sample = (
 
            "@first hi there @world here's my email username@email.com "
 
            "@first hi there @world here's my email username@example.com "
 
            "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three "
 
            "@UPPER    @cAmEL @2one_more22 @john please see this http://org.pl "
 
            "@marian.user just do it @marco-polo and next extract @marco_polo "
 
            "user.dot  hej ! not-needed maril@domain.org"
 
            "user.dot  hej ! not-needed maril@example.com"
 
        )
 

	
 
        s = sorted([
 
            '2one_more22', 'first', 'lukaszb', 'one', 'one_more22', 'UPPER', 'cAmEL', 'john',
 
            'marian.user', 'marco-polo', 'marco_polo', 'world'], key=lambda k: k.lower())
 
        self.assertEqual(s, extract_mentioned_users(sample))
 

	
 
    @parameterized.expand([
 
        (dict(), u'just now'),
 
        (dict(seconds= -1), u'1 second ago'),
 
        (dict(seconds= -60 * 2), u'2 minutes ago'),
 
        (dict(hours= -1), u'1 hour ago'),
 
        (dict(hours= -24), u'1 day ago'),
 
        (dict(hours= -24 * 5), u'5 days ago'),
 
        (dict(months= -1), u'1 month ago'),
 
        (dict(months= -1, days= -2), u'1 month and 2 days ago'),
 
        (dict(months= -1, days= -20), u'1 month and 19 days ago'),
 
        (dict(years= -1, months= -1), u'1 year and 1 month ago'),
 
        (dict(years= -1, months= -10), u'1 year and 10 months ago'),
 
        (dict(years= -2, months= -4), u'2 years and 4 months ago'),
 
        (dict(years= -2, months= -11), u'2 years and 11 months ago'),
 
        (dict(years= -3, months= -2), u'3 years and 2 months ago'),
 
    ])
 
    def test_age(self, age_args, expected):
 
@@ -163,127 +163,127 @@ class TestLibs(BaseTestCase):
 
        delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
 
        self.assertEqual(age(n + delt(**age_args), show_short_version=True, now=n), expected)
 

	
 
    @parameterized.expand([
 
        (dict(), u'just now'),
 
        (dict(seconds=1), u'in 1 second'),
 
        (dict(seconds=60 * 2), u'in 2 minutes'),
 
        (dict(hours=1), u'in 1 hour'),
 
        (dict(hours=24), u'in 1 day'),
 
        (dict(hours=24 * 5), u'in 5 days'),
 
        (dict(months=1), u'in 1 month'),
 
        (dict(months=1, days=1), u'in 1 month and 1 day'),
 
        (dict(years=1, months=1), u'in 1 year and 1 month')
 
    ])
 
    def test_age_in_future(self, age_args, expected):
 
        from kallithea.lib.utils2 import age
 
        from dateutil import relativedelta
 
        n = datetime.datetime(year=2012, month=5, day=17)
 
        delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
 
        self.assertEqual(age(n + delt(**age_args), now=n), expected)
 

	
 
    def test_tag_exctrator(self):
 
        sample = (
 
            "hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
 
            "[requires] [stale] [see<>=>] [see => http://url.com]"
 
            "[requires] [stale] [see<>=>] [see => http://example.com]"
 
            "[requires => url] [lang => python] [just a tag]"
 
            "[,d] [ => ULR ] [obsolete] [desc]]"
 
        )
 
        from kallithea.lib.helpers import urlify_text
 
        res = urlify_text(sample, stylize=True)
 
        self.assertIn('<div class="metatag" tag="tag">tag</div>', res)
 
        self.assertIn('<div class="metatag" tag="obsolete">obsolete</div>', res)
 
        self.assertIn('<div class="metatag" tag="stale">stale</div>', res)
 
        self.assertIn('<div class="metatag" tag="lang">python</div>', res)
 
        self.assertIn('<div class="metatag" tag="requires">requires =&gt; <a href="/url">url</a></div>', res)
 
        self.assertIn('<div class="metatag" tag="tag">tag</div>', res)
 

	
 
    def test_alternative_gravatar(self):
 
        from kallithea.lib.helpers import gravatar_url
 
        _md5 = lambda s: hashlib.md5(s).hexdigest()
 

	
 
        #mock pylons.url
 
        class fake_url(object):
 
            @classmethod
 
            def current(cls, *args, **kwargs):
 
                return 'https://server.com'
 
                return 'https://example.com'
 

	
 
        #mock pylons.tmpl_context
 
        def fake_tmpl_context(_url):
 
            _c = AttributeDict()
 
            _c.visual = AttributeDict()
 
            _c.visual.use_gravatar = True
 
            _c.visual.gravatar_url = _url
 

	
 
            return _c
 

	
 

	
 
        with mock.patch('pylons.url', fake_url):
 
            fake = fake_tmpl_context(_url='http://test.com/{email}')
 
            fake = fake_tmpl_context(_url='http://example.com/{email}')
 
            with mock.patch('pylons.tmpl_context', fake):
 
                    from pylons import url
 
                    assert url.current() == 'https://server.com'
 
                    grav = gravatar_url(email_address='test@foo.com', size=24)
 
                    assert grav == 'http://test.com/test@foo.com'
 
                    assert url.current() == 'https://example.com'
 
                    grav = gravatar_url(email_address='test@example.com', size=24)
 
                    assert grav == 'http://example.com/test@example.com'
 

	
 
            fake = fake_tmpl_context(_url='http://test.com/{email}')
 
            fake = fake_tmpl_context(_url='http://example.com/{email}')
 
            with mock.patch('pylons.tmpl_context', fake):
 
                grav = gravatar_url(email_address='test@foo.com', size=24)
 
                assert grav == 'http://test.com/test@foo.com'
 
                grav = gravatar_url(email_address='test@example.com', size=24)
 
                assert grav == 'http://example.com/test@example.com'
 

	
 
            fake = fake_tmpl_context(_url='http://test.com/{md5email}')
 
            fake = fake_tmpl_context(_url='http://example.com/{md5email}')
 
            with mock.patch('pylons.tmpl_context', fake):
 
                em = 'test@foo.com'
 
                em = 'test@example.com'
 
                grav = gravatar_url(email_address=em, size=24)
 
                assert grav == 'http://test.com/%s' % (_md5(em))
 
                assert grav == 'http://example.com/%s' % (_md5(em))
 

	
 
            fake = fake_tmpl_context(_url='http://test.com/{md5email}/{size}')
 
            fake = fake_tmpl_context(_url='http://example.com/{md5email}/{size}')
 
            with mock.patch('pylons.tmpl_context', fake):
 
                em = 'test@foo.com'
 
                em = 'test@example.com'
 
                grav = gravatar_url(email_address=em, size=24)
 
                assert grav == 'http://test.com/%s/%s' % (_md5(em), 24)
 
                assert grav == 'http://example.com/%s/%s' % (_md5(em), 24)
 

	
 
            fake = fake_tmpl_context(_url='{scheme}://{netloc}/{md5email}/{size}')
 
            with mock.patch('pylons.tmpl_context', fake):
 
                em = 'test@foo.com'
 
                em = 'test@example.com'
 
                grav = gravatar_url(email_address=em, size=24)
 
                assert grav == 'https://server.com/%s/%s' % (_md5(em), 24)
 
                assert grav == 'https://example.com/%s/%s' % (_md5(em), 24)
 

	
 
    @parameterized.expand([
 
        (Repository.DEFAULT_CLONE_URI, 'group/repo1', {}, '', 'http://vps1:8000/group/repo1'),
 
        (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'username'}, '', 'http://username@vps1:8000/group/repo1'),
 
        (Repository.DEFAULT_CLONE_URI, 'group/repo1', {}, '/prefix', 'http://vps1:8000/prefix/group/repo1'),
 
        (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'user'}, '/prefix', 'http://user@vps1:8000/prefix/group/repo1'),
 
        (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'username'}, '/prefix', 'http://username@vps1:8000/prefix/group/repo1'),
 
        (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'user'}, '/prefix/', 'http://user@vps1:8000/prefix/group/repo1'),
 
        (Repository.DEFAULT_CLONE_URI, 'group/repo1', {'user': 'username'}, '/prefix/', 'http://username@vps1:8000/prefix/group/repo1'),
 
        ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', {}, '', 'http://vps1:8000/_23'),
 
        ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', {'user': 'username'}, '', 'http://username@vps1:8000/_23'),
 
        ('http://{user}@{netloc}/_{repoid}', 'group/repo1', {'user': 'username'}, '', 'http://username@vps1:8000/_23'),
 
        ('http://{netloc}/_{repoid}', 'group/repo1', {'user': 'username'}, '', 'http://vps1:8000/_23'),
 
        ('https://{user}@proxy1.server.com/{repo}', 'group/repo1', {'user': 'username'}, '', 'https://username@proxy1.server.com/group/repo1'),
 
        ('https://{user}@proxy1.server.com/{repo}', 'group/repo1', {}, '', 'https://proxy1.server.com/group/repo1'),
 
        ('https://proxy1.server.com/{user}/{repo}', 'group/repo1', {'user': 'username'}, '', 'https://proxy1.server.com/username/group/repo1'),
 
        ('https://{user}@proxy1.example.com/{repo}', 'group/repo1', {'user': 'username'}, '', 'https://username@proxy1.example.com/group/repo1'),
 
        ('https://{user}@proxy1.example.com/{repo}', 'group/repo1', {}, '', 'https://proxy1.example.com/group/repo1'),
 
        ('https://proxy1.example.com/{user}/{repo}', 'group/repo1', {'user': 'username'}, '', 'https://proxy1.example.com/username/group/repo1'),
 
    ])
 
    def test_clone_url_generator(self, tmpl, repo_name, overrides, prefix, expected):
 
        from kallithea.lib.utils2 import get_clone_url
 
        clone_url = get_clone_url(uri_tmpl=tmpl, qualified_home_url='http://vps1:8000'+prefix,
 
                                  repo_name=repo_name, repo_id=23, **overrides)
 
        self.assertEqual(clone_url, expected)
 

	
 
    def _quick_url(self, text, tmpl="""<a class="revision-link" href="%s">%s</a>""", url_=None):
 
        """
 
        Changes `some text url[foo]` => `some text <a href="/">foo</a>
 

	
 
        :param text:
 
        """
 
        import re
 
        # quickly change expected url[] into a link
 
        URL_PAT = re.compile(r'(?:url\[)(.+?)(?:\])')
 

	
 
        def url_func(match_obj):
 
            _url = match_obj.groups()[0]
 
            return tmpl % (url_ or '/some-url', _url)
 
        return URL_PAT.sub(url_func, text)
 

	
 
    @parameterized.expand([
 
      ("",
 
@@ -316,54 +316,54 @@ class TestLibs(BaseTestCase):
 
    def test_urlify_changesets(self, sample, expected):
 
        def fake_url(self, *args, **kwargs):
 
            return '/some-url'
 

	
 
        expected = self._quick_url(expected)
 

	
 
        with mock.patch('pylons.url', fake_url):
 
            from kallithea.lib.helpers import urlify_changesets
 
            self.assertEqual(urlify_changesets(sample, 'repo_name'), expected)
 

	
 
    @parameterized.expand([
 
      ("",
 
       "",
 
       ""),
 
      ("https://svn.apache.org/repos",
 
       "url[https://svn.apache.org/repos]",
 
       "https://svn.apache.org/repos"),
 
      ("http://svn.apache.org/repos",
 
       "url[http://svn.apache.org/repos]",
 
       "http://svn.apache.org/repos"),
 
      ("from rev a also rev http://google.com",
 
       "from rev a also rev url[http://google.com]",
 
       "http://google.com"),
 
       ("""Multi line
 
       https://foo.bar.com
 
       https://foo.bar.example.com
 
       some text lalala""",
 
       """Multi line
 
       url[https://foo.bar.com]
 
       url[https://foo.bar.example.com]
 
       some text lalala""",
 
       "https://foo.bar.com")
 
       "https://foo.bar.example.com")
 
    ])
 
    def test_urlify_test(self, sample, expected, url_):
 
        from kallithea.lib.helpers import urlify_text
 
        expected = self._quick_url(expected,
 
                                   tmpl="""<a href="%s">%s</a>""", url_=url_)
 
        self.assertEqual(urlify_text(sample), expected)
 

	
 
    @parameterized.expand([
 
      ("", None),
 
      ("/_2", '2'),
 
      ("_2", '2'),
 
      ("/_2/", '2'),
 
      ("_2/", '2'),
 

	
 
      ("/_21", '21'),
 
      ("_21", '21'),
 
      ("/_21/", '21'),
 
      ("_21/", '21'),
 

	
 
      ("/_21/foobar", '21'),
 
      ("_21/121", '21'),
 
      ("/_21/_12", '21'),
 
      ("_21/prefix/foo", '21'),
 
    ])
kallithea/tests/scripts/manual_test_concurrency.py
Show inline comments
 
@@ -86,49 +86,49 @@ def get_session():
 
    engine = engine_from_config(conf, 'sqlalchemy.db1.')
 
    init_model(engine)
 
    sa = meta.Session
 
    return sa
 

	
 

	
 
def create_test_user(force=True):
 
    print 'creating test user'
 
    sa = get_session()
 

	
 
    user = sa.query(User).filter(User.username == USER).scalar()
 

	
 
    if force and user is not None:
 
        print 'removing current user'
 
        for repo in sa.query(Repository).filter(Repository.user == user).all():
 
            sa.delete(repo)
 
        sa.delete(user)
 
        sa.commit()
 

	
 
    if user is None or force:
 
        print 'creating new one'
 
        new_usr = User()
 
        new_usr.username = USER
 
        new_usr.password = get_crypt_password(PASS)
 
        new_usr.email = 'mail@mail.com'
 
        new_usr.email = 'mail@example.com'
 
        new_usr.name = 'test'
 
        new_usr.lastname = 'lasttestname'
 
        new_usr.active = True
 
        new_usr.admin = True
 
        sa.add(new_usr)
 
        sa.commit()
 

	
 
    print 'done'
 

	
 

	
 
def create_test_repo(force=True):
 
    print 'creating test repo'
 
    from kallithea.model.repo import RepoModel
 
    sa = get_session()
 

	
 
    user = sa.query(User).filter(User.username == USER).scalar()
 
    if user is None:
 
        raise Exception('user not found')
 

	
 
    repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
 

	
 
    if repo is None:
 
        print 'repo not found creating'
 

	
kallithea/tests/test.ini
Show inline comments
 
@@ -35,49 +35,49 @@ pdebug = false
 
## Default:
 
#email_prefix =
 
## Example:
 
#email_prefix = [Kallithea]
 

	
 
## Recipients for error emails and fallback recipients of application mails.
 
## Multiple addresses can be specified, space-separated.
 
## Only addresses are allowed, do not add any name part.
 
## Default:
 
#email_to =
 
## Examples:
 
#email_to = admin@example.com
 
#email_to = admin@example.com another_admin@example.com
 

	
 
## 'From' header for error emails. You can optionally add a name.
 
## Default:
 
#error_email_from = pylons@yourapp.com
 
## Examples:
 
#error_email_from = Kallithea Errors <kallithea-noreply@example.com>
 
#error_email_from = paste_error@example.com
 

	
 
## SMTP server settings
 
## Only smtp_server is mandatory. All other settings take the specified default
 
## values.
 
#smtp_server = mail.server.com
 
#smtp_server = smtp.example.com
 
#smtp_username =
 
#smtp_password =
 
#smtp_port = 25
 
#smtp_use_tls = false
 
#smtp_use_ssl = false
 
## SMTP authentication parameters to use (e.g. LOGIN PLAIN CRAM-MD5, etc.).
 
## If empty, use any of the authentication parameters supported by the server.
 
#smtp_auth =
 

	
 
[server:main]
 
## PASTE ##
 
#use = egg:Paste#http
 
## nr of worker threads to spawn
 
#threadpool_workers = 5
 
## max request before thread respawn
 
#threadpool_max_requests = 10
 
## option to use threads of process
 
#use_threadpool = true
 

	
 
## WAITRESS ##
 
use = egg:waitress#main
 
## number of worker threads
 
threads = 5
 
## MAX BODY SIZE 100GB
 
@@ -207,98 +207,98 @@ force_https = false
 
## use Strict-Transport-Security headers
 
use_htsts = false
 

	
 
## number of commits stats will parse on each iteration
 
commit_parse_limit = 25
 

	
 
## path to git executable
 
git_path = git
 

	
 
## git rev filter option, --all is the default filter, if you need to
 
## hide all refs in changelog switch this to --branches --tags
 
#git_rev_filter = --branches --tags
 

	
 
## RSS feed options
 
rss_cut_off_limit = 256000
 
rss_items_per_page = 10
 
rss_include_diff = false
 

	
 
## options for showing and identifying changesets
 
show_sha_length = 12
 
show_revision_number = true
 

	
 
## gist URL alias, used to create nicer urls for gist. This should be an
 
## url that does rewrites to _admin/gists/<gistid>.
 
## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
 
## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
 
## example: http://gist.example.com/{gistid}. Empty means use the internal
 
## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
 
gist_alias_url =
 

	
 
## white list of API enabled controllers. This allows to add list of
 
## controllers to which access will be enabled by api_key. eg: to enable
 
## api access to raw_files put `FilesController:raw`, to enable access to patches
 
## add `ChangesetController:changeset_patch`. This list should be "," separated
 
## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
 
## Recommended settings below are commented out:
 
api_access_controllers_whitelist =
 
#    ChangesetController:changeset_patch,
 
#    ChangesetController:changeset_raw,
 
#    FilesController:raw,
 
#    FilesController:archivefile
 

	
 
## default encoding used to convert from and to unicode
 
## can be also a comma seperated list of encoding in case of mixed encodings
 
default_encoding = utf8
 

	
 
## issue tracker for Kallithea (leave blank to disable, absent for default)
 
#bugtracker = https://bitbucket.org/conservancy/kallithea/issues
 

	
 
## issue tracking mapping for commits messages
 
## comment out issue_pat, issue_server, issue_prefix to enable
 

	
 
## pattern to get the issues from commit messages
 
## default one used here is #<numbers> with a regex passive group for `#`
 
## {id} will be all groups matched from this pattern
 

	
 
issue_pat = (?:\s*#)(\d+)
 

	
 
## server url to the issue, each {id} will be replaced with match
 
## fetched from the regex and {repo} is replaced with full repository name
 
## including groups {repo_name} is replaced with just name of repo
 

	
 
issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
issue_server_link = https://issues.example.com/{repo}/issue/{id}
 

	
 
## prefix to add to link to indicate it's an url
 
## #314 will be replaced by <issue_prefix><id>
 

	
 
issue_prefix = #
 

	
 
## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
 
## multiple patterns, to other issues server, wiki or others
 
## below an example how to create a wiki pattern
 
# wiki-some-id -> https://mywiki.com/some-id
 
# wiki-some-id -> https://wiki.example.com/some-id
 

	
 
#issue_pat_wiki = (?:wiki-)(.+)
 
#issue_server_link_wiki = https://mywiki.com/{id}
 
#issue_server_link_wiki = https://wiki.example.com/{id}
 
#issue_prefix_wiki = WIKI-
 

	
 
## instance-id prefix
 
## a prefix key for this instance used for cache invalidation when running
 
## multiple instances of kallithea, make sure it's globally unique for
 
## all running kallithea instances. Leave empty if you don't use it
 
instance_id =
 

	
 
## alternative return HTTP header for failed authentication. Default HTTP
 
## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 
## allows to change the repository location in settings page
 
allow_repo_location_change = True
 

	
 
## allows to setup custom hooks in settings page
 
allow_custom_hooks_settings = True
 

	
 
####################################
kallithea/tests/vcs/test_utils.py
Show inline comments
 
@@ -163,68 +163,68 @@ class TestParseDatetime(unittest.TestCas
 
        self.assertEqual(parse_datetime('3 d'), expected)
 
        self.assertEqual(parse_datetime('3 day'), expected)
 
        self.assertEqual(parse_datetime('3 days'), expected)
 

	
 
    def test_weeks(self):
 
        timestamp = datetime.datetime.today() - datetime.timedelta(days=3 * 7)
 
        args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
 
        expected = datetime.datetime(*args)
 
        self.assertEqual(parse_datetime('3w'), expected)
 
        self.assertEqual(parse_datetime('3 w'), expected)
 
        self.assertEqual(parse_datetime('3 week'), expected)
 
        self.assertEqual(parse_datetime('3 weeks'), expected)
 

	
 
    def test_mixed(self):
 
        timestamp = datetime.datetime.today() - datetime.timedelta(days=2 * 7 + 3)
 
        args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
 
        expected = datetime.datetime(*args)
 
        self.assertEqual(parse_datetime('2w3d'), expected)
 
        self.assertEqual(parse_datetime('2w 3d'), expected)
 
        self.assertEqual(parse_datetime('2w 3 days'), expected)
 
        self.assertEqual(parse_datetime('2 weeks 3 days'), expected)
 

	
 

	
 
class TestAuthorExtractors(unittest.TestCase):
 
    TEST_AUTHORS = [("Username Last'o'Name <username@python-works.com>",
 
                    ("Username Last'o'Name", "username@python-works.com")),
 
                  ("Username Last'o'Name Spaces < username@python-works.com >",
 
                    ("Username Last'o'Name Spaces", "username@python-works.com")),
 
                  ("Username Last'o'Name <username.lastname@python-works.com>",
 
                    ("Username Last'o'Name", "username.lastname@python-works.com")),
 
                  ('mrf RFC_SPEC <username+lastname@python-works.com>',
 
                    ('mrf RFC_SPEC', 'username+lastname@python-works.com')),
 
                  ('username <user@email.com>',
 
                    ('username', 'user@email.com')),
 
                  ('username <user@email.com',
 
                   ('username', 'user@email.com')),
 
                  ('broken missing@email.com',
 
                   ('broken', 'missing@email.com')),
 
                  ('<justemail@mail.com>',
 
                   ('', 'justemail@mail.com')),
 
    TEST_AUTHORS = [("Username Last'o'Name <username@example.com>",
 
                    ("Username Last'o'Name", "username@example.com")),
 
                  ("Username Last'o'Name Spaces < username@example.com >",
 
                    ("Username Last'o'Name Spaces", "username@example.com")),
 
                  ("Username Last'o'Name <username.lastname@example.com>",
 
                    ("Username Last'o'Name", "username.lastname@example.com")),
 
                  ('mrf RFC_SPEC <username+lastname@example.com>',
 
                    ('mrf RFC_SPEC', 'username+lastname@example.com')),
 
                  ('username <user@example.com>',
 
                    ('username', 'user@example.com')),
 
                  ('username <user@example.com',
 
                   ('username', 'user@example.com')),
 
                  ('broken missing@example.com',
 
                   ('broken', 'missing@example.com')),
 
                  ('<justemail@example.com>',
 
                   ('', 'justemail@example.com')),
 
                  ('justname',
 
                   ('justname', '')),
 
                  ('Mr Double Name withemail@email.com ',
 
                   ('Mr Double Name', 'withemail@email.com')),
 
                  ('Mr Double Name withemail@example.com ',
 
                   ('Mr Double Name', 'withemail@example.com')),
 
                  ]
 

	
 
    def test_author_email(self):
 

	
 
        for test_str, result in self.TEST_AUTHORS:
 
            self.assertEqual(result[1], author_email(test_str))
 

	
 

	
 
    def test_author_name(self):
 

	
 
        for test_str, result in self.TEST_AUTHORS:
 
            self.assertEqual(result[0], author_name(test_str))
 

	
 

	
 
class TestGetDictForAttrs(unittest.TestCase):
 

	
 
    def test_returned_dict_has_expected_attrs(self):
 
        obj = mock.Mock()
 
        obj.NOT_INCLUDED = 'this key/value should not be included'
 
        obj.CONST = True
 
        obj.foo = 'aaa'
 
        obj.attrs = {'foo': 'bar'}
 
        obj.date = datetime.datetime(2010, 12, 31)
 
        obj.count = 1001
scripts/make-release
Show inline comments
 
new file 100755
 
#!/bin/bash
 
set -e
 
set -x
 

	
 
echo "Checking tools needed for uploading stuff"
 
pip freeze | grep '^Sphinx==' || pip install Sphinx
 
pip freeze | grep '^Sphinx-PyPI-upload==' || pip install Sphinx-PyPI-upload
 

	
 
echo "Verifying everything can build"
 
hg purge --all dist
 
python2 setup.py build_sphinx
 
python2 setup.py compile_catalog # TODO: check for errors
 
python2 setup.py sdist
 

	
 
echo "Verifying VERSION from kallithea/__init__.py"
 
namerel=$(cd dist && echo Kallithea-*.tar.gz)
 
namerel=${namerel%.tar.gz}
 
version=${namerel#Kallithea-}
 
echo "Releasing Kallithea $version in directory $namerel"
 
echo "Verifying current revision is tagged for $version"
 
hg log -r "'$version'&." | grep .
 

	
 
echo "Cleaning before making release build"
 
hg up -c .
 
hg revert -a -r null
 
hg up -C "'$version'&."
 
hg purge --all
 

	
 
echo "Building dist file"
 
python2 setup.py compile_catalog
 
python2 setup.py sdist
 

	
 
echo "Verifying dist file content"
 
tar tf dist/Kallithea-*.tar.gz | sed "s|^$namerel/||" | LANG=C sort > scripts/manifest
 
hg diff
 
hg up -c . # fail if manifest changed
 

	
 
echo "Now, make sure"
 
echo "* the copyright and contributor lists have been updated"
 
echo "* all tests are passing"
 
echo "* release note is ready"
 
echo "* announcement is ready"
 
echo "* source has been pushed to https://kallithea-scm.org/repos/kallithea"
 
echo
 

	
 
echo -n "Enter \"pypi\" to upload Kallithea $version to pypi: "
 
read answer
 
[ "$answer" = "pypi" ]
 
extraargs=${EMAIL:+--identity=$EMAIL}
 
python2 setup.py sdist upload --sign $extraargs
 
xdg-open https://pypi.python.org/pypi/Kallithea
 

	
 
echo "Uploading docs to pypi"
 
# See https://wiki.python.org/moin/PyPiDocumentationHosting
 
python2 setup.py build_sphinx upload_sphinx
 
xdg-open https://pythonhosted.org/Kallithea/
 
xdg-open http://packages.python.org/Kallithea/installation.html
 

	
 
echo "Rebuilding readthedocs for docs.kallithea-scm.org"
 
xdg-open https://readthedocs.org/projects/kallithea/
 
curl -X POST http://readthedocs.org/build/kallithea
 
xdg-open https://readthedocs.org/builds/kallithea/
 
xdg-open http://docs.kallithea-scm.org/en/latest/ # or whatever the branch is
scripts/manifest
Show inline comments
 
new file 100644
 

	
 
Apache-License-2.0.txt
 
CONTRIBUTORS
 
COPYING
 
Kallithea.egg-info/
 
Kallithea.egg-info/PKG-INFO
 
Kallithea.egg-info/SOURCES.txt
 
Kallithea.egg-info/dependency_links.txt
 
Kallithea.egg-info/entry_points.txt
 
Kallithea.egg-info/not-zip-safe
 
Kallithea.egg-info/paster_plugins.txt
 
Kallithea.egg-info/requires.txt
 
Kallithea.egg-info/top_level.txt
 
LICENSE-MERGELY.html
 
LICENSE.md
 
MANIFEST.in
 
MIT-Permissive-License.txt
 
PKG-INFO
 
README.rst
 
development.ini
 
docs/
 
docs/Makefile
 
docs/api/
 
docs/api/api.rst
 
docs/api/models.rst
 
docs/changelog.rst
 
docs/conf.py
 
docs/contributing.rst
 
docs/images/
 
docs/images/.img
 
docs/index.rst
 
docs/installation.rst
 
docs/installation_iis.rst
 
docs/installation_puppet.rst
 
docs/installation_win.rst
 
docs/installation_win_old.rst
 
docs/make.bat
 
docs/overview.rst
 
docs/readme.rst
 
docs/setup.rst
 
docs/theme/
 
docs/theme/nature/
 
docs/theme/nature/layout.html
 
docs/theme/nature/static/
 
docs/theme/nature/static/kallithea-logo.svg
 
docs/theme/nature/static/nature.css_t
 
docs/theme/nature/static/pygments.css
 
docs/theme/nature/theme.conf
 
docs/usage/
 
docs/usage/backup.rst
 
docs/usage/debugging.rst
 
docs/usage/email.rst
 
docs/usage/general.rst
 
docs/usage/locking.rst
 
docs/usage/performance.rst
 
docs/usage/statistics.rst
 
docs/usage/troubleshooting.rst
 
docs/usage/vcs_support.rst
 
init.d/
 
init.d/celeryd-upstart.conf
 
init.d/kallithea-daemon-arch
 
init.d/kallithea-daemon-debian
 
init.d/kallithea-daemon-gentoo
 
init.d/kallithea-daemon-redhat
 
init.d/kallithea-upstart.conf
 
init.d/supervisord.conf
 
kallithea/
 
kallithea/__init__.py
 
kallithea/bin/
 
kallithea/bin/__init__.py
 
kallithea/bin/base.py
 
kallithea/bin/kallithea_api.py
 
kallithea/bin/kallithea_backup.py
 
kallithea/bin/kallithea_config.py
 
kallithea/bin/kallithea_gist.py
 
kallithea/bin/ldap_sync.conf
 
kallithea/bin/ldap_sync.py
 
kallithea/bin/rebranddb.py
 
kallithea/bin/template.ini.mako
 
kallithea/config/
 
kallithea/config/__init__.py
 
kallithea/config/conf.py
 
kallithea/config/deployment.ini_tmpl
 
kallithea/config/environment.py
 
kallithea/config/middleware.py
 
kallithea/config/post_receive_tmpl.py
 
kallithea/config/pre_receive_tmpl.py
 
kallithea/config/rcextensions/
 
kallithea/config/rcextensions/__init__.py
 
kallithea/config/routing.py
 
kallithea/controllers/
 
kallithea/controllers/__init__.py
 
kallithea/controllers/admin/
 
kallithea/controllers/admin/__init__.py
 
kallithea/controllers/admin/admin.py
 
kallithea/controllers/admin/auth_settings.py
 
kallithea/controllers/admin/defaults.py
 
kallithea/controllers/admin/gists.py
 
kallithea/controllers/admin/my_account.py
 
kallithea/controllers/admin/notifications.py
 
kallithea/controllers/admin/permissions.py
 
kallithea/controllers/admin/repo_groups.py
 
kallithea/controllers/admin/repos.py
 
kallithea/controllers/admin/settings.py
 
kallithea/controllers/admin/user_groups.py
 
kallithea/controllers/admin/users.py
 
kallithea/controllers/api/
 
kallithea/controllers/api/__init__.py
 
kallithea/controllers/api/api.py
 
kallithea/controllers/bookmarks.py
 
kallithea/controllers/branches.py
 
kallithea/controllers/changelog.py
 
kallithea/controllers/changeset.py
 
kallithea/controllers/compare.py
 
kallithea/controllers/error.py
 
kallithea/controllers/feed.py
 
kallithea/controllers/files.py
 
kallithea/controllers/followers.py
 
kallithea/controllers/forks.py
 
kallithea/controllers/home.py
 
kallithea/controllers/journal.py
 
kallithea/controllers/login.py
 
kallithea/controllers/pullrequests.py
 
kallithea/controllers/search.py
 
kallithea/controllers/summary.py
 
kallithea/controllers/tags.py
 
kallithea/i18n/
 
kallithea/i18n/be/
 
kallithea/i18n/be/LC_MESSAGES/
 
kallithea/i18n/be/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/be/LC_MESSAGES/kallithea.po
 
kallithea/i18n/cs/
 
kallithea/i18n/cs/LC_MESSAGES/
 
kallithea/i18n/cs/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/cs/LC_MESSAGES/kallithea.po
 
kallithea/i18n/de/
 
kallithea/i18n/de/LC_MESSAGES/
 
kallithea/i18n/de/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/de/LC_MESSAGES/kallithea.po
 
kallithea/i18n/en/
 
kallithea/i18n/en/LC_MESSAGES/
 
kallithea/i18n/en/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/fr/
 
kallithea/i18n/fr/LC_MESSAGES/
 
kallithea/i18n/fr/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/fr/LC_MESSAGES/kallithea.po
 
kallithea/i18n/how_to
 
kallithea/i18n/hu/
 
kallithea/i18n/hu/LC_MESSAGES/
 
kallithea/i18n/hu/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/hu/LC_MESSAGES/kallithea.po
 
kallithea/i18n/ja/
 
kallithea/i18n/ja/LC_MESSAGES/
 
kallithea/i18n/ja/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/ja/LC_MESSAGES/kallithea.po
 
kallithea/i18n/kallithea.pot
 
kallithea/i18n/nl_BE/
 
kallithea/i18n/nl_BE/LC_MESSAGES/
 
kallithea/i18n/nl_BE/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/nl_BE/LC_MESSAGES/kallithea.po
 
kallithea/i18n/pl/
 
kallithea/i18n/pl/LC_MESSAGES/
 
kallithea/i18n/pl/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/pl/LC_MESSAGES/kallithea.po
 
kallithea/i18n/pt_BR/
 
kallithea/i18n/pt_BR/LC_MESSAGES/
 
kallithea/i18n/pt_BR/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/pt_BR/LC_MESSAGES/kallithea.po
 
kallithea/i18n/ru/
 
kallithea/i18n/ru/LC_MESSAGES/
 
kallithea/i18n/ru/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/ru/LC_MESSAGES/kallithea.po
 
kallithea/i18n/sk/
 
kallithea/i18n/sk/LC_MESSAGES/
 
kallithea/i18n/sk/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/sk/LC_MESSAGES/kallithea.po
 
kallithea/i18n/zh_CN/
 
kallithea/i18n/zh_CN/LC_MESSAGES/
 
kallithea/i18n/zh_CN/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/zh_CN/LC_MESSAGES/kallithea.po
 
kallithea/i18n/zh_TW/
 
kallithea/i18n/zh_TW/LC_MESSAGES/
 
kallithea/i18n/zh_TW/LC_MESSAGES/kallithea.mo
 
kallithea/i18n/zh_TW/LC_MESSAGES/kallithea.po
 
kallithea/lib/
 
kallithea/lib/__init__.py
 
kallithea/lib/annotate.py
 
kallithea/lib/app_globals.py
 
kallithea/lib/auth.py
 
kallithea/lib/auth_modules/
 
kallithea/lib/auth_modules/__init__.py
 
kallithea/lib/auth_modules/auth_container.py
 
kallithea/lib/auth_modules/auth_crowd.py
 
kallithea/lib/auth_modules/auth_internal.py
 
kallithea/lib/auth_modules/auth_ldap.py
 
kallithea/lib/auth_modules/auth_pam.py
 
kallithea/lib/base.py
 
kallithea/lib/caching_query.py
 
kallithea/lib/celerylib/
 
kallithea/lib/celerylib/__init__.py
 
kallithea/lib/celerylib/tasks.py
 
kallithea/lib/celerypylons/
 
kallithea/lib/celerypylons/__init__.py
 
kallithea/lib/celerypylons/commands.py
 
kallithea/lib/celerypylons/loader.py
 
kallithea/lib/colored_formatter.py
 
kallithea/lib/compat.py
 
kallithea/lib/db_manage.py
 
kallithea/lib/dbmigrate/
 
kallithea/lib/dbmigrate/__init__.py
 
kallithea/lib/dbmigrate/migrate.cfg
 
kallithea/lib/dbmigrate/migrate/
 
kallithea/lib/dbmigrate/migrate/__init__.py
 
kallithea/lib/dbmigrate/migrate/changeset/
 
kallithea/lib/dbmigrate/migrate/changeset/__init__.py
 
kallithea/lib/dbmigrate/migrate/changeset/ansisql.py
 
kallithea/lib/dbmigrate/migrate/changeset/constraint.py
 
kallithea/lib/dbmigrate/migrate/changeset/databases/
 
kallithea/lib/dbmigrate/migrate/changeset/databases/__init__.py
 
kallithea/lib/dbmigrate/migrate/changeset/databases/firebird.py
 
kallithea/lib/dbmigrate/migrate/changeset/databases/mysql.py
 
kallithea/lib/dbmigrate/migrate/changeset/databases/oracle.py
 
kallithea/lib/dbmigrate/migrate/changeset/databases/postgres.py
 
kallithea/lib/dbmigrate/migrate/changeset/databases/sqlite.py
 
kallithea/lib/dbmigrate/migrate/changeset/databases/visitor.py
 
kallithea/lib/dbmigrate/migrate/changeset/schema.py
 
kallithea/lib/dbmigrate/migrate/exceptions.py
 
kallithea/lib/dbmigrate/migrate/versioning/
 
kallithea/lib/dbmigrate/migrate/versioning/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/api.py
 
kallithea/lib/dbmigrate/migrate/versioning/cfgparse.py
 
kallithea/lib/dbmigrate/migrate/versioning/config.py
 
kallithea/lib/dbmigrate/migrate/versioning/genmodel.py
 
kallithea/lib/dbmigrate/migrate/versioning/migrate_repository.py
 
kallithea/lib/dbmigrate/migrate/versioning/pathed.py
 
kallithea/lib/dbmigrate/migrate/versioning/repository.py
 
kallithea/lib/dbmigrate/migrate/versioning/schema.py
 
kallithea/lib/dbmigrate/migrate/versioning/schemadiff.py
 
kallithea/lib/dbmigrate/migrate/versioning/script/
 
kallithea/lib/dbmigrate/migrate/versioning/script/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/script/base.py
 
kallithea/lib/dbmigrate/migrate/versioning/script/py.py
 
kallithea/lib/dbmigrate/migrate/versioning/script/sql.py
 
kallithea/lib/dbmigrate/migrate/versioning/shell.py
 
kallithea/lib/dbmigrate/migrate/versioning/template.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/manage.py_tmpl
 
kallithea/lib/dbmigrate/migrate/versioning/templates/manage/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/manage/default.py_tmpl
 
kallithea/lib/dbmigrate/migrate/versioning/templates/manage/pylons.py_tmpl
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/default/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/default/README
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/default/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/default/migrate.cfg
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/default/versions/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/default/versions/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/pylons/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/pylons/README
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/pylons/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/pylons/migrate.cfg
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/pylons/versions/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/repository/pylons/versions/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/script/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/script/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/templates/script/default.py_tmpl
 
kallithea/lib/dbmigrate/migrate/versioning/templates/script/pylons.py_tmpl
 
kallithea/lib/dbmigrate/migrate/versioning/templates/sql_script/
 
kallithea/lib/dbmigrate/migrate/versioning/templates/sql_script/default.py_tmpl
 
kallithea/lib/dbmigrate/migrate/versioning/templates/sql_script/pylons.py_tmpl
 
kallithea/lib/dbmigrate/migrate/versioning/util/
 
kallithea/lib/dbmigrate/migrate/versioning/util/__init__.py
 
kallithea/lib/dbmigrate/migrate/versioning/util/importpath.py
 
kallithea/lib/dbmigrate/migrate/versioning/util/keyedinstance.py
 
kallithea/lib/dbmigrate/migrate/versioning/version.py
 
kallithea/lib/dbmigrate/schema/
 
kallithea/lib/dbmigrate/schema/__init__.py
 
kallithea/lib/dbmigrate/schema/db_1_1_0.py
 
kallithea/lib/dbmigrate/schema/db_1_2_0.py
 
kallithea/lib/dbmigrate/schema/db_1_3_0.py
 
kallithea/lib/dbmigrate/schema/db_1_4_0.py
 
kallithea/lib/dbmigrate/schema/db_1_5_0.py
 
kallithea/lib/dbmigrate/schema/db_1_5_2.py
 
kallithea/lib/dbmigrate/schema/db_1_6_0.py
 
kallithea/lib/dbmigrate/schema/db_1_7_0.py
 
kallithea/lib/dbmigrate/schema/db_1_8_0.py
 
kallithea/lib/dbmigrate/schema/db_2_0_0.py
 
kallithea/lib/dbmigrate/schema/db_2_0_1.py
 
kallithea/lib/dbmigrate/schema/db_2_0_2.py
 
kallithea/lib/dbmigrate/schema/db_2_1_0.py
 
kallithea/lib/dbmigrate/schema/db_2_2_0.py
 
kallithea/lib/dbmigrate/schema/db_2_2_3.py
 
kallithea/lib/dbmigrate/versions/
 
kallithea/lib/dbmigrate/versions/001_initial_release.py
 
kallithea/lib/dbmigrate/versions/002_version_1_1_0.py
 
kallithea/lib/dbmigrate/versions/003_version_1_2_0.py
 
kallithea/lib/dbmigrate/versions/004_version_1_3_0.py
 
kallithea/lib/dbmigrate/versions/005_version_1_3_0.py
 
kallithea/lib/dbmigrate/versions/006_version_1_4_0.py
 
kallithea/lib/dbmigrate/versions/007_version_1_4_0.py
 
kallithea/lib/dbmigrate/versions/008_version_1_5_0.py
 
kallithea/lib/dbmigrate/versions/009_version_1_5_1.py
 
kallithea/lib/dbmigrate/versions/010_version_1_5_2.py
 
kallithea/lib/dbmigrate/versions/011_version_1_6_0.py
 
kallithea/lib/dbmigrate/versions/012_version_1_7_0.py
 
kallithea/lib/dbmigrate/versions/013_version_1_7_0.py
 
kallithea/lib/dbmigrate/versions/014_version_1_7_1.py
 
kallithea/lib/dbmigrate/versions/015_version_1_8_0.py
 
kallithea/lib/dbmigrate/versions/016_version_2_0_0.py
 
kallithea/lib/dbmigrate/versions/017_version_2_0_0.py
 
kallithea/lib/dbmigrate/versions/018_version_2_0_0.py
 
kallithea/lib/dbmigrate/versions/019_version_2_0_0.py
 
kallithea/lib/dbmigrate/versions/020_version_2_0_1.py
 
kallithea/lib/dbmigrate/versions/021_version_2_0_2.py
 
kallithea/lib/dbmigrate/versions/022_version_2_0_2.py
 
kallithea/lib/dbmigrate/versions/023_version_2_1_0.py
 
kallithea/lib/dbmigrate/versions/024_version_2_1_0.py
 
kallithea/lib/dbmigrate/versions/025_version_2_1_0.py
 
kallithea/lib/dbmigrate/versions/026_version_2_2_0.py
 
kallithea/lib/dbmigrate/versions/027_version_2_2_0.py
 
kallithea/lib/dbmigrate/versions/028_version_2_2_3.py
 
kallithea/lib/dbmigrate/versions/029_version_2_2_3.py
 
kallithea/lib/dbmigrate/versions/030_version_2_2_3.py
 
kallithea/lib/dbmigrate/versions/031_version_2_2_3.py
 
kallithea/lib/dbmigrate/versions/__init__.py
 
kallithea/lib/diffs.py
 
kallithea/lib/exceptions.py
 
kallithea/lib/ext_json.py
 
kallithea/lib/graphmod.py
 
kallithea/lib/helpers.py
 
kallithea/lib/hooks.py
 
kallithea/lib/indexers/
 
kallithea/lib/indexers/__init__.py
 
kallithea/lib/indexers/daemon.py
 
kallithea/lib/ipaddr.py
 
kallithea/lib/markup_renderer.py
 
kallithea/lib/middleware/
 
kallithea/lib/middleware/__init__.py
 
kallithea/lib/middleware/errormator.py
 
kallithea/lib/middleware/https_fixup.py
 
kallithea/lib/middleware/pygrack.py
 
kallithea/lib/middleware/sentry.py
 
kallithea/lib/middleware/sessionmiddleware.py
 
kallithea/lib/middleware/simplegit.py
 
kallithea/lib/middleware/simplehg.py
 
kallithea/lib/middleware/wrapper.py
 
kallithea/lib/paster_commands/
 
kallithea/lib/paster_commands/__init__.py
 
kallithea/lib/paster_commands/cache_keys.py
 
kallithea/lib/paster_commands/cleanup.py
 
kallithea/lib/paster_commands/install_iis.py
 
kallithea/lib/paster_commands/ishell.py
 
kallithea/lib/paster_commands/make_index.py
 
kallithea/lib/paster_commands/make_rcextensions.py
 
kallithea/lib/paster_commands/repo_scan.py
 
kallithea/lib/paster_commands/setup_db.py
 
kallithea/lib/paster_commands/update_repoinfo.py
 
kallithea/lib/pidlock.py
 
kallithea/lib/profiler.py
 
kallithea/lib/rcmail/
 
kallithea/lib/rcmail/__init__.py
 
kallithea/lib/rcmail/exceptions.py
 
kallithea/lib/rcmail/message.py
 
kallithea/lib/rcmail/response.py
 
kallithea/lib/rcmail/smtp_mailer.py
 
kallithea/lib/rcmail/utils.py
 
kallithea/lib/recaptcha.py
 
kallithea/lib/timerproxy.py
 
kallithea/lib/utils.py
 
kallithea/lib/utils2.py
 
kallithea/lib/vcs/
 
kallithea/lib/vcs/__init__.py
 
kallithea/lib/vcs/backends/
 
kallithea/lib/vcs/backends/__init__.py
 
kallithea/lib/vcs/backends/base.py
 
kallithea/lib/vcs/backends/git/
 
kallithea/lib/vcs/backends/git/__init__.py
 
kallithea/lib/vcs/backends/git/changeset.py
 
kallithea/lib/vcs/backends/git/inmemory.py
 
kallithea/lib/vcs/backends/git/repository.py
 
kallithea/lib/vcs/backends/git/workdir.py
 
kallithea/lib/vcs/backends/hg/
 
kallithea/lib/vcs/backends/hg/__init__.py
 
kallithea/lib/vcs/backends/hg/changeset.py
 
kallithea/lib/vcs/backends/hg/inmemory.py
 
kallithea/lib/vcs/backends/hg/repository.py
 
kallithea/lib/vcs/backends/hg/workdir.py
 
kallithea/lib/vcs/conf/
 
kallithea/lib/vcs/conf/__init__.py
 
kallithea/lib/vcs/conf/settings.py
 
kallithea/lib/vcs/exceptions.py
 
kallithea/lib/vcs/nodes.py
 
kallithea/lib/vcs/subprocessio.py
 
kallithea/lib/vcs/utils/
 
kallithea/lib/vcs/utils/__init__.py
 
kallithea/lib/vcs/utils/annotate.py
 
kallithea/lib/vcs/utils/archivers.py
 
kallithea/lib/vcs/utils/baseui_config.py
 
kallithea/lib/vcs/utils/compat.py
 
kallithea/lib/vcs/utils/diffs.py
 
kallithea/lib/vcs/utils/fakemod.py
 
kallithea/lib/vcs/utils/filesize.py
 
kallithea/lib/vcs/utils/helpers.py
 
kallithea/lib/vcs/utils/hgcompat.py
 
kallithea/lib/vcs/utils/imports.py
 
kallithea/lib/vcs/utils/lazy.py
 
kallithea/lib/vcs/utils/lockfiles.py
 
kallithea/lib/vcs/utils/ordered_dict.py
 
kallithea/lib/vcs/utils/paths.py
 
kallithea/lib/vcs/utils/progressbar.py
 
kallithea/lib/vcs/utils/termcolors.py
 
kallithea/lib/verlib.py
 
kallithea/model/
 
kallithea/model/__init__.py
 
kallithea/model/api_key.py
 
kallithea/model/changeset_status.py
 
kallithea/model/comment.py
 
kallithea/model/db.py
 
kallithea/model/forms.py
 
kallithea/model/gist.py
 
kallithea/model/meta.py
 
kallithea/model/notification.py
 
kallithea/model/permission.py
 
kallithea/model/pull_request.py
 
kallithea/model/repo.py
 
kallithea/model/repo_group.py
 
kallithea/model/repo_permission.py
 
kallithea/model/scm.py
 
kallithea/model/user.py
 
kallithea/model/user_group.py
 
kallithea/model/validators.py
 
kallithea/public/
 
kallithea/public/codemirror/
 
kallithea/public/codemirror/LICENSE
 
kallithea/public/codemirror/lib/
 
kallithea/public/codemirror/lib/codemirror.css
 
kallithea/public/codemirror/lib/codemirror.js
 
kallithea/public/codemirror/mode/
 
kallithea/public/codemirror/mode/apl/
 
kallithea/public/codemirror/mode/apl/apl.js
 
kallithea/public/codemirror/mode/asterisk/
 
kallithea/public/codemirror/mode/asterisk/asterisk.js
 
kallithea/public/codemirror/mode/clike/
 
kallithea/public/codemirror/mode/clike/clike.js
 
kallithea/public/codemirror/mode/clojure/
 
kallithea/public/codemirror/mode/clojure/clojure.js
 
kallithea/public/codemirror/mode/cobol/
 
kallithea/public/codemirror/mode/cobol/cobol.js
 
kallithea/public/codemirror/mode/coffeescript/
 
kallithea/public/codemirror/mode/coffeescript/coffeescript.js
 
kallithea/public/codemirror/mode/commonlisp/
 
kallithea/public/codemirror/mode/commonlisp/commonlisp.js
 
kallithea/public/codemirror/mode/css/
 
kallithea/public/codemirror/mode/css/css.js
 
kallithea/public/codemirror/mode/css/less_test.js
 
kallithea/public/codemirror/mode/css/scss_test.js
 
kallithea/public/codemirror/mode/cypher/
 
kallithea/public/codemirror/mode/cypher/cypher.js
 
kallithea/public/codemirror/mode/d/
 
kallithea/public/codemirror/mode/d/d.js
 
kallithea/public/codemirror/mode/diff/
 
kallithea/public/codemirror/mode/diff/diff.js
 
kallithea/public/codemirror/mode/django/
 
kallithea/public/codemirror/mode/django/django.js
 
kallithea/public/codemirror/mode/dtd/
 
kallithea/public/codemirror/mode/dtd/dtd.js
 
kallithea/public/codemirror/mode/dylan/
 
kallithea/public/codemirror/mode/dylan/dylan.js
 
kallithea/public/codemirror/mode/ecl/
 
kallithea/public/codemirror/mode/ecl/ecl.js
 
kallithea/public/codemirror/mode/eiffel/
 
kallithea/public/codemirror/mode/eiffel/eiffel.js
 
kallithea/public/codemirror/mode/erlang/
 
kallithea/public/codemirror/mode/erlang/erlang.js
 
kallithea/public/codemirror/mode/fortran/
 
kallithea/public/codemirror/mode/fortran/fortran.js
 
kallithea/public/codemirror/mode/gas/
 
kallithea/public/codemirror/mode/gas/gas.js
 
kallithea/public/codemirror/mode/gfm/
 
kallithea/public/codemirror/mode/gfm/gfm.js
 
kallithea/public/codemirror/mode/gherkin/
 
kallithea/public/codemirror/mode/gherkin/gherkin.js
 
kallithea/public/codemirror/mode/go/
 
kallithea/public/codemirror/mode/go/go.js
 
kallithea/public/codemirror/mode/groovy/
 
kallithea/public/codemirror/mode/groovy/groovy.js
 
kallithea/public/codemirror/mode/haml/
 
kallithea/public/codemirror/mode/haml/haml.js
 
kallithea/public/codemirror/mode/haskell/
 
kallithea/public/codemirror/mode/haskell/haskell.js
 
kallithea/public/codemirror/mode/haxe/
 
kallithea/public/codemirror/mode/haxe/haxe.js
 
kallithea/public/codemirror/mode/htmlembedded/
 
kallithea/public/codemirror/mode/htmlembedded/htmlembedded.js
 
kallithea/public/codemirror/mode/htmlmixed/
 
kallithea/public/codemirror/mode/htmlmixed/htmlmixed.js
 
kallithea/public/codemirror/mode/http/
 
kallithea/public/codemirror/mode/http/http.js
 
kallithea/public/codemirror/mode/jade/
 
kallithea/public/codemirror/mode/jade/jade.js
 
kallithea/public/codemirror/mode/javascript/
 
kallithea/public/codemirror/mode/javascript/javascript.js
 
kallithea/public/codemirror/mode/jinja2/
 
kallithea/public/codemirror/mode/jinja2/jinja2.js
 
kallithea/public/codemirror/mode/julia/
 
kallithea/public/codemirror/mode/julia/julia.js
 
kallithea/public/codemirror/mode/kotlin/
 
kallithea/public/codemirror/mode/kotlin/kotlin.js
 
kallithea/public/codemirror/mode/livescript/
 
kallithea/public/codemirror/mode/livescript/livescript.js
 
kallithea/public/codemirror/mode/lua/
 
kallithea/public/codemirror/mode/lua/lua.js
 
kallithea/public/codemirror/mode/markdown/
 
kallithea/public/codemirror/mode/markdown/markdown.js
 
kallithea/public/codemirror/mode/meta.js
 
kallithea/public/codemirror/mode/mirc/
 
kallithea/public/codemirror/mode/mirc/mirc.js
 
kallithea/public/codemirror/mode/mllike/
 
kallithea/public/codemirror/mode/mllike/mllike.js
 
kallithea/public/codemirror/mode/modelica/
 
kallithea/public/codemirror/mode/modelica/modelica.js
 
kallithea/public/codemirror/mode/nginx/
 
kallithea/public/codemirror/mode/nginx/nginx.js
 
kallithea/public/codemirror/mode/ntriples/
 
kallithea/public/codemirror/mode/ntriples/ntriples.js
 
kallithea/public/codemirror/mode/octave/
 
kallithea/public/codemirror/mode/octave/octave.js
 
kallithea/public/codemirror/mode/pascal/
 
kallithea/public/codemirror/mode/pascal/pascal.js
 
kallithea/public/codemirror/mode/pegjs/
 
kallithea/public/codemirror/mode/pegjs/pegjs.js
 
kallithea/public/codemirror/mode/perl/
 
kallithea/public/codemirror/mode/perl/perl.js
 
kallithea/public/codemirror/mode/php/
 
kallithea/public/codemirror/mode/php/php.js
 
kallithea/public/codemirror/mode/pig/
 
kallithea/public/codemirror/mode/pig/pig.js
 
kallithea/public/codemirror/mode/properties/
 
kallithea/public/codemirror/mode/properties/properties.js
 
kallithea/public/codemirror/mode/puppet/
 
kallithea/public/codemirror/mode/puppet/puppet.js
 
kallithea/public/codemirror/mode/python/
 
kallithea/public/codemirror/mode/python/python.js
 
kallithea/public/codemirror/mode/q/
 
kallithea/public/codemirror/mode/q/q.js
 
kallithea/public/codemirror/mode/r/
 
kallithea/public/codemirror/mode/r/r.js
 
kallithea/public/codemirror/mode/rpm/
 
kallithea/public/codemirror/mode/rpm/rpm.js
 
kallithea/public/codemirror/mode/rst/
 
kallithea/public/codemirror/mode/rst/rst.js
 
kallithea/public/codemirror/mode/ruby/
 
kallithea/public/codemirror/mode/ruby/ruby.js
 
kallithea/public/codemirror/mode/rust/
 
kallithea/public/codemirror/mode/rust/rust.js
 
kallithea/public/codemirror/mode/sass/
 
kallithea/public/codemirror/mode/sass/sass.js
 
kallithea/public/codemirror/mode/scheme/
 
kallithea/public/codemirror/mode/scheme/scheme.js
 
kallithea/public/codemirror/mode/shell/
 
kallithea/public/codemirror/mode/shell/shell.js
 
kallithea/public/codemirror/mode/sieve/
 
kallithea/public/codemirror/mode/sieve/sieve.js
 
kallithea/public/codemirror/mode/slim/
 
kallithea/public/codemirror/mode/slim/slim.js
 
kallithea/public/codemirror/mode/smalltalk/
 
kallithea/public/codemirror/mode/smalltalk/smalltalk.js
 
kallithea/public/codemirror/mode/smarty/
 
kallithea/public/codemirror/mode/smarty/smarty.js
 
kallithea/public/codemirror/mode/smartymixed/
 
kallithea/public/codemirror/mode/smartymixed/smartymixed.js
 
kallithea/public/codemirror/mode/solr/
 
kallithea/public/codemirror/mode/solr/solr.js
 
kallithea/public/codemirror/mode/sparql/
 
kallithea/public/codemirror/mode/sparql/sparql.js
 
kallithea/public/codemirror/mode/sql/
 
kallithea/public/codemirror/mode/sql/sql.js
 
kallithea/public/codemirror/mode/stex/
 
kallithea/public/codemirror/mode/stex/stex.js
 
kallithea/public/codemirror/mode/tcl/
 
kallithea/public/codemirror/mode/tcl/tcl.js
 
kallithea/public/codemirror/mode/textile/
 
kallithea/public/codemirror/mode/textile/textile.js
 
kallithea/public/codemirror/mode/tiddlywiki/
 
kallithea/public/codemirror/mode/tiddlywiki/tiddlywiki.css
 
kallithea/public/codemirror/mode/tiddlywiki/tiddlywiki.js
 
kallithea/public/codemirror/mode/tiki/
 
kallithea/public/codemirror/mode/tiki/tiki.css
 
kallithea/public/codemirror/mode/tiki/tiki.js
 
kallithea/public/codemirror/mode/toml/
 
kallithea/public/codemirror/mode/toml/toml.js
 
kallithea/public/codemirror/mode/tornado/
 
kallithea/public/codemirror/mode/tornado/tornado.js
 
kallithea/public/codemirror/mode/turtle/
 
kallithea/public/codemirror/mode/turtle/turtle.js
 
kallithea/public/codemirror/mode/vb/
 
kallithea/public/codemirror/mode/vb/vb.js
 
kallithea/public/codemirror/mode/vbscript/
 
kallithea/public/codemirror/mode/vbscript/vbscript.js
 
kallithea/public/codemirror/mode/velocity/
 
kallithea/public/codemirror/mode/velocity/velocity.js
 
kallithea/public/codemirror/mode/verilog/
 
kallithea/public/codemirror/mode/verilog/verilog.js
 
kallithea/public/codemirror/mode/xml/
 
kallithea/public/codemirror/mode/xml/xml.js
 
kallithea/public/codemirror/mode/xquery/
 
kallithea/public/codemirror/mode/xquery/xquery.js
 
kallithea/public/codemirror/mode/yaml/
 
kallithea/public/codemirror/mode/yaml/yaml.js
 
kallithea/public/codemirror/mode/z80/
 
kallithea/public/codemirror/mode/z80/z80.js
 
kallithea/public/css/
 
kallithea/public/css/bootstrap.css
 
kallithea/public/css/contextbar.css
 
kallithea/public/css/mergely.css
 
kallithea/public/css/pygments.css
 
kallithea/public/css/style.css
 
kallithea/public/fontello/
 
kallithea/public/fontello/README-kallithea.txt
 
kallithea/public/fontello/README.txt
 
kallithea/public/fontello/config.json
 
kallithea/public/fontello/css/
 
kallithea/public/fontello/css/kallithea.css
 
kallithea/public/fontello/font/
 
kallithea/public/fontello/font/kallithea.eot
 
kallithea/public/fontello/font/kallithea.svg
 
kallithea/public/fontello/font/kallithea.ttf
 
kallithea/public/fontello/font/kallithea.woff
 
kallithea/public/images/
 
kallithea/public/images/background.png
 
kallithea/public/images/favicon.ico
 
kallithea/public/images/kallithea-logo.png
 
kallithea/public/images/kallithea-logo.svg
 
kallithea/public/images/pager.png
 
kallithea/public/images/pager_selected.png
 
kallithea/public/js/
 
kallithea/public/js/base.js
 
kallithea/public/js/bootstrap.js
 
kallithea/public/js/codemirror_loadmode.js
 
kallithea/public/js/graph.js
 
kallithea/public/js/jquery-1.11.1.min.js
 
kallithea/public/js/mergely.js
 
kallithea/public/js/mousetrap.js
 
kallithea/public/js/native.history.js
 
kallithea/public/js/select2/
 
kallithea/public/js/select2/select2-bootstrap.css
 
kallithea/public/js/select2/select2-spinner.gif
 
kallithea/public/js/select2/select2.css
 
kallithea/public/js/select2/select2.js
 
kallithea/public/js/select2/select2.png
 
kallithea/public/js/select2/select2x2.png
 
kallithea/public/js/yui.2.9.js
 
kallithea/public/js/yui.flot.js
 
kallithea/templates/
 
kallithea/templates/about.html
 
kallithea/templates/admin/
 
kallithea/templates/admin/admin.html
 
kallithea/templates/admin/admin_log.html
 
kallithea/templates/admin/auth/
 
kallithea/templates/admin/auth/auth_settings.html
 
kallithea/templates/admin/defaults/
 
kallithea/templates/admin/defaults/defaults.html
 
kallithea/templates/admin/gists/
 
kallithea/templates/admin/gists/edit.html
 
kallithea/templates/admin/gists/index.html
 
kallithea/templates/admin/gists/new.html
 
kallithea/templates/admin/gists/show.html
 
kallithea/templates/admin/my_account/
 
kallithea/templates/admin/my_account/my_account.html
 
kallithea/templates/admin/my_account/my_account_api_keys.html
 
kallithea/templates/admin/my_account/my_account_emails.html
 
kallithea/templates/admin/my_account/my_account_password.html
 
kallithea/templates/admin/my_account/my_account_perms.html
 
kallithea/templates/admin/my_account/my_account_profile.html
 
kallithea/templates/admin/my_account/my_account_repos.html
 
kallithea/templates/admin/my_account/my_account_watched.html
 
kallithea/templates/admin/notifications/
 
kallithea/templates/admin/notifications/notifications.html
 
kallithea/templates/admin/notifications/notifications_data.html
 
kallithea/templates/admin/notifications/show_notification.html
 
kallithea/templates/admin/permissions/
 
kallithea/templates/admin/permissions/permissions.html
 
kallithea/templates/admin/permissions/permissions_globals.html
 
kallithea/templates/admin/permissions/permissions_ips.html
 
kallithea/templates/admin/permissions/permissions_perms.html
 
kallithea/templates/admin/repo_groups/
 
kallithea/templates/admin/repo_groups/repo_group_add.html
 
kallithea/templates/admin/repo_groups/repo_group_edit.html
 
kallithea/templates/admin/repo_groups/repo_group_edit_advanced.html
 
kallithea/templates/admin/repo_groups/repo_group_edit_perms.html
 
kallithea/templates/admin/repo_groups/repo_group_edit_settings.html
 
kallithea/templates/admin/repo_groups/repo_group_show.html
 
kallithea/templates/admin/repo_groups/repo_groups.html
 
kallithea/templates/admin/repos/
 
kallithea/templates/admin/repos/repo_add.html
 
kallithea/templates/admin/repos/repo_add_base.html
 
kallithea/templates/admin/repos/repo_creating.html
 
kallithea/templates/admin/repos/repo_edit.html
 
kallithea/templates/admin/repos/repo_edit_advanced.html
 
kallithea/templates/admin/repos/repo_edit_caches.html
 
kallithea/templates/admin/repos/repo_edit_fields.html
 
kallithea/templates/admin/repos/repo_edit_fork.html
 
kallithea/templates/admin/repos/repo_edit_permissions.html
 
kallithea/templates/admin/repos/repo_edit_remote.html
 
kallithea/templates/admin/repos/repo_edit_settings.html
 
kallithea/templates/admin/repos/repo_edit_statistics.html
 
kallithea/templates/admin/repos/repos.html
 
kallithea/templates/admin/settings/
 
kallithea/templates/admin/settings/settings.html
 
kallithea/templates/admin/settings/settings_email.html
 
kallithea/templates/admin/settings/settings_global.html
 
kallithea/templates/admin/settings/settings_hooks.html
 
kallithea/templates/admin/settings/settings_mapping.html
 
kallithea/templates/admin/settings/settings_search.html
 
kallithea/templates/admin/settings/settings_system.html
 
kallithea/templates/admin/settings/settings_system_update.html
 
kallithea/templates/admin/settings/settings_vcs.html
 
kallithea/templates/admin/settings/settings_visual.html
 
kallithea/templates/admin/user_groups/
 
kallithea/templates/admin/user_groups/user_group_add.html
 
kallithea/templates/admin/user_groups/user_group_edit.html
 
kallithea/templates/admin/user_groups/user_group_edit_advanced.html
 
kallithea/templates/admin/user_groups/user_group_edit_default_perms.html
 
kallithea/templates/admin/user_groups/user_group_edit_members.html
 
kallithea/templates/admin/user_groups/user_group_edit_perms.html
 
kallithea/templates/admin/user_groups/user_group_edit_settings.html
 
kallithea/templates/admin/user_groups/user_groups.html
 
kallithea/templates/admin/users/
 
kallithea/templates/admin/users/user_add.html
 
kallithea/templates/admin/users/user_edit.html
 
kallithea/templates/admin/users/user_edit_advanced.html
 
kallithea/templates/admin/users/user_edit_api_keys.html
 
kallithea/templates/admin/users/user_edit_emails.html
 
kallithea/templates/admin/users/user_edit_ips.html
 
kallithea/templates/admin/users/user_edit_perms.html
 
kallithea/templates/admin/users/user_edit_profile.html
 
kallithea/templates/admin/users/users.html
 
kallithea/templates/base/
 
kallithea/templates/base/base.html
 
kallithea/templates/base/default_perms_box.html
 
kallithea/templates/base/flash_msg.html
 
kallithea/templates/base/perms_summary.html
 
kallithea/templates/base/root.html
 
kallithea/templates/bookmarks/
 
kallithea/templates/bookmarks/bookmarks.html
 
kallithea/templates/bookmarks/bookmarks_data.html
 
kallithea/templates/branches/
 
kallithea/templates/branches/branches.html
 
kallithea/templates/branches/branches_data.html
 
kallithea/templates/changelog/
 
kallithea/templates/changelog/changelog.html
 
kallithea/templates/changelog/changelog_details.html
 
kallithea/templates/changelog/changelog_summary_data.html
 
kallithea/templates/changeset/
 
kallithea/templates/changeset/changeset.html
 
kallithea/templates/changeset/changeset_comment_block.html
 
kallithea/templates/changeset/changeset_file_comment.html
 
kallithea/templates/changeset/changeset_range.html
 
kallithea/templates/changeset/diff_block.html
 
kallithea/templates/changeset/patch_changeset.html
 
kallithea/templates/compare/
 
kallithea/templates/compare/compare_cs.html
 
kallithea/templates/compare/compare_diff.html
 
kallithea/templates/data_table/
 
kallithea/templates/data_table/_dt_elements.html
 
kallithea/templates/email_templates/
 
kallithea/templates/email_templates/changeset_comment.html
 
kallithea/templates/email_templates/changeset_comment.txt
 
kallithea/templates/email_templates/default.html
 
kallithea/templates/email_templates/default.txt
 
kallithea/templates/email_templates/main.html
 
kallithea/templates/email_templates/main.txt
 
kallithea/templates/email_templates/password_reset.html
 
kallithea/templates/email_templates/password_reset.txt
 
kallithea/templates/email_templates/pull_request.html
 
kallithea/templates/email_templates/pull_request.txt
 
kallithea/templates/email_templates/pull_request_comment.html
 
kallithea/templates/email_templates/pull_request_comment.txt
 
kallithea/templates/email_templates/registration.html
 
kallithea/templates/email_templates/registration.txt
 
kallithea/templates/errors/
 
kallithea/templates/errors/error_document.html
 
kallithea/templates/files/
 
kallithea/templates/files/diff_2way.html
 
kallithea/templates/files/file_diff.html
 
kallithea/templates/files/files.html
 
kallithea/templates/files/files_add.html
 
kallithea/templates/files/files_browser.html
 
kallithea/templates/files/files_delete.html
 
kallithea/templates/files/files_edit.html
 
kallithea/templates/files/files_history_box.html
 
kallithea/templates/files/files_source.html
 
kallithea/templates/files/files_ypjax.html
 
kallithea/templates/followers/
 
kallithea/templates/followers/followers.html
 
kallithea/templates/followers/followers_data.html
 
kallithea/templates/forks/
 
kallithea/templates/forks/fork.html
 
kallithea/templates/forks/forks.html
 
kallithea/templates/forks/forks_data.html
 
kallithea/templates/index.html
 
kallithea/templates/index_base.html
 
kallithea/templates/journal/
 
kallithea/templates/journal/journal.html
 
kallithea/templates/journal/journal_data.html
 
kallithea/templates/journal/public_journal.html
 
kallithea/templates/login.html
 
kallithea/templates/password_reset.html
 
kallithea/templates/password_reset_confirmation.html
 
kallithea/templates/pullrequests/
 
kallithea/templates/pullrequests/pullrequest.html
 
kallithea/templates/pullrequests/pullrequest_data.html
 
kallithea/templates/pullrequests/pullrequest_show.html
 
kallithea/templates/pullrequests/pullrequest_show_all.html
 
kallithea/templates/pullrequests/pullrequest_show_my.html
 
kallithea/templates/register.html
 
kallithea/templates/search/
 
kallithea/templates/search/search.html
 
kallithea/templates/search/search_commit.html
 
kallithea/templates/search/search_content.html
 
kallithea/templates/search/search_path.html
 
kallithea/templates/search/search_repository.html
 
kallithea/templates/summary/
 
kallithea/templates/summary/statistics.html
 
kallithea/templates/summary/summary.html
 
kallithea/templates/switch_to_list.html
 
kallithea/templates/tags/
 
kallithea/templates/tags/tags.html
 
kallithea/templates/tags/tags_data.html
 
kallithea/tests/
 
kallithea/tests/__init__.py
 
kallithea/tests/api/
 
kallithea/tests/api/__init__.py
 
kallithea/tests/api/api_base.py
 
kallithea/tests/api/test_api_git.py
 
kallithea/tests/api/test_api_hg.py
 
kallithea/tests/conftest.py
 
kallithea/tests/fixture.py
 
kallithea/tests/fixtures/
 
kallithea/tests/fixtures/diff_with_diff_data.diff
 
kallithea/tests/fixtures/git_diff_binary_and_normal.diff
 
kallithea/tests/fixtures/git_diff_chmod.diff
 
kallithea/tests/fixtures/git_diff_mod_single_binary_file.diff
 
kallithea/tests/fixtures/git_diff_modify_binary_file.diff
 
kallithea/tests/fixtures/git_diff_rename_file.diff
 
kallithea/tests/fixtures/git_node_history_response.json
 
kallithea/tests/fixtures/hg_diff_add_single_binary_file.diff
 
kallithea/tests/fixtures/hg_diff_binary_and_normal.diff
 
kallithea/tests/fixtures/hg_diff_chmod.diff
 
kallithea/tests/fixtures/hg_diff_chmod_and_mod_single_binary_file.diff
 
kallithea/tests/fixtures/hg_diff_copy_and_chmod_file.diff
 
kallithea/tests/fixtures/hg_diff_copy_and_modify_file.diff
 
kallithea/tests/fixtures/hg_diff_copy_chmod_and_edit_file.diff
 
kallithea/tests/fixtures/hg_diff_copy_file.diff
 
kallithea/tests/fixtures/hg_diff_del_single_binary_file.diff
 
kallithea/tests/fixtures/hg_diff_mod_file_and_rename.diff
 
kallithea/tests/fixtures/hg_diff_mod_single_binary_file.diff
 
kallithea/tests/fixtures/hg_diff_mod_single_file_and_rename_and_chmod.diff
 
kallithea/tests/fixtures/hg_diff_rename_and_chmod_file.diff
 
kallithea/tests/fixtures/hg_diff_rename_file.diff
 
kallithea/tests/fixtures/hg_diff_rename_space_cr.diff
 
kallithea/tests/fixtures/hg_node_history_response.json
 
kallithea/tests/fixtures/journal_dump.csv
 
kallithea/tests/fixtures/markuptest.diff
 
kallithea/tests/fixtures/vcs_test_git.tar.gz
 
kallithea/tests/fixtures/vcs_test_hg.tar.gz
 
kallithea/tests/functional/
 
kallithea/tests/functional/__init__.py
 
kallithea/tests/functional/test_admin.py
 
kallithea/tests/functional/test_admin_auth_settings.py
 
kallithea/tests/functional/test_admin_defaults.py
 
kallithea/tests/functional/test_admin_gists.py
 
kallithea/tests/functional/test_admin_notifications.py
 
kallithea/tests/functional/test_admin_permissions.py
 
kallithea/tests/functional/test_admin_repo_groups.py
 
kallithea/tests/functional/test_admin_repos.py
 
kallithea/tests/functional/test_admin_settings.py
 
kallithea/tests/functional/test_admin_user_groups.py
 
kallithea/tests/functional/test_admin_users.py
 
kallithea/tests/functional/test_branches.py
 
kallithea/tests/functional/test_changelog.py
 
kallithea/tests/functional/test_changeset.py
 
kallithea/tests/functional/test_changeset_comments.py
 
kallithea/tests/functional/test_compare.py
 
kallithea/tests/functional/test_compare_local.py
 
kallithea/tests/functional/test_feed.py
 
kallithea/tests/functional/test_files.py
 
kallithea/tests/functional/test_followers.py
 
kallithea/tests/functional/test_forks.py
 
kallithea/tests/functional/test_home.py
 
kallithea/tests/functional/test_journal.py
 
kallithea/tests/functional/test_login.py
 
kallithea/tests/functional/test_my_account.py
 
kallithea/tests/functional/test_pullrequests.py
 
kallithea/tests/functional/test_repo_groups.py
 
kallithea/tests/functional/test_search.py
 
kallithea/tests/functional/test_summary.py
 
kallithea/tests/functional/test_tags.py
 
kallithea/tests/models/
 
kallithea/tests/models/__init__.py
 
kallithea/tests/models/common.py
 
kallithea/tests/models/test_changeset_status.py
 
kallithea/tests/models/test_diff_parsers.py
 
kallithea/tests/models/test_notifications.py
 
kallithea/tests/models/test_permissions.py
 
kallithea/tests/models/test_repo_groups.py
 
kallithea/tests/models/test_repos.py
 
kallithea/tests/models/test_user_group_permissions_on_repo_groups.py
 
kallithea/tests/models/test_user_groups.py
 
kallithea/tests/models/test_user_permissions_on_repo_groups.py
 
kallithea/tests/models/test_user_permissions_on_repos.py
 
kallithea/tests/models/test_users.py
 
kallithea/tests/other/
 
kallithea/tests/other/__init__.py
 
kallithea/tests/other/manual_test_vcs_operations.py
 
kallithea/tests/other/test_libs.py
 
kallithea/tests/other/test_mail.py
 
kallithea/tests/other/test_validators.py
 
kallithea/tests/parameterized.py
 
kallithea/tests/scripts/
 
kallithea/tests/scripts/create_rc.sh
 
kallithea/tests/scripts/manual_test_concurrency.py
 
kallithea/tests/scripts/manual_test_crawler.py
 
kallithea/tests/scripts/mem_watch
 
kallithea/tests/test.ini
 
kallithea/tests/vcs/
 
kallithea/tests/vcs/__init__.py
 
kallithea/tests/vcs/aconfig
 
kallithea/tests/vcs/base.py
 
kallithea/tests/vcs/conf.py
 
kallithea/tests/vcs/test_archives.py
 
kallithea/tests/vcs/test_branches.py
 
kallithea/tests/vcs/test_changesets.py
 
kallithea/tests/vcs/test_filenodes_unicode_path.py
 
kallithea/tests/vcs/test_getitem.py
 
kallithea/tests/vcs/test_getslice.py
 
kallithea/tests/vcs/test_git.py
 
kallithea/tests/vcs/test_hg.py
 
kallithea/tests/vcs/test_inmemchangesets.py
 
kallithea/tests/vcs/test_nodes.py
 
kallithea/tests/vcs/test_repository.py
 
kallithea/tests/vcs/test_tags.py
 
kallithea/tests/vcs/test_utils.py
 
kallithea/tests/vcs/test_utils_filesize.py
 
kallithea/tests/vcs/test_vcs.py
 
kallithea/tests/vcs/test_workdirs.py
 
kallithea/tests/vcs/utils.py
 
kallithea/websetup.py
 
setup.cfg
 
setup.py
scripts/whitespacecleanup.sh
Show inline comments
 
file renamed from whitespacecleanup.sh to scripts/whitespacecleanup.sh
setup.py
Show inline comments
 
@@ -100,48 +100,58 @@ keywords = ' '.join([
 
    'repo groups', 'ldap', 'repository management', 'hgweb replacement',
 
    'hgwebdir', 'gitweb replacement', 'serving hgweb',
 
])
 

	
 
# long description
 
README_FILE = 'README.rst'
 
CHANGELOG_FILE = 'docs/changelog.rst'
 
try:
 
    long_description = open(README_FILE).read() + '\n\n' + \
 
        open(CHANGELOG_FILE).read()
 

	
 
except IOError as err:
 
    sys.stderr.write(
 
        "[WARNING] Cannot find file specified as long_description (%s)\n or "
 
        "changelog (%s) skipping that file" % (README_FILE, CHANGELOG_FILE)
 
    )
 
    long_description = description
 

	
 
try:
 
    from setuptools import setup, find_packages
 
except ImportError:
 
    from ez_setup import use_setuptools
 
    use_setuptools()
 
    from setuptools import setup, find_packages
 

	
 
# monkey patch setuptools to use distutils owner/group functionality
 
from setuptools.command import sdist
 
sdist_org = sdist.sdist
 
class sdist_new(sdist_org):
 
    def initialize_options(self):
 
        sdist_org.initialize_options(self)
 
        self.owner = self.group = 'root'
 
sdist.sdist = sdist_new
 

	
 
# packages
 
packages = find_packages(exclude=['ez_setup'])
 

	
 
setup(
 
    name='Kallithea',
 
    version=__version__,
 
    description=description,
 
    long_description=long_description,
 
    keywords=keywords,
 
    license=__license__,
 
    author=__author__,
 
    author_email='kallithea@sfconservancy.org',
 
    dependency_links=dependency_links,
 
    url=__url__,
 
    install_requires=requirements,
 
    classifiers=classifiers,
 
    setup_requires=["PasteScript>=1.6.3"],
 
    data_files=data_files,
 
    packages=packages,
 
    include_package_data=True,
 
    test_suite='nose.collector',
 
    package_data=package_data,
 
    message_extractors={'kallithea': [
 
            ('**.py', 'python', None),
0 comments (0 inline, 0 general)