private function updateBuildSteps(HarbormasterBuild $build)
 {
     $targets = id(new HarbormasterBuildTargetQuery())->setViewer($this->getViewer())->withBuildPHIDs(array($build->getPHID()))->withBuildGenerations(array($build->getBuildGeneration()))->execute();
     $this->updateWaitingTargets($targets);
     $targets = mgroup($targets, 'getBuildStepPHID');
     $steps = id(new HarbormasterBuildStepQuery())->setViewer($this->getViewer())->withBuildPlanPHIDs(array($build->getBuildPlan()->getPHID()))->execute();
     // Identify steps which are in various states.
     $queued = array();
     $underway = array();
     $waiting = array();
     $complete = array();
     $failed = array();
     foreach ($steps as $step) {
         $step_targets = idx($targets, $step->getPHID(), array());
         if ($step_targets) {
             $is_queued = false;
             $is_underway = false;
             foreach ($step_targets as $target) {
                 if ($target->isUnderway()) {
                     $is_underway = true;
                     break;
                 }
             }
             $is_waiting = false;
             foreach ($step_targets as $target) {
                 if ($target->isWaiting()) {
                     $is_waiting = true;
                     break;
                 }
             }
             $is_complete = true;
             foreach ($step_targets as $target) {
                 if (!$target->isComplete()) {
                     $is_complete = false;
                     break;
                 }
             }
             $is_failed = false;
             foreach ($step_targets as $target) {
                 if ($target->isFailed()) {
                     $is_failed = true;
                     break;
                 }
             }
         } else {
             $is_queued = true;
             $is_underway = false;
             $is_waiting = false;
             $is_complete = false;
             $is_failed = false;
         }
         if ($is_queued) {
             $queued[$step->getPHID()] = true;
         }
         if ($is_underway) {
             $underway[$step->getPHID()] = true;
         }
         if ($is_waiting) {
             $waiting[$step->getPHID()] = true;
         }
         if ($is_complete) {
             $complete[$step->getPHID()] = true;
         }
         if ($is_failed) {
             $failed[$step->getPHID()] = true;
         }
     }
     // If any step failed, fail the whole build, then bail.
     if (count($failed)) {
         $build->setBuildStatus(HarbormasterBuild::STATUS_FAILED);
         $build->save();
         return;
     }
     // If every step is complete, we're done with this build. Mark it passed
     // and bail.
     if (count($complete) == count($steps)) {
         $build->setBuildStatus(HarbormasterBuild::STATUS_PASSED);
         $build->save();
         return;
     }
     // Identify all the steps which are ready to run (because all their
     // dependencies are complete).
     $runnable = array();
     foreach ($steps as $step) {
         $dependencies = $step->getStepImplementation()->getDependencies($step);
         if (isset($queued[$step->getPHID()])) {
             $can_run = true;
             foreach ($dependencies as $dependency) {
                 if (empty($complete[$dependency])) {
                     $can_run = false;
                     break;
                 }
             }
             if ($can_run) {
                 $runnable[] = $step;
             }
         }
     }
     if (!$runnable && !$waiting && !$underway) {
         // This means the build is deadlocked, and the user has configured
         // circular dependencies.
         $build->setBuildStatus(HarbormasterBuild::STATUS_DEADLOCKED);
         $build->save();
         return;
     }
     foreach ($runnable as $runnable_step) {
         $target = HarbormasterBuildTarget::initializeNewBuildTarget($build, $runnable_step, $build->retrieveVariablesFromBuild());
         $target->save();
         $this->queueNewBuildTarget($target);
     }
 }