/[drupal]/contributions/modules/autopilot/autopilot.module
ViewVC logotype

Contents of /contributions/modules/autopilot/autopilot.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.6 - (show annotations) (download) (as text)
Thu Oct 9 21:35:48 2008 UTC (13 months, 2 weeks ago) by souvent22
Branch: MAIN
CVS Tags: DRUPAL-5--2-0-BETA4, DRUPAL-5--2-0-BETA3, DRUPAL-5--1-4, DRUPAL-5--1-3, HEAD
Changes since 1.5: +10 -4 lines
File MIME type: text/x-php
Patching WSOD issue.
1 <?php
2 define('AUTOPILOT_OSTYPE_WINDOWS', 1);
3 define('AUTOPILOT_OSTYPE_LINUX', 2);
4
5 define('AUTOPILOT_OWNERSHIP_NORMAL', 1);
6 define('AUTOPILOT_OWNERSHIP_GLOBAL', 2);
7 define('AUTOPILOT_OWNERSHIP_TEMPLATE', 3);
8
9 define('AUTOPILOT_DEBUG_MODE', true);
10
11 define('AUTOPILOT_MAIL_KEY', 'autopilot');
12
13 /**
14 * Implementation of hook_help
15 * Since our help section is rather large,
16 * it is delegated to a seperate file.
17 * The file is included, and the function is passed off
18 * to this helper function/file.
19 */
20 function autopilot_help($section) {
21 require_once(drupal_get_path('module', 'autopilot') . '/autopilot_help.inc');
22 return _autopilot_help($section);
23 }
24
25 function autopilot_menu($maycache = false) {
26 _autopilot_init();
27 _autopilot_get_autopilot();
28 $items = array();
29
30 $maycache = true; // For debugging
31 $user_edit_autopilots = user_access('autopilot admin');
32 $user_view_autopilots = user_access('autopilot view') | user_access('autopilot build user');
33 $items[] = array(
34 'path' => 'admin/autopilot',
35 'title' => t('Autopilot'),
36 'callback' => 'admin_autopilot_page',
37 'access' => user_access('autopilot admin'),
38 );
39 if($maycache) {
40 # Main AutoPilot overview
41
42 $items[] = array(
43 'path' => 'autopilot',
44 'title' => t('Autopilots'),
45 'type' => MENU_NORMAL_ITEM,
46 'callback' => 'autopilot_page',
47 'access' => $user_view_autopilots,
48 );
49 $items[] = array(
50 'path' => 'autopilot/select',
51 'title' => t('Selects an autopilot.'),
52 'type' => MENU_CALLBACK,
53 'callback' => '_autopilot_select_autopilot',
54 'access' => $user_view_autopilots,
55 );
56
57 # Overview
58 $items[] = array(
59 'path' => 'autopilot/overview',
60 'title' => t('Home'),
61 'type' => MENU_DEFAULT_LOCAL_TASK,
62 'callback' => 'autopilot_page',
63 'access' => $user_view_autopilots,
64 'weight' => -1,
65 );
66 }
67
68 // Autopilot/Home Section
69 // For buildplan
70 $items[] = array(
71 'path' => 'autopilot/buildplans',
72 'title' => t('Build Plans'),
73 'type' => MENU_LOCAL_TASK,
74 'callback' => 'buildplan_overview_page',
75 'callback arguments' => array(arg(2), arg(4)),
76 'access' => $user_view_autopilots,
77 'weight' => -1,
78 );
79 if(arg(1) == 'buildplans' && is_numeric(arg(2))) {
80 $items[] = array(
81 'path' => 'autopilot/buildplans/' . arg(2) ,
82 'title' => t('Overview'),
83 'type' => MENU_LOCAL_TASK,
84 'callback' => 'buildplan_view_page',
85 'callback arguments' => array(arg(2)),
86 'access' => $user_view_autopilots,
87 'weight' => -1,
88 );
89 $items[] = array(
90 'path' => 'autopilot/buildplans/' . arg(2) . '/buildrun_log',
91 'title' => t('Build Run Logs'),
92 'type' => MENU_LOCAL_TASK,
93 'callback' => 'buildrun_log',
94 'callback arguments' => array(arg(3)),
95 'access' => $user_view_autopilots,
96 );
97 $items[] = array(
98 'path' => 'autopilot/buildplans/' . arg(2) . '/buildrun_log/' . arg(4),
99 'title' => t('Run Log'),
100 'type' => MENU_LOCAL_TASK,
101 'callback' => 'buildrun_log_view',
102 'callback arguments' => array(arg(4)),
103 'access' => $user_edit_autopilots,
104 );
105 $items[] = array(
106 'path' => 'autopilot/buildplans/' . arg(2) . '/maintinance',
107 'title' => t('Maintianance'),
108 'type' => MENU_LOCAL_TASK,
109 'callback' => 'buildplan_maintianance',
110 'callback arguments' => array(arg(2)),
111 'access' => $user_edit_autopilots,
112 );
113 }
114
115 // Setup Section
116 $items[] = array(
117 'path' => 'autopilot/setup',
118 'title' => t('Setup'),
119 'type' => MENU_LOCAL_TASK,
120 'callback' => 'autopilot_setup_overview',
121 'access' => user_access('autopilot admin'),
122 );
123 # Database Section
124 $items[] = array(
125 'path' => 'autopilot/database',
126 'title' => t('Database'),
127 'type' => MENU_LOCAL_TASK,
128 'callback' => 'autopilot_database_overview',
129 'access' => user_access('autopilot database admin') | user_access('autopilot admin'),
130 );
131 $items[] = array(
132 'path' => 'autopilot/database/tx',
133 'title' => t('Transfer Database'),
134 'type' => MENU_DEFAULT_LOCAL_TASK,
135 'callback' => 'drupal_get_form',
136 'callback arguments' => array('autopilot_database_transfer_form'),
137 'access' => user_access('autopilot database admin') | user_access('autopilot admin'),
138 );
139 # Build Plans
140 $items[] = array(
141 'path' => 'autopilot/setup/buildplans',
142 'title' => t('Build Plans'),
143 'type' => MENU_LOCAL_TASK,
144 'callback' => 'buildplan_overview_page',
145 'callback arguments' => array(arg(3), arg(4)),
146 'access' => $user_view_autopilots,
147 );
148
149 # Builds
150 $items[] = array(
151 'path' => 'autopilot/setup/builds',
152 'title' => t('Builds'),
153 'type' => MENU_LOCAL_TASK,
154 'callback' => 'builds_page',
155 'callback arguments' => array(arg(3), arg(4)),
156 'access' => $user_edit_autopilots,
157 );
158 $items[] = array(
159 'path' => 'autopilot/setup/builds/add',
160 'type' => MENU_CALLBACK,
161 'title' => t('Add a build to a BuildPlan'),
162 'access' => $user_edit_autopilots,
163 'callback' => 'ap_build_edit_page',
164 );
165 $items[] = array(
166 'path' => 'autopilot/setup/targets',
167 'title' => t('Targets'),
168 'type' => MENU_LOCAL_TASK,
169 'callback' => 'targets_page',
170 'callback arguments' => array(arg(3), arg(4)),
171 'access' => $user_edit_autopilots,
172 );
173
174
175 /*
176 $items[] = array(
177 'path' => 'autopilot/commands',
178 'title' => t('Commands'),
179 'type' => MENU_LOCAL_TASK,
180 'callback' => 'commands_page',
181 'callback arguments' => array(arg(2), arg(3)),
182 'access' => user_access('autopilot view'),
183 );
184
185 $items[] = array(
186 'path' => 'autopilot/channels',
187 'title' => t('Channels'),
188 'type' => MENU_LOCAL_TASK,
189 'callback' => 'channels_page',
190 'callback arguments' => array(arg(2), arg(3)),
191 'access' => user_access('autopilot view'),
192 );
193
194 */
195
196
197 $items[] = array(
198 'path' => 'admin/settings/autopilot',
199 'title' => t('Autopilot'),
200 'callback' => 'drupal_get_form',
201 'description' => t('Global and general settings (cipher keys, path locations, etc.) for the Autopilot system.'),
202 'callback arguments' => 'autopilot_settings',
203 'access' => user_access('autopilot admin'));
204 # Label Settings
205 $items[] = array(
206 'path' => 'admin/autopilot/labels',
207 'title' => t('Label Settings'),
208 'callback' => 'autopilot_label_settings',
209 'access' => user_access('autopilot admin'),
210 );
211 $items[] = array(
212 'path' => 'admin/autopilot/labels/add',
213 'title' => t('Create Labels'),
214 'callback' => 'drupal_get_form',
215 'callback arguments' => array('autopilot_label_types_form'),
216 'type' => MENU_CALLBACK,
217 'access' => user_access('autopilot admin'),
218 );
219
220 $ajax_menu = _autopilot_ajax_menu();
221
222 $items = array_merge($items, $ajax_menu);
223 return $items;
224 }
225
226 function autopilot_settings() {
227 $form = array();
228 $form['autopilot_tmp_path'] = array(
229 '#type' => 'textfield',
230 '#title' => t('Temp Directory'),
231 '#description' => t('This is the directory that is used during builds.'),
232 '#default_value' => variable_get('autopilot_tmp_path', file_directory_temp()));
233 $form['autopilot_custom_navigation'] = array(
234 '#type' => 'checkbox',
235 '#title' => t('Use a custom navigation scheme'),
236 '#description' => t('This takes away the default setup of tabs, links, etc. and allows one
237 to setup their own navigation scheme.'),
238 '#default_value' => variable_get('autopilot_custom_navigation', false),
239 );
240 $form['autopilot_cipher_key'] = array(
241 '#type' => 'textfield',
242 '#title' => t('Cipher Key'),
243 '#description' => t('This is the key that will be used to encrypt your information.'),
244 '#default_value' => variable_get('autopilot_cipher_key', variable_get('drupal_private_key', null)),
245 );
246 return system_settings_form($form);
247 }
248
249 function autopilot_label_settings() {
250 if(is_numeric(arg(3))) {
251 return autopilot_label_page(arg(3), arg(4));
252 }
253 $page = '<h2>' . t('Current Label Types') . '</h2>';
254 $page .= l( theme('image',
255 drupal_get_path('module', 'autopilot') . '/media/images/bookmark-new.png'
256 ),
257 'admin/autopilot/labels/add',
258 array(),
259 NULL,
260 NULL,
261 FALSE,
262 TRUE
263 ) . ' - ' . t('Add New Label');
264 $rs = db_query("SELECT * FROM {ap_label_types}");
265 $row = array();
266 $rows = array();
267 while($type = db_fetch_object($rs)) {
268 $row = array();
269 $links = array();
270 $links[] = array(
271 'href' => 'admin/autopilot/labels/' . $type->lid . '/edit',
272 'title' => t('edit'),
273 );
274 $row[] = $type->short_title;
275 $row[] = $type->title;
276 $row[] = theme('links', $links);
277 $rows[] = $row;
278 }
279 if(count($rows) > 0) {
280 $header = array(t('Short Title'), t('Title'), ' ');
281 $page .= theme('table', $header, $rows);
282 }
283 else {
284 $page .= t('You have no label types defined. Define some new target
285 types !new_type_link.',
286 array('!new_type_link' => l(t('here'), 'admin/autopilot/labels/add'))
287 );
288 }
289 return $page;
290 }
291
292 function autopilot_label_page($lid = null, $action = null) {
293 if($action == 'edit') {
294 return drupal_get_form('autopilot_label_types_form', $lid);
295 }
296 else {
297 $type = db_fetch_object(db_query("SELECT * FROM {ap_label_types} WHERE lid = %d", $lid));
298 $page .= '<h2>' . t('Items Tagged as %tag_name', array('%tag_name' => $type->title)) . '</h2>';
299 }
300 }
301
302 /**
303 * Form to create/edit a label type
304 * @param int $tid ID of a type to edit
305 * @return
306 */
307 function autopilot_label_types_form($lid = null) {
308 $type = db_fetch_array(db_query("SELECT * FROM {ap_label_types} WHERE lid = %d", $lid));
309 $form = array();
310 $form['title'] = array(
311 '#type' => 'textfield',
312 '#title' => t('Type Title/Name'),
313 '#default_value' => $type['title'],
314 );
315 $form['short_title'] = array(
316 '#type' => 'textfield',
317 '#title' => t('Short Title'),
318 '#description' => t('A short title, no longer than 10 letters, to descirption the type. E.g. "DEV", or "PROD".'),
319 '#default_value' => $type['short_title'],
320 '#size' => 10,
321 );
322 $form['description'] = array(
323 '#type' => 'textarea',
324 '#title' => t('Description'),
325 '#default_value' => $type['description'],
326 );
327 if($lid != null) {
328 $form['lid'] = array('#type' => 'hidden', '#value' => $lid);
329 $form['update'] = array(
330 '#type' => 'submit',
331 '#value' => t('Update'),
332 );
333 $form['cancel'] = array(
334 '#value' => l(t('Cancel'), 'admin/autopilot/labels')
335 );
336 }
337 else {
338 $form['go'] = array(
339 '#type' => 'submit',
340 '#value' => t('Submit'),
341 );
342 $form['cancel'] = array(
343 '#value' => l(t('Cancel'), 'admin/autopilot/labels')
344 );
345 }
346
347 return $form;
348 }
349 /**
350 * Implementation of hook_submit for the target types form
351 * autopilot_target_types_form
352 * @param String $form_id ID of rhe form
353 * @param mixed $form_values Submission values
354 * @return URL Path to go to after submission
355 */
356 function autopilot_label_types_form_submit($form_id, $form_values) {
357 if(isset($form_values['lid'])) {
358 db_query("UPDATE {ap_label_types}
359 SET title = '%s', short_title = '%s',
360 description = '%s' WHERE lid = %d",
361 $form_values['title'], $form_values['short_title'],
362 $form_values['description'], $form_values['lid']);
363 drupal_set_message(t('Updated label type %type.',
364 array('%type' => $form_values['title'])));
365 }
366 else {
367 $lid = db_next_id('{ap_label_types}_lid');
368 drupal_set_message(t('Created the new label %type.',
369 array('%type' => $form_values['title'])));
370 db_query("INSERT INTO {ap_label_types}(lid, title, short_title, description)
371 VALUES(%d, '%s', '%s', '%s')",
372 $lid, $form_values['title'], $form_values['short_title'],
373 $form_values['description']);
374 }
375 return 'admin/autopilot/labels';
376 }
377
378 function admin_autopilot_page() {
379 $page = '';
380
381 // Diagnostics
382 $stats = variable_get('autopilot_system_diagnostics', serialize(array()));
383 $stats = unserialize($stats);
384 $page .= '<p>' . t('Diagnostics last run') . ': <strong>';
385 $page .= $stats['last_run'] > 0 ? format_date($stats['last_run'], 'large') : t('Never');
386 $page .= '</strong></p>';
387 $page .= drupal_get_form('autopilot_diagnostics_form', 'system');
388 return $page;
389 }
390
391 // Function runs the diagnostics for the system.
392 function autopilot_diagnostics_form($type = 'system') {
393 $stats = variable_get('autopilot_system_diagnostics', serialize(array()));
394 $stats = unserialize($stats);
395 $form = '';
396 $form['log4php_stats'] = array(
397 '#type' => 'fieldset',
398 '#title' => t('Log4PHP Status'),
399 '#collapsible' => true,
400 '#collapsed' => true,
401 );
402 $form['log4php_stats']['#theme'] = 'diagnostics_status_table';
403 $form['log4php_stats']['log_db_check'] = array(
404 '#type' => 'markup',
405 '#title' => t('Write to DB Log Check'),
406 '#value' => '<p><strong>' . ($stats['log_db_check'] >= 1) ? 'OK' : 'FAILED' . '</strong></p>'
407 );
408 $form['run'] = array(
409 '#type' => 'submit',
410 '#value' => t('Run Diagnostics'),
411 );
412 return $form;
413 }
414 // Runs the diagnostics
415 function autopilot_diagnostics_form_submit($form_id, $form_values) {
416 $stats = array();
417 $stats['last_run'] = time();
418 // Run the Log4PHP Check
419 $logger = 'diagnostics';
420 $log = LoggerManager::getLogger($logger);
421 db_query("DELETE FROM {autopilot_logger} WHERE logger = '%s'", $logger);
422 $log->info('Running log Diagnostics');
423 $stats['log_db_check'] = db_result(db_query("SELECT COUNT(*) FROM {autopilot_logger} WHERE logger = '%s'", $logger));
424 db_query("DELETE FROM {autopilot_logger} WHERE logger = '%s'", $logger);
425 variable_set('autopilot_system_diagnostics', serialize($stats));
426 return;
427 }
428 function theme_diagnostics_status_table($form_values) {
429 $i = 0;
430 $header = array(t('Variable'), t('Status'));
431 $rows = array();
432 $row = array();
433 // TODO Make prettier
434 foreach(element_children($form_values) as $key) {
435 // Render to the row
436 $row = array();
437 $row[] = $form_values[$key]['#title'];
438 unset($form_values[$key]['#title']);
439 $row[] = drupal_render($form_values[$key]);
440 $rows[] = $row;
441 }
442 return theme('table', $header, $rows);
443 }
444
445
446 function autopilot_setup_overview() {
447 $page = '';
448 $page .= 'This page will have a description/overview of the current setup,
449 number of users, etc. and links to "help" items.';
450
451 return $page;
452 }
453
454 /**
455 * Implementation of hook_link
456 */
457 function autopilot_link($type, $node = NULL, $teaser = FALSE) {
458 $links = array();
459 if($node->type == 'autopilot') {
460 $link['href'] = 'autopilot/select/' . $node->nid;
461 $link['title'] = t('View AutoPilot');
462 $links[] = $link;
463 }
464 return $links;
465 }
466
467 /**
468 * Function selects an autopilot, and applies it to the session
469 * programatically.
470 */
471 function _autopilot_select_autopilot() {
472 $apid = arg(2);
473 _autopilot_get_apid($apid);
474 drupal_goto('autopilot');
475 }
476
477 function autopilot_perm() {
478 return array('autopilot admin',
479 'autopilot database admin',
480 'autopilot view',
481 'autopilot create autopilot',
482 'autopilot edit autopilot',
483 'autopilot create buildplan global',
484 'autopilot create buildplan user',
485 'autopilot build user',
486 'autopliot build global');
487 }
488
489 /**
490 *Implementation of hook_node_info
491 */
492 function autopilot_node_info() {
493 return array(
494 'autopilot' => array(
495 'name' => t('AutoPilot'),
496 'module' => 'autopilot',
497 'description' => t('This an AutoPilot which allows you to create a build,
498 and push that build to a target.'),
499 ),
500 );
501 }
502
503 /**
504 *Implementation of hook_block
505 */
506 function autopilot_block($op = 'list', $delta = 0) {
507 if($op == 'list') {
508 $block[0]['info'] = t('My AutoPilots');
509 return $block;
510 }
511 else {
512 if($delta == 0) {
513 $block_content = '';
514 $nodes = node_load(array('type' => 'autopilot'));
515
516 $block['subject'] = t('My AutoPilots');
517 $block['content'] = $block_content ;
518 }
519
520 return $block;
521 }
522
523
524 }
525
526 /**
527 *Implementation of hook_node_access
528 */
529 function autopilot_node_access($op, $node) {
530 global $user;
531
532 if($op == 'create') {
533 return user_access('autopilot create autopilot');
534 }
535
536 if($op == 'update' || $op == 'delete') {
537 return user_access('autopilot edit autopilot');
538 }
539 }
540
541 /**
542 *Implementation of hook_form
543 */
544 function autopilot_form(&$node) {
545 $type = node_get_types('type', $node);
546
547 // We need to define form elements for the node's title and body.
548 $form['title'] = array(
549 '#type' => 'textfield',
550 '#title' => t('AutoPilot Name'),
551 '#required' => TRUE,
552 '#description' => t('A general title for this AutoPilot'),
553 '#default_value' => $node->title,
554 '#weight' => -5
555 );
556
557 $form['body_filter']['body'] = array(
558 '#type' => 'textarea',
559 '#title' => t('Description'),
560 '#default_value' => $node->body,
561 '#required' => FALSE,
562 '#description' => t('User this area to descripe what this AutoPilot is used for.'),
563 );
564 $form['body_filter']['filter'] = filter_form($node->format);
565
566 return $form;
567 }
568
569 /**
570 * Implementation of hook_insert
571 */
572 function autopilot_insert($node) {
573 db_query("INSERT INTO {autopilot}(apid, name, description)
574 VALUES(%d, '%s', '%s');", $node->nid, $node->title,
575 $node->body);
576 return;
577 }
578
579 /**
580 * Implementation of hook_delete
581 */
582 function autopilot_delete($node) {
583 db_query("DELETE FROM {autopilot} WHERE apid = %d", $node->nid);
584 return;
585 }
586
587 /**
588 * Implementation of hook_update
589 */
590 function autopilot_update($node) {
591 db_query("UPDATE {autopilot}
592 SET name = '%s', description = '%s'
593 WHERE apid = %d", $node->title, $node->body,
594 $node->nid);
595 return;
596 }
597
598 /**
599 *Implentation of hook_load
600 *We want to load ALL information about an autopilot.
601 *We may also want to look at options to do 'partial-loads'.
602 *e.g. AP_LOAD_FULL, AP_LOAD_BASE, AP_LOAD_LIGHT, etc. Because
603 *there could be a LOT of information to load.
604 */
605 function autopilot_load($node, $args = null) {
606 _autopilot_init(); // Load the neccessary files and/or classes.
607 $info = new stdClass();
608 return;
609 return $info;
610 }
611
612 /**
613 *Implementation of hook_view
614 */
615 function autopilot_view($node, $teaser = FALSE, $page = FALSE) {
616 $output = '';
617
618 $node = node_prepare($node, $teaser);
619 return $node;
620 }
621
622
623 function autopilot_page($view = 'overview') {
624 $page = '';
625 $apid = _autopilot_get_apid();
626 if(is_numeric($apid)) {
627 $autopilot = node_load($apid);
628 }
629 else {
630 $autopilot = new stdClass();
631 $autopilot->title = t('NONE SELECTED');
632 }
633 $page .= '<div class="info-box">' .
634 t('!ap_name is the currently selected autopilot.',
635 array('!ap_name' => '<strong>' . $autopilot->title . '</strong>'))
636 . drupal_get_form('autopilot_select_autopilot_form')
637 . "</div>\n";
638
639 // Step out if there is not an APID set.
640 if($apid == null) {
641 $page .= t('Please select an AutoPilot or create a new one !here', array(
642 '!here' => l('here', 'node/add/autopilot')) );
643 return $page;
644 }
645
646 // Lets build the main page
647 /**
648 * Repository overview
649 * The Repository overview aggregates ALL the build plans that are
650 * used by this autopilot and shows what changes have been made lately
651 * via the log, and what BuildPlan that change will effect.
652 */
653
654 /**
655 * Build Plan Overview
656 */
657
658 return $page;
659 }
660
661 function autopilot_select_autopilot_form($encapsulate = true) {
662 global $user;
663 $form = array();
664
665 $ars = db_query("SELECT nid, title FROM {node} WHERE type = '%s'", 'autopilot', $user->uid);
666 $aps = array();
667 while($row = db_fetch_object($ars)) {
668 $aps[$row->nid] = $row->title;
669 }
670 // Don't build a full form if we don't have any autopilots.
671 if(count($aps) == 0) {
672 $form['nothing'] = array('#value' => t('No Autopilots found.'));
673 return $form;
674 }
675
676 // Form
677 $form['apid'] = array(
678 '#type' => 'select',
679 '#title' => t('Select an AutoPilot'),
680 '#options' => $aps,
681 );
682
683 $form['submit_ap'] = array(
684 '#type' => 'submit',
685 '#value' => t('Select AutoPilot'),
686 );
687
688 if($encapsulate) {
689 $form_sub = $form;
690 $form = array();
691 $form['select_ap_sec'] = array('#type' => 'fieldset',
692 '#title' => t('Select an AutoPilot'),
693 '#collapsed' => true,
694 '#collapsible' => true,
695 );
696 foreach($form_sub as $k => $v) {
697 $form['select_ap_sec'][$k] = $v;
698 }
699 }
700
701 return $form;
702
703 }
704
705 /**
706 * @abstract Implementation of hook_submit for ap form.
707 * This sets the apid for the session to work with.
708 */
709 function autopilot_select_autopilot_form_submit($form_id, $form_values) {
710 _autopilot_get_apid($form_values['apid']);
711 drupal_set_message(t('Working AutoPilot has been changed.'));
712 return 'autopilot';
713 }
714
715 function _autopilot_get_autopilot($set_apid = null) {
716 static $autopilot;
717 if($set_apid != null) {
718 $autopilot = new AutoPilot($set_apid);
719 _autopilot_get_apid($set_apid);
720 AutoPilot::setCurrentAutoPilot($set_apid);
721 }
722 else if($autopilot == null || $autopilot == '') {
723 $autopilot = AutoPilot::setCurrentAutoPilot(_autopilot_get_apid());
724 }
725
726 return $autopilot;
727 }
728 function _autopilot_get_apid($set_apid = null) {
729 static $apid;
730 if($set_apid != null) {
731 $apid = $set_apid;
732 $_SESSION['autopilot_apid'] = $apid;
733 }
734 else if($apid == '') {
735 $apid = $_SESSION['autopilot_apid'];
736 }
737
738 return $apid;
739 }
740
741
742 // ===========================================================================
743 /**
744 *
745 * Misc function and helper functions/classes
746 *
747 */
748 // ===========================================================================
749
750 /**
751 * @abstract Initializes the files needed to
752 * work with an AutoPilot.
753 *
754 * Default log4php setup
755 * log4php.appender.default = LoggerAppenderDailyFile
756 log4php.appender.default.layout = LoggerPatternLayout
757 log4php.appender.default.layout.conversionPattern="%d{Y-m-d H:i:s} %-5p %c(%L): %m%n"
758 log4php.appender.default.fileName = /tmp/test.log
759
760 log4php.appender.stdout = LoggerAppenderEcho
761 log4php.appender.stdout.layout = LoggerPatternLayout
762 log4php.appender.stdout.layout.conversionPattern="%d{Y-m-d H:i:s} %-5p %c: %m at line %L%n<br/>"
763
764 log4php.rootLogger = DEBUG, default
765
766
767 ;log4php.logger.ActionResolver=ERROR
768 ;log4php.logger.ArtifactResolver=ERROR
769 *
770 * @return void
771 */
772 function _autopilot_init() {
773 static $loaded;
774 // Check for the security key
775
776 if($loaded === true) {
777 return;
778 }
779 // TODO: You need to do a PEAR check here!!
780 _autopilot_setup_validation();
781
782 define('LOG4PHP_CONFIGURATION', drupal_get_path('module', 'autopilot') . '/log4php/DrupalLoggerConfig.xml');
783 define('LOG4PHP_DIR', drupal_get_path('module', 'autopilot') . '/log4php');
784 require_once( LOG4PHP_DIR . '/LoggerManager.php' );
785 // Look in the includes folder for files
786 // that we MUST include. These will have
787 // the extension .inc.
788 $dir_path = drupal_get_path('module', 'autopilot') . '/includes';
789 // Interfaces first
790 _autopilot_include_files($dir_path, false, 'Interface');
791 // All others next
792 _autopilot_include_files($dir_path);
793 // File the hook
794 // TODO
795 // Do we need this?
796 module_invoke_all('autopilot_classload');
797
798 // Media init
799 _autopilot_media_init();
800 $loaded = true;
801 return;
802 }
803
804 function _autopilot_init_js() {
805 drupal_add_js(drupal_get_path('module', 'autopilot') . '/autopilot.js', 'module','header', FALSE, FALSE);
806 return;
807 }
808
809 function _autopilot_media_init() {
810 // Add the CSS
811 $module_path = drupal_get_path('module', 'autopilot');
812 drupal_add_css("$module_path/media/autopilot.css");
813 return;
814 }
815
816 function _autopilot_setup_validation() {
817 // Check for the key
818 $msg_args = array();
819 $setup_ok = true;
820 // check for pear dependencies
821 //
822 include_once('DB.php');
823 if (!class_exists('DB')) {
824 $admin_msg = t('AutoPilot requires the PEAR DB library. Either it is not installed or PEAR is not in your include path.');
825 $setup_ok = false;
826 }
827
828 if(variable_get('autopilot_cipher_key', null) == null) {
829 $setup_ok = false;
830 $admin_msg = t('The Autopilot cipher key has not been set. Please set it here.');
831 }
832 // Check for mcrypt
833 if(!function_exists('mcrypt_encrypt')) {
834 $setup_ok = false;
835 $admin_msg = t('The mcrypt php library is required for Autopilot.');
836 }
837 // Check for SSH2
838
839
840 if($setup_ok == false) {
841 drupal_set_message(t('There is a problem with your autopilot setup. Please contact your adminitrator.'), 'error');
842 if(arg(0) == 'admin') {
843 drupal_set_message($admin_msg);
844 }
845 watchdog('autopilot', $admin_msg, WATCHDOG_ERROR);
846 return $setup_ok;
847 }
848 return true;
849 }
850
851 function _autopilot_include_files($dir, $absolute = false, $filter = null) {
852 $osinfo = _autopilot_detect_os();
853 $sep = $osinfo['path_sep'];
854
855 // Handles .svn and other misc files that we don't want to load
856 if(strpos(basename($dir),'.') === 0) {
857 return;
858 }
859
860 if(!$absolute) {
861 $cwd = getcwd();
862 $dir_path = $cwd . '/' . $dir;
863 $dir_path = str_replace('/', $sep, $dir_path);
864 }
865 else {
866 $dir_path = str_replace('/', $sep, $dir);
867 }
868
869 $files = @scandir($dir_path);
870 if(!$files) {
871 return;
872 }
873
874 foreach($files as $k => $filename) {
875 $filter_out = false;
876 $current_path = ($absolute) ? "$dir_path/$filename" : "$cwd/$dir/$filename";
877 $current_path = str_replace('/', $sep, $current_path);
878
879 if($filename != '.' && $filename != '..' && substr($filename, 0, 1) != '.') {
880 if($filter !== null) {
881 if(!ereg($filter, basename($filename))) {
882 $filter_out = true;
883 }
884 }
885
886 if( !is_dir($current_path) && !$filter_out) {
887 include_once($current_path);
888 }
889 else {
890 _autopilot_include_files($current_path, true, $filter);
891 }
892 }
893
894 }
895 return;
896 }
897
898 function _autopilot_detect_os() {
899 static $ostype;
900 if($ostype != '') {
901 return $ostype;
902 }
903
904 $winos = eregi("windows", strtolower(php_uname()));
905 if($winos) {
906 $ostype['type'] = AUTOPILOT_OSTYPE_WINDOWS;
907 $ostype['path_sep'] = '\\';
908 }
909 else {
910 $ostype['type'] = AUTOPILOT_OSTYPE_LINUX;
911 $ostype['path_sep'] = '/';
912 }
913 return $ostype;
914 }
915
916 function _autopilot_sanitize_path($path) {
917 if( _autopilot_detect_os == AUTOPILOT_OSTYPE_WINDOWS ) {
918 return str_replace('/', '\\', $path);
919 }
920 else {
921 return str_replace('\\','/', $path);
922 }
923 }
924
925 function _autopilot_get_owernships($type = 'full') {
926 $os = array();
927 $os[AUTOPILOT_OWNERSHIP_NORMAL] = t('Normal');
928 $os[AUTOPILOT_OWNERSHIP_GLOBAL] = t('Global');
929 $os[AUTOPILOT_OWNERSHIP_TEMPLATE] = t('Template');
930
931 return $os;
932 }
933
934 function autopilot_exit() {
935 @LoggerManager::shutdown();
936
937 }
938
939
940 /**
941 * Modified from http://us3.php.net/time
942 */
943 function _autopilot_time_diff($time, $opt = array()) {
944 if($time == 0) {
945 return t('N/A');
946 }
947 // The default values
948 $defOptions = array(
949 'to' => 0,
950 'parts' => 1,
951 'precision' => 'second',
952 'distance' => TRUE,
953 'separator' => ', '
954 );
955 $opt = array_merge($defOptions, $opt);
956 // Default to current time if no to point is given
957 (!$opt['to']) && ($opt['to'] = time());
958 // Init an empty string
959 $str = '';
960 // To or From computation
961 $diff = ($opt['to'] > $time) ? $opt['to']-$time : $time-$opt['to'];
962 // An array of label => periods of seconds;
963 $periods = array(
964 'decade' => 315569260,
965 'year' => 31556926,
966 'month' => 2629744,
967 'week' => 604800,
968 'day' => 86400,
969 'hour' => 3600,
970 'minute' => 60,
971 'second' => 1
972 );
973 // Round to precision
974 if ($opt['precision'] != 'second')
975 $diff = round(($diff/$periods[$opt['precision']])) * $periods[$opt['precision']];
976 // Report the value is 'less than 1 ' precision period away
977 (0 == $diff) && ($str = 'less than 1 '.$opt['precision']);
978 // Loop over each period
979 foreach ($periods as $label => $value) {
980 // Stitch together the time difference string
981 (($x=floor($diff/$value))&&$opt['parts']--) && $str.=($str?$opt['separator']:'').($x.' '.$label.($x>1?'s':''));
982 // Stop processing if no more parts are going to be reported.
983 if ($opt['parts'] == 0 || $label == $opt['precision']) break;
984 // Get ready for the next pass
985 $diff -= $x*$value;
986 }
987 $opt['distance'] && $str.=($str&&$opt['to']>$time)?' ago':' away';
988 return $str;
989 }
990
991 // ===========================================================================
992 /**
993 *
994 * Autopilot XML-RPC Section
995 *
996 */
997 // ===========================================================================
998 function _autopilot_ajax_menu() {
999 $items = array();
1000 $items[] = array(
1001 'path' => 'autopilot/jquery/get_buildrun_log',
1002 'type' => MENU_CALLBACK,
1003 'callback' => '_autopilot_get_buildrun_logs',
1004 'access' => TRUE,
1005 'callback arguments' => array($_REQUEST),
1006 );
1007 $items[] = array(
1008 'path' => 'autopilot/jquery/buildrun_init',
1009 'type' => MENU_CALLBACK,
1010 'callback' => '_autopilot_buildrun_init',
1011 'access' => TRUE,
1012 'callback arguments' => array($_REQUEST),
1013 );
1014 $items[] = array(
1015 'path' => 'autopilot/jquery/buildrun_start',
1016 'type' => MENU_CALLBACK,
1017 'access' => TRUE,
1018 'callback' => '_autopilot_buildrun_start_run',
1019 'callback arguments' => array($_REQUEST),
1020 );
1021 return $items;
1022 }
1023
1024 /**
1025 * Returns a portion of the buildrun log
1026 *
1027 * @param $buildrun_id The id of the BuildRun
1028 * @param $log_id The id of the log to return
1029 * @param $log_batch The maxinum number of logs to return
1030 *
1031 * @return mixed An array of log entries
1032 */
1033 function _autopilot_get_buildrun_logs($data) {
1034 if($data['run_id'] == '') {
1035 return;
1036 }
1037
1038 $log_page = $data['log_id'];
1039 $log_length = isset($data['log_length']) ? $data['log_length'] : null;
1040 $info = new stdClass();
1041
1042 $run = BuildRun::buildRunFactory($run_id);
1043 $info->logs = $run->getLogs($log_page, $log_length);
1044 //$info = drupal_to_js($info);
1045 //error_log("Sending back: " . print_r($info,1));
1046 ob_end_clean();
1047 print drupal_to_js($info);
1048 exit();
1049 }
1050
1051 function _autopilot_get_buildrun_info($data) {
1052 if($data['run_id'] == '') {
1053 return;
1054 }
1055 $log_page = $data['log_id'];
1056 $log_length = isset($data['log_length']) ? $data['log_length'] : 10;
1057 $info = new stdClass();
1058 $run = new BuildRun();
1059 //$run = BuildRun::buildRunFactory($run_id);
1060 $info->logs = $run->getLogs($log_page, $log_length);
1061 //$info = drupal_to_js($info);
1062 ob_end_clean();
1063 echo $info->view;
1064 exit();
1065 }
1066
1067 /**
1068 * This is used to setup/prepare a new
1069 * build run.
1070 *
1071 * @return int A new buildrun_id
1072 */
1073 function _autopilot_buildrun_init($data) {
1074
1075 $bpid = $data['bpid'];
1076
1077 $bp = new SimpleBuildPlan($bpid);
1078
1079 # Set the code revisions
1080 $bp->setCodeRevision($data['code_rev']);
1081 $bp->setSQLRevision($data['sql_rev']);
1082
1083 $run = BuildRun::buildRunFactory($bp);
1084 $run->init();
1085 $run->update();
1086 $id = $run->getID();
1087
1088 $json = new stdClass();
1089 $json->run_id = $id;
1090
1091
1092 unset($run);
1093 print drupal_to_js($json);
1094 exit();
1095 }
1096
1097 /**
1098 * This starts a build run. Now the build run is transmitted
1099 * as a serialized array of the information needed
1100 * to make the run. We need to create a build BuidPlan
1101 * object from this information and run the build.
1102 *
1103 * @return void
1104 */
1105 function _autopilot_buildrun_start_run($data) {
1106 set_time_limit(300);
1107 $run_id = $data['run_id'];
1108
1109 $json = new stdClass();
1110 if(!is_numeric($run_id)) {
1111 $json->errors = true;
1112 $json->error_msg = "Invalid run id.";
1113 print drupal_to_js($json);
1114 exit();
1115 }
1116 $json = new stdClass();
1117
1118 $bp = new SimpleBuildPlan($data['bpid']);
1119 # Set the code revisions
1120 $bp->setCodeRevision($data['code_rev']);
1121 $bp->setSQLRevision($data['sql_rev']);
1122
1123 if($run_id == '') {
1124 $json->error = true;
1125 $json->error_msg = t('Invalid run id given.');
1126 return drupal_to_js($json);
1127 }
1128
1129 $run = new BuildRun($run_id);
1130 if(!is_a($run->getBuildPlan(), 'BuildPlan')) {
1131 $run = null;
1132 }
1133
1134 if(!$run) {
1135 $json->errors = true;
1136 $json->error_msg = "Unable to locate build.";
1137 print drupal_to_js($json);
1138 exit();
1139 }
1140 $run->setBuildPlan($bp);
1141 $run->runBuild();
1142 $json->errors = false;
1143 $json->error_msg = "Run Complete";
1144 print drupal_to_js($json);
1145 exit();
1146 }
1147
1148 /*******************************
1149 * Database Section
1150 */
1151 /**
1152 * @author Earnest Berry III <earnest at workhabit dot com>
1153 * Generates a page showing the databases that are associated with
1154 * this autopilot.
1155 */
1156 function autopilot_database_overview() {
1157 $page = "";
1158 $page .= '<h2>' . t('This section allows one to do simple database maintianance tasks.') . '</h2>';
1159 $page .= '<p>' . t('Please select one of the following database options:') . '</p>';
1160 $links[] = array('href' => 'autopilot/database/tx', 'title' => t('Transfer Databases'), 'name' => 'he');
1161 $page .= theme('links', $links);
1162 return $page;
1163 }
1164
1165 /**
1166 * Database Transfer Staction
1167 */
1168 /**
1169 * @abstract Pushes database. User can select a
1170 * LIVE source database, and then have that database
1171 * pushed into the repository location of their choice.
1172 */
1173 function autopilot_database_transfer_form() {
1174 _autopilot_init_js();
1175 $form = array();
1176
1177 # Source Sectoin
1178 $form['source_info'] = array(
1179 '#type' => 'fieldset',
1180 '#title' => t('Source Inforamtion'),
1181 '#collapsible' => true,
1182 '#collapsed' => false,
1183 );
1184
1185 /**
1186 * Get a listing of the databases from the different build plans
1187 * for this autopilot
1188 */
1189 $rs = db_query("SELECT apt.tid
1190 FROM {ap_target} apt
1191 INNER JOIN {ap_targets} apts ON (apt.tid = apts.tid)
1192 WHERE apid = %d", _autopilot_get_apid());
1193 # Grab the tids
1194 $dbs = array();
1195 $avail_dbs = array('0' => '-');
1196 while($row = db_fetch_object($rs)) {
1197 $t = Target::targetFactory($row->tid);
1198 $avail_dbs[$row->tid] = $t->getName();
1199 $dbs[] = $t;
1200 }
1201
1202 $form['source_info']['source_tid'] = array(
1203 '#title' => t('Source Database'),
1204 '#description'