Merge branch 'develop'

master
Loïc d'Anterroches 2011-01-24 12:06:05 +01:00
commit f7228ef2ec
17 changed files with 270 additions and 59 deletions

View File

@ -187,10 +187,11 @@ Remote commands can be helpful for a user or a 3rd party tool (like
contents remotely without having to pull everything in first instance.
Private projects on the other hand can only be synced by team members
or additional invited people. Remote command execution is still enabled
by default - if you want to disable that, simply remove the symlink to
the file `indefero_authorize_remote_automate.conf` in your project's `hooks.d`
directory or copy the file from the original location and adapt it.
or additional invited people. Remote command execution is disabled
by default. If you want to enable that, simply put the keys of the users
you want to give access to in your project's `remote-automate-permissions`
file. In the future this plugin might handle this file just as it handles
`read-permissions` and `write-permissions`.
## Notifications

View File

@ -154,7 +154,7 @@ class IDF_Commit extends Pluf_Model
$commit->summary = self::toUTF8($change->title);
$commit->fullmessage = self::toUTF8($change->full_message);
$commit->author = $scm->findAuthor($change->author);
$commit->origauthor = $change->author;
$commit->origauthor = self::toUTF8($change->author);
$commit->creation_dtime = $change->date;
$commit->create();
$commit->notify($project->getConf());

View File

@ -117,6 +117,12 @@ class IDF_Plugin_SyncMonotone
'hooks.d/indefero_post_push.conf.in',
'hooks.d/indefero_post_push.lua',
);
if (!$project->private) {
// this is linked and not copied to be able to update
// the list of read-only commands on upgrades
$confdir_contents[] = 'hooks.d/indefero_authorize_remote_automate.conf';
}
// check whether we should handle additional files in the config directory
$confdir_extra_contents = Pluf::f('mtn_confdir_extra', false);
if ($confdir_extra_contents !== false) {
@ -383,6 +389,41 @@ class IDF_Plugin_SyncMonotone
__('Could not write read-permissions file "%s"'), $rcfile
));
}
// link / unlink the read-only automate permissions for the project
$confdir = Pluf::f('mtn_confdir', false);
if ($confdir === false) {
$confdir = dirname(__FILE__).'/SyncMonotone/';
}
$file = 'hooks.d/indefero_authorize_remote_automate.conf';
$projectfile = $projectpath.'/'.$file;
$templatefile = $confdir.'/'.$file;
$serverRestartRequired = false;
if ($project->private && file_exists($projectfile) && is_link($projectfile)) {
if (!unlink($projectfile)) {
IDF_Scm_Exception(sprintf(
__('Could not remove symlink "%s"'), $projectfile
));
}
$serverRestartRequired = true;
} else
if (!$project->private && !file_exists($projectfile)) {
if (!symlink($templatefile, $projectfile)) {
throw new IDF_Scm_Exception(sprintf(
__('Could not create symlink "%s"'), $projectfile
));
}
$serverRestartRequired = true;
}
if ($serverRestartRequired) {
// FIXME: we should actually use stopServer() here, but this
// seems to be ignored when the server should be started
// again immediately afterwards
IDF_Scm_Monotone_Usher::killServer($project->shortname);
IDF_Scm_Monotone_Usher::startServer($project->shortname);
}
}
/**

View File

@ -55,7 +55,9 @@ class IDF_Scm_Cache_Git extends Pluf_Model
$cache->project = $this->_project;
$cache->githash = $blob->hash;
$blob->title = IDF_Commit::toUTF8($blob->title);
$cache->content = $blob->date.chr(31).$blob->author.chr(31).$blob->title;
$cache->content = IDF_Commit::toUTF8($blob->date) . chr(31)
. IDF_Commit::toUTF8($blob->author) . chr(31)
. IDF_Commit::toUTF8($blob->title);
$sql = new Pluf_SQL('project=%s AND githash=%s',
array($this->_project->id, $blob->hash));
if (0 == Pluf::factory(__CLASS__)->getCount(array('filter' => $sql->gen()))) {

View File

@ -27,7 +27,7 @@
*/
class IDF_Scm_Git extends IDF_Scm
{
public $mediumtree_fmt = 'commit %H%nAuthor: %an <%ae>%nTree: %T%nDate: %ai%n%n%s%n%n%b';
public $mediumtree_fmt = 'commit %H%nAuthor: %an <%ae>%nTree: %T%nParents: %P%nDate: %ai%n%n%s%n%n%b';
/* ============================================== *
* *
@ -518,6 +518,9 @@ class IDF_Scm_Git extends IDF_Scm
$c['full_message'] = trim($c['full_message']);
$c['full_message'] = IDF_Commit::toUTF8($c['full_message']);
$c['title'] = IDF_Commit::toUTF8($c['title']);
if (isset($c['parents'])) {
$c['parents'] = explode(' ', trim($c['parents']));
}
$res[] = (object) $c;
}
$c = array();
@ -553,6 +556,9 @@ class IDF_Scm_Git extends IDF_Scm
$c['full_message'] = !empty($c['full_message']) ? trim($c['full_message']) : '';
$c['full_message'] = IDF_Commit::toUTF8($c['full_message']);
$c['title'] = IDF_Commit::toUTF8($c['title']);
if (isset($c['parents'])) {
$c['parents'] = explode(' ', trim($c['parents']));
}
$res[] = (object) $c;
return $res;
}

View File

@ -21,9 +21,6 @@
#
# ***** END LICENSE BLOCK ***** */
//require_once(dirname(__FILE__) . "/Monotone/Stdio.php");
//require_once(dirname(__FILE__) . "/Monotone/BasicIO.php");
/**
* Monotone scm class
*
@ -677,8 +674,12 @@ class IDF_Scm_Monotone extends IDF_Scm
if (count($revs) == 0)
return array();
$certs = $this->_getCerts($revs[0]);
$res = array();
$parents = $this->stdio->exec(array('parents', $revs[0]));
$res['parents'] = preg_split("/\n/", $parents, -1, PREG_SPLIT_NO_EMPTY);
$certs = $this->_getCerts($revs[0]);
// FIXME: this assumes that author, date and changelog are always given
$res['author'] = implode(', ', $certs['author']);
@ -749,10 +750,9 @@ class IDF_Scm_Monotone extends IDF_Scm
// read in the initial branches we should follow
if (count($initialBranches) == 0) {
if (!isset($certs['branch'])) {
throw new IDF_Scm_Exception(sprintf(
__("revision %s has no branch cert - cannot start ".
"logging from this revision"), $rev
));
// this revision has no branch cert, we cannot start logging
// from this revision
continue;
}
$initialBranches = $certs['branch'];
}

View File

@ -342,7 +342,7 @@ class IDF_Views_Source
if (!$cobject) {
throw new Exception('could not retrieve commit object for '. $commit);
}
$rep = new Pluf_HTTP_Response($cobject->changes, 'text/plain');
$rep = new Pluf_HTTP_Response($cobject->diff, 'text/plain');
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$commit.'.diff"';
return $rep;
}

View File

@ -69,6 +69,7 @@
<div id="ft">{block foot}{/block}</div>
</div>
{include 'idf/js-hotkeys.html'}
{include 'idf/list-filter.html'}
{block javascript}{/block}
{if $project}
<script type="text/javascript" charset="utf-8">{literal}

View File

@ -53,6 +53,7 @@
<div id="ft">{block foot}{/block}</div>
</div>
{include 'idf/js-hotkeys.html'}
{include 'idf/list-filter.html'}
{block javascript}{/block}
</body>
</html>

View File

@ -70,6 +70,7 @@
<div id="ft">{block foot}{/block}</div>
</div>
{include 'idf/js-hotkeys.html'}
{include 'idf/list-filter.html'}
{block javascript}{/block}
{if $project}
<script type="text/javascript" charset="utf-8">{literal}

View File

@ -0,0 +1,51 @@
{**
* Looks for input fields like
* <input type="text" class="filter-list" rel="target" />
* and filters out anchors below $(target) which do not match
* the entered input.
*}
<script type="text/javascript" charset="utf-8">
{literal}
$(document).ready(function() {
$("input.filter-list").each(function() {
var lists = $("ul#" + $(this).attr("rel"));
if (lists.length == 0)
return;
var list = $(lists[0]);
// a list should contain a reasonable amount of items
// to be filterable - we also give the filter input a
// special class here so we recognize it later in case
// we have to hide it when the list view is collapsed
if (list.children("li").length > 10) {
$(this).addClass("activated");
$(this).focus(function() {
// ensure that the parent of the list keeps activated / opened
list.parent().addClass("activated");
if ($(this)[0].value == $(this).attr("title"))
$(this).attr("value", "").removeClass("default");
});
$(this).blur(function() {
list.parent().removeClass("activated");
if ($(this)[0].value.length == 0)
$(this).attr("value", $(this).attr("title")).addClass("default");
});
$(this).keyup(function(ev) {
var filter = $(this)[0];
list.children("li").css('display', 'block');
list.children("li").filter(function(index) {
if (filter.value == "")
return false;
if ($(this).text().indexOf(filter.value) > -1)
return false;
return true;
}).css('display', 'none');
});
// initialize it with the default
$(this)[0].value = "";
$(this).blur();
}
});
});
{/literal}
</script>

View File

@ -15,6 +15,12 @@
<tr>
<th><strong>{trans 'Commit:'}</strong></th><td class="mono"><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}" title="{trans 'View corresponding source tree'}">{$cobject.commit}</a></td>
</tr>
{if $cobject.parents}<tr>
<th><strong>{trans 'Parents:'}</strong></th><td class="mono">{foreach $cobject.parents as $parent}
<a href="{url 'IDF_Views_Source::commit', array($project.shortname, $parent)}" title="{trans 'View corresponding commit'}">{$parent}</a><br />
{/foreach}
</td>
</tr>{/if}
<tr>
<th><strong>{trans 'Message:'}</strong></th><td>{issuetext $cobject.title, $request}{if isset($cobject.full_message)}<br/><br/>{issuetext $cobject.full_message, $request, true, false, true, true, true}{/if}</td>
</tr>{if count($changes)}

View File

@ -1,25 +1,32 @@
{extends "idf/source/changelog.html"}
{block context}
<p><strong>{trans 'Branches:'}</strong><br/>
<div class="expander">
<div class="gradient"></div>
<h1>
{trans 'Branches'}
<input type="text" rel="branch-list" class="filter-list" title="{trans 'filter branches'}" />
</h1>
<ul id="branch-list">
{foreach $branches as $selector => $branch}
{aurl 'url', 'IDF_Views_Source::changeLog', array($project.shortname, $selector)}
<span class="label{if in_array($selector, $tree_in)} active{/if}">
<a href="{$url}" class="label" title="{$branch}">
{$branch|shorten:24}
</a>
</span><br/>
<li class="{if in_array($selector, $tree_in)}active{/if}">
<a href="{$url}" class="label">{$branch}</a>
</li>
{/foreach}
</p>
</ul>
{if $tags}
<p><strong>{trans 'Tags:'}</strong><br/>
<h1>
{trans 'Tags'}
<input type="text" rel="tag-list" class="filter-list" title="{trans 'filter tags'}" />
</h1>
<ul id="tag-list">
{foreach $tags as $selector => $tag}
{aurl 'url', 'IDF_Views_Source::changeLog', array($project.shortname, $selector)}
<span class="label{if in_array($selector, $tags_in)} active{/if}">
<a href="{$url}" class="label" title="{$tag}">
{$tag|shorten:24}
</a>
</span><br/>
<li class="{if in_array($selector, $tags_in)}active{/if}">
<a href="{$url}" class="label">{$tag}</a>
</li>
{/foreach}
</p>
</ul>
{/if}
</div>
{/block}

View File

@ -1,26 +1,32 @@
{extends "idf/source/commit.html"}
{block context}
<p><strong>{trans 'Branches:'}</strong><br/>
<div class="expander">
<div class="gradient"></div>
<h1>
{trans 'Branches'}
<input type="text" rel="branch-list" class="filter-list" title="{trans 'filter branches'}" />
</h1>
<ul id="branch-list">
{foreach $branches as $selector => $branch}
{aurl 'url', 'IDF_Views_Source::treeBase', array($project.shortname, $selector)}
<span class="label{if in_array($branch, $tree_in)} active{/if}">
<a href="{$url}" class="label" title="{$branch}">
{$branch|shorten:25}
</a>
</span><br/>
<li class="{if in_array($branch, $tree_in)}active{/if}">
<a href="{$url}" class="label">{$branch}</a>
</li>
{/foreach}
</p>
</ul>
{if $tags}
<p><strong>{trans 'Tags:'}</strong><br/>
<h1>
{trans 'Tags'}
<input type="text" rel="tag-list" class="filter-list" title="{trans 'filter tags'}" />
</h1>
<ul id="tag-list">
{foreach $tags as $selector => $tag}
{aurl 'url', 'IDF_Views_Source::treeBase', array($project.shortname, $selector)}
<span class="label{if in_array($tag, $tags_in)} active{/if}">
<a href="{$url}" class="label" title="{$tag}">
{$tag|shorten:25}
</a>
</span><br/>
<li class="{if in_array($tag, $tags_in)}active{/if}">
<a href="{$url}" class="label">{$tag}</a>
</li>
{/foreach}
</p>
</ul>
{/if}
</div>
{/block}

View File

@ -55,26 +55,33 @@
{/block}
{block context}
<p><strong>{trans 'Branches:'}</strong><br/>
<div class="expander">
<div class="gradient"></div>
<h1>
{trans 'Branches'}
<input type="text" rel="branch-list" class="filter-list" title="{trans 'filter branches'}" />
</h1>
<ul id="branch-list">
{foreach $branches as $selector => $branch}
{aurl 'url', 'IDF_Views_Source::treeBase', array($project.shortname, $selector)}
<span class="label{if in_array($selector, $tree_in)} active{/if}">
<a href="{$url}" class="label" title="{$branch}">
{$branch|shorten:24}
</a>
</span><br/>
<li class="{if in_array($selector, $tree_in)}active{/if}">
<a href="{$url}" class="label">{$branch}</a>
</li>
{/foreach}
</p>
</ul>
{if $tags}
<p><strong>{trans 'Tags:'}</strong><br/>
<h1>
{trans 'Tags'}
<input type="text" rel="tag-list" class="filter-list" title="{trans 'filter tags'}" />
</h1>
<ul id="tag-list">
{foreach $tags as $selector => $tag}
{aurl 'url', 'IDF_Views_Source::treeBase', array($project.shortname, $selector)}
<span class="label{if in_array($selector, $tags_in)} active{/if}">
<a href="{$url}" class="label" title="{$tag}">
{$tag|shorten:24}
</a>
</span><br/>
<li class="{if in_array($selector, $tags_in)}active{/if}">
<a href="{$url}" class="label">{$tag}</a>
</li>
{/foreach}
</p>
</ul>
{/if}
</div>
{/block}

View File

@ -858,3 +858,84 @@ ol > li {
color: #2E3436;
}
/**
* List expander for tag and branch view
*/
.context {}
.context h1 {
font-size: 13px;
font-weight: bold;
margin: 10px 0 5px;
}
.context > .expander {
position: relative;
overflow: hidden;
background: white;
}
.context > .expander > ul {
margin: 5px;
}
.context > .expander > ul > li {
white-space: nowrap;
list-style-type: none;
}
.context > .expander > ul > li.active {
font-weight: bold;
}
.context > .expander > .gradient {
position: absolute;
right: 0;
width: 20px;
height: 100%;
z-index: 998;
background: url(../img/white_gradient.png) repeat-y;
}
.context > .expander:hover,
.context > .expander.activated {
position: absolute;
z-index: 999;
overflow: visible;
-moz-border-radius: 0 10px 10px 0;
-webkit-border-radius: 0 10px 10px 0;
border-radius: 0 10px 10px 0;
-moz-box-shadow: 3px 3px 5px #333;
-webkit-box-shadow: 3px 3px 5px #333;
box-shadow: 3px 3px 5px #333;
padding: 5px 10px;
margin: -5px -10px;
min-width: 180px;
}
.context > .expander:hover > .gradient,
.context > .expander.activated > .gradient {
display: none;
}
.context > .expander input.filter-list {
font-size: 11px;
font-weight: normal;
color: #333;
border: 1px dotted #474747;
margin-left: 10px;
padding: 2px;
width: 80px;
display: none;
float: right;
}
.context > .expander:hover input.filter-list.activated,
.context > .expander.activated input.filter-list.activated {
display: block;
}
.context > .expander input.filter-list.default {
color: #aaa;
border-color: #aaa;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B