Example #1
0
 public function updateAction($projects, $tag, $user)
 {
     $individual_file_rev_updates = array();
     $individual_file_rev_projects = array();
     ###  Target mode
     $target_mode_update = false;
     if ($tag == 'Target') {
         $target_mode_update = true;
         $tag = 'HEAD';
         ###  Get the max file tag for files in more than one project
         $file_tags = array();
         foreach ($projects as $project) {
             $tags = $project->get_file_tags();
             foreach ($project->get_affected_files() as $file) {
                 if (empty($file_tags[$file]) || empty($tags[$file]) && $file_tags[$file] != 'HEAD' || !empty($tags[$file]) && is_numeric($tags[$file]) && $file_tags[$file] != 'HEAD' && $file_tags[$file] < $tags[$file]) {
                     $file_tags[$file] = isset($tags[$file]) ? $tags[$file] : 'HEAD';
                 }
             }
         }
         foreach ($file_tags as $file => $tag) {
             if ($tag == 'HEAD') {
                 unset($file_tags[$file]);
             }
         }
     }
     ###  Prepare for a MASS HEAD update if updating to HEAD
     $doing_indiv_dir_update = array();
     $mass_head_update_files = array();
     $mass_head_update_projects = array();
     if ($tag == 'HEAD') {
         foreach ($projects as $project) {
             foreach ($project->get_affected_files() as $file) {
                 if (is_dir($this->stage->env()->repo_base . "/{$file}") || $target_mode_update && isset($file_tags[$file])) {
                     continue;
                 }
                 $mass_head_update_files[$file] = $file;
                 $mass_head_update_projects[$project->project_name] = $project;
             }
         }
         ###  Get Target Mode files
         if ($target_mode_update) {
             foreach ($projects as $project) {
                 foreach ($project->get_affected_files() as $file) {
                     if (is_dir($this->stage->env()->repo_base . "/{$file}")) {
                         continue;
                     }
                     if (!empty($file_tags[$file]) && abs(floor($file_tags[$file])) == $file_tags[$file]) {
                         $individual_file_rev_updates[$file] = array($file, $file_tags[$file]);
                         $individual_file_rev_projects[$file][$project->project_name] = $project;
                     }
                 }
             }
         }
     } else {
         if (preg_match('/^RP-(\\d+)$/', $tag, $m)) {
             require_once dirname(__FILE__) . '/../model/RollPoint.class.php';
             ///  Get the rollback point
             $point = new Ansible__RollPoint($m[1]);
             if (!$point->exists()) {
                 trigger_error("Non-existant Roll Point: " . $tag, E_USER_ERROR);
             }
             ///  Check out that this rollout includes all the files from
             ///    this rollback point
             if (!$point->includes_same_projects($projects)) {
                 trigger_error("Not all selected projects are in the selected roll point: " . $tag, E_USER_ERROR);
             }
             ///  Create new ROLL entry
             $point_roll = $point->new_roll($user);
             ///  If we are rolling out to a 'rollout' point then auto-make a Rollback point
             if ($point->point_type == 'rollout') {
                 list($tag_cmd, $tag_command_output, $rb_point) = $this->tagAction($projects, 'prod_rollback', $user);
                 #				bug('TAGGED prod_rollback!!', $tag_cmd, $tag_command_output);
                 $point_roll->set_and_save(array('rollback_rlpt_id' => $rb_point->rlpt_id));
             }
             foreach ($point->files as $point_file) {
                 if (!empty($point_file->revision)) {
                     $dir_test = $point_file->file;
                     ###  Before we do Inidividual Tag updates on files the containing dirs must exist
                     $dirs_to_update = array();
                     while (!empty($dir_test) && !is_dir(dirname($this->stage->env()->repo_base . "/{$dir_test}")) && $this->stage->env()->repo_base != dirname($this->stage->env()->repo_base . "/{$dir_test}") && !array_key_exists(dirname($dir_test), $doing_indiv_dir_update)) {
                         $dir = dirname($dir_test);
                         $dirs_to_update[] = $dir;
                         $doing_indiv_dir_update[$dir] = true;
                         $dir_test = $dir;
                         // iterate backwards
                     }
                     ///  Need to add in parent-first order
                     ///    NOTE: we only need to do the parent one, because the in-between ones will be included
                     if (count($dirs_to_update)) {
                         $first_dir = array_pop($dirs_to_update);
                         $individual_file_rev_updates[$first_dir] = array($first_dir, $point_file->revision);
                         $individual_file_rev_projects[$first_dir] = $point->get_file_projects($first_dir);
                     }
                     $individual_file_rev_updates[$point_file->file] = array($point_file->file, $point_file->revision);
                     $individual_file_rev_projects[$point_file->file] = $point->get_file_projects($point_file);
                 } else {
                     list($first_rev, $error) = $this->get_first_rev($point_file->file);
                     if (empty($error)) {
                         $rev_before_first = $first_rev - 1;
                         $individual_file_rev_updates[$point_file->file] = array($point_file->file, $rev_before_first);
                         $individual_file_rev_projects[$point_file->file] = $point->get_file_projects($point_file->file);
                     }
                 }
             }
         } else {
             foreach ($projects as $project) {
                 foreach ($project->get_affected_files() as $file) {
                     if (is_dir($this->stage->env()->repo_base . "/{$file}")) {
                         continue;
                     }
                     ###  Get the tag rev for this file...
                     $sth = dbh_query_bind("SELECT revision FROM file_tag WHERE file = ? AND tag = ?", $file, $tag);
                     $rev = $sth->fetch(PDO::FETCH_NUM);
                     $sth->closeCursor();
                     if (!empty($rev)) {
                         $dir_test = $file;
                         ###  Before we do Inidividual Tag updates on files the containing dirs must exist
                         $dirs_to_update = array();
                         while (!empty($dir_test) && !is_dir(dirname($this->stage->env()->repo_base . "/{$dir_test}")) && $this->stage->env()->repo_base != dirname($this->stage->env()->repo_base . "/{$dir_test}") && !array_key_exists(dirname($dir_test), $doing_indiv_dir_update)) {
                             $dir = dirname($dir_test);
                             $dirs_to_update[] = $dir;
                             $doing_indiv_dir_update[$dir] = true;
                             $dir_test = $dir;
                             // iterate backwards
                         }
                         ///  Need to add in parent-first order
                         ///    NOTE: we only need to do the parent one, because the in-between ones will be included
                         if (count($dirs_to_update)) {
                             $individual_file_rev_updates[] = array(array_pop($dirs_to_update), $rev[0]);
                             $individual_file_rev_projects[$file][$project->project_name] = $project;
                         }
                         $individual_file_rev_updates[$file] = array($file, $rev[0]);
                         $individual_file_rev_projects[$file][$project->project_name] = $project;
                     } else {
                         list($first_rev, $error) = $this->get_first_rev($file);
                         if (empty($error)) {
                             $rev_before_first = $first_rev - 1;
                             $individual_file_rev_updates[$file] = array($file, $rev_before_first);
                             $individual_file_rev_projects[$file][$project->project_name] = $project;
                         }
                     }
                 }
             }
         }
     }
     ###  Run the MASS HEAD update (if any)
     if (!empty($mass_head_update_files)) {
         $head_update_cmd = "svn update ";
         foreach ($mass_head_update_files as $file) {
             $head_update_cmd .= ' ' . escapeshellcmd($file);
         }
         START_TIMER('REPO_CMD', PROJECT_PROJECT_TIMERS);
         foreach ($mass_head_update_projects as $project) {
             $this->log_repo_action($head_update_cmd, $project, $user);
         }
         $cmd_prefix = $this->stage->config('repo_cmd_prefix');
         $command_output .= shell_exec("{$cmd_prefix}{$head_update_cmd} 2>&1 | cat -");
         END_TIMER('REPO_CMD', PROJECT_PROJECT_TIMERS);
         $cmd .= "\n" . (strlen($cmd) ? ' ; ' : '') . $head_update_cmd;
     }
     ###  File tag update
     if (!empty($individual_file_rev_updates)) {
         foreach ($individual_file_rev_updates as $update) {
             list($file, $rev) = $update;
             $indiv_update_cmd = "svn update -r{$rev} " . escapeshellcmd($file);
             START_TIMER('REPO_CMD', PROJECT_PROJECT_TIMERS);
             foreach ($individual_file_rev_projects[$file] as $project) {
                 $this->log_repo_action($indiv_update_cmd, $project, $user);
             }
             $cmd_prefix = $this->stage->config('repo_cmd_prefix');
             $command_output .= shell_exec("{$cmd_prefix}{$indiv_update_cmd} 2>&1 | cat -");
             END_TIMER('REPO_CMD', PROJECT_PROJECT_TIMERS);
             $cmd .= "\n" . (strlen($cmd) ? ' ; ' : '') . $indiv_update_cmd;
         }
     }
     ///  After a rollout on Production, retag PROD_TEST for other people's reference
     if ($this->stage->onLive()) {
         list($tag_cmd, $tag_command_output) = $this->tagAction($projects, 'PROD_TEST', $user);
         #			bug('TAGGED PROD_TEST!!', $tag_cmd, $tag_command_output);
     }
     ///  If this is a Roll to Point then save the command output
     if (isset($point_roll)) {
         $point_roll->set_and_save(array('cmd' => $cmd, 'cmd_output' => $command_output));
     }
     if (empty($command_output)) {
         $command_output = '</xmp><i>No output</i>';
     }
     return array($cmd, $command_output);
 }