Compare commits
111 Commits
feature.do
...
feature.di
Author | SHA1 | Date | |
---|---|---|---|
|
464c1a8ef5 | ||
|
e5b10a8494 | ||
|
ffc49b9ea6 | ||
|
0efc14dd6f | ||
|
4fb15ccb7d | ||
|
234b70845c | ||
|
6abd0b6faa | ||
|
fef2bd15bf | ||
|
74d07d8fb8 | ||
|
473e9153ed | ||
|
efa10c9afd | ||
|
7438a2bf19 | ||
|
2e0995abac | ||
|
c84afd0f78 | ||
|
b1276dff6c | ||
|
b413b7ee89 | ||
|
f19f07ec59 | ||
|
83761c66c5 | ||
|
d0e2977746 | ||
|
1be91e5a2a | ||
|
15d4d1aa7d | ||
|
708b90fccd | ||
|
ac7a4c4aa5 | ||
|
b90246a239 | ||
|
a9d327d54f | ||
|
eb8fd0aa55 | ||
|
813184f06c | ||
|
ef2d3a9af9 | ||
|
9a8bd464a3 | ||
|
9e2ea7404b | ||
|
160d11b89b | ||
|
d860f299fd | ||
|
33882d4fa7 | ||
|
85978a4d18 | ||
|
e1e7696d53 | ||
|
695428075b | ||
|
e7c2e721b4 | ||
|
13fad756ab | ||
|
1f0791df0e | ||
|
a2c832a130 | ||
|
b17de014ec | ||
|
b1b72190e1 | ||
|
2ff2f888bc | ||
|
57c2389aae | ||
|
d54c86f813 | ||
|
05a9697007 | ||
|
945429abf0 | ||
|
a016bcb51b | ||
|
f2b1ce795c | ||
|
3a8c56acc4 | ||
|
7b2552f940 | ||
|
324b202215 | ||
|
2c2da6082a | ||
|
dd3fbbd7e4 | ||
|
9bbcd571ec | ||
|
bbc185bf3b | ||
|
d1bcdcda20 | ||
|
6d55602ef3 | ||
|
6e7c9f7c4b | ||
|
5427aab456 | ||
|
4879d64989 | ||
|
dab8ea63fc | ||
|
b03d7a04a0 | ||
|
ef5b93e3f7 | ||
|
69ae1c08ef | ||
|
8e4f828cc6 | ||
|
c4f92f4569 | ||
|
c4d2b99656 | ||
|
d4fe88adab | ||
|
69d0e8313a | ||
|
11a234e135 | ||
|
2f30e4e2f6 | ||
|
118ca9f11f | ||
|
24fc41ee0d | ||
|
c00dbac5e0 | ||
|
ac6be0d3c0 | ||
|
7ff6f09f67 | ||
|
00b576c5a3 | ||
|
2a33510c96 | ||
|
d1f79d906d | ||
|
aa043f14ac | ||
|
638b28399e | ||
|
1d86f036a3 | ||
|
2f6e0f0a22 | ||
|
1b1b00a10c | ||
|
8693418d39 | ||
|
8ff15368ce | ||
|
32cde534bd | ||
|
c0e26133bd | ||
|
592c2ff9ff | ||
|
30efd0a2db | ||
|
20c3f14cc8 | ||
|
80313c88c8 | ||
|
cab1c09ffc | ||
|
c421919092 | ||
|
d350876bc1 | ||
|
de09c8af56 | ||
|
998f4576fe | ||
|
2aab4eea3b | ||
|
5bbff9f5a6 | ||
|
b5fcf1636a | ||
|
13012be5d7 | ||
|
ca2ef814fb | ||
|
9bcb5f9456 | ||
|
f412099f69 | ||
|
0aa5999bb3 | ||
|
16dda0743c | ||
|
bcba64b2a1 | ||
|
e40d922eef | ||
|
7e226b43d3 | ||
|
9171bfd1ab |
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,14 +1,19 @@
|
|||||||
*~
|
*~
|
||||||
tmp
|
.buildpath
|
||||||
|
.externalToolBuilders
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.tx/config
|
||||||
|
attachments
|
||||||
|
indefero-*.zip
|
||||||
src/IDF/conf/idf.php
|
src/IDF/conf/idf.php
|
||||||
src/IDF/conf/idf.test.php
|
src/IDF/conf/idf.test.php
|
||||||
www/test.php
|
|
||||||
www/media/upload
|
|
||||||
src/IDF/gettexttemplates
|
|
||||||
indefero-*.zip
|
|
||||||
src/IDF/conf/path.php
|
src/IDF/conf/path.php
|
||||||
.tx/config
|
src/IDF/gettexttemplates
|
||||||
src/IDF/locale/idf.pot.bak
|
src/IDF/locale/idf.pot.bak
|
||||||
|
test/config.php
|
||||||
test/test.db
|
test/test.db
|
||||||
test/tmp
|
test/tmp
|
||||||
test/config.php
|
tmp
|
||||||
|
www/media/upload
|
||||||
|
www/test.php
|
||||||
|
2
AUTHORS
2
AUTHORS
@@ -12,6 +12,7 @@ Much appreciated contributors (in alphabetical order):
|
|||||||
Brian Armstrong <brianar>
|
Brian Armstrong <brianar>
|
||||||
Charles Melbye <charlie@yourwiki.net>
|
Charles Melbye <charlie@yourwiki.net>
|
||||||
Ciaran Gultnieks <ciaran@ciarang.com>
|
Ciaran Gultnieks <ciaran@ciarang.com>
|
||||||
|
Daniel Steudler <steudlerdaniel@gmail.com>
|
||||||
David Feeney <davidf>
|
David Feeney <davidf>
|
||||||
Denis Kot <denis.kot@gmail.com> - Russian translation
|
Denis Kot <denis.kot@gmail.com> - Russian translation
|
||||||
Dmitry Dulepov <dmitryd>
|
Dmitry Dulepov <dmitryd>
|
||||||
@@ -32,6 +33,7 @@ Much appreciated contributors (in alphabetical order):
|
|||||||
Samuel Suther <info@suther.de> - German translation
|
Samuel Suther <info@suther.de> - German translation
|
||||||
Sindre R. Myren <sindrero@stud.ntnu.no>
|
Sindre R. Myren <sindrero@stud.ntnu.no>
|
||||||
Stewart Platt <stew@futurete.ch>
|
Stewart Platt <stew@futurete.ch>
|
||||||
|
Stéphane Baron <sbaron>
|
||||||
Thomas Keller <me@thomaskeller.biz> - Monotone support
|
Thomas Keller <me@thomaskeller.biz> - Monotone support
|
||||||
Vladimir Solomatin <slash>
|
Vladimir Solomatin <slash>
|
||||||
William Martin <william.martin@lcpc.fr>
|
William Martin <william.martin@lcpc.fr>
|
||||||
|
9
Makefile
9
Makefile
@@ -37,6 +37,10 @@ help:
|
|||||||
@printf "\tpo-push - Send the all PO files to the transifex server.\n"
|
@printf "\tpo-push - Send the all PO files to the transifex server.\n"
|
||||||
@printf "\tpo-pull - Get all PO files from the transifex server.\n"
|
@printf "\tpo-pull - Get all PO files from the transifex server.\n"
|
||||||
@printf "\tpo-stats - Show translation statistics of all PO files.\n"
|
@printf "\tpo-stats - Show translation statistics of all PO files.\n"
|
||||||
|
@printf "\nMisc Rules :\n";
|
||||||
|
@printf "\tdb-install - Install the database schema.\n"
|
||||||
|
@printf "\tdb-update - Update the database schema.\n"
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Internationalization rule, POT & PO file manipulation
|
# Internationalization rule, POT & PO file manipulation
|
||||||
@@ -139,3 +143,8 @@ po-stats:
|
|||||||
> indefero-$(@:-zipfile=)-`git log $(@:-zipfile=) -n 1 \
|
> indefero-$(@:-zipfile=)-`git log $(@:-zipfile=) -n 1 \
|
||||||
--pretty=format:%h`.zip
|
--pretty=format:%h`.zip
|
||||||
|
|
||||||
|
db-install:
|
||||||
|
@cd src && php $(PLUF_PATH)/migrate.php --conf=IDF/conf/idf.php -a -d -i
|
||||||
|
|
||||||
|
db-update:
|
||||||
|
@cd src && php $(PLUF_PATH)/migrate.php --conf=IDF/conf/idf.php -a -d
|
||||||
|
46
NEWS.mdtext
46
NEWS.mdtext
@@ -1,20 +1,60 @@
|
|||||||
# InDefero 1.2 - xxx xxx xx xx:xx 2011 UTC
|
# InDefero 1.2 - xxx xxx xx xx:xx 2011 UTC
|
||||||
|
|
||||||
|
ATTENTION: You need Pluf [324ae60b](http://projects.ceondo.com/p/pluf/source/commit/324ae60b)
|
||||||
|
or newer to properly run this version of Indefero!
|
||||||
|
|
||||||
## New Features
|
## New Features
|
||||||
|
|
||||||
|
- Indefero's issue tracker can now bi-directionally link issues with variable, configurable
|
||||||
|
terms, such as "is related to", "is blocked by" or "is duplicated by" (issue 638)
|
||||||
|
- When you search for issues, the results can further be refined by issue state (open or closed)
|
||||||
|
and label (partially implements issue 548)
|
||||||
- Mercurial source views now show parent revisions (if any) and detailed change information
|
- Mercurial source views now show parent revisions (if any) and detailed change information
|
||||||
- File download URLs now contain the file name rather than the upload id; old links still work though (issue 686)
|
- Subversion source views now show detailed change information (issue 622)
|
||||||
|
- File download URLs now contain the file name rather than the upload id; old links still work though (issues 559 and 686)
|
||||||
|
- Display monotone file and directory attributes in the tree and file view
|
||||||
|
(needs a monotone with an interface version of 13.1 or newer)
|
||||||
|
- The context area is now kept in view when a page scrolls down several pages
|
||||||
|
- Add a summary section to the issue tracker with statistics about open/close issues,
|
||||||
|
tags of open issue, and count of open tickets for each owner.
|
||||||
|
- Improved home page with an customizable icon for each project.
|
||||||
|
- The download section provide MD5 for each files.
|
||||||
|
- Wiki page have now a css for printer output (issue 713)
|
||||||
|
|
||||||
## Bugfixes
|
## Bugfixes
|
||||||
|
|
||||||
|
- The SVN interface acts more robust if an underlying repository has been restructured (issues 364 and 721)
|
||||||
- monotone zip archive entries now all carry the revision date as mtime (issue 645)
|
- monotone zip archive entries now all carry the revision date as mtime (issue 645)
|
||||||
- Timeline only displays filter options for items a user has actually access to (issue 655)
|
- Timeline only displays filter options for items a user has actually access to (issue 655)
|
||||||
- The log, tags and branches parsers for Mercurial are more robust now (issue 663)
|
- The log, tags and branches parsers for Mercurial are more robust now (issue 663)
|
||||||
- Fix SSH public key parsing issues and improve the check for existing, uploaded keys (issue 679)
|
- Fix SSH public key parsing issues and improve the check for existing, uploaded keys (issue 679)
|
||||||
|
- Diff views now show empty context lines for git and hg again (issue 688)
|
||||||
- Let the SVN command line client not store the login credentials we give him as arguments
|
- Let the SVN command line client not store the login credentials we give him as arguments
|
||||||
|
- The usher section in the forge administration no longer displays a bogus
|
||||||
|
server enty in case no monotone server is configured in the connected
|
||||||
|
usher instance
|
||||||
|
- Prevent a timeout from popping up when Usher is restarted (issue 695)
|
||||||
|
- The SyncMonotone plugin now cleans up partial artifacts it created during the addition of
|
||||||
|
a new project or monotone key, in case an error popped up in the middle (issue 697)
|
||||||
|
- Indefero now sends the MD5 checksum as HTTP header when downloading a file from the
|
||||||
|
download area. Additionally, a unneeded redirect has been removed. (issue 716)
|
||||||
|
- Source links without a specific revision did not work due to a wrong regex (issue 730)
|
||||||
|
- Better error detection and reporting in the SyncMonotone plugin
|
||||||
|
ATTENTION: This needs Pluf 46b7f251 or newer!
|
||||||
|
- Fix the branch links users of the Subversion frontend get when they enter a wrong revision
|
||||||
|
and only display this list if there are any branches available for all SCMs
|
||||||
|
- If git's author name is not encoded in an UTF-8 compatible encoding, skip the author lookup,
|
||||||
|
as we have no information what the author string is actually encoded in
|
||||||
|
- Indefero no longer displays an empty parents paragraph in the commit view for root revisions of
|
||||||
|
a git repository
|
||||||
|
- Indefero now only shows the tags of the closed and not the open issues in the closed issues list
|
||||||
|
- Avatar URL generation use correctly the configuration (issue 732)
|
||||||
|
- Git cron job doesn't erase anymore manually added keys (issue 247)
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
- The documentation on the setup of the monotone plugin has been improved.
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
|
|
||||||
# InDefero 1.1.2 - Thu May 26 07:42:25 2011 UTC
|
# InDefero 1.1.2 - Thu May 26 07:42:25 2011 UTC
|
||||||
|
@@ -25,7 +25,7 @@ If you install monotone from source (<http://monotone.ca/downloads.php>),
|
|||||||
please follow the `INSTALL` document which comes with the software.
|
please follow the `INSTALL` document which comes with the software.
|
||||||
It contains detailed instructions, including all needed dependencies.
|
It contains detailed instructions, including all needed dependencies.
|
||||||
|
|
||||||
## Choose your indefero setup
|
## Choose your indefero (IDF) setup
|
||||||
|
|
||||||
The monotone plugin can be used in several different ways:
|
The monotone plugin can be used in several different ways:
|
||||||
|
|
||||||
@@ -112,14 +112,40 @@ The monotone plugin can be used in several different ways:
|
|||||||
^D
|
^D
|
||||||
$ chmod 600 usher.conf
|
$ chmod 600 usher.conf
|
||||||
|
|
||||||
|
**ATTENTION:** Do _not_ configure a default monotone server key in `usher.conf`,
|
||||||
|
otherwise the individual server key that IDF creates for each project is
|
||||||
|
not used and this could cause problems.
|
||||||
|
|
||||||
Your indefero www user needs later write access to `usher.conf` and
|
Your indefero www user needs later write access to `usher.conf` and
|
||||||
`projects/`. There are two ways of setting this up:
|
`projects/`. There are two ways of setting this up:
|
||||||
|
|
||||||
* Make the usher user the web user, for example via Apache's `suexec`
|
* Make the usher user the web user, for example via Apache's `suexec`.
|
||||||
* Use acls, like this:
|
This is however a bit clumsy.
|
||||||
|
* Preferred: Use Access Control Lists (ACLs), like this:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Linux
|
||||||
|
#
|
||||||
$ setfacl -m u:www:rw usher.conf
|
$ setfacl -m u:www:rw usher.conf
|
||||||
$ setfacl -m d:u:www:rwx projects/
|
$ setfacl -m d:u:www:rwx projects/
|
||||||
|
$ setfacl -m d:u:usher:rwx projects/
|
||||||
|
#
|
||||||
|
# FreeBSD
|
||||||
|
#
|
||||||
|
$ setfacl -m user:www:rw::allow usher.conf
|
||||||
|
$ setfacl -m user:www:rwxp:fd:allow projects/
|
||||||
|
$ setfacl -m user:usher:rwxp:fd:allow projects/
|
||||||
|
#
|
||||||
|
# Mac OS X
|
||||||
|
#
|
||||||
|
chmod +a '_www allow read,write' usher.conf
|
||||||
|
chmod +a '_www allow read,write,delete,add_file,add_subdirectory,file_inherit,directory_inherit' projects/
|
||||||
|
chmod +a 'usher allow read,write,delete,add_file,add_subdirectory,file_inherit,directory_inherit' projects/
|
||||||
|
|
||||||
|
In each example's last line, `usher` is the user which is executing
|
||||||
|
the usher instance. **It is very important to add this line, otherwise
|
||||||
|
usher won't be able to read and write into the initial file system
|
||||||
|
setup IDF creates!**
|
||||||
|
|
||||||
5. Wrap a daemonizer around usher, for example supervise from daemontools
|
5. Wrap a daemonizer around usher, for example supervise from daemontools
|
||||||
(<http://cr.yp.to/damontools.html>):
|
(<http://cr.yp.to/damontools.html>):
|
||||||
|
221
src/IDF/Diff.php
221
src/IDF/Diff.php
@@ -35,9 +35,7 @@ class IDF_Diff
|
|||||||
public function __construct($diff, $path_strip_level = 0)
|
public function __construct($diff, $path_strip_level = 0)
|
||||||
{
|
{
|
||||||
$this->path_strip_level = $path_strip_level;
|
$this->path_strip_level = $path_strip_level;
|
||||||
// this works because in unified diff format even empty lines are
|
$this->lines = IDF_FileUtil::splitIntoLines($diff, true);
|
||||||
// either prefixed with a '+', '-' or ' '
|
|
||||||
$this->lines = preg_split("/\015\012|\015|\012/", $diff, -1, PREG_SPLIT_NO_EMPTY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parse()
|
public function parse()
|
||||||
@@ -66,12 +64,12 @@ class IDF_Diff
|
|||||||
}
|
}
|
||||||
|
|
||||||
// use new file name by default
|
// use new file name by default
|
||||||
preg_match("/^\+\+\+ ([^\t]+)/", $newfileline, $m);
|
preg_match("/^\+\+\+ ([^\t\n\r]+)/", $newfileline, $m);
|
||||||
$current_file = $m[1];
|
$current_file = $m[1];
|
||||||
if ($current_file === '/dev/null') {
|
if ($current_file === '/dev/null') {
|
||||||
// except if it's /dev/null, use the old one instead
|
// except if it's /dev/null, use the old one instead
|
||||||
// eg. mtn 0.48 and newer
|
// eg. mtn 0.48 and newer
|
||||||
preg_match("/^--- ([^\t]+)/", $oldfileline, $m);
|
preg_match("/^--- ([^\t\r\n]+)/", $oldfileline, $m);
|
||||||
$current_file = $m[1];
|
$current_file = $m[1];
|
||||||
}
|
}
|
||||||
if ($this->path_strip_level > 0) {
|
if ($this->path_strip_level > 0) {
|
||||||
@@ -101,11 +99,12 @@ class IDF_Diff
|
|||||||
$files[$current_file]['chunks'][] = array();
|
$files[$current_file]['chunks'][] = array();
|
||||||
|
|
||||||
while ($i < $diffsize && ($addlines >= 0 || $dellines >= 0)) {
|
while ($i < $diffsize && ($addlines >= 0 || $dellines >= 0)) {
|
||||||
$linetype = $this->lines[$i] != '' ? $this->lines[$i][0] : ' ';
|
$linetype = $this->lines[$i] != '' ? $this->lines[$i][0] : false;
|
||||||
|
$content = substr($this->lines[$i], 1);
|
||||||
switch ($linetype) {
|
switch ($linetype) {
|
||||||
case ' ':
|
case ' ':
|
||||||
$files[$current_file]['chunks'][$current_chunk][] =
|
$files[$current_file]['chunks'][$current_chunk][] =
|
||||||
array($delstart, $addstart, substr($this->lines[$i++], 1));
|
array($delstart, $addstart, $content);
|
||||||
$dellines--;
|
$dellines--;
|
||||||
$addlines--;
|
$addlines--;
|
||||||
$delstart++;
|
$delstart++;
|
||||||
@@ -113,23 +112,26 @@ class IDF_Diff
|
|||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
$files[$current_file]['chunks'][$current_chunk][] =
|
$files[$current_file]['chunks'][$current_chunk][] =
|
||||||
array('', $addstart, substr($this->lines[$i++], 1));
|
array('', $addstart, $content);
|
||||||
$addlines--;
|
$addlines--;
|
||||||
$addstart++;
|
$addstart++;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
$files[$current_file]['chunks'][$current_chunk][] =
|
$files[$current_file]['chunks'][$current_chunk][] =
|
||||||
array($delstart, '', substr($this->lines[$i++], 1));
|
array($delstart, '', $content);
|
||||||
$dellines--;
|
$dellines--;
|
||||||
$delstart++;
|
$delstart++;
|
||||||
break;
|
break;
|
||||||
case '\\':
|
case '\\':
|
||||||
// ignore newline handling for now, see issue 636
|
// no new line at the end of this file; remove pseudo new line from last line
|
||||||
$i++;
|
$cur = count($files[$current_file]['chunks'][$current_chunk]) - 1;
|
||||||
|
$files[$current_file]['chunks'][$current_chunk][$cur][2] =
|
||||||
|
rtrim($files[$current_file]['chunks'][$current_chunk][$cur][2], "\r\n");
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
|
$i++;
|
||||||
}
|
}
|
||||||
$current_chunk++;
|
$current_chunk++;
|
||||||
}
|
}
|
||||||
@@ -144,46 +146,80 @@ class IDF_Diff
|
|||||||
public function as_html()
|
public function as_html()
|
||||||
{
|
{
|
||||||
$out = '';
|
$out = '';
|
||||||
foreach ($this->files as $filename=>$file) {
|
foreach ($this->files as $filename => $file) {
|
||||||
$pretty = '';
|
$pretty = '';
|
||||||
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
||||||
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
|
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
|
||||||
$pretty = ' prettyprint';
|
$pretty = ' prettyprint';
|
||||||
}
|
}
|
||||||
$out .= "\n".'<table class="diff" summary="">'."\n";
|
|
||||||
$out .= '<tr id="diff-'.md5($filename).'"><th colspan="3">'.Pluf_esc($filename).'</th></tr>'."\n";
|
|
||||||
$cc = 1;
|
$cc = 1;
|
||||||
|
$offsets = array();
|
||||||
|
$contents = array();
|
||||||
|
|
||||||
foreach ($file['chunks'] as $chunk) {
|
foreach ($file['chunks'] as $chunk) {
|
||||||
foreach ($chunk as $line) {
|
foreach ($chunk as $line) {
|
||||||
if ($line[0] and $line[1]) {
|
list($left, $right, $content) = $line;
|
||||||
$class = 'diff-c';
|
if ($left and $right) {
|
||||||
} elseif ($line[0]) {
|
$class = 'context';
|
||||||
$class = 'diff-r';
|
} elseif ($left) {
|
||||||
|
$class = 'removed';
|
||||||
} else {
|
} else {
|
||||||
$class = 'diff-a';
|
$class = 'added';
|
||||||
}
|
}
|
||||||
$line_content = self::padLine(Pluf_esc($line[2]));
|
|
||||||
$out .= sprintf('<tr class="diff-line"><td class="diff-lc">%s</td><td class="diff-lc">%s</td><td class="%s%s mono">%s</td></tr>'."\n", $line[0], $line[1], $class, $pretty, $line_content);
|
$offsets[] = sprintf('<td>%s</td><td>%s</td>', $left, $right);
|
||||||
|
$content = IDF_FileUtil::emphasizeControlCharacters(Pluf_esc($content));
|
||||||
|
$contents[] = sprintf('<td class="%s%s mono">%s</td>', $class, $pretty, $content);
|
||||||
|
}
|
||||||
|
if (count($file['chunks']) > $cc) {
|
||||||
|
$offsets[] = '<td class="next">...</td><td class="next">...</td>';
|
||||||
|
$contents[] = '<td class="next"></td>';
|
||||||
}
|
}
|
||||||
if (count($file['chunks']) > $cc)
|
|
||||||
$out .= '<tr class="diff-next"><td>...</td><td>...</td><td> </td></tr>'."\n";
|
|
||||||
$cc++;
|
$cc++;
|
||||||
}
|
}
|
||||||
$out .= '</table>';
|
|
||||||
}
|
|
||||||
return Pluf_Template::markSafe($out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function padLine($line)
|
list($added, $removed) = end($file['chunks_def']);
|
||||||
{
|
|
||||||
$line = str_replace("\t", ' ', $line);
|
$added = $added[0] + $added[1];
|
||||||
$n = strlen($line);
|
$leftwidth = 1;
|
||||||
for ($i=0;$i<$n;$i++) {
|
if ($added > 0)
|
||||||
if (substr($line, $i, 1) != ' ') {
|
$leftwidth = ((ceil(log10($added)) + 1) * 8) + 12;
|
||||||
break;
|
|
||||||
}
|
$removed = $removed[0] + $removed[1];
|
||||||
|
$rightwidth = 1;
|
||||||
|
if ($removed > 0)
|
||||||
|
$rightwidth = ((ceil(log10($removed)) + 1) * 8) + 12;
|
||||||
|
|
||||||
|
$inner_linecounts =
|
||||||
|
'<table class="diff-linecounts">' ."\n".
|
||||||
|
'<colgroup><col width="'.$leftwidth.'" /><col width="'. $rightwidth.'" /></colgroup>' ."\n".
|
||||||
|
'<tr class="line">' .
|
||||||
|
implode('</tr>'."\n".'<tr class="line">', $offsets).
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
|
|
||||||
|
|
||||||
|
$inner_contents =
|
||||||
|
'<table class="diff-contents">' ."\n".
|
||||||
|
'<tr class="line">' .
|
||||||
|
implode('</tr>'."\n".'<tr class="line">', $contents) .
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
|
|
||||||
|
$out .= '<table class="diff unified">' ."\n".
|
||||||
|
'<colgroup><col width="'.($leftwidth + $rightwidth + 1).'" /><col width="*" /></colgroup>' ."\n".
|
||||||
|
'<tr id="diff-'.md5($filename).'">'.
|
||||||
|
'<th colspan="2">'.Pluf_esc($filename).'</th>'.
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'<tr>' .
|
||||||
|
'<td>'. $inner_linecounts .'</td>'. "\n".
|
||||||
|
'<td><div class="scroll">'. $inner_contents .'</div></td>'.
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
}
|
}
|
||||||
return str_repeat(' ', $i).substr($line, $i);
|
|
||||||
|
return Pluf_Template::markSafe($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,12 +244,12 @@ class IDF_Diff
|
|||||||
*/
|
*/
|
||||||
public function fileCompare($orig, $chunks, $filename, $context=10)
|
public function fileCompare($orig, $chunks, $filename, $context=10)
|
||||||
{
|
{
|
||||||
$orig_lines = preg_split("/\015\012|\015|\012/", $orig);
|
$orig_lines = IDF_FileUtil::splitIntoLines($orig);
|
||||||
$new_chunks = $this->mergeChunks($orig_lines, $chunks, $context);
|
$new_chunks = $this->mergeChunks($orig_lines, $chunks, $context);
|
||||||
return $this->renderCompared($new_chunks, $filename);
|
return $this->renderCompared($new_chunks, $filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mergeChunks($orig_lines, $chunks, $context=10)
|
private function mergeChunks($orig_lines, $chunks, $context=10)
|
||||||
{
|
{
|
||||||
$spans = array();
|
$spans = array();
|
||||||
$new_chunks = array();
|
$new_chunks = array();
|
||||||
@@ -310,38 +346,115 @@ class IDF_Diff
|
|||||||
return $nnew_chunks;
|
return $nnew_chunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderCompared($chunks, $filename)
|
private function renderCompared($chunks, $filename)
|
||||||
{
|
{
|
||||||
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
||||||
$pretty = '';
|
$pretty = '';
|
||||||
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
|
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
|
||||||
$pretty = ' prettyprint';
|
$pretty = ' prettyprint';
|
||||||
}
|
}
|
||||||
$out = '';
|
|
||||||
$cc = 1;
|
$cc = 1;
|
||||||
$i = 0;
|
$left_offsets = array();
|
||||||
|
$left_contents = array();
|
||||||
|
$right_offsets = array();
|
||||||
|
$right_contents = array();
|
||||||
|
|
||||||
|
$max_lineno_left = $max_lineno_right = 0;
|
||||||
|
|
||||||
foreach ($chunks as $chunk) {
|
foreach ($chunks as $chunk) {
|
||||||
foreach ($chunk as $line) {
|
foreach ($chunk as $line) {
|
||||||
$line1 = ' ';
|
$left = '';
|
||||||
$line2 = ' ';
|
$right = '';
|
||||||
$line[2] = (strlen($line[2])) ? self::padLine(Pluf_esc($line[2])) : ' ';
|
$content = IDF_FileUtil::emphasizeControlCharacters(Pluf_esc($line[2]));
|
||||||
|
|
||||||
if ($line[0] and $line[1]) {
|
if ($line[0] and $line[1]) {
|
||||||
$class = 'diff-c';
|
$class = 'context';
|
||||||
$line1 = $line2 = $line[2];
|
$left = $right = $content;
|
||||||
} elseif ($line[0]) {
|
} elseif ($line[0]) {
|
||||||
$class = 'diff-r';
|
$class = 'removed';
|
||||||
$line1 = $line[2];
|
$left = $content;
|
||||||
} else {
|
} else {
|
||||||
$class = 'diff-a';
|
$class = 'added';
|
||||||
$line2 = $line[2];
|
$right = $content;
|
||||||
}
|
}
|
||||||
$out .= sprintf('<tr class="diff-line"><td class="diff-lc">%s</td><td class="%s mono%s"><code>%s</code></td><td class="diff-lc">%s</td><td class="%s mono%s"><code>%s</code></td></tr>'."\n", $line[0], $class, $pretty, $line1, $line[1], $class, $pretty, $line2);
|
|
||||||
|
$left_offsets[] = sprintf('<td>%s</td>', $line[0]);
|
||||||
|
$right_offsets[] = sprintf('<td>%s</td>', $line[1]);
|
||||||
|
$left_contents[] = sprintf('<td class="%s%s mono">%s</td>', $class, $pretty, $left);
|
||||||
|
$right_contents[] = sprintf('<td class="%s%s mono">%s</td>', $class, $pretty, $right);
|
||||||
|
|
||||||
|
$max_lineno_left = max($max_lineno_left, $line[0]);
|
||||||
|
$max_lineno_right = max($max_lineno_right, $line[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($chunks) > $cc) {
|
||||||
|
$left_offsets[] = '<td class="next">...</td>';
|
||||||
|
$right_offsets[] = '<td class="next">...</td>';
|
||||||
|
$left_contents[] = '<td></td>';
|
||||||
|
$right_contents[] = '<td></td>';
|
||||||
}
|
}
|
||||||
if (count($chunks) > $cc)
|
|
||||||
$out .= '<tr class="diff-next"><td>...</td><td> </td><td>...</td><td> </td></tr>'."\n";
|
|
||||||
$cc++;
|
$cc++;
|
||||||
$i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$leftwidth = 1;
|
||||||
|
if ($max_lineno_left > 0)
|
||||||
|
$leftwidth = ((ceil(log10($max_lineno_left)) + 1) * 8) + 12;
|
||||||
|
|
||||||
|
$rightwidth = 1;
|
||||||
|
if ($max_lineno_right > 0)
|
||||||
|
$rightwidth = ((ceil(log10($max_lineno_right)) + 1) * 8) + 12;
|
||||||
|
|
||||||
|
$inner_linecounts_left =
|
||||||
|
'<table class="diff-linecounts">' ."\n".
|
||||||
|
'<colgroup><col width="'.$leftwidth.'" /></colgroup>' ."\n".
|
||||||
|
'<tr class="line">' .
|
||||||
|
implode('</tr>'."\n".'<tr class="line">', $left_offsets).
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
|
|
||||||
|
$inner_linecounts_right =
|
||||||
|
'<table class="diff-linecounts">' ."\n".
|
||||||
|
'<colgroup><col width="'.$rightwidth.'" /></colgroup>' ."\n".
|
||||||
|
'<tr class="line">' .
|
||||||
|
implode('</tr>'."\n".'<tr class="line">', $right_offsets).
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
|
|
||||||
|
$inner_contents_left =
|
||||||
|
'<table class="diff-contents">' ."\n".
|
||||||
|
'<tr class="line">' .
|
||||||
|
implode('</tr>'."\n".'<tr class="line">', $left_contents) .
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
|
|
||||||
|
$inner_contents_right =
|
||||||
|
'<table class="diff-contents">' ."\n".
|
||||||
|
'<tr class="line">' .
|
||||||
|
implode('</tr>'."\n".'<tr class="line">', $right_contents) .
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
|
|
||||||
|
$out =
|
||||||
|
'<table class="diff context">' ."\n".
|
||||||
|
'<colgroup>' .
|
||||||
|
'<col width="'.($leftwidth + 1).'" /><col width="*" />' .
|
||||||
|
'<col width="'.($rightwidth + 1).'" /><col width="*" />' .
|
||||||
|
'</colgroup>' ."\n".
|
||||||
|
'<tr id="diff-'.md5($filename).'">'.
|
||||||
|
'<th colspan="4">'.Pluf_esc($filename).'</th>'.
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'<tr>' .
|
||||||
|
'<th colspan="2">'.__('Old').'</th><th colspan="2">'.__('New').'</th>' .
|
||||||
|
'</tr>'.
|
||||||
|
'<tr>' .
|
||||||
|
'<td>'. $inner_linecounts_left .'</td>'. "\n".
|
||||||
|
'<td><div class="scroll">'. $inner_contents_left .'</div></td>'. "\n".
|
||||||
|
'<td>'. $inner_linecounts_right .'</td>'. "\n".
|
||||||
|
'<td><div class="scroll">'. $inner_contents_right .'</div></td>'. "\n".
|
||||||
|
'</tr>' ."\n".
|
||||||
|
'</table>' ."\n";
|
||||||
|
|
||||||
return Pluf_Template::markSafe($out);
|
return Pluf_Template::markSafe($out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -65,9 +65,9 @@ class IDF_FileUtil
|
|||||||
}
|
}
|
||||||
$table = array();
|
$table = array();
|
||||||
$i = 1;
|
$i = 1;
|
||||||
foreach (preg_split("/\015\012|\015|\012/", $content) as $line) {
|
foreach (self::splitIntoLines($content) as $line) {
|
||||||
$table[] = '<tr class="c-line"><td class="code-lc" id="L'.$i.'"><a href="#L'.$i.'">'.$i.'</a></td>'
|
$table[] = '<tr class="c-line"><td class="code-lc" id="L'.$i.'"><a href="#L'.$i.'">'.$i.'</a></td>'
|
||||||
.'<td class="code mono'.$pretty.'">'.IDF_Diff::padLine(Pluf_esc($line)).'</td></tr>';
|
.'<td class="code mono'.$pretty.'">'.self::emphasizeControlCharacters(Pluf_esc($line)).'</td></tr>';
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
return Pluf_Template::markSafe(implode("\n", $table));
|
return Pluf_Template::markSafe(implode("\n", $table));
|
||||||
@@ -143,6 +143,56 @@ class IDF_FileUtil
|
|||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits a string into separate lines while retaining the individual
|
||||||
|
* line ending character for every line.
|
||||||
|
*
|
||||||
|
* OS9 line endings are not supported.
|
||||||
|
*
|
||||||
|
* @param string content
|
||||||
|
* @param boolean if true, skip completely empty lines
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function splitIntoLines($content, $skipEmpty = false)
|
||||||
|
{
|
||||||
|
$flags = PREG_SPLIT_OFFSET_CAPTURE;
|
||||||
|
if ($skipEmpty) $flags |= PREG_SPLIT_NO_EMPTY;
|
||||||
|
$splitted = preg_split("/\r\n|\n/", $content, -1, $flags);
|
||||||
|
|
||||||
|
$last_off = -1;
|
||||||
|
$lines = array();
|
||||||
|
while (($split = array_shift($splitted)) !== null) {
|
||||||
|
if ($last_off != -1) {
|
||||||
|
$lines[] .= substr($content, $last_off, $split[1] - $last_off);
|
||||||
|
}
|
||||||
|
$last_off = $split[1];
|
||||||
|
}
|
||||||
|
$lines[] = substr($content, $last_off);
|
||||||
|
return $lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This translates most of the C0 ASCII control characters into
|
||||||
|
* their visual counterparts in the 0x24## unicode plane
|
||||||
|
* (http://en.wikipedia.org/wiki/C0_and_C1_control_codes).
|
||||||
|
*
|
||||||
|
* We could add DEL (0x7F) to this set, but unfortunately this
|
||||||
|
* is not nicely mapped to 0x247F in the control plane, but 0x2421
|
||||||
|
* and adding an if expression below just for this is a little bit
|
||||||
|
* of a hassle. And of course, the more esoteric ones from C1 are
|
||||||
|
* missing as well...
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function emphasizeControlCharacters($content)
|
||||||
|
{
|
||||||
|
return preg_replace(
|
||||||
|
'/([\x00-\x1F])/ue',
|
||||||
|
'"<span class=\"ctrl-char\" title=\"0x".bin2hex("\\1")."\">$".bin2hex("\\1")."</span>"',
|
||||||
|
$content);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find if a given mime type is a text file.
|
* Find if a given mime type is a text file.
|
||||||
* This uses the output of the self::getMimeType function.
|
* This uses the output of the self::getMimeType function.
|
||||||
|
@@ -319,6 +319,7 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
|
|||||||
'labels_issue_closed' => IDF_Form_IssueTrackingConf::init_closed,
|
'labels_issue_closed' => IDF_Form_IssueTrackingConf::init_closed,
|
||||||
'labels_issue_predefined' => IDF_Form_IssueTrackingConf::init_predefined,
|
'labels_issue_predefined' => IDF_Form_IssueTrackingConf::init_predefined,
|
||||||
'labels_issue_one_max' => IDF_Form_IssueTrackingConf::init_one_max,
|
'labels_issue_one_max' => IDF_Form_IssueTrackingConf::init_one_max,
|
||||||
|
'issue_relations' => IDF_Form_IssueTrackingConf::init_relations,
|
||||||
'webhook_url' => '',
|
'webhook_url' => '',
|
||||||
'downloads_access_rights' => 'all',
|
'downloads_access_rights' => 'all',
|
||||||
'review_access_rights' => 'all',
|
'review_access_rights' => 'all',
|
||||||
|
@@ -36,6 +36,7 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
public $user = null;
|
public $user = null;
|
||||||
public $project = null;
|
public $project = null;
|
||||||
public $show_full = false;
|
public $show_full = false;
|
||||||
|
public $relation_types = null;
|
||||||
|
|
||||||
public function initFields($extra=array())
|
public function initFields($extra=array())
|
||||||
{
|
{
|
||||||
@@ -45,9 +46,12 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||||
$this->show_full = true;
|
$this->show_full = true;
|
||||||
}
|
}
|
||||||
|
$this->relation_types = $this->project->getRelationsFromConfig();
|
||||||
|
|
||||||
$contentTemplate = $this->project->getConf()->getVal(
|
$contentTemplate = $this->project->getConf()->getVal(
|
||||||
'labels_issue_template', IDF_Form_IssueTrackingConf::init_template
|
'labels_issue_template', IDF_Form_IssueTrackingConf::init_template
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => true,
|
array('required' => true,
|
||||||
'label' => __('Summary'),
|
'label' => __('Summary'),
|
||||||
@@ -76,11 +80,11 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
// case of someone allowing the upload path to be accessible
|
// case of someone allowing the upload path to be accessible
|
||||||
// to everybody.
|
// to everybody.
|
||||||
for ($i=1;$i<4;$i++) {
|
for ($i=1;$i<4;$i++) {
|
||||||
$filename = substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/'.substr($md5, 4).'/%s.dummy';
|
$filename = substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/'.substr($md5, 4).'/%s.dummy';
|
||||||
$this->fields['attachment'.$i] = new Pluf_Form_Field_File(
|
$this->fields['attachment'.$i] = new Pluf_Form_Field_File(
|
||||||
array('required' => false,
|
array('required' => false,
|
||||||
'label' => __('Attach a file'),
|
'label' => __('Attach a file'),
|
||||||
'move_function_params' =>
|
'move_function_params' =>
|
||||||
array('upload_path' => $upload_path,
|
array('upload_path' => $upload_path,
|
||||||
'upload_path_create' => true,
|
'upload_path_create' => true,
|
||||||
'file_name' => $filename,
|
'file_name' => $filename,
|
||||||
@@ -109,6 +113,20 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$this->fields['relation_type0'] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => __('This issue'),
|
||||||
|
'initial' => current($this->relation_types),
|
||||||
|
'widget_attrs' => array('size' => 15),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->fields['relation_issue0'] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => null,
|
||||||
|
'initial' => '',
|
||||||
|
'widget_attrs' => array('size' => 10),
|
||||||
|
));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get predefined tags for issues from current project
|
* get predefined tags for issues from current project
|
||||||
*
|
*
|
||||||
@@ -181,7 +199,7 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||||
trim($name));
|
trim($name));
|
||||||
} else {
|
} else {
|
||||||
$class = 'other';
|
$class = 'other';
|
||||||
@@ -215,10 +233,10 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
function clean_status()
|
function clean_status()
|
||||||
{
|
{
|
||||||
// Check that the status is in the list of official status
|
// Check that the status is in the list of official status
|
||||||
$tags = $this->project->getTagsFromConfig('labels_issue_open',
|
$tags = $this->project->getTagsFromConfig('labels_issue_open',
|
||||||
IDF_Form_IssueTrackingConf::init_open,
|
IDF_Form_IssueTrackingConf::init_open,
|
||||||
'Status');
|
'Status');
|
||||||
$tags = array_merge($this->project->getTagsFromConfig('labels_issue_closed',
|
$tags = array_merge($this->project->getTagsFromConfig('labels_issue_closed',
|
||||||
IDF_Form_IssueTrackingConf::init_closed,
|
IDF_Form_IssueTrackingConf::init_closed,
|
||||||
'Status')
|
'Status')
|
||||||
, $tags);
|
, $tags);
|
||||||
@@ -235,6 +253,63 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
return $this->cleaned_data['status'];
|
return $this->cleaned_data['status'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this method is not called from Pluf_Form directly, but shared for
|
||||||
|
// among all similar fields
|
||||||
|
function clean_relation_type($value)
|
||||||
|
{
|
||||||
|
$relation_type = trim($value);
|
||||||
|
if (empty($relation_type))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
$found = false;
|
||||||
|
foreach ($this->relation_types as $type) {
|
||||||
|
if ($type == $relation_type) {
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$found) {
|
||||||
|
throw new Pluf_Form_Invalid(__('You provided an invalid relation type.'));
|
||||||
|
}
|
||||||
|
return $relation_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean_relation_type0()
|
||||||
|
{
|
||||||
|
return $this->clean_relation_type($this->cleaned_data['relation_type0']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method is not called from Pluf_Form directly, but shared for
|
||||||
|
// among all similar fields
|
||||||
|
function clean_relation_issue($value)
|
||||||
|
{
|
||||||
|
$issues = trim($value);
|
||||||
|
if (empty($issues))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
$issue_ids = preg_split('/\s*,\s*/', $issues, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
foreach ($issue_ids as $issue_id) {
|
||||||
|
if (!ctype_digit($issue_id) || (int)$issue_id < 1) {
|
||||||
|
throw new Pluf_Form_Invalid(sprintf(
|
||||||
|
__('The value "%s" is not a valid issue id.'), $issue_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
$issue = new IDF_Issue($issue_id);
|
||||||
|
if ($issue->id != $issue_id || $issue->project != $this->project->id) {
|
||||||
|
throw new Pluf_Form_Invalid(sprintf(
|
||||||
|
__('The issue "%s" does not exist.'), $issue_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(', ', $issue_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean_relation_issue0()
|
||||||
|
{
|
||||||
|
return $this->clean_relation_issue($this->cleaned_data['relation_issue0']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean the attachments post failure.
|
* Clean the attachments post failure.
|
||||||
*/
|
*/
|
||||||
@@ -298,6 +373,30 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
$issue->setAssoc($tag);
|
$issue->setAssoc($tag);
|
||||||
}
|
}
|
||||||
|
// add relations (if any)
|
||||||
|
if (!empty($this->cleaned_data['relation_type0'])) {
|
||||||
|
$verb = $this->cleaned_data['relation_type0'];
|
||||||
|
$other_verb = $this->relation_types[$verb];
|
||||||
|
$related_issues = preg_split('/\s*,\s*/', $this->cleaned_data['relation_issue0'], -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
|
||||||
|
foreach ($related_issues as $related_issue_id) {
|
||||||
|
$related_issue = new IDF_Issue($related_issue_id);
|
||||||
|
$rel = new IDF_IssueRelation();
|
||||||
|
$rel->issue = $issue;
|
||||||
|
$rel->verb = $verb;
|
||||||
|
$rel->other_issue = $related_issue;
|
||||||
|
$rel->submitter = $this->user;
|
||||||
|
$rel->create();
|
||||||
|
|
||||||
|
$other_rel = new IDF_IssueRelation();
|
||||||
|
$other_rel->issue = $related_issue;
|
||||||
|
$other_rel->verb = $other_verb;
|
||||||
|
$other_rel->other_issue = $issue;
|
||||||
|
$other_rel->submitter = $this->user;
|
||||||
|
$other_rel->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add the first comment
|
// add the first comment
|
||||||
$comment = new IDF_IssueComment();
|
$comment = new IDF_IssueComment();
|
||||||
$comment->issue = $issue;
|
$comment->issue = $issue;
|
||||||
|
@@ -72,12 +72,29 @@ Performance = Performance issue
|
|||||||
Usability = Affects program usability
|
Usability = Affects program usability
|
||||||
Maintainability = Hinders future changes';
|
Maintainability = Hinders future changes';
|
||||||
const init_one_max = 'Type, Priority, Milestone';
|
const init_one_max = 'Type, Priority, Milestone';
|
||||||
|
// ATTENTION: if you change something here, change the values below as well!
|
||||||
|
const init_relations = 'is related to
|
||||||
|
blocks, is blocked by
|
||||||
|
duplicates, is duplicated by';
|
||||||
|
|
||||||
|
// These are actually all noop's, but we have no other chance to
|
||||||
|
// tell IDF's translation mechanism to mark the strings as translatable
|
||||||
|
// FIXME: IDF should get a internal translation system for strings like
|
||||||
|
// that, that can also be easily expanded by users
|
||||||
|
private function noop()
|
||||||
|
{
|
||||||
|
__('is related to');
|
||||||
|
__('blocks');
|
||||||
|
__('is blocked by');
|
||||||
|
__('duplicates');
|
||||||
|
__('is duplicated by');
|
||||||
|
}
|
||||||
|
|
||||||
public function initFields($extra=array())
|
public function initFields($extra=array())
|
||||||
{
|
{
|
||||||
$this->fields['labels_issue_template'] = new Pluf_Form_Field_Varchar(
|
$this->fields['labels_issue_template'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => false,
|
array('required' => false,
|
||||||
'label' => __('Define an issue template to hint to the reporter to provide certain information'),
|
'label' => __('Define an issue template to hint the reporter to provide certain information'),
|
||||||
'initial' => self::init_template,
|
'initial' => self::init_template,
|
||||||
'widget_attrs' => array('rows' => 7,
|
'widget_attrs' => array('rows' => 7,
|
||||||
'cols' => 75),
|
'cols' => 75),
|
||||||
@@ -114,10 +131,19 @@ Maintainability = Hinders future changes';
|
|||||||
$this->fields['labels_issue_one_max'] = new Pluf_Form_Field_Varchar(
|
$this->fields['labels_issue_one_max'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => false,
|
array('required' => false,
|
||||||
'label' => __('Each issue may have at most one label with each of these classes'),
|
'label' => __('Each issue may have at most one label with each of these classes'),
|
||||||
'initial' => self::init_one_max,
|
'initial' => self::init_one_max,
|
||||||
'widget_attrs' => array('size' => 60),
|
'widget_attrs' => array('size' => 60),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$this->fields['issue_relations'] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => true,
|
||||||
|
'label' => __('Issue relations'),
|
||||||
|
'initial' => self::init_relations,
|
||||||
|
'help_text' => __('You can define bidirectional relations like "is related to" or "blocks, is blocked by".'),
|
||||||
|
'widget_attrs' => array('rows' => 7,
|
||||||
|
'cols' => 75),
|
||||||
|
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,6 +39,7 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
|||||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||||
$this->show_full = true;
|
$this->show_full = true;
|
||||||
}
|
}
|
||||||
|
$this->relation_types = $this->project->getRelationsFromConfig();
|
||||||
if ($this->show_full) {
|
if ($this->show_full) {
|
||||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => true,
|
array('required' => true,
|
||||||
@@ -69,11 +70,11 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
|||||||
// case of someone allowing the upload path to be accessible
|
// case of someone allowing the upload path to be accessible
|
||||||
// to everybody.
|
// to everybody.
|
||||||
for ($i=1;$i<4;$i++) {
|
for ($i=1;$i<4;$i++) {
|
||||||
$filename = substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/'.substr($md5, 4).'/%s.dummy';
|
$filename = substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/'.substr($md5, 4).'/%s.dummy';
|
||||||
$this->fields['attachment'.$i] = new Pluf_Form_Field_File(
|
$this->fields['attachment'.$i] = new Pluf_Form_Field_File(
|
||||||
array('required' => false,
|
array('required' => false,
|
||||||
'label' => __('Attach a file'),
|
'label' => __('Attach a file'),
|
||||||
'move_function_params' =>
|
'move_function_params' =>
|
||||||
array('upload_path' => $upload_path,
|
array('upload_path' => $upload_path,
|
||||||
'upload_path_create' => true,
|
'upload_path_create' => true,
|
||||||
'file_name' => $filename,
|
'file_name' => $filename,
|
||||||
@@ -102,6 +103,52 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
|||||||
'size' => 15,
|
'size' => 15,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$idx = 0;
|
||||||
|
// note: clean_relation_type0 and clean_relation_issue0 already
|
||||||
|
// exist in the base class
|
||||||
|
$this->fields['relation_type'.$idx] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => __('This issue'),
|
||||||
|
'initial' => current($this->relation_types),
|
||||||
|
'widget_attrs' => array('size' => 15),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->fields['relation_issue'.$idx] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => null,
|
||||||
|
'initial' => '',
|
||||||
|
'widget_attrs' => array('size' => 10),
|
||||||
|
));
|
||||||
|
|
||||||
|
++$idx;
|
||||||
|
$relatedIssues = $this->issue->getGroupedRelatedIssues(array(), true);
|
||||||
|
foreach ($relatedIssues as $verb => $ids) {
|
||||||
|
$this->fields['relation_type'.$idx] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => __('This issue'),
|
||||||
|
'initial' => $verb,
|
||||||
|
'widget_attrs' => array('size' => 15),
|
||||||
|
));
|
||||||
|
$m = 'clean_relation_type'.$idx;
|
||||||
|
$this->$m = create_function('$form', '
|
||||||
|
return $form->clean_relation_type($form->cleaned_data["relation_type'.$idx.'"]);
|
||||||
|
');
|
||||||
|
|
||||||
|
$this->fields['relation_issue'.$idx] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => null,
|
||||||
|
'initial' => implode(', ', $ids),
|
||||||
|
'widget_attrs' => array('size' => 10),
|
||||||
|
));
|
||||||
|
$m = 'clean_relation_issue'.$idx;
|
||||||
|
$this->$m = create_function('$form', '
|
||||||
|
return $form->clean_relation_issue($form->cleaned_data["relation_issue'.$idx.'"]);
|
||||||
|
');
|
||||||
|
|
||||||
|
++$idx;
|
||||||
|
}
|
||||||
|
|
||||||
$tags = $this->issue->get_tags_list();
|
$tags = $this->issue->get_tags_list();
|
||||||
for ($i=1;$i<7;$i++) {
|
for ($i=1;$i<7;$i++) {
|
||||||
$initial = '';
|
$initial = '';
|
||||||
@@ -155,6 +202,51 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
|||||||
public function clean()
|
public function clean()
|
||||||
{
|
{
|
||||||
$this->cleaned_data = parent::clean();
|
$this->cleaned_data = parent::clean();
|
||||||
|
|
||||||
|
// normalize the user's input by removing dublettes and by combining
|
||||||
|
// ids from identical verbs in different input fields into one array
|
||||||
|
$normRelatedIssues = array();
|
||||||
|
for ($idx = 0; isset($this->cleaned_data['relation_type'.$idx]); ++$idx) {
|
||||||
|
$verb = $this->cleaned_data['relation_type'.$idx];
|
||||||
|
if (empty($verb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$ids = preg_split('/\s*,\s*/', $this->cleaned_data['relation_issue'.$idx],
|
||||||
|
-1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
if (count($ids) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!array_key_exists($verb, $normRelatedIssues))
|
||||||
|
$normRelatedIssues[$verb] = array();
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
if (!in_array($id, $normRelatedIssues[$verb]))
|
||||||
|
$normRelatedIssues[$verb][] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now look at any added / removed ids
|
||||||
|
$added = $removed = array();
|
||||||
|
$relatedIssues = $this->issue->getGroupedRelatedIssues(array(), true);
|
||||||
|
$added = array_diff_key($normRelatedIssues, $relatedIssues);
|
||||||
|
$removed = array_diff_key($relatedIssues, $normRelatedIssues);
|
||||||
|
|
||||||
|
$keysToLookAt = array_keys(
|
||||||
|
array_intersect_key($relatedIssues, $normRelatedIssues)
|
||||||
|
);
|
||||||
|
foreach ($keysToLookAt as $key) {
|
||||||
|
$a = array_diff($normRelatedIssues[$key], $relatedIssues[$key]);
|
||||||
|
if (count($a) > 0)
|
||||||
|
$added[$key] = $a;
|
||||||
|
$r = array_diff($relatedIssues[$key], $normRelatedIssues[$key]);
|
||||||
|
if (count($r) > 0)
|
||||||
|
$removed[$key] = $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache the added / removed data, so we do not have to
|
||||||
|
// calculate that again
|
||||||
|
$this->cleaned_data['_added_issue_relations'] = $added;
|
||||||
|
$this->cleaned_data['_removed_issue_relations'] = $removed;
|
||||||
|
|
||||||
// As soon as we know that at least one change was done, we
|
// As soon as we know that at least one change was done, we
|
||||||
// return the cleaned data and do not go further.
|
// return the cleaned data and do not go further.
|
||||||
if (strlen(trim($this->cleaned_data['content']))) {
|
if (strlen(trim($this->cleaned_data['content']))) {
|
||||||
@@ -214,6 +306,11 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
|||||||
return $this->cleaned_data;
|
return $this->cleaned_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count($this->cleaned_data['_added_issue_relations']) != 0 ||
|
||||||
|
count($this->cleaned_data['_removed_issue_relations']) != 0) {
|
||||||
|
return $this->cleaned_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// no changes!
|
// no changes!
|
||||||
throw new Pluf_Form_Invalid(__('No changes were entered.'));
|
throw new Pluf_Form_Invalid(__('No changes were entered.'));
|
||||||
@@ -255,20 +352,22 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
|||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
if (!Pluf_Model_InArray($tag, $oldtags)) {
|
if (!Pluf_Model_InArray($tag, $oldtags)) {
|
||||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||||
|
if (!isset($changes['lb']['add'])) $changes['lb']['add'] = array();
|
||||||
if ($tag->class != 'Other') {
|
if ($tag->class != 'Other') {
|
||||||
$changes['lb'][] = (string) $tag; //new tag
|
$changes['lb']['add'][] = (string) $tag; //new tag
|
||||||
} else {
|
} else {
|
||||||
$changes['lb'][] = (string) $tag->name;
|
$changes['lb']['add'][] = (string) $tag->name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($oldtags as $tag) {
|
foreach ($oldtags as $tag) {
|
||||||
if (!Pluf_Model_InArray($tag, $tags)) {
|
if (!Pluf_Model_InArray($tag, $tags)) {
|
||||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||||
|
if (!isset($changes['lb']['rem'])) $changes['lb']['rem'] = array();
|
||||||
if ($tag->class != 'Other') {
|
if ($tag->class != 'Other') {
|
||||||
$changes['lb'][] = '-'.(string) $tag; //new tag
|
$changes['lb']['rem'][] = (string) $tag; //new tag
|
||||||
} else {
|
} else {
|
||||||
$changes['lb'][] = '-'.(string) $tag->name;
|
$changes['lb']['rem'][] = (string) $tag->name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,6 +385,47 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
|||||||
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
|
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
|
||||||
$changes['ow'] = (is_null($owner)) ? '---' : $owner->login;
|
$changes['ow'] = (is_null($owner)) ? '---' : $owner->login;
|
||||||
}
|
}
|
||||||
|
// Issue relations - additions
|
||||||
|
foreach ($this->cleaned_data['_added_issue_relations'] as $verb => $ids) {
|
||||||
|
$other_verb = $this->relation_types[$verb];
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
$related_issue = new IDF_Issue($id);
|
||||||
|
$rel = new IDF_IssueRelation();
|
||||||
|
$rel->issue = $this->issue;
|
||||||
|
$rel->verb = $verb;
|
||||||
|
$rel->other_issue = $related_issue;
|
||||||
|
$rel->submitter = $this->user;
|
||||||
|
$rel->create();
|
||||||
|
|
||||||
|
$other_rel = new IDF_IssueRelation();
|
||||||
|
$other_rel->issue = $related_issue;
|
||||||
|
$other_rel->verb = $other_verb;
|
||||||
|
$other_rel->other_issue = $this->issue;
|
||||||
|
$other_rel->submitter = $this->user;
|
||||||
|
$other_rel->create();
|
||||||
|
}
|
||||||
|
if (!isset($changes['rel'])) $changes['rel'] = array();
|
||||||
|
if (!isset($changes['rel']['add'])) $changes['rel']['add'] = array();
|
||||||
|
$changes['rel']['add'][] = $verb.' '.implode(', ', $ids);
|
||||||
|
}
|
||||||
|
// Issue relations - removals
|
||||||
|
foreach ($this->cleaned_data['_removed_issue_relations'] as $verb => $ids) {
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
$db = &Pluf::db();
|
||||||
|
$table = Pluf::factory('IDF_IssueRelation')->getSqlTable();
|
||||||
|
$sql = new Pluf_SQL('verb=%s AND (
|
||||||
|
(issue=%s AND other_issue=%s) OR
|
||||||
|
(other_issue=%s AND issue=%s))',
|
||||||
|
array($verb,
|
||||||
|
$this->issue->id, $id,
|
||||||
|
$this->issue->id, $id));
|
||||||
|
$db->execute('DELETE FROM '.$table.' WHERE '.$sql->gen());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($changes['rel'])) $changes['rel'] = array();
|
||||||
|
if (!isset($changes['rel']['rem'])) $changes['rel']['rem'] = array();
|
||||||
|
$changes['rel']['rem'][] = $verb.' '.implode(', ', $ids);
|
||||||
|
}
|
||||||
// Update the issue
|
// Update the issue
|
||||||
$this->issue->batchAssoc('IDF_Tag', $tagids);
|
$this->issue->batchAssoc('IDF_Tag', $tagids);
|
||||||
$this->issue->summary = trim($this->cleaned_data['summary']);
|
$this->issue->summary = trim($this->cleaned_data['summary']);
|
||||||
|
@@ -169,6 +169,24 @@ class IDF_Issue extends Pluf_Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGroupedRelatedIssues($opts = array(), $idsOnly = false)
|
||||||
|
{
|
||||||
|
$rels = $this->get_related_issues_list(array_merge($opts, array(
|
||||||
|
'view' => 'with_other_issue',
|
||||||
|
)));
|
||||||
|
|
||||||
|
$res = array();
|
||||||
|
foreach ($rels as $rel) {
|
||||||
|
$verb = $rel->verb;
|
||||||
|
if (!array_key_exists($verb, $res)) {
|
||||||
|
$res[$verb] = array();
|
||||||
|
}
|
||||||
|
$res[$verb][] = $idsOnly ? $rel->other_issue : $rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an HTML fragment used to display this issue in the
|
* Returns an HTML fragment used to display this issue in the
|
||||||
* timeline.
|
* timeline.
|
||||||
|
@@ -155,10 +155,19 @@ class IDF_IssueComment extends Pluf_Model
|
|||||||
$out .= __('Owner:'); break;
|
$out .= __('Owner:'); break;
|
||||||
case 'lb':
|
case 'lb':
|
||||||
$out .= __('Labels:'); break;
|
$out .= __('Labels:'); break;
|
||||||
|
case 'rel':
|
||||||
|
$out .= __('Relations:'); break;
|
||||||
}
|
}
|
||||||
$out .= '</strong> ';
|
$out .= '</strong> ';
|
||||||
if ($w == 'lb') {
|
if ($w == 'lb' || $w == 'rel') {
|
||||||
$out .= Pluf_esc(implode(', ', $v));
|
foreach ($v as $t => $ls) {
|
||||||
|
foreach ($ls as $l) {
|
||||||
|
if ($t == 'rem') $out .= '<s>';
|
||||||
|
$out .= Pluf_esc($l);
|
||||||
|
if ($t == 'rem') $out .= '</s>';
|
||||||
|
$out .= ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$out .= Pluf_esc($v);
|
$out .= Pluf_esc($v);
|
||||||
}
|
}
|
||||||
|
100
src/IDF/IssueRelation.php
Normal file
100
src/IDF/IssueRelation.php
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero 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 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A relation of one issue to another
|
||||||
|
*/
|
||||||
|
class IDF_IssueRelation extends Pluf_Model
|
||||||
|
{
|
||||||
|
public $_model = __CLASS__;
|
||||||
|
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
$this->_a['table'] = 'idf_issuerelations';
|
||||||
|
$this->_a['model'] = __CLASS__;
|
||||||
|
$this->_a['cols'] = array(
|
||||||
|
// It is mandatory to have an "id" column.
|
||||||
|
'id' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Sequence',
|
||||||
|
'blank' => true,
|
||||||
|
),
|
||||||
|
'issue' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||||
|
'model' => 'IDF_Issue',
|
||||||
|
'blank' => false,
|
||||||
|
'verbose' => __('issue'),
|
||||||
|
'relate_name' => 'related_issues',
|
||||||
|
),
|
||||||
|
'verb' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Text',
|
||||||
|
'blank' => false,
|
||||||
|
'verbose' => __('verb'),
|
||||||
|
),
|
||||||
|
'other_issue' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||||
|
'model' => 'IDF_Issue',
|
||||||
|
'blank' => false,
|
||||||
|
'verbose' => __('other issue'),
|
||||||
|
'relate_name' => 'related_other_issues',
|
||||||
|
),
|
||||||
|
'submitter' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||||
|
'model' => 'Pluf_User',
|
||||||
|
'blank' => false,
|
||||||
|
'verbose' => __('submitter'),
|
||||||
|
),
|
||||||
|
'creation_dtime' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Datetime',
|
||||||
|
'blank' => true,
|
||||||
|
'verbose' => __('creation date'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$this->_a['idx'] = array(
|
||||||
|
'creation_dtime_idx' =>
|
||||||
|
array(
|
||||||
|
'col' => 'creation_dtime',
|
||||||
|
'type' => 'normal',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$issuetbl = $this->_con->pfx.'idf_issues';
|
||||||
|
$this->_a['views'] = array(
|
||||||
|
'with_other_issue' => array(
|
||||||
|
'join' => 'INNER JOIN '.$issuetbl.' ON other_issue='.$issuetbl.'.id',
|
||||||
|
'select' => $this->getSelect().', summary',
|
||||||
|
'props' => array('summary' => 'other_summary'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
function preSave($create=false)
|
||||||
|
{
|
||||||
|
if ($this->id == '') {
|
||||||
|
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -88,6 +88,7 @@ class IDF_Middleware
|
|||||||
'showuser' => 'IDF_Template_ShowUser',
|
'showuser' => 'IDF_Template_ShowUser',
|
||||||
'ashowuser' => 'IDF_Template_AssignShowUser',
|
'ashowuser' => 'IDF_Template_AssignShowUser',
|
||||||
'appversion' => 'IDF_Template_AppVersion',
|
'appversion' => 'IDF_Template_AppVersion',
|
||||||
|
'upload' => 'IDF_Template_Tag_UploadUrl',
|
||||||
));
|
));
|
||||||
$params['modifiers'] = array_merge($params['modifiers'],
|
$params['modifiers'] = array_merge($params['modifiers'],
|
||||||
array(
|
array(
|
||||||
|
90
src/IDF/Migrations/17AddIssueRelations.php
Normal file
90
src/IDF/Migrations/17AddIssueRelations.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero 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 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the new IDF_IssueRelation model.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function IDF_Migrations_17AddIssueRelations_up($params=null)
|
||||||
|
{
|
||||||
|
$db = Pluf::db();
|
||||||
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
$schema->model = new IDF_IssueRelation();
|
||||||
|
$schema->createTables();
|
||||||
|
|
||||||
|
// change the serialization format for added / removed labels in IDF_IssueComment
|
||||||
|
$comments = Pluf::factory('IDF_IssueComment')->getList();
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
if (!isset($comment->changes['lb'])) continue;
|
||||||
|
$changes = $comment->changes;
|
||||||
|
$adds = $removals = array();
|
||||||
|
foreach ($comment->changes['lb'] as $lb) {
|
||||||
|
if (substr($lb, 0, 1) == '-')
|
||||||
|
$removals[] = substr($lb, 1);
|
||||||
|
else
|
||||||
|
$adds[] = $lb;
|
||||||
|
}
|
||||||
|
$changes['lb'] = array();
|
||||||
|
if (count($adds) > 0)
|
||||||
|
$changes['lb']['add'] = $adds;
|
||||||
|
if (count($removals) > 0)
|
||||||
|
$changes['lb']['rem'] = $removals;
|
||||||
|
$comment->changes = $changes;
|
||||||
|
$comment->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function IDF_Migrations_17AddIssueRelations_down($params=null)
|
||||||
|
{
|
||||||
|
$db = Pluf::db();
|
||||||
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
$schema->model = new IDF_IssueRelation();
|
||||||
|
$schema->dropTables();
|
||||||
|
|
||||||
|
// change the serialization format for added / removed labels in IDF_IssueComment
|
||||||
|
$comments = Pluf::factory('IDF_IssueComment')->getList();
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
$changes = $comment->changes;
|
||||||
|
if (empty($changes))
|
||||||
|
continue;
|
||||||
|
if (isset($changes['lb'])) {
|
||||||
|
$labels = array();
|
||||||
|
foreach ($changes['lb'] as $type => $lbs) {
|
||||||
|
if (!is_array($lbs)) {
|
||||||
|
$labels[] = $lbs;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($lbs as $lb) {
|
||||||
|
$labels[] = ($type == 'rem' ? '-' : '') . $lb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$changes['lb'] = $labels;
|
||||||
|
}
|
||||||
|
// while we're at it, remove any 'rel' changes
|
||||||
|
unset($changes['rel']);
|
||||||
|
$comment->changes = $changes;
|
||||||
|
$comment->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -54,6 +54,7 @@ function IDF_Migrations_Backup_run($folder, $name=null)
|
|||||||
'IDF_Queue',
|
'IDF_Queue',
|
||||||
'IDF_Gconf',
|
'IDF_Gconf',
|
||||||
'IDF_EmailAddress',
|
'IDF_EmailAddress',
|
||||||
|
'IDF_IssueRelation',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
// Now, for each table, we dump the content in json, this is a
|
// Now, for each table, we dump the content in json, this is a
|
||||||
@@ -100,6 +101,7 @@ function IDF_Migrations_Backup_restore($folder, $name)
|
|||||||
'IDF_Queue',
|
'IDF_Queue',
|
||||||
'IDF_Gconf',
|
'IDF_Gconf',
|
||||||
'IDF_EmailAddress',
|
'IDF_EmailAddress',
|
||||||
|
'IDF_IssueRelation',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
$schema = new Pluf_DB_Schema($db);
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
@@ -51,6 +51,7 @@ function IDF_Migrations_Install_setup($params=null)
|
|||||||
'IDF_Queue',
|
'IDF_Queue',
|
||||||
'IDF_Gconf',
|
'IDF_Gconf',
|
||||||
'IDF_EmailAddress',
|
'IDF_EmailAddress',
|
||||||
|
'IDF_IssueRelation',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
$schema = new Pluf_DB_Schema($db);
|
$schema = new Pluf_DB_Schema($db);
|
||||||
@@ -109,6 +110,7 @@ function IDF_Migrations_Install_teardown($params=null)
|
|||||||
'IDF_Commit',
|
'IDF_Commit',
|
||||||
'IDF_Project',
|
'IDF_Project',
|
||||||
'IDF_EmailAddress',
|
'IDF_EmailAddress',
|
||||||
|
'IDF_IssueRelation',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
$schema = new Pluf_DB_Schema($db);
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
@@ -59,6 +59,16 @@ class IDF_Plugin_SyncGit_Cron
|
|||||||
$out .= sprintf($template, $cmd, $key->login, $content)."\n";
|
$out .= sprintf($template, $cmd, $key->login, $content)."\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$out = "# indefero start" . PHP_EOL . $out . "# indefero end" . PHP_EOL;
|
||||||
|
|
||||||
|
// We update only the part of the file between IDF_START / IDF_END comment
|
||||||
|
$original_keys = file_get_contents($authorized_keys);
|
||||||
|
if (strstr($original_keys, "# indefero start") && strstr($original_keys, "# indefero end")) {
|
||||||
|
$out = preg_replace('/(#\sindefero\sstart).+(#\sindefero\send\s\s?)/isU',
|
||||||
|
$out, $original_keys);
|
||||||
|
} else {
|
||||||
|
$out .= $original_keys;
|
||||||
|
}
|
||||||
file_put_contents($authorized_keys, $out, LOCK_EX);
|
file_put_contents($authorized_keys, $out, LOCK_EX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,6 +27,18 @@
|
|||||||
*/
|
*/
|
||||||
class IDF_Plugin_SyncMonotone
|
class IDF_Plugin_SyncMonotone
|
||||||
{
|
{
|
||||||
|
private $old_err_rep = 0;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->old_err_rep = error_reporting(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
error_reporting($this->old_err_rep);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point of the plugin.
|
* Entry point of the plugin.
|
||||||
*/
|
*/
|
||||||
@@ -80,24 +92,33 @@ class IDF_Plugin_SyncMonotone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This guard cleans up on any kind of error, and here is how it works:
|
||||||
|
// As long as the guard is not committed, it keeps a reference to
|
||||||
|
// the given project. When the guard is destroyed and the reference
|
||||||
|
// is still present, it deletes the object. The deletion indirectly
|
||||||
|
// also calls into this plugin again, as the project delete hook
|
||||||
|
// will be called, that removes any changes we've made during the
|
||||||
|
// process.
|
||||||
|
$projectGuard = new IDF_Plugin_SyncMonotone_ModelGuard($project);
|
||||||
|
|
||||||
$projecttempl = Pluf::f('mtn_repositories', false);
|
$projecttempl = Pluf::f('mtn_repositories', false);
|
||||||
if ($projecttempl === false) {
|
if ($projecttempl === false) {
|
||||||
throw new IDF_Scm_Exception(
|
$this->_diagnoseProblem(
|
||||||
__('"mtn_repositories" must be defined in your configuration file.')
|
__('"mtn_repositories" must be defined in your configuration file')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$usher_config = Pluf::f('mtn_usher_conf', false);
|
$usher_config = Pluf::f('mtn_usher_conf', false);
|
||||||
if (!$usher_config || !is_writable($usher_config)) {
|
if (!$usher_config || !is_writable($usher_config)) {
|
||||||
throw new IDF_Scm_Exception(
|
$this->_diagnoseProblem(
|
||||||
__('"mtn_usher_conf" does not exist or is not writable.')
|
__('"mtn_usher_conf" does not exist or is not writable')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$mtnpostpush = realpath(dirname(__FILE__) . '/../../../scripts/mtn-post-push');
|
$mtnpostpush = realpath(dirname(__FILE__) . '/../../../scripts/mtn-post-push');
|
||||||
if (!file_exists($mtnpostpush)) {
|
if (!file_exists($mtnpostpush)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not find mtn-post-push script "%s".'), $mtnpostpush
|
__('Could not find mtn-post-push script "%s"'), $mtnpostpush
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,13 +131,12 @@ class IDF_Plugin_SyncMonotone
|
|||||||
'monotonerc.in',
|
'monotonerc.in',
|
||||||
'remote-automate-permissions.in',
|
'remote-automate-permissions.in',
|
||||||
'hooks.d/',
|
'hooks.d/',
|
||||||
// this is linked and not copied to be able to update
|
|
||||||
// the list of read-only commands on upgrades
|
|
||||||
'hooks.d/indefero_authorize_remote_automate.conf',
|
|
||||||
'hooks.d/indefero_authorize_remote_automate.lua',
|
'hooks.d/indefero_authorize_remote_automate.lua',
|
||||||
'hooks.d/indefero_post_push.conf.in',
|
'hooks.d/indefero_post_push.conf.in',
|
||||||
'hooks.d/indefero_post_push.lua',
|
'hooks.d/indefero_post_push.lua',
|
||||||
);
|
);
|
||||||
|
// enable remote command execution of read-only commands
|
||||||
|
// only for public projects
|
||||||
if (!$project->private) {
|
if (!$project->private) {
|
||||||
// this is linked and not copied to be able to update
|
// this is linked and not copied to be able to update
|
||||||
// the list of read-only commands on upgrades
|
// the list of read-only commands on upgrades
|
||||||
@@ -131,8 +151,8 @@ class IDF_Plugin_SyncMonotone
|
|||||||
}
|
}
|
||||||
foreach ($confdir_contents as $content) {
|
foreach ($confdir_contents as $content) {
|
||||||
if (!file_exists($confdir.$content)) {
|
if (!file_exists($confdir.$content)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('The configuration file %s is missing.'), $content
|
__('The configuration file "%s" is missing'), $content
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,14 +160,15 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$shortname = $project->shortname;
|
$shortname = $project->shortname;
|
||||||
$projectpath = sprintf($projecttempl, $shortname);
|
$projectpath = sprintf($projecttempl, $shortname);
|
||||||
if (file_exists($projectpath)) {
|
if (file_exists($projectpath)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('The project path %s already exists.'), $projectpath
|
__('The project path "%s" already exists'), $projectpath
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mkdir($projectpath)) {
|
if (!@mkdir($projectpath)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('The project path %s could not be created.'), $projectpath
|
__('The project path "%s" could not be created'),
|
||||||
|
$projectpath
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +177,7 @@ class IDF_Plugin_SyncMonotone
|
|||||||
//
|
//
|
||||||
$dbfile = $projectpath.'/database.mtn';
|
$dbfile = $projectpath.'/database.mtn';
|
||||||
$cmd = sprintf('db init -d %s', escapeshellarg($dbfile));
|
$cmd = sprintf('db init -d %s', escapeshellarg($dbfile));
|
||||||
self::_mtn_exec($cmd);
|
$this->_mtn_exec($cmd);
|
||||||
|
|
||||||
//
|
//
|
||||||
// step 2) create a server key
|
// step 2) create a server key
|
||||||
@@ -175,16 +196,17 @@ class IDF_Plugin_SyncMonotone
|
|||||||
escapeshellarg($projectpath),
|
escapeshellarg($projectpath),
|
||||||
escapeshellarg($serverkey)
|
escapeshellarg($serverkey)
|
||||||
);
|
);
|
||||||
self::_mtn_exec($cmd);
|
$this->_mtn_exec($cmd);
|
||||||
|
|
||||||
//
|
//
|
||||||
// step 3) create a client key, and save it in IDF
|
// step 3) create a client key, and save it in IDF
|
||||||
//
|
//
|
||||||
$keydir = Pluf::f('tmp_folder').'/mtn-client-keys';
|
$keydir = Pluf::f('tmp_folder').'/mtn-client-keys';
|
||||||
if (!file_exists($keydir)) {
|
if (!file_exists($keydir)) {
|
||||||
if (!mkdir($keydir)) {
|
if (!@mkdir($keydir)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('The key directory %s could not be created.'), $keydir
|
__('The key directory "%s" could not be created'),
|
||||||
|
$keydir
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,14 +216,14 @@ class IDF_Plugin_SyncMonotone
|
|||||||
escapeshellarg($keydir),
|
escapeshellarg($keydir),
|
||||||
escapeshellarg($clientkey_name)
|
escapeshellarg($clientkey_name)
|
||||||
);
|
);
|
||||||
$keyinfo = self::_mtn_exec($cmd);
|
$keyinfo = $this->_mtn_exec($cmd);
|
||||||
|
|
||||||
$parsed_keyinfo = array();
|
$parsed_keyinfo = array();
|
||||||
try {
|
try {
|
||||||
$parsed_keyinfo = IDF_Scm_Monotone_BasicIO::parse($keyinfo);
|
$parsed_keyinfo = IDF_Scm_Monotone_BasicIO::parse($keyinfo);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not parse key information: %s'), $e->getMessage()
|
__('Could not parse key information: %s'), $e->getMessage()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -219,13 +241,13 @@ class IDF_Plugin_SyncMonotone
|
|||||||
escapeshellarg($keydir),
|
escapeshellarg($keydir),
|
||||||
escapeshellarg($clientkey_hash)
|
escapeshellarg($clientkey_hash)
|
||||||
);
|
);
|
||||||
$clientkey_pubdata = self::_mtn_exec($cmd);
|
$clientkey_pubdata = $this->_mtn_exec($cmd);
|
||||||
|
|
||||||
$cmd = sprintf('au put_public_key --db=%s %s',
|
$cmd = sprintf('au put_public_key --db=%s %s',
|
||||||
escapeshellarg($dbfile),
|
escapeshellarg($dbfile),
|
||||||
escapeshellarg($clientkey_pubdata)
|
escapeshellarg($clientkey_pubdata)
|
||||||
);
|
);
|
||||||
self::_mtn_exec($cmd);
|
$this->_mtn_exec($cmd);
|
||||||
|
|
||||||
//
|
//
|
||||||
// step 4) setup the configuration
|
// step 4) setup the configuration
|
||||||
@@ -238,18 +260,20 @@ class IDF_Plugin_SyncMonotone
|
|||||||
foreach ($confdir_contents as $content) {
|
foreach ($confdir_contents as $content) {
|
||||||
$filepath = $projectpath.'/'.$content;
|
$filepath = $projectpath.'/'.$content;
|
||||||
if (substr($content, -1) == '/') {
|
if (substr($content, -1) == '/') {
|
||||||
if (!mkdir($filepath)) {
|
if (!@mkdir($filepath)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not create configuration directory "%s"'), $filepath
|
__('Could not create configuration directory "%s"'),
|
||||||
|
$filepath
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (substr($content, -3) != '.in') {
|
if (substr($content, -3) != '.in') {
|
||||||
if (!symlink($confdir.$content, $filepath)) {
|
if (!@symlink($confdir.$content, $filepath)) {
|
||||||
IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not create symlink "%s"'), $filepath
|
__('Could not create symlink for configuration file "%s"'),
|
||||||
|
$filepath
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -264,9 +288,10 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
// remove the .in
|
// remove the .in
|
||||||
$filepath = substr($filepath, 0, -3);
|
$filepath = substr($filepath, 0, -3);
|
||||||
if (file_put_contents($filepath, $filecontents, LOCK_EX) === false) {
|
if (@file_put_contents($filepath, $filecontents, LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write configuration file "%s"'), $filepath
|
__('Could not write configuration file "%s"'),
|
||||||
|
$filepath
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,7 +305,7 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$parsed_config = IDF_Scm_Monotone_BasicIO::parse($usher_rc);
|
$parsed_config = IDF_Scm_Monotone_BasicIO::parse($usher_rc);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not parse usher configuration in "%s": %s'),
|
__('Could not parse usher configuration in "%s": %s'),
|
||||||
$usher_config, $e->getMessage()
|
$usher_config, $e->getMessage()
|
||||||
));
|
));
|
||||||
@@ -291,7 +316,7 @@ class IDF_Plugin_SyncMonotone
|
|||||||
foreach ($stanzas as $stanza_line) {
|
foreach ($stanzas as $stanza_line) {
|
||||||
if ($stanza_line['key'] == 'server' &&
|
if ($stanza_line['key'] == 'server' &&
|
||||||
$stanza_line['values'][0] == $shortname) {
|
$stanza_line['values'][0] == $shortname) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('usher configuration already contains a server '.
|
__('usher configuration already contains a server '.
|
||||||
'entry named "%s"'),
|
'entry named "%s"'),
|
||||||
$shortname
|
$shortname
|
||||||
@@ -315,9 +340,10 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
// FIXME: more sanity - what happens on failing writes? we do not
|
// FIXME: more sanity - what happens on failing writes? we do not
|
||||||
// have a backup copy of usher.conf around...
|
// have a backup copy of usher.conf around...
|
||||||
if (file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
|
if (@file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write usher configuration file "%s"'), $usher_config
|
__('Could not write usher configuration file "%s"'),
|
||||||
|
$usher_config
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,6 +351,9 @@ class IDF_Plugin_SyncMonotone
|
|||||||
// step 6) reload usher to pick up the new configuration
|
// step 6) reload usher to pick up the new configuration
|
||||||
//
|
//
|
||||||
IDF_Scm_Monotone_Usher::reload();
|
IDF_Scm_Monotone_Usher::reload();
|
||||||
|
|
||||||
|
// commit the guard, so the newly created project is not deleted
|
||||||
|
$projectGuard->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -345,8 +374,8 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$mtn = IDF_Scm_Monotone::factory($project);
|
$mtn = IDF_Scm_Monotone::factory($project);
|
||||||
$stdio = $mtn->getStdio();
|
$stdio = $mtn->getStdio();
|
||||||
|
|
||||||
$projectpath = self::_get_project_path($project);
|
$projectpath = $this->_get_project_path($project);
|
||||||
$auth_ids = self::_get_authorized_user_ids($project);
|
$auth_ids = $this->_get_authorized_user_ids($project);
|
||||||
$key_ids = array();
|
$key_ids = array();
|
||||||
foreach ($auth_ids as $auth_id) {
|
foreach ($auth_ids as $auth_id) {
|
||||||
$sql = new Pluf_SQL('user=%s', array($auth_id));
|
$sql = new Pluf_SQL('user=%s', array($auth_id));
|
||||||
@@ -361,9 +390,10 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
$write_permissions = implode("\n", $key_ids);
|
$write_permissions = implode("\n", $key_ids);
|
||||||
$rcfile = $projectpath.'/write-permissions';
|
$rcfile = $projectpath.'/write-permissions';
|
||||||
if (file_put_contents($rcfile, $write_permissions, LOCK_EX) === false) {
|
if (@file_put_contents($rcfile, $write_permissions, LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write write-permissions file "%s"'), $rcfile
|
__('Could not write write-permissions file "%s"'),
|
||||||
|
$rcfile
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,11 +412,13 @@ class IDF_Plugin_SyncMonotone
|
|||||||
array('key' => 'allow', 'values' => array('*')),
|
array('key' => 'allow', 'values' => array('*')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$read_permissions = IDF_Scm_Monotone_BasicIO::compile(array($stanza));
|
$read_permissions = IDF_Scm_Monotone_BasicIO::compile(array($stanza));
|
||||||
$rcfile = $projectpath.'/read-permissions';
|
$rcfile = $projectpath.'/read-permissions';
|
||||||
if (file_put_contents($rcfile, $read_permissions, LOCK_EX) === false) {
|
if (@file_put_contents($rcfile, $read_permissions, LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write read-permissions file "%s"'), $rcfile
|
__('Could not write read-permissions file "%s"'),
|
||||||
|
$rcfile
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,16 +433,16 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
$serverRestartRequired = false;
|
$serverRestartRequired = false;
|
||||||
if ($project->private && file_exists($projectfile) && is_link($projectfile)) {
|
if ($project->private && file_exists($projectfile) && is_link($projectfile)) {
|
||||||
if (!unlink($projectfile)) {
|
if (!@unlink($projectfile)) {
|
||||||
IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not remove symlink "%s"'), $projectfile
|
__('Could not remove symlink "%s"'), $projectfile
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
$serverRestartRequired = true;
|
$serverRestartRequired = true;
|
||||||
} else
|
} else
|
||||||
if (!$project->private && !file_exists($projectfile)) {
|
if (!$project->private && !file_exists($projectfile)) {
|
||||||
if (!symlink($templatefile, $projectfile)) {
|
if (!@symlink($templatefile, $projectfile)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not create symlink "%s"'), $projectfile
|
__('Could not create symlink "%s"'), $projectfile
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -422,6 +454,9 @@ class IDF_Plugin_SyncMonotone
|
|||||||
// seems to be ignored when the server should be started
|
// seems to be ignored when the server should be started
|
||||||
// again immediately afterwards
|
// again immediately afterwards
|
||||||
IDF_Scm_Monotone_Usher::killServer($project->shortname);
|
IDF_Scm_Monotone_Usher::killServer($project->shortname);
|
||||||
|
// give usher some time to cool down, otherwise it might hang
|
||||||
|
// (see https://code.monotone.ca/p/contrib/issues/175/)
|
||||||
|
sleep(2);
|
||||||
IDF_Scm_Monotone_Usher::startServer($project->shortname);
|
IDF_Scm_Monotone_Usher::startServer($project->shortname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,8 +478,8 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
$usher_config = Pluf::f('mtn_usher_conf', false);
|
$usher_config = Pluf::f('mtn_usher_conf', false);
|
||||||
if (!$usher_config || !is_writable($usher_config)) {
|
if (!$usher_config || !is_writable($usher_config)) {
|
||||||
throw new IDF_Scm_Exception(
|
$this->_diagnoseProblem(
|
||||||
__('"mtn_usher_conf" does not exist or is not writable.')
|
__('"mtn_usher_conf" does not exist or is not writable')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,16 +488,16 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
$projecttempl = Pluf::f('mtn_repositories', false);
|
$projecttempl = Pluf::f('mtn_repositories', false);
|
||||||
if ($projecttempl === false) {
|
if ($projecttempl === false) {
|
||||||
throw new IDF_Scm_Exception(
|
$this->_diagnoseProblem(
|
||||||
__('"mtn_repositories" must be defined in your configuration file.')
|
__('"mtn_repositories" must be defined in your configuration file')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$projectpath = sprintf($projecttempl, $shortname);
|
$projectpath = sprintf($projecttempl, $shortname);
|
||||||
if (file_exists($projectpath)) {
|
if (file_exists($projectpath)) {
|
||||||
if (!self::_delete_recursive($projectpath)) {
|
if (!$this->_delete_recursive($projectpath)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('One or more paths underknees %s could not be deleted.'), $projectpath
|
__('One or more paths underneath %s could not be deleted'), $projectpath
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -473,8 +508,9 @@ class IDF_Plugin_SyncMonotone
|
|||||||
if ($keyname && $keyhash &&
|
if ($keyname && $keyhash &&
|
||||||
file_exists($keydir .'/'. $keyname . '.' . $keyhash)) {
|
file_exists($keydir .'/'. $keyname . '.' . $keyhash)) {
|
||||||
if (!@unlink($keydir .'/'. $keyname . '.' . $keyhash)) {
|
if (!@unlink($keydir .'/'. $keyname . '.' . $keyhash)) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not delete client private key %s'), $keyname
|
__('Could not delete client private key "%s"'),
|
||||||
|
$keyname
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -485,7 +521,7 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$parsed_config = IDF_Scm_Monotone_BasicIO::parse($usher_rc);
|
$parsed_config = IDF_Scm_Monotone_BasicIO::parse($usher_rc);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not parse usher configuration in "%s": %s'),
|
__('Could not parse usher configuration in "%s": %s'),
|
||||||
$usher_config, $e->getMessage()
|
$usher_config, $e->getMessage()
|
||||||
));
|
));
|
||||||
@@ -505,9 +541,10 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
// FIXME: more sanity - what happens on failing writes? we do not
|
// FIXME: more sanity - what happens on failing writes? we do not
|
||||||
// have a backup copy of usher.conf around...
|
// have a backup copy of usher.conf around...
|
||||||
if (file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
|
if (@file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write usher configuration file "%s"'), $usher_config
|
__('Could not write usher configuration file "%s"'),
|
||||||
|
$usher_config
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,6 +565,8 @@ class IDF_Plugin_SyncMonotone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$keyGuard = new IDF_Plugin_SyncMonotone_ModelGuard($key);
|
||||||
|
|
||||||
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
||||||
$conf = new IDF_Conf();
|
$conf = new IDF_Conf();
|
||||||
$conf->setProject($project);
|
$conf->setProject($project);
|
||||||
@@ -535,8 +574,8 @@ class IDF_Plugin_SyncMonotone
|
|||||||
if ($scm != 'mtn')
|
if ($scm != 'mtn')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$projectpath = self::_get_project_path($project);
|
$projectpath = $this->_get_project_path($project);
|
||||||
$auth_ids = self::_get_authorized_user_ids($project);
|
$auth_ids = $this->_get_authorized_user_ids($project);
|
||||||
if (!in_array($key->user, $auth_ids))
|
if (!in_array($key->user, $auth_ids))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -556,7 +595,7 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$parsed_read_perms = IDF_Scm_Monotone_BasicIO::parse($read_perms);
|
$parsed_read_perms = IDF_Scm_Monotone_BasicIO::parse($read_perms);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not parse read-permissions for project "%s": %s'),
|
__('Could not parse read-permissions for project "%s": %s'),
|
||||||
$shortname, $e->getMessage()
|
$shortname, $e->getMessage()
|
||||||
));
|
));
|
||||||
@@ -598,10 +637,11 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
$read_perms = IDF_Scm_Monotone_BasicIO::compile($parsed_read_perms);
|
$read_perms = IDF_Scm_Monotone_BasicIO::compile($parsed_read_perms);
|
||||||
|
|
||||||
if (file_put_contents($projectpath.'/read-permissions',
|
if (@file_put_contents($projectpath.'/read-permissions',
|
||||||
$read_perms, LOCK_EX) === false) {
|
$read_perms, LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write read-permissions for project "%s"'), $shortname
|
__('Could not write read-permissions for project "%s"'),
|
||||||
|
$shortname
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,9 +651,9 @@ class IDF_Plugin_SyncMonotone
|
|||||||
if (!in_array('*', $lines) && !in_array($mtn_key_id, $lines)) {
|
if (!in_array('*', $lines) && !in_array($mtn_key_id, $lines)) {
|
||||||
$lines[] = $mtn_key_id;
|
$lines[] = $mtn_key_id;
|
||||||
}
|
}
|
||||||
if (file_put_contents($projectpath.'/write-permissions',
|
if (@file_put_contents($projectpath.'/write-permissions',
|
||||||
implode("\n", $lines) . "\n", LOCK_EX) === false) {
|
implode("\n", $lines) . "\n", LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write write-permissions file for project "%s"'),
|
__('Could not write write-permissions file for project "%s"'),
|
||||||
$shortname
|
$shortname
|
||||||
));
|
));
|
||||||
@@ -623,6 +663,8 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$stdio = $mtn->getStdio();
|
$stdio = $mtn->getStdio();
|
||||||
$stdio->exec(array('put_public_key', $key->content));
|
$stdio->exec(array('put_public_key', $key->content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$keyGuard->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -651,8 +693,8 @@ class IDF_Plugin_SyncMonotone
|
|||||||
if ($scm != 'mtn')
|
if ($scm != 'mtn')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$projectpath = self::_get_project_path($project);
|
$projectpath = $this->_get_project_path($project);
|
||||||
$auth_ids = self::_get_authorized_user_ids($project);
|
$auth_ids = $this->_get_authorized_user_ids($project);
|
||||||
if (!in_array($key->user, $auth_ids))
|
if (!in_array($key->user, $auth_ids))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -672,7 +714,7 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$parsed_read_perms = IDF_Scm_Monotone_BasicIO::parse($read_perms);
|
$parsed_read_perms = IDF_Scm_Monotone_BasicIO::parse($read_perms);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not parse read-permissions for project "%s": %s'),
|
__('Could not parse read-permissions for project "%s": %s'),
|
||||||
$shortname, $e->getMessage()
|
$shortname, $e->getMessage()
|
||||||
));
|
));
|
||||||
@@ -693,10 +735,11 @@ class IDF_Plugin_SyncMonotone
|
|||||||
|
|
||||||
$read_perms = IDF_Scm_Monotone_BasicIO::compile($parsed_read_perms);
|
$read_perms = IDF_Scm_Monotone_BasicIO::compile($parsed_read_perms);
|
||||||
|
|
||||||
if (file_put_contents($projectpath.'/read-permissions',
|
if (@file_put_contents($projectpath.'/read-permissions',
|
||||||
$read_perms, LOCK_EX) === false) {
|
$read_perms, LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write read-permissions for project "%s"'), $shortname
|
__('Could not write read-permissions for project "%s"'),
|
||||||
|
$shortname
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -711,9 +754,9 @@ class IDF_Plugin_SyncMonotone
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (file_put_contents($projectpath.'/write-permissions',
|
if (@file_put_contents($projectpath.'/write-permissions',
|
||||||
implode("\n", $lines) . "\n", LOCK_EX) === false) {
|
implode("\n", $lines) . "\n", LOCK_EX) === false) {
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
$this->_diagnoseProblem(sprintf(
|
||||||
__('Could not write write-permissions file for project "%s"'),
|
__('Could not write write-permissions file for project "%s"'),
|
||||||
$shortname
|
$shortname
|
||||||
));
|
));
|
||||||
@@ -762,7 +805,43 @@ class IDF_Plugin_SyncMonotone
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function _get_authorized_user_ids($project)
|
private function _get_project_path($project)
|
||||||
|
{
|
||||||
|
$projecttempl = Pluf::f('mtn_repositories', false);
|
||||||
|
if ($projecttempl === false) {
|
||||||
|
$this->_diagnoseProblem(
|
||||||
|
__('"mtn_repositories" must be defined in your configuration file.')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$projectpath = sprintf($projecttempl, $project->shortname);
|
||||||
|
if (!file_exists($projectpath)) {
|
||||||
|
$this->_diagnoseProblem(sprintf(
|
||||||
|
__('The project path %s does not exists.'), $projectpath
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return $projectpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _mtn_exec($cmd)
|
||||||
|
{
|
||||||
|
$fullcmd = sprintf('%s %s %s',
|
||||||
|
Pluf::f('idf_exec_cmd_prefix', ''),
|
||||||
|
Pluf::f('mtn_path', 'mtn'),
|
||||||
|
$cmd
|
||||||
|
);
|
||||||
|
|
||||||
|
$output = $return = null;
|
||||||
|
exec($fullcmd, $output, $return);
|
||||||
|
if ($return != 0) {
|
||||||
|
$this->_diagnoseProblem(sprintf(
|
||||||
|
__('The command "%s" could not be executed.'), $cmd
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return implode("\n", $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _get_authorized_user_ids($project)
|
||||||
{
|
{
|
||||||
$mem = $project->getMembershipData();
|
$mem = $project->getMembershipData();
|
||||||
$members = array_merge((array)$mem['members'],
|
$members = array_merge((array)$mem['members'],
|
||||||
@@ -775,43 +854,7 @@ class IDF_Plugin_SyncMonotone
|
|||||||
return $userids;
|
return $userids;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function _get_project_path($project)
|
private function _delete_recursive($path)
|
||||||
{
|
|
||||||
$projecttempl = Pluf::f('mtn_repositories', false);
|
|
||||||
if ($projecttempl === false) {
|
|
||||||
throw new IDF_Scm_Exception(
|
|
||||||
__('"mtn_repositories" must be defined in your configuration file.')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$projectpath = sprintf($projecttempl, $project->shortname);
|
|
||||||
if (!file_exists($projectpath)) {
|
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
|
||||||
__('The project path %s does not exists.'), $projectpath
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return $projectpath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function _mtn_exec($cmd)
|
|
||||||
{
|
|
||||||
$fullcmd = sprintf('%s %s %s',
|
|
||||||
Pluf::f('idf_exec_cmd_prefix', ''),
|
|
||||||
Pluf::f('mtn_path', 'mtn'),
|
|
||||||
$cmd
|
|
||||||
);
|
|
||||||
|
|
||||||
$output = $return = null;
|
|
||||||
exec($fullcmd, $output, $return);
|
|
||||||
if ($return != 0) {
|
|
||||||
throw new IDF_Scm_Exception(sprintf(
|
|
||||||
__('The command "%s" could not be executed.'), $cmd
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return implode("\n", $output);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function _delete_recursive($path)
|
|
||||||
{
|
{
|
||||||
if (is_file($path) || is_link($path)) {
|
if (is_file($path) || is_link($path)) {
|
||||||
return @unlink($path);
|
return @unlink($path);
|
||||||
@@ -821,10 +864,48 @@ class IDF_Plugin_SyncMonotone
|
|||||||
$scan = glob(rtrim($path, '/') . '/*');
|
$scan = glob(rtrim($path, '/') . '/*');
|
||||||
$status = 0;
|
$status = 0;
|
||||||
foreach ($scan as $subpath) {
|
foreach ($scan as $subpath) {
|
||||||
$status |= self::_delete_recursive($subpath);
|
$status |= $this->_delete_recursive($subpath);
|
||||||
}
|
}
|
||||||
$status |= rmdir($path);
|
$status |= @rmdir($path);
|
||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function _diagnoseProblem($msg)
|
||||||
|
{
|
||||||
|
$system_err = error_get_last();
|
||||||
|
if (!empty($system_err)) {
|
||||||
|
$msg .= ': '.$system_err['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
error_reporting($this->old_err_rep);
|
||||||
|
throw new IDF_Scm_Exception($msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple helper class that deletes the model instance if
|
||||||
|
* it is not committed
|
||||||
|
*/
|
||||||
|
class IDF_Plugin_SyncMonotone_ModelGuard
|
||||||
|
{
|
||||||
|
private $model;
|
||||||
|
|
||||||
|
public function __construct(Pluf_Model $m)
|
||||||
|
{
|
||||||
|
$this->model = $m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
if ($this->model == null)
|
||||||
|
return;
|
||||||
|
$this->model->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commit()
|
||||||
|
{
|
||||||
|
$this->model = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -140,7 +140,48 @@ class IDF_Project extends Pluf_Model
|
|||||||
* @param IDF_Tag Subfilter with a label (null)
|
* @param IDF_Tag Subfilter with a label (null)
|
||||||
* @return int Count
|
* @return int Count
|
||||||
*/
|
*/
|
||||||
public function getIssueCountByStatus($status='open', $label=null)
|
public function getIssueCountByOwner($status='open')
|
||||||
|
{
|
||||||
|
switch ($status) {
|
||||||
|
case 'open':
|
||||||
|
$tags = implode(',', $this->getTagIdsByStatus('open'));
|
||||||
|
break;
|
||||||
|
case 'closed':
|
||||||
|
default:
|
||||||
|
$tags = implode(',', $this->getTagIdsByStatus('closed'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$sqlIssueTable = Pluf::factory('IDF_Issue')->getSqlTable();
|
||||||
|
$query = "SELECT uid AS id,COUNT(uid) AS nb
|
||||||
|
FROM (
|
||||||
|
SELECT COALESCE(owner, -1) AS uid
|
||||||
|
FROM $sqlIssueTable
|
||||||
|
WHERE status IN ($tags)
|
||||||
|
) AS ff
|
||||||
|
GROUP BY uid";
|
||||||
|
|
||||||
|
$db = Pluf::db();
|
||||||
|
$dbData = $db->select($query);
|
||||||
|
$ownerStatistics = array();
|
||||||
|
foreach ($dbData as $k => $v) {
|
||||||
|
$key = ($v['id'] === '-1') ? null : $v['id'];
|
||||||
|
$ownerStatistics[$key] = (int)$v['nb'];
|
||||||
|
}
|
||||||
|
|
||||||
|
arsort($ownerStatistics);
|
||||||
|
|
||||||
|
return $ownerStatistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of open/closed issues.
|
||||||
|
*
|
||||||
|
* @param string Status ('open'), 'closed'
|
||||||
|
* @param IDF_Tag Subfilter with a label (null)
|
||||||
|
* @param array Restrict further to a list of ids
|
||||||
|
* @return int Count
|
||||||
|
*/
|
||||||
|
public function getIssueCountByStatus($status='open', $label=null, $ids=array())
|
||||||
{
|
{
|
||||||
switch ($status) {
|
switch ($status) {
|
||||||
case 'open':
|
case 'open':
|
||||||
@@ -163,12 +204,48 @@ class IDF_Project extends Pluf_Model
|
|||||||
$sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id));
|
$sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id));
|
||||||
$sql->SAnd($sql2);
|
$sql->SAnd($sql2);
|
||||||
}
|
}
|
||||||
|
if (count($ids) > 0) {
|
||||||
|
$sql2 = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
|
||||||
|
$sql->SAnd($sql2);
|
||||||
|
}
|
||||||
$params = array('filter' => $sql->gen());
|
$params = array('filter' => $sql->gen());
|
||||||
if (!is_null($label)) { $params['view'] = 'join_tags'; }
|
if (!is_null($label)) { $params['view'] = 'join_tags'; }
|
||||||
$gissue = new IDF_Issue();
|
$gissue = new IDF_Issue();
|
||||||
return $gissue->getCount($params);
|
return $gissue->getCount($params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the tags for a specific list of issues.
|
||||||
|
*
|
||||||
|
* @param string Status ('open') or 'closed'
|
||||||
|
* @param array A list of issue ids
|
||||||
|
* @return array An array of tag objects
|
||||||
|
*/
|
||||||
|
public function getTagsByIssues($issue_ids=array())
|
||||||
|
{
|
||||||
|
// make the below query always a valid one
|
||||||
|
if (count($issue_ids) == 0) $issue_ids[] = 0;
|
||||||
|
|
||||||
|
$assocTable = $this->_con->pfx.'idf_issue_idf_tag_assoc';
|
||||||
|
$query = sprintf(
|
||||||
|
'SELECT DISTINCT idf_tag_id FROM %s '.
|
||||||
|
'WHERE idf_issue_id IN (%s) '.
|
||||||
|
'GROUP BY idf_tag_id',
|
||||||
|
$assocTable, implode(',', $issue_ids)
|
||||||
|
);
|
||||||
|
|
||||||
|
$db = Pluf::db();
|
||||||
|
$dbData = $db->select($query);
|
||||||
|
$ids = array(0);
|
||||||
|
foreach ($dbData as $data) {
|
||||||
|
$ids[] = $data['idf_tag_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
|
||||||
|
$model = new IDF_Tag();
|
||||||
|
return $model->getList(array('filter' => $sql->gen()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the open/closed tag ids as they are often used when doing
|
* Get the open/closed tag ids as they are often used when doing
|
||||||
* listings.
|
* listings.
|
||||||
@@ -233,6 +310,29 @@ class IDF_Project extends Pluf_Model
|
|||||||
return $tags;
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of relations which are available in this project as
|
||||||
|
* associative array. Each key-value pair marks a set of orthogonal
|
||||||
|
* relations. To ease processing, each of these pairs is included twice
|
||||||
|
* in the array, once as key1 => key2 and once as key2 => key1.
|
||||||
|
*
|
||||||
|
* @return array List of relation names
|
||||||
|
*/
|
||||||
|
public function getRelationsFromConfig()
|
||||||
|
{
|
||||||
|
$conf = $this->getConf();
|
||||||
|
$rel = $conf->getVal('issue_relations', IDF_Form_IssueTrackingConf::init_relations);
|
||||||
|
$relations = array();
|
||||||
|
foreach (preg_split("/\015\012|\015|\012/", $rel, -1, PREG_SPLIT_NO_EMPTY) as $s) {
|
||||||
|
$verbs = preg_split("/\s*,\s*/", $s, 2);
|
||||||
|
if (count($verbs) == 1)
|
||||||
|
$relations += array($verbs[0] => $verbs[0]);
|
||||||
|
else
|
||||||
|
$relations += array($verbs[0] => $verbs[1], $verbs[1] => $verbs[0]);
|
||||||
|
}
|
||||||
|
return $relations;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return membership data.
|
* Return membership data.
|
||||||
*
|
*
|
||||||
@@ -352,7 +452,11 @@ class IDF_Project extends Pluf_Model
|
|||||||
foreach ($this->_con->select($sql) as $idc) {
|
foreach ($this->_con->select($sql) as $idc) {
|
||||||
$tag = new IDF_Tag($idc['id']);
|
$tag = new IDF_Tag($idc['id']);
|
||||||
$tag->nb_use = $idc['nb_use'];
|
$tag->nb_use = $idc['nb_use'];
|
||||||
$tags[] = $tag;
|
// group by class
|
||||||
|
if (!array_key_exists($tag->class, $tags)) {
|
||||||
|
$tags[$tag->class] = array();
|
||||||
|
}
|
||||||
|
$tags[$tag->class][] = $tag;
|
||||||
}
|
}
|
||||||
return new Pluf_Template_ContextVars($tags);
|
return new Pluf_Template_ContextVars($tags);
|
||||||
}
|
}
|
||||||
|
@@ -88,22 +88,36 @@ class IDF_Scm
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run exec and log some information.
|
* Runs the given command and log some information.
|
||||||
|
*
|
||||||
|
* A previous version used plain exec(), but this should not be used
|
||||||
|
* for various reasons, one being that this command does not preserve
|
||||||
|
* trailing whitespace, which is essential for proper diff parsing.
|
||||||
*
|
*
|
||||||
* @param $caller Calling method
|
* @param $caller Calling method
|
||||||
* @param $cmd Command to run
|
* @param $cmd Command to run
|
||||||
* @param &$out Array of output
|
* @param &$out Array of output
|
||||||
* @param &$return Return value
|
* @param &$return Return value
|
||||||
* @return string Last line of the command
|
|
||||||
*/
|
*/
|
||||||
public static function exec($caller, $cmd, &$out=null, &$return=null)
|
public static function exec($caller, $cmd, &$out=null, &$return=null)
|
||||||
{
|
{
|
||||||
|
$return = -1;
|
||||||
Pluf_Log::stime('timer');
|
Pluf_Log::stime('timer');
|
||||||
$ret = exec($cmd, $out, $return);
|
$fp = popen($cmd, 'r');
|
||||||
|
$buf = '';
|
||||||
|
if ($fp !== false) {
|
||||||
|
while (!feof($fp)) {
|
||||||
|
$buf .= fread($fp, 1024);
|
||||||
|
}
|
||||||
|
$return = pclose($fp);
|
||||||
|
}
|
||||||
|
$out = preg_split('/\r\n|\r|\n/', $buf);
|
||||||
|
$elem = count($out);
|
||||||
|
if ($elem > 0 && $out[$elem-1] === '')
|
||||||
|
unset($out[$elem-1]);
|
||||||
Pluf_Log::perf(array($caller, $cmd, Pluf_Log::etime('timer', 'total_exec')));
|
Pluf_Log::perf(array($caller, $cmd, Pluf_Log::etime('timer', 'total_exec')));
|
||||||
Pluf_Log::debug(array($caller, $cmd, $out));
|
Pluf_Log::debug(array($caller, $cmd, $out));
|
||||||
Pluf_Log::inc('exec_calls');
|
Pluf_Log::inc('exec_calls');
|
||||||
return $ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -325,7 +339,8 @@ class IDF_Scm
|
|||||||
* stdClass object {
|
* stdClass object {
|
||||||
* 'additions' => array('path/to/file', 'path/to/directory', ...),
|
* 'additions' => array('path/to/file', 'path/to/directory', ...),
|
||||||
* 'deletions' => array('path/to/file', 'path/to/directory', ...),
|
* 'deletions' => array('path/to/file', 'path/to/directory', ...),
|
||||||
* 'renames' => array('old/path/to/file' => 'new/path/to/file', ...)
|
* 'renames' => array('old/path/to/file' => 'new/path/to/file', ...),
|
||||||
|
* 'copies' => array('path/to/source' => 'path/to/target', ...),
|
||||||
* 'patches' => array('path/to/file', ...),
|
* 'patches' => array('path/to/file', ...),
|
||||||
* 'properties' => array('path/to/file' => array(
|
* 'properties' => array('path/to/file' => array(
|
||||||
* 'propname' => 'propvalue', 'deletedprop' => null, ...)
|
* 'propname' => 'propvalue', 'deletedprop' => null, ...)
|
||||||
|
@@ -67,6 +67,7 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
'additions' => array(),
|
'additions' => array(),
|
||||||
'deletions' => array(),
|
'deletions' => array(),
|
||||||
'renames' => array(),
|
'renames' => array(),
|
||||||
|
'copies' => array(),
|
||||||
'patches' => array(),
|
'patches' => array(),
|
||||||
'properties' => array(),
|
'properties' => array(),
|
||||||
);
|
);
|
||||||
@@ -218,15 +219,15 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
$cmd, $return,
|
$cmd, $return,
|
||||||
implode("\n", $out)));
|
implode("\n", $out)));
|
||||||
}
|
}
|
||||||
rsort($out);
|
|
||||||
$res = array();
|
$res = array();
|
||||||
foreach ($out as $b) {
|
foreach ($out as $b) {
|
||||||
$elts = explode(' ', $b, 2);
|
$elts = explode(' ', $b, 2);
|
||||||
$tag = substr(trim($elts[1]), 10); // Remove refs/tags/ prefix
|
$tag = substr(trim($elts[1]), 10); // Remove refs/tags/ prefix
|
||||||
$res[$tag] = '';
|
$res[$tag] = '';
|
||||||
}
|
}
|
||||||
|
krsort($res);
|
||||||
$this->cache['tags'] = $res;
|
$this->cache['tags'] = $res;
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,6 +346,14 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
if (!preg_match('/<(.*)>/', $author, $match)) {
|
if (!preg_match('/<(.*)>/', $author, $match)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// FIXME: newer git versions know a i18n.commitencoding setting which
|
||||||
|
// leads to another header, "encoding", with which we _could_ try to
|
||||||
|
// decode the string into utf8. Unfortunately this does not always
|
||||||
|
// work, especially not in older repos, so we would then still have
|
||||||
|
// to supply some fallback.
|
||||||
|
if (!mb_check_encoding($match[1], 'UTF-8')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
$sql = new Pluf_SQL('login=%s', array($match[1]));
|
$sql = new Pluf_SQL('login=%s', array($match[1]));
|
||||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||||
if ($users->count() > 0) {
|
if ($users->count() > 0) {
|
||||||
@@ -498,33 +507,27 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
"'".$this->mediumtree_fmt."'",
|
"'".$this->mediumtree_fmt."'",
|
||||||
escapeshellarg($commit));
|
escapeshellarg($commit));
|
||||||
}
|
}
|
||||||
$out = array();
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||||
self::exec('IDF_Scm_Git::getCommit', $cmd, $out, $ret);
|
$out = self::shell_exec('IDF_Scm_Git::getCommit', $cmd);
|
||||||
if ($ret != 0 or count($out) == 0) {
|
if (strlen($out) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($getdiff) {
|
|
||||||
$log = array();
|
$diffStart = false;
|
||||||
$change = array();
|
if (preg_match('/^diff (?:--git a|--cc)/m', $out, $m, PREG_OFFSET_CAPTURE)) {
|
||||||
$inchange = false;
|
$diffStart = $m[0][1];
|
||||||
foreach ($out as $line) {
|
|
||||||
if (!$inchange and 0 === strpos($line, 'diff --git a')) {
|
|
||||||
$inchange = true;
|
|
||||||
}
|
|
||||||
if ($inchange) {
|
|
||||||
$change[] = $line;
|
|
||||||
} else {
|
|
||||||
$log[] = $line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$out = self::parseLog($log);
|
|
||||||
$out[0]->diff = implode("\n", $change);
|
|
||||||
} else {
|
|
||||||
$out = self::parseLog($out);
|
|
||||||
$out[0]->diff = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$diff = '';
|
||||||
|
if ($diffStart !== false) {
|
||||||
|
$log = substr($out, 0, $diffStart);
|
||||||
|
$diff = substr($out, $diffStart);
|
||||||
|
} else {
|
||||||
|
$log = $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = self::parseLog(preg_split('/\r\n|\n/', $log));
|
||||||
|
$out[0]->diff = $diff;
|
||||||
$out[0]->branch = implode(', ', $this->inBranches($out[0]->commit, null));
|
$out[0]->branch = implode(', ', $this->inBranches($out[0]->commit, null));
|
||||||
return $out[0];
|
return $out[0];
|
||||||
}
|
}
|
||||||
@@ -637,7 +640,11 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
$c['full_message'] = IDF_Commit::toUTF8($c['full_message']);
|
$c['full_message'] = IDF_Commit::toUTF8($c['full_message']);
|
||||||
$c['title'] = IDF_Commit::toUTF8($c['title']);
|
$c['title'] = IDF_Commit::toUTF8($c['title']);
|
||||||
if (isset($c['parents'])) {
|
if (isset($c['parents'])) {
|
||||||
$c['parents'] = explode(' ', trim($c['parents']));
|
$c['parents'] = preg_split('/ /', trim($c['parents']), -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
} else {
|
||||||
|
// this is actually an error state because we should _always_
|
||||||
|
// be able to parse the parents line with every git version
|
||||||
|
$c['parents'] = null;
|
||||||
}
|
}
|
||||||
$res[] = (object) $c;
|
$res[] = (object) $c;
|
||||||
return $res;
|
return $res;
|
||||||
|
@@ -59,7 +59,7 @@ class IDF_Scm_Mercurial_LogStyle
|
|||||||
. "\n"
|
. "\n"
|
||||||
. 'file_del = "{file_del}\0"'
|
. 'file_del = "{file_del}\0"'
|
||||||
. "\n"
|
. "\n"
|
||||||
. 'file_copy = "{name}\0{source}\0"'
|
. 'file_copy = "{source}\0{name}\0"'
|
||||||
. "\n";
|
. "\n";
|
||||||
} else {
|
} else {
|
||||||
throw new IDF_Scm_Exception('invalid type ' . $type);
|
throw new IDF_Scm_Exception('invalid type ' . $type);
|
||||||
@@ -408,24 +408,23 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
escapeshellarg($commit),
|
escapeshellarg($commit),
|
||||||
escapeshellarg($this->repo),
|
escapeshellarg($this->repo),
|
||||||
escapeshellarg($logStyle->get()));
|
escapeshellarg($logStyle->get()));
|
||||||
$out = array();
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||||
self::exec('IDF_Scm_Mercurial::getCommit', $cmd, $out);
|
$out = self::shell_exec('IDF_Scm_Mercurial::getCommit', $cmd);
|
||||||
$log = array();
|
if (strlen($out) == 0) {
|
||||||
$change = array();
|
return false;
|
||||||
$inchange = false;
|
|
||||||
foreach ($out as $line) {
|
|
||||||
if (!$inchange and 0 === strpos($line, 'diff -r')) {
|
|
||||||
$inchange = true;
|
|
||||||
}
|
|
||||||
if ($inchange) {
|
|
||||||
$change[] = $line;
|
|
||||||
} else {
|
|
||||||
$log[] = $line;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$out = self::parseLog($log);
|
|
||||||
$out[0]->diff = implode("\n", $change);
|
$diffStart = strpos($out, 'diff -r');
|
||||||
|
$diff = '';
|
||||||
|
if ($diffStart !== false) {
|
||||||
|
$log = substr($out, 0, $diffStart);
|
||||||
|
$diff = substr($out, $diffStart);
|
||||||
|
} else {
|
||||||
|
$log = $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = self::parseLog(preg_split('/\r\n|\n/', $log));
|
||||||
|
$out[0]->diff = $diff;
|
||||||
return $out[0];
|
return $out[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,24 +456,32 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
'patches' => preg_split('/\0/', $log->file_mods, -1, PREG_SPLIT_NO_EMPTY),
|
'patches' => preg_split('/\0/', $log->file_mods, -1, PREG_SPLIT_NO_EMPTY),
|
||||||
// hg has no support for built-in attributes, so this keeps empty
|
// hg has no support for built-in attributes, so this keeps empty
|
||||||
'properties' => array(),
|
'properties' => array(),
|
||||||
// this is filled below
|
// these two are filled below
|
||||||
|
'copies' => array(),
|
||||||
'renames' => array(),
|
'renames' => array(),
|
||||||
);
|
);
|
||||||
|
|
||||||
$file_copies = preg_split('/\0/', $log->file_copies, -1, PREG_SPLIT_NO_EMPTY);
|
$file_copies = preg_split('/\0/', $log->file_copies, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
|
||||||
// FIXME: copies are only treated as renames if they have an add _and_
|
// copies are treated as renames if they have an add _and_ a drop;
|
||||||
// an drop, otherwise they're just treated as adds
|
// only if they only have an add, but no drop, they're treated as copies
|
||||||
for ($i=0; $i<count($file_copies); $i+=2) {
|
for ($i=0; $i<count($file_copies); $i+=2) {
|
||||||
$new = $file_copies[$i];
|
$src = $file_copies[$i];
|
||||||
$old = $file_copies[$i+1];
|
$trg = $file_copies[$i+1];
|
||||||
$newidx = array_search($new, $return->additions);
|
$srcidx = array_search($src, $return->deletions);
|
||||||
$oldidx = array_search($old, $return->deletions);
|
$trgidx = array_search($trg, $return->additions);
|
||||||
if ($newidx !== false && $oldidx !== false) {
|
if ($srcidx !== false && $trgidx !== false) {
|
||||||
$return->renames[$old] = $new;
|
$return->renames[$src] = $trg;
|
||||||
unset($return->additions[$newidx]);
|
unset($return->deletions[$srcidx]);
|
||||||
unset($return->deletions[$oldidx]);
|
unset($return->additions[$trgidx]);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
if ($srcidx === false && $trgidx !== false) {
|
||||||
|
$return->copies[$src] = $trg;
|
||||||
|
unset($return->additions[$trgidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// file sutures (counter-operation to copy) not supported
|
||||||
}
|
}
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
@@ -531,7 +538,8 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
if ($line == "\0") {
|
if ($line == "\0") {
|
||||||
$headers_processed = false;
|
$headers_processed = false;
|
||||||
if (count($c) > 0) {
|
if (count($c) > 0) {
|
||||||
$c['full_message'] = trim($c['full_message']);
|
if (array_key_exists('full_message', $c))
|
||||||
|
$c['full_message'] = trim($c['full_message']);
|
||||||
$res[] = (object) $c;
|
$res[] = (object) $c;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -547,10 +555,8 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
$c['commit'] = $match[2];
|
$c['commit'] = $match[2];
|
||||||
$c['tree'] = $c['commit'];
|
$c['tree'] = $c['commit'];
|
||||||
$c['full_message'] = '';
|
$c['full_message'] = '';
|
||||||
} elseif ($match[1] == 'user') {
|
} elseif ($match[1] == 'author') {
|
||||||
$c['author'] = $match[2];
|
$c['author'] = $match[2];
|
||||||
} elseif ($match[1] == 'summary') {
|
|
||||||
$c['title'] = $match[2];
|
|
||||||
} elseif ($match[1] == 'branch') {
|
} elseif ($match[1] == 'branch') {
|
||||||
$c['branch'] = empty($match[2]) ? 'default' : $match[2];
|
$c['branch'] = empty($match[2]) ? 'default' : $match[2];
|
||||||
} elseif ($match[1] == 'parents') {
|
} elseif ($match[1] == 'parents') {
|
||||||
|
@@ -31,10 +31,10 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
/** the minimum supported interface version */
|
/** the minimum supported interface version */
|
||||||
public static $MIN_INTERFACE_VERSION = 13.0;
|
public static $MIN_INTERFACE_VERSION = 13.0;
|
||||||
|
|
||||||
private $stdio;
|
|
||||||
|
|
||||||
private static $instances = array();
|
private static $instances = array();
|
||||||
|
|
||||||
|
private $stdio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
@@ -609,6 +609,7 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
'additions' => array(),
|
'additions' => array(),
|
||||||
'deletions' => array(),
|
'deletions' => array(),
|
||||||
'renames' => array(),
|
'renames' => array(),
|
||||||
|
'copies' => array(),
|
||||||
'patches' => array(),
|
'patches' => array(),
|
||||||
'properties' => array(),
|
'properties' => array(),
|
||||||
);
|
);
|
||||||
@@ -698,6 +699,29 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
return (object) $res;
|
return (object) $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see IDF_Scm::getProperties()
|
||||||
|
*/
|
||||||
|
public function getProperties($rev, $path='')
|
||||||
|
{
|
||||||
|
$out = $this->stdio->exec(array('interface_version'));
|
||||||
|
// support for querying file attributes of committed revisions
|
||||||
|
// was added for mtn 1.1 (interface version 13.1)
|
||||||
|
if (floatval($out) < 13.1)
|
||||||
|
return array();
|
||||||
|
|
||||||
|
$out = $this->stdio->exec(array('get_attributes', $path), array('r' => $rev));
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
|
||||||
|
$res = array();
|
||||||
|
|
||||||
|
foreach ($stanzas as $stanza) {
|
||||||
|
$line = $stanza[0];
|
||||||
|
$res[$line['values'][0]] = $line['values'][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IDF_Scm::getExtraProperties
|
* @see IDF_Scm::getExtraProperties
|
||||||
*/
|
*/
|
||||||
|
@@ -48,7 +48,7 @@ class IDF_Scm_Monotone_Usher
|
|||||||
if ($conn == 'none')
|
if ($conn == 'none')
|
||||||
return array();
|
return array();
|
||||||
|
|
||||||
return preg_split('/[ ]/', $conn);
|
return preg_split('/[ ]/', $conn, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,10 +73,10 @@ class IDF_Scm_Monotone_Usher
|
|||||||
if ($conn == 'none')
|
if ($conn == 'none')
|
||||||
return array();
|
return array();
|
||||||
|
|
||||||
$single_conns = preg_split('/[ ]/', $conn);
|
$single_conns = preg_split('/[ ]/', $conn, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
$ret = array();
|
$ret = array();
|
||||||
foreach ($single_conns as $conn) {
|
foreach ($single_conns as $conn) {
|
||||||
preg_match('/\((\w+)\)([^:]+):(\d+)/', $conn, $matches);
|
preg_match('/\(([^)]+)\)([^:]+):(\d+)/', $conn, $matches);
|
||||||
$ret[$matches[1]][] = (object)array(
|
$ret[$matches[1]][] = (object)array(
|
||||||
'server' => $matches[1],
|
'server' => $matches[1],
|
||||||
'address' => $matches[2],
|
'address' => $matches[2],
|
||||||
|
@@ -33,7 +33,6 @@
|
|||||||
*/
|
*/
|
||||||
class IDF_Scm_Svn extends IDF_Scm
|
class IDF_Scm_Svn extends IDF_Scm
|
||||||
{
|
{
|
||||||
|
|
||||||
public $username = '';
|
public $username = '';
|
||||||
public $password = '';
|
public $password = '';
|
||||||
private $assoc = array('dir' => 'tree',
|
private $assoc = array('dir' => 'tree',
|
||||||
@@ -48,11 +47,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
|
|
||||||
public function isAvailable()
|
public function isAvailable()
|
||||||
{
|
{
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s %s',
|
$cmd = $this->svnCmd(array('info', '--xml'), $this->repo);
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::isAvailable', $cmd);
|
$xmlInfo = self::shell_exec('IDF_Scm_Svn::isAvailable', $cmd);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -163,12 +158,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return IDF_Scm::REVISION_VALID;
|
return IDF_Scm::REVISION_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('info'), $this->repo, $rev);
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo),
|
|
||||||
escapeshellarg($rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
self::exec('IDF_Scm_Svn::validateRevision', $cmd, $out, $ret);
|
self::exec('IDF_Scm_Svn::validateRevision', $cmd, $out, $ret);
|
||||||
|
|
||||||
if ($ret == 0)
|
if ($ret == 0)
|
||||||
@@ -176,7 +166,6 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return IDF_Scm::REVISION_INVALID;
|
return IDF_Scm::REVISION_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test a given object hash.
|
* Test a given object hash.
|
||||||
*
|
*
|
||||||
@@ -191,12 +180,9 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Else, test the path on revision
|
// Else, test the path on revision
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('info', '--xml'),
|
||||||
escapeshellarg($this->username),
|
$this->repo.'/'.self::smartEncode($path),
|
||||||
escapeshellarg($this->password),
|
$rev);
|
||||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)),
|
|
||||||
escapeshellarg($rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::testHash', $cmd);
|
$xmlInfo = self::shell_exec('IDF_Scm_Svn::testHash', $cmd);
|
||||||
|
|
||||||
// If exception is thrown, return false
|
// If exception is thrown, return false
|
||||||
@@ -218,12 +204,9 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
|
|
||||||
public function getTree($commit, $folder='/', $branch=null)
|
public function getTree($commit, $folder='/', $branch=null)
|
||||||
{
|
{
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --no-auth-cache --xml --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('ls', '--xml'),
|
||||||
escapeshellarg($this->username),
|
$this->repo.'/'.self::smartEncode($folder),
|
||||||
escapeshellarg($this->password),
|
$commit);
|
||||||
escapeshellarg($this->repo.'/'.self::smartEncode($folder)),
|
|
||||||
escapeshellarg($commit));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getTree', $cmd));
|
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getTree', $cmd));
|
||||||
$res = array();
|
$res = array();
|
||||||
$folder = (strlen($folder) and ($folder != '/')) ? $folder.'/' : '';
|
$folder = (strlen($folder) and ($folder != '/')) ? $folder.'/' : '';
|
||||||
@@ -248,7 +231,6 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the commit message of a revision revision.
|
* Get the commit message of a revision revision.
|
||||||
*
|
*
|
||||||
@@ -260,12 +242,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
if (isset($this->cache['commitmess'][$rev])) {
|
if (isset($this->cache['commitmess'][$rev])) {
|
||||||
return $this->cache['commitmess'][$rev];
|
return $this->cache['commitmess'][$rev];
|
||||||
}
|
}
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --no-auth-cache --xml --limit 1 --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('log', '--xml', '--limit', '1'), $this->repo, $rev);
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo),
|
|
||||||
escapeshellarg($rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
try {
|
try {
|
||||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getCommitMessage', $cmd));
|
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getCommitMessage', $cmd));
|
||||||
$this->cache['commitmess'][$rev] = (string) $xml->logentry->msg;
|
$this->cache['commitmess'][$rev] = (string) $xml->logentry->msg;
|
||||||
@@ -281,12 +258,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
if ($rev == null) {
|
if ($rev == null) {
|
||||||
$rev = 'HEAD';
|
$rev = 'HEAD';
|
||||||
}
|
}
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('info', '--xml'),
|
||||||
escapeshellarg($this->username),
|
$this->repo.'/'.self::smartEncode($filename), $rev);
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo.'/'.self::smartEncode($filename)),
|
|
||||||
escapeshellarg($rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getPathInfo', $cmd));
|
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getPathInfo', $cmd));
|
||||||
if (!isset($xml->entry)) {
|
if (!isset($xml->entry)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -308,12 +281,9 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
|
|
||||||
public function getFile($def, $cmd_only=false)
|
public function getFile($def, $cmd_only=false)
|
||||||
{
|
{
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' cat --no-auth-cache --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('cat'),
|
||||||
escapeshellarg($this->username),
|
$this->repo.'/'.self::smartEncode($def->fullpath),
|
||||||
escapeshellarg($this->password),
|
$def->rev);
|
||||||
escapeshellarg($this->repo.'/'.self::smartEncode($def->fullpath)),
|
|
||||||
escapeshellarg($def->rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
return ($cmd_only) ?
|
return ($cmd_only) ?
|
||||||
$cmd : self::shell_exec('IDF_Scm_Svn::getFile', $cmd);
|
$cmd : self::shell_exec('IDF_Scm_Svn::getFile', $cmd);
|
||||||
}
|
}
|
||||||
@@ -329,11 +299,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return $this->cache['branches'];
|
return $this->cache['branches'];
|
||||||
}
|
}
|
||||||
$res = array();
|
$res = array();
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --no-auth-cache --username=%s --password=%s %s@HEAD',
|
$cmd = $this->svnCmd(array('ls'), $this->repo.'/branches', 'HEAD');
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo.'/branches'));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
||||||
if ($ret == 0) {
|
if ($ret == 0) {
|
||||||
foreach ($out as $entry) {
|
foreach ($out as $entry) {
|
||||||
@@ -344,11 +310,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ksort($res);
|
ksort($res);
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --username=%s --password=%s %s@HEAD',
|
|
||||||
escapeshellarg($this->username),
|
$cmd = $this->svnCmd(array('info'), $this->repo.'/trunk', 'HEAD');
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo.'/trunk'));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
||||||
if ($ret == 0) {
|
if ($ret == 0) {
|
||||||
$res = array('trunk' => 'trunk') + $res;
|
$res = array('trunk' => 'trunk') + $res;
|
||||||
@@ -368,11 +331,7 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return $this->cache['tags'];
|
return $this->cache['tags'];
|
||||||
}
|
}
|
||||||
$res = array();
|
$res = array();
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --no-auth-cache --username=%s --password=%s %s@HEAD',
|
$cmd = $this->svnCmd(array('ls'), $this->repo.'/tags', 'HEAD');
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo.'/tags'));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
self::exec('IDF_Scm_Svn::getTags', $cmd, $out, $ret);
|
self::exec('IDF_Scm_Svn::getTags', $cmd, $out, $ret);
|
||||||
if ($ret == 0) {
|
if ($ret == 0) {
|
||||||
foreach ($out as $entry) {
|
foreach ($out as $entry) {
|
||||||
@@ -412,7 +371,6 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get commit details.
|
* Get commit details.
|
||||||
*
|
*
|
||||||
@@ -426,12 +384,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$res = array();
|
$res = array();
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --no-auth-cache --xml --limit 1 -v --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('log', '--xml', '--limit', '1', '-v'),
|
||||||
escapeshellarg($this->username),
|
$this->repo, $commit);
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo),
|
|
||||||
escapeshellarg($commit));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xmlRes = self::shell_exec('IDF_Scm_Svn::getCommit', $cmd);
|
$xmlRes = self::shell_exec('IDF_Scm_Svn::getCommit', $cmd);
|
||||||
$xml = simplexml_load_string($xmlRes);
|
$xml = simplexml_load_string($xmlRes);
|
||||||
$res['author'] = (string) $xml->logentry->author;
|
$res['author'] = (string) $xml->logentry->author;
|
||||||
@@ -473,15 +427,87 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
private function getDiff($rev='HEAD')
|
private function getDiff($rev='HEAD')
|
||||||
{
|
{
|
||||||
$res = array();
|
$res = array();
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' diff --no-auth-cache -c %s --username=%s --password=%s %s',
|
$cmd = $this->svnCmd(array('diff', '-c', $rev), $this->repo);
|
||||||
escapeshellarg($rev),
|
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
return self::shell_exec('IDF_Scm_Svn::getDiff', $cmd);
|
return self::shell_exec('IDF_Scm_Svn::getDiff', $cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see IDF_Scm::getChanges()
|
||||||
|
*/
|
||||||
|
public function getChanges($commit)
|
||||||
|
{
|
||||||
|
if ($this->validateRevision($commit) != IDF_Scm::REVISION_VALID) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$cmd = $this->svnCmd(array('log', '--xml', '-v'), $this->repo, $commit);
|
||||||
|
$out = array();
|
||||||
|
$out = self::shell_exec('IDF_Scm_Svn::getChanges', $cmd);
|
||||||
|
$xml = simplexml_load_string($out);
|
||||||
|
if (count($xml) == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$entry = current($xml);
|
||||||
|
|
||||||
|
$return = (object) array(
|
||||||
|
'additions' => array(),
|
||||||
|
'deletions' => array(),
|
||||||
|
'patches' => array(),
|
||||||
|
// while SVN has support for attributes, we cannot see their changes
|
||||||
|
// in the log's XML unfortunately
|
||||||
|
'properties' => array(),
|
||||||
|
'copies' => array(),
|
||||||
|
'renames' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($entry->paths->path as $p) {
|
||||||
|
$path = (string) $p;
|
||||||
|
foreach ($p->attributes() as $k => $v) {
|
||||||
|
$key = (string) $k;
|
||||||
|
$val = (string) $v;
|
||||||
|
if ($key != 'action')
|
||||||
|
continue;
|
||||||
|
if ($val == 'M')
|
||||||
|
$return->patches[] = $path;
|
||||||
|
else if ($val == 'A')
|
||||||
|
$return->additions[] = $path;
|
||||||
|
else if ($val == 'D')
|
||||||
|
$return->deletions[] = $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copies are treated as renames if they have an add _and_ a drop;
|
||||||
|
// only if they only have an add, but no drop, they're treated as copies
|
||||||
|
foreach ($entry->paths->path as $p) {
|
||||||
|
$trg = (string) $p;
|
||||||
|
$src = null;
|
||||||
|
foreach ($p->attributes() as $k => $v) {
|
||||||
|
if ((string) $k == 'copyfrom-path') {
|
||||||
|
$src = (string) $v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($src == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$srcidx = array_search($src, $return->deletions);
|
||||||
|
$trgidx = array_search($trg, $return->additions);
|
||||||
|
if ($srcidx !== false && $trgidx !== false) {
|
||||||
|
$return->renames[$src] = $trg;
|
||||||
|
unset($return->deletions[$srcidx]);
|
||||||
|
unset($return->additions[$trgidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($srcidx === false && $trgidx !== false) {
|
||||||
|
$return->copies[$src] = $trg;
|
||||||
|
unset($return->additions[$trgidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// file sutures (counter-operation to copy) not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get latest changes.
|
* Get latest changes.
|
||||||
@@ -491,20 +517,15 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
*
|
*
|
||||||
* @return array Changes.
|
* @return array Changes.
|
||||||
*/
|
*/
|
||||||
public function getChangeLog($branch=null, $n=10)
|
public function getChangeLog($rev=null, $n=10)
|
||||||
{
|
{
|
||||||
if ($branch != 'HEAD' and !preg_match('/^\d+$/', $branch)) {
|
if ($rev != 'HEAD' and !preg_match('/^\d+$/', $rev)) {
|
||||||
// we accept only revisions or HEAD
|
// we accept only revisions or HEAD
|
||||||
$branch = 'HEAD';
|
$rev = 'HEAD';
|
||||||
}
|
}
|
||||||
$res = array();
|
$res = array();
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --no-auth-cache --xml -v --limit %s --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('log', '--xml', '-v', '--limit', $n),
|
||||||
escapeshellarg($n),
|
$this->repo.'@'.$rev);
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo),
|
|
||||||
escapeshellarg($branch));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xmlRes = self::shell_exec('IDF_Scm_Svn::getChangeLog', $cmd);
|
$xmlRes = self::shell_exec('IDF_Scm_Svn::getChangeLog', $cmd);
|
||||||
$xml = simplexml_load_string($xmlRes);
|
$xml = simplexml_load_string($xmlRes);
|
||||||
foreach ($xml->logentry as $entry) {
|
foreach ($xml->logentry as $entry) {
|
||||||
@@ -520,7 +541,6 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get additionnals properties on path and revision
|
* Get additionnals properties on path and revision
|
||||||
*
|
*
|
||||||
@@ -531,12 +551,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
public function getProperties($rev, $path='')
|
public function getProperties($rev, $path='')
|
||||||
{
|
{
|
||||||
$res = array();
|
$res = array();
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' proplist --no-auth-cache --xml --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('proplist', '--xml'),
|
||||||
escapeshellarg($this->username),
|
$this->repo.'/'.self::smartEncode($path), $rev);
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)),
|
|
||||||
escapeshellarg($rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xmlProps = self::shell_exec('IDF_Scm_Svn::getProperties', $cmd);
|
$xmlProps = self::shell_exec('IDF_Scm_Svn::getProperties', $cmd);
|
||||||
$props = simplexml_load_string($xmlProps);
|
$props = simplexml_load_string($xmlProps);
|
||||||
|
|
||||||
@@ -554,7 +570,6 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a specific additionnal property on path and revision
|
* Get a specific additionnal property on path and revision
|
||||||
*
|
*
|
||||||
@@ -566,20 +581,14 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
private function getProperty($property, $rev, $path='')
|
private function getProperty($property, $rev, $path='')
|
||||||
{
|
{
|
||||||
$res = array();
|
$res = array();
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' propget --no-auth-cache --xml %s --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('propget', $property, '--xml'),
|
||||||
escapeshellarg($property),
|
$this->repo.'/'.self::smartEncode($path), $rev);
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)),
|
|
||||||
escapeshellarg($rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xmlProp = self::shell_exec('IDF_Scm_Svn::getProperty', $cmd);
|
$xmlProp = self::shell_exec('IDF_Scm_Svn::getProperty', $cmd);
|
||||||
$prop = simplexml_load_string($xmlProp);
|
$prop = simplexml_load_string($xmlProp);
|
||||||
|
|
||||||
return (string) $prop->target->property;
|
return (string) $prop->target->property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of the last commit in the repository.
|
* Get the number of the last commit in the repository.
|
||||||
*
|
*
|
||||||
@@ -590,16 +599,38 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
public function getLastCommit($rev='HEAD')
|
public function getLastCommit($rev='HEAD')
|
||||||
{
|
{
|
||||||
$xmlInfo = '';
|
$xmlInfo = '';
|
||||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --no-auth-cache --xml --username=%s --password=%s %s@%s',
|
$cmd = $this->svnCmd(array('info', '--xml'), $this->repo, $rev);
|
||||||
escapeshellarg($this->username),
|
|
||||||
escapeshellarg($this->password),
|
|
||||||
escapeshellarg($this->repo),
|
|
||||||
escapeshellarg($rev));
|
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
|
||||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::getLastCommit', $cmd);
|
$xmlInfo = self::shell_exec('IDF_Scm_Svn::getLastCommit', $cmd);
|
||||||
|
|
||||||
$xml = simplexml_load_string($xmlInfo);
|
$xml = simplexml_load_string($xmlInfo);
|
||||||
return (string) $xml->entry->commit['revision'];
|
return (string) $xml->entry->commit['revision'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function svnCmd($args = array(), $repoarg = null, $revarg = null)
|
||||||
|
{
|
||||||
|
$cmdline = array();
|
||||||
|
$cmdline[] = Pluf::f('idf_exec_cmd_prefix', '');
|
||||||
|
$cmdline[] = Pluf::f('svn_path', 'svn');
|
||||||
|
$cmdline[] = '--no-auth-cache';
|
||||||
|
$cmdline[] = '--username='.escapeshellarg($this->username);
|
||||||
|
$cmdline[] = '--password='.escapeshellarg($this->password);
|
||||||
|
|
||||||
|
foreach ($args as $arg) {
|
||||||
|
$cmdline[] = escapeshellarg($arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($repoarg != null) {
|
||||||
|
if ($revarg != null) {
|
||||||
|
$repoarg .= '@'.$revarg;
|
||||||
|
}
|
||||||
|
$cmdline[] = escapeshellarg($repoarg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($revarg != null) {
|
||||||
|
$cmdline[] = '--revision='.escapeshellarg($revarg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' ', $cmdline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -58,7 +58,7 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
|||||||
implode('|', $nouns);
|
implode('|', $nouns);
|
||||||
$text = IDF_Template_safePregReplace('#((?:'.$prefix.')(?:\s+r?))([0-9a-f]{1,40}((?:\s+and|\s+or|,)\s+r?[0-9a-f]{1,40})*)\b#i',
|
$text = IDF_Template_safePregReplace('#((?:'.$prefix.')(?:\s+r?))([0-9a-f]{1,40}((?:\s+and|\s+or|,)\s+r?[0-9a-f]{1,40})*)\b#i',
|
||||||
array($this, 'callbackCommits'), $text);
|
array($this, 'callbackCommits'), $text);
|
||||||
$text = IDF_Template_safePregReplace('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))(?:#(\d+))?=im',
|
$text = IDF_Template_safePregReplace('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))?(?:#(\d+))?=im',
|
||||||
array($this, 'callbackSource'), $text);
|
array($this, 'callbackSource'), $text);
|
||||||
}
|
}
|
||||||
if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
|
if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
|
||||||
|
@@ -90,40 +90,69 @@ class IDF_Template_MarkdownPrefilter extends Pluf_Text_HTML_Filter
|
|||||||
);
|
);
|
||||||
|
|
||||||
public $allowed = array(
|
public $allowed = array(
|
||||||
'a' => array('href', 'title', 'rel'),
|
'a' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'abbr' => array('title'),
|
'href', 'hreflang', 'rel'),
|
||||||
'address' => array(),
|
'abbr' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'b' => array(),
|
'address' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'blockquote' => array(),
|
'b' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'br' => array(),
|
'blockquote' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'caption' => array(),
|
'cite'),
|
||||||
'code' => array(),
|
'br' => array('class', 'id', 'style', 'title'),
|
||||||
'dd' => array(),
|
'caption' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'del' => array('cite', 'class', 'datetime', 'dir', 'id', 'title'),
|
'align'), // deprecated attribute),
|
||||||
'div' => array('align', 'class'),
|
'code' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'dl' => array(),
|
'dd' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'dt' => array(),
|
'del' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'em' => array(),
|
'cite', 'datetime'),
|
||||||
'h1' => array('id'),
|
'div' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'h2' => array('id'),
|
'align'), // deprecated attribute
|
||||||
'h3' => array('id'),
|
'dl' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'h4' => array('id'),
|
'dt' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'h5' => array('id'),
|
'em' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
'h6' => array('id'),
|
'font' => array('class', 'dir', 'id', 'style', 'title', // deprecated element
|
||||||
'hr' => array(),
|
'color', 'face', 'size'), // deprecated attribute
|
||||||
'i' => array(),
|
'h1' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'img' => array('src', 'class', 'alt', 'height', 'width', 'style'),
|
'align'), // deprecated attribute
|
||||||
'ins' => array('cite', 'class', 'datetime', 'dir', 'id', 'title'),
|
'h2' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'li' => array(),
|
'align'), // deprecated attribute
|
||||||
'ol' => array(),
|
'h3' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'p' => array('align', 'class'),
|
'align'), // deprecated attribute
|
||||||
'pre' => array(),
|
'h4' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'strong' => array(),
|
'align'), // deprecated attribute
|
||||||
'table' => array('summary'),
|
'h5' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'td' => array('style'),
|
'align'), // deprecated attribute
|
||||||
'th' => array(),
|
'h6' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
'tr' => array(),
|
'align'), // deprecated attribute
|
||||||
'ul' => array(),
|
'hr' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'align', 'noshade', 'size', 'width'), // deprecated attribute
|
||||||
|
'i' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
|
'img' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'src', 'alt', 'height', 'width'),
|
||||||
|
'ins' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'cite', 'datetime'),
|
||||||
|
'li' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'type'), // deprecated attribute
|
||||||
|
'ol' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'type'), // deprecated attribute
|
||||||
|
'p' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'align'), // deprecated attribute
|
||||||
|
'pre' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'width'), // deprecated attribute
|
||||||
|
'strong' => array('class', 'dir', 'id', 'style', 'title'),
|
||||||
|
'table' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'border', 'cellpadding', 'cellspacing', 'frame', 'rules', 'summary', 'width',
|
||||||
|
'align', 'bgcolor'), // deprecated attribute
|
||||||
|
'td' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'align', 'colspan', 'headers', 'rowspan', 'scope', 'valign',
|
||||||
|
'bgcolor', 'height', 'nowrap', 'width'), // deprecated attribute
|
||||||
|
'th' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'align', 'colspan', 'rowspan', 'scope', 'valign',
|
||||||
|
'bgcolor', 'height', 'nowrap', 'width'), // deprecated attribute
|
||||||
|
'tr' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'align', 'valign',
|
||||||
|
'bgcolor'), // deprecated attribute
|
||||||
|
'ul' => array('class', 'dir', 'id', 'style', 'title',
|
||||||
|
'type'), // deprecated attribute
|
||||||
);
|
);
|
||||||
// tags which should always be self-closing (e.g. "<img />")
|
// tags which should always be self-closing (e.g. "<img />")
|
||||||
public $no_close = array(
|
public $no_close = array(
|
||||||
|
35
src/IDF/Template/Tag/UploadUrl.php
Normal file
35
src/IDF/Template/Tag/UploadUrl.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero 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 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
class IDF_Template_Tag_UploadUrl extends Pluf_Template_Tag
|
||||||
|
{
|
||||||
|
function start($file='')
|
||||||
|
{
|
||||||
|
echo IDF_Template_Tag_UploadUrl::url($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function url($file='')
|
||||||
|
{
|
||||||
|
return Pluf::f('url_upload', Pluf_Template_Tag_MediaUrl::url() . '/upload') . $file;
|
||||||
|
}
|
||||||
|
}
|
@@ -32,21 +32,24 @@ class IDF_Tests_TestDiff extends UnitTestCase
|
|||||||
parent::__construct('Test the diff parser.');
|
parent::__construct('Test the diff parser.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testBinaryDiff()
|
//
|
||||||
{
|
// IDF_Diff::mergeChunks() is now private, so this test needs to be rewritten
|
||||||
$diff_content = file_get_contents(dirname(__FILE__).'/test-diff.diff');
|
//
|
||||||
$orig = file_get_contents(dirname(__FILE__).'/test-diff-view.html');
|
//public function testBinaryDiff()
|
||||||
$diff = new IDF_Diff($diff_content);
|
//{
|
||||||
$diff->parse();
|
// $diff_content = file_get_contents(dirname(__FILE__).'/test-diff.diff');
|
||||||
$def = $diff->files['src/IDF/templates/idf/issues/view.html'];
|
// $orig = file_get_contents(dirname(__FILE__).'/test-diff-view.html');
|
||||||
|
// $diff = new IDF_Diff($diff_content);
|
||||||
$orig_lines = preg_split("/\015\012|\015|\012/", $orig);
|
// $diff->parse();
|
||||||
$merged = $diff->mergeChunks($orig_lines, $def, 10);
|
// $def = $diff->files['src/IDF/templates/idf/issues/view.html'];
|
||||||
$lchunk = end($merged);
|
//
|
||||||
$lline = end($lchunk);
|
// $orig_lines = preg_split("/\015\012|\015|\012/", $orig);
|
||||||
$this->assertEqual(array('', '166', '{/if}{/block}'),
|
// $merged = $diff->mergeChunks($orig_lines, $def, 10);
|
||||||
$lline);
|
// $lchunk = end($merged);
|
||||||
}
|
// $lline = end($lchunk);
|
||||||
|
// $this->assertEqual(array('', '166', '{/if}{/block}'),
|
||||||
|
// $lline);
|
||||||
|
//}
|
||||||
|
|
||||||
public function testDiffWithHeaders()
|
public function testDiffWithHeaders()
|
||||||
{
|
{
|
||||||
|
@@ -150,7 +150,7 @@ class IDF_Upload extends Pluf_Model
|
|||||||
if ($this->id == '') {
|
if ($this->id == '') {
|
||||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||||
$this->modif_dtime = gmdate('Y-m-d H:i:s');
|
$this->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||||
$this->md5 = md5_file (Pluf::f('upload_path') . '/' . $this->get_project()->shortname . '/files/' . $this->file);
|
$this->md5 = md5_file ($this->getFullPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +167,11 @@ class IDF_Upload extends Pluf_Model
|
|||||||
return Pluf::f('url_upload').'/'.$project->shortname.'/files/'.$this->file;
|
return Pluf::f('url_upload').'/'.$project->shortname.'/files/'.$this->file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFullPath()
|
||||||
|
{
|
||||||
|
return(Pluf::f('upload_path').'/'.$this->get_project()->shortname.'/files/'.$this->file);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We drop the information from the timeline.
|
* We drop the information from the timeline.
|
||||||
*/
|
*/
|
||||||
@@ -256,4 +261,4 @@ class IDF_Upload extends Pluf_Model
|
|||||||
}
|
}
|
||||||
Pluf_Translation::loadSetLocale($current_locale);
|
Pluf_Translation::loadSetLocale($current_locale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -202,7 +202,11 @@ class IDF_Views_Download
|
|||||||
$prj->inOr404($upload);
|
$prj->inOr404($upload);
|
||||||
$upload->downloads += 1;
|
$upload->downloads += 1;
|
||||||
$upload->update();
|
$upload->update();
|
||||||
return new Pluf_HTTP_Response_Redirect($upload->getAbsoluteUrl($prj));
|
$path = $upload->getFullPath();
|
||||||
|
$mime = IDF_FileUtil::getMimeType($path);
|
||||||
|
$render = new Pluf_HTTP_Response_File($path, $mime[0]);
|
||||||
|
$render->headers["Content-MD5"] = $upload->md5;
|
||||||
|
return $render;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -315,13 +319,11 @@ class IDF_Views_Download
|
|||||||
$pag->no_results_text = __('No downloads were found.');
|
$pag->no_results_text = __('No downloads were found.');
|
||||||
$pag->sort_order = array('creation_dtime', 'DESC');
|
$pag->sort_order = array('creation_dtime', 'DESC');
|
||||||
$pag->setFromRequest($request);
|
$pag->setFromRequest($request);
|
||||||
$tags = $prj->getTagCloud('downloads');
|
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html',
|
||||||
array(
|
array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'label' => $tag,
|
'label' => $tag,
|
||||||
'downloads' => $pag,
|
'downloads' => $pag,
|
||||||
'tags' => $tags,
|
|
||||||
'dlabel' => $dtag,
|
'dlabel' => $dtag,
|
||||||
),
|
),
|
||||||
$request);
|
$request);
|
||||||
|
@@ -71,12 +71,91 @@ class IDF_Views_Issue
|
|||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'open' => $open,
|
'open' => $open,
|
||||||
'closed' => $closed,
|
'closed' => $closed,
|
||||||
'issues' => $pag);
|
'issues' => $pag,
|
||||||
|
'cloud' => 'issues',
|
||||||
|
);
|
||||||
if ($api) return $params;
|
if ($api) return $params;
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
|
||||||
$params, $request);
|
$params, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View the issue summary.
|
||||||
|
* TODO Add thoses data in cache, and process it only after an issue update
|
||||||
|
*/
|
||||||
|
public $summary_precond = array('IDF_Precondition::accessIssues');
|
||||||
|
public function summary($request, $match)
|
||||||
|
{
|
||||||
|
$tagStatistics = array();
|
||||||
|
$ownerStatistics = array();
|
||||||
|
$status = array();
|
||||||
|
$isTrackerEmpty = false;
|
||||||
|
|
||||||
|
$prj = $request->project;
|
||||||
|
$opened = $prj->getIssueCountByStatus('open');
|
||||||
|
$closed = $prj->getIssueCountByStatus('closed');
|
||||||
|
|
||||||
|
// Check if the tracker is empty
|
||||||
|
if ($opened === 0 && $closed === 0) {
|
||||||
|
$isTrackerEmpty = true;
|
||||||
|
} else {
|
||||||
|
if ($opened > 0 || $closed > 0) {
|
||||||
|
// Issue status statistics
|
||||||
|
$status['Open'] = array($opened, (int)(100 * $opened / ($opened + $closed)));
|
||||||
|
$status['Closed'] = array($closed, (int)(100 * $closed / ($opened + $closed)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opened > 0) {
|
||||||
|
// Issue owner statistics
|
||||||
|
$owners = $prj->getIssueCountByOwner('open');
|
||||||
|
foreach ($owners as $user => $nb) {
|
||||||
|
if ($user === '') {
|
||||||
|
$key = __('Not assigned');
|
||||||
|
$login = null;
|
||||||
|
} else {
|
||||||
|
$obj = Pluf::factory('Pluf_User')->getOne(array('filter'=>'id='.$user));
|
||||||
|
$key = $obj->first_name . ' ' . $obj->last_name;
|
||||||
|
$login = $obj->login;
|
||||||
|
}
|
||||||
|
$ownerStatistics[$key] = array($nb, (int)(100 * $nb / $opened), $login);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue class tag statistics
|
||||||
|
$grouped_tags = $prj->getTagCloud();
|
||||||
|
foreach ($grouped_tags as $class => $tags) {
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$tagStatistics[$class][$tag->name] = array($tag->nb_use, $tag->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($tagStatistics as $k => $v) {
|
||||||
|
$nbIssueInClass = 0;
|
||||||
|
foreach ($v as $val) {
|
||||||
|
$nbIssueInClass += $val[0];
|
||||||
|
}
|
||||||
|
foreach ($v as $kk => $vv) {
|
||||||
|
$tagStatistics[$k][$kk] = array($vv[0], (int)(100 * $vv[0] / $nbIssueInClass), $vv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
krsort($tagStatistics);
|
||||||
|
arsort($ownerStatistics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = sprintf(__('Summary of tracked issues in %s.'), (string) $prj);
|
||||||
|
|
||||||
|
return Pluf_Shortcuts_RenderToResponse('idf/issues/summary.html',
|
||||||
|
array('page_title' => $title,
|
||||||
|
'trackerEmpty' => $isTrackerEmpty,
|
||||||
|
'project' => $prj,
|
||||||
|
'tagStatistics' => $tagStatistics,
|
||||||
|
'ownerStatistics' => $ownerStatistics,
|
||||||
|
'status' => $status,
|
||||||
|
),
|
||||||
|
$request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View the issues watch list of a given user.
|
* View the issues watch list of a given user.
|
||||||
* Limited to a specified project
|
* Limited to a specified project
|
||||||
@@ -90,37 +169,37 @@ class IDF_Views_Issue
|
|||||||
$ctags = $prj->getTagIdsByStatus('closed');
|
$ctags = $prj->getTagIdsByStatus('closed');
|
||||||
if (count($otags) == 0) $otags[] = 0;
|
if (count($otags) == 0) $otags[] = 0;
|
||||||
if (count($ctags) == 0) $ctags[] = 0;
|
if (count($ctags) == 0) $ctags[] = 0;
|
||||||
|
|
||||||
// Get the id list of issue in the user watch list (for all projects !)
|
// Get the id list of issue in the user watch list (for all projects !)
|
||||||
$db =& Pluf::db();
|
$db =& Pluf::db();
|
||||||
$sql_results = $db->select('SELECT idf_issue_id as id FROM '.Pluf::f('db_table_prefix', '').'idf_issue_pluf_user_assoc WHERE pluf_user_id='.$request->user->id);
|
$sql_results = $db->select('SELECT idf_issue_id as id FROM '.Pluf::f('db_table_prefix', '').'idf_issue_pluf_user_assoc WHERE pluf_user_id='.$request->user->id);
|
||||||
$issue_ids = array(0);
|
$issue_ids = array(0);
|
||||||
foreach ($sql_results as $id) {
|
foreach ($sql_results as $id) {
|
||||||
$issue_ids[] = $id['id'];
|
$issue_ids[] = $id['id'];
|
||||||
}
|
}
|
||||||
$issue_ids = implode (',', $issue_ids);
|
$issue_ids = implode (',', $issue_ids);
|
||||||
|
|
||||||
// Count open and close issues
|
// Count open and close issues
|
||||||
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).')', array($prj->id));
|
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).')', array($prj->id));
|
||||||
$nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
$nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||||
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array($prj->id));
|
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array($prj->id));
|
||||||
$nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
$nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||||
|
|
||||||
// Generate a filter for the paginator
|
// Generate a filter for the paginator
|
||||||
switch ($match[2]) {
|
switch ($match[2]) {
|
||||||
case 'closed':
|
case 'closed':
|
||||||
$title = sprintf(__('Watch List: Closed Issues for %s'), (string) $prj);
|
$title = sprintf(__('Watch List: Closed Issues for %s'), (string) $prj);
|
||||||
$summary = __('This table shows the closed issues in your watch list for %s project.', (string) $prj);
|
$summary = __('This table shows the closed issues in your watch list for %s project.', (string) $prj);
|
||||||
$f_sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array($prj->id));
|
$f_sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array($prj->id));
|
||||||
break;
|
break;
|
||||||
case 'open':
|
case 'open':
|
||||||
default:
|
default:
|
||||||
$title = sprintf(__('Watch List: Open Issues for %s'), (string) $prj);
|
$title = sprintf(__('Watch List: Open Issues for %s'), (string) $prj);
|
||||||
$summary = __('This table shows the open issues in your watch list for %s project.', (string) $prj);
|
$summary = __('This table shows the open issues in your watch list for %s project.', (string) $prj);
|
||||||
$f_sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).')', array($prj->id));
|
$f_sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).')', array($prj->id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paginator to paginate the issues
|
// Paginator to paginate the issues
|
||||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||||
$pag->class = 'recent-issues';
|
$pag->class = 'recent-issues';
|
||||||
@@ -170,17 +249,17 @@ class IDF_Views_Issue
|
|||||||
}
|
}
|
||||||
foreach (IDF_Views::getProjects($request->user) as $project) {
|
foreach (IDF_Views::getProjects($request->user) as $project) {
|
||||||
$ctags = array_merge($ctags, $project->getTagIdsByStatus('closed'));
|
$ctags = array_merge($ctags, $project->getTagIdsByStatus('closed'));
|
||||||
}
|
}
|
||||||
if (count($otags) == 0) $otags[] = 0;
|
if (count($otags) == 0) $otags[] = 0;
|
||||||
if (count($ctags) == 0) $ctags[] = 0;
|
if (count($ctags) == 0) $ctags[] = 0;
|
||||||
|
|
||||||
// Get the id list of issue in the user watch list (for all projects !)
|
// Get the id list of issue in the user watch list (for all projects !)
|
||||||
$db =& Pluf::db();
|
$db =& Pluf::db();
|
||||||
$sql_results = $db->select('SELECT idf_issue_id as id FROM '.Pluf::f('db_table_prefix', '').'idf_issue_pluf_user_assoc WHERE pluf_user_id='.$request->user->id);
|
$sql_results = $db->select('SELECT idf_issue_id as id FROM '.Pluf::f('db_table_prefix', '').'idf_issue_pluf_user_assoc WHERE pluf_user_id='.$request->user->id);
|
||||||
$issue_ids = array(0);
|
$issue_ids = array(0);
|
||||||
foreach ($sql_results as $id) {
|
foreach ($sql_results as $id) {
|
||||||
$issue_ids[] = $id['id'];
|
$issue_ids[] = $id['id'];
|
||||||
}
|
}
|
||||||
$issue_ids = implode (',', $issue_ids);
|
$issue_ids = implode (',', $issue_ids);
|
||||||
|
|
||||||
// Count open and close issues
|
// Count open and close issues
|
||||||
@@ -194,16 +273,16 @@ class IDF_Views_Issue
|
|||||||
case 'closed':
|
case 'closed':
|
||||||
$title = sprintf(__('Watch List: Closed Issues'));
|
$title = sprintf(__('Watch List: Closed Issues'));
|
||||||
$summary = __('This table shows the closed issues in your watch list.');
|
$summary = __('This table shows the closed issues in your watch list.');
|
||||||
$f_sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array());
|
$f_sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array());
|
||||||
break;
|
break;
|
||||||
case 'open':
|
case 'open':
|
||||||
default:
|
default:
|
||||||
$title = sprintf(__('Watch List: Open Issues'));
|
$title = sprintf(__('Watch List: Open Issues'));
|
||||||
$summary = __('This table shows the open issues in your watch list.');
|
$summary = __('This table shows the open issues in your watch list.');
|
||||||
$f_sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).')', array());
|
$f_sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).')', array());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paginator to paginate the issues
|
// Paginator to paginate the issues
|
||||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||||
$pag->class = 'recent-issues';
|
$pag->class = 'recent-issues';
|
||||||
@@ -240,42 +319,55 @@ class IDF_Views_Issue
|
|||||||
*
|
*
|
||||||
* Only open issues are shown.
|
* Only open issues are shown.
|
||||||
*/
|
*/
|
||||||
public $myIssues_precond = array('IDF_Precondition::accessIssues',
|
public $userIssues_precond = array('IDF_Precondition::accessIssues');
|
||||||
'Pluf_Precondition::loginRequired');
|
public function userIssues($request, $match)
|
||||||
public function myIssues($request, $match)
|
|
||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
|
|
||||||
|
$sql = new Pluf_SQL('login=%s', array($match[2]));
|
||||||
|
$user = Pluf::factory('Pluf_User')->getOne(array('filter' => $sql->gen()));
|
||||||
|
if ($user === null) {
|
||||||
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||||
|
array($prj->shortname));
|
||||||
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
|
}
|
||||||
|
|
||||||
$otags = $prj->getTagIdsByStatus('open');
|
$otags = $prj->getTagIdsByStatus('open');
|
||||||
$ctags = $prj->getTagIdsByStatus('closed');
|
$ctags = $prj->getTagIdsByStatus('closed');
|
||||||
if (count($otags) == 0) $otags[] = 0;
|
if (count($otags) == 0) $otags[] = 0;
|
||||||
if (count($ctags) == 0) $ctags[] = 0;
|
if (count($ctags) == 0) $ctags[] = 0;
|
||||||
switch ($match[2]) {
|
switch ($match[3]) {
|
||||||
case 'submit':
|
case 'submit':
|
||||||
$title = sprintf(__('My Submitted %s Issues'), (string) $prj);
|
$titleFormat = __('%s %s Submitted %s Issues');
|
||||||
$f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id));
|
$f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
|
||||||
break;
|
break;
|
||||||
case 'submitclosed':
|
case 'submitclosed':
|
||||||
$title = sprintf(__('My Closed Submitted %s Issues'), (string) $prj);
|
$titleFormat = __('%s %s Closed Submitted %s Issues');
|
||||||
$f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id));
|
$f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
|
||||||
break;
|
break;
|
||||||
case 'ownerclosed':
|
case 'ownerclosed':
|
||||||
$title = sprintf(__('My Closed Working %s Issues'), (string) $prj);
|
$titleFormat = __('%s %s Closed Working %s Issues');
|
||||||
$f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id));
|
$f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$title = sprintf(__('My Working %s Issues'), (string) $prj);
|
$titleFormat = __('%s %s Working %s Issues');
|
||||||
$f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id));
|
$f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$title = sprintf($titleFormat,
|
||||||
|
$user->first_name,
|
||||||
|
$user->last_name,
|
||||||
|
(string) $prj);
|
||||||
|
|
||||||
// Get stats about the issues
|
// Get stats about the issues
|
||||||
$sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id));
|
$sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
|
||||||
$nb_submit = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
$nb_submit = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||||
$sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id));
|
$sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
|
||||||
$nb_owner = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
$nb_owner = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||||
// Closed issues
|
// Closed issues
|
||||||
$sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id));
|
$sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
|
||||||
$nb_submit_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
$nb_submit_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||||
$sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id));
|
$sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
|
||||||
$nb_owner_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
$nb_owner_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||||
|
|
||||||
// Paginator to paginate the issues
|
// Paginator to paginate the issues
|
||||||
@@ -286,7 +378,7 @@ class IDF_Views_Issue
|
|||||||
'current_user' => $request->user);
|
'current_user' => $request->user);
|
||||||
$pag->summary = __('This table shows the open issues.');
|
$pag->summary = __('This table shows the open issues.');
|
||||||
$pag->forced_where = $f_sql;
|
$pag->forced_where = $f_sql;
|
||||||
$pag->action = array('IDF_Views_Issue::myIssues', array($prj->shortname, $match[2]));
|
$pag->action = array('IDF_Views_Issue::userIssues', array($prj->shortname, $match[2]));
|
||||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||||
$pag->sort_reverse_order = array('modif_dtime');
|
$pag->sort_reverse_order = array('modif_dtime');
|
||||||
$pag->sort_link_title = true;
|
$pag->sort_link_title = true;
|
||||||
@@ -301,9 +393,10 @@ class IDF_Views_Issue
|
|||||||
$pag->items_per_page = 10;
|
$pag->items_per_page = 10;
|
||||||
$pag->no_results_text = __('No issues were found.');
|
$pag->no_results_text = __('No issues were found.');
|
||||||
$pag->setFromRequest($request);
|
$pag->setFromRequest($request);
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/my-issues.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/issues/userIssues.html',
|
||||||
array('project' => $prj,
|
array('project' => $prj,
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
|
'login' => $user->login,
|
||||||
'nb_submit' => $nb_submit,
|
'nb_submit' => $nb_submit,
|
||||||
'nb_owner' => $nb_owner,
|
'nb_owner' => $nb_owner,
|
||||||
'nb_submit_closed' => $nb_submit_closed,
|
'nb_submit_closed' => $nb_submit_closed,
|
||||||
@@ -345,6 +438,7 @@ class IDF_Views_Issue
|
|||||||
'form' => $form,
|
'form' => $form,
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'preview' => $preview,
|
'preview' => $preview,
|
||||||
|
'issue' => new IDF_Issue(),
|
||||||
),
|
),
|
||||||
self::autoCompleteArrays($prj)
|
self::autoCompleteArrays($prj)
|
||||||
);
|
);
|
||||||
@@ -355,45 +449,142 @@ class IDF_Views_Issue
|
|||||||
|
|
||||||
public $search_precond = array('IDF_Precondition::accessIssues');
|
public $search_precond = array('IDF_Precondition::accessIssues');
|
||||||
public function search($request, $match)
|
public function search($request, $match)
|
||||||
|
{
|
||||||
|
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||||
|
return $this->doSearch($request, $query, 'open');
|
||||||
|
}
|
||||||
|
|
||||||
|
public $searchStatus_precond = array('IDF_Precondition::accessIssues');
|
||||||
|
public function searchStatus($request, $match)
|
||||||
|
{
|
||||||
|
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||||
|
$status = in_array($match[2], array('open', 'closed')) ? $match[2] : 'open';
|
||||||
|
return $this->doSearch($request, $query, $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public $searchLabel_precond = array('IDF_Precondition::accessIssues');
|
||||||
|
public function searchLabel($request, $match)
|
||||||
|
{
|
||||||
|
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||||
|
$tag_id = intval($match[2]);
|
||||||
|
$status = in_array($match[3], array('open', 'closed')) ? $match[3] : 'open';
|
||||||
|
return $this->doSearch($request, $query, $status, $tag_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function doSearch($request, $query, $status, $tag_id=null)
|
||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
|
if (trim($query) == '') {
|
||||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index', array($prj->shortname));
|
||||||
array($prj->shortname));
|
|
||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
$q = $request->REQUEST['q'];
|
|
||||||
$title = sprintf(__('Search Issues - %s'), $q);
|
$tag = null;
|
||||||
$issues = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj, 'IDF_Issue'));
|
if ($tag_id !== null) {
|
||||||
if (count($issues) > 100) {
|
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $tag_id);
|
||||||
// no more than 100 results as we do not care
|
|
||||||
$issues->results = array_slice($issues->results, 0, 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$title = sprintf(__('Search issues - %s'), $query);
|
||||||
|
if ($status === 'closed') {
|
||||||
|
$title = sprintf(__('Search closed issues - %s'), $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// using Plufs ResultSet implementation here is inefficient, because
|
||||||
|
// it makes a SELECT for each item and does not allow for further
|
||||||
|
// filtering neither, so we just return the ids and filter by them
|
||||||
|
// and other things in the next round
|
||||||
|
$results = IDF_Search::mySearch($query, $prj, 'IDF_Issue');
|
||||||
|
|
||||||
|
$issue_ids = array(0);
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$issue_ids[] = $result['model_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$otags = $prj->getTagIdsByStatus($status);
|
||||||
|
if (count($otags) == 0) $otags[] = 0;
|
||||||
|
$sql = new Pluf_SQL(
|
||||||
|
'id IN ('.implode(',', $issue_ids).') '.
|
||||||
|
'AND status IN ('.implode(', ', $otags).') '.
|
||||||
|
($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '')
|
||||||
|
);
|
||||||
|
$model = new IDF_Issue();
|
||||||
|
$issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'));
|
||||||
|
|
||||||
|
// we unfortunately loose the original sort order,
|
||||||
|
// so we manually have to apply it here again
|
||||||
|
$sorted_issues = new ArrayObject();
|
||||||
|
$filtered_issue_ids = array(0);
|
||||||
|
foreach ($issue_ids as $issue_id) {
|
||||||
|
foreach ($issues as $issue) {
|
||||||
|
if ($issue->id != $issue_id)
|
||||||
|
continue;
|
||||||
|
if (array_key_exists($issue_id, $sorted_issues))
|
||||||
|
continue;
|
||||||
|
$sorted_issues[$issue_id] = $issue;
|
||||||
|
$filtered_issue_ids[] = $issue_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$pag = new Pluf_Paginator();
|
$pag = new Pluf_Paginator();
|
||||||
$pag->items = $issues;
|
|
||||||
$pag->class = 'recent-issues';
|
$pag->class = 'recent-issues';
|
||||||
$pag->item_extra_props = array('project_m' => $prj,
|
$pag->items = $sorted_issues;
|
||||||
'shortname' => $prj->shortname,
|
$pag->item_extra_props = array(
|
||||||
'current_user' => $request->user);
|
'project_m' => $prj,
|
||||||
|
'shortname' => $prj->shortname,
|
||||||
|
'current_user' => $request->user
|
||||||
|
);
|
||||||
$pag->summary = __('This table shows the found issues.');
|
$pag->summary = __('This table shows the found issues.');
|
||||||
$pag->action = array('IDF_Views_Issue::search', array($prj->shortname), array('q'=> $q));
|
|
||||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||||
$list_display = array(
|
$pag->configure(array(
|
||||||
'id' => __('Id'),
|
'id' => __('Id'),
|
||||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||||
);
|
));
|
||||||
$pag->configure($list_display);
|
// disable paginating
|
||||||
$pag->items_per_page = 100;
|
$pag->items_per_page = PHP_INT_MAX;
|
||||||
$pag->no_results_text = __('No issues were found.');
|
$pag->no_results_text = __('No issues were found.');
|
||||||
$pag->setFromRequest($request);
|
$pag->setFromRequest($request);
|
||||||
$params = array('page_title' => $title,
|
|
||||||
'issues' => $pag,
|
|
||||||
'q' => $q,
|
|
||||||
);
|
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
|
|
||||||
|
|
||||||
|
if ($tag_id === null) {
|
||||||
|
$pag->action = array('IDF_Views_Issue::searchStatus',
|
||||||
|
array($prj->shortname, $status),
|
||||||
|
array('q'=> $query),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$pag->action = array('IDF_Views_Issue::searchLabel',
|
||||||
|
array($prj->shortname, $tag_id, $status),
|
||||||
|
array('q'=> $query),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get stats about the issues
|
||||||
|
$open = $prj->getIssueCountByStatus('open', $tag, $issue_ids);
|
||||||
|
$closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids);
|
||||||
|
|
||||||
|
// query the available tags for this search result
|
||||||
|
$all_tags = $prj->getTagsByIssues($filtered_issue_ids);
|
||||||
|
$grouped_tags = array();
|
||||||
|
foreach ($all_tags as $atag) {
|
||||||
|
// group by class
|
||||||
|
if (!array_key_exists($atag->class, $grouped_tags)) {
|
||||||
|
$grouped_tags[$atag->class] = array();
|
||||||
|
}
|
||||||
|
$grouped_tags[$atag->class][] = $atag;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'page_title' => $title,
|
||||||
|
'issues' => $pag,
|
||||||
|
'query' => $query,
|
||||||
|
'status' => $status,
|
||||||
|
'open' => $open,
|
||||||
|
'closed' => $closed,
|
||||||
|
'tag' => $tag,
|
||||||
|
'all_tags' => $grouped_tags,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public $view_precond = array('IDF_Precondition::accessIssues');
|
public $view_precond = array('IDF_Precondition::accessIssues');
|
||||||
@@ -403,6 +594,8 @@ class IDF_Views_Issue
|
|||||||
$issue = Pluf_Shortcuts_GetObjectOr404('IDF_Issue', $match[2]);
|
$issue = Pluf_Shortcuts_GetObjectOr404('IDF_Issue', $match[2]);
|
||||||
$prj->inOr404($issue);
|
$prj->inOr404($issue);
|
||||||
$comments = $issue->get_comments_list(array('order' => 'id ASC'));
|
$comments = $issue->get_comments_list(array('order' => 'id ASC'));
|
||||||
|
$related_issues = $issue->getGroupedRelatedIssues(array('order' => 'other_issue ASC'));
|
||||||
|
|
||||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||||
array($prj->shortname, $issue->id));
|
array($prj->shortname, $issue->id));
|
||||||
$title = Pluf_Template::markSafe(sprintf(__('Issue <a href="%s">%d</a>: %s'), $url, $issue->id, $issue->summary));
|
$title = Pluf_Template::markSafe(sprintf(__('Issue <a href="%s">%d</a>: %s'), $url, $issue->id, $issue->summary));
|
||||||
@@ -453,7 +646,7 @@ class IDF_Views_Issue
|
|||||||
$next_issue = Pluf::factory('IDF_Issue')->getList(array('filter' => $sql_next->gen(),
|
$next_issue = Pluf::factory('IDF_Issue')->getList(array('filter' => $sql_next->gen(),
|
||||||
'order' => 'id ASC',
|
'order' => 'id ASC',
|
||||||
'nb' => 1
|
'nb' => 1
|
||||||
));
|
));
|
||||||
$previous_issue_id = (isset($previous_issue[0])) ? $previous_issue[0]->id : 0;
|
$previous_issue_id = (isset($previous_issue[0])) ? $previous_issue[0]->id : 0;
|
||||||
$next_issue_id = (isset($next_issue[0])) ? $next_issue[0]->id : 0;
|
$next_issue_id = (isset($next_issue[0])) ? $next_issue[0]->id : 0;
|
||||||
|
|
||||||
@@ -470,7 +663,8 @@ class IDF_Views_Issue
|
|||||||
'preview' => $preview,
|
'preview' => $preview,
|
||||||
'interested' => $interested->count(),
|
'interested' => $interested->count(),
|
||||||
'previous_issue_id' => $previous_issue_id,
|
'previous_issue_id' => $previous_issue_id,
|
||||||
'next_issue_id' => $next_issue_id
|
'next_issue_id' => $next_issue_id,
|
||||||
|
'related_issues' => $related_issues,
|
||||||
),
|
),
|
||||||
$arrays),
|
$arrays),
|
||||||
$request);
|
$request);
|
||||||
@@ -538,6 +732,13 @@ class IDF_Views_Issue
|
|||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
$status = $match[2];
|
$status = $match[2];
|
||||||
|
|
||||||
|
if (mb_strtolower($status) == 'open') {
|
||||||
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||||
|
array($prj->shortname));
|
||||||
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
|
}
|
||||||
|
|
||||||
$title = sprintf(__('%s Closed Issues'), (string) $prj);
|
$title = sprintf(__('%s Closed Issues'), (string) $prj);
|
||||||
// Get stats about the issues
|
// Get stats about the issues
|
||||||
$open = $prj->getIssueCountByStatus('open');
|
$open = $prj->getIssueCountByStatus('open');
|
||||||
@@ -643,6 +844,79 @@ class IDF_Views_Issue
|
|||||||
$request);
|
$request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a JSON string containing completed issue information
|
||||||
|
* based on the queried / partial string
|
||||||
|
*/
|
||||||
|
public $autoCompleteIssueList_precond = array('IDF_Precondition::accessIssues');
|
||||||
|
public function autoCompleteIssueList($request, $match)
|
||||||
|
{
|
||||||
|
$prj = $request->project;
|
||||||
|
$issue_id = !empty($match[2]) ? intval($match[2]) : 0;
|
||||||
|
$query = trim($request->REQUEST['q']);
|
||||||
|
$limit = !empty($request->REQUEST['limit']) ? intval($request->REQUEST['limit']) : 0;
|
||||||
|
$limit = max(10, $limit);
|
||||||
|
|
||||||
|
$issues = array();
|
||||||
|
|
||||||
|
// empty search, return the most recently updated issues
|
||||||
|
if (empty($query)) {
|
||||||
|
$sql = new Pluf_SQL('project=%s', array($prj->id));
|
||||||
|
$tmp = Pluf::factory('IDF_Issue')->getList(array(
|
||||||
|
'filter' => $sql->gen(),
|
||||||
|
'order' => 'modif_dtime DESC'
|
||||||
|
));
|
||||||
|
$issues += $tmp->getArrayCopy();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ID-based search
|
||||||
|
if (is_numeric($query)) {
|
||||||
|
$sql = 'project=%s AND CAST(id AS VARCHAR) LIKE %s';
|
||||||
|
// MySQL can't cast to VARCHAR and a CAST to CHAR converts
|
||||||
|
// the whole number, not just the first digit
|
||||||
|
if (strtolower(Pluf::f('db_engine')) == 'mysql') {
|
||||||
|
$sql = 'project=%s AND CAST(id AS CHAR) LIKE %s';
|
||||||
|
}
|
||||||
|
$sql = new Pluf_SQL($sql, array($prj->id, $query.'%'));
|
||||||
|
$tmp = Pluf::factory('IDF_Issue')->getList(array(
|
||||||
|
'filter' => $sql->gen(),
|
||||||
|
'order' => 'id ASC'
|
||||||
|
));
|
||||||
|
$issues += $tmp->getArrayCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// text-based search
|
||||||
|
$res = new Pluf_Search_ResultSet(
|
||||||
|
IDF_Search::mySearch($query, $prj, 'IDF_Issue')
|
||||||
|
);
|
||||||
|
foreach ($res as $issue)
|
||||||
|
$issues[] = $issue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autocomplete from jQuery UI works with JSON, this old one still
|
||||||
|
// expects a parsable string; since we'd need to bump jQuery beyond
|
||||||
|
// 1.2.6 for this to use as well, we're trying to cope with the old format.
|
||||||
|
// see http://www.learningjquery.com/2010/06/autocomplete-migration-guide
|
||||||
|
$out = '';
|
||||||
|
$ids = array();
|
||||||
|
foreach ($issues as $issue)
|
||||||
|
{
|
||||||
|
if ($issue->id == $issue_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (in_array($issue->id, $ids))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (--$limit < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
$out .= str_replace('|', '|', $issue->summary) .'|'.$issue->id."\n";
|
||||||
|
$ids[] = $issue->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pluf_HTTP_Response($out);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Star/Unstar an issue.
|
* Star/Unstar an issue.
|
||||||
*/
|
*/
|
||||||
@@ -715,6 +989,15 @@ class IDF_Views_Issue
|
|||||||
}
|
}
|
||||||
$auto['auto_owner'] = substr($auto['auto_owner'], 0, -2);
|
$auto['auto_owner'] = substr($auto['auto_owner'], 0, -2);
|
||||||
unset($auto['_auto_owner']);
|
unset($auto['_auto_owner']);
|
||||||
|
// Get issue relations
|
||||||
|
$r = $project->getRelationsFromConfig();
|
||||||
|
$auto['auto_relation_types'] = '';
|
||||||
|
foreach ($r as $rt) {
|
||||||
|
$esc = Pluf_esc($rt);
|
||||||
|
$auto['auto_relation_types'] .= sprintf('{ name: "%s", to: "%s" }, ',
|
||||||
|
$esc, $esc);
|
||||||
|
}
|
||||||
|
$auto['auto_relation_types'] = substr($auto['auto_relation_types'], 0, -2);
|
||||||
return $auto;
|
return $auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,18 +38,18 @@ class IDF_Views_Project
|
|||||||
public function logo($request, $match)
|
public function logo($request, $match)
|
||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
|
|
||||||
$logo = $prj->getConf()->getVal('logo');
|
$logo = $prj->getConf()->getVal('logo');
|
||||||
if (empty($logo)) {
|
if (empty($logo)) {
|
||||||
$url = Pluf::f('url_media') . '/idf/img/no_logo.png';
|
$url = Pluf::f('url_media') . '/idf/img/no_logo.png';
|
||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
|
|
||||||
$info = IDF_FileUtil::getMimeType($logo);
|
$info = IDF_FileUtil::getMimeType($logo);
|
||||||
return new Pluf_HTTP_Response_File(Pluf::f('upload_path') . '/' . $prj->shortname . $logo,
|
return new Pluf_HTTP_Response_File(Pluf::f('upload_path') . '/' . $prj->shortname . $logo,
|
||||||
$info[0]);
|
$info[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Home page of a project.
|
* Home page of a project.
|
||||||
*/
|
*/
|
||||||
@@ -291,12 +291,12 @@ class IDF_Views_Project
|
|||||||
public function admin($request, $match)
|
public function admin($request, $match)
|
||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
$title = sprintf(__('%s Project Summary'), (string) $prj);
|
$title = sprintf(__('%s Project Summary'), (string) $prj);
|
||||||
$extra = array('project' => $prj);
|
$extra = array('project' => $prj);
|
||||||
if ($request->method == 'POST') {
|
if ($request->method == 'POST') {
|
||||||
$form = new IDF_Form_ProjectConf(array_merge($request->POST,
|
$form = new IDF_Form_ProjectConf(array_merge($request->POST,
|
||||||
$request->FILES),
|
$request->FILES),
|
||||||
$extra);
|
$extra);
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
$form->save();
|
$form->save();
|
||||||
$request->user->setMessage(__('The project has been updated.'));
|
$request->user->setMessage(__('The project has been updated.'));
|
||||||
@@ -305,9 +305,9 @@ class IDF_Views_Project
|
|||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$form = new IDF_Form_ProjectConf($prj->getData(), $extra);
|
$form = new IDF_Form_ProjectConf($prj->getData(), $extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
$logo = $prj->getConf()->getVal('logo');
|
$logo = $prj->getConf()->getVal('logo');
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/admin/summary.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/admin/summary.html',
|
||||||
array(
|
array(
|
||||||
@@ -316,7 +316,7 @@ class IDF_Views_Project
|
|||||||
'project' => $prj,
|
'project' => $prj,
|
||||||
'logo' => $logo,
|
'logo' => $logo,
|
||||||
),
|
),
|
||||||
$request);
|
$request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -344,7 +344,8 @@ class IDF_Views_Project
|
|||||||
$params = array();
|
$params = array();
|
||||||
$keys = array('labels_issue_template',
|
$keys = array('labels_issue_template',
|
||||||
'labels_issue_open', 'labels_issue_closed',
|
'labels_issue_open', 'labels_issue_closed',
|
||||||
'labels_issue_predefined', 'labels_issue_one_max');
|
'labels_issue_predefined', 'labels_issue_one_max',
|
||||||
|
'issue_relations');
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
$_val = $conf->getVal($key, false);
|
$_val = $conf->getVal($key, false);
|
||||||
if ($_val !== false) {
|
if ($_val !== false) {
|
||||||
|
@@ -58,7 +58,7 @@ class IDF_Views_Source
|
|||||||
$title = sprintf(__('%s Invalid Revision'), (string) $request->project);
|
$title = sprintf(__('%s Invalid Revision'), (string) $request->project);
|
||||||
$scm = IDF_Scm::get($request->project);
|
$scm = IDF_Scm::get($request->project);
|
||||||
$branches = $scm->getBranches();
|
$branches = $scm->getBranches();
|
||||||
|
|
||||||
$commit = $match[2];
|
$commit = $match[2];
|
||||||
$params = array(
|
$params = array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
@@ -66,7 +66,8 @@ class IDF_Views_Source
|
|||||||
'commit' => $commit,
|
'commit' => $commit,
|
||||||
'branches' => $branches,
|
'branches' => $branches,
|
||||||
);
|
);
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/source/invalid_revision.html',
|
$scmConf = $request->conf->getVal('scm', 'git');
|
||||||
|
return Pluf_Shortcuts_RenderToResponse('idf/source/'.$scmConf.'/invalid_revision.html',
|
||||||
$params, $request);
|
$params, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,12 +308,7 @@ class IDF_Views_Source
|
|||||||
$cobject->diff = null;
|
$cobject->diff = null;
|
||||||
$diff->parse();
|
$diff->parse();
|
||||||
$scmConf = $request->conf->getVal('scm', 'git');
|
$scmConf = $request->conf->getVal('scm', 'git');
|
||||||
try {
|
$changes = $scm->getChanges($commit);
|
||||||
$changes = $scm->getChanges($commit);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// getChanges is not yes supported by this backend.
|
|
||||||
$changes = array();
|
|
||||||
}
|
|
||||||
$branches = $scm->getBranches();
|
$branches = $scm->getBranches();
|
||||||
$in_branches = $scm->inBranches($cobject->commit, '');
|
$in_branches = $scm->inBranches($cobject->commit, '');
|
||||||
$tags = $scm->getTags();
|
$tags = $scm->getTags();
|
||||||
@@ -477,7 +473,7 @@ class IDF_Views_Source
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compare two nodes of different types, directories ("tree")
|
// compare two nodes of different types, directories ("tree")
|
||||||
// should come before files ("blob")
|
// should come before files ("blob")
|
||||||
if ($a->type > $b->type) {
|
if ($a->type > $b->type) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@@ -152,13 +152,11 @@ class IDF_Views_Wiki
|
|||||||
$pag->items_per_page = 25;
|
$pag->items_per_page = 25;
|
||||||
$pag->no_results_text = __('No documentation pages were found.');
|
$pag->no_results_text = __('No documentation pages were found.');
|
||||||
$pag->setFromRequest($request);
|
$pag->setFromRequest($request);
|
||||||
$tags = $prj->getTagCloud('wiki');
|
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
|
||||||
array(
|
array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'label' => $tag,
|
'label' => $tag,
|
||||||
'pages' => $pag,
|
'pages' => $pag,
|
||||||
'tags' => $tags,
|
|
||||||
'dlabel' => $dtag,
|
'dlabel' => $dtag,
|
||||||
),
|
),
|
||||||
$request);
|
$request);
|
||||||
|
@@ -118,11 +118,26 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#',
|
|||||||
'model' => 'IDF_Views_Issue',
|
'model' => 'IDF_Views_Issue',
|
||||||
'method' => 'index');
|
'method' => 'index');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/summary/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Issue',
|
||||||
|
'method' => 'summary');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Issue',
|
'model' => 'IDF_Views_Issue',
|
||||||
'method' => 'search');
|
'method' => 'search');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/status/(\w+)/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Issue',
|
||||||
|
'method' => 'searchStatus');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/label/(\d+)/(\w+)/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Issue',
|
||||||
|
'method' => 'searchLabel');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Issue',
|
'model' => 'IDF_Views_Issue',
|
||||||
@@ -148,10 +163,10 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/create/$#',
|
|||||||
'model' => 'IDF_Views_Issue',
|
'model' => 'IDF_Views_Issue',
|
||||||
'method' => 'create');
|
'method' => 'create');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/my/(\w+)/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(.*)/(\w+)/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Issue',
|
'model' => 'IDF_Views_Issue',
|
||||||
'method' => 'myIssues');
|
'method' => 'userIssues');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/attachment/(\d+)/(.*)$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/attachment/(\d+)/(.*)$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
@@ -173,6 +188,11 @@ $ctl[] = array('regex' => '#^/watchlist/(\w+)$#',
|
|||||||
'model' => 'IDF_Views_Issue',
|
'model' => 'IDF_Views_Issue',
|
||||||
'method' => 'forgeWatchList');
|
'method' => 'forgeWatchList');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/autocomplete/(\d*)$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Issue',
|
||||||
|
'method' => 'autoCompleteIssueList');
|
||||||
|
|
||||||
// ---------- SCM ----------------------------------------
|
// ---------- SCM ----------------------------------------
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/help/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/help/$#',
|
||||||
|
@@ -130,7 +130,7 @@ msgstr "Entferntes Subversion-Depot"
|
|||||||
|
|
||||||
#: IDF/Form/Admin/ProjectCreate.php:92 IDF/Form/SourceConf.php:40
|
#: IDF/Form/Admin/ProjectCreate.php:92 IDF/Form/SourceConf.php:40
|
||||||
msgid "Repository username"
|
msgid "Repository username"
|
||||||
msgstr "Depot-Nutzername"
|
msgstr "Depot-Benutzername"
|
||||||
|
|
||||||
#: IDF/Form/Admin/ProjectCreate.php:99 IDF/Form/SourceConf.php:47
|
#: IDF/Form/Admin/ProjectCreate.php:99 IDF/Form/SourceConf.php:47
|
||||||
msgid "Repository password"
|
msgid "Repository password"
|
||||||
@@ -156,11 +156,11 @@ msgstr "Projekt-Eigentümer"
|
|||||||
#: IDF/Form/Admin/ProjectCreate.php:123 IDF/Form/Admin/ProjectUpdate.php:76
|
#: IDF/Form/Admin/ProjectCreate.php:123 IDF/Form/Admin/ProjectUpdate.php:76
|
||||||
#: IDF/Form/MembersConf.php:54 IDF/Form/TabsConf.php:52
|
#: IDF/Form/MembersConf.php:54 IDF/Form/TabsConf.php:52
|
||||||
msgid "Project members"
|
msgid "Project members"
|
||||||
msgstr "Projekt-Mitglieder"
|
msgstr "Projektmitglieder"
|
||||||
|
|
||||||
#: IDF/Form/Admin/ProjectCreate.php:136
|
#: IDF/Form/Admin/ProjectCreate.php:136
|
||||||
msgid "Project template"
|
msgid "Project template"
|
||||||
msgstr "Projekt-Vorlage"
|
msgstr "Projektvorlage"
|
||||||
|
|
||||||
#: IDF/Form/Admin/ProjectCreate.php:138
|
#: IDF/Form/Admin/ProjectCreate.php:138
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -168,7 +168,7 @@ msgid ""
|
|||||||
"general configuration will be taken from the template project."
|
"general configuration will be taken from the template project."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Benutze das vorgegebene Projekt, um ein neues zu initialisieren. "
|
"Benutze das vorgegebene Projekt, um ein neues zu initialisieren. "
|
||||||
"Zugriffsrechte und allgemeine Konfiguration werden von der Projekt-Vorlage "
|
"Zugriffsrechte und allgemeine Konfiguration werden von der Projektvorlage "
|
||||||
"übernommen."
|
"übernommen."
|
||||||
|
|
||||||
#: IDF/Form/Admin/ProjectCreate.php:185
|
#: IDF/Form/Admin/ProjectCreate.php:185
|
||||||
@@ -350,7 +350,7 @@ msgid ""
|
|||||||
"The password must be hard for other people to guess, but easy for the user "
|
"The password must be hard for other people to guess, but easy for the user "
|
||||||
"to remember."
|
"to remember."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Das Passwort sollte für andere Leute schwer zu erraten, aber für den Nutzer "
|
"Das Passwort sollte für andere Leute schwer zu erraten, aber für den Benutzer "
|
||||||
"einfach zu erinnern sein."
|
"einfach zu erinnern sein."
|
||||||
|
|
||||||
#: IDF/Form/Admin/UserUpdate.php:89
|
#: IDF/Form/Admin/UserUpdate.php:89
|
||||||
@@ -366,7 +366,7 @@ msgstr "Beschreibung"
|
|||||||
|
|
||||||
#: IDF/Form/Admin/UserUpdate.php:109 IDF/Form/UserAccount.php:110
|
#: IDF/Form/Admin/UserUpdate.php:109 IDF/Form/UserAccount.php:110
|
||||||
msgid "Twitter username"
|
msgid "Twitter username"
|
||||||
msgstr "Twitter-Nutzername"
|
msgstr "Twitter-Benutzername"
|
||||||
|
|
||||||
#: IDF/Form/Admin/UserUpdate.php:119 IDF/Form/UserAccount.php:120
|
#: IDF/Form/Admin/UserUpdate.php:119 IDF/Form/UserAccount.php:120
|
||||||
msgid "Public email address"
|
msgid "Public email address"
|
||||||
@@ -403,7 +403,7 @@ msgstr "Stab"
|
|||||||
#: IDF/Form/Admin/UserUpdate.php:164
|
#: IDF/Form/Admin/UserUpdate.php:164
|
||||||
msgid "If you give staff rights to a user, you really need to trust them."
|
msgid "If you give staff rights to a user, you really need to trust them."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn Du einen Nutzer zum Stab hinzufügst, solltest Du ihm wirklich trauen."
|
"Wenn Du einen Benutzer zum Stab hinzufügst, solltest Du ihm wirklich trauen."
|
||||||
|
|
||||||
#: IDF/Form/Admin/UserUpdate.php:172 IDF/Views/Admin.php:213
|
#: IDF/Form/Admin/UserUpdate.php:172 IDF/Views/Admin.php:213
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
@@ -414,8 +414,8 @@ msgid ""
|
|||||||
"If the user is not getting the confirmation email or is abusing the system, "
|
"If the user is not getting the confirmation email or is abusing the system, "
|
||||||
"you can directly enable or disable their account here."
|
"you can directly enable or disable their account here."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn der Nutzer keine Bestätigungs-E-Mail erhält oder das System "
|
"Wenn der Benutzer keine Bestätigungs-E-Mail erhält oder das System "
|
||||||
"missbraucht, kannst Du sein Konto hier direkt aktivieren oder deaktivieren."
|
"missbraucht, kannst Du sein Benutzerkonto hier direkt aktivieren oder deaktivieren."
|
||||||
|
|
||||||
#: IDF/Form/Admin/UserUpdate.php:274
|
#: IDF/Form/Admin/UserUpdate.php:274
|
||||||
msgid "--- is not a valid first name."
|
msgid "--- is not a valid first name."
|
||||||
@@ -425,7 +425,7 @@ msgstr "--- ist kein gültiger Vorname"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"A user with this email already exists, please provide another email address."
|
"A user with this email already exists, please provide another email address."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ein Nutzer mit dieser E-Mail-Adresse existiert bereits, bitte gib eine "
|
"Ein Benutzer mit dieser E-Mail-Adresse existiert bereits, bitte gib eine "
|
||||||
"andere E-Mail-Adresse an."
|
"andere E-Mail-Adresse an."
|
||||||
|
|
||||||
#: IDF/Form/Admin/UserUpdate.php:301 IDF/Form/UserAccount.php:389
|
#: IDF/Form/Admin/UserUpdate.php:301 IDF/Form/UserAccount.php:389
|
||||||
@@ -678,7 +678,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: IDF/Form/Register.php:148
|
#: IDF/Form/Register.php:148
|
||||||
msgid "Confirm the creation of your account."
|
msgid "Confirm the creation of your account."
|
||||||
msgstr "Bestätige die Erstellung deines Accounts."
|
msgstr "Bestätige die Erstellung Deines Benutzerkontos."
|
||||||
|
|
||||||
#: IDF/Form/RegisterConfirmation.php:40 IDF/Form/RegisterInputKey.php:36
|
#: IDF/Form/RegisterConfirmation.php:40 IDF/Form/RegisterInputKey.php:36
|
||||||
msgid "Your confirmation key"
|
msgid "Your confirmation key"
|
||||||
@@ -705,7 +705,7 @@ msgid ""
|
|||||||
"This account has already been confirmed. Maybe should you try to recover "
|
"This account has already been confirmed. Maybe should you try to recover "
|
||||||
"your password using the help link."
|
"your password using the help link."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Dieses Konto wurde bereits bestätigt. Vielleicht möchtest Du versuchen, Dein "
|
"Dieses Benutzerkonto wurde bereits bestätigt. Vielleicht möchtest Du versuchen, Dein "
|
||||||
"Passwort über den Hilfe-Link wiederherzustellen?"
|
"Passwort über den Hilfe-Link wiederherzustellen?"
|
||||||
|
|
||||||
#: IDF/Form/ReviewCreate.php:74
|
#: IDF/Form/ReviewCreate.php:74
|
||||||
@@ -1204,7 +1204,7 @@ msgstr ""
|
|||||||
"Quellcode.<br />\n"
|
"Quellcode.<br />\n"
|
||||||
"Wenn Du den Zugriff auf den Quellcode beschränkst, wird kein anonymer "
|
"Wenn Du den Zugriff auf den Quellcode beschränkst, wird kein anonymer "
|
||||||
"Zugriff<br />\n"
|
"Zugriff<br />\n"
|
||||||
"angeboten und die Nutzer müssen sich mit ihrem Passwort oder "
|
"angeboten und die Benutzer müssen sich mit ihrem Passwort oder "
|
||||||
"öffentlichen<br />\n"
|
"öffentlichen<br />\n"
|
||||||
"Schlüssel authentifizieren."
|
"Schlüssel authentifizieren."
|
||||||
|
|
||||||
@@ -1241,7 +1241,7 @@ msgid ""
|
|||||||
"\" will default to authorized users only."
|
"\" will default to authorized users only."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn Du ein Projekt als privat markierst, haben nur Projektmitglieder und "
|
"Wenn Du ein Projekt als privat markierst, haben nur Projektmitglieder und "
|
||||||
"Administratoren zusammen mit den von Dir extra authorisierten Nutzern "
|
"Administratoren zusammen mit den von Dir extra authorisierten Benutzern "
|
||||||
"Zugriff darauf. Du kannst weiterhin zusätzliche Zugriffsrechte für bestimmte "
|
"Zugriff darauf. Du kannst weiterhin zusätzliche Zugriffsrechte für bestimmte "
|
||||||
"Projektfunktionen vergeben, aber die Einstellungen \"Für alle offen\" und "
|
"Projektfunktionen vergeben, aber die Einstellungen \"Für alle offen\" und "
|
||||||
"\"Angemeldete Benutzer\" werden standardmäßig nur authorisierte Benutzer "
|
"\"Angemeldete Benutzer\" werden standardmäßig nur authorisierte Benutzer "
|
||||||
@@ -1287,7 +1287,7 @@ msgid ""
|
|||||||
"<a href=\"%%url%%\">Sign in or create your account</a> to create issues or "
|
"<a href=\"%%url%%\">Sign in or create your account</a> to create issues or "
|
||||||
"add comments"
|
"add comments"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"<a href=\"%%url%%\">Melde Dich an oder lege ein Konto an</a>, um Tickets "
|
"<a href=\"%%url%%\">Melde Dich an oder lege ein Benutzerkonto an</a>, um Tickets "
|
||||||
"oder Kommentare hinzuzufügen"
|
"oder Kommentare hinzuzufügen"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/base-full.html.php:4
|
#: IDF/gettexttemplates/idf/base-full.html.php:4
|
||||||
@@ -1587,7 +1587,7 @@ msgid ""
|
|||||||
"You need to create an account on <a href=\"http://en.gravatar.com/"
|
"You need to create an account on <a href=\"http://en.gravatar.com/"
|
||||||
"\">Gravatar</a>, this takes about 5 minutes and is free."
|
"\">Gravatar</a>, this takes about 5 minutes and is free."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Du musst Dir einen Account auf <a href=\"http://de.gravatar.com/\">Gravatar</"
|
"Du musst Dir ein Benutzerkonto auf <a href=\"http://de.gravatar.com/\">Gravatar.com</"
|
||||||
"a> erstellen, es dauert nur 5 Minuten und ist kostenfrei."
|
"a> erstellen, es dauert nur 5 Minuten und ist kostenfrei."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/faq.html.php:10
|
#: IDF/gettexttemplates/idf/faq.html.php:10
|
||||||
@@ -1632,7 +1632,7 @@ msgstr "<kbd>Umschalt+h</kbd>: Diese Hilfeseite."
|
|||||||
#: IDF/gettexttemplates/idf/faq.html.php:18
|
#: IDF/gettexttemplates/idf/faq.html.php:18
|
||||||
msgid "If you are in a project, you have the following shortcuts:"
|
msgid "If you are in a project, you have the following shortcuts:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Befindest Du Dich in einem Projekt, kannst du die folgenden Tastaturkürzel "
|
"Befindest Du Dich in einem Projekt, kannst Du die folgenden Tastaturkürzel "
|
||||||
"benutzen:"
|
"benutzen:"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/faq.html.php:19
|
#: IDF/gettexttemplates/idf/faq.html.php:19
|
||||||
@@ -1874,28 +1874,28 @@ msgstr "Es wird eine Bestätigung verlangt."
|
|||||||
#: IDF/gettexttemplates/idf/gadmin/users/base.html.php:3
|
#: IDF/gettexttemplates/idf/gadmin/users/base.html.php:3
|
||||||
#: IDF/Views/Admin.php:201
|
#: IDF/Views/Admin.php:201
|
||||||
msgid "User List"
|
msgid "User List"
|
||||||
msgstr "Nutzerliste"
|
msgstr "Benutzerliste"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/base.html.php:4
|
#: IDF/gettexttemplates/idf/gadmin/users/base.html.php:4
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:13
|
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:13
|
||||||
msgid "Update User"
|
msgid "Update User"
|
||||||
msgstr "Nutzer aktualisieren"
|
msgstr "Benutzer aktualisieren"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/base.html.php:5
|
#: IDF/gettexttemplates/idf/gadmin/users/base.html.php:5
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/create.html.php:4
|
#: IDF/gettexttemplates/idf/gadmin/users/create.html.php:4
|
||||||
msgid "Create User"
|
msgid "Create User"
|
||||||
msgstr "Nutzer anlegen"
|
msgstr "Benutzer anlegen"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/create.html.php:3
|
#: IDF/gettexttemplates/idf/gadmin/users/create.html.php:3
|
||||||
msgid "The form contains some errors. Please correct them to create the user."
|
msgid "The form contains some errors. Please correct them to create the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Die Eingabemaske enthält einige Fehler. Bitte korrigiere diese, um den "
|
"Die Eingabemaske enthält einige Fehler. Bitte korrigiere diese, um den "
|
||||||
"Nutzer zu erstellen."
|
"Benutzer zu erstellen."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/create.html.php:6
|
#: IDF/gettexttemplates/idf/gadmin/users/create.html.php:6
|
||||||
msgid "The user password will be sent by email to the user."
|
msgid "The user password will be sent by email to the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Das Passwort des Nutzers wird an die E-Mail-Adresse des Nutzers versandt."
|
"Das Passwort des Benutzers wird an die E-Mail-Adresse des Benutzers versandt."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/createuser-email.txt.php:3
|
#: IDF/gettexttemplates/idf/gadmin/users/createuser-email.txt.php:3
|
||||||
#, php-format
|
#, php-format
|
||||||
@@ -1916,10 +1916,11 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Hallo %%user%%,\n"
|
"Hallo %%user%%,\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Der Administrator %%admin%% hat ein neues Konto für Dich\n"
|
"Der Administrator %%admin%% hat ein neues Benutzerkonto\n"
|
||||||
"auf der Forge angelegt.\n"
|
"für Dich auf der Forge angelegt.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Hier sind die Zugangsdaten, mit denen Du auf Dein Konto zugreifen kannst:\n"
|
"Hier sind die Zugangsdaten, mit denen Du auf Dein Benutzerkonto\n"
|
||||||
|
"zugreifen kannst:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Adresse: %%url%%\n"
|
" Adresse: %%url%%\n"
|
||||||
" Anmeldename: %%user.login%%\n"
|
" Anmeldename: %%user.login%%\n"
|
||||||
@@ -1931,17 +1932,17 @@ msgstr ""
|
|||||||
#: IDF/gettexttemplates/idf/gadmin/users/index.html.php:3
|
#: IDF/gettexttemplates/idf/gadmin/users/index.html.php:3
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "See <a href=\"%%url%%\">not validated users</a>."
|
msgid "See <a href=\"%%url%%\">not validated users</a>."
|
||||||
msgstr "Zeige <a href=\"%%url%%\">nicht validierte Nutzer</a>."
|
msgstr "Zeige <a href=\"%%url%%\">nicht validierte Benutzer</a>."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/index.html.php:4
|
#: IDF/gettexttemplates/idf/gadmin/users/index.html.php:4
|
||||||
msgid "<p>You have here an overview of the users registered in the forge.</p>"
|
msgid "<p>You have here an overview of the users registered in the forge.</p>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"<p>Hier siehst Du eine Übersicht der Nutzer, die sich in der Forge "
|
"<p>Hier siehst Du eine Übersicht der Benutzer, die sich in der Forge "
|
||||||
"registriert haben."
|
"registriert haben."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/index.html.php:5
|
#: IDF/gettexttemplates/idf/gadmin/users/index.html.php:5
|
||||||
msgid "Number of users:"
|
msgid "Number of users:"
|
||||||
msgstr "Anzahl der Nutzer:"
|
msgstr "Anzahl der Benutzer:"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:3
|
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:3
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1949,7 +1950,7 @@ msgid ""
|
|||||||
"need to ensure that you are providing a valid email\n"
|
"need to ensure that you are providing a valid email\n"
|
||||||
"address"
|
"address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn Du die E-Mail-Adresse eines Nutzers änderst,\n"
|
"Wenn Du die E-Mail-Adresse eines Benutzers änderst,\n"
|
||||||
"musst Du sicherstellen, eine gültige, neue E-Mail-Adresse\n"
|
"musst Du sicherstellen, eine gültige, neue E-Mail-Adresse\n"
|
||||||
"als Ersatz bereitzustellen."
|
"als Ersatz bereitzustellen."
|
||||||
|
|
||||||
@@ -1959,14 +1960,14 @@ msgid ""
|
|||||||
"able to create new projects and update other non staff users.\n"
|
"able to create new projects and update other non staff users.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn Du dem Benutzer Stab-Rechte erteilst, kann er\n"
|
"Wenn Du dem Benutzer Stab-Rechte erteilst, kann er\n"
|
||||||
"neue Projekte anlegen und andere Nutzer, die nicht zum Stab\n"
|
"neue Projekte anlegen und andere Benutzer, die nicht zum Stab\n"
|
||||||
"gehören, aktualisieren.\n"
|
"gehören, aktualisieren.\n"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:9
|
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:9
|
||||||
msgid "The form contains some errors. Please correct them to update the user."
|
msgid "The form contains some errors. Please correct them to update the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Die Eingabemaske enthält einige Fehler. Bitte korrigiere diese, um den "
|
"Die Eingabemaske enthält einige Fehler. Bitte korrigiere diese, um den "
|
||||||
"Nutzer zu aktualisieren."
|
"Benutzer zu aktualisieren."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:10
|
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:10
|
||||||
#: IDF/gettexttemplates/idf/register/confirmation.html.php:4
|
#: IDF/gettexttemplates/idf/register/confirmation.html.php:4
|
||||||
@@ -2449,7 +2450,7 @@ msgid ""
|
|||||||
"is still valid and more work is needed to fully fix it."
|
"is still valid and more work is needed to fully fix it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Dieses Ticket wurde als geschlossen markiert. Füge nur dann einen Kommentar "
|
"Dieses Ticket wurde als geschlossen markiert. Füge nur dann einen Kommentar "
|
||||||
"hinzu, wenn du denkst, dass das geschilderte Problem noch nicht ganz "
|
"hinzu, wenn Du denkst, dass das geschilderte Problem noch nicht ganz "
|
||||||
"beseitigt wurde."
|
"beseitigt wurde."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/issues/view.html.orig.php:8
|
#: IDF/gettexttemplates/idf/issues/view.html.orig.php:8
|
||||||
@@ -2531,7 +2532,7 @@ msgid ""
|
|||||||
"If you don't have an account yet, you can create one <a href=\"%%url%%"
|
"If you don't have an account yet, you can create one <a href=\"%%url%%"
|
||||||
"\">here</a>."
|
"\">here</a>."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn Du noch kein Konto hast, kannst Du <a href=\"%%url%%\">hier</a> ein "
|
"Wenn Du noch kein Benutzerkonto hast, kannst Du <a href=\"%%url%%\">hier</a> ein "
|
||||||
"neues erstellen."
|
"neues erstellen."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/login_form.html.php:4
|
#: IDF/gettexttemplates/idf/login_form.html.php:4
|
||||||
@@ -2560,7 +2561,7 @@ msgstr "Willkommen."
|
|||||||
|
|
||||||
#: IDF/gettexttemplates/idf/login_form.html.php:10
|
#: IDF/gettexttemplates/idf/login_form.html.php:10
|
||||||
msgid "It takes less than a minute to create your account."
|
msgid "It takes less than a minute to create your account."
|
||||||
msgstr "Es dauert weniger als eine Minute, um Dein Konto zu erstellen."
|
msgstr "Es dauert weniger als eine Minute, um Dein Benutzerkonto zu erstellen."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/main-menu.html.php:3
|
#: IDF/gettexttemplates/idf/main-menu.html.php:3
|
||||||
#, php-format
|
#, php-format
|
||||||
@@ -2576,7 +2577,7 @@ msgstr "Abmelden"
|
|||||||
|
|
||||||
#: IDF/gettexttemplates/idf/main-menu.html.php:5
|
#: IDF/gettexttemplates/idf/main-menu.html.php:5
|
||||||
msgid "Sign in or create your account"
|
msgid "Sign in or create your account"
|
||||||
msgstr "Anmelden oder Konto erstellen"
|
msgstr "Anmelden oder Benutzerkonto erstellen"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/main-menu.html.php:8 IDF/Views/Admin.php:42
|
#: IDF/gettexttemplates/idf/main-menu.html.php:8 IDF/Views/Admin.php:42
|
||||||
msgid "Forge Management"
|
msgid "Forge Management"
|
||||||
@@ -2671,7 +2672,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Hallo,\n"
|
"Hallo,\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Du hast die Anlage eines Kontos angeforder, um an dem Leben\n"
|
"Du hast die Anlage eines Benutzerkontos angefordert, um an dem Leben\n"
|
||||||
"eines Softwareprojektes teilhaben zu können.\n"
|
"eines Softwareprojektes teilhaben zu können.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Um Dein Konto zu bestätigen, folge bitte dem folgenden Link:\n"
|
"Um Dein Konto zu bestätigen, folge bitte dem folgenden Link:\n"
|
||||||
@@ -2688,7 +2689,7 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"Wenn Du nicht mehr länger an diesem Software-Projekt\n"
|
"Wenn Du nicht mehr länger an diesem Software-Projekt\n"
|
||||||
"interessiert bist oder wenn Du Dich nicht daran erinnern\n"
|
"interessiert bist oder wenn Du Dich nicht daran erinnern\n"
|
||||||
"kannst, dieses Konto erstellen zu wollen, entschuldige\n"
|
"kannst, dieses Benutzerkonto erstellen zu wollen, entschuldige\n"
|
||||||
"und ignoriere einfach diese E-Mail.\n"
|
"und ignoriere einfach diese E-Mail.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Mit freundlichen Grüßen,\n"
|
"Mit freundlichen Grüßen,\n"
|
||||||
@@ -2716,7 +2717,7 @@ msgid ""
|
|||||||
"strong> to log in afterwards."
|
"strong> to log in afterwards."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Dies ist der letzte Schritt, aber bitte <strong>stelle sicher, dass Du "
|
"Dies ist der letzte Schritt, aber bitte <strong>stelle sicher, dass Du "
|
||||||
"Cookies aktiviert hast</strong>, um Dich im folgenden anzumelden."
|
"Cookies aktiviert hast</strong>, um Dich im Folgenden anzumelden."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/register/index.html.php:3
|
#: IDF/gettexttemplates/idf/register/index.html.php:3
|
||||||
#: IDF/gettexttemplates/idf/register/index.html~.php:3
|
#: IDF/gettexttemplates/idf/register/index.html~.php:3
|
||||||
@@ -2736,7 +2737,7 @@ msgid ""
|
|||||||
"login name and password."
|
"login name and password."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn Du einfach nur Deine Anmeldedaten vergessen hast, gibt es keinen Grund, "
|
"Wenn Du einfach nur Deine Anmeldedaten vergessen hast, gibt es keinen Grund, "
|
||||||
"ein neues Konto zu erstellen. Gehe einfach <a href=\"%%url%%\">hier her</a>, "
|
"ein neues Benutzerkonto zu erstellen. Gehe einfach <a href=\"%%url%%\">hier her</a>, "
|
||||||
"um Deinen Anmeldenamen und Dein Passwort wiederherzustellen."
|
"um Deinen Anmeldenamen und Dein Passwort wiederherzustellen."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/register/index.html.php:5
|
#: IDF/gettexttemplates/idf/register/index.html.php:5
|
||||||
@@ -2748,7 +2749,7 @@ msgid ""
|
|||||||
"you have troubles, you can <a href=\"%%url%%\">let us know about your issues "
|
"you have troubles, you can <a href=\"%%url%%\">let us know about your issues "
|
||||||
"at anytime</a>!"
|
"at anytime</a>!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Durch Dein Konto bist Du in der Lage, an dem Leben aller Softwareprojekte, "
|
"Durch Dein Benutzerkonto bist Du in der Lage, an dem Leben aller Softwareprojekte, "
|
||||||
"die hierüber verwaltet werden, teilzuhaben. Das Teilnehmen an einem "
|
"die hierüber verwaltet werden, teilzuhaben. Das Teilnehmen an einem "
|
||||||
"Softwareprojekt muss Spass machen, deshalb <a href=\"%%url%%\">lass uns "
|
"Softwareprojekt muss Spass machen, deshalb <a href=\"%%url%%\">lass uns "
|
||||||
"jederzeit von Deinen Problemen wissen</a>, solltest Du welche haben."
|
"jederzeit von Deinen Problemen wissen</a>, solltest Du welche haben."
|
||||||
@@ -3209,13 +3210,13 @@ msgstr "Zweige filtern"
|
|||||||
#: IDF/gettexttemplates/idf/source/mercurial/branch_tag_list.html.php:5
|
#: IDF/gettexttemplates/idf/source/mercurial/branch_tag_list.html.php:5
|
||||||
#: IDF/gettexttemplates/idf/source/mtn/branch_tag_list.html.php:5
|
#: IDF/gettexttemplates/idf/source/mtn/branch_tag_list.html.php:5
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr "Marken"
|
msgstr "Tags"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/source/git/branch_tag_list.html.php:6
|
#: IDF/gettexttemplates/idf/source/git/branch_tag_list.html.php:6
|
||||||
#: IDF/gettexttemplates/idf/source/mercurial/branch_tag_list.html.php:6
|
#: IDF/gettexttemplates/idf/source/mercurial/branch_tag_list.html.php:6
|
||||||
#: IDF/gettexttemplates/idf/source/mtn/branch_tag_list.html.php:6
|
#: IDF/gettexttemplates/idf/source/mtn/branch_tag_list.html.php:6
|
||||||
msgid "filter tags"
|
msgid "filter tags"
|
||||||
msgstr "Marken filtern"
|
msgstr "Tags filtern"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/source/git/file.html.php:3
|
#: IDF/gettexttemplates/idf/source/git/file.html.php:3
|
||||||
#: IDF/gettexttemplates/idf/source/git/tree.html.php:3
|
#: IDF/gettexttemplates/idf/source/git/tree.html.php:3
|
||||||
@@ -3231,7 +3232,7 @@ msgid ""
|
|||||||
"%%cobject.date%%."
|
"%%cobject.date%%."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Quellcode bei Revision <a class=\"mono\" href=\"%%url%%\">%%commit%%</a> "
|
"Quellcode bei Revision <a class=\"mono\" href=\"%%url%%\">%%commit%%</a> "
|
||||||
"erzeugt am %%cobject.date%%."
|
"erzeugt %%cobject.date%%."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/source/git/file.html.php:4
|
#: IDF/gettexttemplates/idf/source/git/file.html.php:4
|
||||||
#: IDF/gettexttemplates/idf/source/git/tree.html.php:4
|
#: IDF/gettexttemplates/idf/source/git/tree.html.php:4
|
||||||
@@ -3409,8 +3410,8 @@ msgstr "Revision:"
|
|||||||
#: IDF/gettexttemplates/idf/source/svn/commit.html.php:4
|
#: IDF/gettexttemplates/idf/source/svn/commit.html.php:4
|
||||||
#: IDF/gettexttemplates/idf/source/svn/file.html.php:11
|
#: IDF/gettexttemplates/idf/source/svn/file.html.php:11
|
||||||
#: IDF/gettexttemplates/idf/source/svn/tree.html.php:16
|
#: IDF/gettexttemplates/idf/source/svn/tree.html.php:16
|
||||||
msgid "Go to revision"
|
msgid "Switch"
|
||||||
msgstr "Zu Revision gehen:"
|
msgstr "Wechseln"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/source/svn/file.html.php:6
|
#: IDF/gettexttemplates/idf/source/svn/file.html.php:6
|
||||||
#: IDF/gettexttemplates/idf/source/svn/tree.html.php:11
|
#: IDF/gettexttemplates/idf/source/svn/tree.html.php:11
|
||||||
@@ -3442,7 +3443,7 @@ msgstr "Zweige:"
|
|||||||
|
|
||||||
#: IDF/gettexttemplates/idf/source/svn/tree.html.php:18
|
#: IDF/gettexttemplates/idf/source/svn/tree.html.php:18
|
||||||
msgid "Tags:"
|
msgid "Tags:"
|
||||||
msgstr "Marken:"
|
msgstr "Tags:"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/user/changeemail-email.txt.php:3
|
#: IDF/gettexttemplates/idf/user/changeemail-email.txt.php:3
|
||||||
#, php-format
|
#, php-format
|
||||||
@@ -3491,7 +3492,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: IDF/gettexttemplates/idf/user/changeemail.html.php:4
|
#: IDF/gettexttemplates/idf/user/changeemail.html.php:4
|
||||||
msgid "Confirm Your New Email Address"
|
msgid "Confirm Your New Email Address"
|
||||||
msgstr "Bestätige deine neue Email-Adresse"
|
msgstr "Bestätige Deine neue Email-Adresse"
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/user/changeemail.html.php:7
|
#: IDF/gettexttemplates/idf/user/changeemail.html.php:7
|
||||||
#: IDF/gettexttemplates/idf/user/passrecovery-inputkey.html.php:7
|
#: IDF/gettexttemplates/idf/user/passrecovery-inputkey.html.php:7
|
||||||
@@ -3508,7 +3509,7 @@ msgstr ""
|
|||||||
#: IDF/gettexttemplates/idf/user/dashboard.html.php:3
|
#: IDF/gettexttemplates/idf/user/dashboard.html.php:3
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "<a href=\"%%url%%\">Update your account</a>."
|
msgid "<a href=\"%%url%%\">Update your account</a>."
|
||||||
msgstr "<a href=\"%%url%%\">Aktualisiere Dein Konto</a>."
|
msgstr "<a href=\"%%url%%\">Aktualisiere Dein Benutzerkonto</a>."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/user/dashboard.html.php:4
|
#: IDF/gettexttemplates/idf/user/dashboard.html.php:4
|
||||||
#, php-format
|
#, php-format
|
||||||
@@ -3578,7 +3579,7 @@ msgid ""
|
|||||||
"If possible, use your real name. By using your real name, people will have "
|
"If possible, use your real name. By using your real name, people will have "
|
||||||
"more trust in your comments and remarks."
|
"more trust in your comments and remarks."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wenn möglich, nutze Deinen realen Namen. Dadurch wird deinen Kommentaren und "
|
"Wenn möglich, nutze Deinen realen Namen. Dadurch wird Deinen Kommentaren und "
|
||||||
"Bemerkungen mehr Vertrauen geschenkt."
|
"Bemerkungen mehr Vertrauen geschenkt."
|
||||||
|
|
||||||
#: IDF/gettexttemplates/idf/user/myaccount.html.php:19
|
#: IDF/gettexttemplates/idf/user/myaccount.html.php:19
|
||||||
@@ -3646,7 +3647,7 @@ msgstr ""
|
|||||||
"Hallo %%user%%,\n"
|
"Hallo %%user%%,\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Du hast Dein Passwort verloren und möchtest es wiederherstellen.\n"
|
"Du hast Dein Passwort verloren und möchtest es wiederherstellen.\n"
|
||||||
"Um ein neues Passwort für Dein Konto anzugeben, musst Du lediglich\n"
|
"Um ein neues Passwort für Dein Benutzerkonto anzugeben, musst Du lediglich\n"
|
||||||
"dem folgenden Link folgen. Sie führt zu einer einfachen Eingabemaske,\n"
|
"dem folgenden Link folgen. Sie führt zu einer einfachen Eingabemaske,\n"
|
||||||
"mit der Du ein neues Passwort setzen kannst.\n"
|
"mit der Du ein neues Passwort setzen kannst.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -3801,7 +3802,7 @@ msgstr ""
|
|||||||
"a> mit der <a href=\"%%eurl%%\"><em>Extra</em>-Erweiterung</a> verwendet "
|
"a> mit der <a href=\"%%eurl%%\"><em>Extra</em>-Erweiterung</a> verwendet "
|
||||||
"werden.</p>\n"
|
"werden.</p>\n"
|
||||||
"<p>Website-Adresses werden automatisch verlinkt und Du kannst außerdem zu "
|
"<p>Website-Adresses werden automatisch verlinkt und Du kannst außerdem zu "
|
||||||
"anderen Dokumentations-Seiten durch die Benutzung von doppelten, eckige "
|
"anderen Dokumentations-Seiten durch die Benutzung von doppelten, eckigen "
|
||||||
"Klammern verlinken, etwa so: [[AndereSeite]].</p>\n"
|
"Klammern verlinken, etwa so: [[AndereSeite]].</p>\n"
|
||||||
"<p>Um direkt die Inhalte einer Datei aus dem Depot einzubinden, umklammere "
|
"<p>Um direkt die Inhalte einer Datei aus dem Depot einzubinden, umklammere "
|
||||||
"den Pfad zur Datei mit dreifachen, eckigen Klammern: [[[Pfad/zu/Datei.txt]]]."
|
"den Pfad zur Datei mit dreifachen, eckigen Klammern: [[[Pfad/zu/Datei.txt]]]."
|
||||||
@@ -4388,7 +4389,7 @@ msgstr "Administrator"
|
|||||||
|
|
||||||
#: IDF/Views/Admin.php:214
|
#: IDF/Views/Admin.php:214
|
||||||
msgid "Last Login"
|
msgid "Last Login"
|
||||||
msgstr "Letzter Login"
|
msgstr "Letztes Login"
|
||||||
|
|
||||||
#: IDF/Views/Admin.php:221
|
#: IDF/Views/Admin.php:221
|
||||||
msgid "No users were found."
|
msgid "No users were found."
|
||||||
@@ -4954,7 +4955,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: IDF/Views.php:284
|
#: IDF/Views.php:284
|
||||||
msgid "Here to Help You!"
|
msgid "Here to Help You!"
|
||||||
msgstr "Hier, um dir zu helfen!"
|
msgstr "Hier, um Dir zu helfen!"
|
||||||
|
|
||||||
#: IDF/Views.php:300
|
#: IDF/Views.php:300
|
||||||
msgid "InDefero API (Application Programming Interface)"
|
msgid "InDefero API (Application Programming Interface)"
|
||||||
|
@@ -45,6 +45,7 @@ $m['IDF_Scm_Cache_Git'] = array('relate_to' => array('IDF_Project'));
|
|||||||
|
|
||||||
$m['IDF_UserData'] = array('relate_to' => array('Pluf_User'));
|
$m['IDF_UserData'] = array('relate_to' => array('Pluf_User'));
|
||||||
$m['IDF_EmailAddress'] = array('relate_to' => array('Pluf_User'));
|
$m['IDF_EmailAddress'] = array('relate_to' => array('Pluf_User'));
|
||||||
|
$m['IDF_IssueRelation'] = array('relate_to' => array('IDF_Issue', 'Pluf_User'));
|
||||||
|
|
||||||
Pluf_Signal::connect('Pluf_Template_Compiler::construct_template_tags_modifiers',
|
Pluf_Signal::connect('Pluf_Template_Compiler::construct_template_tags_modifiers',
|
||||||
array('IDF_Middleware', 'updateTemplateTagsModifiers'));
|
array('IDF_Middleware', 'updateTemplateTagsModifiers'));
|
||||||
|
@@ -35,8 +35,15 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td colspan="2"><strong>{$form.f.issue_relations.labelTag}:</strong><br />
|
||||||
|
{if $form.f.issue_relations.errors}{$form.f.issue_relations.fieldErrors}{/if}
|
||||||
|
{$form.f.issue_relations|unsafe}<br />
|
||||||
|
<span class="helptext">{$form.f.issue_relations.help_text}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<input type="submit" value="{trans 'Save Changes'}" name="submit" />
|
<input type="submit" value="{trans 'Save Changes'}" name="submit" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@@ -70,7 +70,6 @@
|
|||||||
<div id="ft">{block foot}{/block}</div>
|
<div id="ft">{block foot}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
{include 'idf/js-hotkeys.html'}
|
{include 'idf/js-hotkeys.html'}
|
||||||
{include 'idf/list-filter.html'}
|
|
||||||
{block javascript}{/block}
|
{block javascript}{/block}
|
||||||
{if $project}
|
{if $project}
|
||||||
<script type="text/javascript" charset="utf-8">{literal}
|
<script type="text/javascript" charset="utf-8">{literal}
|
||||||
|
@@ -49,7 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="yui-b context">{block context}{/block}</div>
|
<div class="yui-b context" id="context">{block context}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="ft">{block foot}{/block}</div>
|
<div id="ft">{block foot}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -66,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="yui-b context">{block context}{/block}</div>
|
<div class="yui-b context" id="context">{block context}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="ft">{block foot}{/block}</div>
|
<div id="ft">{block foot}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,6 +84,21 @@ $(document).ready(function(){
|
|||||||
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
||||||
$(frag).addClass("issue-comment-focus");
|
$(frag).addClass("issue-comment-focus");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var contextTop = $('div#context').position().top;
|
||||||
|
var contextFixEnabled = true;
|
||||||
|
$(window).scroll(function() {
|
||||||
|
if (!contextFixEnabled || $(window).scrollTop() < contextTop)
|
||||||
|
$('div#context').css('position', 'relative');
|
||||||
|
else
|
||||||
|
$('div#context').css('position', 'fixed');
|
||||||
|
});
|
||||||
|
$(window).resize(function() {
|
||||||
|
contextFixEnabled =
|
||||||
|
$('div#context').offset().top + $('div#context').height() <
|
||||||
|
$(window).height();
|
||||||
|
});
|
||||||
|
$(window).resize();
|
||||||
});
|
});
|
||||||
//]]>{/literal}
|
//]]>{/literal}
|
||||||
</script>{/if}
|
</script>{/if}
|
||||||
|
@@ -8,12 +8,18 @@
|
|||||||
<th>{trans "address"}</th>
|
<th>{trans "address"}</th>
|
||||||
<th>{trans "port"}</th>
|
<th>{trans "port"}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
{if count($connections) == 0}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="center">{trans 'No connections found.'}</td>
|
||||||
|
</tr>
|
||||||
|
{else}
|
||||||
{foreach $connections as $connection}
|
{foreach $connections as $connection}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{$connection.address}</td>
|
<td>{$connection.address}</td>
|
||||||
<td>{$connection.port}</td>
|
<td>{$connection.port}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
|
{/if}
|
||||||
</table>
|
</table>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
|
@@ -9,6 +9,11 @@
|
|||||||
<th>{trans "status"}</th>
|
<th>{trans "status"}</th>
|
||||||
<th>{trans "action"}</th>
|
<th>{trans "action"}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
{if count($servers) == 0}
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" align="center">{trans 'No monotone servers configured.'}</td>
|
||||||
|
</tr>
|
||||||
|
{else}
|
||||||
{foreach $servers as $server}
|
{foreach $servers as $server}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{$server.name}</td>
|
<td>{$server.name}</td>
|
||||||
@@ -31,6 +36,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</tr>
|
</tr>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
|
{/if}
|
||||||
</table>
|
</table>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
|
@@ -2,11 +2,12 @@
|
|||||||
{block tabissues} class="active"{/block}
|
{block tabissues} class="active"{/block}
|
||||||
{block subtabs}
|
{block subtabs}
|
||||||
<div id="sub-tabs">
|
<div id="sub-tabs">
|
||||||
<a {if $inOpenIssues}class="active" {/if}href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Open Issues'}</a>
|
<a {if $inSummaryIssues}class="active" {/if}href="{url 'IDF_Views_Issue::summary', array($project.shortname)}">{trans 'Summary'}</a>
|
||||||
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a>
|
| <a {if $inOpenIssues}class="active" {/if}href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Open Issues'}</a>
|
||||||
|
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'submit')}">{trans 'My Issues'}</a>
|
||||||
| <a {if $inWatchList}class="active" {/if}href="{url 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}">{trans 'My watch list'}</a>{/if} |
|
| <a {if $inWatchList}class="active" {/if}href="{url 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}">{trans 'My watch list'}</a>{/if} |
|
||||||
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
|
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
|
||||||
<input accesskey="4" type="text" value="{$q}" name="q" size="20" />
|
<input accesskey="4" type="text" value="{$query}" name="q" size="20" />
|
||||||
<input type="submit" name="s" value="{trans 'Search'}" />
|
<input type="submit" name="s" value="{trans 'Search'}" />
|
||||||
</form>
|
</form>
|
||||||
{if $inIssue} |
|
{if $inIssue} |
|
||||||
|
@@ -8,16 +8,15 @@
|
|||||||
|
|
||||||
{/block}
|
{/block}
|
||||||
{block context}
|
{block context}
|
||||||
<p><strong>{trans 'Label:'}</strong>
|
|
||||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
|
||||||
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
|
|
||||||
{aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
{aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||||
{aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')}
|
{aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')}
|
||||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
|
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
|
||||||
{/blocktrans}{if $completion}
|
{/blocktrans}
|
||||||
|
<p><strong>{trans 'Label:'}</strong>
|
||||||
|
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||||
|
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
|
||||||
|
{if $completion}
|
||||||
<p><strong>{trans 'Completion:'}</strong> {$completion}</p>
|
<p><strong>{trans 'Completion:'}</strong> {$completion}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
{/block}
|
{/block}
|
||||||
|
@@ -63,6 +63,15 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>{$form.f.relation_type0.labelTag}:</th>
|
||||||
|
<td>
|
||||||
|
{if $form.f.relation_type0.errors}{$form.f.relation_type0.fieldErrors}{/if}
|
||||||
|
{if $form.f.relation_issue0.errors}{$form.f.relation_issue0.fieldErrors}{/if}
|
||||||
|
{$form.f.relation_type0|unsafe}
|
||||||
|
{$form.f.relation_issue0|unsafe}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<th>{$form.f.label1.labelTag}:</th>
|
<th>{$form.f.label1.labelTag}:</th>
|
||||||
<td>
|
<td>
|
||||||
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
||||||
@@ -76,8 +85,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td>
|
<td>
|
||||||
<input type="submit" value="{trans 'Submit Issue'}" name="submit" />
|
<input type="submit" value="{trans 'Submit Issue'}" name="submit" />
|
||||||
<input type="submit" value="{trans 'Preview'}" name="preview" /> |
|
<input type="submit" value="{trans 'Preview'}" name="preview" /> |
|
||||||
<a href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Cancel'}</a>
|
<a href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Cancel'}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -123,11 +132,11 @@ $(document).ready(function(){
|
|||||||
});
|
});
|
||||||
var j=0;
|
var j=0;
|
||||||
for (j=1;j<4;j=j+1) {
|
for (j=1;j<4;j=j+1) {
|
||||||
if($("tr#form-attachment-"+j+" > td > ul.errorlist").length == 0){
|
if($("tr#form-attachment-"+j+" > td > ul.errorlist").length == 0){
|
||||||
$("#form-attachment-"+j).hide();
|
$("#form-attachment-"+j).hide();
|
||||||
}else{
|
}else{
|
||||||
$("#form-block-"+(j-1)).remove();
|
$("#form-block-"+(j-1)).remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -10,12 +10,22 @@
|
|||||||
{if $attachments.count() > 0}
|
{if $attachments.count() > 0}
|
||||||
<hr align="left" class="attach" />
|
<hr align="left" class="attach" />
|
||||||
<ul>
|
<ul>
|
||||||
{foreach $attachments as $a}<li><a href="{url 'IDF_Views_Issue::viewAttachment', array($project.shortname, $a.id, $a.filename)}">{$a.filename}</a> - {$a.filesize|ssize}</li>{/foreach}
|
{foreach $attachments as $a}<li><a href="{url 'IDF_Views_Issue::viewAttachment', array($project.shortname, $a.id, $a.filename)}">{$a.filename}</a> - {$a.filesize|ssize}</li>{/foreach}
|
||||||
</ul>{/if}
|
</ul>{/if}
|
||||||
{if $c.changes}
|
{if $c.changes}
|
||||||
{foreach $c.changes as $w => $v}
|
{foreach $c.changes as $w => $v}
|
||||||
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}</strong> {if $w == 'lb'}{assign $l = implode(', ', $v)}{$l}{else}{$v}{/if}<br />
|
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong>
|
||||||
|
{if $w == 'lb' or $w == 'rel'}
|
||||||
|
{foreach $v as $t => $ls}
|
||||||
|
{foreach $ls as $l}
|
||||||
|
{if $t == 'rem'}<s>{/if}{$l}{if $t == 'rem'}</s>{/if}
|
||||||
|
{/foreach}
|
||||||
|
{/foreach}
|
||||||
|
{else}
|
||||||
|
{$v}
|
||||||
|
{/if}<br />
|
||||||
{/foreach}
|
{/foreach}
|
||||||
{/if}
|
{/if}
|
||||||
</div></content>
|
</div></content>
|
||||||
</entry>
|
</entry>
|
||||||
|
|
||||||
|
@@ -13,6 +13,5 @@
|
|||||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
||||||
{assign $cloud_url = 'IDF_Views_Issue::listLabel'}
|
{assign $cloud_url = 'IDF_Views_Issue::listLabel'}
|
||||||
{assign $cloud = 'issues'}
|
|
||||||
{include 'idf/tags-cloud.html'}
|
{include 'idf/tags-cloud.html'}
|
||||||
{/block}
|
{/block}
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
{if strlen($c.content) > 0}{$c.content|safe}{/if}{if $c.changedIssue()}
|
{if strlen($c.content) > 0}{$c.content|safe}{/if}{if $c.changedIssue()}
|
||||||
{foreach $c.changes as $w => $v}
|
{foreach $c.changes as $w => $v}
|
||||||
{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if} {if $w == 'lb'}{assign $l = implode(', ', $v)}{$l}{else}{$v}{/if}{/foreach}{/if}{assign $attachments = $c.get_attachment_list()}{if $attachments.count() > 0}
|
{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if} {if $w == 'lb' or $w == 'rel'}{foreach $v as $t => $ls}{foreach $ls as $l}{if $t == 'rem'}-{/if}{$l} {/foreach}{/foreach}{else}{$v}{/if}{/foreach}{/if}{assign $attachments = $c.get_attachment_list()}{if $attachments.count() > 0}
|
||||||
|
|
||||||
{trans 'Attachments:'}{foreach $attachments as $a}
|
{trans 'Attachments:'}{foreach $attachments as $a}
|
||||||
- {$a.filename|safe} - {$a.filesize|ssize}
|
- {$a.filename|safe} - {$a.filesize|ssize}
|
||||||
|
@@ -2,54 +2,94 @@
|
|||||||
<script type="text/javascript" src="{media '/idf/js/jquery.bgiframe.min.js'}"></script>
|
<script type="text/javascript" src="{media '/idf/js/jquery.bgiframe.min.js'}"></script>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery.autocomplete.min.js'}"></script>
|
<script type="text/javascript" src="{media '/idf/js/jquery.autocomplete.min.js'}"></script>
|
||||||
<script type="text/javascript" charset="utf-8">
|
<script type="text/javascript" charset="utf-8">
|
||||||
// <!-- {literal}
|
// <!-- {literal}
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
var auto_labels = [{/literal}{$auto_labels|safe}{literal}];
|
var auto_labels = [{/literal}{$auto_labels|safe}{literal}];
|
||||||
var auto_status = [{/literal}{$auto_status|safe}{literal}];
|
var auto_status = [{/literal}{$auto_status|safe}{literal}];
|
||||||
var auto_owner = [{/literal}{$auto_owner|safe}{literal}];
|
var auto_owner = [{/literal}{$auto_owner|safe}{literal}];
|
||||||
|
var auto_relation_types = [{/literal}{$auto_relation_types|safe}{literal}];
|
||||||
|
|
||||||
var j=0;
|
var j=0;
|
||||||
for (j=1;j<7;j=j+1) {
|
for (j=1;j<7;j=j+1) {
|
||||||
$("#id_label"+j).autocomplete(auto_labels, {
|
$("#id_label"+j).autocomplete(auto_labels, {
|
||||||
minChars: 0,
|
minChars: 0,
|
||||||
width: 310,
|
width: 310,
|
||||||
matchContains: true,
|
matchContains: true,
|
||||||
max: 50,
|
max: 50,
|
||||||
highlightItem: false,
|
highlightItem: false,
|
||||||
formatItem: function(row, i, max, term) {
|
formatItem: function(row, i, max, term) {
|
||||||
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
||||||
},
|
},
|
||||||
formatResult: function(row) {
|
formatResult: function(row) {
|
||||||
return row.to;
|
return row.to;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$("#id_status").autocomplete(auto_status, {
|
$("#id_status").autocomplete(auto_status, {
|
||||||
minChars: 0,
|
minChars: 0,
|
||||||
width: 310,
|
width: 310,
|
||||||
matchContains: true,
|
matchContains: true,
|
||||||
max: 50,
|
max: 50,
|
||||||
highlightItem: false,
|
highlightItem: false,
|
||||||
formatItem: function(row, i, max, term) {
|
formatItem: function(row, i, max, term) {
|
||||||
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
||||||
},
|
},
|
||||||
formatResult: function(row) {
|
formatResult: function(row) {
|
||||||
return row.to;
|
return row.to;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("#id_owner").autocomplete(auto_owner, {
|
$("#id_owner").autocomplete(auto_owner, {
|
||||||
minChars: 0,
|
minChars: 0,
|
||||||
width: 310,
|
width: 310,
|
||||||
matchContains: true,
|
matchContains: true,
|
||||||
max: 50,
|
max: 50,
|
||||||
highlightItem: false,
|
highlightItem: false,
|
||||||
formatItem: function(row, i, max, term) {
|
formatItem: function(row, i, max, term) {
|
||||||
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
||||||
},
|
},
|
||||||
formatResult: function(row) {
|
formatResult: function(row) {
|
||||||
return row.to;
|
return row.to;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
for (var idx = 0; ; ++idx) {
|
||||||
|
if ($("#id_relation_type" + idx).length == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
$("#id_relation_type" + idx).autocomplete(auto_relation_types, {
|
||||||
|
minChars: 0,
|
||||||
|
width: 310,
|
||||||
|
matchContains: true,
|
||||||
|
max: 50,
|
||||||
|
highlightItem: false,
|
||||||
|
formatItem: function(row, i, max, term) {
|
||||||
|
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
||||||
|
},
|
||||||
|
formatResult: function(row) {
|
||||||
|
return row.to;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
{/literal}
|
||||||
|
{if $issue}
|
||||||
|
{literal}
|
||||||
|
$("#id_relation_issue" + idx).autocomplete("{/literal}{url 'IDF_Views_Issue::autoCompleteIssueList', array($project.shortname, $issue.id)}{literal}", {
|
||||||
|
minChars: 0,
|
||||||
|
width: 310,
|
||||||
|
matchContains: true,
|
||||||
|
max: 10,
|
||||||
|
multiple: true,
|
||||||
|
delay: 500,
|
||||||
|
highlightItem: false,
|
||||||
|
formatItem: function(row, i, max, term) {
|
||||||
|
return row[1].replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row[0] + "</span>";
|
||||||
|
},
|
||||||
|
formatResult: function(row) {
|
||||||
|
return row[1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
{/literal}
|
||||||
|
{/if}
|
||||||
|
{literal}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
{/literal} //-->
|
{/literal} //-->
|
||||||
</script>
|
</script>
|
||||||
|
@@ -8,5 +8,25 @@
|
|||||||
|
|
||||||
{/block}
|
{/block}
|
||||||
{block context}
|
{block context}
|
||||||
<p><strong>{trans 'Found issues:'}</strong> {$issues.nb_items}</p>
|
{aurl 'open_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'open'), array('q' => $query)}
|
||||||
|
{aurl 'closed_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'closed'), array('q' => $query)}
|
||||||
|
{if $tag != null}
|
||||||
|
{aurl 'open_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'open'), array('q' => $query)}
|
||||||
|
{aurl 'closed_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'closed'), array('q' => $query)}
|
||||||
|
{/if}
|
||||||
|
{blocktrans}
|
||||||
|
<p><strong>Found open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||||
|
<p><strong>Found closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
||||||
|
{if $tag !== null}
|
||||||
|
{blocktrans}<p><strong>Label:</strong>
|
||||||
|
<a href="{$open_url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></p>{/blocktrans}
|
||||||
|
{else}
|
||||||
|
{* yes, this is duplicated from tags-cloud.html, but the code there cannot be easily overridden *}
|
||||||
|
<div id="tagscloud" class="smaller"><dl>{foreach $all_tags as $class => $labels}
|
||||||
|
<dt class="label">{$class}</dt>
|
||||||
|
{foreach $labels as $idx => $label}
|
||||||
|
{aurl 'url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $label.id, $status), array('q'=> $query)}
|
||||||
|
<dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
|
||||||
|
{/foreach}{/foreach}</dl></p>
|
||||||
|
{/if}
|
||||||
{/block}
|
{/block}
|
||||||
|
100
src/IDF/templates/idf/issues/summary.html
Normal file
100
src/IDF/templates/idf/issues/summary.html
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
{extends "idf/issues/base.html"}
|
||||||
|
|
||||||
|
{block docclass}yui-t2{assign $inSummaryIssues=true}{/block}
|
||||||
|
|
||||||
|
{block body}
|
||||||
|
{if $trackerEmpty}
|
||||||
|
{aurl 'create_url', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||||
|
<p>{blocktrans}The issue tracker is empty.<br />You can create your first issue <a href="{$create_url}">here</a>.{/blocktrans}</p>
|
||||||
|
{else}
|
||||||
|
<div class='issue-summary'>
|
||||||
|
{foreach $tagStatistics as $key => $class}
|
||||||
|
<div>
|
||||||
|
<h2>{blocktrans}Unresolved: By {$key}{/blocktrans}</h2>
|
||||||
|
<table class='issue-summary'>
|
||||||
|
<tbody>
|
||||||
|
{foreach $class as $key => $value}
|
||||||
|
<tr>
|
||||||
|
<td class="name"><a href="{url 'IDF_Views_Issue::listLabel', array($project.shortname, $value[2], 'open')}">{$key}</a></td>
|
||||||
|
<td class="count">{$value[0]}</td>
|
||||||
|
<td class="graph">
|
||||||
|
<table class='graph'>
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="width:{$value[1] * 0.8 + 1}%" class="graph-color" valign="center">
|
||||||
|
<div class="colour-bar"></div>
|
||||||
|
</td>
|
||||||
|
<td class="graph-percent">{$value[1]}%</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='issue-summary'>
|
||||||
|
{if $status}
|
||||||
|
<div>
|
||||||
|
<h2>{blocktrans}Status Summary{/blocktrans}</h2>
|
||||||
|
<table class='issue-summary'>
|
||||||
|
<tbody>
|
||||||
|
{foreach $status as $key => $value}
|
||||||
|
<tr>
|
||||||
|
<td class="name"><a href="{url 'IDF_Views_Issue::listStatus', array($project.shortname, $key)}">{$key}</a></td>
|
||||||
|
<td class="count">{$value[0]}</td>
|
||||||
|
<td class="graph">
|
||||||
|
<table class='graph'>
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="width:{$value[1] * 0.8 + 1}%" class="graph-color" valign="center">
|
||||||
|
<div class="colour-bar"></div>
|
||||||
|
</td>
|
||||||
|
<td class="graph-percent">{$value[1]}%</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{if $ownerStatistics}
|
||||||
|
<div>
|
||||||
|
<h2>{blocktrans}Unresolved: By Assignee{/blocktrans}</h2>
|
||||||
|
<table class='issue-summary'>
|
||||||
|
<tbody>
|
||||||
|
{foreach $ownerStatistics as $key => $value}
|
||||||
|
<tr>
|
||||||
|
<td class="name">
|
||||||
|
{if !empty($value[2])}
|
||||||
|
{aurl 'url', 'IDF_Views_Issue::userIssues', array($project.shortname, $value[2], 'owner')}
|
||||||
|
<a href="{$url}">{$key}</a>
|
||||||
|
{else}{$key}{/if}
|
||||||
|
</td>
|
||||||
|
<td class="count">{$value[0]}</td>
|
||||||
|
<td class="graph">
|
||||||
|
<table class='graph'>
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="width:{$value[1] * 0.8 + 1}%" class="graph-color" valign="center">
|
||||||
|
<div class="colour-bar"></div>
|
||||||
|
</td>
|
||||||
|
<td class="graph-percent">{$value[1]}%</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/block}
|
@@ -1,5 +1,5 @@
|
|||||||
{extends "idf/issues/base.html"}
|
{extends "idf/issues/base.html"}
|
||||||
{block docclass}yui-t2{assign $inMyIssues = true}{/block}
|
{block docclass}yui-t2{if $user.login == $login}{assign $inMyIssues = true}{/if}{/block}
|
||||||
{block body}
|
{block body}
|
||||||
{$issues.render}
|
{$issues.render}
|
||||||
{if !$user.isAnonymous()}
|
{if !$user.isAnonymous()}
|
||||||
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
{/block}
|
{/block}
|
||||||
{block context}
|
{block context}
|
||||||
{aurl 'owner_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'owner')}
|
{aurl 'owner_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'owner')}
|
||||||
{aurl 'submit_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}
|
{aurl 'submit_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'submit')}
|
||||||
{aurl 'owner_closed_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'ownerclosed')}
|
{aurl 'owner_closed_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'ownerclosed')}
|
||||||
{aurl 'submit_closed_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'submitclosed')}
|
{aurl 'submit_closed_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'submitclosed')}
|
||||||
<p><strong>{trans 'Submitted issues:'}</strong> <a href="{$submit_url}">{$nb_submit}</a>
|
<p><strong>{trans 'Submitted issues:'}</strong> <a href="{$submit_url}">{$nb_submit}</a>
|
||||||
{if $nb_submit_closed}<br /><span class="helptext">{blocktrans $nb_submit_closed}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{plural}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{/blocktrans}</span>{/if}</p>
|
{if $nb_submit_closed}<br /><span class="helptext">{blocktrans $nb_submit_closed}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{plural}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{/blocktrans}</span>{/if}</p>
|
||||||
{if $nb_owner > 0}
|
{if $nb_owner > 0}
|
@@ -17,7 +17,7 @@
|
|||||||
{assign $submitter_data = $c.get_submitter_data()}
|
{assign $submitter_data = $c.get_submitter_data()}
|
||||||
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}">
|
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}">
|
||||||
{if $submitter_data.avatar != ''}
|
{if $submitter_data.avatar != ''}
|
||||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
|
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$submitter_data.avatar}" alt=" " />
|
||||||
{else}
|
{else}
|
||||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
||||||
{/if}
|
{/if}
|
||||||
@@ -40,7 +40,16 @@
|
|||||||
{if $i> 0 and $c.changedIssue()}
|
{if $i> 0 and $c.changedIssue()}
|
||||||
<div class="issue-changes">
|
<div class="issue-changes">
|
||||||
{foreach $c.changes as $w => $v}
|
{foreach $c.changes as $w => $v}
|
||||||
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}</strong> {if $w == 'lb'}{assign $l = implode(', ', $v)}{$l}{else}{$v}{/if}<br />
|
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong>
|
||||||
|
{if $w == 'lb' or $w == 'rel'}
|
||||||
|
{foreach $v as $t => $ls}
|
||||||
|
{foreach $ls as $l}
|
||||||
|
{if $t == 'rem'}<s>{/if}{$l}{if $t == 'rem'}</s>{/if}
|
||||||
|
{/foreach}
|
||||||
|
{/foreach}
|
||||||
|
{else}
|
||||||
|
{$v}
|
||||||
|
{/if}<br />
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -120,6 +129,23 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>{$form.f.relation_type0.labelTag}:</th>
|
||||||
|
<td>
|
||||||
|
{assign $prevField}
|
||||||
|
{foreach $form as $field}
|
||||||
|
{if strpos($field.name, 'relation_type') === 0}
|
||||||
|
{$field|unsafe}
|
||||||
|
{assign $prevField = $field}
|
||||||
|
{/if}
|
||||||
|
{if strpos($field.name, 'relation_issue') === 0}
|
||||||
|
{$field|unsafe}<br />
|
||||||
|
{if $prevField.errors}{$prevField.fieldErrors}{/if}
|
||||||
|
{if $field.errors}{$field.fieldErrors}{/if}
|
||||||
|
{/if}
|
||||||
|
{/foreach}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<th>{$form.f.label1.labelTag}:</th>
|
<th>{$form.f.label1.labelTag}:</th>
|
||||||
<td>
|
<td>
|
||||||
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
||||||
@@ -161,6 +187,21 @@
|
|||||||
<span class="label"><a href="{$url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></span><br />
|
<span class="label"><a href="{$url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></span><br />
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</p>{/if}
|
</p>{/if}
|
||||||
|
{if count($related_issues) > 0}
|
||||||
|
{foreach $related_issues as $verb => $rel_issues}
|
||||||
|
<p>
|
||||||
|
<strong>{blocktrans}This issue {$verb}{/blocktrans}</strong><br />
|
||||||
|
{foreach $rel_issues as $rel_issue}
|
||||||
|
<span class="label">
|
||||||
|
<a href="{url 'IDF_Views_Issue::view', array($project.shortname, $rel_issue.other_issue)}"
|
||||||
|
class="label" title="{$rel_issue.other_summary}">
|
||||||
|
<strong>{$rel_issue.other_issue}</strong> - {$rel_issue.other_summary|shorten:30}
|
||||||
|
</a>
|
||||||
|
</span><br />
|
||||||
|
{/foreach}
|
||||||
|
</p>
|
||||||
|
{/foreach}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
{block javascript}{if $form}{include 'idf/issues/js-autocomplete.html'}
|
{block javascript}{if $form}{include 'idf/issues/js-autocomplete.html'}
|
||||||
|
@@ -10,8 +10,8 @@
|
|||||||
{if $hasWikiAccess}{hotkey 'Shift+o', 'IDF_Views_Wiki::index', array($project.shortname)}{/if}
|
{if $hasWikiAccess}{hotkey 'Shift+o', 'IDF_Views_Wiki::index', array($project.shortname)}{/if}
|
||||||
{if $hasSourceAccess}{hotkey 'Shift+s', 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}{/if}
|
{if $hasSourceAccess}{hotkey 'Shift+s', 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}{/if}
|
||||||
{if $hasIssuesAccess and !$user.isAnonymous()}
|
{if $hasIssuesAccess and !$user.isAnonymous()}
|
||||||
{hotkey 'Shift+m', 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}
|
{hotkey 'Shift+m', 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'submit')}
|
||||||
{hotkey 'Shift+w', 'IDF_Views_Issue::myIssues', array($project.shortname, 'owner')}
|
{hotkey 'Shift+w', 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'owner')}
|
||||||
{/if}{/if} //-->
|
{/if}{/if} //-->
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<div id="sub-tabs">
|
<div id="sub-tabs">
|
||||||
<a {if $inOpenReviews}class="active" {/if}href="{url 'IDF_Views_Review::index', array($project.shortname)}">{trans 'Open Reviews'}</a> {*
|
<a {if $inOpenReviews}class="active" {/if}href="{url 'IDF_Views_Review::index', array($project.shortname)}">{trans 'Open Reviews'}</a> {*
|
||||||
|
|
||||||
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a>{/if} |
|
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'submit')}">{trans 'My Issues'}</a>{/if} |
|
||||||
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
|
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
|
||||||
<input accesskey="4" type="text" value="{$q}" name="q" size="20" />
|
<input accesskey="4" type="text" value="{$q}" name="q" size="20" />
|
||||||
<input type="submit" name="s" value="{trans 'Search'}" />
|
<input type="submit" name="s" value="{trans 'Search'}" />
|
||||||
|
@@ -5,17 +5,4 @@
|
|||||||
{if !$user.isAnonymous()}
|
{if !$user.isAnonymous()}
|
||||||
{aurl 'url', 'IDF_Views_Review::create', array($project.shortname)}
|
{aurl 'url', 'IDF_Views_Review::create', array($project.shortname)}
|
||||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'Start Code Review'}</a></p>{/if}
|
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'Start Code Review'}</a></p>{/if}
|
||||||
|
|
||||||
{/block}
|
{/block}
|
||||||
{block context}
|
|
||||||
{*
|
|
||||||
{aurl 'open_url', 'IDF_Views_Issue::index', array($project.shortname)}
|
|
||||||
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
|
|
||||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
|
||||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
|
||||||
{assign $class = ''}{assign $i = 0}
|
|
||||||
<p class="smaller">{foreach $project.getTagCloud($cloud) as $label}
|
|
||||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
|
||||||
{if $class != $label.class}{if $i != 0}<br />{/if}<strong class="label">{$label.class}:</strong> {/if}
|
|
||||||
<a href="{$url}" class="label">{$label.name}</a>,{assign $class = $label.class}{assign $i = $i + 1}{/foreach}</p>
|
|
||||||
*}{/block}
|
|
||||||
|
@@ -10,8 +10,26 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<table class="disp" summary="">
|
{if !$user.isAnonymous()}
|
||||||
<tr><td>
|
<div class="issue-submit-info" style="width: 50%; float: right; position: relative;">
|
||||||
|
<p><strong>{trans 'How to Participate in a Code Review'}</strong></p>
|
||||||
|
|
||||||
|
<p>{blocktrans}Code review is a process in which
|
||||||
|
after or before changes are commited into the code repository,
|
||||||
|
different people discuss the code changes. The goal is
|
||||||
|
to <strong>improve the quality of the code and the
|
||||||
|
contributions</strong>, as such, you must be pragmatic when writing
|
||||||
|
your review. Correctly mention the line numbers (in the old or in the
|
||||||
|
new file) and try to keep a good balance between seriousness and fun.
|
||||||
|
{/blocktrans}</p>
|
||||||
|
<p>{blocktrans}
|
||||||
|
<strong>Proposing code for review is intimidating</strong>, you know
|
||||||
|
you will receive critics, so please, as a reviewer, <strong>keep this
|
||||||
|
process fun</strong>, use it to help your contributor learn your
|
||||||
|
coding standards and the structure of the code and <strong>make them want
|
||||||
|
to propose more contributions</strong>.
|
||||||
|
{/blocktrans}</p></div>
|
||||||
|
{/if}
|
||||||
<table class="commit" summary="">
|
<table class="commit" summary="">
|
||||||
<tr>
|
<tr>
|
||||||
<th><strong>{trans 'Created:'}</strong></th><td>{$patch.creation_dtime|date:"%Y-%m-%d %H:%M:%S"} ({$patch.creation_dtime|dateago})</td>
|
<th><strong>{trans 'Created:'}</strong></th><td>{$patch.creation_dtime|date:"%Y-%m-%d %H:%M:%S"} ({$patch.creation_dtime|dateago})</td>
|
||||||
@@ -45,39 +63,12 @@
|
|||||||
<th> </th><td><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/package-grey.png'}" alt="{trans 'Archive'}" align="bottom" /></a> <a href="{$url}" class="soft">{trans 'Download the corresponding diff file'}</a></td>
|
<th> </th><td><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/package-grey.png'}" alt="{trans 'Archive'}" align="bottom" /></a> <a href="{$url}" class="soft">{trans 'Download the corresponding diff file'}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</td><td>
|
|
||||||
{if !$user.isAnonymous()}
|
|
||||||
<div class="issue-submit-info" style="width: 90%; float: right; position: relative;">
|
|
||||||
<p><strong>{trans 'How to Participate in a Code Review'}</strong></p>
|
|
||||||
|
|
||||||
<p>{blocktrans}Code review is a process in which
|
|
||||||
after or before changes are commited into the code repository,
|
|
||||||
different people discuss the code changes. The goal is
|
|
||||||
to <strong>improve the quality of the code and the
|
|
||||||
contributions</strong>, as such, you must be pragmatic when writing
|
|
||||||
your review. Correctly mention the line numbers (in the old or in the
|
|
||||||
new file) and try to keep a good balance between seriousness and fun.
|
|
||||||
{/blocktrans}</p>
|
|
||||||
<p>{blocktrans}
|
|
||||||
<strong>Proposing code for review is intimidating</strong>, you know
|
|
||||||
you will receive critics, so please, as a reviewer, <strong>keep this
|
|
||||||
process fun</strong>, use it to help your contributor learn your
|
|
||||||
coding standards and the structure of the code and <strong>make them want
|
|
||||||
to propose more contributions</strong>.
|
|
||||||
{/blocktrans}</p></div>
|
|
||||||
{/if}
|
|
||||||
</td></tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<form method="post" action=".">
|
<form method="post" action=".">
|
||||||
{foreach $files as $file=>$def}
|
{foreach $files as $file=>$def}
|
||||||
<table class="diff" summary=" ">
|
|
||||||
<tbody>
|
{$def[0]}
|
||||||
<tr id="diff-{$file|md5}"><th colspan="4">{$file}</th></tr>
|
|
||||||
<tr><th colspan="2">{trans 'Old'}</th><th colspan="2">{trans 'New'}</th></tr>
|
|
||||||
{$def[0]}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{assign $fcomments = $def[2]}
|
{assign $fcomments = $def[2]}
|
||||||
{assign $nc = $fcomments.count()}
|
{assign $nc = $fcomments.count()}
|
||||||
{assign $i = 1}
|
{assign $i = 1}
|
||||||
@@ -109,7 +100,7 @@ to propose more contributions</strong>.
|
|||||||
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $submitter = $c.get_submitter()}{assign $submitter_data = $c.get_submitter_data()}
|
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $submitter = $c.get_submitter()}{assign $submitter_data = $c.get_submitter_data()}
|
||||||
<div class="issue-comment{if $i == 1} issue-comment-first{/if}{if $i == ($nc)} issue-comment-last{/if}" id="ic{$c.id}">
|
<div class="issue-comment{if $i == 1} issue-comment-first{/if}{if $i == ($nc)} issue-comment-last{/if}" id="ic{$c.id}">
|
||||||
{if $submitter_data.avatar != ''}
|
{if $submitter_data.avatar != ''}
|
||||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
|
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$submitter_data.avatar}" alt=" " />
|
||||||
{else}
|
{else}
|
||||||
<img style="float:right; position: relative;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
<img style="float:right; position: relative;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -34,6 +34,9 @@
|
|||||||
{foreach $changes.renames as $oldname => $newname}
|
{foreach $changes.renames as $oldname => $newname}
|
||||||
<tr><td><span class="scm-action renamed" title="{trans 'renamed'}">R</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $newname)}">{$oldname} → {$newname}</a></td></tr>
|
<tr><td><span class="scm-action renamed" title="{trans 'renamed'}">R</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $newname)}">{$oldname} → {$newname}</a></td></tr>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
|
{foreach $changes.copies as $srcname => $destname}
|
||||||
|
<tr><td><span class="scm-action copied" title="{trans 'copied'}">C</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $destname)}">{$srcname} → {$destname}</a></td></tr>
|
||||||
|
{/foreach}
|
||||||
{foreach $changes.additions as $filename}
|
{foreach $changes.additions as $filename}
|
||||||
<tr><td><span class="scm-action added" title="{trans 'added'}">A</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
|
<tr><td><span class="scm-action added" title="{trans 'added'}">A</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
|
2
src/IDF/templates/idf/source/git/invalid_revision.html
Normal file
2
src/IDF/templates/idf/source/git/invalid_revision.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{extends "idf/source/invalid_revision.html"}
|
||||||
|
|
@@ -5,6 +5,7 @@
|
|||||||
<p>{blocktrans}The branch or revision <b>{$commit}</b> is not valid or does not exist
|
<p>{blocktrans}The branch or revision <b>{$commit}</b> is not valid or does not exist
|
||||||
in this repository.{/blocktrans}</p>
|
in this repository.{/blocktrans}</p>
|
||||||
|
|
||||||
|
{if count($branches) > 0}
|
||||||
<p>{blocktrans}The following list shows all available branches:{/blocktrans}</p>
|
<p>{blocktrans}The following list shows all available branches:{/blocktrans}</p>
|
||||||
<ul>
|
<ul>
|
||||||
{foreach $branches as $branch => $path}
|
{foreach $branches as $branch => $path}
|
||||||
@@ -14,6 +15,7 @@ in this repository.{/blocktrans}</p>
|
|||||||
</li>
|
</li>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</ul>
|
</ul>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{if $isOwner or $isMember}
|
{if $isOwner or $isMember}
|
||||||
{aurl 'url', 'IDF_Views_Source::help', array($project.shortname)}
|
{aurl 'url', 'IDF_Views_Source::help', array($project.shortname)}
|
||||||
|
@@ -0,0 +1,2 @@
|
|||||||
|
{extends "idf/source/invalid_revision.html"}
|
||||||
|
|
@@ -5,12 +5,25 @@
|
|||||||
<h2 class="top"><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}">{trans 'Root'}</a><span class="sep">/</span>{if $breadcrumb}{$breadcrumb|safe}{/if}</h2>
|
<h2 class="top"><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}">{trans 'Root'}</a><span class="sep">/</span>{if $breadcrumb}{$breadcrumb|safe}{/if}</h2>
|
||||||
|
|
||||||
<table class="code" summary=" ">
|
<table class="code" summary=" ">
|
||||||
{if !$tree_in and !$tags_in}
|
{if (!$tree_in and !$tags_in) or $props}
|
||||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr><th colspan="2">{blocktrans}Source at commit <a class="mono" href="{$url}">{$commit}</a> created {$cobject.date|dateago}.{/blocktrans}<br/>
|
{if $props}
|
||||||
<span class="smaller">{blocktrans}By {$cobject.author|strip_tags|trim}, {$cobject.title}{/blocktrans}</span>
|
<tr><th colspan="2">
|
||||||
</th></tr>
|
<ul>
|
||||||
|
{foreach $props as $prop => $val}
|
||||||
|
<li>{blocktrans}Property <strong>{$prop}</strong> set to <em>{$val}</em>{/blocktrans}</li>
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
</th></tr>
|
||||||
|
{/if}
|
||||||
|
{if !$tree_in and !$tags_in}
|
||||||
|
<tr>
|
||||||
|
<th colspan="2">{blocktrans}Source at commit <a class="mono" href="{$url}">{$commit}</a> created {$cobject.date|dateago}.{/blocktrans}<br/>
|
||||||
|
<span class="smaller">{blocktrans}By {$cobject.author|strip_tags|trim}, {$cobject.title}{/blocktrans}</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
{/if}
|
||||||
</tfoot>
|
</tfoot>
|
||||||
{/if}
|
{/if}
|
||||||
<tbody>
|
<tbody>
|
||||||
|
2
src/IDF/templates/idf/source/mtn/invalid_revision.html
Normal file
2
src/IDF/templates/idf/source/mtn/invalid_revision.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{extends "idf/source/invalid_revision.html"}
|
||||||
|
|
@@ -11,14 +11,27 @@
|
|||||||
<th>{trans 'Message'}</th>
|
<th>{trans 'Message'}</th>
|
||||||
<th>{trans 'Size'}</th>
|
<th>{trans 'Size'}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>{if !$tree_in and !$tags_in}
|
</thead>
|
||||||
|
{if (!$tree_in and !$tags_in) or $props}
|
||||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr><th colspan="5">{blocktrans}Source at commit <a class="mono" href="{$url}">{$commit}</a> created {$cobject.date|dateago}.{/blocktrans}<br/>
|
{if $props}
|
||||||
<span class="smaller">{blocktrans}By {$cobject.author|strip_tags|trim}, {$cobject.title}{/blocktrans}</span>
|
<tr><th colspan="5">
|
||||||
</th></tr>
|
<ul>
|
||||||
|
{foreach $props as $prop => $val}
|
||||||
|
<li>{blocktrans}Property <strong>{$prop}</strong> set to <em>{$val}</em>{/blocktrans}</li>
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
</th></tr>
|
||||||
|
{/if}
|
||||||
|
{if !$tree_in and !$tags_in}
|
||||||
|
<tr><th colspan="5">{blocktrans}Source at commit <a class="mono" href="{$url}">{$commit}</a> created {$cobject.date|dateago}.{/blocktrans}<br/>
|
||||||
|
<span class="smaller">{blocktrans}By {$cobject.author|strip_tags|trim}, {$cobject.title}{/blocktrans}</span>
|
||||||
|
</th></tr>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
</tfoot>
|
</tfoot>
|
||||||
{/if}<tbody>
|
<tbody>
|
||||||
{if $base}
|
{if $base}
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<p><strong>{trans 'Revision:'}</strong> {$commit}</p>
|
<p><strong>{trans 'Revision:'}</strong> {$commit}</p>
|
||||||
<p>
|
<p>
|
||||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
||||||
<input type="submit" name="s" value="{trans 'Go to revision'}" />
|
<input type="submit" name="s" value="{trans 'Switch'}" />
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
{/block}
|
{/block}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<p><strong>{trans 'Revision:'}</strong> {$commit}</p>
|
<p><strong>{trans 'Revision:'}</strong> {$commit}</p>
|
||||||
<p>
|
<p>
|
||||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5"/>
|
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5"/>
|
||||||
<input type="submit" name="s" value="{trans 'Go to revision'}"/>
|
<input type="submit" name="s" value="{trans 'Switch'}"/>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
{/block}
|
{/block}
|
||||||
|
@@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
<table class="code" summary=" ">
|
<table class="code" summary=" ">
|
||||||
{if !$tree_in || $props}
|
{if !$tree_in || $props}
|
||||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
{if $props}
|
{if $props}
|
||||||
<tr><th colspan="2">
|
<tr><th colspan="2">
|
||||||
<ul>
|
<ul>
|
||||||
{foreach $props as $prop => $val}
|
{foreach $props as $prop => $val}
|
||||||
<li>{trans 'Property'} <strong>{$prop}</strong> {trans 'set to:'} <em>{$val}</em></li>
|
<li>{blocktrans}Property <strong>{$prop}</strong> set to <em>{$val}</em>{/blocktrans}</li>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</ul>
|
</ul>
|
||||||
</th></tr>
|
</th></tr>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<p>
|
<p>
|
||||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
||||||
<input type="hidden" name="sourcefile" value="{$base}"/>
|
<input type="hidden" name="sourcefile" value="{$base}"/>
|
||||||
<input type="submit" name="s" value="{trans 'Go to revision'}" /></p>
|
<input type="submit" name="s" value="{trans 'Switch'}" /></p>
|
||||||
</form>
|
</form>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
|
30
src/IDF/templates/idf/source/svn/invalid_revision.html
Normal file
30
src/IDF/templates/idf/source/svn/invalid_revision.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{extends "idf/source/base.html"}
|
||||||
|
{block docclass}yui-t2{assign $inError=true}{/block}
|
||||||
|
{block body}
|
||||||
|
|
||||||
|
<p>{blocktrans}The revision <b>{$commit}</b> is not valid or does not exist
|
||||||
|
in this repository.{/blocktrans}</p>
|
||||||
|
|
||||||
|
{if count($branches) > 0}
|
||||||
|
<p>{blocktrans}The following list shows all available branches:{/blocktrans}</p>
|
||||||
|
<ul>
|
||||||
|
{foreach $branches as $branch => $path}
|
||||||
|
{if $path}{aurl 'url', 'IDF_Views_Source::tree', array($project.shortname, 'HEAD', $path)}
|
||||||
|
{else}{aurl 'url', 'IDF_Views_Source::treeBase', array($project.shortname, 'HEAD')}{/if}
|
||||||
|
<li class="label">
|
||||||
|
<a href="{$url}" class="label">{$branch}</a>
|
||||||
|
</li>
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{if $isOwner or $isMember}
|
||||||
|
{aurl 'url', 'IDF_Views_Source::help', array($project.shortname)}
|
||||||
|
<p>{blocktrans}If this is a new repository, the reason for this error
|
||||||
|
could be that you have not committed and / or pushed any change so far.
|
||||||
|
In this case please take a look at the <a href="{$url}">Help</a> page
|
||||||
|
how to access your repository.{/blocktrans}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{/block}
|
||||||
|
|
@@ -13,13 +13,13 @@
|
|||||||
<th>{trans 'Size'}</th>
|
<th>{trans 'Size'}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>{if (!$tree_in and !$tags_in and $commit != 'HEAD') || $props}
|
</thead>{if (!$tree_in and !$tags_in and $commit != 'HEAD') || $props}
|
||||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
||||||
<tfoot>
|
<tfoot>
|
||||||
{if $props}
|
{if $props}
|
||||||
<tr><th colspan="6">
|
<tr><th colspan="6">
|
||||||
<ul>
|
<ul>
|
||||||
{foreach $props as $prop => $val}
|
{foreach $props as $prop => $val}
|
||||||
<li>{trans 'Property'} <strong>{$prop}</strong> {trans 'set to:'} <em>{$val}</em></li>
|
<li>{blocktrans}Property <strong>{$prop}</strong> set to <em>{$val}</em>{/blocktrans}</li>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</ul>
|
</ul>
|
||||||
</th></tr>
|
</th></tr>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<td class="fileicon"><img src="{media '/idf/img/'~$file.type~'.png'}" alt="{$file.type}" /></td>
|
<td class="fileicon"><img src="{media '/idf/img/'~$file.type~'.png'}" alt="{$file.type}" /></td>
|
||||||
|
|
||||||
<td><a href="{$url}">{$file.file}</a></td>
|
<td><a href="{$url}">{$file.file}</a></td>
|
||||||
<td><span class="smaller">{$file.date|dateago:"without"}</span></td>
|
<td><span class="smaller">{$file.date|dateago:"without"}</span></td>
|
||||||
<td>{$file.rev}</td>
|
<td>{$file.rev}</td>
|
||||||
<td{if $file.type != 'blob'} colspan="2"{/if}><span class="smaller">{$file.author|strip_tags|trim}{trans ':'} {issuetext $file.log, $request, true, false}</span></td>
|
<td{if $file.type != 'blob'} colspan="2"{/if}><span class="smaller">{$file.author|strip_tags|trim}{trans ':'} {issuetext $file.log, $request, true, false}</span></td>
|
||||||
{if $file.type == 'blob'}
|
{if $file.type == 'blob'}
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
<p>
|
<p>
|
||||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
||||||
<input type="hidden" name="sourcefile" value="{$base}"/>
|
<input type="hidden" name="sourcefile" value="{$base}"/>
|
||||||
<input type="submit" name="s" value="{trans 'Go to revision'}" /></p>
|
<input type="submit" name="s" value="{trans 'Switch'}" /></p>
|
||||||
</form>
|
</form>
|
||||||
<p><strong>{trans 'Branches:'}</strong><br />
|
<p><strong>{trans 'Branches:'}</strong><br />
|
||||||
{foreach $branches as $branch => $path}
|
{foreach $branches as $branch => $path}
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
{assign $class = ''}{assign $i = 0}
|
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $class => $labels}
|
||||||
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $label}
|
<dt class="label">{$class}</dt>
|
||||||
|
{foreach $labels as $idx => $label}
|
||||||
{aurl 'url', $cloud_url, array($project.shortname, $label.id, 'open')}
|
{aurl 'url', $cloud_url, array($project.shortname, $label.id, 'open')}
|
||||||
{if $class != $label.class}<dt class="label">{$label.class}</dt>{assign $i = 0}{/if}
|
<dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
|
||||||
<dd><a href="{$url}" class="label">{$label.name},</a></dd>
|
{/foreach}{/foreach}</dl></p>
|
||||||
{assign $class = $label.class}
|
|
||||||
{assign $i = $i + 1}
|
|
||||||
{/foreach}</dl></p>
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
<table class="form" summary="">
|
<table class="form" summary="">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="text-align: right">{if $user_data.avatar != ''}
|
<th style="text-align: right">{if $user_data.avatar != ''}
|
||||||
<img style="max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$user_data.avatar}" alt=" " />
|
<img style="max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$user_data.avatar}" alt=" " />
|
||||||
{else}
|
{else}
|
||||||
<img src="http://www.gravatar.com/avatar/{$member.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
<img src="http://www.gravatar.com/avatar/{$member.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
{extends "idf/wiki/base.html"}
|
{extends "idf/wiki/base.html"}
|
||||||
{block extraheader}{if $oldrev}<meta name="ROBOTS" content="NOINDEX" />{/if}{/block}
|
|
||||||
|
{block extraheader}
|
||||||
|
{if $oldrev}<meta name="ROBOTS" content="NOINDEX" />{/if}
|
||||||
|
<link rel="stylesheet" type="text/css" media="print" href="{media '/idf/css/print-wiki.css'}" />
|
||||||
|
{/block}
|
||||||
|
|
||||||
{block docclass}yui-t3{assign $inView=true}{/block}
|
{block docclass}yui-t3{assign $inView=true}{/block}
|
||||||
|
|
||||||
{block body}
|
{block body}
|
||||||
|
@@ -38,11 +38,9 @@ class IDF_DiffTest extends PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
$expectedfile = str_replace('.diff', '.expected', $difffile);
|
$expectedfile = str_replace('.diff', '.expected', $difffile);
|
||||||
$expectedcontent = @file_get_contents($expectedfile);
|
|
||||||
|
|
||||||
$diffcontent = file_get_contents($difffile);
|
$diffcontent = file_get_contents($difffile);
|
||||||
$diff = new IDF_Diff($diffcontent, $diffprefix);
|
$diff = new IDF_Diff($diffcontent, $diffprefix);
|
||||||
$this->assertEquals(unserialize($expectedcontent),
|
$this->assertEquals(require_once($expectedfile),
|
||||||
$diff->parse(),
|
$diff->parse(),
|
||||||
'parsed diff '.$difffile.' does not match');
|
'parsed diff '.$difffile.' does not match');
|
||||||
}
|
}
|
||||||
|
90
test/IDF/ProjectTest.php
Normal file
90
test/IDF/ProjectTest.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero 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 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
class IDF_ProjectTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testGetIssueCountByOwner()
|
||||||
|
{
|
||||||
|
// Add users
|
||||||
|
$user1 = new Pluf_User();
|
||||||
|
$user1->login = 'user1';
|
||||||
|
$user1->create();
|
||||||
|
$user2 = new Pluf_User();
|
||||||
|
$user2->login = 'user2';
|
||||||
|
$user2->create();
|
||||||
|
|
||||||
|
// Add a project
|
||||||
|
$prj = new IDF_Project();
|
||||||
|
$prj->create();
|
||||||
|
$tag = $prj->getTagIdsByStatus('open');
|
||||||
|
|
||||||
|
// First test with no issue
|
||||||
|
$stats = $prj->getIssueCountByOwner();
|
||||||
|
$this->assertEquals($stats, array());
|
||||||
|
|
||||||
|
// Add some issues
|
||||||
|
$issue1 = new IDF_Issue();
|
||||||
|
$issue1->project = $prj;
|
||||||
|
$issue1->submitter = $user1;
|
||||||
|
$issue1->owner = $user1;
|
||||||
|
$issue1->status = new IDF_Tag($tag[0]);
|
||||||
|
$issue1->create();
|
||||||
|
|
||||||
|
$issue2 = new IDF_Issue();
|
||||||
|
$issue2->project = $prj;
|
||||||
|
$issue2->submitter = $user2;
|
||||||
|
$issue2->owner = $user1;
|
||||||
|
$issue2->status = new IDF_Tag($tag[0]);
|
||||||
|
$issue2->create();
|
||||||
|
|
||||||
|
$issue3 = new IDF_Issue();
|
||||||
|
$issue3->project = $prj;
|
||||||
|
$issue3->submitter = $user2;
|
||||||
|
$issue3->status = new IDF_Tag($tag[0]);
|
||||||
|
$issue3->create();
|
||||||
|
|
||||||
|
$issue4 = new IDF_Issue();
|
||||||
|
$issue4->project = $prj;
|
||||||
|
$issue4->submitter = $user2;
|
||||||
|
$issue4->owner = $user2;
|
||||||
|
$issue4->status = new IDF_Tag($tag[0]);
|
||||||
|
$issue4->create();
|
||||||
|
|
||||||
|
// 2nd test
|
||||||
|
$stats = $prj->getIssueCountByOwner();
|
||||||
|
$expected = array(0 => 1,
|
||||||
|
$user2->id => 1,
|
||||||
|
$user1->id => 2);
|
||||||
|
$this->assertEquals($stats, $expected);
|
||||||
|
|
||||||
|
// Clean DB
|
||||||
|
$issue4->delete();
|
||||||
|
$issue3->delete();
|
||||||
|
$issue2->delete();
|
||||||
|
$issue1->delete();
|
||||||
|
$prj->delete();
|
||||||
|
$user2->delete();
|
||||||
|
$user1->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -625,6 +625,7 @@ END;
|
|||||||
'additions' => array('new_dir', 'new_dir/new_file'),
|
'additions' => array('new_dir', 'new_dir/new_file'),
|
||||||
'deletions' => array('old_dir', 'old_dir/old_file'),
|
'deletions' => array('old_dir', 'old_dir/old_file'),
|
||||||
'renames' => array('dir_with_old_name' => 'new_dir/dir_with_new_name'),
|
'renames' => array('dir_with_old_name' => 'new_dir/dir_with_new_name'),
|
||||||
|
'copies' => array(), // this is always empty
|
||||||
'patches' => array('existing_file'),
|
'patches' => array('existing_file'),
|
||||||
'properties' => array(
|
'properties' => array(
|
||||||
'new_dir/dir_with_new_name' => array(
|
'new_dir/dir_with_new_name' => array(
|
||||||
@@ -714,6 +715,31 @@ END;
|
|||||||
$this->assertEquals('', $commit->diff);
|
$this->assertEquals('', $commit->diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetProperties()
|
||||||
|
{
|
||||||
|
$rev = "2345678901234567890123456789012345678901";
|
||||||
|
|
||||||
|
$instance = $this->createMock();
|
||||||
|
$instance->getStdio()->setExpectedOutput(array('interface_version'), array(), '13.1');
|
||||||
|
|
||||||
|
$stdio =<<<END
|
||||||
|
attr "foo" "bar"
|
||||||
|
state "unchanged"
|
||||||
|
|
||||||
|
attr "some new
|
||||||
|
line" "and more <weird>-
|
||||||
|
nesses"
|
||||||
|
END;
|
||||||
|
$instance->getStdio()->setExpectedOutput(array('get_attributes', 'foo'), array('r' => $rev), $stdio);
|
||||||
|
$res = $instance->getProperties($rev, 'foo');
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($res));
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'foo' => 'bar',
|
||||||
|
"some new\nline" => "and more <weird>-\nnesses"
|
||||||
|
), $res);
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetExtraProperties()
|
public function testGetExtraProperties()
|
||||||
{
|
{
|
||||||
$instance = $this->createMock();
|
$instance = $this->createMock();
|
||||||
|
55
test/IDF/Scm/SvnTest.php
Normal file
55
test/IDF/Scm/SvnTest.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero 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 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
class IDF_Scm_SvnTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
private $proj = null;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->proj = new IDF_Project();
|
||||||
|
$this->proj->id = 1;
|
||||||
|
$this->proj->name = $this->proj->shortname = 'test';
|
||||||
|
$this->proj->create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
$this->proj->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createMock($reponame)
|
||||||
|
{
|
||||||
|
$repourl = 'file://'.DATADIR.'/'.__CLASS__.'/'.$reponame;
|
||||||
|
$instance = new IDF_Scm_Svn($repourl, $this->proj);
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAccessHistoryOfRenamedAndDeletedFiles()
|
||||||
|
{
|
||||||
|
$instance = $this->createMock(__FUNCTION__);
|
||||||
|
$this->assertEquals('new-file', $instance->getPathInfo('new-file', 1)->fullpath);
|
||||||
|
$this->assertEquals('alternate-name', $instance->getPathInfo('alternate-name', 2)->fullpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -21,7 +21,7 @@ if (file_exists($testconfig['db_database'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
echo ">>> creating empty test database...\n";
|
echo ">>> creating empty test database...\n";
|
||||||
passthru('php ' . PLUF_PATH . '/migrate.php --conf=' . TESTDIR . '/config.php -a -i');
|
passthru('php ' . escapeshellarg(PLUF_PATH.'/migrate.php') . ' --conf=' . escapeshellarg(TESTDIR.'/config.php').' -a -i');
|
||||||
|
|
||||||
echo ">>> setting up web application...\n";
|
echo ">>> setting up web application...\n";
|
||||||
require 'Pluf.php';
|
require 'Pluf.php';
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -15,375 +15,10 @@ Index: LinuxBIOSv1/src/include/cpu/i786/cpufixup.h
|
|||||||
+
|
+
|
||||||
+
|
+
|
||||||
|
|
||||||
Eigenschafts<EFBFBD>nderungen: LinuxBIOSv1\src\include\cpu\i786\cpufixup.h
|
Eigenschafts<EFBFBD>nderungen: LinuxBIOSv1\src\include\cpu\i786\cpufixup.h
|
||||||
___________________________________________________________________
|
___________________________________________________________________
|
||||||
Hinzugef<EFBFBD>gt: svn:keywords
|
Hinzugef<EFBFBD>gt: svn:keywords
|
||||||
+ Author Date Id Revision
|
+ Author Date Id Revision
|
||||||
Hinzugef<EFBFBD>gt: svn:eol-style
|
Hinzugef<EFBFBD>gt: svn:eol-style
|
||||||
+ native
|
|
||||||
|
|
||||||
Index: LinuxBIOSv1/src/mainboard/tyan/guiness/cmos.layout
|
|
||||||
===================================================================
|
|
||||||
--- LinuxBIOSv1/src/mainboard/tyan/guiness/cmos.layout (Revision 0)
|
|
||||||
+++ LinuxBIOSv1/src/mainboard/tyan/guiness/cmos.layout (Revision 665)
|
|
||||||
@@ -0,0 +1,63 @@
|
|
||||||
+entries
|
|
||||||
+
|
|
||||||
+#start-bit length config config-ID name
|
|
||||||
+#0 8 r 0 seconds
|
|
||||||
+#8 8 r 0 alarm_seconds
|
|
||||||
+#16 8 r 0 minutes
|
|
||||||
+#24 8 r 0 alarm_minutes
|
|
||||||
+#32 8 r 0 hours
|
|
||||||
+#40 8 r 0 alarm_hours
|
|
||||||
+#48 8 r 0 day_of_week
|
|
||||||
+#56 8 r 0 day_of_month
|
|
||||||
+#64 8 r 0 month
|
|
||||||
+#72 8 r 0 year
|
|
||||||
+#80 4 r 0 rate_select
|
|
||||||
+#84 3 r 0 REF_Clock
|
|
||||||
+#87 1 r 0 UIP
|
|
||||||
+#88 1 r 0 auto_switch_DST
|
|
||||||
+#89 1 r 0 24_hour_mode
|
|
||||||
+#90 1 r 0 binary_values_enable
|
|
||||||
+#91 1 r 0 square-wave_out_enable
|
|
||||||
+#92 1 r 0 update_finished_enable
|
|
||||||
+#93 1 r 0 alarm_interrupt_enable
|
|
||||||
+#94 1 r 0 periodic_interrupt_enable
|
|
||||||
+#95 1 r 0 disable_clock_updates
|
|
||||||
+#96 288 r 0 temporary_filler
|
|
||||||
+0 384 r 0 reserved_memory
|
|
||||||
+384 1 e 4 boot_option
|
|
||||||
+385 1 e 4 last_boot
|
|
||||||
+386 3 e 5 baud_rate
|
|
||||||
+392 4 e 6 debug_level
|
|
||||||
+396 1 e 1 power_on_after_fail
|
|
||||||
+#401 1 e 1 ECC_memory
|
|
||||||
+#402 1 e 2 hda_disk
|
|
||||||
+#403 1 e 2 hdb_disk
|
|
||||||
+#404 1 e 2 hdc_disk
|
|
||||||
+#405 1 e 2 hdd_disk
|
|
||||||
+#406 2 e 7 boot_device
|
|
||||||
+
|
|
||||||
+enumerations
|
|
||||||
+
|
|
||||||
+#ID value text
|
|
||||||
+1 0 Disable
|
|
||||||
+1 1 Enable
|
|
||||||
+#2 0 No
|
|
||||||
+#2 1 Yes
|
|
||||||
+4 0 Fallback
|
|
||||||
+4 1 Normal
|
|
||||||
+5 0 115200
|
|
||||||
+5 1 57600
|
|
||||||
+5 2 38400
|
|
||||||
+5 3 19200
|
|
||||||
+5 4 9600
|
|
||||||
+5 5 4800
|
|
||||||
+5 6 2400
|
|
||||||
+5 7 1200
|
|
||||||
+6 6 Notice
|
|
||||||
+6 7 Info
|
|
||||||
+6 8 Debug
|
|
||||||
+6 9 Spew
|
|
||||||
+#7 0 Network
|
|
||||||
+#7 1 HDD
|
|
||||||
+#7 2 Floppy
|
|
||||||
+#7 3 ROM
|
|
||||||
|
|
||||||
Eigenschafts<EFBFBD>nderungen: LinuxBIOSv1\src\mainboard\tyan\guiness\cmos.layout
|
|
||||||
___________________________________________________________________
|
|
||||||
Hinzugef<EFBFBD>gt: svn:keywords
|
|
||||||
+ Author Date Id Revision
|
|
||||||
Hinzugef<EFBFBD>gt: svn:eol-style
|
|
||||||
+ native
|
|
||||||
|
|
||||||
Index: LinuxBIOSv1/src/config/linuxbios_c.ld
|
|
||||||
===================================================================
|
|
||||||
--- LinuxBIOSv1/src/config/linuxbios_c.ld (Revision 0)
|
|
||||||
+++ LinuxBIOSv1/src/config/linuxbios_c.ld (Revision 665)
|
|
||||||
@@ -0,0 +1,105 @@
|
|
||||||
+/*
|
|
||||||
+ * Memory map:
|
|
||||||
+ *
|
|
||||||
+ * _RAMBASE
|
|
||||||
+ * : data segment
|
|
||||||
+ * : bss segment
|
|
||||||
+ * : heap
|
|
||||||
+ * : stack
|
|
||||||
+ */
|
|
||||||
+/*
|
|
||||||
+ * Bootstrap code for the STPC Consumer
|
|
||||||
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
|
|
||||||
+ *
|
|
||||||
+ * $Id$
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Written by Johan Rydberg, based on work by Daniel Kahlin.
|
|
||||||
+ * Rewritten by Eric Biederman
|
|
||||||
+ */
|
|
||||||
+/*
|
|
||||||
+ * We use ELF as output format. So that we can
|
|
||||||
+ * debug the code in some form.
|
|
||||||
+ */
|
|
||||||
+INCLUDE ldoptions
|
|
||||||
+
|
|
||||||
+ENTRY(_start)
|
|
||||||
+
|
|
||||||
+SECTIONS
|
|
||||||
+{
|
|
||||||
+ . = _RAMBASE;
|
|
||||||
+ /*
|
|
||||||
+ * First we place the code and read only data (typically const declared).
|
|
||||||
+ * This get placed in rom.
|
|
||||||
+ */
|
|
||||||
+ .text : {
|
|
||||||
+ _text = .;
|
|
||||||
+ *(.text);
|
|
||||||
+ *(.text.*);
|
|
||||||
+ . = ALIGN(16);
|
|
||||||
+ _etext = .;
|
|
||||||
+ }
|
|
||||||
+ .rodata : {
|
|
||||||
+ _rodata = .;
|
|
||||||
+ . = ALIGN(4);
|
|
||||||
+ streams = . ;
|
|
||||||
+ *(.rodata.streams)
|
|
||||||
+ estreams = .;
|
|
||||||
+ . = ALIGN(4);
|
|
||||||
+ pci_drivers = . ;
|
|
||||||
+ *(.rodata.pci_drivers)
|
|
||||||
+ epci_drivers = . ;
|
|
||||||
+ *(.rodata)
|
|
||||||
+ *(.rodata.*)
|
|
||||||
+ _erodata = .;
|
|
||||||
+ }
|
|
||||||
+ /*
|
|
||||||
+ * After the code we place initialized data (typically initialized
|
|
||||||
+ * global variables). This gets copied into ram by startup code.
|
|
||||||
+ * __data_start and __data_end shows where in ram this should be placed,
|
|
||||||
+ * whereas __data_loadstart and __data_loadend shows where in rom to
|
|
||||||
+ * copy from.
|
|
||||||
+ */
|
|
||||||
+ .data : {
|
|
||||||
+ _data = .;
|
|
||||||
+ *(.data)
|
|
||||||
+ _edata = .;
|
|
||||||
+ }
|
|
||||||
+ /*
|
|
||||||
+ * bss does not contain data, it is just a space that should be zero
|
|
||||||
+ * initialized on startup. (typically uninitialized global variables)
|
|
||||||
+ * crt0.S fills between _bss and _ebss with zeroes.
|
|
||||||
+ */
|
|
||||||
+ _bss = .;
|
|
||||||
+ .bss . : {
|
|
||||||
+ *(.bss)
|
|
||||||
+ *(.sbss)
|
|
||||||
+ *(COMMON)
|
|
||||||
+ }
|
|
||||||
+ _ebss = .;
|
|
||||||
+ _end = .;
|
|
||||||
+ _stack = .;
|
|
||||||
+ .stack . : {
|
|
||||||
+ /* Reserve a stack for each possible cpu, +1 extra */
|
|
||||||
+ . = ((MAX_CPUS * STACK_SIZE) + STACK_SIZE) ;
|
|
||||||
+ }
|
|
||||||
+ _estack = .;
|
|
||||||
+ _heap = .;
|
|
||||||
+ .heap . : {
|
|
||||||
+ /* Reserve 256K for the heap */
|
|
||||||
+ . = HEAP_SIZE ;
|
|
||||||
+ . = ALIGN(4);
|
|
||||||
+ }
|
|
||||||
+ _eheap = .;
|
|
||||||
+ /* The ram segment
|
|
||||||
+ * This is all address of the memory resident copy of linuxBIOS.
|
|
||||||
+ */
|
|
||||||
+ _ram_seg = _text;
|
|
||||||
+ _eram_seg = _eheap;
|
|
||||||
+ /DISCARD/ : {
|
|
||||||
+ *(.comment)
|
|
||||||
+ *(.note)
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
|
|
||||||
Eigenschafts<EFBFBD>nderungen: LinuxBIOSv1\src\config\linuxbios_c.ld
|
|
||||||
___________________________________________________________________
|
|
||||||
Hinzugef<EFBFBD>gt: svn:keywords
|
|
||||||
+ Author Date Id Revision
|
|
||||||
Hinzugef<EFBFBD>gt: svn:eol-style
|
|
||||||
+ native
|
|
||||||
|
|
||||||
Index: LinuxBIOSv1/src/arch/i386/include/arch/rom_segs.h
|
|
||||||
===================================================================
|
|
||||||
--- LinuxBIOSv1/src/arch/i386/include/arch/rom_segs.h (Revision 0)
|
|
||||||
+++ LinuxBIOSv1/src/arch/i386/include/arch/rom_segs.h (Revision 665)
|
|
||||||
@@ -0,0 +1,10 @@
|
|
||||||
+#ifndef ROM_SEGS_H
|
|
||||||
+#define ROM_SEGS_H
|
|
||||||
+
|
|
||||||
+#define ROM_CODE_SEG 0x08
|
|
||||||
+#define ROM_DATA_SEG 0x10
|
|
||||||
+
|
|
||||||
+#define CACHE_RAM_CODE_SEG 0x18
|
|
||||||
+#define CACHE_RAM_DATA_SEG 0x20
|
|
||||||
+
|
|
||||||
+#endif /* ROM_SEGS_H */
|
|
||||||
|
|
||||||
Eigenschafts<EFBFBD>nderungen: LinuxBIOSv1\src\arch\i386\include\arch\rom_segs.h
|
|
||||||
___________________________________________________________________
|
|
||||||
Hinzugef<EFBFBD>gt: svn:keywords
|
|
||||||
+ Author Date Id Revision
|
|
||||||
Hinzugef<EFBFBD>gt: svn:eol-style
|
|
||||||
+ native
|
|
||||||
|
|
||||||
Index: LinuxBIOSv1/src/arch/i386/lib/c_start.S
|
|
||||||
===================================================================
|
|
||||||
--- LinuxBIOSv1/src/arch/i386/lib/c_start.S (Revision 0)
|
|
||||||
+++ LinuxBIOSv1/src/arch/i386/lib/c_start.S (Revision 665)
|
|
||||||
@@ -0,0 +1,135 @@
|
|
||||||
+#include <arch/asm.h>
|
|
||||||
+#include <arch/intel.h>
|
|
||||||
+#ifdef SMP
|
|
||||||
+#include <cpu/p6/apic.h>
|
|
||||||
+#endif
|
|
||||||
+ .section ".text"
|
|
||||||
+ .code32
|
|
||||||
+ .globl _start
|
|
||||||
+_start:
|
|
||||||
+ cli
|
|
||||||
+ lgdt %cs:gdtaddr
|
|
||||||
+ ljmp $0x10, $1f
|
|
||||||
+1: movl $0x18, %ax
|
|
||||||
+ movl %eax, %ds
|
|
||||||
+ movl %eax, %es
|
|
||||||
+ movl %eax, %ss
|
|
||||||
+ movl %eax, %fs
|
|
||||||
+ movl %eax, %gs
|
|
||||||
+
|
|
||||||
+ intel_chip_post_macro(0x13) /* post 12 */
|
|
||||||
+
|
|
||||||
+ /** clear stack */
|
|
||||||
+ leal EXT(_stack), %edi
|
|
||||||
+ movl $EXT(_estack), %ecx
|
|
||||||
+ subl %edi, %ecx
|
|
||||||
+ xorl %eax, %eax
|
|
||||||
+ rep
|
|
||||||
+ stosb
|
|
||||||
+
|
|
||||||
+ /** clear bss */
|
|
||||||
+ leal EXT(_bss), %edi
|
|
||||||
+ movl $EXT(_ebss), %ecx
|
|
||||||
+ subl %edi, %ecx
|
|
||||||
+ jz .Lnobss
|
|
||||||
+ xorl %eax, %eax
|
|
||||||
+ rep
|
|
||||||
+ stosb
|
|
||||||
+.Lnobss:
|
|
||||||
+
|
|
||||||
+ /* set new stack */
|
|
||||||
+ movl $_estack, %esp
|
|
||||||
+#ifdef SMP
|
|
||||||
+ /* Get the cpu id */
|
|
||||||
+ movl $APIC_DEFAULT_BASE, %edi
|
|
||||||
+ movl APIC_ID(%edi), %eax
|
|
||||||
+ shrl $24, %eax
|
|
||||||
+
|
|
||||||
+ /* Get the cpu index (MAX_CPUS on error) */
|
|
||||||
+ movl $-4, %ebx
|
|
||||||
+1: addl $4, %ebx
|
|
||||||
+ cmpl $(MAX_CPUS << 2), %ebx
|
|
||||||
+ je 2
|
|
||||||
+ cmpl %eax, EXT(initial_apicid)(%ebx)
|
|
||||||
+ jne 1b
|
|
||||||
+2: shrl $2, %ebx
|
|
||||||
+
|
|
||||||
+ /* Now compute the appropriate stack */
|
|
||||||
+ movl %ebx, %eax
|
|
||||||
+ movl $STACK_SIZE, %ebx
|
|
||||||
+ mull %ebx
|
|
||||||
+ subl %eax, %esp
|
|
||||||
+
|
|
||||||
+ /* push the boot_complete flag */
|
|
||||||
+ pushl %ebp
|
|
||||||
+
|
|
||||||
+ /* Save the stack location */
|
|
||||||
+ movl %esp, %ebp
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Now we are finished. Memory is up, data is copied and
|
|
||||||
+ * bss is cleared. Now we call the main routine and
|
|
||||||
+ * let it do the rest.
|
|
||||||
+ */
|
|
||||||
+ intel_chip_post_macro(0xfe) /* post fe */
|
|
||||||
+
|
|
||||||
+ /* Resort the stack location */
|
|
||||||
+ movl %ebp, %esp
|
|
||||||
+
|
|
||||||
+ /* The boot_complete flag has already been pushed */
|
|
||||||
+ call EXT(hardwaremain)
|
|
||||||
+ /*NOTREACHED*/
|
|
||||||
+.Lhlt:
|
|
||||||
+ intel_chip_post_macro(0xee) /* post fe */
|
|
||||||
+ hlt
|
|
||||||
+ jmp .Lhlt
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ .globl gdt, gdt_end, gdt_limit
|
|
||||||
+
|
|
||||||
+gdt_limit = gdt_end - gdt - 1 /* compute the table limit */
|
|
||||||
+gdtaddr:
|
|
||||||
+ .word gdt_limit
|
|
||||||
+ .long gdt /* we know the offset */
|
|
||||||
+
|
|
||||||
+gdt:
|
|
||||||
+// selgdt 0
|
|
||||||
+ .word 0x0000, 0x0000 /* dummy */
|
|
||||||
+ .byte 0x00, 0x00, 0x00, 0x00
|
|
||||||
+
|
|
||||||
+// selgdt 8
|
|
||||||
+ .word 0x0000, 0x0000 /* dummy */
|
|
||||||
+ .byte 0x00, 0x00, 0x00, 0x00
|
|
||||||
+
|
|
||||||
+// selgdt 0x10
|
|
||||||
+/* flat code segment */
|
|
||||||
+ .word 0xffff, 0x0000
|
|
||||||
+ .byte 0x00, 0x9b, 0xcf, 0x00
|
|
||||||
+
|
|
||||||
+//selgdt 0x18
|
|
||||||
+/* flat data segment */
|
|
||||||
+ .word 0xffff, 0x0000
|
|
||||||
+ .byte 0x00, 0x93, 0xcf, 0x00
|
|
||||||
+
|
|
||||||
+//selgdt 0x20
|
|
||||||
+ .word 0x0000, 0x0000 /* dummy */
|
|
||||||
+ .byte 0x00, 0x00, 0x00, 0x00
|
|
||||||
+
|
|
||||||
+#if defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
|
|
||||||
+ // from monty:
|
|
||||||
+ /* 0x00009a00,0000ffffULL, 20h: 16-bit 64k code at 0x00000000 */
|
|
||||||
+ /* 0x00009200,0000ffffULL 28h: 16-bit 64k data at 0x00000000 */
|
|
||||||
+// selgdt 0x28
|
|
||||||
+/*16-bit 64k code at 0x00000000 */
|
|
||||||
+ .word 0xffff, 0x0000
|
|
||||||
+ .byte 0, 0x9a, 0, 0
|
|
||||||
+
|
|
||||||
+// selgdt 0x30
|
|
||||||
+/*16-bit 64k data at 0x00000000 */
|
|
||||||
+ .word 0xffff, 0x0000
|
|
||||||
+ .byte 0, 0x92, 0, 0
|
|
||||||
+#endif // defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
|
|
||||||
+gdt_end:
|
|
||||||
+
|
|
||||||
+.code32
|
|
||||||
|
|
||||||
Eigenschafts<EFBFBD>nderungen: LinuxBIOSv1\src\arch\i386\lib\c_start.S
|
|
||||||
___________________________________________________________________
|
|
||||||
Hinzugef<EFBFBD>gt: svn:keywords
|
|
||||||
+ Author Date Id Revision
|
|
||||||
Hinzugef<EFBFBD>gt: svn:eol-style
|
|
||||||
+ native
|
+ native
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -1 +1,33 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:1:{i:0;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:3:"abc";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"0";i:1;s:1:"0";}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => "abc\r\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '0',
|
||||||
|
1 => '0',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:3:"abc";}i:1;a:3:{i:0;s:0:"";i:1;i:2;i:2;s:3:"abc";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"0";i:1;s:1:"0";}i:1;a:2:{i:0;s:1:"1";i:1;s:1:"2";}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => "abc\r\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => 2,
|
||||||
|
2 => "abc\r\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '0',
|
||||||
|
1 => '0',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:1:"1";i:1;s:1:"1";i:2;s:3:"abc";}i:1;a:3:{i:0;i:2;i:1;s:0:"";i:2;s:3:"abc";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;s:1:"2";}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
2 => "abc\r\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => 2,
|
||||||
|
1 => '',
|
||||||
|
2 => "abc\r\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '2',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:1:"1";i:1;s:0:"";i:2;s:3:"abc";}i:1;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:2:"ls";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;i:1;}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '',
|
||||||
|
2 => "abc\r\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => "ls\r\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:1:"1";i:1;s:1:"1";i:2;s:2:"ls";}i:1;a:3:{i:0;s:0:"";i:1;i:2;i:2;s:2:"ls";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;i:1;}i:1;a:2:{i:0;s:1:"1";i:1;s:1:"2";}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
2 => "ls\r\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => 2,
|
||||||
|
2 => "ls\r\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,45 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:3:{i:0;a:3:{i:0;s:1:"1";i:1;s:1:"1";i:2;s:2:"ls";}i:1;a:3:{i:0;i:2;i:1;i:2;i:2;s:2:"ls";}i:2;a:3:{i:0;s:0:"";i:1;i:3;i:2;s:1:"l";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;s:1:"2";}i:1;a:2:{i:0;s:1:"1";i:1;s:1:"3";}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
2 => "ls\r\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => 2,
|
||||||
|
1 => 2,
|
||||||
|
2 => "ls\r\n",
|
||||||
|
),
|
||||||
|
2 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => 3,
|
||||||
|
2 => "l\r\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '2',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '3',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,33 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:1:{i:0;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:3:"foo";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"0";i:1;s:1:"0";}i:1;a:2:{i:0;s:1:"1";i:1;s:1:"1";}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => "foo\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '0',
|
||||||
|
1 => '0',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:1:"1";i:1;s:1:"1";i:2;s:3:"foo";}i:1;a:3:{i:0;s:0:"";i:1;i:2;i:2;s:2:"bf";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;s:1:"1";}i:1;a:2:{i:0;s:1:"1";i:1;s:1:"2";}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
2 => "foo\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => 2,
|
||||||
|
2 => "bf\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,33 @@
|
|||||||
a:1:{s:1:"a";a:2:{s:6:"chunks";a:1:{i:0;a:1:{i:0;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:3:"abc";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"0";i:1;s:1:"0";}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'a' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => "abc\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '0',
|
||||||
|
1 => '0',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,45 @@
|
|||||||
a:1:{s:1:"b";a:2:{s:6:"chunks";a:1:{i:0;a:3:{i:0;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:1:"a";}i:1;a:3:{i:0;s:0:"";i:1;i:2;i:2;s:1:"b";}i:2;a:3:{i:0;s:0:"";i:1;i:3;i:2;b:0;}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"0";i:1;s:1:"0";}i:1;a:2:{i:0;s:1:"1";i:1;s:1:"3";}}}}}
|
<?php return array (
|
||||||
|
'b' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => "a\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => 2,
|
||||||
|
2 => "b\n",
|
||||||
|
),
|
||||||
|
2 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => 3,
|
||||||
|
2 => "\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '0',
|
||||||
|
1 => '0',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '3',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,51 @@
|
|||||||
a:1:{s:1:"b";a:2:{s:6:"chunks";a:1:{i:0;a:4:{i:0;a:3:{i:0;s:1:"1";i:1;s:1:"1";i:2;s:1:"a";}i:1;a:3:{i:0;s:0:"";i:1;i:2;i:2;s:1:"l";}i:2;a:3:{i:0;i:2;i:1;i:3;i:2;s:1:"b";}i:3;a:3:{i:0;i:3;i:1;i:4;i:2;b:0;}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;s:1:"3";}i:1;a:2:{i:0;s:1:"1";i:1;s:1:"4";}}}}}
|
<?php return array (
|
||||||
|
'b' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
2 => "a\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => 2,
|
||||||
|
2 => "l\n",
|
||||||
|
),
|
||||||
|
2 =>
|
||||||
|
array (
|
||||||
|
0 => 2,
|
||||||
|
1 => 3,
|
||||||
|
2 => "b\n",
|
||||||
|
),
|
||||||
|
3 =>
|
||||||
|
array (
|
||||||
|
0 => 3,
|
||||||
|
1 => 4,
|
||||||
|
2 => "\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '3',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '4',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,45 @@
|
|||||||
a:1:{s:1:"b";a:2:{s:6:"chunks";a:1:{i:0;a:3:{i:0;a:3:{i:0;s:1:"1";i:1;s:1:"1";i:2;s:1:"a";}i:1;a:3:{i:0;i:2;i:1;s:0:"";i:2;s:1:"b";}i:2;a:3:{i:0;i:3;i:1;s:0:"";i:2;b:0;}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;s:1:"3";}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'b' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '1',
|
||||||
|
2 => "a\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => 2,
|
||||||
|
1 => '',
|
||||||
|
2 => "b\n",
|
||||||
|
),
|
||||||
|
2 =>
|
||||||
|
array (
|
||||||
|
0 => 3,
|
||||||
|
1 => '',
|
||||||
|
2 => "\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '3',
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:9:"test_file";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:1:"1";i:1;s:0:"";i:2;s:17:"Steddy is awesome";}i:1;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:22:"Steddy is very awesome";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;i:1;}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'test_file' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '',
|
||||||
|
2 => "Steddy is awesome\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => 'Steddy is very awesome',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:3:"foo";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:1:"1";i:1;s:0:"";i:2;s:11:"This is foo";}i:1;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:11:"This is foo";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;i:1;}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'foo' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '',
|
||||||
|
2 => "This is foo\n",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => 'This is foo',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
@@ -1 +1,39 @@
|
|||||||
a:1:{s:3:"foo";a:2:{s:6:"chunks";a:1:{i:0;a:2:{i:0;a:3:{i:0;s:1:"1";i:1;s:0:"";i:2;s:11:"This is foo";}i:1;a:3:{i:0;s:0:"";i:1;s:1:"1";i:2;s:11:"This is foo";}}}s:10:"chunks_def";a:1:{i:0;a:2:{i:0;a:2:{i:0;s:1:"1";i:1;i:1;}i:1;a:2:{i:0;s:1:"1";i:1;i:1;}}}}}
|
<?php return array (
|
||||||
|
'foo' =>
|
||||||
|
array (
|
||||||
|
'chunks' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => '',
|
||||||
|
2 => "This is foo",
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '',
|
||||||
|
1 => '1',
|
||||||
|
2 => "This is foo\n",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'chunks_def' =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
1 =>
|
||||||
|
array (
|
||||||
|
0 => '1',
|
||||||
|
1 => 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
10
test/data/IDF_DiffTest/test-18-git-lineendings.diff
Normal file
10
test/data/IDF_DiffTest/test-18-git-lineendings.diff
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
diff --git a/lineendings b/lineendings
|
||||||
|
index 7c2b7ec..9c59944 100644
|
||||||
|
--- a/lineendings
|
||||||
|
+++ b/lineendings
|
||||||
|
@@ -1,3 +1,4 @@
|
||||||
|
+Unix, again
|
||||||
|
Windows
|
||||||
|
Unix
|
||||||
|
Old Macintosh
|
||||||
|
Nothing
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user