Indefero

Indefero Commit Details


Date:2011-06-04 19:37:47 (13 years 6 months ago)
Author:Thomas Keller
Branch:develop, feature.content-md5, feature.diff-whitespace, feature.issue-of-others, feature.issue-summary, feature.search-filter, feature.webrepos, feature.wiki-default-page, release-1.2, release-1.3
Commit:638b28399e0969967b527cb931b205a81f7b4049
Parents: 1d86f036a3b31db939c188973cdc3877d6f41142
Message:Fix issues 695 and 697. Still, public keys aren't added to monotone databases for some weird reason, so issue 696 is still open.

Changes:

File differences

NEWS.mdtext
2020
2121
2222
23
24
25
26
27
2328
2429
2530
31
32
2633
2734
2835
- 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)
- Better error detection and reporting in the SyncMonotone plugin
ATTENTION: This needs Pluf 46b7f251 or newer!
## Documentation
- The documentation on the setup of the monotone plugin has been improved.
## Translations
# InDefero 1.1.2 - Thu May 26 07:42:25 2011 UTC
src/IDF/Plugin/SyncMonotone.php
2727
2828
2929
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
3053
3154
3255
......
80103
81104
82105
106
107
108
109
110
111
112
113
114
83115
84116
85
86
117
118
87119
88120
89121
90122
91123
92
93
124
125
94126
95127
96128
97129
98130
99
100
131
132
101133
102134
103135
......
131163
132164
133165
134
135
166
167
136168
137169
138170
......
140172
141173
142174
143
144
175
176
145177
146178
147179
148
149
150
180
181
182
183
151184
152185
153186
......
182215
183216
184217
185
186
187
218
219
220
221
188222
189223
190224
......
201235
202236
203237
204
238
205239
206240
207241
......
238272
239273
240274
241
242
243
275
276
277
278
244279
245280
246281
247282
248283
249284
250
285
251286
252
287
288
253289
254290
255291
......
264300
265301
266302
267
268
269
303
304
305
306
270307
271308
272309
......
280317
281318
282319
283
320
284321
285322
286323
......
291328
292329
293330
294
331
295332
296333
297334
......
315352
316353
317354
318
319
320
355
356
357
358
321359
322360
323361
......
325363
326364
327365
366
367
368
328369
329370
330371
......
361402
362403
363404
364
365
366
405
406
407
408
367409
368410
369411
......
382424
383425
384426
427
385428
386429
387
388
389
430
431
432
433
390434
391435
392436
......
401445
402446
403447
404
448
405449
406450
407451
......
409453
410454
411455
412
413
456
457
414458
415459
416460
......
422466
423467
424468
469
470
471
425472
426473
427474
......
443490
444491
445492
446
447
493
494
448495
449496
450497
......
453500
454501
455502
456
457
503
504
458505
459506
460507
461508
462509
463510
464
465
511
512
466513
467514
468515
......
473520
474521
475522
476
477
523
524
525
478526
479527
480528
......
485533
486534
487535
488
536
489537
490538
491539
......
505553
506554
507555
508
509
510
556
557
558
559
511560
512561
513562
......
528577
529578
530579
580
581
531582
532583
533584
......
556607
557608
558609
559
610
560611
561612
562613
......
598649
599650
600651
601
652
602653
603
604
654
655
656
605657
606658
607659
......
611663
612664
613665
614
666
615667
616
668
617669
618670
619671
......
623675
624676
625677
678
679
626680
627681
628682
......
672726
673727
674728
675
729
676730
677731
678732
......
693747
694748
695749
696
750
697751
698
699
752
753
754
700755
701756
702757
......
711766
712767
713768
714
715
716
769
770
771
717772
718773
719774
......
779834
780835
781836
782
837
783838
784839
785840
786841
787842
788843
789
844
790845
791846
792847
......
804859
805860
806861
807
862
808863
809864
810865
......
823878
824879
825880
826
881
827882
828883
829884
830885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
*/
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);
}
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);
}
/**
* Entry point of the plugin.
*/
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);
if ($projecttempl === false) {
throw new IDF_Scm_Exception(
__('"mtn_repositories" must be defined in your configuration file.')
$this->_diagnoseProblem(
__('"mtn_repositories" must be defined in your configuration file')
);
}
$usher_config = Pluf::f('mtn_usher_conf', false);
if (!$usher_config || !is_writable($usher_config)) {
throw new IDF_Scm_Exception(
__('"mtn_usher_conf" does not exist or is not writable.')
$this->_diagnoseProblem(
__('"mtn_usher_conf" does not exist or is not writable')
);
}
$mtnpostpush = realpath(dirname(__FILE__) . '/../../../scripts/mtn-post-push');
if (!file_exists($mtnpostpush)) {
throw new IDF_Scm_Exception(sprintf(
__('Could not find mtn-post-push script "%s".'), $mtnpostpush
$this->_diagnoseProblem(sprintf(
__('Could not find mtn-post-push script "%s"'), $mtnpostpush
));
}
}
foreach ($confdir_contents as $content) {
if (!file_exists($confdir.$content)) {
throw new IDF_Scm_Exception(sprintf(
__('The configuration file %s is missing.'), $content
$this->_diagnoseProblem(sprintf(
__('The configuration file "%s" is missing'), $content
));
}
}
$shortname = $project->shortname;
$projectpath = sprintf($projecttempl, $shortname);
if (file_exists($projectpath)) {
throw new IDF_Scm_Exception(sprintf(
__('The project path %s already exists.'), $projectpath
$this->_diagnoseProblem(sprintf(
__('The project path "%s" already exists'), $projectpath
));
}
if (!mkdir($projectpath)) {
throw new IDF_Scm_Exception(sprintf(
__('The project path %s could not be created.'), $projectpath
if (!@mkdir($projectpath)) {
$this->_diagnoseProblem(sprintf(
__('The project path "%s" could not be created'),
$projectpath
));
}
//
$keydir = Pluf::f('tmp_folder').'/mtn-client-keys';
if (!file_exists($keydir)) {
if (!mkdir($keydir)) {
throw new IDF_Scm_Exception(sprintf(
__('The key directory %s could not be created.'), $keydir
if (!@mkdir($keydir)) {
$this->_diagnoseProblem(sprintf(
__('The key directory "%s" could not be created'),
$keydir
));
}
}
$parsed_keyinfo = IDF_Scm_Monotone_BasicIO::parse($keyinfo);
}
catch (Exception $e) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('Could not parse key information: %s'), $e->getMessage()
));
}
foreach ($confdir_contents as $content) {
$filepath = $projectpath.'/'.$content;
if (substr($content, -1) == '/') {
if (!mkdir($filepath)) {
throw new IDF_Scm_Exception(sprintf(
__('Could not create configuration directory "%s"'), $filepath
if (!@mkdir($filepath)) {
$this->_diagnoseProblem(sprintf(
__('Could not create configuration directory "%s"'),
$filepath
));
}
continue;
}
if (substr($content, -3) != '.in') {
if (!symlink($confdir.$content, $filepath)) {
if (!@symlink($confdir.$content, $filepath)) {
IDF_Scm_Exception(sprintf(
__('Could not create symlink "%s"'), $filepath
__('Could not create symlink for configuration file "%s"'),
$filepath
));
}
continue;
// remove the .in
$filepath = substr($filepath, 0, -3);
if (file_put_contents($filepath, $filecontents, LOCK_EX) === false) {
throw new IDF_Scm_Exception(sprintf(
__('Could not write configuration file "%s"'), $filepath
if (@file_put_contents($filepath, $filecontents, LOCK_EX) === false) {
$this->_diagnoseProblem(sprintf(
__('Could not write configuration file "%s"'),
$filepath
));
}
}
$parsed_config = IDF_Scm_Monotone_BasicIO::parse($usher_rc);
}
catch (Exception $e) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('Could not parse usher configuration in "%s": %s'),
$usher_config, $e->getMessage()
));
foreach ($stanzas as $stanza_line) {
if ($stanza_line['key'] == 'server' &&
$stanza_line['values'][0] == $shortname) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('usher configuration already contains a server '.
'entry named "%s"'),
$shortname
// FIXME: more sanity - what happens on failing writes? we do not
// have a backup copy of usher.conf around...
if (file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
throw new IDF_Scm_Exception(sprintf(
__('Could not write usher configuration file "%s"'), $usher_config
if (@file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
$this->_diagnoseProblem(sprintf(
__('Could not write usher configuration file "%s"'),
$usher_config
));
}
// step 6) reload usher to pick up the new configuration
//
IDF_Scm_Monotone_Usher::reload();
// commit the guard, so the newly created project is not deleted
$projectGuard->commit();
}
/**
$write_permissions = implode("\n", $key_ids);
$rcfile = $projectpath.'/write-permissions';
if (file_put_contents($rcfile, $write_permissions, LOCK_EX) === false) {
throw new IDF_Scm_Exception(sprintf(
__('Could not write write-permissions file "%s"'), $rcfile
if (@file_put_contents($rcfile, $write_permissions, LOCK_EX) === false) {
$this->_diagnoseProblem(sprintf(
__('Could not write write-permissions file "%s"'),
$rcfile
));
}
array('key' => 'allow', 'values' => array('*')),
);
}
$read_permissions = IDF_Scm_Monotone_BasicIO::compile(array($stanza));
$rcfile = $projectpath.'/read-permissions';
if (file_put_contents($rcfile, $read_permissions, LOCK_EX) === false) {
throw new IDF_Scm_Exception(sprintf(
__('Could not write read-permissions file "%s"'), $rcfile
if (@file_put_contents($rcfile, $read_permissions, LOCK_EX) === false) {
$this->_diagnoseProblem(sprintf(
__('Could not write read-permissions file "%s"'),
$rcfile
));
}
$serverRestartRequired = false;
if ($project->private && file_exists($projectfile) && is_link($projectfile)) {
if (!unlink($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(
if (!@symlink($templatefile, $projectfile)) {
$this->_diagnoseProblem(sprintf(
__('Could not create symlink "%s"'), $projectfile
));
}
// seems to be ignored when the server should be started
// again immediately afterwards
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);
}
}
$usher_config = Pluf::f('mtn_usher_conf', false);
if (!$usher_config || !is_writable($usher_config)) {
throw new IDF_Scm_Exception(
__('"mtn_usher_conf" does not exist or is not writable.')
$this->_diagnoseProblem(
__('"mtn_usher_conf" does not exist or is not writable')
);
}
$projecttempl = Pluf::f('mtn_repositories', false);
if ($projecttempl === false) {
throw new IDF_Scm_Exception(
__('"mtn_repositories" must be defined in your configuration file.')
$this->_diagnoseProblem(
__('"mtn_repositories" must be defined in your configuration file')
);
}
$projectpath = sprintf($projecttempl, $shortname);
if (file_exists($projectpath)) {
if (!self::_delete_recursive($projectpath)) {
throw new IDF_Scm_Exception(sprintf(
__('One or more paths underknees %s could not be deleted.'), $projectpath
$this->_diagnoseProblem(sprintf(
__('One or more paths underneath %s could not be deleted'), $projectpath
));
}
}
if ($keyname && $keyhash &&
file_exists($keydir .'/'. $keyname . '.' . $keyhash)) {
if (!@unlink($keydir .'/'. $keyname . '.' . $keyhash)) {
throw new IDF_Scm_Exception(sprintf(
__('Could not delete client private key %s'), $keyname
$this->_diagnoseProblem(sprintf(
__('Could not delete client private key "%s"'),
$keyname
));
}
}
$parsed_config = IDF_Scm_Monotone_BasicIO::parse($usher_rc);
}
catch (Exception $e) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('Could not parse usher configuration in "%s": %s'),
$usher_config, $e->getMessage()
));
// FIXME: more sanity - what happens on failing writes? we do not
// have a backup copy of usher.conf around...
if (file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
throw new IDF_Scm_Exception(sprintf(
__('Could not write usher configuration file "%s"'), $usher_config
if (@file_put_contents($usher_config, $usher_rc, LOCK_EX) === false) {
$this->_diagnoseProblem(sprintf(
__('Could not write usher configuration file "%s"'),
$usher_config
));
}
return;
}
$keyGuard = new IDF_Plugin_SyncMonotone_ModelGuard($key);
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
$conf = new IDF_Conf();
$conf->setProject($project);
$parsed_read_perms = IDF_Scm_Monotone_BasicIO::parse($read_perms);
}
catch (Exception $e) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('Could not parse read-permissions for project "%s": %s'),
$shortname, $e->getMessage()
));
$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) {
throw new IDF_Scm_Exception(sprintf(
__('Could not write read-permissions for project "%s"'), $shortname
$this->_diagnoseProblem(sprintf(
__('Could not write read-permissions for project "%s"'),
$shortname
));
}
}
if (!in_array('*', $lines) && !in_array($mtn_key_id, $lines)) {
$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) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('Could not write write-permissions file for project "%s"'),
$shortname
));
$stdio = $mtn->getStdio();
$stdio->exec(array('put_public_key', $key->content));
}
$key->commit();
}
/**
$parsed_read_perms = IDF_Scm_Monotone_BasicIO::parse($read_perms);
}
catch (Exception $e) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('Could not parse read-permissions for project "%s": %s'),
$shortname, $e->getMessage()
));
$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) {
throw new IDF_Scm_Exception(sprintf(
__('Could not write read-permissions for project "%s"'), $shortname
$this->_diagnoseProblem(sprintf(
__('Could not write read-permissions for project "%s"'),
$shortname
));
}
}
continue;
}
}
if (file_put_contents($projectpath.'/write-permissions',
implode("\n", $lines) . "\n", LOCK_EX) === false) {
throw new IDF_Scm_Exception(sprintf(
if (@file_put_contents($projectpath.'/write-permissions',
implode("\n", $lines) . "\n", LOCK_EX) === false) {
$this->_diagnoseProblem(sprintf(
__('Could not write write-permissions file for project "%s"'),
$shortname
));
{
$projecttempl = Pluf::f('mtn_repositories', false);
if ($projecttempl === false) {
throw new IDF_Scm_Exception(
$this->_diagnoseProblem(
__('"mtn_repositories" must be defined in your configuration file.')
);
}
$projectpath = sprintf($projecttempl, $project->shortname);
if (!file_exists($projectpath)) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('The project path %s does not exists.'), $projectpath
));
}
$output = $return = null;
exec($fullcmd, $output, $return);
if ($return != 0) {
throw new IDF_Scm_Exception(sprintf(
$this->_diagnoseProblem(sprintf(
__('The command "%s" could not be executed.'), $cmd
));
}
foreach ($scan as $subpath) {
$status |= self::_delete_recursive($subpath);
}
$status |= rmdir($path);
$status |= @rmdir($path);
return $status;
}
}
}
/**
* 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;
}
}

Archive Download the corresponding diff file

Page rendered in 0.09414s using 16 queries.