Indefero

Indefero Commit Details


Date:2010-09-01 08:13:52 (14 years 3 months ago)
Author:Thomas Keller
Branch:develop, feature-issue_links, feature.better-home, feature.content-md5, feature.diff-whitespace, feature.download-md5, feature.issue-links, feature.issue-of-others, feature.issue-summary, feature.search-filter, feature.webrepos, feature.wiki-default-page, master, release-1.1, release-1.2, release-1.3
Commit:21cdf60c31553261fc1e72b79f8631ee03bbf650
Parents: 5d263e78e00dd3d5569cc23f81c9279fdad81385
Message:Introduce a more subtle concept of validity when it comes to revision indentifiers in IDF - the SCM function isValidRevision has been replaced by a validateRevision() method which returns one of three states, valid, invalid or ambiguous. The source view can then act accordingly and display disambiguate view for the latter, so the user can select for which revision he actually wants to execute the requested action. Also, invalid revisions now lead to another separate view, telling the user that it is invalid / does not exist and pointing him optionally to the help page where he can read further how to access his repository to push the first changes into. (partially resolves issue 525)

Changes:

File differences

src/IDF/Scm.php
6363
6464
6565
66
66
6767
6868
6969
......
166166
167167
168168
169
170
171
172
169173
170
174
171175
172176
173
177
174178
175
179
180
181
182
183
184
185
186
187
188
189
190
176191
177192
178193
......
217232
218233
219234
220
235
221236
222237
223238
......
282297
283298
284299
285
300
286301
287302
288303
......
396411
397412
398413
399
414
400415
401416
402417
public $project = null;
/**
* Cache storage.
* Cache storage.
*
* It must only be used to store data for the lifetime of the
* object. For example if you need to get the list of branches in
throw new Pluf_Exception_NotImplemented();
}
const REVISION_VALID = 0;
const REVISION_INVALID = 1;
const REVISION_AMBIGUOUS = 2;
/**
* Check if a revision or commit is valid.
* Check if a revision or commit is valid, invalid or ambiguous.
*
* @param string Revision or commit
* @return bool
* @return int One of REVISION_VALID, REVISION_INVALID or REVISION_AMBIGIOUS
*/
public function isValidRevision($rev)
public function validateRevision($rev)
{
throw new Pluf_Exception_NotImplemented();
}
/**
* Returns an array of single commit objects for ambiguous commit identifiers
*
* @param string Ambiguous commit identifier
* @return array of objects
*/
public function disambiguateRevision($commit)
{
throw new Pluf_Exception_NotImplemented();
}
* 'foo-branch' => 'branches/foo-branch',)
* </pre>
*
* @return array Branches
* @return array Branches
*/
public function getBranches()
{
* @param string Revision or commit
* @param string Folder ('/')
* @param string Branch (null)
* @return array
* @return array
*/
public function getTree($rev, $folder='/', $branch=null)
{
public static function syncTimeline($project, $force=false)
{
$cache = Pluf_Cache::factory();
$key = 'IDF_Scm:'.$project->shortname.':lastsync';
$key = 'IDF_Scm:'.$project->shortname.':lastsync';
if ($force or null === ($res=$cache->get($key))) {
$scm = IDF_Scm::get($project);
if ($scm->isAvailable()) {
src/IDF/Scm/Git.php
296296
297297
298298
299
299
300300
301301
302
302
303
304
303305
304306
305307
}
public function isValidRevision($commit)
public function validateRevision($commit)
{
$type = $this->testHash($commit);
return ('commit' == $type || 'tag' == $type);
if ('commit' == $type || 'tag' == $type)
return IDF_Scm::REVISION_VALID;
return IDF_Scm::REVISION_INVALID;
}
/**
src/IDF/Scm/Mercurial.php
8787
8888
8989
90
90
9191
9292
9393
9494
9595
9696
97
97
98
99
100
101
102
98103
99104
100105
return sprintf(Pluf::f('mercurial_remote_url'), $project->shortname);
}
public function isValidRevision($rev)
public function validateRevision($rev)
{
$cmd = sprintf(Pluf::f('hg_path', 'hg').' log -R %s -r %s',
escapeshellarg($this->repo),
escapeshellarg($rev));
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
self::exec('IDF_Scm_Mercurial::isValidRevision', $cmd, $out, $ret);
return ($ret == 0) && (count($out) > 0);
// FIXME: apparently a given hg revision can also be ambigious -
// handle this case here sometime
if ($ret == 0 && count($out) > 0)
return IDF_Scm::REVISION_VALID;
return IDF_Scm::REVISION_INVALID;
}
/**
src/IDF/Scm/Monotone.php
425425
426426
427427
428
428
429429
430
430
431431
432432
433
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
434475
435476
436477
......
630671
631672
632673
633
674
634675
635676
636677
}
/**
* @see IDF_Scm::isValidRevision()
* @see IDF_Scm::validateRevision()
*/
public function isValidRevision($commit)
public function validateRevision($commit)
{
$revs = $this->_resolveSelector($commit);
return count($revs) == 1;
if (count($revs) == 0)
return IDF_Scm::REVISION_INVALID;
if (count($revs) > 1)
return IDF_Scm::REVISION_AMBIGUOUS;
return IDF_Scm::REVISION_VALID;
}
/**
* @see IDF_Scm::disambiguateRevision
*/
public function disambiguateRevision($commit)
{
$revs = $this->_resolveSelector($commit);
$out = array();
foreach ($revs as $rev)
{
$certs = $this->_getCerts($rev);
$log = array();
$log['author'] = implode(', ', $certs['author']);
$log['branch'] = implode(', ', $certs['branch']);
$dates = array();
foreach ($certs['date'] as $date)
$dates[] = date('Y-m-d H:i:s', strtotime($date));
$log['date'] = implode(', ', $dates);
$combinedChangelog = implode("\n---\n", $certs['changelog']);
$split = preg_split("/[\n\r]/", $combinedChangelog, 2);
$log['title'] = $split[0];
$log['full_message'] = (isset($split[1])) ? trim($split[1]) : '';
$log['commit'] = $rev;
$out[] = (object)$log;
}
return $out;
}
/**
--$n;
$log = array();
$log['author'] = implode(", ", $certs['author']);
$log['author'] = implode(', ', $certs['author']);
$dates = array();
foreach ($certs['date'] as $date)
src/IDF/Scm/Svn.php
138138
139139
140140
141
141
142142
143143
144144
......
149149
150150
151151
152
153
152
153
154
155
156
154157
155158
156159
/**
* Subversion revisions are either a number or 'HEAD'.
*/
public function isValidRevision($rev)
public function validateRevision($rev)
{
if ($rev == 'HEAD') {
return true;
escapeshellarg($this->repo),
escapeshellarg($rev));
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
self::exec('IDF_Scm_Svn::isValidRevision', $cmd, $out, $ret);
return (0 == $ret);
self::exec('IDF_Scm_Svn::validateRevision', $cmd, $out, $ret);
if ($ret == 0)
return IDF_Scm::REVISION_VALID;
return IDF_Scm::REVISION_INVALID;
}
src/IDF/Views/Source.php
5959
6060
6161
62
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
63106
64107
65108
66
67
68
69
70
71109
72110
73
74
75
76
77
78
79
80
81
82
83
84
85
111
86112
87113
88114
......
111137
112138
113139
114
140
141
142
115143
116144
117145
118
119
120
121
122
123146
147
124148
125149
126
127
128
129
150
130151
131152
132153
......
159180
160181
161182
162
183
184
185
163186
164187
165188
166189
167190
168
169
170
171
172
173
174
175
176191
177192
178193
......
181196
182197
183198
184
185
186
187
199
188200
189201
190
202
203
204
205
191206
192207
193208
......
277292
278293
279294
280
295
296
297
281298
282299
283300
284301
285
286
287
288
289
290
291
292302
293303
294304
295
296
297
298
299
305
300306
301307
302308
......
326332
327333
328334
329
335
336
337
330338
331339
332340
333341
334
335
336
337
338
339
340
341342
343
344
345
342346
343347
344348
......
394398
395399
396400
397
401
402
403
398404
399405
400406
401407
402408
403
404
405
406
407
408
409
410409
411410
412411
......
427426
428427
429428
430
429
430
431
431432
432433
433434
434435
435
436
437
438
439
440
441
442436
443437
444438
......
447441
448442
449443
450
451444
452445
453446
......
495488
496489
497490
498
499491
500492
501493
......
610602
611603
612604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
$params, $request);
}
public $changeLog_precond = array('IDF_Precondition::accessSource');
/**
* Is displayed in case an invalid revision is requested
*/
public $invalidRevision_precond = array('IDF_Precondition::accessSource');
public function invalidRevision($request, $match)
{
$title = sprintf(__('%s Invalid Revision'), (string) $request->project);
$commit = $match[2];
$params = array(
'page_title' => $title,
'title' => $title,
'commit' => $commit,
);
return Pluf_Shortcuts_RenderToResponse('idf/source/invalid_revision.html',
$params, $request);
}
/**
* Is displayed in case a revision identifier cannot be uniquely resolved
* to one single revision
*/
public $disambiguateRevision_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable');
public function disambiguateRevision($request, $match)
{
$title = sprintf(__('%s Ambiguous Revision'), (string) $request->project);
$commit = $match[2];
$redirect = $match[3];
$scm = IDF_Scm::get($request->project);
$revisions = $scm->disambiguateRevision($commit);
$params = array(
'page_title' => $title,
'title' => $title,
'commit' => $commit,
'revisions' => $revisions,
'redirect' => $redirect,
);
return Pluf_Shortcuts_RenderToResponse('idf/source/disambiguate_revision.html',
$params, $request);
}
public $changeLog_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
public function changeLog($request, $match)
{
$scm = IDF_Scm::get($request->project);
if (!$scm->isAvailable()) {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
array($request->project->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
$branches = $scm->getBranches();
$commit = $match[2];
if (!$scm->isValidRevision($commit)) {
if (count($branches) == 0) {
// Redirect to the project source help
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
array($request->project->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::changeLog',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($url);
}
$title = sprintf(__('%1$s %2$s Change Log'), (string) $request->project,
$this->getScmType($request));
$changes = $scm->getChangeLog($commit, 25);
$request);
}
public $treeBase_precond = array('IDF_Precondition::accessSource');
public $treeBase_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
public function treeBase($request, $match)
{
$scm = IDF_Scm::get($request->project);
if (!$scm->isAvailable()) {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
array($request->project->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
$commit = $match[2];
$cobject = $scm->getCommit($commit);
if (!$cobject) {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($url);
throw new Exception('could not retrieve commit object for '. $commit);
}
$title = sprintf(__('%1$s %2$s Source Tree'),
$request->project, $this->getScmType($request));
$request);
}
public $tree_precond = array('IDF_Precondition::accessSource');
public $tree_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
public function tree($request, $match)
{
$scm = IDF_Scm::get($request->project);
$commit = $match[2];
if (!$scm->isAvailable()) {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
array($request->project->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
$fburl = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
$request_file = $match[3];
if (substr($request_file, -1) == '/') {
$request_file = substr($request_file, 0, -1);
$request_file));
return new Pluf_HTTP_Response_Redirect($url, 301);
}
if (!$scm->isValidRevision($commit)) {
// Redirect to the first branch
return new Pluf_HTTP_Response_Redirect($fburl);
}
$request_file_info = $scm->getPathInfo($request_file, $commit);
if (!$request_file_info) {
// Redirect to the first branch
// Redirect to the main branch
$fburl = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($fburl);
}
$branches = $scm->getBranches();
return '<span class="breadcrumb">'.implode('<span class="sep">'.$sep.'</span>', $out).'</span>';
}
public $commit_precond = array('IDF_Precondition::accessSource');
public $commit_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
public function commit($request, $match)
{
$scm = IDF_Scm::get($request->project);
$commit = $match[2];
if (!$scm->isValidRevision($commit)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($url);
}
$large = $scm->isCommitLarge($commit);
$cobject = $scm->getCommit($commit, !$large);
if (!$cobject) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($url);
throw new Exception('could not retrieve commit object for '. $commit);
}
$title = sprintf(__('%s Commit Details'), (string) $request->project);
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
$request);
}
public $downloadDiff_precond = array('IDF_Precondition::accessSource');
public $downloadDiff_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
public function downloadDiff($request, $match)
{
$scm = IDF_Scm::get($request->project);
$commit = $match[2];
if (!$scm->isValidRevision($commit)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($url);
}
$cobject = $scm->getCommit($commit, true);
if (!$cobject) {
throw new Exception('could not retrieve commit object for '. $commit);
}
$rep = new Pluf_HTTP_Response($cobject->changes, 'text/plain');
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$commit.'.diff"';
return $rep;
* Get a given file at a given commit.
*
*/
public $getFile_precond = array('IDF_Precondition::accessSource');
public $getFile_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
public function getFile($request, $match)
{
$scm = IDF_Scm::get($request->project);
$commit = $match[2];
$request_file = $match[3];
if (!$scm->isValidRevision($commit)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($url);
}
$request_file_info = $scm->getPathInfo($request_file, $commit);
if (!$request_file_info or $request_file_info->type == 'tree') {
// Redirect to the first branch
* Get a zip archive of the current commit.
*
*/
public $download_precond = array('IDF_Precondition::accessSource');
public $download_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
public function download($request, $match)
{
$commit = trim($match[2]);
$scm = IDF_Scm::get($request->project);
if (!$scm->isValidRevision($commit)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$scm->getMainBranch()));
return new Pluf_HTTP_Response_Redirect($url);
}
$base = $request->project->shortname.'-'.$commit;
$cmd = $scm->getArchiveCommand($commit, $base.'/');
$rep = new Pluf_HTTP_Response_CommandPassThru($cmd, 'application/x-zip');
return $rep;
}
/**
* Find the mime type of a requested file.
*
return $res;
}
/**
* Find the mime type of a file.
*
substr($string, -($length - $preflen - mb_strlen($ellipse)));
}
class IDF_Views_Source_Precondition
{
/**
* Ensures that the configured SCM for the project is available
*
* @param $request
* @return true | Pluf_HTTP_Response_Redirect
*/
static public function scmAvailable($request)
{
$scm = IDF_Scm::get($request->project);
if (!$scm->isAvailable()) {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
array($request->project->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
return true;
}
/**
* Validates the revision given in the URL path and acts accordingly
*
* @param $request
* @return true | Pluf_HTTP_Response_Redirect
* @throws Exception
*/
static public function revisionValid($request)
{
list($url_info, $url_matches) = $request->view;
list(, $project, $commit) = $url_matches;
$scm = IDF_Scm::get($request->project);
$res = $scm->validateRevision($commit);
switch ($res) {
case IDF_Scm::REVISION_VALID:
return true;
case IDF_Scm::REVISION_INVALID:
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::invalidRevision',
array($request->project->shortname, $commit));
return new Pluf_HTTP_Response_Redirect($url);
case IDF_Scm::REVISION_AMBIGUOUS:
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::disambiguateRevision',
array($request->project->shortname,
$commit,
$url_info['model'].'::'.$url_info['method']));
return new Pluf_HTTP_Response_Redirect($url);
default:
throw new Exception('unknown validation result: '. $res);
}
}
}
src/IDF/conf/urls.php
148148
149149
150150
151
152
153
154
155
156
157
158
159
160
151161
152162
153163
'model' => 'IDF_Views_Source',
'method' => 'help');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/invalid/([^/]+)/$#',
'base' => $base,
'model' => 'IDF_Views_Source',
'method' => 'invalidRevision');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/disambiguate/([^/]+)/from/([^/]+)/$#',
'base' => $base,
'model' => 'IDF_Views_Source',
'method' => 'disambiguateRevision');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/tree/([^/]+)/$#',
'base' => $base,
'model' => 'IDF_Views_Source',
src/IDF/templates/idf/source/base.html
11
22
33
4
4
55
66
77
{extends "idf/base.html"}
{block tabsource} class="active"{/block}
{block subtabs}
{if !$inHelp and (in_array($commit, $tree_in) or (in_array($commit, $tags_in)))}{assign $currentCommit = $commit}{else}{assign $currentCommit = $project.getScmRoot()}{/if}
{if !$inHelp and !$inError and (in_array($commit, $tree_in) or (in_array($commit, $tags_in)))}{assign $currentCommit = $commit}{else}{assign $currentCommit = $project.getScmRoot()}{/if}
<div id="sub-tabs">
<a {if $inSourceTree}class="active" {/if}href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $currentCommit)}">{trans 'Source Tree'}</a> |
<a {if $inChangeLog}class="active" {/if}href="{url 'IDF_Views_Source::changeLog', array($project.shortname, $currentCommit)}">{trans 'Change Log'}</a>
src/IDF/templates/idf/source/disambiguate_revision.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{extends "idf/source/base.html"}
{block docclass}yui-t2{assign $inError=true}{/block}
{block body}
<p>{blocktrans}The revision identifier <b>{$commit}</b> is ambiguous and can be
expanded to multiple valid revisions - please choose one:{/blocktrans}</p>
<table summary="" class="tree-list">
<thead>
<tr>
<th>{trans 'Title'}</th>
<th>{trans 'Author'}</th>
<th>{trans 'Date'}</th>
<th>{trans 'Branch'}</th>
<th>{trans 'Revision'}</th>
</tr>
</thead>
<tbody>
{foreach $revisions as $revision}
{aurl 'url', $redirect, array($project.shortname, $revision.commit)}
<tr class="log">
<td>{$revision.title}</td>
<td>{$revision.author}</td>
<td>{$revision.date}</td>
<td>{$revision.branch}</td>
<td><a href="{$url}">{$revision.commit}</a></td>
</td>
</tr>
{/foreach}
</tbody>
</table>
{/block}
src/IDF/templates/idf/source/invalid_revision.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{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 $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}

Archive Download the corresponding diff file

Page rendered in 0.11888s using 14 queries.