Compare commits
222 Commits
Author | SHA1 | Date |
---|---|---|
Adam Waldenberg | b8375442a7 | |
Adam Waldenberg | 6d77989e34 | |
Adam Waldenberg | c80c822892 | |
Adam Waldenberg | b3fbb3e3c3 | |
Bart van Andel | 40cfd0ac84 | |
Bart van Andel | 1e5f5959db | |
Bart van Andel | a8e0de7910 | |
Bart van Andel | 09c5e50381 | |
Bart van Andel | 55434ff76a | |
Bart van Andel | 3d11cdce44 | |
GuillermoMI | 315f4079ac | |
Adam Waldenberg | d0798d8358 | |
Adam Waldenberg | a56680c4b4 | |
Adam Waldenberg | 8cff4bd208 | |
Adam Waldenberg | 983d3d05bd | |
Adam Waldenberg | 9f336e63ce | |
Adam Waldenberg | ba1c3341fe | |
Adam Waldenberg | e543eeaf58 | |
Adam Waldenberg | 6e0365e8ba | |
Adam Waldenberg | 139f5306f4 | |
Adam Waldenberg | 9b5bbc469f | |
Adam Waldenberg | a9d519c93b | |
Adam Waldenberg | 9aa4aba336 | |
Adam Waldenberg | 6ef9936508 | |
Adam Waldenberg | 150e316918 | |
Adam Waldenberg | ba049a0367 | |
Gregrs | 3c48789890 | |
Adam Waldenberg | 533bba64c6 | |
Adam Waldenberg | 4ee02f5907 | |
Adam Waldenberg | 5275521a9a | |
Adam Waldenberg | ecc67a31a5 | |
Adam Waldenberg | 9bd4b979b3 | |
Adam Waldenberg | bfde70db91 | |
Adam Waldenberg | 12f8c8a192 | |
Adam Waldenberg | 9a22763e64 | |
Adam Waldenberg | 346645d655 | |
Adam Waldenberg | 91d94446a7 | |
Adam Waldenberg | 88d840dd51 | |
Adam Waldenberg | 26f77e0ee4 | |
Adam Waldenberg | 4d6ecd3123 | |
Adam Waldenberg | 9b3a5b674e | |
Adam Waldenberg | 87fd5b467f | |
Adam Waldenberg | 4fd918fca4 | |
Adam Waldenberg | 949a301698 | |
Adam Waldenberg | 211060c20e | |
Adam Waldenberg | 9ada057d81 | |
Adam Waldenberg | 7dda8d34b5 | |
Adam Waldenberg | d5106a7302 | |
Adam Waldenberg | 01bdbfaba1 | |
Adam Waldenberg | 7f5b50cd0d | |
Adam Waldenberg | 802f18e7e5 | |
Adam Waldenberg | 7acf871ab1 | |
Adam Waldenberg | 98615ccbfc | |
Adam Waldenberg | 46b21db196 | |
Adam Waldenberg | 3bae1be0cb | |
Adam Waldenberg | 9287b187f7 | |
Adam Waldenberg | dd2feedbe4 | |
Adam Waldenberg | e0941fdcf1 | |
Adam Waldenberg | 109a94e1e7 | |
Adam Waldenberg | 258eefa1e7 | |
Adam Waldenberg | d88ff2c5b9 | |
Adam Waldenberg | c01a59430c | |
Adam Waldenberg | 5af89f798a | |
Adam Waldenberg | d30715cc84 | |
Adam Waldenberg | ce91c4176a | |
Adam Waldenberg | 6606d8b13c | |
Adam Waldenberg | 1ed9b5e3cf | |
Adam Waldenberg | fa04eb57f3 | |
Adam Waldenberg | d941487280 | |
Adam Waldenberg | d8dfecb19a | |
Adam Waldenberg | 4bd723eea0 | |
Adam Waldenberg | 859224f36f | |
Bill Wang | 5ee5127b15 | |
Bill Wang | 75b528a84a | |
Adam Waldenberg | 8a0ba3dca1 | |
Luca Motta | 58a983ed27 | |
Adam Waldenberg | eec6741cfb | |
Yannick Moy | 21c6346868 | |
Adam Waldenberg | 78831c1b9b | |
Kamila Chyla | 79e390afe8 | |
Adam Waldenberg | 81e18ff075 | |
xxyy | b0e7bb5ae9 | |
Adam Waldenberg | b4eb5484ac | |
Adam Waldenberg | bbe07f061d | |
Adam Waldenberg | cff8dd109b | |
Adam Waldenberg | 124636cb85 | |
Adam Waldenberg | e9eab37c83 | |
Marc Harper | 59d9e5c7ae | |
Marc Harper | 4f3e0d3073 | |
Marc Harper | 9abb9b3d56 | |
Adam Waldenberg | f2a4cb92d3 | |
Adam Waldenberg | d333f7bdd2 | |
Adam Waldenberg | 1f2f120389 | |
Adam Waldenberg | 34337dec17 | |
Adam Waldenberg | 6aa41ade9f | |
Adam Waldenberg | fa483b4327 | |
Adam Waldenberg | 5259b76b94 | |
Adam Waldenberg | 4b92e7a3cc | |
Agustín Cañas | 9368898d6d | |
Adam Waldenberg | 38df413ebf | |
Adam Waldenberg | c0cb2d2801 | |
Adam Waldenberg | 07f17f3d2e | |
Adam Waldenberg | 47b11addd9 | |
Adam Waldenberg | aa727a95c3 | |
Adam Waldenberg | 3e88fcb71a | |
Adam Waldenberg | 243e52b5de | |
Adam Waldenberg | e4827ee58e | |
Adam Waldenberg | 6d89cdf8c8 | |
Agustín Cañas | ad36849afb | |
Adam Waldenberg | e3f741b518 | |
Adam Waldenberg | 583b5fa753 | |
Adam Waldenberg | 582ffe7246 | |
Adam Waldenberg | a6c05cc619 | |
Adam Waldenberg | da1553b57e | |
Adam Waldenberg | f368c0019a | |
Adam Waldenberg | 5a18732112 | |
Adam Waldenberg | b4b48deebd | |
Adam Waldenberg | aeb9ad69f9 | |
Adam Waldenberg | 7a9eb69ab0 | |
Adam Waldenberg | f37bdb7c58 | |
Adam Waldenberg | f6fd00f411 | |
Adam Waldenberg | 124ca74650 | |
Adam Waldenberg | 98c375a0ab | |
Adam Waldenberg | b48c65efb1 | |
Adam Waldenberg | 25b5507267 | |
Adam Waldenberg | c5e861d662 | |
Adam Waldenberg | ade7a5ad9b | |
Adam Waldenberg | b20d91b3cb | |
Adam Waldenberg | 15c1816a73 | |
Adam Waldenberg | 8b4ac7d423 | |
Adam Waldenberg | 52946d4770 | |
Adam Waldenberg | bf9e5b700c | |
Adam Waldenberg | 42b2288c85 | |
Roman Levin | edf1843300 | |
Adam Waldenberg | 4aa388553c | |
Kamila Chyla | 96e2b0fdf0 | |
Adam Waldenberg | 30a20e6b52 | |
Adam Waldenberg | 4803c511df | |
Adam Waldenberg | 1bc3e026ed | |
Adam Waldenberg | e8648a51c2 | |
Adam Waldenberg | 02b6db512b | |
Adam Waldenberg | de602bb70f | |
Kamila Chyla | 6c45819a62 | |
Adam Waldenberg | 568a5e5e8b | |
Adam Waldenberg | b327238496 | |
Adam Waldenberg | 1230fcf80c | |
Adam Waldenberg | eed6d0debf | |
Adam Waldenberg | 8c464fddd4 | |
Philipp Nowak | a42726aedb | |
Bill Wang | e169421fa9 | |
Dmitry Dzhus | c6928bd675 | |
Luca Motta | cbed2ac13f | |
Yannick Moy | 2ca997cc9d | |
Adam Waldenberg | e703856560 | |
Adam Waldenberg | b22d614849 | |
Adam Waldenberg | 4d6e51a760 | |
Adam Waldenberg | 26e2ce7c07 | |
Adam Waldenberg | bc6be1c56f | |
Adam Waldenberg | bc9fd8b207 | |
Adam Waldenberg | d315829e9d | |
Adam Waldenberg | 8755fb33dc | |
Christian Kastner | 3010359eb2 | |
Adam Waldenberg | dd50994f2c | |
Christian Kastner | e3b4857eb6 | |
Jon Warghed | 68a6e90228 | |
Adam Waldenberg | 1d2fd619bd | |
Adam Waldenberg | fa5e5411f5 | |
Yannick Moy | 12dce7f365 | |
Diomidis Spinellis | bc5b0abe74 | |
Diomidis Spinellis | b20f15e794 | |
Chris Barry | d6a2f33de5 | |
Adam Waldenberg | 7b61a46d7c | |
Adam Waldenberg | 93b18cdd9a | |
Adam Waldenberg | 722ca9b91a | |
Adam Waldenberg | 144303dab6 | |
Adam Waldenberg | 6052eb5646 | |
Adam Waldenberg | 232e041861 | |
Adam Waldenberg | efe04cc10b | |
Adam Waldenberg | f85c2fe7b4 | |
Adam Waldenberg | b2528cfda7 | |
Adam Waldenberg | fac4b34646 | |
Adam Waldenberg | 9b2aecc3e9 | |
Adam Waldenberg | 786a44ddbc | |
Adam Waldenberg | 4e4d0a2ddb | |
Adam Waldenberg | 12e08daf72 | |
Adam Waldenberg | 0447da1933 | |
Adam Waldenberg | e902f7b82d | |
Adam Waldenberg | 02e0858985 | |
Adam Waldenberg | a1e90d0a9d | |
Adam Waldenberg | 16154cd0ba | |
Adam Waldenberg | 98e3f45d65 | |
Adam Waldenberg | d99e8cb58d | |
Adam Waldenberg | d8bdbe9f6f | |
Adam Waldenberg | a45df61aa9 | |
Adam Waldenberg | 974be06f2b | |
Adam Waldenberg | 2b4e6bb111 | |
Kamila Chyla | 49c80184e2 | |
Bill Wang | f834fc613e | |
Adam Waldenberg | 1269df639e | |
Adam Waldenberg | 37c295186c | |
Adam Waldenberg | 3d6789f728 | |
Luca Motta | 949d73a4b4 | |
Adam Waldenberg | 8d9d73549c | |
Adam Waldenberg | f044b9ef9d | |
Adam Waldenberg | 23bc5fbbea | |
Adam Waldenberg | bc00f9731b | |
Adam Waldenberg | af7840be81 | |
Adam Waldenberg | a1d83ead9e | |
Adam Waldenberg | abbeed5356 | |
Adam Waldenberg | 37d78ff992 | |
Adam Waldenberg | 1a828136b5 | |
Adam Waldenberg | 998ec7456f | |
Adam Waldenberg | 791e9e39dd | |
Adam Waldenberg | e263982806 | |
Adam Waldenberg | cf0f40cc4d | |
Adam Waldenberg | c96d3c3ffe | |
Adam Waldenberg | e7d69d78aa | |
Adam Waldenberg | 2633e04c3a | |
Adam Waldenberg | bc182c6924 | |
Chris Ring | 00fdec2928 | |
Adam Waldenberg | a4a0e409a2 | |
Adam Waldenberg | 1edae66fee |
|
@ -2,5 +2,7 @@ build
|
|||
debian
|
||||
deb_dist
|
||||
dist
|
||||
node_modules
|
||||
*.egg-info
|
||||
*.pyc
|
||||
*.tgz
|
||||
|
|
|
@ -3,7 +3,7 @@ include-ids=yes
|
|||
comment=yes
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
disable=C0111,R0801,W0232,W0603,W0622,W0702
|
||||
disable=C0111,R0801,W0232,W0603,W0622,W0702,W0141
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
gitinspector (0.4.4)
|
||||
|
||||
Minor release with some minor fixes.
|
||||
|
||||
* Better support for additional terminals.
|
||||
* -f "**" now properly ignores binary files.
|
||||
|
||||
gitinspector (0.4.3)
|
||||
|
||||
Minor release with updated language locales.
|
||||
|
||||
|
||||
gitinspector (0.4.2)
|
||||
|
||||
Minor release with many small, but great improvements.
|
||||
|
||||
* The changes module is now threaded and uses all available cores. This
|
||||
results in a significant speed up.
|
||||
* Printed extensions are now alphabetically sorted.
|
||||
* Ability to exclude commits with certain comments from statistics.
|
||||
* Support for C# code and comments.
|
||||
* Extensionless files can now be included in statistics.
|
||||
* Ability to include all file extensions by specifying "**".
|
||||
* Spanish translation.
|
||||
|
||||
|
||||
gitinspector (0.4.1)
|
||||
|
||||
Maintenance release fixing several issues found in the previous version.
|
||||
|
||||
|
||||
gitinspector (0.4.0)
|
||||
|
||||
Major update with many fixes and new features.
|
||||
|
||||
* Support for remote repositories (git://, http(s)://, ssh://).
|
||||
* Code stability and age shown in blame output.
|
||||
* Support for cyclomatic complexity and cyclomatic complexity density
|
||||
metrics.
|
||||
* Ability to exclude commit hashes (revisions) from statistics.
|
||||
* Improved HTML output.
|
||||
* Support for ADA, OCaml and Haskell comments.
|
||||
* Improved localization support for languages with multi-column
|
||||
characters.
|
||||
* Many (big and small) bug fixes.
|
||||
* French translation.
|
||||
* German translation.
|
||||
|
||||
|
||||
gitinspector (0.3.2)
|
||||
|
||||
Maintenance release that adds several new features and bug fixes.
|
||||
|
||||
* Better handling of terminals that have no encoding configured.
|
||||
* File extensions .cc and .hh scanned by default.
|
||||
* Support for bare repositories.
|
||||
* Support for comments in .xhtml, .jspx, and .scala files.
|
||||
* The ability to filter out statistics from specific authors or
|
||||
emails.
|
||||
* The flag --since now behaves correctly.
|
||||
* Italian translation.
|
||||
* Polish translation.
|
||||
|
||||
|
||||
gitinspector (0.3.1)
|
||||
|
||||
Minor release which adds support for gravatars.
|
||||
|
||||
* A few minor bug fixes.
|
||||
* Chinese translation.
|
||||
* Support for gravatars in the HTML and XML outputs.
|
||||
* Improved responsibilities section in the HTML output.
|
||||
* Debian package now properly depends on git.
|
||||
|
||||
|
||||
gitinspector (0.3.0)
|
||||
|
||||
This is a major release with many new features.
|
||||
|
||||
* Support for comments in LaTex (.tex) and PHP files.
|
||||
* Many bugfixes.
|
||||
* Localization support (English and Swedish for now).
|
||||
* Support for setting gitinspector options via git-config.
|
||||
* Support for regular expressions in conjunction with -x/--exclude.
|
||||
* New output format; "htmlembedded".
|
||||
* Support for Python packaging via setuptools.
|
||||
* Improved HTML output with new JQuery and flot versions.
|
||||
|
||||
|
||||
gitinspector (0.2.2)
|
||||
|
||||
This is a maintenance release that fixes several bugs; many related to
|
||||
character encoding. This version also adds table sorting to the HTML
|
||||
output.
|
||||
|
||||
|
||||
gitinspector (0.2.1)
|
||||
|
||||
Maintenance release that fixes compatibility with Python 3 and
|
||||
introduces the --since and --until interval flags.
|
||||
|
||||
|
||||
gitinspector (0.2.0)
|
||||
|
||||
This release includes several bug fixes and introduces HTML and XML
|
||||
output formats.
|
||||
|
||||
|
||||
gitinspector (0.1.0)
|
||||
|
||||
First public release. While incomplete, this release fulfills the most
|
||||
important feature requirements that were originally outlined.
|
|
@ -0,0 +1,56 @@
|
|||
[![Latest release](https://img.shields.io/github/release/ejwa/gitinspector.svg?style=flat-square)](https://github.com/ejwa/gitinspector/releases/latest)
|
||||
[![License](https://img.shields.io/github/license/ejwa/gitinspector.svg?style=flat-square)](https://github.com/ejwa/gitinspector/blob/master/LICENSE.txt)
|
||||
<h2>
|
||||
<img align="left" height="65px"
|
||||
src="https://raw.githubusercontent.com/ejwa/gitinspector/master/gitinspector/html/gitinspector_piclet.png"/>
|
||||
About Gitinspector
|
||||
</h2>
|
||||
<img align="right" width="30%" src="https://raw.github.com/wiki/ejwa/gitinspector/images/html_example.jpg" />
|
||||
Gitinspector is a statistical analysis tool for git repositories. The default analysis shows general statistics per author, which can be complemented with a timeline analysis that shows the workload and activity of each author. Under normal operation, it filters the results to only show statistics about a number of given extensions and by default only includes source files in the statistical analysis.
|
||||
|
||||
This tool was originally written to help fetch repository statistics from student projects in the course Object-oriented Programming Project (TDA367/DIT211) at Chalmers University of Technology and Gothenburg University.
|
||||
|
||||
Today, gitinspector is used as a grading aid by universities worldwide.
|
||||
|
||||
A full [Documentation](https://github.com/ejwa/gitinspector/wiki/Documentation) of the usage and available options of gitinspector is available on the wiki. For help on the most common questions, please refer to the [FAQ](https://github.com/ejwa/gitinspector/wiki/FAQ) document.
|
||||
|
||||
### Some of the features
|
||||
* Shows cumulative work by each author in the history.
|
||||
* Filters results by extension (default: java,c,cc,cpp,h,hh,hpp,py,glsl,rb,js,sql).
|
||||
* Can display a statistical timeline analysis.
|
||||
* Scans for all filetypes (by extension) found in the repository.
|
||||
* Multi-threaded; uses multiple instances of git to speed up analysis when possible.
|
||||
* Supports HTML, JSON, XML and plain text output (console).
|
||||
* Can report violations of different code metrics.
|
||||
|
||||
### Example outputs
|
||||
Below are some example outputs for a number of famous open source projects. All the statistics were generated using the *"-HTlrm"* flags.
|
||||
|
||||
| Project name | | | | |
|
||||
|---|---|---|---|---|
|
||||
| Django | [HTML](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/django_output.html) | [HTML Embedded](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/django_output.emb.html) | [Plain Text](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/django_output.txt) | [XML](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/django_output.xml) |
|
||||
| JQuery | [HTML](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/jquery_output.html) | [HTML Embedded](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/jquery_output.emb.html) | [Plain Text](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/jquery_output.txt) | [XML](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/jquery_output.xml) |
|
||||
| Pango | [HTML](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/pango_output.html) | [HTML Embedded](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/pango_output.emb.html) | [Plain Text](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/pango_output.txt) | [XML](http://githubproxy.ejwa.se/wiki/ejwa/gitinspector/examples/pango_output.xml) |
|
||||
|
||||
### The Team
|
||||
* Adam Waldenberg, Lead maintainer and Swedish translation
|
||||
* Agustín Cañas, Spanish translation
|
||||
* Bart van Andel, npm package maintainer
|
||||
* Bill Wang, Chinese translation
|
||||
* Christian Kastner, Debian package maintainer
|
||||
* Jiwon Kim, Korean translation
|
||||
* Kamila Chyla, Polish translation
|
||||
* Luca Motta, Italian translation
|
||||
* Philipp Nowak, German translation
|
||||
* Sergei Lomakov, Russian translation
|
||||
* Yannick Moy, French translation
|
||||
|
||||
*We need translations for gitinspector!* If you are a gitinspector user, feel willing to help and have good language skills in any unsupported language we urge you to contact us. We also happily accept code patches. Please refer to [Contributing](https://github.com/ejwa/gitinspector/wiki/Contributing) for more information on how to contribute to the project.
|
||||
|
||||
### Packages
|
||||
The Debian packages offered with releases of gitinspector are unofficial and very simple packages generated with [stdeb](https://github.com/astraw/stdeb). Christian Kastner is maintaining the official Debian packages. You can check the current status on the [Debian Package Tracker](https://tracker.debian.org/pkg/gitinspector). Consequently, there are official packages for many Debian based distributions installable via *apt-get*.
|
||||
|
||||
An [npm](https://npmjs.com) package is provided for convenience as well. To install it globally, execute `npm i -g gitinspector`.
|
||||
|
||||
### License
|
||||
gitinspector is licensed under the *GNU GPL v3*. The gitinspector logo is partly based on the git logo; based on the work of Jason Long. The logo is licensed under the *Creative Commons Attribution 3.0 Unported License*.
|
|
@ -1,4 +1,4 @@
|
|||
Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
|
||||
This program comes with ABSOLUTELY NO WARRANTY.
|
||||
This is free software, and you are welcome to redistribute it under
|
||||
|
@ -7,9 +7,9 @@ certain conditions; see the accompanying LICENSE.txt file for further details.
|
|||
For questions regarding gitinspector you can contact the current maintainer
|
||||
in charge at gitinspector@ejwa.se.
|
||||
|
||||
To run gitinspector; please start it via the gitinspector/gitinspector.py
|
||||
script. Use the -h or --help flags to get help about available options.
|
||||
To run gitinspector; please start it via the gitinspector.py script. Use
|
||||
the -h or --help flags to get help about available options.
|
||||
|
||||
It is also possible to set gitinspector options using the "git config"
|
||||
command. Refer to the project page at http://gitinspector.googlecode.com
|
||||
command. Refer to the project page at https://github.com/ejwa/gitinspector
|
||||
for more information.
|
||||
|
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
CSS stylesheet for XHTML produced by DocBook XSL stylesheets.
|
||||
*/
|
||||
|
||||
body {
|
||||
font-family: Georgia,serif;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
|
||||
span.strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
body blockquote {
|
||||
margin-top: .75em;
|
||||
line-height: 1.5;
|
||||
margin-bottom: .75em;
|
||||
}
|
||||
|
||||
html body {
|
||||
margin: 1em 5% 1em 5%;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
body div {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6
|
||||
{
|
||||
color: #527bbd;
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
}
|
||||
|
||||
div.toc p:first-child,
|
||||
div.list-of-figures p:first-child,
|
||||
div.list-of-tables p:first-child,
|
||||
div.list-of-examples p:first-child,
|
||||
div.example p.title,
|
||||
div.sidebar p.title
|
||||
{
|
||||
font-weight: bold;
|
||||
color: #527bbd;
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
body h1 {
|
||||
margin: .0em 0 0 -4%;
|
||||
line-height: 1.3;
|
||||
border-bottom: 2px solid silver;
|
||||
}
|
||||
|
||||
body h2 {
|
||||
margin: 0.5em 0 0 -4%;
|
||||
line-height: 1.3;
|
||||
border-bottom: 2px solid silver;
|
||||
}
|
||||
|
||||
body h3 {
|
||||
margin: .8em 0 0 -3%;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
body h4 {
|
||||
margin: .8em 0 0 -3%;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
body h5 {
|
||||
margin: .8em 0 0 -2%;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
body h6 {
|
||||
margin: .8em 0 0 -1%;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
body hr {
|
||||
border: none; /* Broken on IE6 */
|
||||
}
|
||||
div.footnotes hr {
|
||||
border: 1px solid silver;
|
||||
}
|
||||
|
||||
div.navheader th, div.navheader td, div.navfooter td {
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
color: #527bbd;
|
||||
}
|
||||
div.navheader img, div.navfooter img {
|
||||
border-style: none;
|
||||
}
|
||||
div.navheader a, div.navfooter a {
|
||||
font-weight: normal;
|
||||
}
|
||||
div.navfooter hr {
|
||||
border: 1px solid silver;
|
||||
}
|
||||
|
||||
body td {
|
||||
line-height: 1.2
|
||||
}
|
||||
|
||||
body th {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
ol {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
ul, body dir, body menu {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body h1, body h2, body h3, body h4, body h5, body h6 {
|
||||
margin-left: 0
|
||||
}
|
||||
|
||||
body pre {
|
||||
margin: 0.5em 10% 0.5em 1em;
|
||||
line-height: 1.0;
|
||||
color: navy;
|
||||
}
|
||||
|
||||
tt.literal, code.literal {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
.programlisting, .screen {
|
||||
border: 1px solid silver;
|
||||
background: #f4f4f4;
|
||||
margin: 0.5em 10% 0.5em 0;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
div.sidebar {
|
||||
background: #ffffee;
|
||||
margin: 1.0em 10% 0.5em 0;
|
||||
padding: 0.5em 1em;
|
||||
border: 1px solid silver;
|
||||
}
|
||||
div.sidebar * { padding: 0; }
|
||||
div.sidebar div { margin: 0; }
|
||||
div.sidebar p.title {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
div.bibliomixed {
|
||||
margin: 0.5em 5% 0.5em 1em;
|
||||
}
|
||||
|
||||
div.glossary dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
div.glossary dd p {
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: .8em 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
dt span.term {
|
||||
font-style: normal;
|
||||
color: navy;
|
||||
}
|
||||
|
||||
div.variablelist dd p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
div.itemizedlist li, div.orderedlist li {
|
||||
margin-left: -0.8em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
list-style-position: outside;
|
||||
}
|
||||
|
||||
div.sidebar ul, div.sidebar ol {
|
||||
margin-left: 2.8em;
|
||||
}
|
||||
|
||||
div.itemizedlist p.title,
|
||||
div.orderedlist p.title,
|
||||
div.variablelist p.title
|
||||
{
|
||||
margin-bottom: -0.8em;
|
||||
}
|
||||
|
||||
div.revhistory table {
|
||||
border-collapse: collapse;
|
||||
border: none;
|
||||
}
|
||||
div.revhistory th {
|
||||
border: none;
|
||||
color: #527bbd;
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
}
|
||||
div.revhistory td {
|
||||
border: 1px solid silver;
|
||||
}
|
||||
|
||||
/* Keep TOC and index lines close together. */
|
||||
div.toc dl, div.toc dt,
|
||||
div.list-of-figures dl, div.list-of-figures dt,
|
||||
div.list-of-tables dl, div.list-of-tables dt,
|
||||
div.indexdiv dl, div.indexdiv dt
|
||||
{
|
||||
line-height: normal;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Table styling does not work because of overriding attributes in
|
||||
generated HTML.
|
||||
*/
|
||||
div.table table,
|
||||
div.informaltable table
|
||||
{
|
||||
margin-left: 0;
|
||||
margin-right: 5%;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
div.informaltable table
|
||||
{
|
||||
margin-top: 0.4em
|
||||
}
|
||||
div.table thead,
|
||||
div.table tfoot,
|
||||
div.table tbody,
|
||||
div.informaltable thead,
|
||||
div.informaltable tfoot,
|
||||
div.informaltable tbody
|
||||
{
|
||||
/* No effect in IE6. */
|
||||
border-top: 3px solid #527bbd;
|
||||
border-bottom: 3px solid #527bbd;
|
||||
}
|
||||
div.table thead, div.table tfoot,
|
||||
div.informaltable thead, div.informaltable tfoot
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.mediaobject img {
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
div.figure p.title,
|
||||
div.table p.title
|
||||
{
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
div.calloutlist p
|
||||
{
|
||||
margin-top: 0em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
a img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
div.navheader, div.navfooter { display: none; }
|
||||
}
|
||||
|
||||
span.aqua { color: aqua; }
|
||||
span.black { color: black; }
|
||||
span.blue { color: blue; }
|
||||
span.fuchsia { color: fuchsia; }
|
||||
span.gray { color: gray; }
|
||||
span.green { color: green; }
|
||||
span.lime { color: lime; }
|
||||
span.maroon { color: maroon; }
|
||||
span.navy { color: navy; }
|
||||
span.olive { color: olive; }
|
||||
span.purple { color: purple; }
|
||||
span.red { color: red; }
|
||||
span.silver { color: silver; }
|
||||
span.teal { color: teal; }
|
||||
span.white { color: white; }
|
||||
span.yellow { color: yellow; }
|
||||
|
||||
span.aqua-background { background: aqua; }
|
||||
span.black-background { background: black; }
|
||||
span.blue-background { background: blue; }
|
||||
span.fuchsia-background { background: fuchsia; }
|
||||
span.gray-background { background: gray; }
|
||||
span.green-background { background: green; }
|
||||
span.lime-background { background: lime; }
|
||||
span.maroon-background { background: maroon; }
|
||||
span.navy-background { background: navy; }
|
||||
span.olive-background { background: olive; }
|
||||
span.purple-background { background: purple; }
|
||||
span.red-background { background: red; }
|
||||
span.silver-background { background: silver; }
|
||||
span.teal-background { background: teal; }
|
||||
span.white-background { background: white; }
|
||||
span.yellow-background { background: yellow; }
|
||||
|
||||
span.big { font-size: 2em; }
|
||||
span.small { font-size: 0.6em; }
|
||||
|
||||
span.underline { text-decoration: underline; }
|
||||
span.overline { text-decoration: overline; }
|
||||
span.line-through { text-decoration: line-through; }
|
|
@ -0,0 +1,313 @@
|
|||
'\" t
|
||||
.\" Title: gitinspector
|
||||
.\" Author: [see the "AUTHOR" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 12/14/2015
|
||||
.\" Manual: The gitinspector Manual
|
||||
.\" Source: gitinspector 0.4.2
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "GITINSPECTOR" "1" "12/14/2015" "gitinspector 0\&.4\&.2" "The gitinspector Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
gitinspector \- statistical analysis tool for git repositories
|
||||
.SH "SYNOPSIS"
|
||||
.sp
|
||||
\fBgitinspector\fR [OPTION]\&... [REPOSITORY]
|
||||
.SH "DESCRIPTION"
|
||||
.sp
|
||||
Analyze and gather statistics about a git repository\&. The defaut analysis shows general statistics per author, which can be complemented with a timeline analysis that shows the workload and activity of each author\&. Under normal operation, gitinspector filters the results to only show statistics about a number of given extensions and by default only includes source files in the statistical analysis\&.
|
||||
.sp
|
||||
Several output formats are supported, including plain text, HTML, JSON and XML\&.
|
||||
.SH "OPTIONS"
|
||||
.sp
|
||||
List information about the repository in REPOSITORY\&. If no repository is specified, the current directory is used\&. If multiple repositories are given, information will be fetched from the last repository specified\&.
|
||||
.sp
|
||||
Mandatory arguments to long options are mandatory for short options too\&. Boolean arguments can only be given to long options\&.
|
||||
.PP
|
||||
\fB\-f, \-\-file\-types\fR=EXTENSIONS
|
||||
.RS 4
|
||||
A comma separated list of file extensions to include when computing statistics\&. The default extensions used are: java,c,cc,cpp,h,hh,hpp,py,glsl,rb,js,sql\&. Specifying a single
|
||||
\fI*\fR
|
||||
asterisk character includes files with no extension\&. Specifying two consecutive
|
||||
\fI**\fR
|
||||
asterisk characters includes all files regardless of extension\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-F, \-\-format\fR=FORMAT
|
||||
.RS 4
|
||||
Defines in which format output should be generated; the default format is
|
||||
\fItext\fR
|
||||
and the available formats are: html,htmlembedded,json,text,xml (see
|
||||
\fBOUTPUT FORMATS\fR)
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-grading\fR[=BOOL]
|
||||
.RS 4
|
||||
Show statistics and information in a way that is formatted for grading of student projects; this is the same as supplying the options
|
||||
\fB\-HlmrTw\fR
|
||||
.RE
|
||||
.PP
|
||||
\fB\-H, \-\-hard\fR[=BOOL]
|
||||
.RS 4
|
||||
Track rows and look for duplicates harder; this can be quite slow with big repositories
|
||||
.RE
|
||||
.PP
|
||||
\fB\-l, \-\-list\-file\-types\fR[=BOOL]
|
||||
.RS 4
|
||||
List all the file extensions available in the current branch of the repository
|
||||
.RE
|
||||
.PP
|
||||
\fB\-L, \-\-localize\-output\fR[=BOOL]
|
||||
.RS 4
|
||||
Localize the generated output to the selected system language if a translation is available
|
||||
.RE
|
||||
.PP
|
||||
\fB\-m, \-\-metrics\fR[=BOOL]
|
||||
.RS 4
|
||||
Include checks for certain metrics during the analysis of commits
|
||||
.RE
|
||||
.PP
|
||||
\fB\-r \-\-responsibilities\fR[=BOOL]
|
||||
.RS 4
|
||||
Show which files the different authors seem most responsible for
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-since\fR=DATE
|
||||
.RS 4
|
||||
Only show statistics for commits more recent than a specific date
|
||||
.RE
|
||||
.PP
|
||||
\fB\-T, \-\-timeline\fR[=BOOL]
|
||||
.RS 4
|
||||
Show commit timeline, including author names
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-until\fR=DATE
|
||||
.RS 4
|
||||
Only show statistics for commits older than a specific date
|
||||
.RE
|
||||
.PP
|
||||
\fB\-w, \-\-weeks\fR[=BOOL]
|
||||
.RS 4
|
||||
Show all statistical information in weeks instead of in months
|
||||
.RE
|
||||
.PP
|
||||
\fB\-x, \-\-exclude\fR=PATTERN
|
||||
.RS 4
|
||||
An exclusion pattern describing the file paths, revisions, author names or author emails that should be excluded from the statistics; can be specified multiple times (see
|
||||
\fBFILTERING\fR)
|
||||
.RE
|
||||
.PP
|
||||
\fB\-h, \-\-help\fR
|
||||
.RS 4
|
||||
Display help and exit
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-version\fR
|
||||
.RS 4
|
||||
Output version information and exit
|
||||
.RE
|
||||
.SH "OUTPUT FORMATS"
|
||||
.sp
|
||||
There is support for multiple output formats in gitinspector\&. They can be selected using the \fB\-F\fR/\fB\-\-format\fR flags when running the main gitinspector script\&.
|
||||
.PP
|
||||
\fBtext (plain text)\fR
|
||||
.RS 4
|
||||
Plain text with some very simple ANSI formatting, suitable for console output\&. This is the format chosen by default in gitinspector\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBhtml\fR
|
||||
.RS 4
|
||||
HTML with external links\&. The generated HTML page links to some external resources; such as the JavaScript library JQuery\&. It requires an active internet connection to properly function\&. This output format will most likely also link to additional external resources in the future\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBhtmlembedded\fR
|
||||
.RS 4
|
||||
HTML with no external links\&. Similar to the HTML output format, but requires no active internet connection\&. As a consequence; the generated pages are bigger (as certain scripts have to be embedded into the generated output)\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBjson\fR
|
||||
.RS 4
|
||||
JSON suitable for machine consumption\&. If you want to parse the output generated by gitinspector in a script or application of your own; this format is suitable\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBxml\fR
|
||||
.RS 4
|
||||
XML suitable for machine consumption\&. If you want to parse the output generated by gitinspector in a script or application of your own; this format is suitable\&.
|
||||
.RE
|
||||
.SH "FILTERING"
|
||||
.sp
|
||||
gitinspector offers several different ways of filtering out unwanted information from the generated statistics:
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x myfile\fR, filter out and exclude statistics from all files (or paths) with the string "myfile"
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x file:myfile\fR, filter out and exclude statistics from all files (or paths) with the string "myfile"
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x author:John\fR, filter out and exclude statistics from all authors containing the string "John"
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x email:@gmail\&.com\fR, filter out and exclude statistics from all authors with a gmail account
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x revision:8755fb33\fR, filter out and exclude statistics from all revisions containing the hash "8755fb33"
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x message:BUGFIX\fR, filter out and exclude statistics from all revisions containing "BUGFIX" in the commit message\&.
|
||||
.RE
|
||||
.sp
|
||||
The gitinspector command also lets you add multiple filtering rules by simply specifying the \-x options several times or by separating each filtering rule with a comma;
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x author:John \-x email:@gmail\&.com\fR
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x author:John,email:@gmail\&.com\fR
|
||||
.RE
|
||||
.sp
|
||||
Sometimes, sub\-string matching (as described above) is simply not enough\&. Therefore, gitinspector let\(cqs you specify regular expressions as filtering rules\&. This makes filtering much more flexible:
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x "author:\e^(?!(John Smith))"\fR, only show statistics from author "John Smith"
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x "author:\e^(?!([A\-C]))"\fR, only show statistics from authors starting with the letters A/B/C
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
\fBgitinspector \-x "email:\&.com$"\fR, filter out statistics from all email addresses ending with "\&.com"
|
||||
.RE
|
||||
.SH "USING GIT TO CONFIGURE GITINSPECTOR"
|
||||
.sp
|
||||
Options in gitinspector can be set using \fBgit config\fR\&. Consequently, it is possible to configure gitinspector behavior globally (in all git repositories) or locally (in a specific git repository)\&. It also means that settings will be permanently stored\&. All the long options that can be given to gitinspector can also be configured via git config (and take the same arguments)\&.
|
||||
.sp
|
||||
To configure how gitinspector should behave in all git repositories, execute the following git command:
|
||||
.sp
|
||||
\fBgit config \-\-global inspector\&.option setting\fR
|
||||
.sp
|
||||
To configure how gitinspector should behave in a specific git repository, execute the following git command (with the current directory standing inside the repository in question):
|
||||
.sp
|
||||
\fBgit config inspector\&.option setting\fR
|
||||
.SH "AUTHOR"
|
||||
.sp
|
||||
Originally written by Adam Waldenberg\&.
|
||||
.SH "REPORTING BUGS"
|
||||
.sp
|
||||
Report gitinspector bugs to gitinspector@ejwa\&.se
|
||||
.sp
|
||||
The gitinspector project page: https://github\&.com/ejwa/gitinspector
|
||||
.sp
|
||||
If you encounter problems, be sure to read the FAQ first: https://github\&.com/ejwa/gitinspector/wiki/FAQ
|
||||
.sp
|
||||
There is also an issue tracker at: https://github\&.com/ejwa/gitinspector/issues
|
||||
.SH "COPYRIGHT"
|
||||
.sp
|
||||
Copyright \(co 2012\-2015 Ejwa Software\&. All rights reserved\&. License GPLv3+: GNU GPL version 3 or later http://gnu\&.org/licenses/gpl\&.html\&. This is free software: you are free to change and redistribute it\&. There is NO WARRANTY, to the extent permitted by law\&.
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBgit\fR(1)
|
|
@ -0,0 +1,105 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>gitinspector</title><link rel="stylesheet" type="text/css" href="docbook-xsl.css" /><meta name="generator" content="DocBook XSL Stylesheets V1.78.1" /></head><body><div xml:lang="en" class="refentry" lang="en"><a id="idp53245840"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>gitinspector — statistical analysis tool for git repositories</p></div><div class="refsynopsisdiv"><a id="_synopsis"></a><h2>Synopsis</h2><p><span class="strong"><strong>gitinspector</strong></span> [OPTION]… [REPOSITORY]</p></div><div class="refsect1"><a id="_description"></a><h2>DESCRIPTION</h2><p>Analyze and gather statistics about a git repository. The defaut analysis shows general statistics per author, which can be complemented with a timeline analysis that shows the workload and activity of each author. Under normal operation, gitinspector filters the results to only show statistics about a number of given extensions and by default only includes source files in the statistical analysis.</p><p>Several output formats are supported, including plain text, HTML, JSON and XML.</p></div><div class="refsect1"><a id="_options"></a><h2>OPTIONS</h2><p>List information about the repository in REPOSITORY. If no repository is specified, the current directory is used. If multiple repositories are given, information will be fetched from the last repository specified.</p><p>Mandatory arguments to long options are mandatory for short options too. Boolean arguments can only be given to long options.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">
|
||||
<span class="strong"><strong>-f, --file-types</strong></span>=EXTENSIONS
|
||||
</span></dt><dd>
|
||||
A comma separated list of file extensions to include when computing statistics. The default extensions used are: java,c,cc,cpp,h,hh,hpp,py,glsl,rb,js,sql. Specifying a single <span class="emphasis"><em>*</em></span> asterisk character includes files with no extension. Specifying two consecutive <span class="emphasis"><em>**</em></span> asterisk characters includes all files regardless of extension.
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-F, --format</strong></span>=FORMAT
|
||||
</span></dt><dd>
|
||||
Defines in which format output should be generated; the default format is <span class="emphasis"><em>text</em></span> and the available formats are: html,htmlembedded,json,text,xml (see <a class="link" href="#X1" title="OUTPUT FORMATS"><span class="strong"><strong>OUTPUT FORMATS</strong></span></a>)
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>--grading</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
Show statistics and information in a way that is formatted for grading of student projects; this is the same as supplying the options <span class="strong"><strong>-HlmrTw</strong></span>
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-H, --hard</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
Track rows and look for duplicates harder; this can be quite slow with big repositories
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-l, --list-file-types</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
List all the file extensions available in the current branch of the repository
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-L, --localize-output</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
Localize the generated output to the selected system language if a translation is available
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-m, --metrics</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
Include checks for certain metrics during the analysis of commits
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-r --responsibilities</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
Show which files the different authors seem most responsible for
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>--since</strong></span>=DATE
|
||||
</span></dt><dd>
|
||||
Only show statistics for commits more recent than a specific date
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-T, --timeline</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
Show commit timeline, including author names
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>--until</strong></span>=DATE
|
||||
</span></dt><dd>
|
||||
Only show statistics for commits older than a specific date
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-w, --weeks</strong></span>[=BOOL]
|
||||
</span></dt><dd>
|
||||
Show all statistical information in weeks instead of in months
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-x, --exclude</strong></span>=PATTERN
|
||||
</span></dt><dd>
|
||||
An exclusion pattern describing the file paths, revisions, author names or author emails that should be excluded from the statistics; can be specified multiple times (see <a class="link" href="#X2" title="FILTERING"><span class="strong"><strong>FILTERING</strong></span></a>)
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>-h, --help</strong></span>
|
||||
</span></dt><dd>
|
||||
Display help and exit
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>--version</strong></span>
|
||||
</span></dt><dd>
|
||||
Output version information and exit
|
||||
</dd></dl></div></div><div class="refsect1"><a id="X1"></a><h2>OUTPUT FORMATS</h2><p>There is support for multiple output formats in gitinspector. They can be selected using the <span class="strong"><strong>-F</strong></span>/<span class="strong"><strong>--format</strong></span> flags when running the main gitinspector script.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">
|
||||
<span class="strong"><strong>text (plain text)</strong></span>
|
||||
</span></dt><dd>
|
||||
Plain text with some very simple ANSI formatting, suitable for console output. This is the format chosen by default in gitinspector.
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>html</strong></span>
|
||||
</span></dt><dd>
|
||||
HTML with external links. The generated HTML page links to some external resources; such as the JavaScript library JQuery. It requires an active internet connection to properly function. This output format will most likely also link to additional external resources in the future.
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>htmlembedded</strong></span>
|
||||
</span></dt><dd>
|
||||
HTML with no external links. Similar to the HTML output format, but requires no active internet connection. As a consequence; the generated pages are bigger (as certain scripts have to be embedded into the generated output).
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>json</strong></span>
|
||||
</span></dt><dd>
|
||||
JSON suitable for machine consumption. If you want to parse the output generated by gitinspector in a script or application of your own; this format is suitable.
|
||||
</dd><dt><span class="term">
|
||||
<span class="strong"><strong>xml</strong></span>
|
||||
</span></dt><dd>
|
||||
XML suitable for machine consumption. If you want to parse the output generated by gitinspector in a script or application of your own; this format is suitable.
|
||||
</dd></dl></div></div><div class="refsect1"><a id="X2"></a><h2>FILTERING</h2><p>gitinspector offers several different ways of filtering out unwanted information from the generated statistics:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x myfile</strong></span>, filter out and exclude statistics from all files (or paths) with the string "myfile"
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x file:myfile</strong></span>, filter out and exclude statistics from all files (or paths) with the string "myfile"
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x author:John</strong></span>, filter out and exclude statistics from all authors containing the string "John"
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x email:@gmail.com</strong></span>, filter out and exclude statistics from all authors with a gmail account
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x revision:8755fb33</strong></span>, filter out and exclude statistics from all revisions containing the hash "8755fb33"
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x message:BUGFIX</strong></span>, filter out and exclude statistics from all revisions containing "BUGFIX" in the commit message.
|
||||
</li></ul></div><p>The gitinspector command also lets you add multiple filtering rules by simply specifying the -x options several times or by separating each filtering rule with a comma;</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x author:John -x email:@gmail.com</strong></span>
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x author:John,email:@gmail.com</strong></span>
|
||||
</li></ul></div><p>Sometimes, sub-string matching (as described above) is simply not enough. Therefore, gitinspector let’s you specify regular expressions as filtering rules. This makes filtering much more flexible:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x "author:\^(?!(John Smith))"</strong></span>, only show statistics from author "John Smith"
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x "author:\^(?!([A-C]))"</strong></span>, only show statistics from authors starting with the letters A/B/C
|
||||
</li><li class="listitem">
|
||||
<span class="strong"><strong>gitinspector -x "email:.com$"</strong></span>, filter out statistics from all email addresses ending with ".com"
|
||||
</li></ul></div></div><div class="refsect1"><a id="_using_git_to_configure_gitinspector"></a><h2>USING GIT TO CONFIGURE GITINSPECTOR</h2><p>Options in gitinspector can be set using <span class="strong"><strong>git config</strong></span>. Consequently, it is possible to configure gitinspector behavior globally (in all git repositories) or locally (in a specific git repository). It also means that settings will be permanently stored. All the long options that can be given to gitinspector can also be configured via git config (and take the same arguments).</p><p>To configure how gitinspector should behave in all git repositories, execute the following git command:</p><p><span class="strong"><strong>git config --global inspector.option setting</strong></span></p><p>To configure how gitinspector should behave in a specific git repository, execute the following git command (with the current directory standing inside the repository in question):</p><p><span class="strong"><strong>git config inspector.option setting</strong></span></p></div><div class="refsect1"><a id="_author"></a><h2>AUTHOR</h2><p>Originally written by Adam Waldenberg.</p></div><div class="refsect1"><a id="_reporting_bugs"></a><h2>REPORTING BUGS</h2><p>Report gitinspector bugs to <a class="ulink" href="mailto:gitinspector@ejwa.se" target="_top">gitinspector@ejwa.se</a></p><p>The gitinspector project page: <a class="ulink" href="https://github.com/ejwa/gitinspector" target="_top">https://github.com/ejwa/gitinspector</a></p><p>If you encounter problems, be sure to read the FAQ first: <a class="ulink" href="https://github.com/ejwa/gitinspector/wiki/FAQ" target="_top">https://github.com/ejwa/gitinspector/wiki/FAQ</a></p><p>There is also an issue tracker at: <a class="ulink" href="https://github.com/ejwa/gitinspector/issues" target="_top">https://github.com/ejwa/gitinspector/issues</a></p></div><div class="refsect1"><a id="_copyright"></a><h2>COPYRIGHT</h2><p>Copyright © 2012-2015 Ejwa Software. All rights reserved. License GPLv3+: GNU GPL version 3 or later <a class="ulink" href="http://gnu.org/licenses/gpl.html" target="_top">http://gnu.org/licenses/gpl.html</a>.
|
||||
This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.</p></div><div class="refsect1"><a id="_see_also"></a><h2>SEE ALSO</h2><p><span class="strong"><strong>git</strong></span>(1)</p></div></div></body></html>
|
Binary file not shown.
|
@ -0,0 +1,161 @@
|
|||
// a2x -v gitinspector.txt; a2x -v -f manpage gitinspector.txt; a2x -v -f xhtml gitinspector.txt
|
||||
|
||||
GITINSPECTOR(1)
|
||||
===============
|
||||
:doctype: manpage
|
||||
:man version: 0.4.2
|
||||
:man source: gitinspector
|
||||
:man manual: The gitinspector Manual
|
||||
|
||||
|
||||
NAME
|
||||
----
|
||||
gitinspector - statistical analysis tool for git repositories
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*gitinspector* [OPTION]... [REPOSITORY]
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Analyze and gather statistics about a git repository. The default analysis shows general statistics per author, which can be complemented with a timeline analysis that shows the workload and activity of each author. Under normal operation, gitinspector filters the results to only show statistics about a number of given extensions and by default only includes source files in the statistical analysis.
|
||||
|
||||
Several output formats are supported, including plain text, HTML, JSON and XML.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
List information about the repository in REPOSITORY. If no repository is specified, the current directory is used. If multiple repositories are given, information will be fetched from the last repository specified.
|
||||
|
||||
Mandatory arguments to long options are mandatory for short options too. Boolean arguments can only be given to long options.
|
||||
|
||||
*-f, --file-types*=EXTENSIONS::
|
||||
A comma separated list of file extensions to include when computing statistics. The default extensions used are: java,c,cc,cpp,h,hh,hpp,py,glsl,rb,js,sql. Specifying a single '\*' asterisk character includes files with no extension. Specifying two consecutive '**' asterisk characters includes all files regardless of extension.
|
||||
|
||||
*-F, --format*=FORMAT::
|
||||
Defines in which format output should be generated; the default format is 'text' and the available formats are: html,htmlembedded,json,text,xml (see <<X1,*OUTPUT FORMATS*>>)
|
||||
|
||||
*--grading*[=BOOL]::
|
||||
Show statistics and information in a way that is formatted for grading of student projects; this is the same as supplying the options *-HlmrTw*
|
||||
|
||||
*-H, --hard*[=BOOL]::
|
||||
Track rows and look for duplicates harder; this can be quite slow with big repositories
|
||||
|
||||
*-l, --list-file-types*[=BOOL]::
|
||||
List all the file extensions available in the current branch of the repository
|
||||
|
||||
*-L, --localize-output*[=BOOL]::
|
||||
Localize the generated output to the selected system language if a translation is available
|
||||
|
||||
*-m, --metrics*[=BOOL]::
|
||||
Include checks for certain metrics during the analysis of commits
|
||||
|
||||
*-r --responsibilities*[=BOOL]::
|
||||
Show which files the different authors seem most responsible for
|
||||
|
||||
*--since*=DATE::
|
||||
Only show statistics for commits more recent than a specific date
|
||||
|
||||
*-T, --timeline*[=BOOL]::
|
||||
Show commit timeline, including author names
|
||||
|
||||
*--until*=DATE::
|
||||
Only show statistics for commits older than a specific date
|
||||
|
||||
*-w, --weeks*[=BOOL]::
|
||||
Show all statistical information in weeks instead of in months
|
||||
|
||||
*-x, --exclude*=PATTERN::
|
||||
An exclusion pattern describing the file paths, revisions, author names or author emails that should be excluded from the statistics; can be specified multiple times (see <<X2,*FILTERING*>>)
|
||||
|
||||
*-h, --help*::
|
||||
Display help and exit
|
||||
|
||||
*--version*::
|
||||
Output version information and exit
|
||||
|
||||
|
||||
[[X1]]
|
||||
OUTPUT FORMATS
|
||||
--------------
|
||||
There is support for multiple output formats in gitinspector. They can be selected using the *-F*/*--format* flags when running the main gitinspector script.
|
||||
|
||||
*text (plain text)*::
|
||||
Plain text with some very simple ANSI formatting, suitable for console output. This is the format chosen by default in gitinspector.
|
||||
|
||||
*html*::
|
||||
HTML with external links. The generated HTML page links to some external resources; such as the JavaScript library JQuery. It requires an active internet connection to properly function. This output format will most likely also link to additional external resources in the future.
|
||||
|
||||
*htmlembedded*::
|
||||
HTML with no external links. Similar to the HTML output format, but requires no active internet connection. As a consequence; the generated pages are bigger (as certain scripts have to be embedded into the generated output).
|
||||
|
||||
*json*::
|
||||
JSON suitable for machine consumption. If you want to parse the output generated by gitinspector in a script or application of your own; this format is suitable.
|
||||
|
||||
*xml*::
|
||||
XML suitable for machine consumption. If you want to parse the output generated by gitinspector in a script or application of your own; this format is suitable.
|
||||
|
||||
|
||||
[[X2]]
|
||||
FILTERING
|
||||
---------
|
||||
gitinspector offers several different ways of filtering out unwanted information from the generated statistics:
|
||||
|
||||
* *gitinspector -x myfile*, filter out and exclude statistics from all files (or paths) with the string "myfile"
|
||||
* *gitinspector -x file:myfile*, filter out and exclude statistics from all files (or paths) with the string "myfile"
|
||||
* *gitinspector -x author:John*, filter out and exclude statistics from all authors containing the string "John"
|
||||
* *gitinspector -x email:@gmail.com*, filter out and exclude statistics from all authors with a gmail account
|
||||
* *gitinspector -x revision:8755fb33*, filter out and exclude statistics from all revisions containing the hash "8755fb33"
|
||||
* *gitinspector -x message:BUGFIX*, filter out and exclude statistics from all revisions containing "BUGFIX" in the commit message.
|
||||
|
||||
The gitinspector command also lets you add multiple filtering rules by simply specifying the -x options several times or by separating each filtering rule with a comma;
|
||||
|
||||
* *gitinspector -x author:John -x email:@gmail.com*
|
||||
* *gitinspector -x author:John,email:@gmail.com*
|
||||
|
||||
Sometimes, sub-string matching (as described above) is simply not enough. Therefore, gitinspector let's you specify regular expressions as filtering rules. This makes filtering much more flexible:
|
||||
|
||||
* *gitinspector -x "author:\^(?!(John Smith))"*, only show statistics from author "John Smith"
|
||||
* *gitinspector -x "author:\^(?!([A-C]))"*, only show statistics from authors starting with the letters A/B/C
|
||||
* *gitinspector -x "email:.com$"*, filter out statistics from all email addresses ending with ".com"
|
||||
|
||||
|
||||
USING GIT TO CONFIGURE GITINSPECTOR
|
||||
-----------------------------------
|
||||
Options in gitinspector can be set using *git config*. Consequently, it is possible to configure gitinspector behavior globally (in all git repositories) or locally (in a specific git repository). It also means that settings will be permanently stored. All the long options that can be given to gitinspector can also be configured via git config (and take the same arguments).
|
||||
|
||||
To configure how gitinspector should behave in all git repositories, execute the following git command:
|
||||
|
||||
*git config --global inspector.option setting*
|
||||
|
||||
To configure how gitinspector should behave in a specific git repository, execute the following git command (with the current directory standing inside the repository in question):
|
||||
|
||||
*git config inspector.option setting*
|
||||
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
Originally written by Adam Waldenberg.
|
||||
|
||||
|
||||
REPORTING BUGS
|
||||
--------------
|
||||
Report gitinspector bugs to gitinspector@ejwa.se
|
||||
|
||||
The gitinspector project page: <https://github.com/ejwa/gitinspector>
|
||||
|
||||
If you encounter problems, be sure to read the FAQ first: <https://github.com/ejwa/gitinspector/wiki/FAQ>
|
||||
|
||||
There is also an issue tracker at: <https://github.com/ejwa/gitinspector/issues>
|
||||
|
||||
COPYRIGHT
|
||||
---------
|
||||
Copyright (C) 2012-2015 Ejwa Software. All rights reserved. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
*git*(1)
|
|
@ -0,0 +1,29 @@
|
|||
var PythonShell = require('python-shell');
|
||||
|
||||
var options = {
|
||||
// The main python script is in the same directory as this file
|
||||
scriptPath: __dirname,
|
||||
|
||||
// Get command line arguments, skipping the default node args:
|
||||
// arg0 == node executable, arg1 == this file
|
||||
args: process.argv.slice(2)
|
||||
};
|
||||
|
||||
|
||||
// Set encoding used by stdin etc manually. Without this, gitinspector may fail to run.
|
||||
process.env.PYTHONIOENCODING = 'utf8';
|
||||
|
||||
// Start inspector
|
||||
var inspector = new PythonShell('gitinspector.py', options);
|
||||
|
||||
// Handle stdout
|
||||
inspector.on('message', function(message) {
|
||||
console.log(message);
|
||||
});
|
||||
|
||||
// Let the inspector run, catching any error at the end
|
||||
inspector.end(function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gitinspector import gitinspector
|
||||
|
||||
if __name__ == "__main__":
|
||||
gitinspector.main()
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -18,10 +18,46 @@
|
|||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def get_basedir():
|
||||
if hasattr(sys,'frozen'): # exists when running via py2exe
|
||||
if hasattr(sys, "frozen"): # exists when running via py2exe
|
||||
return sys.prefix
|
||||
else:
|
||||
return os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
def get_basedir_git(path=None):
|
||||
previous_directory = None
|
||||
|
||||
if path != None:
|
||||
previous_directory = os.getcwd()
|
||||
os.chdir(path)
|
||||
|
||||
bare_command = subprocess.Popen(["git", "rev-parse", "--is-bare-repository"], bufsize=1,
|
||||
stdout=subprocess.PIPE, stderr=open(os.devnull, "w"))
|
||||
|
||||
isbare = bare_command.stdout.readlines()
|
||||
bare_command.wait()
|
||||
|
||||
if bare_command.returncode != 0:
|
||||
sys.exit(_("Error processing git repository at \"%s\"." % os.getcwd()))
|
||||
|
||||
isbare = (isbare[0].decode("utf-8", "replace").strip() == "true")
|
||||
absolute_path = None
|
||||
|
||||
if isbare:
|
||||
absolute_path = subprocess.Popen(["git", "rev-parse", "--git-dir"], bufsize=1, stdout=subprocess.PIPE).stdout
|
||||
else:
|
||||
absolute_path = subprocess.Popen(["git", "rev-parse", "--show-toplevel"], bufsize=1,
|
||||
stdout=subprocess.PIPE).stdout
|
||||
|
||||
absolute_path = absolute_path.readlines()
|
||||
|
||||
if len(absolute_path) == 0:
|
||||
sys.exit(_("Unable to determine absolute path of git repository."))
|
||||
|
||||
if path != None:
|
||||
os.chdir(previous_directory)
|
||||
|
||||
return absolute_path[0].decode("utf-8", "replace").strip()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2017 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -19,114 +19,174 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
from changes import FileDiff
|
||||
import comment
|
||||
import changes
|
||||
import filtering
|
||||
import format
|
||||
import gravatar
|
||||
import interval
|
||||
import missing
|
||||
import datetime
|
||||
import multiprocessing
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import terminal
|
||||
import textwrap
|
||||
import threading
|
||||
from .localization import N_
|
||||
from .changes import FileDiff
|
||||
from . import comment, extensions, filtering, format, interval, terminal
|
||||
|
||||
NUM_THREADS = multiprocessing.cpu_count()
|
||||
|
||||
class BlameEntry:
|
||||
class BlameEntry(object):
|
||||
rows = 0
|
||||
skew = 0 # Used when calculating average code age.
|
||||
comments = 0
|
||||
|
||||
__thread_lock__ = threading.BoundedSemaphore(NUM_THREADS)
|
||||
__blame_lock__ = threading.Lock()
|
||||
|
||||
AVG_DAYS_PER_MONTH = 30.4167
|
||||
|
||||
class BlameThread(threading.Thread):
|
||||
def __init__(self, blame_string, extension, blames, filename):
|
||||
def __init__(self, useweeks, changes, blame_command, extension, blames, filename):
|
||||
__thread_lock__.acquire() # Lock controlling the number of threads running
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
self.blame_string = blame_string
|
||||
self.useweeks = useweeks
|
||||
self.changes = changes
|
||||
self.blame_command = blame_command
|
||||
self.extension = extension
|
||||
self.blames = blames
|
||||
self.filename = filename
|
||||
|
||||
self.is_inside_comment = False
|
||||
|
||||
def __clear_blamechunk_info__(self):
|
||||
self.blamechunk_email = None
|
||||
self.blamechunk_is_last = False
|
||||
self.blamechunk_is_prior = False
|
||||
self.blamechunk_revision = None
|
||||
self.blamechunk_time = None
|
||||
|
||||
def __handle_blamechunk_content__(self, content):
|
||||
author = None
|
||||
(comments, self.is_inside_comment) = comment.handle_comment_block(self.is_inside_comment, self.extension, content)
|
||||
|
||||
if self.blamechunk_is_prior and interval.get_since():
|
||||
return
|
||||
try:
|
||||
author = self.changes.get_latest_author_by_email(self.blamechunk_email)
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
if not filtering.set_filtered(author, "author") and not \
|
||||
filtering.set_filtered(self.blamechunk_email, "email") and not \
|
||||
filtering.set_filtered(self.blamechunk_revision, "revision"):
|
||||
|
||||
__blame_lock__.acquire() # Global lock used to protect calls from here...
|
||||
|
||||
if self.blames.get((author, self.filename), None) == None:
|
||||
self.blames[(author, self.filename)] = BlameEntry()
|
||||
|
||||
self.blames[(author, self.filename)].comments += comments
|
||||
self.blames[(author, self.filename)].rows += 1
|
||||
|
||||
if (self.blamechunk_time - self.changes.first_commit_date).days > 0:
|
||||
self.blames[(author, self.filename)].skew += ((self.changes.last_commit_date - self.blamechunk_time).days /
|
||||
(7.0 if self.useweeks else AVG_DAYS_PER_MONTH))
|
||||
|
||||
__blame_lock__.release() # ...to here.
|
||||
|
||||
def run(self):
|
||||
git_blame_r = subprocess.Popen(self.blame_string, shell=True, bufsize=1, stdout=subprocess.PIPE).stdout
|
||||
is_inside_comment = False
|
||||
|
||||
for j in git_blame_r.readlines():
|
||||
j = j.decode("utf-8", "replace")
|
||||
if Blame.is_blame_line(j):
|
||||
author_mail = Blame.get_author_mail(j)
|
||||
content = Blame.get_content(j)
|
||||
__blame_lock__.acquire() # Global lock used to protect calls from here...
|
||||
|
||||
if self.blames.get((author_mail, self.filename), None) == None:
|
||||
self.blames[(author_mail, self.filename)] = BlameEntry()
|
||||
|
||||
(comments, is_inside_comment) = comment.handle_comment_block(is_inside_comment, self.extension, content)
|
||||
self.blames[(author_mail, self.filename)].comments += comments
|
||||
self.blames[(author_mail, self.filename)].rows += 1
|
||||
__blame_lock__.release() # ...to here.
|
||||
|
||||
git_blame_r = subprocess.Popen(self.blame_command, bufsize=1, stdout=subprocess.PIPE).stdout
|
||||
rows = git_blame_r.readlines()
|
||||
git_blame_r.close()
|
||||
|
||||
self.__clear_blamechunk_info__()
|
||||
|
||||
#pylint: disable=W0201
|
||||
for j in range(0, len(rows)):
|
||||
row = rows[j].decode("utf-8", "replace").strip()
|
||||
keyval = row.split(" ", 2)
|
||||
|
||||
if self.blamechunk_is_last:
|
||||
self.__handle_blamechunk_content__(row)
|
||||
self.__clear_blamechunk_info__()
|
||||
elif keyval[0] == "boundary":
|
||||
self.blamechunk_is_prior = True
|
||||
elif keyval[0] == "author-mail":
|
||||
self.blamechunk_email = keyval[1].lstrip("<").rstrip(">")
|
||||
elif keyval[0] == "author-time":
|
||||
self.blamechunk_time = datetime.date.fromtimestamp(int(keyval[1]))
|
||||
elif keyval[0] == "filename":
|
||||
self.blamechunk_is_last = True
|
||||
elif Blame.is_revision(keyval[0]):
|
||||
self.blamechunk_revision = keyval[0]
|
||||
|
||||
__thread_lock__.release() # Lock controlling the number of threads running
|
||||
|
||||
PROGRESS_TEXT = N_("Checking how many rows belong to each author (Progress): {0:.0f}%")
|
||||
PROGRESS_TEXT = N_("Checking how many rows belong to each author (2 of 2): {0:.0f}%")
|
||||
|
||||
class Blame:
|
||||
def __init__(self, hard):
|
||||
class Blame(object):
|
||||
def __init__(self, repo, hard, useweeks, changes):
|
||||
self.blames = {}
|
||||
ls_tree_r = subprocess.Popen("git ls-tree --name-only -r " + interval.get_ref(), shell=True, bufsize=1,
|
||||
stdout=subprocess.PIPE).stdout
|
||||
lines = ls_tree_r.readlines()
|
||||
ls_tree_p = subprocess.Popen(["git", "ls-tree", "--name-only", "-r", interval.get_ref()], bufsize=1,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
lines = ls_tree_p.communicate()[0].splitlines()
|
||||
ls_tree_p.stdout.close()
|
||||
|
||||
for i, row in enumerate(lines):
|
||||
row = row.strip().decode("unicode_escape", "ignore")
|
||||
row = row.encode("latin-1", "replace")
|
||||
row = row.decode("utf-8", "replace").strip("\"").strip("'").strip()
|
||||
if ls_tree_p.returncode == 0:
|
||||
progress_text = _(PROGRESS_TEXT)
|
||||
|
||||
if FileDiff.is_valid_extension(row) and not filtering.set_filtered(FileDiff.get_filename(row)):
|
||||
if not missing.add(row):
|
||||
blame_string = "git blame -w {0} ".format("-C -C -M" if hard else "") + \
|
||||
interval.get_since() + interval.get_ref() + " -- \"" + row + "\""
|
||||
thread = BlameThread(blame_string, FileDiff.get_extension(row), self.blames, row.strip())
|
||||
if repo != None:
|
||||
progress_text = "[%s] " % repo.name + progress_text
|
||||
|
||||
for i, row in enumerate(lines):
|
||||
row = row.strip().decode("unicode_escape", "ignore")
|
||||
row = row.encode("latin-1", "replace")
|
||||
row = row.decode("utf-8", "replace").strip("\"").strip("'").strip()
|
||||
|
||||
if FileDiff.get_extension(row) in extensions.get_located() and \
|
||||
FileDiff.is_valid_extension(row) and not filtering.set_filtered(FileDiff.get_filename(row)):
|
||||
blame_command = filter(None, ["git", "blame", "--line-porcelain", "-w"] + \
|
||||
(["-C", "-C", "-M"] if hard else []) +
|
||||
[interval.get_since(), interval.get_ref(), "--", row])
|
||||
thread = BlameThread(useweeks, changes, blame_command, FileDiff.get_extension(row),
|
||||
self.blames, row.strip())
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
if hard:
|
||||
Blame.output_progress(i, len(lines))
|
||||
if format.is_interactive_format():
|
||||
terminal.output_progress(progress_text, i, len(lines))
|
||||
|
||||
# Make sure all threads have completed.
|
||||
for i in range(0, NUM_THREADS):
|
||||
__thread_lock__.acquire()
|
||||
# Make sure all threads have completed.
|
||||
for i in range(0, NUM_THREADS):
|
||||
__thread_lock__.acquire()
|
||||
|
||||
# We also have to release them for future use.
|
||||
for i in range(0, NUM_THREADS):
|
||||
__thread_lock__.release()
|
||||
|
||||
def __iadd__(self, other):
|
||||
try:
|
||||
self.blames.update(other.blames)
|
||||
return self;
|
||||
except AttributeError:
|
||||
return other;
|
||||
|
||||
@staticmethod
|
||||
def output_progress(pos, length):
|
||||
if sys.stdout.isatty() and format.is_interactive_format():
|
||||
terminal.clear_row()
|
||||
print("\b" + _(PROGRESS_TEXT).format(100 * pos / length), end="")
|
||||
sys.stdout.flush()
|
||||
def is_revision(string):
|
||||
revision = re.search("([0-9a-f]{40})", string)
|
||||
|
||||
if revision == None:
|
||||
return False
|
||||
|
||||
return revision.group(1).strip()
|
||||
|
||||
@staticmethod
|
||||
def is_blame_line(string):
|
||||
return string.find(" (") != -1
|
||||
def get_stability(author, blamed_rows, changes):
|
||||
if author in changes.get_authorinfo_list():
|
||||
author_insertions = changes.get_authorinfo_list()[author].insertions
|
||||
return 100 if author_insertions == 0 else 100.0 * blamed_rows / author_insertions
|
||||
return 100
|
||||
|
||||
@staticmethod
|
||||
def get_author_mail(string):
|
||||
author_mail = re.search(" \((.*?)\d\d\d\d-\d\d-\d\d", string)
|
||||
return author_mail.group(1).strip().lstrip("<").rstrip(">")
|
||||
|
||||
@staticmethod
|
||||
def get_content(string):
|
||||
content = re.search(" \d+\)(.*)", string)
|
||||
return content.group(1).lstrip()
|
||||
def get_time(string):
|
||||
time = re.search(r" \(.*?(\d\d\d\d-\d\d-\d\d)", string)
|
||||
return time.group(1).strip()
|
||||
|
||||
def get_summed_blames(self):
|
||||
summed_blames = {}
|
||||
|
@ -135,112 +195,7 @@ class Blame:
|
|||
summed_blames[i[0][0]] = BlameEntry()
|
||||
|
||||
summed_blames[i[0][0]].rows += i[1].rows
|
||||
summed_blames[i[0][0]].skew += i[1].skew
|
||||
summed_blames[i[0][0]].comments += i[1].comments
|
||||
|
||||
return summed_blames
|
||||
|
||||
__blame__ = None
|
||||
|
||||
def get(hard):
|
||||
global __blame__
|
||||
if __blame__ == None:
|
||||
__blame__ = Blame(hard)
|
||||
|
||||
return __blame__
|
||||
|
||||
BLAME_INFO_TEXT = N_("Below are the number of rows from each author that have survived and are still "
|
||||
"intact in the current revision")
|
||||
|
||||
class BlameOutput(Outputable):
|
||||
def __init__(self, hard):
|
||||
self.hard = hard
|
||||
self.changes = changes.get(hard)
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_html(self):
|
||||
get(self.hard)
|
||||
|
||||
blame_xml = "<div><div class=\"box\">"
|
||||
blame_xml += "<p>" + _(BLAME_INFO_TEXT) + ".</p><div><table id=\"blame\" class=\"git\">"
|
||||
blame_xml += "<thead><tr> <th>{0}</th> <th>{1}</th> <th>{2}</th> </tr></thead>".format(_("Author"),
|
||||
_("Rows"), _("% in comments"))
|
||||
blame_xml += "<tbody>"
|
||||
chart_data = ""
|
||||
blames = sorted(__blame__.get_summed_blames().items())
|
||||
total_blames = 0
|
||||
|
||||
for i in blames:
|
||||
total_blames += i[1].rows
|
||||
|
||||
for i, entry in enumerate(blames):
|
||||
work_percentage = str("{0:.2f}".format(100.0 * entry[1].rows / total_blames))
|
||||
blame_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
||||
|
||||
if format.get_selected() == "html":
|
||||
author_email = self.changes.get_author_email(entry[0])
|
||||
blame_xml += "<td><img src=\"{0}\"/>{1}</td>".format(gravatar.get_url(author_email), entry[0])
|
||||
else:
|
||||
blame_xml += "<td>" + entry[0] + "</td>"
|
||||
|
||||
blame_xml += "<td>" + str(entry[1].rows) + "</td>"
|
||||
blame_xml += "<td>" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "</td>"
|
||||
blame_xml += "<td style=\"display: none\">" + work_percentage + "</td>"
|
||||
blame_xml += "</tr>"
|
||||
chart_data += "{{label: \"{0}\", data: {1}}}".format(entry[0], work_percentage)
|
||||
|
||||
if blames[-1] != entry:
|
||||
chart_data += ", "
|
||||
|
||||
blame_xml += "<tfoot><tr> <td colspan=\"3\"> </td> </tr></tfoot></tbody></table>"
|
||||
blame_xml += "<div class=\"chart\" id=\"blame_chart\"></div></div>"
|
||||
blame_xml += "<script type=\"text/javascript\">"
|
||||
blame_xml += " $.plot($(\"#blame_chart\"), [{0}], {{".format(chart_data)
|
||||
blame_xml += " series: {"
|
||||
blame_xml += " pie: {"
|
||||
blame_xml += " innerRadius: 0.4,"
|
||||
blame_xml += " show: true,"
|
||||
blame_xml += " combine: {"
|
||||
blame_xml += " threshold: 0.01,"
|
||||
blame_xml += " label: \"" + _("Minor Authors") + "\""
|
||||
blame_xml += " }"
|
||||
blame_xml += " }"
|
||||
blame_xml += " }, grid: {"
|
||||
blame_xml += " hoverable: true"
|
||||
blame_xml += " }"
|
||||
blame_xml += " });"
|
||||
blame_xml += "</script></div></div>"
|
||||
|
||||
print(blame_xml)
|
||||
|
||||
def output_text(self):
|
||||
print("")
|
||||
get(self.hard)
|
||||
|
||||
if self.hard and sys.stdout.isatty():
|
||||
terminal.clear_row()
|
||||
|
||||
print(textwrap.fill(_(BLAME_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n")
|
||||
terminal.printb(_("Author").ljust(21) + _("Rows").rjust(10) + _("% in comments").rjust(20))
|
||||
|
||||
for i in sorted(__blame__.get_summed_blames().items()):
|
||||
print(i[0].ljust(20)[0:20], end=" ")
|
||||
print(str(i[1].rows).rjust(10), end=" ")
|
||||
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(19))
|
||||
|
||||
def output_xml(self):
|
||||
get(self.hard)
|
||||
|
||||
message_xml = "\t\t<message>" + _(BLAME_INFO_TEXT) + "</message>\n"
|
||||
blame_xml = ""
|
||||
|
||||
for i in sorted(__blame__.get_summed_blames().items()):
|
||||
author_email = self.changes.get_author_email(i[0])
|
||||
|
||||
name_xml = "\t\t\t\t<name>" + i[0] + "</name>\n"
|
||||
gravatar_xml = "\t\t\t\t<gravatar>" + gravatar.get_url(author_email) + "</gravatar>\n"
|
||||
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
|
||||
percentage_in_comments_xml = ("\t\t\t\t<percentage-in-comments>" + "{0:.2f}".format(100.0 * i[1].comments / i[1].rows) +
|
||||
"</percentage-in-comments>\n")
|
||||
blame_xml += "\t\t\t<author>\n" + name_xml + gravatar_xml + rows_xml + percentage_in_comments_xml + "\t\t\t</author>\n"
|
||||
|
||||
print("\t<blame>\n" + message_xml + "\t\t<authors>\n" + blame_xml + "\t\t</authors>\n\t</blame>")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2017 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -17,21 +17,24 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
import extensions
|
||||
import filtering
|
||||
import format
|
||||
import gravatar
|
||||
import interval
|
||||
import bisect
|
||||
import datetime
|
||||
import multiprocessing
|
||||
import os
|
||||
import subprocess
|
||||
import terminal
|
||||
import textwrap
|
||||
import threading
|
||||
from .localization import N_
|
||||
from . import extensions, filtering, format, interval, terminal
|
||||
|
||||
class FileDiff:
|
||||
CHANGES_PER_THREAD = 200
|
||||
NUM_THREADS = multiprocessing.cpu_count()
|
||||
|
||||
__thread_lock__ = threading.BoundedSemaphore(NUM_THREADS)
|
||||
__changes_lock__ = threading.Lock()
|
||||
|
||||
class FileDiff(object):
|
||||
def __init__(self, string):
|
||||
commit_line = string.split("|")
|
||||
|
||||
|
@ -59,20 +62,24 @@ class FileDiff:
|
|||
extension = FileDiff.get_extension(string)
|
||||
|
||||
for i in extensions.get():
|
||||
if extension == i:
|
||||
if (extension == "" and i == "*") or extension == i or i == '**':
|
||||
return True
|
||||
return False
|
||||
|
||||
class Commit:
|
||||
class Commit(object):
|
||||
def __init__(self, string):
|
||||
self.filediffs = []
|
||||
commit_line = string.split("|")
|
||||
|
||||
if commit_line.__len__() == 4:
|
||||
self.date = commit_line[0]
|
||||
self.sha = commit_line[1]
|
||||
self.author = commit_line[2].strip()
|
||||
self.email = commit_line[3].strip()
|
||||
if commit_line.__len__() == 5:
|
||||
self.timestamp = commit_line[0]
|
||||
self.date = commit_line[1]
|
||||
self.sha = commit_line[2]
|
||||
self.author = commit_line[3].strip()
|
||||
self.email = commit_line[4].strip()
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.timestamp.__lt__(other.timestamp) # only used for sorting; we just consider the timestamp.
|
||||
|
||||
def add_filediff(self, filediff):
|
||||
self.filediffs.append(filediff)
|
||||
|
@ -84,33 +91,50 @@ class Commit:
|
|||
def get_author_and_email(string):
|
||||
commit_line = string.split("|")
|
||||
|
||||
if commit_line.__len__() == 4:
|
||||
return (commit_line[2].strip(), commit_line[3].strip())
|
||||
if commit_line.__len__() == 5:
|
||||
return (commit_line[3].strip(), commit_line[4].strip())
|
||||
|
||||
@staticmethod
|
||||
def is_commit_line(string):
|
||||
return string.split("|").__len__() == 4
|
||||
return string.split("|").__len__() == 5
|
||||
|
||||
class AuthorInfo:
|
||||
class AuthorInfo(object):
|
||||
email = None
|
||||
insertions = 0
|
||||
deletions = 0
|
||||
commits = 0
|
||||
|
||||
class Changes:
|
||||
authors = {}
|
||||
authors_dateinfo = {}
|
||||
authors_email = {}
|
||||
class ChangesThread(threading.Thread):
|
||||
def __init__(self, hard, changes, first_hash, second_hash, offset):
|
||||
__thread_lock__.acquire() # Lock controlling the number of threads running
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
self.hard = hard
|
||||
self.changes = changes
|
||||
self.first_hash = first_hash
|
||||
self.second_hash = second_hash
|
||||
self.offset = offset
|
||||
|
||||
@staticmethod
|
||||
def create(hard, changes, first_hash, second_hash, offset):
|
||||
thread = ChangesThread(hard, changes, first_hash, second_hash, offset)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
def run(self):
|
||||
git_log_r = subprocess.Popen(filter(None, ["git", "log", "--reverse", "--pretty=%ct|%cd|%H|%aN|%aE",
|
||||
"--stat=100000,8192", "--no-merges", "-w", interval.get_since(),
|
||||
interval.get_until(), "--date=short"] + (["-C", "-C", "-M"] if self.hard else []) +
|
||||
[self.first_hash + self.second_hash]), bufsize=1, stdout=subprocess.PIPE).stdout
|
||||
lines = git_log_r.readlines()
|
||||
git_log_r.close()
|
||||
|
||||
def __init__(self, hard):
|
||||
self.commits = []
|
||||
git_log_r = subprocess.Popen("git log --pretty=\"%cd|%H|%aN|%aE\" --stat=100000,8192 --no-merges -w " +
|
||||
interval.get_since() + interval.get_until() +
|
||||
"{0} --date=short".format("-C -C -M" if hard else ""),
|
||||
shell=True, bufsize=1, stdout=subprocess.PIPE).stdout
|
||||
commit = None
|
||||
found_valid_extension = False
|
||||
lines = git_log_r.readlines()
|
||||
is_filtered = False
|
||||
commits = []
|
||||
|
||||
__changes_lock__.acquire() # Global lock used to protect calls from here...
|
||||
|
||||
for i in lines:
|
||||
j = i.strip().decode("unicode_escape", "ignore")
|
||||
|
@ -119,16 +143,26 @@ class Changes:
|
|||
|
||||
if Commit.is_commit_line(j):
|
||||
(author, email) = Commit.get_author_and_email(j)
|
||||
self.authors_email[author] = email
|
||||
self.changes.emails_by_author[author] = email
|
||||
self.changes.authors_by_email[email] = author
|
||||
|
||||
if Commit.is_commit_line(j) or i is lines[-1]:
|
||||
if found_valid_extension:
|
||||
self.commits.append(commit)
|
||||
bisect.insort(commits, commit)
|
||||
|
||||
found_valid_extension = False
|
||||
is_filtered = False
|
||||
commit = Commit(j)
|
||||
|
||||
if FileDiff.is_filediff_line(j) and not filtering.set_filtered(FileDiff.get_filename(j)):
|
||||
if Commit.is_commit_line(j) and \
|
||||
(filtering.set_filtered(commit.author, "author") or \
|
||||
filtering.set_filtered(commit.email, "email") or \
|
||||
filtering.set_filtered(commit.sha, "revision") or \
|
||||
filtering.set_filtered(commit.sha, "message")):
|
||||
is_filtered = True
|
||||
|
||||
if FileDiff.is_filediff_line(j) and not \
|
||||
filtering.set_filtered(FileDiff.get_filename(j)) and not is_filtered:
|
||||
extensions.add_located(FileDiff.get_extension(j))
|
||||
|
||||
if FileDiff.is_valid_extension(j):
|
||||
|
@ -136,13 +170,91 @@ class Changes:
|
|||
filediff = FileDiff(j)
|
||||
commit.add_filediff(filediff)
|
||||
|
||||
if interval.has_interval() and len(self.commits) > 0:
|
||||
interval.set_ref(self.commits[0].sha)
|
||||
self.changes.commits[self.offset // CHANGES_PER_THREAD] = commits
|
||||
__changes_lock__.release() # ...to here.
|
||||
__thread_lock__.release() # Lock controlling the number of threads running
|
||||
|
||||
PROGRESS_TEXT = N_("Fetching and calculating primary statistics (1 of 2): {0:.0f}%")
|
||||
|
||||
class Changes(object):
|
||||
authors = {}
|
||||
authors_dateinfo = {}
|
||||
authors_by_email = {}
|
||||
emails_by_author = {}
|
||||
|
||||
def __init__(self, repo, hard):
|
||||
self.commits = []
|
||||
interval.set_ref("HEAD");
|
||||
git_rev_list_p = subprocess.Popen(filter(None, ["git", "rev-list", "--reverse", "--no-merges",
|
||||
interval.get_since(), interval.get_until(), "HEAD"]), bufsize=1,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
lines = git_rev_list_p.communicate()[0].splitlines()
|
||||
git_rev_list_p.stdout.close()
|
||||
|
||||
if git_rev_list_p.returncode == 0 and len(lines) > 0:
|
||||
progress_text = _(PROGRESS_TEXT)
|
||||
if repo != None:
|
||||
progress_text = "[%s] " % repo.name + progress_text
|
||||
|
||||
chunks = len(lines) // CHANGES_PER_THREAD
|
||||
self.commits = [None] * (chunks if len(lines) % CHANGES_PER_THREAD == 0 else chunks + 1)
|
||||
first_hash = ""
|
||||
|
||||
for i, entry in enumerate(lines):
|
||||
if i % CHANGES_PER_THREAD == CHANGES_PER_THREAD - 1:
|
||||
entry = entry.decode("utf-8", "replace").strip()
|
||||
second_hash = entry
|
||||
ChangesThread.create(hard, self, first_hash, second_hash, i)
|
||||
first_hash = entry + ".."
|
||||
|
||||
if format.is_interactive_format():
|
||||
terminal.output_progress(progress_text, i, len(lines))
|
||||
else:
|
||||
if CHANGES_PER_THREAD - 1 != i % CHANGES_PER_THREAD:
|
||||
entry = entry.decode("utf-8", "replace").strip()
|
||||
second_hash = entry
|
||||
ChangesThread.create(hard, self, first_hash, second_hash, i)
|
||||
|
||||
# Make sure all threads have completed.
|
||||
for i in range(0, NUM_THREADS):
|
||||
__thread_lock__.acquire()
|
||||
|
||||
# We also have to release them for future use.
|
||||
for i in range(0, NUM_THREADS):
|
||||
__thread_lock__.release()
|
||||
|
||||
self.commits = [item for sublist in self.commits for item in sublist]
|
||||
|
||||
if len(self.commits) > 0:
|
||||
if interval.has_interval():
|
||||
interval.set_ref(self.commits[-1].sha)
|
||||
|
||||
self.first_commit_date = datetime.date(int(self.commits[0].date[0:4]), int(self.commits[0].date[5:7]),
|
||||
int(self.commits[0].date[8:10]))
|
||||
self.last_commit_date = datetime.date(int(self.commits[-1].date[0:4]), int(self.commits[-1].date[5:7]),
|
||||
int(self.commits[-1].date[8:10]))
|
||||
|
||||
def __iadd__(self, other):
|
||||
try:
|
||||
self.authors.update(other.authors)
|
||||
self.authors_dateinfo.update(other.authors_dateinfo)
|
||||
self.authors_by_email.update(other.authors_by_email)
|
||||
self.emails_by_author.update(other.emails_by_author)
|
||||
|
||||
for commit in other.commits:
|
||||
bisect.insort(self.commits, commit)
|
||||
if not self.commits and not other.commits:
|
||||
self.commits = []
|
||||
|
||||
return self
|
||||
except AttributeError:
|
||||
return other
|
||||
|
||||
def get_commits(self):
|
||||
return self.commits
|
||||
|
||||
def __modify_authorinfo__(self, authors, key, commit):
|
||||
@staticmethod
|
||||
def modify_authorinfo(authors, key, commit):
|
||||
if authors.get(key, None) == None:
|
||||
authors[key] = AuthorInfo()
|
||||
|
||||
|
@ -156,149 +268,26 @@ class Changes:
|
|||
def get_authorinfo_list(self):
|
||||
if not self.authors:
|
||||
for i in self.commits:
|
||||
self.__modify_authorinfo__(self.authors, i.author, i)
|
||||
Changes.modify_authorinfo(self.authors, i.author, i)
|
||||
|
||||
return self.authors
|
||||
|
||||
def get_authordateinfo_list(self):
|
||||
if not self.authors_dateinfo:
|
||||
for i in self.commits:
|
||||
self.__modify_authorinfo__(self.authors_dateinfo, (i.date, i.author), i)
|
||||
Changes.modify_authorinfo(self.authors_dateinfo, (i.date, i.author), i)
|
||||
|
||||
return self.authors_dateinfo
|
||||
|
||||
def get_author_email(self, name):
|
||||
return self.authors_email[name]
|
||||
def get_latest_author_by_email(self, name):
|
||||
if not hasattr(name, "decode"):
|
||||
name = str.encode(name)
|
||||
try:
|
||||
name = name.decode("unicode_escape", "ignore")
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
__changes__ = None
|
||||
return self.authors_by_email[name]
|
||||
|
||||
def get(hard):
|
||||
global __changes__
|
||||
if __changes__ == None:
|
||||
__changes__ = Changes(hard)
|
||||
|
||||
return __changes__
|
||||
|
||||
HISTORICAL_INFO_TEXT = N_("The following historical commit information, by author, was found in the repository")
|
||||
NO_COMMITED_FILES_TEXT = N_("No commited files with the specified extensions were found")
|
||||
|
||||
class ChangesOutput(Outputable):
|
||||
def __init__(self, hard):
|
||||
self.changes = get(hard)
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_html(self):
|
||||
authorinfo_list = self.changes.get_authorinfo_list()
|
||||
total_changes = 0.0
|
||||
changes_xml = "<div><div class=\"box\">"
|
||||
chart_data = ""
|
||||
|
||||
for i in authorinfo_list:
|
||||
total_changes += authorinfo_list.get(i).insertions
|
||||
total_changes += authorinfo_list.get(i).deletions
|
||||
|
||||
if authorinfo_list:
|
||||
changes_xml += "<p>" + _(HISTORICAL_INFO_TEXT) + ".</p><div><table id=\"changes\" class=\"git\">"
|
||||
changes_xml += "<thead><tr> <th>{0}</th> <th>{1}</th> <th>{2}</th> <th>{3}</th> <th>{4}</th>".format(
|
||||
_("Author"), _("Commits"), _("Insertions"), _("Deletions"), _("% of changes"))
|
||||
changes_xml += "</tr></thead><tbody>"
|
||||
|
||||
for i, entry in enumerate(sorted(authorinfo_list)):
|
||||
authorinfo = authorinfo_list.get(entry)
|
||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||
|
||||
changes_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
||||
|
||||
if format.get_selected() == "html":
|
||||
changes_xml += "<td><img src=\"{0}\"/>{1}</td>".format(
|
||||
gravatar.get_url(self.changes.get_author_email(entry)), entry)
|
||||
else:
|
||||
changes_xml += "<td>" + entry + "</td>"
|
||||
|
||||
changes_xml += "<td>" + str(authorinfo.commits) + "</td>"
|
||||
changes_xml += "<td>" + str(authorinfo.insertions) + "</td>"
|
||||
changes_xml += "<td>" + str(authorinfo.deletions) + "</td>"
|
||||
changes_xml += "<td>" + "{0:.2f}".format(percentage) + "</td>"
|
||||
changes_xml += "</tr>"
|
||||
chart_data += "{{label: \"{0}\", data: {1}}}".format(entry, "{0:.2f}".format(percentage))
|
||||
|
||||
if sorted(authorinfo_list)[-1] != entry:
|
||||
chart_data += ", "
|
||||
|
||||
changes_xml += ("<tfoot><tr> <td colspan=\"5\"> </td> </tr></tfoot></tbody></table>")
|
||||
changes_xml += "<div class=\"chart\" id=\"changes_chart\"></div></div>"
|
||||
changes_xml += "<script type=\"text/javascript\">"
|
||||
changes_xml += " $.plot($(\"#changes_chart\"), [{0}], {{".format(chart_data)
|
||||
changes_xml += " series: {"
|
||||
changes_xml += " pie: {"
|
||||
changes_xml += " innerRadius: 0.4,"
|
||||
changes_xml += " show: true,"
|
||||
changes_xml += " combine: {"
|
||||
changes_xml += " threshold: 0.01,"
|
||||
changes_xml += " label: \"" + _("Minor Authors") + "\""
|
||||
changes_xml += " }"
|
||||
changes_xml += " }"
|
||||
changes_xml += " }, grid: {"
|
||||
changes_xml += " hoverable: true"
|
||||
changes_xml += " }"
|
||||
changes_xml += " });"
|
||||
changes_xml += "</script>"
|
||||
else:
|
||||
changes_xml += "<p>" + _(NO_COMMITED_FILES_TEXT) + ".</p>"
|
||||
|
||||
changes_xml += "</div></div>"
|
||||
print(changes_xml)
|
||||
|
||||
def output_text(self):
|
||||
authorinfo_list = self.changes.get_authorinfo_list()
|
||||
total_changes = 0.0
|
||||
|
||||
for i in authorinfo_list:
|
||||
total_changes += authorinfo_list.get(i).insertions
|
||||
total_changes += authorinfo_list.get(i).deletions
|
||||
|
||||
if authorinfo_list:
|
||||
print(textwrap.fill(_(HISTORICAL_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n")
|
||||
terminal.printb(_("Author").ljust(21) + _("Commits").rjust(13) + _("Insertions").rjust(14) +
|
||||
_("Deletions").rjust(15) + _("% of changes").rjust(16))
|
||||
|
||||
for i in sorted(authorinfo_list):
|
||||
authorinfo = authorinfo_list.get(i)
|
||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||
|
||||
print(i.ljust(20)[0:20], end=" ")
|
||||
print(str(authorinfo.commits).rjust(13), end=" ")
|
||||
print(str(authorinfo.insertions).rjust(13), end=" ")
|
||||
print(str(authorinfo.deletions).rjust(14), end=" ")
|
||||
print("{0:.2f}".format(percentage).rjust(15))
|
||||
else:
|
||||
print(_(NO_COMMITED_FILES_TEXT) + ".")
|
||||
|
||||
def output_xml(self):
|
||||
authorinfo_list = self.changes.get_authorinfo_list()
|
||||
total_changes = 0.0
|
||||
|
||||
for i in authorinfo_list:
|
||||
total_changes += authorinfo_list.get(i).insertions
|
||||
total_changes += authorinfo_list.get(i).deletions
|
||||
|
||||
if authorinfo_list:
|
||||
message_xml = "\t\t<message>" + _(HISTORICAL_INFO_TEXT) + "</message>\n"
|
||||
changes_xml = ""
|
||||
|
||||
for i in sorted(authorinfo_list):
|
||||
authorinfo = authorinfo_list.get(i)
|
||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||
name_xml = "\t\t\t\t<name>" + i + "</name>\n"
|
||||
gravatar_xml = "\t\t\t\t<gravatar>" + gravatar.get_url(self.changes.get_author_email(i)) + "</gravatar>\n"
|
||||
commits_xml = "\t\t\t\t<commits>" + str(authorinfo.commits) + "</commits>\n"
|
||||
insertions_xml = "\t\t\t\t<insertions>" + str(authorinfo.insertions) + "</insertions>\n"
|
||||
deletions_xml = "\t\t\t\t<deletions>" + str(authorinfo.deletions) + "</deletions>\n"
|
||||
percentage_xml = "\t\t\t\t<percentage-of-changes>" + "{0:.2f}".format(percentage) + "</percentage-of-changes>\n"
|
||||
|
||||
changes_xml += ("\t\t\t<author>\n" + name_xml + gravatar_xml + commits_xml + insertions_xml +
|
||||
deletions_xml + percentage_xml + "\t\t\t</author>\n")
|
||||
|
||||
print("\t<changes>\n" + message_xml + "\t\t<authors>\n" + changes_xml + "\t\t</authors>\n\t</changes>")
|
||||
else:
|
||||
print("\t<changes>\n\t\t<exception>" + _(NO_COMMITED_FILES_TEXT) + "</exception>\n\t</changes>")
|
||||
def get_latest_email_by_author(self, name):
|
||||
return self.emails_by_author[name]
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2014 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
except:
|
||||
from urlparse import urlparse
|
||||
|
||||
__cloned_paths__ = []
|
||||
|
||||
def create(url):
|
||||
class Repository(object):
|
||||
def __init__(self, name, location):
|
||||
self.name = name
|
||||
self.location = location
|
||||
|
||||
parsed_url = urlparse(url)
|
||||
|
||||
if parsed_url.scheme == "file" or parsed_url.scheme == "git" or parsed_url.scheme == "http" or \
|
||||
parsed_url.scheme == "https" or parsed_url.scheme == "ssh":
|
||||
path = tempfile.mkdtemp(suffix=".gitinspector")
|
||||
git_clone = subprocess.Popen(["git", "clone", url, path], bufsize=1, stdout=sys.stderr)
|
||||
git_clone.wait()
|
||||
|
||||
if git_clone.returncode != 0:
|
||||
sys.exit(git_clone.returncode)
|
||||
|
||||
__cloned_paths__.append(path)
|
||||
return Repository(os.path.basename(parsed_url.path), path)
|
||||
|
||||
return Repository(None, os.path.abspath(url))
|
||||
|
||||
def delete():
|
||||
for path in __cloned_paths__:
|
||||
shutil.rmtree(path, ignore_errors=True)
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -19,16 +19,20 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__comment_begining__ = {"java": "/*", "c": "/*", "cpp": "/*", "h": "/*", "hpp": "/*", "html": "<!--", "php": "/*",
|
||||
"py": "\"\"\"", "glsl": "/*", "rb": "=begin", "js": "/*", "sql": "/*",
|
||||
"tex": "\\begin{comment}", "xml": "<!--"}
|
||||
__comment_begining__ = {"java": "/*", "c": "/*", "cc": "/*", "cpp": "/*", "cs": "/*", "h": "/*", "hh": "/*", "hpp": "/*",
|
||||
"hs": "{-", "html": "<!--", "php": "/*", "py": "\"\"\"", "glsl": "/*", "rb": "=begin", "js": "/*",
|
||||
"jspx": "<!--", "scala": "/*", "sql": "/*", "tex": "\\begin{comment}", "xhtml": "<!--",
|
||||
"xml": "<!--", "ml": "(*", "mli": "(*", "go": "/*", "ly": "%{", "ily": "%{"}
|
||||
|
||||
__comment_end__ = {"java": "*/", "c": "*/", "cpp": "*/", "h": "*/", "hpp": "*/", "html": "-->", "php": "/*",
|
||||
"py": "\"\"\"", "glsl": "*/", "rb": "=end", "js": "*/", "sql": "*/",
|
||||
"tex": "\\end{comment}", "xml": "-->"}
|
||||
__comment_end__ = {"java": "*/", "c": "*/", "cc": "*/", "cpp": "*/", "cs": "*/", "h": "*/", "hh": "*/", "hpp": "*/", "hs": "-}",
|
||||
"html": "-->", "php": "*/", "py": "\"\"\"", "glsl": "*/", "rb": "=end", "js": "*/", "jspx": "-->",
|
||||
"scala": "*/", "sql": "*/", "tex": "\\end{comment}", "xhtml": "-->", "xml": "-->", "ml": "*)", "mli": "*)",
|
||||
"go": "*/", "ly": "%}", "ily": "%}"}
|
||||
|
||||
__comment__ = {"java": "//", "c": "//", "cpp": "//", "h": "//", "hpp": "//", "pl": "#", "php": "//", "py": "#",
|
||||
"glsl": "//", "rb": "#", "js": "//", "sql": "--", "tex": "%"}
|
||||
__comment__ = {"java": "//", "c": "//", "cc": "//", "cpp": "//", "cs": "//", "h": "//", "hh": "//", "hpp": "//", "hs": "--",
|
||||
"pl": "#", "php": "//", "py": "#", "glsl": "//", "rb": "#", "robot": "#", "rs": "//", "rlib": "//", "js": "//",
|
||||
"scala": "//", "sql": "--", "tex": "%", "ada": "--", "ads": "--", "adb": "--", "pot": "#", "po": "#", "go": "//",
|
||||
"ly": "%", "ily": "%"}
|
||||
|
||||
__comment_markers_must_be_at_begining__ = {"tex": True}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2013-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -18,77 +18,76 @@
|
|||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import extensions
|
||||
import filtering
|
||||
import format
|
||||
import interval
|
||||
import missing
|
||||
import optval
|
||||
import os
|
||||
import subprocess
|
||||
from . import extensions, filtering, format, interval, optval
|
||||
|
||||
def __read_git_config__(repo, variable):
|
||||
previous_directory = os.getcwd()
|
||||
os.chdir(repo)
|
||||
setting = subprocess.Popen("git config inspector." + variable, shell=True, bufsize=1,
|
||||
stdout=subprocess.PIPE).stdout
|
||||
os.chdir(previous_directory)
|
||||
class GitConfig(object):
|
||||
def __init__(self, run, repo, global_only=False):
|
||||
self.run = run
|
||||
self.repo = repo
|
||||
self.global_only = global_only
|
||||
|
||||
try:
|
||||
setting = setting.readlines()[0]
|
||||
setting = setting.decode("utf-8", "replace").strip()
|
||||
except IndexError:
|
||||
setting = ""
|
||||
def __read_git_config__(self, variable):
|
||||
previous_directory = os.getcwd()
|
||||
os.chdir(self.repo)
|
||||
setting = subprocess.Popen(filter(None, ["git", "config", "--global" if self.global_only else "",
|
||||
"inspector." + variable]), bufsize=1, stdout=subprocess.PIPE).stdout
|
||||
os.chdir(previous_directory)
|
||||
|
||||
return setting
|
||||
try:
|
||||
setting = setting.readlines()[0]
|
||||
setting = setting.decode("utf-8", "replace").strip()
|
||||
except IndexError:
|
||||
setting = ""
|
||||
|
||||
def __read_git_config_bool__(repo, variable):
|
||||
try:
|
||||
variable = __read_git_config__(repo, variable)
|
||||
return optval.get_boolean_argument(False if variable == "" else variable)
|
||||
except optval.InvalidOptionArgument:
|
||||
return False
|
||||
return setting
|
||||
|
||||
def __read_git_config_string__(repo, variable):
|
||||
string = __read_git_config__(repo, variable)
|
||||
return (True, string) if len(string) > 0 else (False, None)
|
||||
def __read_git_config_bool__(self, variable):
|
||||
try:
|
||||
variable = self.__read_git_config__(variable)
|
||||
return optval.get_boolean_argument(False if variable == "" else variable)
|
||||
except optval.InvalidOptionArgument:
|
||||
return False
|
||||
|
||||
def init(run):
|
||||
missing.set_checkout_missing(__read_git_config_bool__(run.repo, "checkout-missing"))
|
||||
def __read_git_config_string__(self, variable):
|
||||
string = self.__read_git_config__(variable)
|
||||
return (True, string) if len(string) > 0 else (False, None)
|
||||
|
||||
var = __read_git_config_string__(run.repo, "file-types")
|
||||
if var[0]:
|
||||
extensions.define(var[1])
|
||||
def read(self):
|
||||
var = self.__read_git_config_string__("file-types")
|
||||
if var[0]:
|
||||
extensions.define(var[1])
|
||||
|
||||
var = __read_git_config_string__(run.repo, "exclude")
|
||||
if var[0]:
|
||||
filtering.add(var[1])
|
||||
var = self.__read_git_config_string__("exclude")
|
||||
if var[0]:
|
||||
filtering.add(var[1])
|
||||
|
||||
var = __read_git_config_string__(run.repo, "format")
|
||||
if var[0] and not format.select(var[1]):
|
||||
raise format.InvalidFormatError(_("specified output format not supported."))
|
||||
var = self.__read_git_config_string__("format")
|
||||
if var[0] and not format.select(var[1]):
|
||||
raise format.InvalidFormatError(_("specified output format not supported."))
|
||||
|
||||
run.hard = __read_git_config_bool__(run.repo, "hard")
|
||||
run.list_file_types = __read_git_config_bool__(run.repo, "list-file-types")
|
||||
run.localize_output = __read_git_config_bool__(run.repo, "localize-output")
|
||||
run.metrics = __read_git_config_bool__(run.repo, "metrics")
|
||||
run.responsibilities = __read_git_config_bool__(run.repo, "responsibilities")
|
||||
run.useweeks = __read_git_config_bool__(run.repo, "weeks")
|
||||
self.run.hard = self.__read_git_config_bool__("hard")
|
||||
self.run.list_file_types = self.__read_git_config_bool__("list-file-types")
|
||||
self.run.localize_output = self.__read_git_config_bool__("localize-output")
|
||||
self.run.metrics = self.__read_git_config_bool__("metrics")
|
||||
self.run.responsibilities = self.__read_git_config_bool__("responsibilities")
|
||||
self.run.useweeks = self.__read_git_config_bool__("weeks")
|
||||
|
||||
var = __read_git_config_string__(run.repo, "since")
|
||||
if var[0]:
|
||||
interval.set_since(var[1])
|
||||
var = self.__read_git_config_string__("since")
|
||||
if var[0]:
|
||||
interval.set_since(var[1])
|
||||
|
||||
var = __read_git_config_string__(run.repo, "until")
|
||||
if var[0]:
|
||||
interval.set_until(var[1])
|
||||
var = self.__read_git_config_string__("until")
|
||||
if var[0]:
|
||||
interval.set_until(var[1])
|
||||
|
||||
run.timeline = __read_git_config_bool__(run.repo, "timeline")
|
||||
self.run.timeline = self.__read_git_config_bool__("timeline")
|
||||
|
||||
if __read_git_config_bool__(run.repo, "grading"):
|
||||
run.hard = True
|
||||
run.list_file_types = True
|
||||
run.metrics = True
|
||||
run.responsibilities = True
|
||||
run.timeline = True
|
||||
run.useweeks = True
|
||||
if self.__read_git_config_bool__("grading"):
|
||||
self.run.hard = True
|
||||
self.run.list_file_types = True
|
||||
self.run.metrics = True
|
||||
self.run.responsibilities = True
|
||||
self.run.timeline = True
|
||||
self.run.useweeks = True
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -17,14 +17,9 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
import terminal
|
||||
import textwrap
|
||||
|
||||
DEFAULT_EXTENSIONS = ["java", "c", "cpp", "h", "hpp", "py", "glsl", "rb", "js", "sql"]
|
||||
DEFAULT_EXTENSIONS = ["java", "c", "cc", "cpp", "h", "hh", "hpp", "py", "glsl", "rb", "js", "sql"]
|
||||
|
||||
__extensions__ = DEFAULT_EXTENSIONS
|
||||
__located_extensions__ = set()
|
||||
|
@ -37,51 +32,10 @@ def define(string):
|
|||
__extensions__ = string.split(",")
|
||||
|
||||
def add_located(string):
|
||||
if len(string) > 0:
|
||||
if len(string) == 0:
|
||||
__located_extensions__.add("*")
|
||||
else:
|
||||
__located_extensions__.add(string)
|
||||
|
||||
EXTENSIONS_INFO_TEXT = N_("The extensions below were found in the repository history")
|
||||
EXTENSIONS_MARKED_TEXT = N_("(extensions used during statistical analysis are marked)")
|
||||
|
||||
class Extensions(Outputable):
|
||||
def output_html(self):
|
||||
if __located_extensions__:
|
||||
extensions_xml = "<div><div class=\"box\">"
|
||||
extensions_xml += "<p>{0} {1}.</p><p>".format(_(EXTENSIONS_INFO_TEXT), _(EXTENSIONS_MARKED_TEXT))
|
||||
|
||||
for i in __located_extensions__:
|
||||
if i in __extensions__:
|
||||
extensions_xml += "<strong>" + i + "</strong>"
|
||||
else:
|
||||
extensions_xml += i
|
||||
extensions_xml += " "
|
||||
|
||||
extensions_xml += "</p></div></div>"
|
||||
print(extensions_xml)
|
||||
|
||||
def output_text(self):
|
||||
if __located_extensions__:
|
||||
print("\n" + textwrap.fill("{0} {1}:".format(_(EXTENSIONS_INFO_TEXT), _(EXTENSIONS_MARKED_TEXT)),
|
||||
width=terminal.get_size()[0]))
|
||||
|
||||
for i in __located_extensions__:
|
||||
if i in __extensions__:
|
||||
print("[" + terminal.__bold__ + i + terminal.__normal__ + "]", end=" ")
|
||||
else:
|
||||
print (i, end=" ")
|
||||
print("")
|
||||
|
||||
def output_xml(self):
|
||||
if __located_extensions__:
|
||||
message_xml = "\t\t<message>" + _(EXTENSIONS_INFO_TEXT) + "</message>\n"
|
||||
used_extensions_xml = ""
|
||||
unused_extensions_xml = ""
|
||||
|
||||
for i in __located_extensions__:
|
||||
if i in __extensions__:
|
||||
used_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
|
||||
else:
|
||||
unused_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
|
||||
|
||||
print("\t<extensions>\n" + message_xml + "\t\t<used>\n" + used_extensions_xml + "\t\t</used>\n" +
|
||||
"\t\t<unused>\n" + unused_extensions_xml + "\t\t</unused>\n" + "\t</extensions>")
|
||||
def get_located():
|
||||
return __located_extensions__
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -17,16 +17,12 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
import re
|
||||
import terminal
|
||||
import textwrap
|
||||
import subprocess
|
||||
|
||||
__filters__ = []
|
||||
__filtered_files__ = set()
|
||||
__filters__ = {"file": [set(), set()], "author": [set(), set()], "email": [set(), set()], "revision": [set(), set()],
|
||||
"message" : [set(), None]}
|
||||
|
||||
class InvalidRegExpError(ValueError):
|
||||
def __init__(self, msg):
|
||||
|
@ -36,57 +32,58 @@ class InvalidRegExpError(ValueError):
|
|||
def get():
|
||||
return __filters__
|
||||
|
||||
def __add_one__(string):
|
||||
for i in __filters__:
|
||||
if (i + ":").lower() == string[0:len(i) + 1].lower():
|
||||
__filters__[i][0].add(string[len(i) + 1:])
|
||||
return
|
||||
__filters__["file"][0].add(string)
|
||||
|
||||
def add(string):
|
||||
__filters__.append(string)
|
||||
rules = string.split(",")
|
||||
for rule in rules:
|
||||
__add_one__(rule)
|
||||
|
||||
def clear():
|
||||
global __filters__
|
||||
__filters__ = []
|
||||
for i in __filters__:
|
||||
__filters__[i][0] = set()
|
||||
|
||||
def get_filered():
|
||||
return __filtered_files__
|
||||
def get_filered(filter_type="file"):
|
||||
return __filters__[filter_type][1]
|
||||
|
||||
def set_filtered(file_name):
|
||||
string = file_name.strip()
|
||||
def has_filtered():
|
||||
for i in __filters__:
|
||||
if __filters__[i][1]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __find_commit_message__(sha):
|
||||
git_show_r = subprocess.Popen(filter(None, ["git", "show", "-s", "--pretty=%B", "-w", sha]), bufsize=1,
|
||||
stdout=subprocess.PIPE).stdout
|
||||
|
||||
commit_message = git_show_r.read()
|
||||
git_show_r.close()
|
||||
|
||||
commit_message = commit_message.strip().decode("unicode_escape", "ignore")
|
||||
commit_message = commit_message.encode("latin-1", "replace")
|
||||
return commit_message.decode("utf-8", "replace")
|
||||
|
||||
def set_filtered(string, filter_type="file"):
|
||||
string = string.strip()
|
||||
|
||||
if len(string) > 0:
|
||||
for i in __filters__:
|
||||
for i in __filters__[filter_type][0]:
|
||||
search_for = string
|
||||
|
||||
if filter_type == "message":
|
||||
search_for = __find_commit_message__(string)
|
||||
try:
|
||||
if re.search(i, string) != None:
|
||||
__filtered_files__.add(string)
|
||||
if re.search(i, search_for) != None:
|
||||
if filter_type == "message":
|
||||
__add_one__("revision:" + string)
|
||||
else:
|
||||
__filters__[filter_type][1].add(string)
|
||||
return True
|
||||
except:
|
||||
raise InvalidRegExpError(_("invalid regular expression specified"))
|
||||
return False
|
||||
|
||||
FILTERING_INFO_TEXT = N_("The following files were excluded from the statistics due to the specified exclusion patterns")
|
||||
|
||||
class Filtering(Outputable):
|
||||
def output_html(self):
|
||||
if __filtered_files__:
|
||||
filtering_xml = "<div><div class=\"box\">"
|
||||
filtering_xml += "<p>" + _(FILTERING_INFO_TEXT) + "."+ "</p>"
|
||||
|
||||
for i in __filtered_files__:
|
||||
filtering_xml += "<p>" + i + "</p>"
|
||||
|
||||
filtering_xml += "</div></div>"
|
||||
print(filtering_xml)
|
||||
|
||||
def output_text(self):
|
||||
if __filtered_files__:
|
||||
print("\n" + textwrap.fill(_(FILTERING_INFO_TEXT) + ":", width=terminal.get_size()[0]))
|
||||
|
||||
for i in __filtered_files__:
|
||||
(width, _unused) = terminal.get_size()
|
||||
print("...%s" % i[-width+3:] if len(i) > width else i)
|
||||
|
||||
def output_xml(self):
|
||||
if __filtered_files__:
|
||||
message_xml = "\t\t<message>" + _(FILTERING_INFO_TEXT) + "</message>\n"
|
||||
filtering_xml = ""
|
||||
|
||||
for i in __filtered_files__:
|
||||
filtering_xml += "\t\t\t<file>" + i + "</file>\n"
|
||||
|
||||
print("\t<filering>\n" + message_xml + "\t\t<files>\n" + filtering_xml + "\t\t</files>\n\t</filtering>")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -19,15 +19,17 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import version
|
||||
import base64
|
||||
import basedir
|
||||
import os
|
||||
import textwrap
|
||||
import time
|
||||
import zipfile
|
||||
from .localization import N_
|
||||
from . import basedir, localization, terminal, version
|
||||
|
||||
__available_formats__ = ["html", "htmlembedded", "text", "xml"]
|
||||
__available_formats__ = ["html", "htmlembedded", "json", "text", "xml"]
|
||||
|
||||
DEFAULT_FORMAT = __available_formats__[2]
|
||||
DEFAULT_FORMAT = __available_formats__[3]
|
||||
|
||||
__selected_format__ = DEFAULT_FORMAT
|
||||
|
||||
|
@ -51,19 +53,30 @@ def is_interactive_format():
|
|||
def __output_html_template__(name):
|
||||
template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), name)
|
||||
file_r = open(template_path, "rb")
|
||||
return file_r.read().decode("utf-8", "replace")
|
||||
template = file_r.read().decode("utf-8", "replace")
|
||||
|
||||
file_r.close()
|
||||
return template
|
||||
|
||||
def __get_zip_file_content__(name, file_name="/html/flot.zip"):
|
||||
zip_file = zipfile.ZipFile(basedir.get_basedir() + file_name, "r")
|
||||
content = zip_file.read(name)
|
||||
|
||||
zip_file.close()
|
||||
return content.decode("utf-8", "replace")
|
||||
|
||||
def output_header():
|
||||
INFO_ONE_REPOSITORY = N_("Statistical information for the repository '{0}' was gathered on {1}.")
|
||||
INFO_MANY_REPOSITORIES = N_("Statistical information for the repositories '{0}' was gathered on {1}.")
|
||||
|
||||
def output_header(repos):
|
||||
repos_string = ", ".join([repo.name for repo in repos])
|
||||
|
||||
if __selected_format__ == "html" or __selected_format__ == "htmlembedded":
|
||||
base = basedir.get_basedir()
|
||||
html_header = __output_html_template__(base + "/html/html.header")
|
||||
tablesorter_js = __get_zip_file_content__("jquery.tablesorter.min.js", "/html/jquery.tablesorter.min.js.zip")
|
||||
tablesorter_js = __get_zip_file_content__("jquery.tablesorter.min.js",
|
||||
"/html/jquery.tablesorter.min.js.zip").encode("latin-1", "replace")
|
||||
tablesorter_js = tablesorter_js.decode("utf-8", "ignore")
|
||||
flot_js = __get_zip_file_content__("jquery.flot.js")
|
||||
pie_js = __get_zip_file_content__("jquery.flot.pie.js")
|
||||
resize_js = __get_zip_file_content__("jquery.flot.resize.js")
|
||||
|
@ -76,29 +89,66 @@ def output_header():
|
|||
if __selected_format__ == "htmlembedded":
|
||||
jquery_js = ">" + __get_zip_file_content__("jquery.js")
|
||||
else:
|
||||
jquery_js = " src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js\">"
|
||||
jquery_js = " src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js\">"
|
||||
|
||||
print(html_header.format(version = version.__version__,
|
||||
jquery = jquery_js,
|
||||
jquery_tablesorter = tablesorter_js,
|
||||
jquery_flot = flot_js,
|
||||
jquery_flot_pie = pie_js,
|
||||
jquery_flot_resize = resize_js,
|
||||
logo = logo.decode("utf-8", "replace"),
|
||||
logo_text = _("The output has been generated by {0}; the statistical analysis tool"
|
||||
print(html_header.format(title=_("Repository statistics for '{0}'").format(repos_string),
|
||||
jquery=jquery_js,
|
||||
jquery_tablesorter=tablesorter_js,
|
||||
jquery_flot=flot_js,
|
||||
jquery_flot_pie=pie_js,
|
||||
jquery_flot_resize=resize_js,
|
||||
logo=logo.decode("utf-8", "replace"),
|
||||
logo_text=_("The output has been generated by {0} {1}. The statistical analysis tool"
|
||||
" for git repositories.").format(
|
||||
"<a href=\"http://gitinspector.googlecode.com\">gitinspector</a>"),
|
||||
show_minor_authors = _("Show minor authors"),
|
||||
hide_minor_authors = _("Hide minor authors"),
|
||||
show_minor_rows = _("Show rows with minor work"),
|
||||
hide_minor_rows = _("Hide rows with minor work")))
|
||||
"<a href=\"https://github.com/ejwa/gitinspector\">gitinspector</a>",
|
||||
version.__version__),
|
||||
repo_text=_(INFO_ONE_REPOSITORY if len(repos) <= 1 else INFO_MANY_REPOSITORIES).format(
|
||||
repos_string, localization.get_date()),
|
||||
show_minor_authors=_("Show minor authors"),
|
||||
hide_minor_authors=_("Hide minor authors"),
|
||||
show_minor_rows=_("Show rows with minor work"),
|
||||
hide_minor_rows=_("Hide rows with minor work")))
|
||||
elif __selected_format__ == "json":
|
||||
print("{\n\t\"gitinspector\": {")
|
||||
print("\t\t\"version\": \"" + version.__version__ + "\",")
|
||||
|
||||
if len(repos) <= 1:
|
||||
print("\t\t\"repository\": \"" + repos_string + "\",")
|
||||
else:
|
||||
repos_json = "\t\t\"repositories\": [ "
|
||||
|
||||
for repo in repos:
|
||||
repos_json += "\"" + repo.name + "\", "
|
||||
|
||||
print(repos_json[:-2] + " ],")
|
||||
|
||||
print("\t\t\"report_date\": \"" + time.strftime("%Y/%m/%d") + "\",")
|
||||
|
||||
elif __selected_format__ == "xml":
|
||||
print("<gitinspector>")
|
||||
print("\t<version>" + version.__version__ + "</version>")
|
||||
|
||||
if len(repos) <= 1:
|
||||
print("\t<repository>" + repos_string + "</repository>")
|
||||
else:
|
||||
print("\t<repositories>")
|
||||
|
||||
for repo in repos:
|
||||
print("\t\t<repository>" + repo.name + "</repository>")
|
||||
|
||||
print("\t</repositories>")
|
||||
|
||||
print("\t<report-date>" + time.strftime("%Y/%m/%d") + "</report-date>")
|
||||
else:
|
||||
print(textwrap.fill(_(INFO_ONE_REPOSITORY if len(repos) <= 1 else INFO_MANY_REPOSITORIES).format(
|
||||
repos_string, localization.get_date()), width=terminal.get_size()[0]))
|
||||
|
||||
def output_footer():
|
||||
if __selected_format__ == "html":
|
||||
html_footer = __output_html_template__("html/html.footer")
|
||||
if __selected_format__ == "html" or __selected_format__ == "htmlembedded":
|
||||
base = basedir.get_basedir()
|
||||
html_footer = __output_html_template__(base + "/html/html.footer")
|
||||
print(html_footer)
|
||||
elif __selected_format__ == "json":
|
||||
print("\n\t}\n}")
|
||||
elif __selected_format__ == "xml":
|
||||
print("</gitinspector>")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -20,80 +19,85 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import atexit
|
||||
import getopt
|
||||
import os
|
||||
import sys
|
||||
from .blame import Blame
|
||||
from .changes import Changes
|
||||
from .config import GitConfig
|
||||
from .metrics import MetricsLogic
|
||||
from . import (basedir, clone, extensions, filtering, format, help, interval,
|
||||
localization, optval, terminal, version)
|
||||
from .output import outputable
|
||||
from .output.blameoutput import BlameOutput
|
||||
from .output.changesoutput import ChangesOutput
|
||||
from .output.extensionsoutput import ExtensionsOutput
|
||||
from .output.filteringoutput import FilteringOutput
|
||||
from .output.metricsoutput import MetricsOutput
|
||||
from .output.responsibilitiesoutput import ResponsibilitiesOutput
|
||||
from .output.timelineoutput import TimelineOutput
|
||||
|
||||
import localization
|
||||
localization.init()
|
||||
|
||||
import blame
|
||||
import changes
|
||||
import config
|
||||
import extensions
|
||||
import filtering
|
||||
import format
|
||||
import help
|
||||
import interval
|
||||
import getopt
|
||||
import metrics
|
||||
import missing
|
||||
import os
|
||||
import optval
|
||||
import outputable
|
||||
import responsibilities
|
||||
import subprocess
|
||||
import sys
|
||||
import terminal
|
||||
import timeline
|
||||
import version
|
||||
|
||||
class Runner:
|
||||
class Runner(object):
|
||||
def __init__(self):
|
||||
self.hard = False
|
||||
self.include_metrics = False
|
||||
self.list_file_types = False
|
||||
self.localize_output = False
|
||||
self.repo = "."
|
||||
self.responsibilities = False
|
||||
self.grading = False
|
||||
self.timeline = False
|
||||
self.useweeks = False
|
||||
|
||||
def output(self):
|
||||
def process(self, repos):
|
||||
localization.check_compatibility(version.__version__)
|
||||
|
||||
if not self.localize_output:
|
||||
localization.disable()
|
||||
|
||||
terminal.skip_escapes(not sys.stdout.isatty())
|
||||
terminal.set_stdout_encoding()
|
||||
previous_directory = os.getcwd()
|
||||
summed_blames = Blame.__new__(Blame)
|
||||
summed_changes = Changes.__new__(Changes)
|
||||
summed_metrics = MetricsLogic.__new__(MetricsLogic)
|
||||
|
||||
os.chdir(self.repo)
|
||||
absolute_path = subprocess.Popen("git rev-parse --show-toplevel", shell=True, bufsize=1,
|
||||
stdout=subprocess.PIPE).stdout
|
||||
absolute_path = absolute_path.readlines()
|
||||
if len(absolute_path) == 0:
|
||||
sys.exit(0)
|
||||
|
||||
os.chdir(absolute_path[0].decode("utf-8", "replace").strip())
|
||||
|
||||
format.output_header()
|
||||
outputable.output(changes.ChangesOutput(self.hard))
|
||||
|
||||
if changes.get(self.hard).get_commits():
|
||||
outputable.output(blame.BlameOutput(self.hard))
|
||||
|
||||
if self.timeline:
|
||||
outputable.output(timeline.Timeline(changes.get(self.hard), self.useweeks))
|
||||
for repo in repos:
|
||||
os.chdir(repo.location)
|
||||
repo = repo if len(repos) > 1 else None
|
||||
changes = Changes(repo, self.hard)
|
||||
summed_blames += Blame(repo, self.hard, self.useweeks, changes)
|
||||
summed_changes += changes
|
||||
|
||||
if self.include_metrics:
|
||||
outputable.output(metrics.Metrics())
|
||||
summed_metrics += MetricsLogic()
|
||||
|
||||
if sys.stdout.isatty() and format.is_interactive_format():
|
||||
terminal.clear_row()
|
||||
else:
|
||||
os.chdir(previous_directory)
|
||||
|
||||
format.output_header(repos)
|
||||
outputable.output(ChangesOutput(summed_changes))
|
||||
|
||||
if summed_changes.get_commits():
|
||||
outputable.output(BlameOutput(summed_changes, summed_blames))
|
||||
|
||||
if self.timeline:
|
||||
outputable.output(TimelineOutput(summed_changes, self.useweeks))
|
||||
|
||||
if self.include_metrics:
|
||||
outputable.output(MetricsOutput(summed_metrics))
|
||||
|
||||
if self.responsibilities:
|
||||
outputable.output(responsibilities.ResponsibilitiesOutput(self.hard))
|
||||
outputable.output(ResponsibilitiesOutput(summed_changes, summed_blames))
|
||||
|
||||
outputable.output(missing.Missing())
|
||||
outputable.output(filtering.Filtering())
|
||||
outputable.output(FilteringOutput())
|
||||
|
||||
if self.list_file_types:
|
||||
outputable.output(extensions.Extensions())
|
||||
outputable.output(ExtensionsOutput())
|
||||
|
||||
format.output_footer()
|
||||
os.chdir(previous_directory)
|
||||
|
@ -103,30 +107,44 @@ def __check_python_version__():
|
|||
python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1])
|
||||
sys.exit(_("gitinspector requires at least Python 2.6 to run (version {0} was found).").format(python_version))
|
||||
|
||||
def __get_validated_git_repos__(repos_relative):
|
||||
if not repos_relative:
|
||||
repos_relative = "."
|
||||
|
||||
repos = []
|
||||
|
||||
#Try to clone the repos or return the same directory and bail out.
|
||||
for repo in repos_relative:
|
||||
cloned_repo = clone.create(repo)
|
||||
|
||||
if cloned_repo.name == None:
|
||||
cloned_repo.location = basedir.get_basedir_git(cloned_repo.location)
|
||||
cloned_repo.name = os.path.basename(cloned_repo.location)
|
||||
|
||||
repos.append(cloned_repo)
|
||||
|
||||
return repos
|
||||
|
||||
def main():
|
||||
terminal.check_terminal_encoding()
|
||||
terminal.set_stdin_encoding()
|
||||
argv = terminal.convert_command_line_to_utf8()
|
||||
__run__ = Runner()
|
||||
run = Runner()
|
||||
repos = []
|
||||
|
||||
try:
|
||||
__opts__, __args__ = optval.gnu_getopt(argv[1:], "cf:F:hHlLmrTwx:", ["checkout-missing:true", "exclude=",
|
||||
"file-types=", "format=", "hard:true", "help",
|
||||
"list-file-types:true", "localize-output:true",
|
||||
"metrics:true", "responsibilities:true", "since=",
|
||||
"grading:true", "timeline:true", "until=", "version",
|
||||
"weeks:true"])
|
||||
for arg in __args__:
|
||||
__run__.repo = arg
|
||||
opts, args = optval.gnu_getopt(argv[1:], "f:F:hHlLmrTwx:", ["exclude=", "file-types=", "format=",
|
||||
"hard:true", "help", "list-file-types:true", "localize-output:true",
|
||||
"metrics:true", "responsibilities:true", "since=", "grading:true",
|
||||
"timeline:true", "until=", "version", "weeks:true"])
|
||||
repos = __get_validated_git_repos__(set(args))
|
||||
|
||||
#We need the repo above to be set before we read the git config.
|
||||
config.init(__run__)
|
||||
#We need the repos above to be set before we read the git config.
|
||||
GitConfig(run, repos[-1].location).read()
|
||||
clear_x_on_next_pass = True
|
||||
|
||||
for o, a in __opts__:
|
||||
if o == "-c":
|
||||
missing.set_checkout_missing(True)
|
||||
elif o == "--checkout-missing":
|
||||
missing.set_checkout_missing(optval.get_boolean_argument(a))
|
||||
elif o in("-h", "--help"):
|
||||
for o, a in opts:
|
||||
if o in("-h", "--help"):
|
||||
help.output()
|
||||
sys.exit(0)
|
||||
elif o in("-f", "--file-types"):
|
||||
|
@ -135,25 +153,25 @@ def main():
|
|||
if not format.select(a):
|
||||
raise format.InvalidFormatError(_("specified output format not supported."))
|
||||
elif o == "-H":
|
||||
__run__.hard = True
|
||||
run.hard = True
|
||||
elif o == "--hard":
|
||||
__run__.hard = optval.get_boolean_argument(a)
|
||||
run.hard = optval.get_boolean_argument(a)
|
||||
elif o == "-l":
|
||||
__run__.list_file_types = True
|
||||
run.list_file_types = True
|
||||
elif o == "--list-file-types":
|
||||
__run__.list_file_types = optval.get_boolean_argument(a)
|
||||
run.list_file_types = optval.get_boolean_argument(a)
|
||||
elif o == "-L":
|
||||
__run__.localize_output = True
|
||||
run.localize_output = True
|
||||
elif o == "--localize-output":
|
||||
__run__.localize_output = optval.get_boolean_argument(a)
|
||||
run.localize_output = optval.get_boolean_argument(a)
|
||||
elif o == "-m":
|
||||
__run__.include_metrics = True
|
||||
run.include_metrics = True
|
||||
elif o == "--metrics":
|
||||
__run__.include_metrics = optval.get_boolean_argument(a)
|
||||
run.include_metrics = optval.get_boolean_argument(a)
|
||||
elif o == "-r":
|
||||
__run__.responsibilities = True
|
||||
run.responsibilities = True
|
||||
elif o == "--responsibilities":
|
||||
__run__.responsibilities = optval.get_boolean_argument(a)
|
||||
run.responsibilities = optval.get_boolean_argument(a)
|
||||
elif o == "--since":
|
||||
interval.set_since(a)
|
||||
elif o == "--version":
|
||||
|
@ -161,23 +179,23 @@ def main():
|
|||
sys.exit(0)
|
||||
elif o == "--grading":
|
||||
grading = optval.get_boolean_argument(a)
|
||||
__run__.include_metrics = grading
|
||||
__run__.list_file_types = grading
|
||||
__run__.responsibilities = grading
|
||||
__run__.grading = grading
|
||||
__run__.hard = grading
|
||||
__run__.timeline = grading
|
||||
__run__.useweeks = grading
|
||||
run.include_metrics = grading
|
||||
run.list_file_types = grading
|
||||
run.responsibilities = grading
|
||||
run.grading = grading
|
||||
run.hard = grading
|
||||
run.timeline = grading
|
||||
run.useweeks = grading
|
||||
elif o == "-T":
|
||||
__run__.timeline = True
|
||||
run.timeline = True
|
||||
elif o == "--timeline":
|
||||
__run__.timeline = optval.get_boolean_argument(a)
|
||||
run.timeline = optval.get_boolean_argument(a)
|
||||
elif o == "--until":
|
||||
interval.set_until(a)
|
||||
elif o == "-w":
|
||||
__run__.useweeks = True
|
||||
run.useweeks = True
|
||||
elif o == "--weeks":
|
||||
__run__.useweeks = optval.get_boolean_argument(a)
|
||||
run.useweeks = optval.get_boolean_argument(a)
|
||||
elif o in("-x", "--exclude"):
|
||||
if clear_x_on_next_pass:
|
||||
clear_x_on_next_pass = False
|
||||
|
@ -185,12 +203,16 @@ def main():
|
|||
filtering.add(a)
|
||||
|
||||
__check_python_version__()
|
||||
__run__.output()
|
||||
run.process(repos)
|
||||
|
||||
except (filtering.InvalidRegExpError, format.InvalidFormatError, optval.InvalidOptionArgument, getopt.error) as exception:
|
||||
print(sys.argv[0], "\b:", exception.msg, file=sys.stderr)
|
||||
print(_("Try `{0} --help' for more information.").format(sys.argv[0]), file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
@atexit.register
|
||||
def cleanup():
|
||||
clone.delete()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2013-2014 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -18,21 +18,23 @@
|
|||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import hashlib
|
||||
|
||||
try:
|
||||
from urllib.parse import urlencode
|
||||
except:
|
||||
from urllib import urlencode
|
||||
import format
|
||||
import hashlib
|
||||
|
||||
from . import format
|
||||
|
||||
def get_url(email, size=20):
|
||||
md5hash = hashlib.md5(email.encode("utf-8").lower().strip()).hexdigest()
|
||||
base_url = "http://www.gravatar.com/avatar/" + md5hash
|
||||
base_url = "https://www.gravatar.com/avatar/" + md5hash
|
||||
params = None
|
||||
|
||||
if format.get_selected() == "html":
|
||||
params = {"default": "identicon", "size": size}
|
||||
elif format.get_selected() == "xml":
|
||||
elif format.get_selected() == "xml" or format.get_selected() == "json":
|
||||
params = {"default": "identicon"}
|
||||
|
||||
return base_url + "?" + urlencode(params)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -19,22 +19,24 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from extensions import DEFAULT_EXTENSIONS
|
||||
from format import __available_formats__
|
||||
import sys
|
||||
from .extensions import DEFAULT_EXTENSIONS
|
||||
from .format import __available_formats__
|
||||
|
||||
__doc__ = _("""Usage: {0} [OPTION]... [DIRECTORY]
|
||||
List information about the repository in DIRECTORY. If no directory is
|
||||
specified, the current directory is used. If multiple directories are
|
||||
given, information will be fetched from the last directory specified.
|
||||
|
||||
__doc__ = _("""Usage: {0} [OPTION]... [REPOSITORY]...
|
||||
List information about the repository in REPOSITORY. If no repository is
|
||||
specified, the current directory is used. If multiple repositories are
|
||||
given, information will be merged into a unified statistical report.
|
||||
|
||||
Mandatory arguments to long options are mandatory for short options too.
|
||||
Boolean arguments can only be given to long options.
|
||||
-c, --checkout-missing[=BOOL] try to checkout any missing files
|
||||
-f, --file-types=EXTENSIONS a comma separated list of file extensions to
|
||||
include when computing statistics. The
|
||||
default extensions used are:
|
||||
{1}
|
||||
Specifying * includes files with no
|
||||
extension, while ** includes all files
|
||||
-F, --format=FORMAT define in which format output should be
|
||||
generated; the default format is 'text' and
|
||||
the available formats are:
|
||||
|
@ -61,9 +63,11 @@ Boolean arguments can only be given to long options.
|
|||
specific date
|
||||
-w, --weeks[=BOOL] show all statistical information in weeks
|
||||
instead of in months
|
||||
-x, --exclude=PATTERN an exclusion pattern describing file names
|
||||
that should be excluded from the statistics;
|
||||
can be specified multiple times
|
||||
-x, --exclude=PATTERN an exclusion pattern describing the file
|
||||
paths, revisions, revisions with certain
|
||||
commit messages, author names or author
|
||||
emails that should be excluded from the
|
||||
statistics; can be specified multiple times
|
||||
-h, --help display this help and exit
|
||||
--version output version information and exit
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 6.5 KiB |
|
@ -2,7 +2,7 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />
|
||||
<title>Generated by gitinspector {version}</title>
|
||||
<title>{title}</title>
|
||||
<script type="application/javascript"{jquery}</script>
|
||||
<script type="application/javascript">{jquery_tablesorter}</script>
|
||||
<script type="application/javascript">{jquery_flot}</script>
|
||||
|
@ -26,6 +26,10 @@
|
|||
}}
|
||||
}}
|
||||
|
||||
// Fix header and set it to the right width.
|
||||
var remainingHeaderWidth = ($("div.logo").width() - 4) - ($("div.logo img").innerWidth() + 48)
|
||||
$("div.logo p").css("width", remainingHeaderWidth);
|
||||
|
||||
var filterResponsibilities = function() {{
|
||||
$("table#blame tbody tr td:last-child").filter(function() {{
|
||||
return parseFloat(this.innerHTML) < MINOR_AUTHOR_PERCENTAGE;
|
||||
|
@ -82,15 +86,19 @@
|
|||
}}).each(function() {{
|
||||
$(this).addClass("hoverable");
|
||||
this.innerHTML = "{show_minor_authors} (" + this.hiddenCount + ") ∨";
|
||||
}}).toggle(function() {{
|
||||
this.innerHTML = "{hide_minor_authors} (" + this.hiddenCount + ") ∧";
|
||||
$(this).parent().parent().parent().find("tbody tr").show().each(colorRows);
|
||||
}}, function() {{
|
||||
this.innerHTML = "{show_minor_authors} (" + this.hiddenCount + ") ∨";
|
||||
$(this).parent().parent().parent().find("tbody tr td:last-child").filter(function() {{
|
||||
return parseFloat(this.innerHTML) < MINOR_AUTHOR_PERCENTAGE;
|
||||
}}).parent().hide();
|
||||
$("table.git tbody tr:visible").each(colorRows);
|
||||
}}).click(function() {{
|
||||
this.clicked = !this.clicked;
|
||||
|
||||
if (this.clicked) {{
|
||||
this.innerHTML = "{hide_minor_authors} (" + this.hiddenCount + ") ∧";
|
||||
$(this).parent().parent().parent().find("tbody tr").show().each(colorRows);
|
||||
}} else {{
|
||||
this.innerHTML = "{show_minor_authors} (" + this.hiddenCount + ") ∨";
|
||||
$(this).parent().parent().parent().find("tbody tr td:last-child").filter(function() {{
|
||||
return parseFloat(this.innerHTML) < MINOR_AUTHOR_PERCENTAGE;
|
||||
}}).parent().hide();
|
||||
$("table.git tbody tr:visible").each(colorRows);
|
||||
}}
|
||||
}});
|
||||
|
||||
filterResponsibilities();
|
||||
|
@ -99,12 +107,15 @@
|
|||
$("div#responsibilities div h3:visible").each(colorRows);
|
||||
$("div#responsibilities").prepend("<div class=\"button\">{show_minor_authors} (" + hiddenResponsibilitiesCount + ") ∨</div>");
|
||||
|
||||
$("div#responsibilities div.button").toggle(function() {{
|
||||
this.innerHTML = "{hide_minor_authors} (" + hiddenResponsibilitiesCount + ") ∧";
|
||||
$("div#responsibilities div").show();
|
||||
}}, function() {{
|
||||
this.innerHTML = "{show_minor_authors} (" + hiddenResponsibilitiesCount + ") ∨";
|
||||
filterResponsibilities();
|
||||
$("div#responsibilities div.button").click(function() {{
|
||||
this.clicked = !this.clicked;
|
||||
if (this.clicked) {{
|
||||
this.innerHTML = "{hide_minor_authors} (" + hiddenResponsibilitiesCount + ") ∧";
|
||||
$("div#responsibilities div").show();
|
||||
}} else {{
|
||||
this.innerHTML = "{show_minor_authors} (" + hiddenResponsibilitiesCount + ") ∨";
|
||||
filterResponsibilities();
|
||||
}}
|
||||
}});
|
||||
}}
|
||||
|
||||
|
@ -115,13 +126,16 @@
|
|||
$("div#timeline table.git tbody tr:visible").each(colorRows);
|
||||
$("div#timeline").prepend("<div class=\"button\">{show_minor_rows} (" + hiddenTimelineCount + ") ∨</div>");
|
||||
|
||||
$("div#timeline div.button").toggle(function() {{
|
||||
this.innerHTML = "{hide_minor_rows} (" + hiddenTimelineCount + ") ∧";
|
||||
$("div#timeline table.git tbody tr").show().each(colorRows);
|
||||
}}, function() {{
|
||||
this.innerHTML = "{show_minor_rows} (" + hiddenTimelineCount + ") ∨";
|
||||
filterTimeLine();
|
||||
$("div#timeline table.git tbody tr:visible").each(colorRows);
|
||||
$("div#timeline div.button").click(function() {{
|
||||
this.clicked = !this.clicked;
|
||||
if (this.clicked) {{
|
||||
this.innerHTML = "{hide_minor_rows} (" + hiddenTimelineCount + ") ∧";
|
||||
$("div#timeline table.git tbody tr").show().each(colorRows);
|
||||
}} else {{
|
||||
this.innerHTML = "{show_minor_rows} (" + hiddenTimelineCount + ") ∨";
|
||||
filterTimeLine();
|
||||
$("div#timeline table.git tbody tr:visible").each(colorRows);
|
||||
}}
|
||||
}});
|
||||
}}
|
||||
|
||||
|
@ -142,6 +156,52 @@
|
|||
this.hoveredElement.removeClass("piehover");
|
||||
}}
|
||||
}});
|
||||
|
||||
// Make sure the two pie charts use the same colors.
|
||||
|
||||
var author_colors = {{}};
|
||||
$.each(changes_plot.getData(), function(i, v) {{
|
||||
author_colors[v["label"]] = v["color"];
|
||||
}});
|
||||
|
||||
$.each(blame_plot.getData(), function(i, v) {{
|
||||
if (author_colors[v["label"]] != undefined) {{
|
||||
v["color"] = author_colors[v["label"]];
|
||||
}}
|
||||
}});
|
||||
|
||||
blame_plot.setupGrid();
|
||||
blame_plot.draw();
|
||||
|
||||
// Color in metrics levels.
|
||||
|
||||
$("div#metrics div div").each(function() {{
|
||||
var rgb = $(this).css("background-color").match(/\d+/g);
|
||||
rgb[0] = parseInt(rgb[0]);
|
||||
rgb[1] = parseInt(rgb[1]);
|
||||
rgb[2] = parseInt(rgb[2]);
|
||||
|
||||
if ($(this).hasClass("minimal")) {{
|
||||
rgb[0] -= 10;
|
||||
rgb[1] += 10;
|
||||
rgb[2] -= 10;
|
||||
}} else if ($(this).hasClass("minor")) {{
|
||||
rgb[1] += 10;
|
||||
}} else if ($(this).hasClass("medium")) {{
|
||||
rgb[0] += 10;
|
||||
rgb[1] += 10;
|
||||
}} else if ($(this).hasClass("bad")) {{
|
||||
rgb[0] += 10;
|
||||
rgb[1] -= 10;
|
||||
rgb[2] -= 10;
|
||||
}} else if ($(this).hasClass("severe")) {{
|
||||
rgb[0] += 20;
|
||||
rgb[1] -= 20;
|
||||
rgb[2] -= 20;
|
||||
}}
|
||||
|
||||
$(this).css("background-color", "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")");
|
||||
}});
|
||||
}});
|
||||
</script>
|
||||
<style type="text/css">
|
||||
|
@ -151,7 +211,6 @@
|
|||
}}
|
||||
html, body {{
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-family: "Arial";
|
||||
}}
|
||||
body > div {{
|
||||
|
@ -170,10 +229,12 @@
|
|||
-moz-box-shadow: 1px 1px 3px #666;
|
||||
}}
|
||||
div.logo p {{
|
||||
margin-top: 18px;
|
||||
width: 60em;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
}}
|
||||
div.logo img {{
|
||||
float: left;
|
||||
vertical-align:middle;
|
||||
padding: 2px 10px 2px 2px;
|
||||
}}
|
||||
body > div {{
|
||||
|
@ -247,12 +308,15 @@
|
|||
border: 1px solid #bbb;
|
||||
cursor: hand;
|
||||
}}
|
||||
div#responsibilities div, div#responsibilities div div {{
|
||||
div#responsibilities div, div#responsibilities div div, div#metrics div, div#metrics div div {{
|
||||
min-height: 0px;
|
||||
padding: 0.5em 0.2em;
|
||||
width: auto;
|
||||
}}
|
||||
div#responsibilities div.odd {{
|
||||
div#metrics div {{
|
||||
background-color: #eee;
|
||||
}}
|
||||
div#responsibilities div.odd, div#metrics div.odd {{
|
||||
background-color: #dbdbdb;
|
||||
}}
|
||||
div#responsibilities p {{
|
||||
|
@ -273,13 +337,17 @@
|
|||
width: 32px;
|
||||
height: 32px;
|
||||
}}
|
||||
h3 {{
|
||||
h3, h4 {{
|
||||
border-radius: 8px 8px 8px 8px;
|
||||
-moz-border-radius: 8px 8px 8px 8px;
|
||||
background-color: #ddcece;
|
||||
margin-bottom: 0.2em;
|
||||
margin-top: 0.6em;
|
||||
}}
|
||||
h4 {{
|
||||
margin-top: 0.2em;
|
||||
padding: 0.5em;
|
||||
}}
|
||||
div.button, div#responsibilities div.button {{
|
||||
border-radius: 8px 8px 8px 8px;
|
||||
-moz-border-radius: 8px 8px 8px 8px;
|
||||
|
@ -294,6 +362,6 @@
|
|||
</head>
|
||||
<body>
|
||||
<div><div class="box logo">
|
||||
<img src="data:image/png;base64,{logo}" />
|
||||
<p>{logo_text}<p>
|
||||
<a href="https://github.com/ejwa/gitinspector"><img src="data:image/png;base64,{logo}" /></a>
|
||||
<p>{repo_text}<br>{logo_text}</p>
|
||||
</div></div>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -20,6 +19,11 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
try:
|
||||
from shlex import quote
|
||||
except ImportError:
|
||||
from pipes import quote
|
||||
|
||||
__since__ = ""
|
||||
|
||||
__until__ = ""
|
||||
|
@ -34,14 +38,14 @@ def get_since():
|
|||
|
||||
def set_since(since):
|
||||
global __since__
|
||||
__since__ = "--since=\"" + since + "\" "
|
||||
__since__ = "--since=" + quote(since)
|
||||
|
||||
def get_until():
|
||||
return __until__
|
||||
|
||||
def set_until(until):
|
||||
global __until__
|
||||
__until__ = "--until=\"" + until + "\" "
|
||||
__until__ = "--until=" + quote(until)
|
||||
|
||||
def get_ref():
|
||||
return __ref__
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2013-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -18,12 +17,17 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import basedir
|
||||
import gettext
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from . import basedir
|
||||
|
||||
__enabled__ = False
|
||||
__installed__ = False
|
||||
__translation__ = None
|
||||
|
||||
|
@ -32,6 +36,7 @@ def N_(message):
|
|||
return message
|
||||
|
||||
def init():
|
||||
global __enabled__
|
||||
global __installed__
|
||||
global __translation__
|
||||
|
||||
|
@ -46,22 +51,56 @@ def init():
|
|||
#Fix for non-POSIX-compliant systems (Windows et al.).
|
||||
if os.getenv('LANG') is None:
|
||||
lang = locale.getdefaultlocale()
|
||||
os.environ['LANG'] = lang[0]
|
||||
|
||||
filename = basedir.get_basedir() + "/translations/messages_%s.mo" % lang[0][0:2]
|
||||
if lang[0]:
|
||||
os.environ['LANG'] = lang[0]
|
||||
|
||||
try:
|
||||
__translation__ = gettext.GNUTranslations(open(filename, "rb"))
|
||||
except IOError:
|
||||
if lang[0] is not None:
|
||||
filename = basedir.get_basedir() + "/translations/messages_%s.mo" % lang[0][0:2]
|
||||
|
||||
try:
|
||||
__translation__ = gettext.GNUTranslations(open(filename, "rb"))
|
||||
except IOError:
|
||||
__translation__ = gettext.NullTranslations()
|
||||
else:
|
||||
print("WARNING: Localization disabled because the system language could not be determined.", file=sys.stderr)
|
||||
__translation__ = gettext.NullTranslations()
|
||||
|
||||
__enabled__ = True
|
||||
__installed__ = True
|
||||
__translation__.install(True)
|
||||
|
||||
def check_compatibility(version):
|
||||
if isinstance(__translation__, gettext.GNUTranslations):
|
||||
header_pattern = re.compile("^([^:\n]+): *(.*?) *$", re.MULTILINE)
|
||||
header_entries = dict(header_pattern.findall(_("")))
|
||||
|
||||
if header_entries["Project-Id-Version"] != "gitinspector {0}".format(version):
|
||||
print("WARNING: The translation for your system locale is not up to date with the current gitinspector "
|
||||
"version. The current maintainer of this locale is {0}.".format(header_entries["Last-Translator"]),
|
||||
file=sys.stderr)
|
||||
|
||||
def get_date():
|
||||
if __enabled__ and isinstance(__translation__, gettext.GNUTranslations):
|
||||
date = time.strftime("%x")
|
||||
|
||||
if hasattr(date, 'decode'):
|
||||
date = date.decode("utf-8", "replace")
|
||||
|
||||
return date
|
||||
else:
|
||||
return time.strftime("%Y/%m/%d")
|
||||
|
||||
def enable():
|
||||
if __installed__ and type(__translation__) is not gettext.GNUTranslations:
|
||||
if isinstance(__translation__, gettext.GNUTranslations):
|
||||
__translation__.install(True)
|
||||
|
||||
global __enabled__
|
||||
__enabled__ = True
|
||||
|
||||
def disable():
|
||||
global __enabled__
|
||||
__enabled__ = False
|
||||
|
||||
if __installed__:
|
||||
gettext.NullTranslations().install(True)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2017 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -17,94 +17,109 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
from changes import FileDiff
|
||||
import comment
|
||||
import filtering
|
||||
import interval
|
||||
import missing
|
||||
import re
|
||||
import subprocess
|
||||
from .changes import FileDiff
|
||||
from . import comment, filtering, interval
|
||||
|
||||
__metric_eloc__ = {"java": 500, "c": 500, "cpp": 500, "h": 300, "hpp": 300, "php": 500, "py": 500, "glsl": 1000,
|
||||
__metric_eloc__ = {"java": 500, "c": 500, "cpp": 500, "cs": 500, "h": 300, "hpp": 300, "php": 500, "py": 500, "glsl": 1000,
|
||||
"rb": 500, "js": 500, "sql": 1000, "xml": 1000}
|
||||
|
||||
class MetricsLogic:
|
||||
__metric_cc_tokens__ = [[["java", "js", "c", "cc", "cpp"], ["else", r"for\s+\(.*\)", r"if\s+\(.*\)", r"case\s+\w+:",
|
||||
"default:", r"while\s+\(.*\)"],
|
||||
["assert", "break", "continue", "return"]],
|
||||
[["cs"], ["else", r"for\s+\(.*\)", r"foreach\s+\(.*\)", r"goto\s+\w+:", r"if\s+\(.*\)", r"case\s+\w+:",
|
||||
"default:", r"while\s+\(.*\)"],
|
||||
["assert", "break", "continue", "return"]],
|
||||
[["py"], [r"^\s+elif .*:$", r"^\s+else:$", r"^\s+for .*:", r"^\s+if .*:$", r"^\s+while .*:$"],
|
||||
[r"^\s+assert", "break", "continue", "return"]]]
|
||||
|
||||
METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD = 50
|
||||
METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD = 0.75
|
||||
|
||||
class MetricsLogic(object):
|
||||
def __init__(self):
|
||||
self.eloc = {}
|
||||
ls_tree_r = subprocess.Popen("git ls-tree --name-only -r " + interval.get_ref(), shell=True, bufsize=1,
|
||||
stdout=subprocess.PIPE).stdout
|
||||
self.cyclomatic_complexity = {}
|
||||
self.cyclomatic_complexity_density = {}
|
||||
|
||||
for i in ls_tree_r.readlines():
|
||||
i = i.strip().decode("unicode_escape", "ignore")
|
||||
i = i.encode("latin-1", "replace")
|
||||
i = i.decode("utf-8", "replace").strip("\"").strip("'").strip()
|
||||
ls_tree_p = subprocess.Popen(["git", "ls-tree", "--name-only", "-r", interval.get_ref()], bufsize=1,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
lines = ls_tree_p.communicate()[0].splitlines()
|
||||
ls_tree_p.stdout.close()
|
||||
|
||||
if ls_tree_p.returncode == 0:
|
||||
for i in lines:
|
||||
i = i.strip().decode("unicode_escape", "ignore")
|
||||
i = i.encode("latin-1", "replace")
|
||||
i = i.decode("utf-8", "replace").strip("\"").strip("'").strip()
|
||||
|
||||
if FileDiff.is_valid_extension(i) and not filtering.set_filtered(FileDiff.get_filename(i)):
|
||||
file_r = subprocess.Popen(["git", "show", interval.get_ref() + ":{0}".format(i.strip())],
|
||||
bufsize=1, stdout=subprocess.PIPE).stdout.readlines()
|
||||
|
||||
if FileDiff.is_valid_extension(i) and not filtering.set_filtered(FileDiff.get_filename(i)):
|
||||
if not missing.add(i):
|
||||
file_r = open(i.strip(), "rb")
|
||||
extension = FileDiff.get_extension(i)
|
||||
lines = MetricsLogic.get_eloc(file_r, extension)
|
||||
cycc = MetricsLogic.get_cyclomatic_complexity(file_r, extension)
|
||||
|
||||
if __metric_eloc__.get(extension, None) != None and __metric_eloc__[extension] < lines:
|
||||
self.eloc[i.strip()] = lines
|
||||
|
||||
if METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD < cycc:
|
||||
self.cyclomatic_complexity[i.strip()] = cycc
|
||||
|
||||
if lines > 0 and METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD < cycc / float(lines):
|
||||
self.cyclomatic_complexity_density[i.strip()] = cycc / float(lines)
|
||||
|
||||
def __iadd__(self, other):
|
||||
try:
|
||||
self.eloc.update(other.eloc)
|
||||
self.cyclomatic_complexity.update(other.cyclomatic_complexity)
|
||||
self.cyclomatic_complexity_density.update(other.cyclomatic_complexity_density)
|
||||
return self
|
||||
except AttributeError:
|
||||
return other;
|
||||
|
||||
@staticmethod
|
||||
def get_cyclomatic_complexity(file_r, extension):
|
||||
is_inside_comment = False
|
||||
cc_counter = 0
|
||||
|
||||
entry_tokens = None
|
||||
exit_tokens = None
|
||||
|
||||
for i in __metric_cc_tokens__:
|
||||
if extension in i[0]:
|
||||
entry_tokens = i[1]
|
||||
exit_tokens = i[2]
|
||||
|
||||
if entry_tokens or exit_tokens:
|
||||
for i in file_r:
|
||||
i = i.decode("utf-8", "replace")
|
||||
(_, is_inside_comment) = comment.handle_comment_block(is_inside_comment, extension, i)
|
||||
|
||||
if not is_inside_comment and not comment.is_comment(extension, i):
|
||||
for j in entry_tokens:
|
||||
if re.search(j, i, re.DOTALL):
|
||||
cc_counter += 2
|
||||
for j in exit_tokens:
|
||||
if re.search(j, i, re.DOTALL):
|
||||
cc_counter += 1
|
||||
return cc_counter
|
||||
|
||||
return -1
|
||||
|
||||
@staticmethod
|
||||
def get_eloc(file_r, extension):
|
||||
is_inside_comment = False
|
||||
eloc_counter = 0
|
||||
|
||||
for j in file_r.readlines():
|
||||
j = j.decode("utf-8", "replace")
|
||||
(_, is_inside_comment) = comment.handle_comment_block(is_inside_comment, extension, j)
|
||||
for i in file_r:
|
||||
i = i.decode("utf-8", "replace")
|
||||
(_, is_inside_comment) = comment.handle_comment_block(is_inside_comment, extension, i)
|
||||
|
||||
if not is_inside_comment and not comment.is_comment(extension, j):
|
||||
if not is_inside_comment and not comment.is_comment(extension, i):
|
||||
eloc_counter += 1
|
||||
|
||||
return eloc_counter
|
||||
|
||||
ELOC_INFO_TEXT = N_("The following files are suspiciously big (in order of severity)")
|
||||
METRICS_MISSING_INFO_TEXT = N_("No metrics violations were found in the repository")
|
||||
|
||||
class Metrics(Outputable):
|
||||
def output_text(self):
|
||||
metrics_logic = MetricsLogic()
|
||||
|
||||
if not metrics_logic.eloc:
|
||||
print("\n" + _(METRICS_MISSING_INFO_TEXT) + ".")
|
||||
else:
|
||||
print("\n" + _(ELOC_INFO_TEXT) + ":")
|
||||
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse = True):
|
||||
print(i[1] + " (" + str(i[0]) + " eloc)")
|
||||
|
||||
def output_html(self):
|
||||
metrics_logic = MetricsLogic()
|
||||
metrics_xml = "<div><div class=\"box\">"
|
||||
|
||||
if not metrics_logic.eloc:
|
||||
metrics_xml += "<p>" + _(METRICS_MISSING_INFO_TEXT) + ".</p>"
|
||||
else:
|
||||
metrics_xml += "<p>" + _(ELOC_INFO_TEXT) + ".</p>"
|
||||
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse = True):
|
||||
metrics_xml += "<p>" + i[1] + " (" + str(i[0]) + " eloc)</p>"
|
||||
|
||||
metrics_xml += "</div></div>"
|
||||
print(metrics_xml)
|
||||
|
||||
def output_xml(self):
|
||||
metrics_logic = MetricsLogic()
|
||||
|
||||
if not metrics_logic.eloc:
|
||||
print("\t<metrics>\n\t\t<message>" + _(METRICS_MISSING_INFO_TEXT) + "</message>\n\t</metrics>")
|
||||
else:
|
||||
eloc_xml = ""
|
||||
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse = True):
|
||||
eloc_xml += "\t\t\t\t\t<violation>\n"
|
||||
eloc_xml += "\t\t\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
|
||||
eloc_xml += "\t\t\t\t\t\t<lines-of-code>" + str(i[0]) + "</lines-of-code>\n"
|
||||
eloc_xml += "\t\t\t\t\t</violation>\n"
|
||||
|
||||
print("\t\t<metrics>\n\t\t\t<eloc>\n\t\t\t\t<message>" + _(ELOC_INFO_TEXT) +
|
||||
"</message>\n\t\t\t\t<violations>\n" + eloc_xml + "\t\t\t\t</violations>\n\t\t\t</eloc>\n\t\t</metrics>")
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
import interval
|
||||
import os
|
||||
import subprocess
|
||||
import terminal
|
||||
import textwrap
|
||||
|
||||
__checkout_missing__ = False
|
||||
__missing_files__ = set()
|
||||
|
||||
def add(file_name):
|
||||
if not interval.has_interval() and not os.path.exists(file_name):
|
||||
if __checkout_missing__:
|
||||
subprocess.call("git checkout \"" + file_name.strip() + "\"", shell=True)
|
||||
else:
|
||||
__missing_files__.add(file_name)
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_checkout_missing(checkout):
|
||||
global __checkout_missing__
|
||||
__checkout_missing__ = checkout
|
||||
|
||||
MISSING_INFO_TEXT = N_("The following files were missing in the repository and were therefore not "
|
||||
"completely included in the statistical analysis. To include them, you can "
|
||||
"either checkout manually using git or use the -c option in gitinspector")
|
||||
|
||||
class Missing(Outputable):
|
||||
def output_html(self):
|
||||
if __missing_files__:
|
||||
missing_xml = "<div><div class=\"box\">"
|
||||
missing_xml += "<p>" + _(MISSING_INFO_TEXT) + ".</p>"
|
||||
|
||||
for missing in __missing_files__:
|
||||
missing_xml += "<p class=\"error\">" + missing + "</p>"
|
||||
|
||||
missing_xml += "</div></div>"
|
||||
print(missing_xml)
|
||||
|
||||
def output_text(self):
|
||||
if __missing_files__:
|
||||
print("\n" + textwrap.fill(_(MISSING_INFO_TEXT) + ":", width=terminal.get_size()[0]))
|
||||
|
||||
for missing in __missing_files__:
|
||||
(width, _unused) = terminal.get_size()
|
||||
print("...%s" % missing[-width+3:] if len(missing) > width else missing)
|
||||
|
||||
def output_xml(self):
|
||||
if __missing_files__:
|
||||
message_xml = "\t\t<message>" + _(MISSING_INFO_TEXT) + "</message>\n"
|
||||
missing_xml = ""
|
||||
|
||||
for missing in __missing_files__:
|
||||
missing_xml += "\t\t\t<file>" + missing + "</file>\n"
|
||||
|
||||
print("\t<missing>\n" + message_xml + "\t\t<files>\n" + missing_xml + "\t\t</files>\n\t</missing>")
|
|
@ -15,6 +15,7 @@
|
|||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import getopt
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2013 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This file was intentionally left blank.
|
|
@ -0,0 +1,154 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
import sys
|
||||
import textwrap
|
||||
from ..localization import N_
|
||||
from .. import format, gravatar, terminal
|
||||
from ..blame import Blame
|
||||
from .outputable import Outputable
|
||||
|
||||
BLAME_INFO_TEXT = N_("Below are the number of rows from each author that have survived and are still "
|
||||
"intact in the current revision")
|
||||
|
||||
class BlameOutput(Outputable):
|
||||
def __init__(self, changes, blame):
|
||||
if format.is_interactive_format():
|
||||
print("")
|
||||
|
||||
self.changes = changes
|
||||
self.blame = blame
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_html(self):
|
||||
blame_xml = "<div><div class=\"box\">"
|
||||
blame_xml += "<p>" + _(BLAME_INFO_TEXT) + ".</p><div><table id=\"blame\" class=\"git\">"
|
||||
blame_xml += "<thead><tr> <th>{0}</th> <th>{1}</th> <th>{2}</th> <th>{3}</th> <th>{4}</th> </tr></thead>".format(
|
||||
_("Author"), _("Rows"), _("Stability"), _("Age"), _("% in comments"))
|
||||
blame_xml += "<tbody>"
|
||||
chart_data = ""
|
||||
blames = sorted(self.blame.get_summed_blames().items())
|
||||
total_blames = 0
|
||||
|
||||
for i in blames:
|
||||
total_blames += i[1].rows
|
||||
|
||||
for i, entry in enumerate(blames):
|
||||
work_percentage = str("{0:.2f}".format(100.0 * entry[1].rows / total_blames))
|
||||
blame_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
||||
|
||||
if format.get_selected() == "html":
|
||||
author_email = self.changes.get_latest_email_by_author(entry[0])
|
||||
blame_xml += "<td><img src=\"{0}\"/>{1}</td>".format(gravatar.get_url(author_email), entry[0])
|
||||
else:
|
||||
blame_xml += "<td>" + entry[0] + "</td>"
|
||||
|
||||
blame_xml += "<td>" + str(entry[1].rows) + "</td>"
|
||||
blame_xml += "<td>" + ("{0:.1f}".format(Blame.get_stability(entry[0], entry[1].rows, self.changes)) + "</td>")
|
||||
blame_xml += "<td>" + "{0:.1f}".format(float(entry[1].skew) / entry[1].rows) + "</td>"
|
||||
blame_xml += "<td>" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "</td>"
|
||||
blame_xml += "<td style=\"display: none\">" + work_percentage + "</td>"
|
||||
blame_xml += "</tr>"
|
||||
chart_data += "{{label: {0}, data: {1}}}".format(json.dumps(entry[0]), work_percentage)
|
||||
|
||||
if blames[-1] != entry:
|
||||
chart_data += ", "
|
||||
|
||||
blame_xml += "<tfoot><tr> <td colspan=\"5\"> </td> </tr></tfoot></tbody></table>"
|
||||
blame_xml += "<div class=\"chart\" id=\"blame_chart\"></div></div>"
|
||||
blame_xml += "<script type=\"text/javascript\">"
|
||||
blame_xml += " blame_plot = $.plot($(\"#blame_chart\"), [{0}], {{".format(chart_data)
|
||||
blame_xml += " series: {"
|
||||
blame_xml += " pie: {"
|
||||
blame_xml += " innerRadius: 0.4,"
|
||||
blame_xml += " show: true,"
|
||||
blame_xml += " combine: {"
|
||||
blame_xml += " threshold: 0.01,"
|
||||
blame_xml += " label: \"" + _("Minor Authors") + "\""
|
||||
blame_xml += " }"
|
||||
blame_xml += " }"
|
||||
blame_xml += " }, grid: {"
|
||||
blame_xml += " hoverable: true"
|
||||
blame_xml += " }"
|
||||
blame_xml += " });"
|
||||
blame_xml += "</script></div></div>"
|
||||
|
||||
print(blame_xml)
|
||||
|
||||
def output_json(self):
|
||||
message_json = "\t\t\t\"message\": \"" + _(BLAME_INFO_TEXT) + "\",\n"
|
||||
blame_json = ""
|
||||
|
||||
for i in sorted(self.blame.get_summed_blames().items()):
|
||||
author_email = self.changes.get_latest_email_by_author(i[0])
|
||||
|
||||
name_json = "\t\t\t\t\"name\": \"" + i[0] + "\",\n"
|
||||
email_json = "\t\t\t\t\"email\": \"" + author_email + "\",\n"
|
||||
gravatar_json = "\t\t\t\t\"gravatar\": \"" + gravatar.get_url(author_email) + "\",\n"
|
||||
rows_json = "\t\t\t\t\"rows\": " + str(i[1].rows) + ",\n"
|
||||
stability_json = ("\t\t\t\t\"stability\": " + "{0:.1f}".format(Blame.get_stability(i[0], i[1].rows,
|
||||
self.changes)) + ",\n")
|
||||
age_json = ("\t\t\t\t\"age\": " + "{0:.1f}".format(float(i[1].skew) / i[1].rows) + ",\n")
|
||||
percentage_in_comments_json = ("\t\t\t\t\"percentage_in_comments\": " +
|
||||
"{0:.2f}".format(100.0 * i[1].comments / i[1].rows) + "\n")
|
||||
blame_json += ("{\n" + name_json + email_json + gravatar_json + rows_json + stability_json + age_json +
|
||||
percentage_in_comments_json + "\t\t\t},")
|
||||
else:
|
||||
blame_json = blame_json[:-1]
|
||||
|
||||
print(",\n\t\t\"blame\": {\n" + message_json + "\t\t\t\"authors\": [\n\t\t\t" + blame_json + "]\n\t\t}", end="")
|
||||
|
||||
def output_text(self):
|
||||
if sys.stdout.isatty() and format.is_interactive_format():
|
||||
terminal.clear_row()
|
||||
|
||||
print(textwrap.fill(_(BLAME_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n")
|
||||
terminal.printb(terminal.ljust(_("Author"), 21) + terminal.rjust(_("Rows"), 10) + terminal.rjust(_("Stability"), 15) +
|
||||
terminal.rjust(_("Age"), 13) + terminal.rjust(_("% in comments"), 20))
|
||||
|
||||
for i in sorted(self.blame.get_summed_blames().items()):
|
||||
print(terminal.ljust(i[0], 20)[0:20 - terminal.get_excess_column_count(i[0])], end=" ")
|
||||
print(str(i[1].rows).rjust(10), end=" ")
|
||||
print("{0:.1f}".format(Blame.get_stability(i[0], i[1].rows, self.changes)).rjust(14), end=" ")
|
||||
print("{0:.1f}".format(float(i[1].skew) / i[1].rows).rjust(12), end=" ")
|
||||
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(19))
|
||||
|
||||
def output_xml(self):
|
||||
message_xml = "\t\t<message>" + _(BLAME_INFO_TEXT) + "</message>\n"
|
||||
blame_xml = ""
|
||||
|
||||
for i in sorted(self.blame.get_summed_blames().items()):
|
||||
author_email = self.changes.get_latest_email_by_author(i[0])
|
||||
|
||||
name_xml = "\t\t\t\t<name>" + i[0] + "</name>\n"
|
||||
email_xml = "\t\t\t\t<email>" + author_email + "</email>\n"
|
||||
gravatar_xml = "\t\t\t\t<gravatar>" + gravatar.get_url(author_email) + "</gravatar>\n"
|
||||
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
|
||||
stability_xml = ("\t\t\t\t<stability>" + "{0:.1f}".format(Blame.get_stability(i[0], i[1].rows,
|
||||
self.changes)) + "</stability>\n")
|
||||
age_xml = ("\t\t\t\t<age>" + "{0:.1f}".format(float(i[1].skew) / i[1].rows) + "</age>\n")
|
||||
percentage_in_comments_xml = ("\t\t\t\t<percentage-in-comments>" + "{0:.2f}".format(100.0 * i[1].comments / i[1].rows) +
|
||||
"</percentage-in-comments>\n")
|
||||
blame_xml += ("\t\t\t<author>\n" + name_xml + email_xml + gravatar_xml + rows_xml + stability_xml +
|
||||
age_xml + percentage_in_comments_xml + "\t\t\t</author>\n")
|
||||
|
||||
print("\t<blame>\n" + message_xml + "\t\t<authors>\n" + blame_xml + "\t\t</authors>\n\t</blame>")
|
|
@ -0,0 +1,189 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
import textwrap
|
||||
from ..localization import N_
|
||||
from .. import format, gravatar, terminal
|
||||
from .outputable import Outputable
|
||||
|
||||
HISTORICAL_INFO_TEXT = N_("The following historical commit information, by author, was found")
|
||||
NO_COMMITED_FILES_TEXT = N_("No commited files with the specified extensions were found")
|
||||
|
||||
class ChangesOutput(Outputable):
|
||||
def __init__(self, changes):
|
||||
self.changes = changes
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_html(self):
|
||||
authorinfo_list = self.changes.get_authorinfo_list()
|
||||
total_changes = 0.0
|
||||
changes_xml = "<div><div class=\"box\">"
|
||||
chart_data = ""
|
||||
|
||||
for i in authorinfo_list:
|
||||
total_changes += authorinfo_list.get(i).insertions
|
||||
total_changes += authorinfo_list.get(i).deletions
|
||||
|
||||
if authorinfo_list:
|
||||
changes_xml += "<p>" + _(HISTORICAL_INFO_TEXT) + ".</p><div><table id=\"changes\" class=\"git\">"
|
||||
changes_xml += "<thead><tr> <th>{0}</th> <th>{1}</th> <th>{2}</th> <th>{3}</th> <th>{4}</th>".format(
|
||||
_("Author"), _("Commits"), _("Insertions"), _("Deletions"), _("% of changes"))
|
||||
changes_xml += "</tr></thead><tbody>"
|
||||
|
||||
for i, entry in enumerate(sorted(authorinfo_list)):
|
||||
authorinfo = authorinfo_list.get(entry)
|
||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||
|
||||
changes_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
||||
|
||||
if format.get_selected() == "html":
|
||||
changes_xml += "<td><img src=\"{0}\"/>{1}</td>".format(
|
||||
gravatar.get_url(self.changes.get_latest_email_by_author(entry)), entry)
|
||||
else:
|
||||
changes_xml += "<td>" + entry + "</td>"
|
||||
|
||||
changes_xml += "<td>" + str(authorinfo.commits) + "</td>"
|
||||
changes_xml += "<td>" + str(authorinfo.insertions) + "</td>"
|
||||
changes_xml += "<td>" + str(authorinfo.deletions) + "</td>"
|
||||
changes_xml += "<td>" + "{0:.2f}".format(percentage) + "</td>"
|
||||
changes_xml += "</tr>"
|
||||
chart_data += "{{label: {0}, data: {1}}}".format(json.dumps(entry), "{0:.2f}".format(percentage))
|
||||
|
||||
if sorted(authorinfo_list)[-1] != entry:
|
||||
chart_data += ", "
|
||||
|
||||
changes_xml += ("<tfoot><tr> <td colspan=\"5\"> </td> </tr></tfoot></tbody></table>")
|
||||
changes_xml += "<div class=\"chart\" id=\"changes_chart\"></div></div>"
|
||||
changes_xml += "<script type=\"text/javascript\">"
|
||||
changes_xml += " changes_plot = $.plot($(\"#changes_chart\"), [{0}], {{".format(chart_data)
|
||||
changes_xml += " series: {"
|
||||
changes_xml += " pie: {"
|
||||
changes_xml += " innerRadius: 0.4,"
|
||||
changes_xml += " show: true,"
|
||||
changes_xml += " combine: {"
|
||||
changes_xml += " threshold: 0.01,"
|
||||
changes_xml += " label: \"" + _("Minor Authors") + "\""
|
||||
changes_xml += " }"
|
||||
changes_xml += " }"
|
||||
changes_xml += " }, grid: {"
|
||||
changes_xml += " hoverable: true"
|
||||
changes_xml += " }"
|
||||
changes_xml += " });"
|
||||
changes_xml += "</script>"
|
||||
else:
|
||||
changes_xml += "<p>" + _(NO_COMMITED_FILES_TEXT) + ".</p>"
|
||||
|
||||
changes_xml += "</div></div>"
|
||||
print(changes_xml)
|
||||
|
||||
def output_json(self):
|
||||
authorinfo_list = self.changes.get_authorinfo_list()
|
||||
total_changes = 0.0
|
||||
|
||||
for i in authorinfo_list:
|
||||
total_changes += authorinfo_list.get(i).insertions
|
||||
total_changes += authorinfo_list.get(i).deletions
|
||||
|
||||
if authorinfo_list:
|
||||
message_json = "\t\t\t\"message\": \"" + _(HISTORICAL_INFO_TEXT) + "\",\n"
|
||||
changes_json = ""
|
||||
|
||||
for i in sorted(authorinfo_list):
|
||||
author_email = self.changes.get_latest_email_by_author(i)
|
||||
authorinfo = authorinfo_list.get(i)
|
||||
|
||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||
name_json = "\t\t\t\t\"name\": \"" + i + "\",\n"
|
||||
email_json = "\t\t\t\t\"email\": \"" + author_email + "\",\n"
|
||||
gravatar_json = "\t\t\t\t\"gravatar\": \"" + gravatar.get_url(author_email) + "\",\n"
|
||||
commits_json = "\t\t\t\t\"commits\": " + str(authorinfo.commits) + ",\n"
|
||||
insertions_json = "\t\t\t\t\"insertions\": " + str(authorinfo.insertions) + ",\n"
|
||||
deletions_json = "\t\t\t\t\"deletions\": " + str(authorinfo.deletions) + ",\n"
|
||||
percentage_json = "\t\t\t\t\"percentage_of_changes\": " + "{0:.2f}".format(percentage) + "\n"
|
||||
|
||||
changes_json += ("{\n" + name_json + email_json + gravatar_json + commits_json +
|
||||
insertions_json + deletions_json + percentage_json + "\t\t\t}")
|
||||
changes_json += ","
|
||||
else:
|
||||
changes_json = changes_json[:-1]
|
||||
|
||||
print("\t\t\"changes\": {\n" + message_json + "\t\t\t\"authors\": [\n\t\t\t" + changes_json + "]\n\t\t}", end="")
|
||||
else:
|
||||
print("\t\t\"exception\": \"" + _(NO_COMMITED_FILES_TEXT) + "\"")
|
||||
|
||||
def output_text(self):
|
||||
authorinfo_list = self.changes.get_authorinfo_list()
|
||||
total_changes = 0.0
|
||||
|
||||
for i in authorinfo_list:
|
||||
total_changes += authorinfo_list.get(i).insertions
|
||||
total_changes += authorinfo_list.get(i).deletions
|
||||
|
||||
if authorinfo_list:
|
||||
print(textwrap.fill(_(HISTORICAL_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n")
|
||||
terminal.printb(terminal.ljust(_("Author"), 21) + terminal.rjust(_("Commits"), 13) +
|
||||
terminal.rjust(_("Insertions"), 14) + terminal.rjust(_("Deletions"), 15) +
|
||||
terminal.rjust(_("% of changes"), 16))
|
||||
|
||||
for i in sorted(authorinfo_list):
|
||||
authorinfo = authorinfo_list.get(i)
|
||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||
|
||||
print(terminal.ljust(i, 20)[0:20 - terminal.get_excess_column_count(i)], end=" ")
|
||||
print(str(authorinfo.commits).rjust(13), end=" ")
|
||||
print(str(authorinfo.insertions).rjust(13), end=" ")
|
||||
print(str(authorinfo.deletions).rjust(14), end=" ")
|
||||
print("{0:.2f}".format(percentage).rjust(15))
|
||||
else:
|
||||
print(_(NO_COMMITED_FILES_TEXT) + ".")
|
||||
|
||||
def output_xml(self):
|
||||
authorinfo_list = self.changes.get_authorinfo_list()
|
||||
total_changes = 0.0
|
||||
|
||||
for i in authorinfo_list:
|
||||
total_changes += authorinfo_list.get(i).insertions
|
||||
total_changes += authorinfo_list.get(i).deletions
|
||||
|
||||
if authorinfo_list:
|
||||
message_xml = "\t\t<message>" + _(HISTORICAL_INFO_TEXT) + "</message>\n"
|
||||
changes_xml = ""
|
||||
|
||||
for i in sorted(authorinfo_list):
|
||||
author_email = self.changes.get_latest_email_by_author(i)
|
||||
authorinfo = authorinfo_list.get(i)
|
||||
|
||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||
name_xml = "\t\t\t\t<name>" + i + "</name>\n"
|
||||
email_xml = "\t\t\t\t<email>" + author_email + "</email>\n"
|
||||
gravatar_xml = "\t\t\t\t<gravatar>" + gravatar.get_url(author_email) + "</gravatar>\n"
|
||||
commits_xml = "\t\t\t\t<commits>" + str(authorinfo.commits) + "</commits>\n"
|
||||
insertions_xml = "\t\t\t\t<insertions>" + str(authorinfo.insertions) + "</insertions>\n"
|
||||
deletions_xml = "\t\t\t\t<deletions>" + str(authorinfo.deletions) + "</deletions>\n"
|
||||
percentage_xml = "\t\t\t\t<percentage-of-changes>" + "{0:.2f}".format(percentage) + "</percentage-of-changes>\n"
|
||||
|
||||
changes_xml += ("\t\t\t<author>\n" + name_xml + email_xml + gravatar_xml + commits_xml +
|
||||
insertions_xml + deletions_xml + percentage_xml + "\t\t\t</author>\n")
|
||||
|
||||
print("\t<changes>\n" + message_xml + "\t\t<authors>\n" + changes_xml + "\t\t</authors>\n\t</changes>")
|
||||
else:
|
||||
print("\t<changes>\n\t\t<exception>" + _(NO_COMMITED_FILES_TEXT) + "</exception>\n\t</changes>")
|
|
@ -0,0 +1,97 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import textwrap
|
||||
from ..localization import N_
|
||||
from .. import extensions, terminal
|
||||
from .outputable import Outputable
|
||||
|
||||
|
||||
EXTENSIONS_INFO_TEXT = N_("The extensions below were found in the repository history")
|
||||
EXTENSIONS_MARKED_TEXT = N_("(extensions used during statistical analysis are marked)")
|
||||
|
||||
class ExtensionsOutput(Outputable):
|
||||
@staticmethod
|
||||
def is_marked(extension):
|
||||
if extension in extensions.__extensions__ or "**" in extensions.__extensions__:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def output_html(self):
|
||||
if extensions.__located_extensions__:
|
||||
extensions_xml = "<div><div class=\"box\">"
|
||||
extensions_xml += "<p>{0} {1}.</p><p>".format(_(EXTENSIONS_INFO_TEXT), _(EXTENSIONS_MARKED_TEXT))
|
||||
|
||||
for i in sorted(extensions.__located_extensions__):
|
||||
if ExtensionsOutput.is_marked(i):
|
||||
extensions_xml += "<strong>" + i + "</strong>"
|
||||
else:
|
||||
extensions_xml += i
|
||||
extensions_xml += " "
|
||||
|
||||
extensions_xml += "</p></div></div>"
|
||||
print(extensions_xml)
|
||||
|
||||
def output_json(self):
|
||||
if extensions.__located_extensions__:
|
||||
message_json = "\t\t\t\"message\": \"" + _(EXTENSIONS_INFO_TEXT) + "\",\n"
|
||||
used_extensions_json = ""
|
||||
unused_extensions_json = ""
|
||||
|
||||
for i in sorted(extensions.__located_extensions__):
|
||||
if ExtensionsOutput.is_marked(i):
|
||||
used_extensions_json += "\"" + i + "\", "
|
||||
else:
|
||||
unused_extensions_json += "\"" + i + "\", "
|
||||
|
||||
used_extensions_json = used_extensions_json[:-2]
|
||||
unused_extensions_json = unused_extensions_json[:-2]
|
||||
|
||||
print(",\n\t\t\"extensions\": {\n" + message_json + "\t\t\t\"used\": [ " + used_extensions_json +
|
||||
" ],\n\t\t\t\"unused\": [ " + unused_extensions_json + " ]\n" + "\t\t}", end="")
|
||||
|
||||
def output_text(self):
|
||||
if extensions.__located_extensions__:
|
||||
print("\n" + textwrap.fill("{0} {1}:".format(_(EXTENSIONS_INFO_TEXT), _(EXTENSIONS_MARKED_TEXT)),
|
||||
width=terminal.get_size()[0]))
|
||||
|
||||
for i in sorted(extensions.__located_extensions__):
|
||||
if ExtensionsOutput.is_marked(i):
|
||||
print("[" + terminal.__bold__ + i + terminal.__normal__ + "]", end=" ")
|
||||
else:
|
||||
print (i, end=" ")
|
||||
print("")
|
||||
|
||||
def output_xml(self):
|
||||
if extensions.__located_extensions__:
|
||||
message_xml = "\t\t<message>" + _(EXTENSIONS_INFO_TEXT) + "</message>\n"
|
||||
used_extensions_xml = ""
|
||||
unused_extensions_xml = ""
|
||||
|
||||
for i in sorted(extensions.__located_extensions__):
|
||||
if ExtensionsOutput.is_marked(i):
|
||||
used_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
|
||||
else:
|
||||
unused_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
|
||||
|
||||
print("\t<extensions>\n" + message_xml + "\t\t<used>\n" + used_extensions_xml + "\t\t</used>\n" +
|
||||
"\t\t<unused>\n" + unused_extensions_xml + "\t\t</unused>\n" + "\t</extensions>")
|
|
@ -0,0 +1,121 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import textwrap
|
||||
from ..localization import N_
|
||||
from ..filtering import __filters__, has_filtered
|
||||
from .. import terminal
|
||||
from .outputable import Outputable
|
||||
|
||||
FILTERING_INFO_TEXT = N_("The following files were excluded from the statistics due to the specified exclusion patterns")
|
||||
FILTERING_AUTHOR_INFO_TEXT = N_("The following authors were excluded from the statistics due to the specified exclusion patterns")
|
||||
FILTERING_EMAIL_INFO_TEXT = N_("The authors with the following emails were excluded from the statistics due to the specified " \
|
||||
"exclusion patterns")
|
||||
FILTERING_COMMIT_INFO_TEXT = N_("The following commit revisions were excluded from the statistics due to the specified " \
|
||||
"exclusion patterns")
|
||||
|
||||
class FilteringOutput(Outputable):
|
||||
@staticmethod
|
||||
def __output_html_section__(info_string, filtered):
|
||||
filtering_xml = ""
|
||||
|
||||
if filtered:
|
||||
filtering_xml += "<p>" + info_string + "."+ "</p>"
|
||||
|
||||
for i in filtered:
|
||||
filtering_xml += "<p>" + i + "</p>"
|
||||
|
||||
return filtering_xml
|
||||
|
||||
def output_html(self):
|
||||
if has_filtered():
|
||||
filtering_xml = "<div><div class=\"box\">"
|
||||
FilteringOutput.__output_html_section__(_(FILTERING_INFO_TEXT), __filters__["file"][1])
|
||||
FilteringOutput.__output_html_section__(_(FILTERING_AUTHOR_INFO_TEXT), __filters__["author"][1])
|
||||
FilteringOutput.__output_html_section__(_(FILTERING_EMAIL_INFO_TEXT), __filters__["email"][1])
|
||||
FilteringOutput.__output_html_section__(_(FILTERING_COMMIT_INFO_TEXT), __filters__["revision"][1])
|
||||
filtering_xml += "</div></div>"
|
||||
|
||||
print(filtering_xml)
|
||||
|
||||
@staticmethod
|
||||
def __output_json_section__(info_string, filtered, container_tagname):
|
||||
if filtered:
|
||||
message_json = "\t\t\t\t\"message\": \"" + info_string + "\",\n"
|
||||
filtering_json = ""
|
||||
|
||||
for i in filtered:
|
||||
filtering_json += "\t\t\t\t\t\"" + i + "\",\n"
|
||||
else:
|
||||
filtering_json = filtering_json[:-3]
|
||||
|
||||
return "\n\t\t\t\"{0}\": {{\n".format(container_tagname) + message_json + \
|
||||
"\t\t\t\t\"entries\": [\n" + filtering_json + "\"\n\t\t\t\t]\n\t\t\t},"
|
||||
|
||||
return ""
|
||||
|
||||
def output_json(self):
|
||||
if has_filtered():
|
||||
output = ",\n\t\t\"filtering\": {"
|
||||
output += FilteringOutput.__output_json_section__(_(FILTERING_INFO_TEXT), __filters__["file"][1], "files")
|
||||
output += FilteringOutput.__output_json_section__(_(FILTERING_AUTHOR_INFO_TEXT), __filters__["author"][1], "authors")
|
||||
output += FilteringOutput.__output_json_section__(_(FILTERING_EMAIL_INFO_TEXT), __filters__["email"][1], "emails")
|
||||
output += FilteringOutput.__output_json_section__(_(FILTERING_COMMIT_INFO_TEXT), __filters__["revision"][1], "revision")
|
||||
output = output[:-1]
|
||||
output += "\n\t\t}"
|
||||
print(output, end="")
|
||||
|
||||
@staticmethod
|
||||
def __output_text_section__(info_string, filtered):
|
||||
if filtered:
|
||||
print("\n" + textwrap.fill(info_string + ":", width=terminal.get_size()[0]))
|
||||
|
||||
for i in filtered:
|
||||
(width, _unused) = terminal.get_size()
|
||||
print("...%s" % i[-width+3:] if len(i) > width else i)
|
||||
|
||||
def output_text(self):
|
||||
FilteringOutput.__output_text_section__(_(FILTERING_INFO_TEXT), __filters__["file"][1])
|
||||
FilteringOutput.__output_text_section__(_(FILTERING_AUTHOR_INFO_TEXT), __filters__["author"][1])
|
||||
FilteringOutput.__output_text_section__(_(FILTERING_EMAIL_INFO_TEXT), __filters__["email"][1])
|
||||
FilteringOutput.__output_text_section__(_(FILTERING_COMMIT_INFO_TEXT), __filters__["revision"][1])
|
||||
|
||||
@staticmethod
|
||||
def __output_xml_section__(info_string, filtered, container_tagname):
|
||||
if filtered:
|
||||
message_xml = "\t\t\t<message>" + info_string + "</message>\n"
|
||||
filtering_xml = ""
|
||||
|
||||
for i in filtered:
|
||||
filtering_xml += "\t\t\t\t<entry>" + i + "</entry>\n"
|
||||
|
||||
print("\t\t<{0}>".format(container_tagname))
|
||||
print(message_xml + "\t\t\t<entries>\n" + filtering_xml + "\t\t\t</entries>\n")
|
||||
print("\t\t</{0}>".format(container_tagname))
|
||||
|
||||
def output_xml(self):
|
||||
if has_filtered():
|
||||
print("\t<filtering>")
|
||||
FilteringOutput.__output_xml_section__(_(FILTERING_INFO_TEXT), __filters__["file"][1], "files")
|
||||
FilteringOutput.__output_xml_section__(_(FILTERING_AUTHOR_INFO_TEXT), __filters__["author"][1], "authors")
|
||||
FilteringOutput.__output_xml_section__(_(FILTERING_EMAIL_INFO_TEXT), __filters__["email"][1], "emails")
|
||||
FilteringOutput.__output_xml_section__(_(FILTERING_COMMIT_INFO_TEXT), __filters__["revision"][1], "revision")
|
||||
print("\t</filtering>")
|
|
@ -0,0 +1,160 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from ..changes import FileDiff
|
||||
from ..localization import N_
|
||||
from ..metrics import (__metric_eloc__, METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD, METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD)
|
||||
from .outputable import Outputable
|
||||
|
||||
ELOC_INFO_TEXT = N_("The following files are suspiciously big (in order of severity)")
|
||||
CYCLOMATIC_COMPLEXITY_TEXT = N_("The following files have an elevated cyclomatic complexity (in order of severity)")
|
||||
CYCLOMATIC_COMPLEXITY_DENSITY_TEXT = N_("The following files have an elevated cyclomatic complexity density " \
|
||||
"(in order of severity)")
|
||||
METRICS_MISSING_INFO_TEXT = N_("No metrics violations were found in the repository")
|
||||
|
||||
METRICS_VIOLATION_SCORES = [[1.0, "minimal"], [1.25, "minor"], [1.5, "medium"], [2.0, "bad"], [3.0, "severe"]]
|
||||
|
||||
def __get_metrics_score__(ceiling, value):
|
||||
for i in reversed(METRICS_VIOLATION_SCORES):
|
||||
if value > ceiling * i[0]:
|
||||
return i[1]
|
||||
|
||||
class MetricsOutput(Outputable):
|
||||
def __init__(self, metrics):
|
||||
self.metrics = metrics
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_text(self):
|
||||
if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
|
||||
print("\n" + _(METRICS_MISSING_INFO_TEXT) + ".")
|
||||
|
||||
if self.metrics.eloc:
|
||||
print("\n" + _(ELOC_INFO_TEXT) + ":")
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True):
|
||||
print(_("{0} ({1} estimated lines of code)").format(i[1], str(i[0])))
|
||||
|
||||
if self.metrics.cyclomatic_complexity:
|
||||
print("\n" + _(CYCLOMATIC_COMPLEXITY_TEXT) + ":")
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True):
|
||||
print(_("{0} ({1} in cyclomatic complexity)").format(i[1], str(i[0])))
|
||||
|
||||
if self.metrics.cyclomatic_complexity_density:
|
||||
print("\n" + _(CYCLOMATIC_COMPLEXITY_DENSITY_TEXT) + ":")
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True):
|
||||
print(_("{0} ({1:.3f} in cyclomatic complexity density)").format(i[1], i[0]))
|
||||
|
||||
def output_html(self):
|
||||
metrics_xml = "<div><div class=\"box\" id=\"metrics\">"
|
||||
|
||||
if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
|
||||
metrics_xml += "<p>" + _(METRICS_MISSING_INFO_TEXT) + ".</p>"
|
||||
|
||||
if self.metrics.eloc:
|
||||
metrics_xml += "<div><h4>" + _(ELOC_INFO_TEXT) + ".</h4>"
|
||||
for num, i in enumerate(sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True)):
|
||||
metrics_xml += "<div class=\"" + __get_metrics_score__(__metric_eloc__[FileDiff.get_extension(i[1])], i[0]) + \
|
||||
(" odd\">" if num % 2 == 1 else "\">") + \
|
||||
_("{0} ({1} estimated lines of code)").format(i[1], str(i[0])) + "</div>"
|
||||
metrics_xml += "</div>"
|
||||
|
||||
if self.metrics.cyclomatic_complexity:
|
||||
metrics_xml += "<div><h4>" + _(CYCLOMATIC_COMPLEXITY_TEXT) + "</h4>"
|
||||
for num, i in enumerate(sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True)):
|
||||
metrics_xml += "<div class=\"" + __get_metrics_score__(METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD, i[0]) + \
|
||||
(" odd\">" if num % 2 == 1 else "\">") + \
|
||||
_("{0} ({1} in cyclomatic complexity)").format(i[1], str(i[0])) + "</div>"
|
||||
metrics_xml += "</div>"
|
||||
|
||||
if self.metrics.cyclomatic_complexity_density:
|
||||
metrics_xml += "<div><h4>" + _(CYCLOMATIC_COMPLEXITY_DENSITY_TEXT) + "</h4>"
|
||||
for num, i in enumerate(sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True)):
|
||||
metrics_xml += "<div class=\"" + __get_metrics_score__(METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD, i[0]) + \
|
||||
(" odd\">" if num % 2 == 1 else "\">") + \
|
||||
_("{0} ({1:.3f} in cyclomatic complexity density)").format(i[1], i[0]) + "</div>"
|
||||
metrics_xml += "</div>"
|
||||
|
||||
metrics_xml += "</div></div>"
|
||||
print(metrics_xml)
|
||||
|
||||
def output_json(self):
|
||||
if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
|
||||
print(",\n\t\t\"metrics\": {\n\t\t\t\"message\": \"" + _(METRICS_MISSING_INFO_TEXT) + "\"\n\t\t}", end="")
|
||||
else:
|
||||
eloc_json = ""
|
||||
|
||||
if self.metrics.eloc:
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True):
|
||||
eloc_json += "{\n\t\t\t\t\"type\": \"estimated-lines-of-code\",\n"
|
||||
eloc_json += "\t\t\t\t\"file_name\": \"" + i[1] + "\",\n"
|
||||
eloc_json += "\t\t\t\t\"value\": " + str(i[0]) + "\n"
|
||||
eloc_json += "\t\t\t},"
|
||||
else:
|
||||
if not self.metrics.cyclomatic_complexity:
|
||||
eloc_json = eloc_json[:-1]
|
||||
|
||||
if self.metrics.cyclomatic_complexity:
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True):
|
||||
eloc_json += "{\n\t\t\t\t\"type\": \"cyclomatic-complexity\",\n"
|
||||
eloc_json += "\t\t\t\t\"file_name\": \"" + i[1] + "\",\n"
|
||||
eloc_json += "\t\t\t\t\"value\": " + str(i[0]) + "\n"
|
||||
eloc_json += "\t\t\t},"
|
||||
else:
|
||||
if not self.metrics.cyclomatic_complexity_density:
|
||||
eloc_json = eloc_json[:-1]
|
||||
|
||||
if self.metrics.cyclomatic_complexity_density:
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True):
|
||||
eloc_json += "{\n\t\t\t\t\"type\": \"cyclomatic-complexity-density\",\n"
|
||||
eloc_json += "\t\t\t\t\"file_name\": \"" + i[1] + "\",\n"
|
||||
eloc_json += "\t\t\t\t\"value\": {0:.3f}\n".format(i[0])
|
||||
eloc_json += "\t\t\t},"
|
||||
else:
|
||||
eloc_json = eloc_json[:-1]
|
||||
|
||||
print(",\n\t\t\"metrics\": {\n\t\t\t\"violations\": [\n\t\t\t" + eloc_json + "]\n\t\t}", end="")
|
||||
def output_xml(self):
|
||||
if not self.metrics.eloc and not self.metrics.cyclomatic_complexity and not self.metrics.cyclomatic_complexity_density:
|
||||
print("\t<metrics>\n\t\t<message>" + _(METRICS_MISSING_INFO_TEXT) + "</message>\n\t</metrics>")
|
||||
else:
|
||||
eloc_xml = ""
|
||||
|
||||
if self.metrics.eloc:
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.eloc.items()]), reverse=True):
|
||||
eloc_xml += "\t\t\t<estimated-lines-of-code>\n"
|
||||
eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
|
||||
eloc_xml += "\t\t\t\t<value>" + str(i[0]) + "</value>\n"
|
||||
eloc_xml += "\t\t\t</estimated-lines-of-code>\n"
|
||||
|
||||
if self.metrics.cyclomatic_complexity:
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity.items()]), reverse=True):
|
||||
eloc_xml += "\t\t\t<cyclomatic-complexity>\n"
|
||||
eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
|
||||
eloc_xml += "\t\t\t\t<value>" + str(i[0]) + "</value>\n"
|
||||
eloc_xml += "\t\t\t</cyclomatic-complexity>\n"
|
||||
|
||||
if self.metrics.cyclomatic_complexity_density:
|
||||
for i in sorted(set([(j, i) for (i, j) in self.metrics.cyclomatic_complexity_density.items()]), reverse=True):
|
||||
eloc_xml += "\t\t\t<cyclomatic-complexity-density>\n"
|
||||
eloc_xml += "\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
|
||||
eloc_xml += "\t\t\t\t<value>{0:.3f}</value>\n".format(i[0])
|
||||
eloc_xml += "\t\t\t</cyclomatic-complexity-density>\n"
|
||||
|
||||
print("\t<metrics>\n\t\t<violations>\n" + eloc_xml + "\t\t</violations>\n\t</metrics>")
|
|
@ -19,21 +19,26 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import format
|
||||
from .. import format
|
||||
|
||||
class Outputable(object):
|
||||
def output_html(self):
|
||||
print(_("HTML output not yet supported in") + " \"" + self.__class__.__name__ + "\".")
|
||||
raise NotImplementedError(_("HTML output not yet supported in") + " \"" + self.__class__.__name__ + "\".")
|
||||
|
||||
def output_json(self):
|
||||
raise NotImplementedError(_("JSON output not yet supported in") + " \"" + self.__class__.__name__ + "\".")
|
||||
|
||||
def output_text(self):
|
||||
print(_("Text output not yet supported in") + " \"" + self.__class__.__name__ + "\".")
|
||||
raise NotImplementedError(_("Text output not yet supported in") + " \"" + self.__class__.__name__ + "\".")
|
||||
|
||||
def output_xml(self):
|
||||
print(_("XML output not yet supported in") + " \"" + self.__class__.__name__ + "\".")
|
||||
raise NotImplementedError(_("XML output not yet supported in") + " \"" + self.__class__.__name__ + "\".")
|
||||
|
||||
def output(outputable):
|
||||
if format.get_selected() == "html" or format.get_selected() == "htmlembedded":
|
||||
outputable.output_html()
|
||||
elif format.get_selected() == "json":
|
||||
outputable.output_json()
|
||||
elif format.get_selected() == "text":
|
||||
outputable.output_text()
|
||||
else:
|
|
@ -0,0 +1,143 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import textwrap
|
||||
from ..localization import N_
|
||||
from .. import format, gravatar, terminal
|
||||
from .. import responsibilities as resp
|
||||
from .outputable import Outputable
|
||||
|
||||
RESPONSIBILITIES_INFO_TEXT = N_("The following responsibilities, by author, were found in the current "
|
||||
"revision of the repository (comments are excluded from the line count, "
|
||||
"if possible)")
|
||||
MOSTLY_RESPONSIBLE_FOR_TEXT = N_("is mostly responsible for")
|
||||
|
||||
class ResponsibilitiesOutput(Outputable):
|
||||
def __init__(self, changes, blame):
|
||||
self.changes = changes
|
||||
self.blame = blame
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_text(self):
|
||||
print("\n" + textwrap.fill(_(RESPONSIBILITIES_INFO_TEXT) + ":", width=terminal.get_size()[0]))
|
||||
|
||||
for i in sorted(set(i[0] for i in self.blame.blames)):
|
||||
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.blame, i)), reverse=True)
|
||||
|
||||
if responsibilities:
|
||||
print("\n" + i, _(MOSTLY_RESPONSIBLE_FOR_TEXT) + ":")
|
||||
|
||||
for j, entry in enumerate(responsibilities):
|
||||
(width, _unused) = terminal.get_size()
|
||||
width -= 7
|
||||
|
||||
print(str(entry[0]).rjust(6), end=" ")
|
||||
print("...%s" % entry[1][-width+3:] if len(entry[1]) > width else entry[1])
|
||||
|
||||
if j >= 9:
|
||||
break
|
||||
|
||||
def output_html(self):
|
||||
resp_xml = "<div><div class=\"box\" id=\"responsibilities\">"
|
||||
resp_xml += "<p>" + _(RESPONSIBILITIES_INFO_TEXT) + ".</p>"
|
||||
|
||||
for i in sorted(set(i[0] for i in self.blame.blames)):
|
||||
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.blame, i)), reverse=True)
|
||||
|
||||
if responsibilities:
|
||||
resp_xml += "<div>"
|
||||
|
||||
if format.get_selected() == "html":
|
||||
author_email = self.changes.get_latest_email_by_author(i)
|
||||
resp_xml += "<h3><img src=\"{0}\"/>{1} {2}</h3>".format(gravatar.get_url(author_email, size=32),
|
||||
i, _(MOSTLY_RESPONSIBLE_FOR_TEXT))
|
||||
else:
|
||||
resp_xml += "<h3>{0} {1}</h3>".format(i, _(MOSTLY_RESPONSIBLE_FOR_TEXT))
|
||||
|
||||
for j, entry in enumerate(responsibilities):
|
||||
resp_xml += "<div" + (" class=\"odd\">" if j % 2 == 1 else ">") + entry[1] + \
|
||||
" (" + str(entry[0]) + " eloc)</div>"
|
||||
if j >= 9:
|
||||
break
|
||||
|
||||
resp_xml += "</div>"
|
||||
resp_xml += "</div></div>"
|
||||
print(resp_xml)
|
||||
|
||||
def output_json(self):
|
||||
message_json = "\t\t\t\"message\": \"" + _(RESPONSIBILITIES_INFO_TEXT) + "\",\n"
|
||||
resp_json = ""
|
||||
|
||||
for i in sorted(set(i[0] for i in self.blame.blames)):
|
||||
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.blame, i)), reverse=True)
|
||||
|
||||
if responsibilities:
|
||||
author_email = self.changes.get_latest_email_by_author(i)
|
||||
|
||||
resp_json += "{\n"
|
||||
resp_json += "\t\t\t\t\"name\": \"" + i + "\",\n"
|
||||
resp_json += "\t\t\t\t\"email\": \"" + author_email + "\",\n"
|
||||
resp_json += "\t\t\t\t\"gravatar\": \"" + gravatar.get_url(author_email) + "\",\n"
|
||||
resp_json += "\t\t\t\t\"files\": [\n\t\t\t\t"
|
||||
|
||||
for j, entry in enumerate(responsibilities):
|
||||
resp_json += "{\n"
|
||||
resp_json += "\t\t\t\t\t\"name\": \"" + entry[1] + "\",\n"
|
||||
resp_json += "\t\t\t\t\t\"rows\": " + str(entry[0]) + "\n"
|
||||
resp_json += "\t\t\t\t},"
|
||||
|
||||
if j >= 9:
|
||||
break
|
||||
|
||||
resp_json = resp_json[:-1]
|
||||
resp_json += "]\n\t\t\t},"
|
||||
|
||||
resp_json = resp_json[:-1]
|
||||
print(",\n\t\t\"responsibilities\": {\n" + message_json + "\t\t\t\"authors\": [\n\t\t\t" + resp_json + "]\n\t\t}", end="")
|
||||
|
||||
def output_xml(self):
|
||||
message_xml = "\t\t<message>" + _(RESPONSIBILITIES_INFO_TEXT) + "</message>\n"
|
||||
resp_xml = ""
|
||||
|
||||
for i in sorted(set(i[0] for i in self.blame.blames)):
|
||||
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.blame, i)), reverse=True)
|
||||
if responsibilities:
|
||||
author_email = self.changes.get_latest_email_by_author(i)
|
||||
|
||||
resp_xml += "\t\t\t<author>\n"
|
||||
resp_xml += "\t\t\t\t<name>" + i + "</name>\n"
|
||||
resp_xml += "\t\t\t\t<email>" + author_email + "</email>\n"
|
||||
resp_xml += "\t\t\t\t<gravatar>" + gravatar.get_url(author_email) + "</gravatar>\n"
|
||||
resp_xml += "\t\t\t\t<files>\n"
|
||||
|
||||
for j, entry in enumerate(responsibilities):
|
||||
resp_xml += "\t\t\t\t\t<file>\n"
|
||||
resp_xml += "\t\t\t\t\t\t<name>" + entry[1] + "</name>\n"
|
||||
resp_xml += "\t\t\t\t\t\t<rows>" + str(entry[0]) + "</rows>\n"
|
||||
resp_xml += "\t\t\t\t\t</file>\n"
|
||||
|
||||
if j >= 9:
|
||||
break
|
||||
|
||||
resp_xml += "\t\t\t\t</files>\n"
|
||||
resp_xml += "\t\t\t</author>\n"
|
||||
|
||||
print("\t<responsibilities>\n" + message_xml + "\t\t<authors>\n" + resp_xml + "\t\t</authors>\n\t</responsibilities>")
|
|
@ -0,0 +1,208 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import textwrap
|
||||
from ..localization import N_
|
||||
from .. import format, gravatar, terminal, timeline
|
||||
from .outputable import Outputable
|
||||
|
||||
TIMELINE_INFO_TEXT = N_("The following history timeline has been gathered from the repository")
|
||||
MODIFIED_ROWS_TEXT = N_("Modified Rows:")
|
||||
|
||||
def __output_row__text__(timeline_data, periods, names):
|
||||
print("\n" + terminal.__bold__ + terminal.ljust(_("Author"), 20), end=" ")
|
||||
|
||||
for period in periods:
|
||||
print(terminal.rjust(period, 10), end=" ")
|
||||
|
||||
print(terminal.__normal__)
|
||||
|
||||
for name in names:
|
||||
if timeline_data.is_author_in_periods(periods, name[0]):
|
||||
print(terminal.ljust(name[0], 20)[0:20 - terminal.get_excess_column_count(name[0])], end=" ")
|
||||
|
||||
for period in periods:
|
||||
multiplier = timeline_data.get_multiplier(period, 9)
|
||||
signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier)
|
||||
signs_str = (signs[1] * "-" + signs[0] * "+")
|
||||
print (("." if timeline_data.is_author_in_period(period, name[0]) and
|
||||
len(signs_str) == 0 else signs_str).rjust(10), end=" ")
|
||||
print("")
|
||||
|
||||
print(terminal.__bold__ + terminal.ljust(_(MODIFIED_ROWS_TEXT), 20) + terminal.__normal__, end=" ")
|
||||
|
||||
for period in periods:
|
||||
total_changes = str(timeline_data.get_total_changes_in_period(period)[2])
|
||||
|
||||
if hasattr(total_changes, 'decode'):
|
||||
total_changes = total_changes.decode("utf-8", "replace")
|
||||
|
||||
print(terminal.rjust(total_changes, 10), end=" ")
|
||||
|
||||
print("")
|
||||
|
||||
def __output_row__html__(timeline_data, periods, names):
|
||||
timeline_xml = "<table class=\"git full\"><thead><tr><th>" + _("Author") + "</th>"
|
||||
|
||||
for period in periods:
|
||||
timeline_xml += "<th>" + str(period) + "</th>"
|
||||
|
||||
timeline_xml += "</tr></thead><tbody>"
|
||||
i = 0
|
||||
|
||||
for name in names:
|
||||
if timeline_data.is_author_in_periods(periods, name[0]):
|
||||
timeline_xml += "<tr" + (" class=\"odd\">" if i % 2 == 1 else ">")
|
||||
|
||||
if format.get_selected() == "html":
|
||||
timeline_xml += "<td><img src=\"{0}\"/>{1}</td>".format(gravatar.get_url(name[1]), name[0])
|
||||
else:
|
||||
timeline_xml += "<td>" + name[0] + "</td>"
|
||||
|
||||
for period in periods:
|
||||
multiplier = timeline_data.get_multiplier(period, 18)
|
||||
signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier)
|
||||
signs_str = (signs[1] * "<div class=\"remove\"> </div>" + signs[0] * "<div class=\"insert\"> </div>")
|
||||
|
||||
timeline_xml += "<td>" + ("." if timeline_data.is_author_in_period(period, name[0]) and len(signs_str) == 0 else signs_str)
|
||||
timeline_xml += "</td>"
|
||||
timeline_xml += "</tr>"
|
||||
i = i + 1
|
||||
|
||||
timeline_xml += "<tfoot><tr><td><strong>" + _(MODIFIED_ROWS_TEXT) + "</strong></td>"
|
||||
|
||||
for period in periods:
|
||||
total_changes = timeline_data.get_total_changes_in_period(period)
|
||||
timeline_xml += "<td>" + str(total_changes[2]) + "</td>"
|
||||
|
||||
timeline_xml += "</tr></tfoot></tbody></table>"
|
||||
print(timeline_xml)
|
||||
|
||||
class TimelineOutput(Outputable):
|
||||
def __init__(self, changes, useweeks):
|
||||
self.changes = changes
|
||||
self.useweeks = useweeks
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_text(self):
|
||||
if self.changes.get_commits():
|
||||
print("\n" + textwrap.fill(_(TIMELINE_INFO_TEXT) + ":", width=terminal.get_size()[0]))
|
||||
|
||||
timeline_data = timeline.TimelineData(self.changes, self.useweeks)
|
||||
periods = timeline_data.get_periods()
|
||||
names = timeline_data.get_authors()
|
||||
(width, _unused) = terminal.get_size()
|
||||
max_periods_per_row = int((width - 21) / 11)
|
||||
|
||||
for i in range(0, len(periods), max_periods_per_row):
|
||||
__output_row__text__(timeline_data, periods[i:i+max_periods_per_row], names)
|
||||
|
||||
def output_html(self):
|
||||
if self.changes.get_commits():
|
||||
timeline_data = timeline.TimelineData(self.changes, self.useweeks)
|
||||
periods = timeline_data.get_periods()
|
||||
names = timeline_data.get_authors()
|
||||
max_periods_per_row = 8
|
||||
|
||||
timeline_xml = "<div><div id=\"timeline\" class=\"box\">"
|
||||
timeline_xml += "<p>" + _(TIMELINE_INFO_TEXT) + ".</p>"
|
||||
print(timeline_xml)
|
||||
|
||||
for i in range(0, len(periods), max_periods_per_row):
|
||||
__output_row__html__(timeline_data, periods[i:i+max_periods_per_row], names)
|
||||
|
||||
timeline_xml = "</div></div>"
|
||||
print(timeline_xml)
|
||||
|
||||
def output_json(self):
|
||||
if self.changes.get_commits():
|
||||
message_json = "\t\t\t\"message\": \"" + _(TIMELINE_INFO_TEXT) + "\",\n"
|
||||
timeline_json = ""
|
||||
periods_json = "\t\t\t\"period_length\": \"{0}\",\n".format("week" if self.useweeks else "month")
|
||||
periods_json += "\t\t\t\"periods\": [\n\t\t\t"
|
||||
|
||||
timeline_data = timeline.TimelineData(self.changes, self.useweeks)
|
||||
periods = timeline_data.get_periods()
|
||||
names = timeline_data.get_authors()
|
||||
|
||||
for period in periods:
|
||||
name_json = "\t\t\t\t\"name\": \"" + str(period) + "\",\n"
|
||||
authors_json = "\t\t\t\t\"authors\": [\n\t\t\t\t"
|
||||
|
||||
for name in names:
|
||||
if timeline_data.is_author_in_period(period, name[0]):
|
||||
multiplier = timeline_data.get_multiplier(period, 24)
|
||||
signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier)
|
||||
signs_str = (signs[1] * "-" + signs[0] * "+")
|
||||
|
||||
if len(signs_str) == 0:
|
||||
signs_str = "."
|
||||
|
||||
authors_json += "{\n\t\t\t\t\t\"name\": \"" + name[0] + "\",\n"
|
||||
authors_json += "\t\t\t\t\t\"email\": \"" + name[1] + "\",\n"
|
||||
authors_json += "\t\t\t\t\t\"gravatar\": \"" + gravatar.get_url(name[1]) + "\",\n"
|
||||
authors_json += "\t\t\t\t\t\"work\": \"" + signs_str + "\"\n\t\t\t\t},"
|
||||
else:
|
||||
authors_json = authors_json[:-1]
|
||||
|
||||
authors_json += "],\n"
|
||||
modified_rows_json = "\t\t\t\t\"modified_rows\": " + \
|
||||
str(timeline_data.get_total_changes_in_period(period)[2]) + "\n"
|
||||
timeline_json += "{\n" + name_json + authors_json + modified_rows_json + "\t\t\t},"
|
||||
else:
|
||||
timeline_json = timeline_json[:-1]
|
||||
|
||||
print(",\n\t\t\"timeline\": {\n" + message_json + periods_json + timeline_json + "]\n\t\t}", end="")
|
||||
|
||||
def output_xml(self):
|
||||
if self.changes.get_commits():
|
||||
message_xml = "\t\t<message>" + _(TIMELINE_INFO_TEXT) + "</message>\n"
|
||||
timeline_xml = ""
|
||||
periods_xml = "\t\t<periods length=\"{0}\">\n".format("week" if self.useweeks else "month")
|
||||
|
||||
timeline_data = timeline.TimelineData(self.changes, self.useweeks)
|
||||
periods = timeline_data.get_periods()
|
||||
names = timeline_data.get_authors()
|
||||
|
||||
for period in periods:
|
||||
name_xml = "\t\t\t\t<name>" + str(period) + "</name>\n"
|
||||
authors_xml = "\t\t\t\t<authors>\n"
|
||||
|
||||
for name in names:
|
||||
if timeline_data.is_author_in_period(period, name[0]):
|
||||
multiplier = timeline_data.get_multiplier(period, 24)
|
||||
signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier)
|
||||
signs_str = (signs[1] * "-" + signs[0] * "+")
|
||||
|
||||
if len(signs_str) == 0:
|
||||
signs_str = "."
|
||||
|
||||
authors_xml += "\t\t\t\t\t<author>\n\t\t\t\t\t\t<name>" + name[0] + "</name>\n"
|
||||
authors_xml += "\t\t\t\t\t\t<email>" + name[1] + "</email>\n"
|
||||
authors_xml += "\t\t\t\t\t\t<gravatar>" + gravatar.get_url(name[1]) + "</gravatar>\n"
|
||||
authors_xml += "\t\t\t\t\t\t<work>" + signs_str + "</work>\n\t\t\t\t\t</author>\n"
|
||||
|
||||
authors_xml += "\t\t\t\t</authors>\n"
|
||||
modified_rows_xml = "\t\t\t\t<modified_rows>" + \
|
||||
str(timeline_data.get_total_changes_in_period(period)[2]) + "</modified_rows>\n"
|
||||
timeline_xml += "\t\t\t<period>\n" + name_xml + authors_xml + modified_rows_xml + "\t\t\t</period>\n"
|
||||
|
||||
print("\t<timeline>\n" + message_xml + periods_xml + timeline_xml + "\t\t</periods>\n\t</timeline>")
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -19,110 +19,19 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
import blame
|
||||
import changes
|
||||
import format
|
||||
import gravatar
|
||||
import terminal
|
||||
import textwrap
|
||||
|
||||
class ResponsibiltyEntry:
|
||||
class ResponsibiltyEntry(object):
|
||||
blames = {}
|
||||
|
||||
class Responsibilities:
|
||||
class Responsibilities(object):
|
||||
@staticmethod
|
||||
def get(hard, author_name):
|
||||
def get(blame, author_name):
|
||||
author_blames = {}
|
||||
|
||||
for i in blame.get(hard).blames.items():
|
||||
if (author_name == i[0][0]):
|
||||
for i in blame.blames.items():
|
||||
if author_name == i[0][0]:
|
||||
total_rows = i[1].rows - i[1].comments
|
||||
if total_rows > 0:
|
||||
author_blames[i[0][1]] = total_rows
|
||||
|
||||
return sorted(author_blames.items())
|
||||
|
||||
RESPONSIBILITIES_INFO_TEXT = N_("The following repsonsibilties, by author, were found in the current "
|
||||
"revision of the repository (comments are exluded from the line count, "
|
||||
"if possible)")
|
||||
MOSTLY_RESPONSIBLE_FOR_TEXT = N_("is mostly responsible for")
|
||||
|
||||
class ResponsibilitiesOutput(Outputable):
|
||||
def __init__(self, hard):
|
||||
self.hard = hard
|
||||
Outputable.__init__(self)
|
||||
self.changes = changes.get(hard)
|
||||
|
||||
def output_text(self):
|
||||
print("\n" + textwrap.fill(_(RESPONSIBILITIES_INFO_TEXT) + ":", width=terminal.get_size()[0]))
|
||||
|
||||
for i in sorted(set(i[0] for i in blame.get(self.hard).blames)):
|
||||
responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(self.hard, i)), reverse=True)
|
||||
if responsibilities:
|
||||
print("\n" + i, _(MOSTLY_RESPONSIBLE_FOR_TEXT) + ":")
|
||||
|
||||
for j, entry in enumerate(responsibilities):
|
||||
(width, _unused) = terminal.get_size()
|
||||
width -= 7
|
||||
|
||||
print(str(entry[0]).rjust(6), end=" ")
|
||||
print("...%s" % entry[1][-width+3:] if len(entry[1]) > width else entry[1])
|
||||
|
||||
if j >= 9:
|
||||
break
|
||||
|
||||
def output_html(self):
|
||||
resp_xml = "<div><div class=\"box\" id=\"responsibilities\">"
|
||||
resp_xml += "<p>" + _(RESPONSIBILITIES_INFO_TEXT) + ".</p>"
|
||||
|
||||
for i in sorted(set(i[0] for i in blame.get(self.hard).blames)):
|
||||
responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(self.hard, i)), reverse=True)
|
||||
if responsibilities:
|
||||
resp_xml += "<div>"
|
||||
|
||||
if format.get_selected() == "html":
|
||||
author_email = self.changes.get_author_email(i)
|
||||
resp_xml += "<h3><img src=\"{0}\"/>{1} {2}</h3>".format(gravatar.get_url(author_email, size=32),
|
||||
i, _(MOSTLY_RESPONSIBLE_FOR_TEXT))
|
||||
else:
|
||||
resp_xml += "<h3>{0} {1}</h3>".format(i, _(MOSTLY_RESPONSIBLE_FOR_TEXT))
|
||||
|
||||
for j, entry in enumerate(responsibilities):
|
||||
resp_xml += "<div" + (" class=\"odd\">" if j % 2 == 1 else ">") + entry[1] + \
|
||||
" (" + str(entry[0]) + " eloc)</div>"
|
||||
if j >= 9:
|
||||
break
|
||||
|
||||
resp_xml += "</div>"
|
||||
resp_xml += "</div></div>"
|
||||
print(resp_xml)
|
||||
|
||||
def output_xml(self):
|
||||
message_xml = "\t\t<message>" + _(RESPONSIBILITIES_INFO_TEXT) + "</message>\n"
|
||||
resp_xml = ""
|
||||
|
||||
for i in sorted(set(i[0] for i in blame.get(self.hard).blames)):
|
||||
responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(self.hard, i)), reverse=True)
|
||||
if responsibilities:
|
||||
author_email = self.changes.get_author_email(i)
|
||||
|
||||
resp_xml += "\t\t\t<author>\n"
|
||||
resp_xml += "\t\t\t\t<name>" + i + "</name>\n"
|
||||
resp_xml += "\t\t\t\t<gravatar>" + gravatar.get_url(author_email) + "</gravatar>\n"
|
||||
resp_xml += "\t\t\t\t<files>\n"
|
||||
|
||||
for j, entry in enumerate(responsibilities):
|
||||
resp_xml += "\t\t\t\t\t<file>\n"
|
||||
resp_xml += "\t\t\t\t\t\t<name>" + entry[1] + "</name>\n"
|
||||
resp_xml += "\t\t\t\t\t\t<rows>" + str(entry[0]) + "</rows>\n"
|
||||
resp_xml += "\t\t\t\t\t</file>\n"
|
||||
|
||||
if j >= 9:
|
||||
break
|
||||
|
||||
resp_xml += "\t\t\t\t</files>\n"
|
||||
resp_xml += "\t\t\t</author>\n"
|
||||
|
||||
print("\t<responsibilities>\n" + message_xml + "\t\t<authors>\n" + resp_xml + "\t\t</authors>\n\t</responsibilities>")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -22,9 +22,10 @@ import codecs
|
|||
import os
|
||||
import platform
|
||||
import sys
|
||||
import unicodedata
|
||||
|
||||
__bold__ = "\033[1m"
|
||||
__normal__ = "\033[0;0m"
|
||||
__bold__ = "\033[1m"
|
||||
__normal__ = "\033[0;0m"
|
||||
|
||||
DEFAULT_TERMINAL_SIZE = (80, 25)
|
||||
|
||||
|
@ -76,7 +77,7 @@ def __get_size_linux__():
|
|||
return int(size[1]), int(size[0])
|
||||
|
||||
def clear_row():
|
||||
print("\b" * 200, end="")
|
||||
print("\r", end="")
|
||||
|
||||
def skip_escapes(skip):
|
||||
if skip:
|
||||
|
@ -109,6 +110,10 @@ def set_stdout_encoding():
|
|||
if not sys.stdout.isatty() and sys.version_info < (3,):
|
||||
sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
|
||||
|
||||
def set_stdin_encoding():
|
||||
if not sys.stdin.isatty() and sys.version_info < (3,):
|
||||
sys.stdin = codecs.getreader("utf-8")(sys.stdin)
|
||||
|
||||
def convert_command_line_to_utf8():
|
||||
try:
|
||||
argv = []
|
||||
|
@ -119,3 +124,35 @@ def convert_command_line_to_utf8():
|
|||
return argv
|
||||
except AttributeError:
|
||||
return sys.argv
|
||||
|
||||
def check_terminal_encoding():
|
||||
if sys.stdout.isatty() and (sys.stdout.encoding == None or sys.stdin.encoding == None):
|
||||
print(_("WARNING: The terminal encoding is not correctly configured. gitinspector might malfunction. "
|
||||
"The encoding can be configured with the environment variable 'PYTHONIOENCODING'."), file=sys.stderr)
|
||||
|
||||
def get_excess_column_count(string):
|
||||
width_mapping = {'F': 2, 'H': 1, 'W': 2, 'Na': 1, 'N': 1, 'A': 1}
|
||||
result = 0
|
||||
|
||||
for i in string:
|
||||
width = unicodedata.east_asian_width(i)
|
||||
result += width_mapping[width]
|
||||
|
||||
return result - len(string)
|
||||
|
||||
def ljust(string, pad):
|
||||
return string.ljust(pad - get_excess_column_count(string))
|
||||
|
||||
def rjust(string, pad):
|
||||
return string.rjust(pad - get_excess_column_count(string))
|
||||
|
||||
def output_progress(text, pos, length):
|
||||
if sys.stdout.isatty():
|
||||
(width, _unused) = get_size()
|
||||
progress_text = text.format(100 * pos / length)
|
||||
|
||||
if len(progress_text) > width:
|
||||
progress_text = "...%s" % progress_text[-width+3:]
|
||||
|
||||
print("\r{0}\r{1}".format(" " * width, progress_text), end="")
|
||||
sys.stdout.flush()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -17,17 +17,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from localization import N_
|
||||
from outputable import Outputable
|
||||
import datetime
|
||||
import format
|
||||
import gravatar
|
||||
import terminal
|
||||
import textwrap
|
||||
|
||||
class TimelineData:
|
||||
class TimelineData(object):
|
||||
def __init__(self, changes, useweeks):
|
||||
authordateinfo_list = sorted(changes.get_authordateinfo_list().items())
|
||||
self.changes = changes
|
||||
|
@ -70,7 +63,7 @@ class TimelineData:
|
|||
return self.total_changes_by_period[period]
|
||||
|
||||
def get_authors(self):
|
||||
return sorted(set([(i[0][0], self.changes.get_author_email(i[0][0])) for i in self.entries.items()]))
|
||||
return sorted(set([(i[0][0], self.changes.get_latest_email_by_author(i[0][0])) for i in self.entries.items()]))
|
||||
|
||||
def get_author_signs_in_period(self, author, period, multiplier):
|
||||
authorinfo = self.entries.get((author, period), None)
|
||||
|
@ -105,141 +98,3 @@ class TimelineData:
|
|||
if self.is_author_in_period(period, author):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
TIMELINE_INFO_TEXT = N_("The following history timeline has been gathered from the repository")
|
||||
MODIFIED_ROWS_TEXT = N_("Modified Rows:")
|
||||
|
||||
def __output_row__text__(timeline_data, periods, names):
|
||||
print("\n" + terminal.__bold__ + _("Author").ljust(20), end=" ")
|
||||
|
||||
for period in periods:
|
||||
print(period.rjust(10), end=" ")
|
||||
|
||||
print(terminal.__normal__)
|
||||
|
||||
for name in names:
|
||||
if timeline_data.is_author_in_periods(periods, name[0]):
|
||||
print(name[0].ljust(20)[0:20], end=" ")
|
||||
for period in periods:
|
||||
multiplier = timeline_data.get_multiplier(period, 9)
|
||||
signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier)
|
||||
signs_str = (signs[1] * "-" + signs[0] * "+")
|
||||
print (("." if timeline_data.is_author_in_period(period, name[0]) and
|
||||
len(signs_str) == 0 else signs_str).rjust(10), end=" ")
|
||||
print("")
|
||||
|
||||
print(terminal.__bold__ + _(MODIFIED_ROWS_TEXT).ljust(20) + terminal.__normal__, end=" ")
|
||||
|
||||
for period in periods:
|
||||
total_changes = timeline_data.get_total_changes_in_period(period)
|
||||
print("" + str(total_changes[2]).rjust(10), end=" ")
|
||||
|
||||
print("")
|
||||
|
||||
def __output_row__html__(timeline_data, periods, names):
|
||||
timeline_xml = "<table class=\"git full\"><thead><tr><th>" + _("Author") + "</th>"
|
||||
|
||||
for period in periods:
|
||||
timeline_xml += "<th>" + str(period) + "</th>"
|
||||
|
||||
timeline_xml += "</tr></thead><tbody>"
|
||||
i = 0
|
||||
|
||||
for name in names:
|
||||
if timeline_data.is_author_in_periods(periods, name[0]):
|
||||
timeline_xml += "<tr" + (" class=\"odd\">" if i % 2 == 1 else ">")
|
||||
|
||||
if format.get_selected() == "html":
|
||||
timeline_xml += "<td><img src=\"{0}\"/>{1}</td>".format(gravatar.get_url(name[1]), name[0])
|
||||
else:
|
||||
timeline_xml += "<td>" + name[0] + "</td>"
|
||||
|
||||
for period in periods:
|
||||
multiplier = timeline_data.get_multiplier(period, 18)
|
||||
signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier)
|
||||
signs_str = (signs[1] * "<div class=\"remove\"> </div>" + signs[0] * "<div class=\"insert\"> </div>")
|
||||
|
||||
timeline_xml += "<td>" + ("." if timeline_data.is_author_in_period(period, name[0]) and len(signs_str) == 0 else signs_str)
|
||||
timeline_xml += "</td>"
|
||||
timeline_xml += "</tr>"
|
||||
i = i + 1
|
||||
|
||||
timeline_xml += "<tfoot><tr><td><strong>" + _(MODIFIED_ROWS_TEXT) + "</strong></td>"
|
||||
|
||||
for period in periods:
|
||||
total_changes = timeline_data.get_total_changes_in_period(period)
|
||||
timeline_xml += "<td>" + str(total_changes[2]) + "</td>"
|
||||
|
||||
timeline_xml += "</tr></tfoot></tbody></table>"
|
||||
print(timeline_xml)
|
||||
|
||||
class Timeline(Outputable):
|
||||
def __init__(self, changes, useweeks):
|
||||
self.changes = changes
|
||||
self.useweeks = useweeks
|
||||
Outputable.__init__(self)
|
||||
|
||||
def output_text(self):
|
||||
if self.changes.get_commits():
|
||||
print("\n" + textwrap.fill(_(TIMELINE_INFO_TEXT) + ":", width=terminal.get_size()[0]))
|
||||
|
||||
timeline_data = TimelineData(self.changes, self.useweeks)
|
||||
periods = timeline_data.get_periods()
|
||||
names = timeline_data.get_authors()
|
||||
(width, _unused) = terminal.get_size()
|
||||
max_periods_per_row = int((width - 21) / 11)
|
||||
|
||||
for i in range(0, len(periods), max_periods_per_row):
|
||||
__output_row__text__(timeline_data, periods[i:i+max_periods_per_row], names)
|
||||
|
||||
def output_html(self):
|
||||
if self.changes.get_commits():
|
||||
timeline_data = TimelineData(self.changes, self.useweeks)
|
||||
periods = timeline_data.get_periods()
|
||||
names = timeline_data.get_authors()
|
||||
max_periods_per_row = 8
|
||||
|
||||
timeline_xml = "<div><div id=\"timeline\" class=\"box\">"
|
||||
timeline_xml += "<p>" + _(TIMELINE_INFO_TEXT) + ".</p>"
|
||||
print(timeline_xml)
|
||||
|
||||
for i in range(0, len(periods), max_periods_per_row):
|
||||
__output_row__html__(timeline_data, periods[i:i+max_periods_per_row], names)
|
||||
|
||||
timeline_xml = "</div></div>"
|
||||
print(timeline_xml)
|
||||
|
||||
def output_xml(self):
|
||||
if self.changes.get_commits():
|
||||
message_xml = "\t\t<message>" + _(TIMELINE_INFO_TEXT) + "</message>\n"
|
||||
timeline_xml = ""
|
||||
periods_xml = "\t\t<periods length=\"{0}\">\n".format("week" if self.useweeks else "month")
|
||||
|
||||
timeline_data = TimelineData(self.changes, self.useweeks)
|
||||
periods = timeline_data.get_periods()
|
||||
names = timeline_data.get_authors()
|
||||
|
||||
for period in periods:
|
||||
name_xml = "\t\t\t\t<name>" + str(period) + "</name>\n"
|
||||
authors_xml = "\t\t\t\t<authors>\n"
|
||||
|
||||
for name in names:
|
||||
if timeline_data.is_author_in_period(period, name[0]):
|
||||
multiplier = timeline_data.get_multiplier(period, 24)
|
||||
signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier)
|
||||
signs_str = (signs[1] * "-" + signs[0] * "+")
|
||||
|
||||
if len(signs_str) == 0:
|
||||
signs_str = "."
|
||||
|
||||
authors_xml += "\t\t\t\t\t<author>\n\t\t\t\t\t\t<name>" + name[0] + "</name>\n"
|
||||
authors_xml += "\t\t\t\t\t\t<gravatar>" + gravatar.get_url(name[1]) + "</gravatar>\n"
|
||||
authors_xml += "\t\t\t\t\t\t<work>" + signs_str + "</work>\n\t\t\t\t\t</author>\n"
|
||||
|
||||
authors_xml += "\t\t\t\t</authors>\n"
|
||||
modified_rows_xml = "\t\t\t\t<modified_rows>" + \
|
||||
str(timeline_data.get_total_changes_in_period(period)[2]) + "</modified_rows>\n"
|
||||
timeline_xml += "\t\t\t<period>\n" + name_xml + authors_xml + modified_rows_xml + "\t\t\t</period>\n"
|
||||
|
||||
print("\t<timeline>\n" + message_xml + periods_xml + timeline_xml + "\t\t</periods>\n\t</timeline>")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -14,62 +14,54 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This file was generated with the following command:
|
||||
#
|
||||
# xgettext --no-wrap -s -w 140 --language=Python --keyword="N_"
|
||||
# --no-location --output=messages.pot *.py
|
||||
#
|
||||
#, fuzzy
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.3.1\n"
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2013-07-15 02:57+0200\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Adam Waldenberg <adam.waldenberg@ejwa.se>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr ""
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following historical commit information, by author, was found in the repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr ""
|
||||
|
||||
msgid "Author"
|
||||
msgstr ""
|
||||
|
||||
msgid "Commits"
|
||||
msgstr ""
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Deletions"
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr ""
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr ""
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgid "Age"
|
||||
msgstr ""
|
||||
|
||||
msgid "Author"
|
||||
msgstr ""
|
||||
|
||||
msgid "Below are the number of rows from each author that have survived and are still intact in the current revision"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr ""
|
||||
|
||||
msgid "Commits"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The following repsonsibilties, by author, were found in the current revision of the repository (comments are exluded from the "
|
||||
"line count, if possible)"
|
||||
msgstr ""
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2013 Ejwa Software. All rights reserved.\n"
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
|
@ -77,88 +69,122 @@ msgid ""
|
|||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
|
||||
msgid "gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgid "Deletions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr ""
|
||||
|
||||
msgid "The output has been generated by {0}; the statistical analysis tool for git repositories."
|
||||
msgstr ""
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr ""
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr ""
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgid "Hide minor authors"
|
||||
msgstr ""
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The following files were missing in the repository and were therefore not completely included in the statistical analysis. To "
|
||||
"include them, you can either checkout manually using git or use the -c option in gitinspector"
|
||||
msgid "Insertions"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr ""
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgid "Minor Authors"
|
||||
msgstr ""
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr ""
|
||||
|
||||
msgid "Below are the number of rows from each author that have survived and are still intact in the current revision"
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Rows"
|
||||
msgstr ""
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgid "Show minor authors"
|
||||
msgstr ""
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgid "Show rows with minor work"
|
||||
msgstr ""
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgid "Stability"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr ""
|
||||
|
||||
msgid "The authors with the following emails were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following authors were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following commit revisions were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity (in order of severity)"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity density (in order of severity)"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following files were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following historical commit information, by author, was found in the repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "The following responsibilities, by author, were found in the current revision of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr ""
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "The output has been generated by {0} {1}. The statistical analysis tool for git repositories."
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [DIRECTORY]\n"
|
||||
"List information about the repository in DIRECTORY. If no directory is\n"
|
||||
"specified, the current directory is used. If multiple directories are\n"
|
||||
"given, information will be fetched from the last directory specified.\n"
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -c, --checkout-missing[=BOOL] try to checkout any missing files\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" Specifying * includes files with no\n"
|
||||
" extension, while ** includes all files\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' and\n"
|
||||
" the available formats are:\n"
|
||||
|
@ -185,9 +211,11 @@ msgid ""
|
|||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing file names\n"
|
||||
" that should be excluded from the statistics;\n"
|
||||
" can be specified multiple times\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, revisions with certain\n"
|
||||
" commit messages, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
|
@ -198,3 +226,34 @@ msgid ""
|
|||
"gitinspector requires that the git executable is available in your PATH.\n"
|
||||
"Report gitinspector bugs to gitinspector@ejwa.se."
|
||||
msgstr ""
|
||||
|
||||
msgid "WARNING: The terminal encoding is not correctly configured. gitinspector might malfunction. The encoding can be configured with the environment variable 'PYTHONIOENCODING'."
|
||||
msgstr ""
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr ""
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr ""
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr ""
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr ""
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,319 @@
|
|||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Philipp Nowak <devnull@nowak-at.net>, 2014-2015
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: 2015-10-21 00:25+0200\n"
|
||||
"Last-Translator: Philipp Nowak <devnull@nowak-at.net>\n"
|
||||
"Language-Team: Deutsch <>\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.8.5\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% in Kommentaren"
|
||||
|
||||
# Poedit complains on validate when using a non-valid format specifier after the percent sign, even if separated by a space. It claims that argument number must be equal in both format and message, so can't use the word. Correct translation would be "% gesamt"
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% d. Änderungen"
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(Einbezogene markiert)"
|
||||
|
||||
msgid "Age"
|
||||
msgstr "Alter"
|
||||
|
||||
msgid "Author"
|
||||
msgstr "Autor"
|
||||
|
||||
# spaces because this needs to override the progress message displayed before
|
||||
msgid "Below are the number of rows from each author that have survived and are still intact in the current revision"
|
||||
msgstr "Noch intakte Codezeilen nach Autoren "
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr "Berechne intakte Zeilen pro Autor...{0:.0f}%"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "Commits"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"Copyright © 2012-2015 Ejwa Software. Alle Rechte vorbehalten.\n"
|
||||
"Lizensiert unter der GNU GPL Version 3 oder neuer\n"
|
||||
"Dies ist freie Software, die Sie unter bestimmten Bedingungen weitergeben\n"
|
||||
"dürfen.\n"
|
||||
"\n"
|
||||
"Für dieses Programm besteht KEINERLEI GARANTIE.\n"
|
||||
"Siehe <http://gnu.org/licenses/gpl.html> für Details.\n"
|
||||
"\n"
|
||||
"Geschrieben von Adam Waldenberg."
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "entfernt"
|
||||
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr "Konnte Git Repository \"%s\" nicht verarbeiten."
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "HTML-Ausgabe ist noch nicht unterstützt in"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "Verstecke irrelevante Autoren"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "Verstecke irrelevante Autoren"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "hinzugefügt"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "Sonstige"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "Bearbeitete Zeilen:"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "Keine eingecheckten Dateien mit den angegebenen Endungen gefunden"
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "Im Repo wurde keine Verletzung der Metriken gefunden"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr "Repositorystatistiken für {0}"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "Zeilen"
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "Zeige irrelevante Autoren"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "Zeige irrelevante Autoren"
|
||||
|
||||
msgid "Stability"
|
||||
msgstr "Stabilität"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr "Statistiken für das Repository '{0}' berechnet am {1}."
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "Textausgabe ist noch nicht unterstützt in"
|
||||
|
||||
msgid "The authors with the following emails were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Die Autoren mit den folgenden E-Mail-Adressen wurden von der Statistik ausgeschlossen, da sie zu den Ausschlussmustern passten"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "Gefundene Dateiendungen"
|
||||
|
||||
msgid "The following authors were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Die folgenden Autoren wurden von der Statistik ausgeschlossen, da sie zu den Ausschlussmustern passten"
|
||||
|
||||
msgid "The following commit revisions were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Die folgenden Änderungen wurden von der Statistik ausgeschlossen, da sie zu den Ausschlussmustern passten"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr "Die folgenden Dateien sind verdächtig groß (Geordnet nach Schweregrad)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity (in order of severity)"
|
||||
msgstr "Folgende Dateien haben eine hohe zyklomatische Komplexität (nach Schweregrad)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity density (in order of severity)"
|
||||
msgstr "Die folgenden Dateien haben eine sehr hohe McCabe-Metrik-Dichte (Geordnet nach Schweregrad)"
|
||||
|
||||
msgid "The following files were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Die folgenden Dateien wurden von der Statistik ausgeschlossen, da sie zu den Ausschlussmustern passten"
|
||||
|
||||
msgid "The following historical commit information, by author, was found in the repository"
|
||||
msgstr "Commits nach Autoren"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr "Commitaktivität nach Autoren"
|
||||
|
||||
msgid "The following responsibilities, by author, were found in the current revision of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr "Verantwortlichkeiten nach Autor (Kommentare nach Möglichkeit ignoriert)"
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "Das eingegebene Optionsargument ist kein valider Bool'scher Wert"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "The output has been generated by {0} {1}. The statistical analysis tool for git repositories."
|
||||
msgstr "Die folgende Analyse wurde erstellt mit {0} {1}, dem statistischen Analysetool for Git-Repositories."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "Verwende `{0} --help` für mehr Informationen."
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr "Konnte absoluten Pfad des Repos nicht finden!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" Specifying * includes files with no\n"
|
||||
" extension, while ** includes all files\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' and\n"
|
||||
" the available formats are:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] show statistics and information in a way that\n"
|
||||
" is formatted for grading of student\n"
|
||||
" projects; this is the same as supplying the\n"
|
||||
" options -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] track rows and look for duplicates harder;\n"
|
||||
" this can be quite slow with big repositories\n"
|
||||
" -l, --list-file-types[=BOOL] list all the file extensions available in the\n"
|
||||
" current branch of the repository\n"
|
||||
" -L, --localize-output[=BOOL] localize the generated output to the selected\n"
|
||||
" system language if a translation is\n"
|
||||
" available\n"
|
||||
" -m --metrics[=BOOL] include checks for certain metrics during the\n"
|
||||
" analysis of commits\n"
|
||||
" -r --responsibilities[=BOOL] show which files the different authors seem\n"
|
||||
" most responsible for\n"
|
||||
" --since=DATE only show statistics for commits more recent\n"
|
||||
" than a specific date\n"
|
||||
" -T, --timeline[=BOOL] show commit timeline, including author names\n"
|
||||
" --until=DATE only show statistics for commits older than a\n"
|
||||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, revisions with certain\n"
|
||||
" commit messages, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
"gitinspector will filter statistics to only include commits that modify,\n"
|
||||
"add or remove one of the specified extensions, see -f or --file-types for\n"
|
||||
"more information.\n"
|
||||
"\n"
|
||||
"gitinspector requires that the git executable is available in your PATH.\n"
|
||||
"Report gitinspector bugs to gitinspector@ejwa.se."
|
||||
msgstr ""
|
||||
"Verwendung: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"Zeigt Informationen über das Git-Repository in REPOSITORY. \n"
|
||||
"Wenn kein Repository angegeben wurde, wird das aktuelle\n"
|
||||
"Verzeichnis verwendet. Wenn mehrere angegeben sind,\n"
|
||||
"wird das letzte verwendet.\n"
|
||||
"\n"
|
||||
"Erforderliche Argumente für Langschreibweisen der Optionensind auch\n"
|
||||
"für Kurzschreibweisen erforderlich. Bool'sche Werte (true/false) können\n"
|
||||
"nur mit Langschreibweisen verwendet werden.\n"
|
||||
" -f, --file-types=ENDUNGEN Eine kommagetrennte Liste der\n"
|
||||
" Dateiendungen die in die Analyse\n"
|
||||
" einbezogen werden sollen. Standard:\n"
|
||||
" {1}\n"
|
||||
" * bezieht Dateien ohne Endung ein,\n"
|
||||
" ** bezieht alle Dateien ein.\n"
|
||||
" -F, --format=FORMAT Definiert das Ausgabeformat der\n"
|
||||
" Analyse. Der Standard ist 'text', verfügbar:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] Formatiert Statistiken so, dass\n"
|
||||
" sie zur Bewertung von Schülern verwendet\n"
|
||||
" werden können. Alias für -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] Verfolge Zeilen und suche genauer\n"
|
||||
" nach Duplikaten; Kann bei großen\n"
|
||||
" Repositories sehr lange dauern.\n"
|
||||
" -l, --list-file-types[=BOOL] Zeige alle Datei-Endungen im aktuellen\n"
|
||||
" Git Branch\n"
|
||||
" -L, --localize-output[=BOOL] Übersetze Ausgabe in die Systemsprache,\n"
|
||||
" wenn eine Übersetzung verfügbar ist.\n"
|
||||
" -m --metrics[=BOOL] Beziehe spezielle Metriken in die Analyse von\n"
|
||||
" Commits ein.\n"
|
||||
" -r --responsibilities[=BOOL] Zeige, für welche Dateien die Autoren am\n"
|
||||
" meisten verantwortlich zu sein scheinen.\n"
|
||||
" -T, --timeline[=BOOL] Berechne Commit-Zeitstrahl (nach Autoren)\n"
|
||||
" --since=DATE Analysiere nur ab einem bestimmten Datum\n"
|
||||
" --until=DATE Analysiere nur vor einem bestimmten Datum\n"
|
||||
" -w, --weeks[=BOOL] Stelle Statisiken in Wochen statt Monaten dar\n"
|
||||
" -x, --exclude=PATTERN Ausschlussmuster für Dateipfade,\n"
|
||||
" Commithashes, Commitnachrichten,\n"
|
||||
" Autorennamen oder -E-Mails, die von\n"
|
||||
" der Analyse ausgeschlossen werden\n"
|
||||
" sollen; Kann mehrmals angegeben werden\n"
|
||||
" -h, --help Zeige diese Nachricht und beende\n"
|
||||
" --version Zeige Version und beende\n"
|
||||
"\n"
|
||||
"gitinspector zeigt nur Statistiken zu Commits, die Dateien\n"
|
||||
"mit bestimmten Endungen bearbeiten, hinzufügen oder\n"
|
||||
"löschen. Siehe -f oder --file-types für mehr informationen.\n"
|
||||
"\n"
|
||||
"gitinspector benötigt git in PATH.\n"
|
||||
"Melde Bugs an gitinspector@ejwa.se."
|
||||
|
||||
msgid "WARNING: The terminal encoding is not correctly configured. gitinspector might malfunction. The encoding can be configured with the environment variable 'PYTHONIOENCODING'."
|
||||
msgstr "WARNUNG: Das Terminal ist nicht richtig konfiguriert. Gitinspector könnte Probleme haben. Die Kodierung kann mit der Umgebungsvariable `PYTHONIOENCODING` konfiguriert werden."
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "XML-Ausgabe ist noch nicht unterstützt in"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "Gitinspector benötigt zumindest Python 2.6 (Du verwendest {0})"
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "Invalider regulärer Ausdruck angegeben"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "ist am meisten verantwortlich für"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "Das angegebene Ausgabeformat wird nicht unterstützt."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr "{0} (zyklomatische Komplexitätsdichte: {1:.3f})"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr "{0} ({1} geschätzte Codezeilen)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr "{0} (zyklomatische Komplexität: {1})"
|
Binary file not shown.
|
@ -0,0 +1,413 @@
|
|||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Agustín Cañas <agustincanas@gmail.com>, 2015
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: 2015-10-02 22:17+0100\n"
|
||||
"Last-Translator: Agustín Cañas <agustincanas@gmail.com>\n"
|
||||
"Language-Team: Spanish <>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% en comentarios"
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% de cambios"
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(se marcan las extensiones usadas durante el análisis)"
|
||||
|
||||
msgid "Age"
|
||||
msgstr "Edad"
|
||||
|
||||
msgid "Author"
|
||||
msgstr "Autor"
|
||||
|
||||
msgid ""
|
||||
"Below are the number of rows from each author that have survived and are "
|
||||
"still intact in the current revision"
|
||||
msgstr ""
|
||||
"El bloque siguiente muestra el número de líneas de cada autor que todavía "
|
||||
"permanecen intactas en la versión actual"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr ""
|
||||
"Comprobando cuantas líneas pertenecen a cada autor (Progreso): {0:.0f}%"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "Commits"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"Copyright © 2012-2015 Ejwa Software. Todos los derechos reservados.\n"
|
||||
"Este programa es software libre. Puede redistribuirlo y/o modificarlo bajo\n"
|
||||
"los términos de la Licencia Pública General de GNU tal como está publicada\n"
|
||||
"por la Free Software Foundation, bien de la versión 3 de dicha Licencia o\n"
|
||||
"bien (según su elección) de cualquier versión posterior.\n"
|
||||
"Esta aplicación es software libre: usted es libre de modificarlo y \n"
|
||||
"redistribuirlo.\n"
|
||||
"Este programa se distribuye con la esperanza de que sea útil, pero SIN\n"
|
||||
"NINGUNA GARANTÍA, incluso sin la garantía MERCANTIL implícita o sin\n"
|
||||
"garantizar la CONVENIENCIA PARA UN PROPÓSITO PARTICULAR. Véase la Licencia \n"
|
||||
"Pública General de GNU para más detalles <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"Escrito por Adam Waldenberg."
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "Borrados"
|
||||
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr "Error procesando el repositorio \"%s\""
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "La salida en HTML no está soportada"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "Ocultar los autores menos prolíficos"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "Ocultar las filas con menor trabajo"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "Inserciones"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "Autores menos prolíficos"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "Líneas modificadas:"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "No se encontraron archivos comiteados con la extensión especificada"
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "No se encontraron violaciones de la métrica en el repositorio"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr "Estadísticas del repositorio para {0}"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "Registros"
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "Mostrar los autores menos prolíficos"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "Mostrar las aportaciones menores"
|
||||
|
||||
msgid "Stability"
|
||||
msgstr "Estabilidad"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr "Información estadística para el repositorio '{0}' obtenida en {1}."
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "La salida de tipo texto no está soportada"
|
||||
|
||||
msgid ""
|
||||
"The authors with the following emails were excluded from the statistics due "
|
||||
"to the specified exclusion patterns"
|
||||
msgstr ""
|
||||
"Los autores con las siguientes direcciones de correo fueron excluidos según "
|
||||
"los patrones de exclusión especificados"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "En el repositorio se encontraron las siguientes extensiones"
|
||||
|
||||
msgid ""
|
||||
"The following authors were excluded from the statistics due to the specified "
|
||||
"exclusion patterns"
|
||||
msgstr ""
|
||||
"Los autores siguientes fueron excluidos de las estadísticas según los "
|
||||
"patrones de exclusión especificados"
|
||||
|
||||
msgid ""
|
||||
"The following commit revisions were excluded from the statistics due to the "
|
||||
"specified exclusion patterns"
|
||||
msgstr ""
|
||||
"Los siguientes commits fueron excluidos de las estadísticas por los "
|
||||
"patrones de exclusión especificados"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr "Los siguientes ficheros son sospechosamente grandes (listados en "
|
||||
"orden de severidad)"
|
||||
|
||||
msgid ""
|
||||
"The following files have an elevated cyclomatic complexity (in order of "
|
||||
"severity)"
|
||||
msgstr "Los siguientes ficheros tienen una elevada cyclomatic complexity "
|
||||
"(listados en orden de severidad)"
|
||||
|
||||
msgid ""
|
||||
"The following files have an elevated cyclomatic complexity density (in order "
|
||||
"of severity)"
|
||||
msgstr "Los siguientes ficheros tienen una elevada cyclomatic complexity "
|
||||
"density (listados en orden de severidad)"
|
||||
|
||||
msgid ""
|
||||
"The following files were excluded from the statistics due to the specified "
|
||||
"exclusion patterns"
|
||||
msgstr ""
|
||||
"Los siguientes ficheros fueron excluidos de las estadísticas por los "
|
||||
"patrones de exclusión especificados"
|
||||
|
||||
msgid ""
|
||||
"The following historical commit information, by author, was found in the "
|
||||
"repository"
|
||||
msgstr "Se encontró en el repositorio el siguiente histórico de commits "
|
||||
"(clasificado por autor)"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr ""
|
||||
"Se ha obtenido del repositorio la siguiente línea temporal"
|
||||
|
||||
msgid ""
|
||||
"The following responsibilities, by author, were found in the current revision "
|
||||
"of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr ""
|
||||
"A continuación se presentan para cada autor los ficheros en los que ha "
|
||||
"tenido mayor responsabilidad o impacto (en la medida de lo posible se han "
|
||||
"excluido las líneas con comentarios)"
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "El argumento especificado no es de tipo booleano"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"The output has been generated by {0} {1}. The statistical analysis tool for "
|
||||
"git repositories."
|
||||
msgstr ""
|
||||
"La salida ha sido generada por {0} {1}. La herramienta de análisis "
|
||||
"estadístico para repositorios git"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "Teclea '{0} --help' para obtener más información"
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr "No se ha podido determinar la ruta absoluta al repositorio git"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions "
|
||||
"to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' "
|
||||
"and\n"
|
||||
" the available formats are:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] show statistics and information in a way "
|
||||
"that\n"
|
||||
" is formatted for grading of student\n"
|
||||
" projects; this is the same as supplying "
|
||||
"the\n"
|
||||
" options -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] track rows and look for duplicates harder;\n"
|
||||
" this can be quite slow with big "
|
||||
"repositories\n"
|
||||
" -l, --list-file-types[=BOOL] list all the file extensions available in "
|
||||
"the\n"
|
||||
" current branch of the repository\n"
|
||||
" -L, --localize-output[=BOOL] localize the generated output to the "
|
||||
"selected\n"
|
||||
" system language if a translation is\n"
|
||||
" available\n"
|
||||
" -m --metrics[=BOOL] include checks for certain metrics during "
|
||||
"the\n"
|
||||
" analysis of commits\n"
|
||||
" -r --responsibilities[=BOOL] show which files the different authors "
|
||||
"seem\n"
|
||||
" most responsible for\n"
|
||||
" --since=DATE only show statistics for commits more "
|
||||
"recent\n"
|
||||
" than a specific date\n"
|
||||
" -T, --timeline[=BOOL] show commit timeline, including author "
|
||||
"names\n"
|
||||
" --until=DATE only show statistics for commits older than "
|
||||
"a\n"
|
||||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple "
|
||||
"times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
"gitinspector will filter statistics to only include commits that modify,\n"
|
||||
"add or remove one of the specified extensions, see -f or --file-types for\n"
|
||||
"more information.\n"
|
||||
"\n"
|
||||
"gitinspector requires that the git executable is available in your PATH.\n"
|
||||
"Report gitinspector bugs to gitinspector@ejwa.se."
|
||||
msgstr ""
|
||||
"Uso: {0} [OPCIÓN]... [REPOSITORIO]\n"
|
||||
"Lista información sobre el repositorio en REPOSITORIO. Si no se especifica \n"
|
||||
"un repositorio se usará el directorio actual. Si se indican varios \n"
|
||||
"repositorios, se extraerá la información del último de ellos\n"
|
||||
"\n"
|
||||
"Los argumentos obligatorios son necesarios tanto usando las opciones largas \n"
|
||||
"como las cortas. Los argumentos de tipo booleano solo pueden combinarse \n"
|
||||
"con opciones largas\n"
|
||||
" -f, --file-types=EXTENSIONES una lista de extensiones (separadas por"
|
||||
" \n"
|
||||
" comas) que se incluirán al extraer "
|
||||
"las \n"
|
||||
" estadísticas. Se incluyen por "
|
||||
"defecto:\n"
|
||||
" {1}\n"
|
||||
" Indicando * se incluirán ficheros "
|
||||
"sin\n"
|
||||
" extensión; con ** se incluirán todos"
|
||||
"\n"
|
||||
" -F, --format=FORMATO define el formato de salida que se "
|
||||
"quiere \n"
|
||||
" generar; el formato por defecto es \n"
|
||||
" 'text' y los formatos disponibles "
|
||||
"son:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOLEANO] muestra estadísticas e información \n"
|
||||
" formateada para valorar el trabajo "
|
||||
"de\n"
|
||||
" un estudiante; es equivalente a "
|
||||
"usar\n"
|
||||
" las opciones -HlmrTw\n"
|
||||
" -H, --hard[=BOOLEANO] hace un seguimiento de las filas y "
|
||||
"busca\n"
|
||||
" duplicados; este análisis puede ser"
|
||||
"\n"
|
||||
" algo lento con repositorios grandes\n"
|
||||
" -l, --list-file-types[=BOOLEANO] muestra todas las extensiones\n"
|
||||
" disponibles en la rama actual del\n"
|
||||
" repositorio\n"
|
||||
" -L, --localize-output[=BOOLEANO] si está disponible, formatea la salida "
|
||||
"en\n"
|
||||
" el idioma del sistema\n"
|
||||
" -m --metrics[=BOOLEANO] incluye comprobaciones para ciertas \n"
|
||||
" métricas durante el análisis de los\n"
|
||||
" commits\n"
|
||||
" -r --responsibilities[=BOOLEANO] muestra para cada autor cuáles son "
|
||||
"los\n"
|
||||
" ficheros en los que parece tener "
|
||||
"mayor\n"
|
||||
" participación\n"
|
||||
" --since=FECHA solo muestra estadísticas para los \n"
|
||||
" commits realizados desde una fecha\n"
|
||||
" determinada\n"
|
||||
" -T, --timeline[=BOOLEANO] muestra los commits en la línea de\n"
|
||||
" tiempo, autor y nombres\n"
|
||||
" --until=FECHA solo muestra estadísticas para commits"
|
||||
"\n"
|
||||
" realizados hasta la fecha "
|
||||
"especificada\n"
|
||||
" -w, --weeks[=BOOLEANO] muestra la información estadística en\n"
|
||||
" semanas en lugar de meses\n"
|
||||
" -x, --exclude=PATRÓN un patrón de exclusión para las rutas "
|
||||
"de\n"
|
||||
" los ficheros, las revisiones, las\n"
|
||||
" revisiones con ciertos mensajes de \n"
|
||||
" commit, los nombres de los autores o "
|
||||
"sus\n"
|
||||
" direcciones de correo electrónico "
|
||||
"que\n"
|
||||
" se desea excluir; pueden indicarse\n"
|
||||
" varios patrones\n"
|
||||
" -h, --help muestra la ayuda y sale\n"
|
||||
" --version muestra información de la versión y "
|
||||
"sale\n"
|
||||
"\n"
|
||||
"gitinspector filtrará las estadísticas para incluir commits que modifiquen,\n"
|
||||
"añaden o eliminen una de las extensiones especificadas, ver -f or "
|
||||
"--file-types para\n"
|
||||
"obtener más información\n"
|
||||
"\n"
|
||||
"gitinspector necesita que el ejecutable git este disponible en el PATH\n"
|
||||
"Por favor, si encuentras errores en gitinspector ponte en contacto en\n"
|
||||
"gitinspector@ejwa.se."
|
||||
|
||||
msgid ""
|
||||
"WARNING: The terminal encoding is not correctly configured. gitinspector "
|
||||
"might malfunction. The encoding can be configured with the environment "
|
||||
"variable 'PYTHONIOENCODING'."
|
||||
msgstr ""
|
||||
"PRECAUCIÓN: La codificación del terminal no está configurada correctamente"
|
||||
"gitinspector podría no funcionar de forma correcta. La codificación puede "
|
||||
"configurarse con la variable `PYTHONIOENCODING`"
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "La salida en XML no esta aún soportada"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "Gitinspector requiere al menos Python 2.6 (se ha encontrado la versión"
|
||||
" {0})"
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "La expresión regular especificada no es válida"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "es principalmente responsable de:"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "el formato de salida especificado no está soportado"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr "{0} En cyclomatic complexity density: {1:.3f})"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr "{0} ({1} líneas de código estimadas)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr "{0} (en cyclomatic complexity: {1})"
|
Binary file not shown.
|
@ -0,0 +1,412 @@
|
|||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Yannick Moy <yannick.moy@gmail.com>, 2014-2015
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: 2015-10-25 21:56+0100\n"
|
||||
"Last-Translator: Yannick Moy <yannick.moy@gmail.com>\n"
|
||||
"Language-Team: French <>\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"
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% en commentaires"
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% de modifications"
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(les extensions utilisées durant l'analyse statistique sont marquées)"
|
||||
|
||||
msgid "Age"
|
||||
msgstr "Âge"
|
||||
|
||||
msgid "Author"
|
||||
msgstr "Auteur"
|
||||
|
||||
msgid ""
|
||||
"Below are the number of rows from each author that have survived and are "
|
||||
"still intact in the current revision"
|
||||
msgstr ""
|
||||
"Le nombre de lignes par auteur encore présentes et intactes dans la version "
|
||||
"courante est reporté ci-dessous"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr ""
|
||||
"Contrôle du nombre de lignes appartenant à chaque auteur (En progrès) : "
|
||||
"{0:.0f}%"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "Soumissions"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"Copyright © 2012-2015 Ejwa Software. Tous droits réservés.\n"
|
||||
"Licence GPLv3+: GNU GPL version 3 ou ultérieure <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"Le présent logiciel est un logiciel libre: you pouvez le modifier et le "
|
||||
"redistributer librement.\n"
|
||||
"Il n'y a AUCUNE GARANTIE, dans les limites autorisées par la loi.\n"
|
||||
"\n"
|
||||
"Écrit par Adam Waldenberg."
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "Suppressions"
|
||||
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr "Erreur pendant l'analyse du dépôt git"
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "Sortie HTML pas encore prise en charge pour"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "Masquer les auteurs mineurs"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "Masquer les lignes avec le moins de travail"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "Insertions"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "Auteurs mineurs"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "Lignes modifiées:"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "Aucun fichier soumis avec l'extension spécifiée n'a été trouvé"
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "Aucune violation des métriques n'a été constatée dans le dépôt"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr "Statistiques du dépôt {0}"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "Lignes"
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "Montrer les auteurs mineurs"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "Montrer les lignes avec le moins de travail"
|
||||
|
||||
msgid "Stability"
|
||||
msgstr "Stabilité"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr ""
|
||||
"Les informations statistiques pour le dépôt '{0}' ont été extraites le {1}."
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "Sortie textuelle pas encore prise en charge pour"
|
||||
|
||||
msgid ""
|
||||
"The authors with the following emails were excluded from the statistics due "
|
||||
"to the specified exclusion patterns"
|
||||
msgstr ""
|
||||
"Les auteurs avec les adresses e-mail suivantes ont été exclus des "
|
||||
"statistiques en raison des filtres d'exclusion spécifiés"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "Les extensions suivantes ont été trouvées dans l'historique du dépôt"
|
||||
|
||||
msgid ""
|
||||
"The following authors were excluded from the statistics due to the specified "
|
||||
"exclusion patterns"
|
||||
msgstr ""
|
||||
"Les auteurs suivants ont été exclus des statistiques en raison des filtres "
|
||||
"d'exclusion spécifiés"
|
||||
|
||||
msgid ""
|
||||
"The following commit revisions were excluded from the statistics due to the "
|
||||
"specified exclusion patterns"
|
||||
msgstr ""
|
||||
"Les soumissions suivantes ont été exclues des statistiques en raison des "
|
||||
"filtres d'exclusion spécifiés"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr "Les fichiers suivants sont étrangement gros (par ordre d'importance)"
|
||||
|
||||
msgid ""
|
||||
"The following files have an elevated cyclomatic complexity (in order of "
|
||||
"severity)"
|
||||
msgstr ""
|
||||
"Les fichiers suivants ont une complexité cyclomatique étrangement élevée "
|
||||
"(par ordre d'importance)"
|
||||
|
||||
msgid ""
|
||||
"The following files have an elevated cyclomatic complexity density (in order "
|
||||
"of severity)"
|
||||
msgstr ""
|
||||
"Les fichiers suivants ont une densité de complexité cyclomatique étrangement "
|
||||
"élevée (par ordre d'importance)"
|
||||
|
||||
msgid ""
|
||||
"The following files were excluded from the statistics due to the specified "
|
||||
"exclusion patterns"
|
||||
msgstr ""
|
||||
"Les fichiers suivants ont été exclus des statistiques en raison des filtres "
|
||||
"d'exclusion spécifiés"
|
||||
|
||||
msgid ""
|
||||
"The following historical commit information, by author, was found in the "
|
||||
"repository"
|
||||
msgstr ""
|
||||
"Les informations suivantes, par auteur, ont été extraites de l'historique de "
|
||||
"soumission du dépôt"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr "La chronologie suivante a été extraite du dépôt"
|
||||
|
||||
msgid ""
|
||||
"The following responsibilities, by author, were found in the current revision "
|
||||
"of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr ""
|
||||
"Les responsabilités suivantes, par auteur, ont été extraites de la version "
|
||||
"courante du dépôt (les commentaires sont exclus du compte des lignes, quand "
|
||||
"c'est possible)"
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "L'option passée en argument n'est pas un booléen valide."
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"The output has been generated by {0} {1}. The statistical analysis tool for "
|
||||
"git repositories."
|
||||
msgstr ""
|
||||
"Cette sortie a été générée par {0} {1}. L'outil d'analyse statistique pour "
|
||||
"les dépôts git."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "Entrez `{0} --help' pour plus d'information."
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr "Impossible de déterminer le chemin absolu du dépôt git."
|
||||
|
||||
#, fuzzy, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions "
|
||||
"to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" Specifying * includes files with no\n"
|
||||
" extension, while ** includes all files\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' "
|
||||
"and\n"
|
||||
" the available formats are:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] show statistics and information in a way "
|
||||
"that\n"
|
||||
" is formatted for grading of student\n"
|
||||
" projects; this is the same as supplying "
|
||||
"the\n"
|
||||
" options -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] track rows and look for duplicates harder;\n"
|
||||
" this can be quite slow with big "
|
||||
"repositories\n"
|
||||
" -l, --list-file-types[=BOOL] list all the file extensions available in "
|
||||
"the\n"
|
||||
" current branch of the repository\n"
|
||||
" -L, --localize-output[=BOOL] localize the generated output to the "
|
||||
"selected\n"
|
||||
" system language if a translation is\n"
|
||||
" available\n"
|
||||
" -m --metrics[=BOOL] include checks for certain metrics during "
|
||||
"the\n"
|
||||
" analysis of commits\n"
|
||||
" -r --responsibilities[=BOOL] show which files the different authors "
|
||||
"seem\n"
|
||||
" most responsible for\n"
|
||||
" --since=DATE only show statistics for commits more "
|
||||
"recent\n"
|
||||
" than a specific date\n"
|
||||
" -T, --timeline[=BOOL] show commit timeline, including author "
|
||||
"names\n"
|
||||
" --until=DATE only show statistics for commits older than "
|
||||
"a\n"
|
||||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, revisions with certain\n"
|
||||
" commit messages, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple "
|
||||
"times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
"gitinspector will filter statistics to only include commits that modify,\n"
|
||||
"add or remove one of the specified extensions, see -f or --file-types for\n"
|
||||
"more information.\n"
|
||||
"\n"
|
||||
"gitinspector requires that the git executable is available in your PATH.\n"
|
||||
"Report gitinspector bugs to gitinspector@ejwa.se."
|
||||
msgstr ""
|
||||
"Utilisation: {0} [OPTION]... [RÉPERTOIRE]\n"
|
||||
"Génère les informations sur le dépôt dans RÉPERTOIRE. Si aucun répertoire\n"
|
||||
"n'est spécifié, le répertoire courant est utilisé. Si plusieurs répertoires\n"
|
||||
"sont spécifiés, les informations seront données pour le dernier répertoire\n"
|
||||
"spécifié.\n"
|
||||
"\n"
|
||||
"Les arguments obligatoires pour les options longues sont également "
|
||||
"obligatoires\n"
|
||||
"pour les options courtes.\n"
|
||||
"Les argument booléens peuvent seulement être passés aux options longues.\n"
|
||||
" -f, --file-types=EXTENSIONS liste séparée par des virgules des "
|
||||
"extensions\n"
|
||||
" de fichiers à considérer pour calculer "
|
||||
"les\n"
|
||||
" statistiques. Les extensions par défaut\n"
|
||||
" sont:\n"
|
||||
" {1}\n"
|
||||
" Utiliser * pour inclure les fichiers\n"
|
||||
" sans extension, et ** pour inclure tous\n"
|
||||
" les fichiers\n"
|
||||
" -F, --format=FORMAT définit le format de sortie à générer ;\n"
|
||||
" le format par défaut est 'text' et\n"
|
||||
" les formats disponibles sont:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] montre les statistiques et les "
|
||||
"informations\n"
|
||||
" sous un format adapté pour noter des "
|
||||
"projets\n"
|
||||
" étudiants ; équivalent aux options -"
|
||||
"HlmrTw\n"
|
||||
" -H, --hard[=BOOL] suit les lignes et cherche les duplications "
|
||||
"de\n"
|
||||
" manière plus approfondie ; cela peut "
|
||||
"être\n"
|
||||
" assez long pour les dépôts très gros\n"
|
||||
" -l, --list-file-types[=BOOL] énumère les extensions de fichiers "
|
||||
"disponibles\n"
|
||||
" dans la branche courante du dépôt\n"
|
||||
" -L, --localize-output[=BOOL] traduit la sortie générée dans la langue\n"
|
||||
" système sélectionnée, si une traduction "
|
||||
"est\n"
|
||||
" disponible\n"
|
||||
" -m --metrics[=BOOL] inclut des contrôles pour certaines "
|
||||
"métriques\n"
|
||||
" durant l'analyse des soumissions\n"
|
||||
" -r --responsibilities[=BOOL] montre de quels fichiers les différents "
|
||||
"auteurs\n"
|
||||
" semblent être responsables\n"
|
||||
" --since=DATE montre les statistiques seulement pour les\n"
|
||||
" soumissions plus récentes qu'une date\n"
|
||||
" spécifiée\n"
|
||||
" -T, --timeline[=BOOL] montre une chronologie des soumissions,\n"
|
||||
" incluant le nom des auteurs\n"
|
||||
" --until=DATE montre les statistiques seulement pour les\n"
|
||||
" soumissions plus anciennes qu'une date\n"
|
||||
" spécifiée\n"
|
||||
" -w, --weeks[=BOOL] montre toutes les informations statistiques "
|
||||
"en\n"
|
||||
" semaines plutôt qu'en mois\n"
|
||||
" -x, --exclude=PATTERN un filtre d'exclusion pour les noms de "
|
||||
"fichiers,\n"
|
||||
" soumissions, soumissions avec certains\n"
|
||||
" messages de soumission, noms d'auteurs "
|
||||
"ou\n"
|
||||
" e-mails à exclure des statistiques ;\n"
|
||||
" peut être spécifié plusieurs fois\n"
|
||||
" -h, --help affiche ce message d'aide et quitte\n"
|
||||
" le programme\n"
|
||||
" --version affiche les informations de version et "
|
||||
"quitte\n"
|
||||
" le programme\n"
|
||||
"\n"
|
||||
"gitinspector filtre les statistiques pour n'inclure que les soumissions "
|
||||
"qui \n"
|
||||
"modifient, ajoutent ou retirent un fichier avec une des extensions "
|
||||
"spécifiées, \n"
|
||||
"voir -f ou --file-type pour plus d'information.\n"
|
||||
"\n"
|
||||
"gitinspector nécessite que l'exécutable git soit trouvé dans le PATH.\n"
|
||||
"Signalez les bugs dans gitinspector à gitinspector@ejwa.se."
|
||||
|
||||
msgid ""
|
||||
"WARNING: The terminal encoding is not correctly configured. gitinspector "
|
||||
"might malfunction. The encoding can be configured with the environment "
|
||||
"variable 'PYTHONIOENCODING'."
|
||||
msgstr ""
|
||||
"ATTENTION: L'encodage du terminal n'est pas configuré correctement. "
|
||||
"gitinspector pourrait ne pas fonctionner correctement. L'encodage peut être "
|
||||
"configuré avec la variable d'environnement 'PYTHONIOENCODING'."
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "Sortie XML pas encore prise en charge pour"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr ""
|
||||
"gitinspector nécessite Python 2.6 ou une version ultérieure (la version "
|
||||
"trouvée est {0})."
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "l'expression régulière spécifiée est invalide"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "est principalement responsable de"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "format de sortie spécifié non pris en charge."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr "{0} ({1:.3f} en densité de complexité cyclomatique)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr "{0} ({1} lignes de code estimées)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr "{0} ({1} en complexité cyclomatique)"
|
Binary file not shown.
|
@ -0,0 +1,317 @@
|
|||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Luca Motta <lucamot@gmail.com>, 2014-2015.
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: 2015-10-26 08:50+0100\n"
|
||||
"Last-Translator: Luca Motta <lucamot@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language-Team: Italiano <>\n"
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% in commenti"
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% dei cambiamenti"
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(le estensioni usate nell'analisi statistica sono evidenziate)"
|
||||
|
||||
msgid "Age"
|
||||
msgstr "Età"
|
||||
|
||||
msgid "Author"
|
||||
msgstr "Autore"
|
||||
|
||||
msgid "Below are the number of rows from each author that have survived and are still intact in the current revision"
|
||||
msgstr "Di seguito il numero di righe da ogni autore che sono sopravvissute a sono ancora intatte nella versione corrente"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr "Controllo quante righe appartengono ad ogni autore (Completamento): {0:.0f}%"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "Commit"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"Copyright © 2012-2015 Ejwa Software. Tutti i diritti riservati.\n"
|
||||
"Licenza GPLv3+: GNU GPL versione 3 or successive <http://gnu.org/licenses/gpl.html>.\n"
|
||||
"Questo software è gratuito: siete liberi di cambiarlo e ridistribuirlo.\n"
|
||||
"NON CI SONO GARANZIE, nei limiti permessi dalla legge.\n"
|
||||
"\n"
|
||||
"Scritto by Adam Waldenberg."
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "Rimozioni"
|
||||
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr "Errore nel processamento del repository GIT \"%s\"."
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "Output HTML non ancora supportato"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "Nascondi autori minori"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "Nascondi righe con lavoro secondario"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "Inserimenti"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "Autori secondari"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "Righe modificate:"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "Non sono stati trovati file committati con l'estensione specificata"
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "Non sono state rilevate violazioni delle metriche nel repository"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr "Statistiche del repository per {0}"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "Righe"
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "Visualizza autori secondari"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "Visualizza righe con lavoro secondario"
|
||||
|
||||
msgid "Stability"
|
||||
msgstr "Stabilità"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr "Informazioni statistiche per il repository '{0}' raccolte in {1}."
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "Output testuale non ancora supportato"
|
||||
|
||||
msgid "The authors with the following emails were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Gli autori con le seguenti email sono stati esclusi dalle statistiche come da pattern di esclusione"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "Le seguenti estensioni sono state trovate nell'history del repository"
|
||||
|
||||
msgid "The following authors were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "I seguenti autori sono stati esclusi dalle statistiche come da pattern di esclusione"
|
||||
|
||||
msgid "The following commit revisions were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Le revision seguenti sono state escluse dalle statistiche come da pattern di esclusione"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr "I seguenti file sono stranamente grandi (in ordine di importanza)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity (in order of severity)"
|
||||
msgstr "I seguenti file hanno un'elevata complessità ciclomatica (in ordine di importanza)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity density (in order of severity)"
|
||||
msgstr "I seguenti file hanno un'elevata densità ciclomatica (in ordine di importanza)"
|
||||
|
||||
msgid "The following files were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "I seguenti file sono stati esclusi dalle statistiche come da pattern di esclusione"
|
||||
|
||||
msgid "The following historical commit information, by author, was found in the repository"
|
||||
msgstr "Le seguenti informazioni storiche sui commit, per autore, sono state trovate nel repository"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr "La seguente timeline storica è stata ricavata dal repository"
|
||||
|
||||
msgid "The following responsibilities, by author, were found in the current revision of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr "Le seguenti responsabilità, per autore, sono state trovate nella revision corrente del repository (i commenti sono esclusi dal conteggio delle linee, se possibile)"
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "L'argomento opzionale passato non è un valore booleano valido."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "The output has been generated by {0} {1}. The statistical analysis tool for git repositories."
|
||||
msgstr "L'output è stato generato da {0} {1}. Il tool di analisi statistica per repository GIT."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "`{0} --help' per maggiori informazioni."
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr "Impossibile determinare un path assoluto di un repository GIT."
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" Specifying * includes files with no\n"
|
||||
" extension, while ** includes all files\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' and\n"
|
||||
" the available formats are:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] show statistics and information in a way that\n"
|
||||
" is formatted for grading of student\n"
|
||||
" projects; this is the same as supplying the\n"
|
||||
" options -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] track rows and look for duplicates harder;\n"
|
||||
" this can be quite slow with big repositories\n"
|
||||
" -l, --list-file-types[=BOOL] list all the file extensions available in the\n"
|
||||
" current branch of the repository\n"
|
||||
" -L, --localize-output[=BOOL] localize the generated output to the selected\n"
|
||||
" system language if a translation is\n"
|
||||
" available\n"
|
||||
" -m --metrics[=BOOL] include checks for certain metrics during the\n"
|
||||
" analysis of commits\n"
|
||||
" -r --responsibilities[=BOOL] show which files the different authors seem\n"
|
||||
" most responsible for\n"
|
||||
" --since=DATE only show statistics for commits more recent\n"
|
||||
" than a specific date\n"
|
||||
" -T, --timeline[=BOOL] show commit timeline, including author names\n"
|
||||
" --until=DATE only show statistics for commits older than a\n"
|
||||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, revisions with certain\n"
|
||||
" commit messages, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
"gitinspector will filter statistics to only include commits that modify,\n"
|
||||
"add or remove one of the specified extensions, see -f or --file-types for\n"
|
||||
"more information.\n"
|
||||
"\n"
|
||||
"gitinspector requires that the git executable is available in your PATH.\n"
|
||||
"Report gitinspector bugs to gitinspector@ejwa.se."
|
||||
msgstr ""
|
||||
"Uso: {0} [OPZIONE]... [REPOSITORY]\n"
|
||||
"Elenca le informazioni sul repository in REPOSITORY. Se non si specifica\n"
|
||||
"un repository, usa la directory corrente. Se sono passati più repository,\n"
|
||||
"le informazioni saranno raccolte dall'ultimo dei repository specificati.\n"
|
||||
"\n"
|
||||
"Gli argomenti obbligatori per le opzioni in formato esteso sono obbligatori\n"
|
||||
"anche per le opzioni in formato ridotto.\n"
|
||||
"Gli argomenti booleani possono essere passati solo alle opzioni estese.\n"
|
||||
" -f, --file-types=EXTENSIONS lista separate da virgole di estensioni da\n"
|
||||
" includere quando si calcolano le\n"
|
||||
" statistiche. Le estensioni di default\n"
|
||||
" usate sono:\n"
|
||||
" {1}\n"
|
||||
" Specificando * si includono i file senza\n"
|
||||
" estensione mentre ** include tutti i file\n"
|
||||
" -F, --format=FORMAT definisce in che formato deve essere l'output;\n"
|
||||
" il formato di default è 'text' e quelli\n"
|
||||
" disponibili sono:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] visualizza le informazionie e le statistiche\n"
|
||||
" formattate per i progetti da studente; è\n"
|
||||
" equivalente alle opzioni -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] traccia le righe e cerca i duplicati in modo\n"
|
||||
" più approfondito; può essere molto lento\n"
|
||||
" per repository grandi\n"
|
||||
" -l, --list-file-types[=BOOL] elenca le estensioni disponibili nel branch\n"
|
||||
" corrente del repository\n"
|
||||
" -L, --localize-output[=BOOL] localizza l'output generato nella lingua\n"
|
||||
" selezionata, se è disponibile\n"
|
||||
" -m --metrics[=BOOL] include controlli per alcune metriche durante\n"
|
||||
" l'analisi dei commit\n"
|
||||
" -r --responsibilities[=BOOL] visualizza quali autori sembrano essere più\n"
|
||||
" responsabili di determinati file\n"
|
||||
" --since=DATE visualizza solo le statistiche per i commit\n"
|
||||
" più recenti di una data specifica\n"
|
||||
" -T, --timeline[=BOOL] visualizza la timeline dei commit, inclusi i\n"
|
||||
" nomi degli autori\n"
|
||||
" --until=DATE visualizza solo le statistiche per i commit\n"
|
||||
" più vecchi di una data specifica\n"
|
||||
" -w, --weeks[=BOOL] visualizza tutte le informazioni statistiche\n"
|
||||
" per settimane anziché per mesi\n"
|
||||
" -x, --exclude=PATTERN pattern di esclusione che descrivono percorsi\n"
|
||||
" di file, revision, revision con determinati\n"
|
||||
" messaggi, nomi di autori o email di autori\n"
|
||||
" che devono essere esclusi dalle statistiche;\n"
|
||||
" può essere specificato più di una volta\n"
|
||||
" -h, --help visualizza questo messaggio ed esce\n"
|
||||
" --version visualizza le informazioni sulla versione ed\n"
|
||||
" esce\n"
|
||||
"\n"
|
||||
"gitinspector filtrerà le statistiche per includere solo commit che modificano,\n"
|
||||
"aggiungono o rimuovono una delle estensioni specificate, vedere -f o\n"
|
||||
"--file-types per altre informazioni.\n"
|
||||
"\n"
|
||||
"gitinspector richiede che l'eseguibile GIT sia nel PATH corrente.\n"
|
||||
"Segnala i bug di gitinspector a gitinspector@ejwa.se."
|
||||
|
||||
msgid "WARNING: The terminal encoding is not correctly configured. gitinspector might malfunction. The encoding can be configured with the environment variable 'PYTHONIOENCODING'."
|
||||
msgstr "ATTENZIONE: L'encoding del terminale non è configurato correttamente. gitinspector potrebbe non funzionare correttamente. L'encoding può essere configurato con la variabile d'ambiente 'PYTHONIOENCODING'"
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "Output XML non ancora supportato"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "gitinspector richiede almeno Python 2.6 per essere eseguito (è stata trovata la versione {0})."
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "l'espressione regolare specificata non è valida"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "è responsabile per"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "il formato di output specificato non è supportato."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr "{0} ({1:.3f} in densità di complessità ciclomatica)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr "{0} ({1} linee di codice stimate)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr "{0} ({1} in complessità ciclomatica)"
|
Binary file not shown.
|
@ -0,0 +1,313 @@
|
|||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
# gitinspector is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gitinspector 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 gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Kamila Chyla <kamila.chyla@gmail.com>, 2015.
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: 2015-10-24 07:50+0100\n"
|
||||
"Last-Translator: Kamila Chyla <kamila.chyla@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language-Team: Polish <>\n"
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% w komentarzach"
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% zmian"
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(zaznaczono rozszerzenia użyte podczas analizy statystycznej)"
|
||||
|
||||
msgid "Age"
|
||||
msgstr "Wiek"
|
||||
|
||||
msgid "Author"
|
||||
msgstr "Autor"
|
||||
|
||||
msgid "Below are the number of rows from each author that have survived and are still intact in the current revision"
|
||||
msgstr "Poniżej podano liczbę wierszy przypadających na autora, które w niezmienionej postaci przetrwały do obecnego stanu rezpozytorium"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr "Sprawdzam ile wierszy należy do każdego z autorów (Postęp): {0:.0f}%"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "Komity"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"Copyright © 2012-2015 Ejwa Software. Wszystkie prawa zastrzeżone.\n"
|
||||
"Licencja GPLv3+: GNU GPL wersja 3 lub późniejsza <http://gnu.org/licenses/gpl.html>.\n"
|
||||
"To jest wolne oprogramowanie: możesz je bezpłatnie zmieniać i dystrybuować.\n"
|
||||
"W zakresie określonym prawem, NIE MA GWARANCJI.\n"
|
||||
"\n"
|
||||
"Napisane przez Adama Waldenberga."
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "Usunięcia"
|
||||
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr "Błąd podczas przetwarzania repozytorium w \"%s\"."
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "Wyjście w formacie HTML nie jest jeszcze wspierane w"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "Ukryj mniej znaczących autorów"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "Ukryj wiersze z mniej znaczącymi zmianami"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "Wstawienia"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "Mniej znaczący autorzy"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "Zmienione wiersze:"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "Brak wkomitowanych plików o podanych rozszerzeniach."
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "W repozytorium nie stwierdzono naruszenia metryk."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr "Statystyki repozytorium dla {0}"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "Wiersze"
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "Pokaż mniej znaczących autorów"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "Pokaż wiersze z mniej znaczącymi zmianami"
|
||||
|
||||
msgid "Stability"
|
||||
msgstr "Stabilność"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr "Informacje statystyczne dla repozytorium '{0}' zostały zebrane {1}"
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "Wyjście tekstowe nie jest jeszcze wspierane w"
|
||||
|
||||
msgid "The authors with the following emails were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Autorzy z następującymi adresami e-mail zostali wyłączeni ze statystyk zgodnie z określonymi wzorcami wykluczającymi"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "W historii repozytorium znajdują się poniższe rozszerzenia plików."
|
||||
|
||||
msgid "The following authors were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Następujący autorzy zostali wyłączeni ze statystyk z powodu użycia wzorców wykluczających"
|
||||
|
||||
msgid "The following commit revisions were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Następujące komity zostały wyłączone ze statystyk z powodu użycia wzorców wykluczających"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr "Następujące pliki są podejrzanie duże (od największych)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity (in order of severity)"
|
||||
msgstr "Następujące pliki mają zwiększoną złożoność cyklometryczną (od największych)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity density (in order of severity)"
|
||||
msgstr "Następujące pliki mają zwiększoną gęstość złożoności cyklometrycznej (od największych)"
|
||||
|
||||
msgid "The following files were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "Ze względu na podane wykluczające wzorce wyrażeń regularnych następujące pliki zostały w statystykach pominięte."
|
||||
|
||||
msgid "The following historical commit information, by author, was found in the repository"
|
||||
msgstr "Informacje o wykonanych komitach, uporządkowane według autorów"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr "Z repozytorium wygenerowano następującą historię zmian"
|
||||
|
||||
msgid "The following responsibilities, by author, were found in the current revision of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr "W bieżącej wersji repozytorium zidentyfikowano następujące odpowiedzialności, uporządkowane według autorów (nie uwzględniono, o ile było to możliwe, wierszy zawierających komentarze."
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "Podany argument opcji nie jest poprawną wartością logiczną."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "The output has been generated by {0} {1}. The statistical analysis tool for git repositories."
|
||||
msgstr "Dane zostały wygenerowane przez {0} {1}. Narzędzie analizy statystycznej dla repozytoriów git."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "Aby dowiedzieć się więcej, wpisz `{0} --help'"
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr "Nie można określić ścieżki bezwzględnej do repozytorium git-a"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' and\n"
|
||||
" the available formats are:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] show statistics and information in a way that\n"
|
||||
" is formatted for grading of student\n"
|
||||
" projects; this is the same as supplying the\n"
|
||||
" options -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] track rows and look for duplicates harder;\n"
|
||||
" this can be quite slow with big repositories\n"
|
||||
" -l, --list-file-types[=BOOL] list all the file extensions available in the\n"
|
||||
" current branch of the repository\n"
|
||||
" -L, --localize-output[=BOOL] localize the generated output to the selected\n"
|
||||
" system language if a translation is\n"
|
||||
" available\n"
|
||||
" -m --metrics[=BOOL] include checks for certain metrics during the\n"
|
||||
" analysis of commits\n"
|
||||
" -r --responsibilities[=BOOL] show which files the different authors seem\n"
|
||||
" most responsible for\n"
|
||||
" --since=DATE only show statistics for commits more recent\n"
|
||||
" than a specific date\n"
|
||||
" -T, --timeline[=BOOL] show commit timeline, including author names\n"
|
||||
" --until=DATE only show statistics for commits older than a\n"
|
||||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
"gitinspector will filter statistics to only include commits that modify,\n"
|
||||
"add or remove one of the specified extensions, see -f or --file-types for\n"
|
||||
"more information.\n"
|
||||
"\n"
|
||||
"gitinspector requires that the git executable is available in your PATH.\n"
|
||||
"Report gitinspector bugs to gitinspector@ejwa.se."
|
||||
msgstr ""
|
||||
"Użycie: {0} [OPCJA]... [REPOZYTORIUM]\n"
|
||||
"Wypisuje informacje o repozytorium znajdującym się w repozytorium REPOZYTORIUM.\n"
|
||||
"Jeśli nie podano repozytorium, użyte jest bieżące. Jeśli podano więcej niż jedno,\n"
|
||||
"informacje zostaną wygenerowane na podstawie ostatniego z nich.\n"
|
||||
"\n"
|
||||
"Obowiązkowe argumenty długich opcji są obowiązkowe również dla opcji krótkich.\n"
|
||||
"Argumenty typu Boolean mogą być użyte wyłącznie w opcjach długich.\n"
|
||||
" -f, --file-types=EXTENSIONS lista rozdzielonych przecinkami rozszerzeń\n"
|
||||
" uwzględnionych przy liczeniu statystyk; \n"
|
||||
" domyślne rozszerzenia to:\n"
|
||||
" {1}\n"
|
||||
" Przekazanie * uwzględnia pliki bez rozszerzeń,\n"
|
||||
" natomiast ** uwzględnia wszystkie pliki.\n"
|
||||
" -F, --format=FORMAT definiuje format wyściowy raportu;\n"
|
||||
" domyślnym formatem jest 'text';\n"
|
||||
" dostępne formaty to:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] pokazuje statystyki i informacje sformatowane\n"
|
||||
" w sposób ułatwiający ocenianie projektów\n"
|
||||
" studenckich; odpowiada wywołaniu z opcjami\n"
|
||||
" -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] dokładniej analizuje wiersze kodu i szuka\n"
|
||||
" powtórzeń; może długo działać na dużych\n"
|
||||
" repozytoriach\n"
|
||||
" -l, --list-file-types[=BOOL] wyświetla wszystkie rozszerzenia używane w\n"
|
||||
" bieżącej gałęzi repozytorium\n"
|
||||
" -L, --localize-output[=BOOL] jeśli dostępne jest tłumaczenie na język\n"
|
||||
" określony w locale systemu, używa go przy\n"
|
||||
" generowaniu wyjścia\n"
|
||||
" -m --metrics[=BOOL] w czasie analizowania komitów używa metryk\n"
|
||||
" -r --responsibilities[=BOOL] pokazuje pliki za które ich autorzy wydają się\n"
|
||||
" być najbardziej odpowiedzialni\n"
|
||||
" --since=DATE pokazuje statystyki dla komitów powstałych po\n"
|
||||
" określonej dacie\n"
|
||||
" -T, --timeline[=BOOL] pokazuje zmiany w czasie wraz z nazwiskami\n"
|
||||
" autorów\n"
|
||||
" --until=DATE pokazuje statystyki dla komitów powstałych\n"
|
||||
" prze dokreśloną datą\n"
|
||||
" -w, --weeks[=BOOL] pokazuje informacje statystyczne w tygodniach\n"
|
||||
" zamiast w miesiącach\n"
|
||||
" -x, --exclude=PATTERN używa wzorca wykluczającego z analizy\n"
|
||||
" statystycznej nazwy plików, komity, komity"
|
||||
" zawierające określoną treść, imiona i\n"
|
||||
" nazwiska, adresy e-mail; opcja może być\n"
|
||||
" użyta wielokrotnie\n"
|
||||
" -h, --help wyświetla tę informację i kończy działanie\n"
|
||||
" --version wyświetla informację o wersji i kończy\n"
|
||||
" działanie\n"
|
||||
"\n"
|
||||
"gitinspector uwzględni w statystyce wyłącznie te komity, które zmieniają,\n"
|
||||
"dodają lub usuwają pliki posiadające jedno z określonych rozszerzeń;\n"
|
||||
"aby uzyskać więcej informacji, sprawdź opcję -f lub --file-types.\n"
|
||||
"\n"
|
||||
"gitinspector wymaga, aby program wykonywalny git był dostępny w zmiennej PATH.\n"
|
||||
"Błędy w programie gitinspector należy zgłaszać na adres gitinspector@ejwa.se."
|
||||
|
||||
msgid "WARNING: The terminal encoding is not correctly configured. gitinspector might malfunction. The encoding can be configured with the environment variable 'PYTHONIOENCODING'."
|
||||
msgstr "OSTRZEŻENIE: Kodowanie używane przez terminal jest niepoprawnie skonfigurowane. gitinspector może niepoprawnie działać. Kodowanie można określić ustawiając zmienną środowiskową 'PYTHONIOENCODING'."
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "Wyjście w formacie XML nie jest jeszcze wspierane w"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "gitinspector wymaga wersji Pythona co najmniej 2.6 (znaleziono wersję {0})."
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "podano niepoprawne wyrażenie regularne"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "jest główną osobą odpowiedzialną za"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "podany format wyjściowy nie jest obsługiwany."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr "{0} ({1:.3f} w gęstości złożoności cyklometrycznej)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr "{0} (szacunkowo {1} wierszy kodu)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr "{0} ({1} w złożoności cyklometrycznej)"
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -15,145 +15,38 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Adam Waldenberg <adam.waldenberg@ejwa.se>, 2013.
|
||||
# Adam Waldenberg <adam.waldenberg@ejwa.se>, 2013-2015.
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.3.1\n"
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2013-07-15 02:57+0200\n"
|
||||
"PO-Revision-Date: 2013-07-15 03:08+0200\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: 2015-10-02 04:12+0200\n"
|
||||
"Last-Translator: Adam Waldenberg <adam.waldenberg@ejwa.se>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language-Team: Swedish <>\n"
|
||||
"Language-Team: Svenska <>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Gtranslator 2.91.6\n"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "Suffixen nedan hittades i förrådshistoriken"
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(suffix som användes vid den statistiska analysen är markerade)"
|
||||
|
||||
msgid ""
|
||||
"The following historical commit information, by author, was found in the "
|
||||
"repository"
|
||||
msgstr ""
|
||||
"Den följande inlämningshistoriken, efter upphovsman, hittades i förrådet"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "Kunde inte hitta några inlämnade filer med det angivna suffixet"
|
||||
|
||||
msgid "Author"
|
||||
msgstr "Upphovsman"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "Inlämningar"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "Insättningar"
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "Borttagningar"
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% i kommentarer"
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% av ändringar"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "Mindre Upphovsmän"
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(suffix som användes vid den statistiska analysen är markerade)"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "det angivna utmatningsformatet stöds inte."
|
||||
msgid "Age"
|
||||
msgstr "Ålder"
|
||||
|
||||
msgid ""
|
||||
"The following repsonsibilties, by author, were found in the current revision "
|
||||
"of the repository (comments are exluded from the line count, if possible)"
|
||||
msgstr ""
|
||||
"Följande ansvar, utefter upphovsman, hittades i den nuvarande revisionen av "
|
||||
"förrådet (kommentarer är uteslutna från radberäkningen, om så möjligt)"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "är mestandels ansvarig för"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2013 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"Upphovsrätt © 2012-2013 Ejwa Software. Alla rättigheter förbehållna.\n"
|
||||
"Licens GPLv3+: GNU GPL version 3 eller senare <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"Detta är fri programvara: du får lov att ändra och vidaredistribuera den.\n"
|
||||
"Det finns INGEN GARANTI, så långt lagen tillåter.\n"
|
||||
"\n"
|
||||
"Skrivet av Adam Waldenberg."
|
||||
|
||||
msgid ""
|
||||
"gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "gitinspector kräver åtminstone Python 2.6 (version {0} hittades)."
|
||||
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "Försök med `{0} --help' för mer information."
|
||||
|
||||
msgid ""
|
||||
"The output has been generated by {0}; the statistical analysis tool for git "
|
||||
"repositories."
|
||||
msgstr ""
|
||||
"Sidan har skapats av {0}; det statistiska analysverktyget för git-förråd."
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "Visa mindre upphovsmän"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "Göm mindre upphovsmän"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "Visa rader med lite arbete"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "Göm rader med lite arbete"
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "HTML-utmatning stöds inte i"
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "Textutmatning stöds inte i"
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "XML-utmatning stöds inte i"
|
||||
|
||||
msgid ""
|
||||
"The following files were missing in the repository and were therefore not "
|
||||
"completely included in the statistical analysis. To include them, you can "
|
||||
"either checkout manually using git or use the -c option in gitinspector"
|
||||
msgstr ""
|
||||
"Följande filer saknades i förrådet och var därför inte helt inräknade i den "
|
||||
"statistiska analysen. För att inkludera dem så kan du antingen checka ut dem "
|
||||
"manuellt med git eller använda -c flaggan i gitinspector"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr ""
|
||||
"Följande filer är misstänksamt stora (sorterat utefter allvarlighetsgrad)"
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "Inga överträdelser av kodmetrik hittades i förrådet"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr "Den följande historiska tidslinjen har samlats in från förrådet"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "Ändrade Rader:"
|
||||
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr ""
|
||||
"Kontrollerar hur många rader som tillhör varje författare (Framsteg): "
|
||||
"{0:.0f}%"
|
||||
msgid "Author"
|
||||
msgstr "Upphovsman"
|
||||
|
||||
msgid ""
|
||||
"Below are the number of rows from each author that have survived and are "
|
||||
|
@ -162,81 +55,214 @@ msgstr ""
|
|||
"Nedan återges antalet rader från varje upphovsman som har överlevt och "
|
||||
"fortfarande är intakta i den nuvarande revisionen"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr ""
|
||||
"Kontrollerar hur många rader som tillhör varje författare (Framsteg): "
|
||||
"{0:.0f}%"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "Inlämningar"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"Upphovsrätt © 2012-2015 Ejwa Software. Alla rättigheter förbehållna.\n"
|
||||
"Licens GPLv3+: GNU GPL version 3 eller senare <http://gnu.org/licenses/gpl."
|
||||
"html>.\n"
|
||||
"Detta är fri programvara: du får lov att ändra och vidaredistribuera den.\n"
|
||||
"Det finns INGEN GARANTI, så långt lagen tillåter.\n"
|
||||
"\n"
|
||||
"Skrivet av Adam Waldenberg."
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "Borttagningar"
|
||||
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr "Kunde inte hitta git-förråd på \"%s\"."
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "HTML-utmatning stöds inte i"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "Göm mindre upphovsmän"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "Göm rader med lite arbete"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "Insättningar"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "Mindre Upphovsmän"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "Ändrade Rader:"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "Kunde inte hitta några inlämnade filer med det angivna suffixet"
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "Inga överträdelser av kodmetrik hittades i förrådet"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr "Statistik för förrådet {0}"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "Rader"
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% i kommentarer"
|
||||
msgid "Show minor authors"
|
||||
msgstr "Visa mindre upphovsmän"
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "Det angivna flaggargumentet är inte en giltig boolean."
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "Visa rader med lite arbete"
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "ogiltigt reguljärt uttryck angivet"
|
||||
msgid "Stability"
|
||||
msgstr "Stabilitet"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr "Statistikinformation för förrådet '{0}' hämtades {1}."
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "Textutmatning stöds inte i"
|
||||
|
||||
msgid ""
|
||||
"The authors with the following emails were excluded from the statistics due "
|
||||
"to the specified exclusion patterns"
|
||||
msgstr ""
|
||||
"Upphovsmännen med följande emailadresser har uteslutits från den statistiska "
|
||||
"analysen till följd av de angivna uteslutningsreglerna"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "Suffixen nedan hittades i förrådshistoriken"
|
||||
|
||||
msgid ""
|
||||
"The following authors were excluded from the statistics due to the specified "
|
||||
"exclusion patterns"
|
||||
msgstr ""
|
||||
"Följande upphovsmän har uteslutits från den statistiska analysen till följd "
|
||||
"av de angivna uteslutningsreglerna"
|
||||
|
||||
msgid ""
|
||||
"The following commit revisions were excluded from the statistics due to the "
|
||||
"specified exclusion patterns"
|
||||
msgstr ""
|
||||
"Följande inlämningsrevisioner har uteslutits från den statistiska analysen "
|
||||
"till följd av de angivna uteslutningsreglerna"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr ""
|
||||
"Följande filer är misstänksamt stora (sorterat utefter allvarlighetsgrad)"
|
||||
|
||||
msgid ""
|
||||
"The following files have an elevated cyclomatic complexity (in order of "
|
||||
"severity)"
|
||||
msgstr ""
|
||||
"Följande filer har en förhöjd cyklomatisk komplexitet (sorterat utefter "
|
||||
"allvarlighetsgrad)"
|
||||
|
||||
msgid ""
|
||||
"The following files have an elevated cyclomatic complexity density (in order "
|
||||
"of severity)"
|
||||
msgstr ""
|
||||
"Följande filer har en förhöjd cyklomatisk komplexitetsdensitet (sorterat "
|
||||
"utefter allvarlighetsgrad)"
|
||||
|
||||
msgid ""
|
||||
"The following files were excluded from the statistics due to the specified "
|
||||
"exclusion patterns"
|
||||
msgstr ""
|
||||
"Följande filer var uteslutna från den statistiska analysen på grund av de "
|
||||
"Följande filer har uteslutits från den statistiska analysen till följd av de "
|
||||
"angivna uteslutningsreglerna"
|
||||
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [DIRECTORY]\n"
|
||||
"List information about the repository in DIRECTORY. If no directory is\n"
|
||||
"specified, the current directory is used. If multiple directories are\n"
|
||||
"given, information will be fetched from the last directory specified.\n"
|
||||
"The following historical commit information, by author, was found in the "
|
||||
"repository"
|
||||
msgstr ""
|
||||
"Den följande inlämningshistoriken, efter upphovsman, hittades i förrådet"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr "Den följande historiska tidslinjen har samlats in från förrådet"
|
||||
|
||||
msgid ""
|
||||
"The following responsibilities, by author, were found in the current revision "
|
||||
"of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr ""
|
||||
"Följande ansvar, utefter upphovsman, hittades i den nuvarande revisionen av "
|
||||
"förrådet (kommentarer är uteslutna från radberäkningen, om så möjligt)"
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "Det angivna flaggargumentet är inte en giltig boolean."
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"The output has been generated by {0} {1}. The statistical analysis tool for "
|
||||
"git repositories."
|
||||
msgstr ""
|
||||
"Sidan har skapats av {0} {1}; det statistiska analysverktyget för git-förråd."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "Försök med `{0} --help' för mer information."
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr "Kunde inte fastställa den absoluta sökvägen till git-förrådet."
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -c, --checkout-missing[=BOOL] try to checkout any missing files\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions "
|
||||
"to\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" Specifying * includes files with no\n"
|
||||
" extension, while ** includes all files\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' "
|
||||
"and\n"
|
||||
" generated; the default format is 'text' and\n"
|
||||
" the available formats are:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] show statistics and information in a way "
|
||||
"that\n"
|
||||
" --grading[=BOOL] show statistics and information in a way that\n"
|
||||
" is formatted for grading of student\n"
|
||||
" projects; this is the same as supplying "
|
||||
"the\n"
|
||||
" projects; this is the same as supplying the\n"
|
||||
" options -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] track rows and look for duplicates harder;\n"
|
||||
" this can be quite slow with big "
|
||||
"repositories\n"
|
||||
" -l, --list-file-types[=BOOL] list all the file extensions available in "
|
||||
"the\n"
|
||||
" this can be quite slow with big repositories\n"
|
||||
" -l, --list-file-types[=BOOL] list all the file extensions available in the\n"
|
||||
" current branch of the repository\n"
|
||||
" -L, --localize-output[=BOOL] localize the generated output to the "
|
||||
"selected\n"
|
||||
" -L, --localize-output[=BOOL] localize the generated output to the selected\n"
|
||||
" system language if a translation is\n"
|
||||
" available\n"
|
||||
" -m --metrics[=BOOL] include checks for certain metrics during "
|
||||
"the\n"
|
||||
" -m --metrics[=BOOL] include checks for certain metrics during the\n"
|
||||
" analysis of commits\n"
|
||||
" -r --responsibilities[=BOOL] show which files the different authors "
|
||||
"seem\n"
|
||||
" -r --responsibilities[=BOOL] show which files the different authors seem\n"
|
||||
" most responsible for\n"
|
||||
" --since=DATE only show statistics for commits more "
|
||||
"recent\n"
|
||||
" --since=DATE only show statistics for commits more recent\n"
|
||||
" than a specific date\n"
|
||||
" -T, --timeline[=BOOL] show commit timeline, including author "
|
||||
"names\n"
|
||||
" --until=DATE only show statistics for commits older than "
|
||||
"a\n"
|
||||
" -T, --timeline[=BOOL] show commit timeline, including author names\n"
|
||||
" --until=DATE only show statistics for commits older than a\n"
|
||||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing file names\n"
|
||||
" that should be excluded from the "
|
||||
"statistics;\n"
|
||||
" can be specified multiple times\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, revisions with certain\n"
|
||||
" commit messages, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
|
@ -249,58 +275,52 @@ msgid ""
|
|||
msgstr ""
|
||||
"Användning: {0} [FLAGGA]... [KATALOG]\n"
|
||||
"Lista information om förrådet i KATALOG. Om ingen katalog anges så\n"
|
||||
"används den nuvarande katalogen istället. Om flera förråd anges så hämtas\n"
|
||||
"används den nuvarande katalogen istället. Om flera kataloger anges så "
|
||||
"hämtas\n"
|
||||
"information från den sista katalogen som angivits.\n"
|
||||
"\n"
|
||||
"Obligatoriska argument till långa flaggor är obligatoriska även för de "
|
||||
"korta.\n"
|
||||
"Booleska argument kan bara ges till långa flaggor.\n"
|
||||
" -c, --checkout-missing=[BOOL] försök att checka ut filer som saknas\n"
|
||||
" -f, --file-types=FILSUFFIX en komma-separerad lista av fil-suffix som\n"
|
||||
" ska inkluderas vid statistikberäkning. "
|
||||
"De\n"
|
||||
" ska inkluderas vid statistikberäkning. De\n"
|
||||
" förvalda suffixen är följande:\n"
|
||||
" {1}\n"
|
||||
" Anges * så inkluderas även filer utan\n"
|
||||
" fil-suffix, medan ** inkluderar alla filer\n"
|
||||
" oavsett fil-suffix\n"
|
||||
" -F, --format=FORMAT ange i vilket format den genererade\n"
|
||||
" utmatningen ska vara; det förvalda "
|
||||
"formatet\n"
|
||||
" utmatningen ska vara; det förvalda formatet\n"
|
||||
" är 'text', de tillgängliga formaten är:\n"
|
||||
" {2}\n"
|
||||
" --grading[=BOOL] visa statistik och information anpassad "
|
||||
"för\n"
|
||||
" rättning av studentprojekt; detta är\n"
|
||||
" detsamma som att ange flaggorna -HlmrTw\n"
|
||||
" -H, --hard[=BOOL] spåra rader och leta efter dubbletter "
|
||||
"hårdare;\n"
|
||||
" -H, --hard[=BOOL] spåra rader och leta efter dubbletter hårdare;\n"
|
||||
" detta kan ta lång tid på stora förråd\n"
|
||||
" -l, --list-file-types[=BOOL] lista alla fil-suffix som hittades i den\n"
|
||||
" nuvarande grenen i förrådet\n"
|
||||
" -L --localize-output[=BOOL] Översätt den genererade utmatningen till "
|
||||
"det\n"
|
||||
" nuvarande systemspråket om en "
|
||||
"översättning\n"
|
||||
" -L --localize-output[=BOOL] översätt den genererade utmatningen till det\n"
|
||||
" nuvarande systemspråket om en översättning\n"
|
||||
" finns tillgänglig\n"
|
||||
" -m --metrics[=BOOL] inkludera kontroller för kodmetrik vid\n"
|
||||
" analysen av inlämningar\n"
|
||||
" -r --responsibilities[=BOOL] visa vilka filer olika upphovsmän verkar "
|
||||
"mest\n"
|
||||
" -r --responsibilities[=BOOL] visa vilka filer olika upphovsmän verkar mest\n"
|
||||
" ansvariga för\n"
|
||||
" --since=DATUM beräkna endast statistik för inlämningar "
|
||||
"nyare\n"
|
||||
" --since=DATUM beräkna endast statistik för inlämningar nyare\n"
|
||||
" än ett angivet datum\n"
|
||||
" -T, --timeline[=BOOL] visa en inlämningstidslinje för alla funna\n"
|
||||
" upphovsmän\n"
|
||||
" --until=DATUM beräkna endast statistik för inlämningar "
|
||||
"äldre\n"
|
||||
" --until=DATUM beräkna endast statistik för inlämningar äldre\n"
|
||||
" än ett angivet datum\n"
|
||||
" -w, --weeks[=BOOL] visa statistisk information indelad i "
|
||||
"veckor\n"
|
||||
" -w, --weeks[=BOOL] visa statistisk information indelad i veckor\n"
|
||||
" istället för månader\n"
|
||||
" -x, --exclude=MÖNSTER ett uteslutningsmönster som anger de "
|
||||
"filnamn\n"
|
||||
" som ska uteslutas ur statistiken; kan "
|
||||
"anges\n"
|
||||
" flera gånger\n"
|
||||
" -x, --exclude=MÖNSTER ett uteslutningsmönster som anger filsökvägar,\n"
|
||||
" inlämningsrevisioner, inlämningsrevisioner\n"
|
||||
" med angivna kommentarer, upphovsmän eller\n"
|
||||
" e-post adresser som ska uteslutas ur\n"
|
||||
" statistiken; kan anges flera gånger\n"
|
||||
" -h, --help visa denna hjälptext och avsluta\n"
|
||||
" --version visa versionsinformation och avsluta\n"
|
||||
"\n"
|
||||
|
@ -310,3 +330,41 @@ msgstr ""
|
|||
"\n"
|
||||
"gitinspector kräver att den körbara filen för git finns i PATH.\n"
|
||||
"Rapportera fel i gitinspector till gitinspector@ejwa.se."
|
||||
|
||||
msgid ""
|
||||
"WARNING: The terminal encoding is not correctly configured. gitinspector "
|
||||
"might malfunction. The encoding can be configured with the environment "
|
||||
"variable 'PYTHONIOENCODING'."
|
||||
msgstr ""
|
||||
"VARNING: Terminalens teckenkodning är inte korrekt konfigurerad; "
|
||||
"gitinspector kanske därför inte fungerar korrekt. Teckenkodningen kan "
|
||||
"konfigureras med miljövariabeln 'PYTHONIOENCODING'."
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "XML-utmatning stöds inte i"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "gitinspector kräver åtminstone Python 2.6 (version {0} hittades)."
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "ogiltigt reguljärt uttryck angivet"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "är mestandels ansvarig för"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "det angivna utmatningsformatet stöds inte."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr "{0} ({1:.3f} i kyklomatisk komplexitetsdensitet)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr "{0} ({1} beräknade antal rader)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr "{0} ({1} i kyklomatisk komplexitet)"
|
||||
|
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -15,71 +15,55 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Bill Wang <wangzhijiebill@gmail.com>, 2013
|
||||
# Bill Wang <wangzhijiebill@gmail.com>, 2013-2015
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gitinspector 0.3.1\n"
|
||||
"Project-Id-Version: gitinspector 0.5.0dev\n"
|
||||
"Report-Msgid-Bugs-To: gitinspector@ejwa.se\n"
|
||||
"POT-Creation-Date: 2013-07-22 03:45+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"POT-Creation-Date: 2015-10-02 03:35+0200\n"
|
||||
"PO-Revision-Date: 2015-20-23 18:33-0500\n"
|
||||
"Last-Translator: Bill Wang <wangzhijiebill@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language-Team: Chinese <>\n"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "在资料库中扎到下列插件"
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% 的注释"
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% 的修改"
|
||||
|
||||
msgid "(extensions used during statistical analysis are marked)"
|
||||
msgstr "(统计分析过程中使用的插件已标记)"
|
||||
|
||||
msgid "The following historical commit information, by author, was found in the repository"
|
||||
msgstr "在资料库中找到下列提交记录,已按作者分类"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "未找到符合条件的已提交文件"
|
||||
msgid "Age"
|
||||
msgstr "年龄"
|
||||
|
||||
msgid "Author"
|
||||
msgstr "作者"
|
||||
|
||||
msgid "Below are the number of rows from each author that have survived and are still intact in the current revision"
|
||||
msgstr "下面是过于每位作者在现在的版本了存留下来的行数"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr "检查每位作者贡献了多少行 (进度): {0:.0f}"
|
||||
|
||||
msgid "Commits"
|
||||
msgstr "提交"
|
||||
|
||||
msgid "Insertions"
|
||||
msgstr "加入"
|
||||
|
||||
msgid "Deletions"
|
||||
msgstr "删除"
|
||||
|
||||
#, python-format
|
||||
msgid "% of changes"
|
||||
msgstr "% 个修改"
|
||||
|
||||
msgid "Minor Authors"
|
||||
msgstr "次要作者"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "不支持设定的输出文件格式"
|
||||
|
||||
msgid ""
|
||||
"The following repsonsibilties, by author, were found in the current revision of the repository (comments are exluded from the "
|
||||
"line count, if possible)"
|
||||
msgstr "在最新的资料库修改中,找到下列分工,按作者分类。 (在计算代码数量时尽可能的排除了批注)"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "主要分工是"
|
||||
|
||||
msgid ""
|
||||
"Copyright © 2012-2013 Ejwa Software. All rights reserved.\n"
|
||||
"Copyright © 2012-2015 Ejwa Software. All rights reserved.\n"
|
||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\n"
|
||||
"Written by Adam Waldenberg."
|
||||
msgstr ""
|
||||
"版权所有 © 2012-2013 Ejwa Software. 保留所有权利。\n"
|
||||
"版权所有 © 2012-2014 Ejwa Software. 保留所有权利。\n"
|
||||
"GPLv3的许可证+:GNU GPL版本3或更高版本<http://gnu.org/licenses/gpl.html>。\n"
|
||||
"这是自由软件:您可以自由地更改并重新发布它。\n"
|
||||
"在法律允许的范围内,没有 任何 保证。\n"
|
||||
|
@ -87,90 +71,122 @@ msgstr ""
|
|||
"撰写: Adam Waldenberg.\n"
|
||||
"翻译: 王之杰 (Bill Wang)"
|
||||
|
||||
msgid "gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "gitinspector 要求 Python版本至少2.6 去运行 (已找到版本 {0}) "
|
||||
msgid "Deletions"
|
||||
msgstr "删除"
|
||||
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "尝试 `{0} --help' 已获得更多信息"
|
||||
|
||||
msgid "The output has been generated by {0}; the statistical analysis tool for git repositories."
|
||||
msgstr "输出结果由 {0}的统计分析组建为git数据库生成; "
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "显示次要作者"
|
||||
|
||||
msgid "Hide minor authors"
|
||||
msgstr "隐藏次要作者"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "显示次要工作栏"
|
||||
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "隐藏次要工作栏"
|
||||
#, python-format
|
||||
msgid "Error processing git repository at \"%s\"."
|
||||
msgstr "在处理\"%s\"库时出现问题"
|
||||
|
||||
msgid "HTML output not yet supported in"
|
||||
msgstr "HTML文本输出暂不支持"
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "TEXT文本输出暂不支持"
|
||||
msgid "Hide minor authors"
|
||||
msgstr "隐藏次要作者"
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "XML文本输出暂不支持"
|
||||
msgid "Hide rows with minor work"
|
||||
msgstr "隐藏次要工作"
|
||||
|
||||
msgid ""
|
||||
"The following files were missing in the repository and were therefore not completely included in the statistical analysis. To "
|
||||
"include them, you can either checkout manually using git or use the -c option in gitinspector"
|
||||
msgstr ""
|
||||
"在数据库中下列文件丢失,因此不完全包括在统计分析中。 你可以用git手动检出或者"
|
||||
"在 gitinspector 中用 -c 选项 "
|
||||
msgid "Insertions"
|
||||
msgstr "添加"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr "下列文件过大文件有些可疑 (按严重性排列)"
|
||||
msgid "Minor Authors"
|
||||
msgstr "次要作者"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "修改过的行"
|
||||
|
||||
msgid "No commited files with the specified extensions were found"
|
||||
msgstr "未找到符合条件的已提交文件"
|
||||
|
||||
msgid "No metrics violations were found in the repository"
|
||||
msgstr "未在数据库中发现违反指标"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Repository statistics for {0}"
|
||||
msgstr "关于{0}代码库统计数据"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "行数"
|
||||
|
||||
msgid "Show minor authors"
|
||||
msgstr "显示次要作者"
|
||||
|
||||
msgid "Show rows with minor work"
|
||||
msgstr "显示次要行"
|
||||
|
||||
msgid "Stability"
|
||||
msgstr "稳定性"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Statistical information for the repository '{0}' was gathered on {1}."
|
||||
msgstr "关于{0}的统计数据基于{1}上信息"
|
||||
|
||||
msgid "Text output not yet supported in"
|
||||
msgstr "文本输出暂不支持"
|
||||
|
||||
msgid "The authors with the following emails were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "下列邮箱相关联的作者已经从数据统计中移除"
|
||||
|
||||
msgid "The extensions below were found in the repository history"
|
||||
msgstr "在资料库中找到下列扩展名"
|
||||
|
||||
msgid "The following authors were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "下列作者已按规则从数据统计中移除"
|
||||
|
||||
msgid "The following commit revisions were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "下列提交已按规则从数据统计中移除"
|
||||
|
||||
msgid "The following files are suspiciously big (in order of severity)"
|
||||
msgstr "下列文件过大文件有些可疑 (按严重程度排列)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity (in order of severity)"
|
||||
msgstr "下列文件过度循环性问题 (按严重程度排列)"
|
||||
|
||||
msgid "The following files have an elevated cyclomatic complexity density (in order of severity)"
|
||||
msgstr "下列文件度循环性过度密集 (按严重程度排列)"
|
||||
|
||||
msgid "The following files were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "下列文件已按排除规律移除数据统计"
|
||||
|
||||
msgid "The following historical commit information, by author, was found in the repository"
|
||||
msgstr "在资料库中找到下列提交记录,已按作者分类"
|
||||
|
||||
msgid "The following history timeline has been gathered from the repository"
|
||||
msgstr "在数据库中收集到下列时间轴"
|
||||
|
||||
msgid "Modified Rows:"
|
||||
msgstr "被更改过的行"
|
||||
|
||||
msgid "Checking how many rows belong to each author (Progress): {0:.0f}%"
|
||||
msgstr "检查每位作者贡献了多少行 (进度): {0:.0f}%"
|
||||
|
||||
msgid "Below are the number of rows from each author that have survived and are still intact in the current revision"
|
||||
msgstr "下面是过于每位作者在现在的版本了存留下来的行数"
|
||||
|
||||
msgid "Rows"
|
||||
msgstr "行"
|
||||
|
||||
#, python-format
|
||||
msgid "% in comments"
|
||||
msgstr "% 批注"
|
||||
msgid "The following responsibilities, by author, were found in the current revision of the repository (comments are excluded from the line count, if possible)"
|
||||
msgstr "在最新的资料库修改中,找到下列分工,按作者分类。 (在计算代码数量时尽可能的排除了批注)"
|
||||
|
||||
msgid "The given option argument is not a valid boolean."
|
||||
msgstr "给予的选项不是一个有效的 布尔值 (boolean)"
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "无效的正则表达式"
|
||||
#, python-brace-format
|
||||
msgid "The output has been generated by {0} {1}. The statistical analysis tool for git repositories."
|
||||
msgstr "导出结果已基于{0}{1}生成。Git数据统计软件。"
|
||||
|
||||
msgid "The following files were excluded from the statistics due to the specified exclusion patterns"
|
||||
msgstr "根据指定的排除模式,下列文件被排除在统计中"
|
||||
#, python-brace-format
|
||||
msgid "Try `{0} --help' for more information."
|
||||
msgstr "尝试 `{0} --help' 已获得更多信息"
|
||||
|
||||
msgid "Unable to determine absolute path of git repository."
|
||||
msgstr "无法确定git库的绝对路径"
|
||||
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"Usage: {0} [OPTION]... [DIRECTORY]\n"
|
||||
"List information about the repository in DIRECTORY. If no directory is\n"
|
||||
"specified, the current directory is used. If multiple directories are\n"
|
||||
"given, information will be fetched from the last directory specified.\n"
|
||||
"Usage: {0} [OPTION]... [REPOSITORY]\n"
|
||||
"List information about the repository in REPOSITORY. If no repository is\n"
|
||||
"specified, the current directory is used. If multiple repositories are\n"
|
||||
"given, information will be fetched from the last repository specified.\n"
|
||||
"\n"
|
||||
"Mandatory arguments to long options are mandatory for short options too.\n"
|
||||
"Boolean arguments can only be given to long options.\n"
|
||||
" -c, --checkout-missing[=BOOL] try to checkout any missing files\n"
|
||||
" -f, --file-types=EXTENSIONS a comma separated list of file extensions to\n"
|
||||
" include when computing statistics. The\n"
|
||||
" default extensions used are:\n"
|
||||
" {1}\n"
|
||||
" Specifying * includes files with no\n"
|
||||
" extension, while ** includes all files\n"
|
||||
" -F, --format=FORMAT define in which format output should be\n"
|
||||
" generated; the default format is 'text' and\n"
|
||||
" the available formats are:\n"
|
||||
|
@ -197,9 +213,11 @@ msgid ""
|
|||
" specific date\n"
|
||||
" -w, --weeks[=BOOL] show all statistical information in weeks\n"
|
||||
" instead of in months\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing file names\n"
|
||||
" that should be excluded from the statistics;\n"
|
||||
" can be specified multiple times\n"
|
||||
" -x, --exclude=PATTERN an exclusion pattern describing the file\n"
|
||||
" paths, revisions, revisions with certain\n"
|
||||
" commit messages, author names or author\n"
|
||||
" emails that should be excluded from the\n"
|
||||
" statistics; can be specified multiple times\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
"\n"
|
||||
|
@ -210,14 +228,15 @@ msgid ""
|
|||
"gitinspector requires that the git executable is available in your PATH.\n"
|
||||
"Report gitinspector bugs to gitinspector@ejwa.se."
|
||||
msgstr ""
|
||||
"用法: {0} [选项]... [目录]\n"
|
||||
"用法:{0} [选项]... [目录] \n"
|
||||
"在目录列出有关库的信息,如果没有指定目录,那么将使用现目录。如果有多个目录,\n"
|
||||
"将采用指定的最后一个目录\n"
|
||||
"\n"
|
||||
"长选项的强制性参数对短选项也适用\n"
|
||||
"布尔参数只能给予长选项\n"
|
||||
" -c, --checkout-missing[=BOOL] 尝试检出任何丢失的文件\n"
|
||||
" -f, --file-types=EXTENSIONS 一串逗号分隔的文件类型\n"
|
||||
" 用 * 来包含无扩展名的文件\n"
|
||||
" 用 ** 包涵所有文件\n"
|
||||
" 这些文件将会被用于计算统计数据.\n"
|
||||
" 默认文件类型:\n"
|
||||
" {1}\n"
|
||||
|
@ -239,13 +258,45 @@ msgstr ""
|
|||
" --until=DATE 只显示特定时间前的结果\n"
|
||||
" -w, --weeks[=BOOL] 按周来显示统计数据,而非月\n"
|
||||
" -x, --exclude=PATTERN 按特定格式排除不应该被统计\n"
|
||||
" 的文件;可以重复\n"
|
||||
" -h, --help 现实这个帮助信息并退出\n"
|
||||
" --version 现实版本信息并退出\n"
|
||||
" 的文件,作者名字或邮箱;可以按文件名,\n"
|
||||
" 作者名,作者邮箱,提交信息,路径和版本。可以重复\n"
|
||||
" -h, --help 显示这个帮助信息并退出\n"
|
||||
" --version 显示版本信息并退出\n"
|
||||
"\n"
|
||||
"gitinspector 会过滤信息并且仅统计那些修改,增加或减少,指定文件类型的提交,\n"
|
||||
"如需详细信息,请参考 -f 或 --file-types 选项\n"
|
||||
"\n"
|
||||
"gitinspector 需要 git 可运行文件 在 PATH 中.\n"
|
||||
"错误报告,请寄 gitinspector@ejwa.se.\n"
|
||||
"翻译错误,请寄 wangzhijiebill@gmail.com."
|
||||
"翻译错误,请寄 wangzhijiebill@gmail.com"
|
||||
|
||||
msgid "WARNING: The terminal encoding is not correctly configured. gitinspector might malfunction. The encoding can be configured with the environment variable 'PYTHONIOENCODING'."
|
||||
msgstr "警告:命令指示符编码格式有误。gitinspector可能出错。编码格式可以在环境变量的'PYTHONIOENCODING'下修改"
|
||||
|
||||
msgid "XML output not yet supported in"
|
||||
msgstr "XML文本输出暂不支持"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "gitinspector requires at least Python 2.6 to run (version {0} was found)."
|
||||
msgstr "gitinspector 要求 Python版本至少2.6 (已找到版本 {0}) "
|
||||
|
||||
msgid "invalid regular expression specified"
|
||||
msgstr "无效的正则表达式"
|
||||
|
||||
msgid "is mostly responsible for"
|
||||
msgstr "主要分工是"
|
||||
|
||||
msgid "specified output format not supported."
|
||||
msgstr "不支持设定的输出文件格式"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1:.3f} in cyclomatic complexity density)"
|
||||
msgstr "{0} (循环型结构密集度{1: 3f})"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} estimated lines of code)"
|
||||
msgstr "{0}(估测代码行数{1})"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{0} ({1} in cyclomatic complexity)"
|
||||
msgstr "{0}(代码循环性结构{1})"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -19,17 +19,12 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from . import localization
|
||||
localization.init()
|
||||
|
||||
try:
|
||||
import localization
|
||||
localization.init()
|
||||
except:
|
||||
import gitinspector.localization
|
||||
gitinspector.localization.init()
|
||||
__version__ = "0.5.0dev"
|
||||
|
||||
__version__ = "0.3.1"
|
||||
|
||||
__doc__ = _("""Copyright © 2012-2013 Ejwa Software. All rights reserved.
|
||||
__doc__ = _("""Copyright © 2012-2015 Ejwa Software. All rights reserved.
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "gitinspector",
|
||||
"version": "0.5.0-dev-1",
|
||||
"description": "Gitinspector is a statistical analysis tool for git repositories. The default analysis shows general statistics per author, which can be complemented with a timeline analysis that shows the workload and activity of each author.",
|
||||
"preferGlobal": true,
|
||||
"main": "gitinspector.py",
|
||||
"directories": {
|
||||
"doc": "docs",
|
||||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf **/*.pyc",
|
||||
"crlf": "crlf --set=LF **/*.py",
|
||||
"prepublish": "npm run clean && npm run crlf",
|
||||
"release": "with-package git commit -am pkg.version && with-package git tag pkg.version && git push && npm publish && git push --tags",
|
||||
"release:beta": "npm run release && npm run tag:beta",
|
||||
"tag:beta": "with-package npm dist-tag add pkg.name@pkg.version beta",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"bin": {
|
||||
"gitinspector": "gitinspector.py"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ejwa/gitinspector.git"
|
||||
},
|
||||
"keywords": [
|
||||
"git",
|
||||
"statistics",
|
||||
"stats",
|
||||
"analytics",
|
||||
"grading"
|
||||
],
|
||||
"author": {
|
||||
"name": "Adam Waldenberg",
|
||||
"email": "adam.waldenberg@ejwa.se",
|
||||
"url": "https://github.com/adam-waldenberg"
|
||||
},
|
||||
"contributors": [
|
||||
"Agustín Cañas",
|
||||
"Bart van Andel <bavanandel@gmail.com>",
|
||||
"Bill Wang",
|
||||
"Christian Kastner",
|
||||
"Jiwon Kim",
|
||||
"Kamila Chyla",
|
||||
"Luca Motta",
|
||||
"Philipp Nowak",
|
||||
"Sergei Lomakov",
|
||||
"Yannick Moy"
|
||||
],
|
||||
"license": "GPL-3.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ejwa/gitinspector/issues"
|
||||
},
|
||||
"homepage": "https://github.com/ejwa/gitinspector#readme",
|
||||
"devDependencies": {
|
||||
"crlf": "^1.1.0",
|
||||
"rimraf": "^2.5.4",
|
||||
"with-package": "^0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"python-shell": "^0.4.0"
|
||||
}
|
||||
}
|
4
setup.py
4
setup.py
|
@ -34,7 +34,7 @@ setup(
|
|||
description = ("A statistical analysis tool for git repositories."),
|
||||
license = "GNU GPL v3",
|
||||
keywords = "analysis analyzer git python statistics stats vc vcs timeline",
|
||||
url = "http://gitinspector.googlecode.com",
|
||||
url = "https://github.com/ejwa/gitinspector",
|
||||
long_description = read("DESCRIPTION.txt"),
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
|
@ -48,5 +48,5 @@ setup(
|
|||
package_data = {"": ["html/*", "translations/*"]},
|
||||
data_files = [("share/doc/gitinspector", glob("*.txt"))],
|
||||
entry_points = {"console_scripts": ["gitinspector = gitinspector.gitinspector:main"]},
|
||||
zip_safe = True
|
||||
zip_safe = False
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright © 2013 Ejwa Software. All rights reserved.
|
||||
# Copyright © 2013-2015 Ejwa Software. All rights reserved.
|
||||
#
|
||||
# This file is part of gitinspector.
|
||||
#
|
||||
|
@ -41,10 +41,10 @@ def __test_extension__(commented_file, extension):
|
|||
|
||||
class TexFileTest(unittest2.TestCase):
|
||||
def test(self):
|
||||
comment_counter = __test_extension__("/commented_file.tex", "tex")
|
||||
comment_counter = __test_extension__("/resources/commented_file.tex", "tex")
|
||||
self.assertEqual(comment_counter, 30)
|
||||
|
||||
class CppFileTest(unittest2.TestCase):
|
||||
def test(self):
|
||||
comment_counter = __test_extension__("/commented_file.cpp", "cpp")
|
||||
comment_counter = __test_extension__("/resources/commented_file.cpp", "cpp")
|
||||
self.assertEqual(comment_counter, 25)
|
||||
|
|
Loading…
Reference in New Issue